# HG changeset patch
# User Alain Mazy <am@orthanc.team>
# Date 1733735239 -3600
# Node ID bfae0fc2ea1ba7df1244bb25d45cf054e6ac022c
# Parent  866defb5f95ad99b993423bf3a2c6a420bc2c7fb
Started to work on handling errors as warnings when trying to store instances whose SOPClassUID has not been accepted during the negotiation.  Work to be finalized later

diff -r 866defb5f95a -r bfae0fc2ea1b OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.cpp
--- a/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.cpp	Mon Dec 09 10:04:34 2024 +0100
+++ b/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.cpp	Mon Dec 09 10:07:19 2024 +0100
@@ -377,7 +377,8 @@
                                        DcmFileFormat& dicom,
                                        bool hasMoveOriginator,
                                        const std::string& moveOriginatorAET,
-                                       uint16_t moveOriginatorID)
+                                       uint16_t moveOriginatorID,
+                                       bool ignoreErrors)
   {
     DicomTransferSyntax transferSyntax;
     LookupParameters(sopClassUid, sopInstanceUid, transferSyntax, dicom);
@@ -388,12 +389,21 @@
     if (!NegotiatePresentationContext(presID, sopClassUid, transferSyntax, proposeUncompressedSyntaxes_,
                                       DicomTransferSyntax_LittleEndianExplicit))
     {
-      throw OrthancException(ErrorCode_NetworkProtocol,
-                             "No valid presentation context was negotiated for "
-                             "SOP class UID [" + sopClassUid + "] and transfer "
-                             "syntax [" + GetTransferSyntaxUid(transferSyntax) + "] "
-                             "while sending to modality [" +
-                             parameters_.GetRemoteModality().GetApplicationEntityTitle() + "]");
+      if (ignoreErrors)
+      {
+        LOG(INFO) << "No valid presentation context was negotiated for SOP class UID [" << sopClassUid << "] and transfer "
+                      "syntax [" << GetTransferSyntaxUid(transferSyntax) << "] "
+                      "while sending to modality [" << parameters_.GetRemoteModality().GetApplicationEntityTitle() << "]";
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_NetworkProtocol,
+                              "No valid presentation context was negotiated for "
+                              "SOP class UID [" + sopClassUid + "] and transfer "
+                              "syntax [" + GetTransferSyntaxUid(transferSyntax) + "] "
+                              "while sending to modality [" +
+                              parameters_.GetRemoteModality().GetApplicationEntityTitle() + "]");
+      }
     }
     
     // Prepare the transmission of data
@@ -469,7 +479,8 @@
                                        size_t size,
                                        bool hasMoveOriginator,
                                        const std::string& moveOriginatorAET,
-                                       uint16_t moveOriginatorID)
+                                       uint16_t moveOriginatorID,
+                                       bool ignoreErrors)
   {
     std::unique_ptr<DcmFileFormat> dicom(
       FromDcmtkBridge::LoadFromMemoryBuffer(buffer, size));
@@ -479,7 +490,7 @@
       throw OrthancException(ErrorCode_InternalError);
     }
     
-    Store(sopClassUid, sopInstanceUid, *dicom, hasMoveOriginator, moveOriginatorAET, moveOriginatorID);
+    Store(sopClassUid, sopInstanceUid, *dicom, hasMoveOriginator, moveOriginatorAET, moveOriginatorID, ignoreErrors);
   }
 
 
@@ -523,7 +534,8 @@
                                            DicomTransferSyntax preferredTransferSyntax,
                                            bool hasMoveOriginator,
                                            const std::string& moveOriginatorAET,
-                                           uint16_t moveOriginatorID)
+                                           uint16_t moveOriginatorID,
+                                           bool ignoreErrors)
   {
     std::unique_ptr<DcmFileFormat> dicom(FromDcmtkBridge::LoadFromMemoryBuffer(buffer, size));
     if (dicom.get() == NULL ||
@@ -540,15 +552,24 @@
 
     if (accepted.size() == 0)
     {
-      throw OrthancException(ErrorCode_NoPresentationContext, "Cannot C-Store an instance of SOPClassUID " + 
-                             sopClassUid + ", the destination has not accepted any TransferSyntax for this SOPClassUID.");
+      if (ignoreErrors)
+      {
+        LOG(WARNING) << "Cannot C-Store an instance of SOPClassUID " << 
+                      sopClassUid + ", the destination has not accepted any TransferSyntax for this SOPClassUID.";  // TODO: add an option to enable/disable this warning
+        return;
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_NoPresentationContext, "Cannot C-Store an instance of SOPClassUID " + 
+                               sopClassUid + ", the destination has not accepted any TransferSyntax for this SOPClassUID.");
+      }
     }
 
     if (accepted.find(sourceSyntax) != accepted.end())
     {
       // No need for transcoding
       Store(sopClassUid, sopInstanceUid, *dicom,
-            hasMoveOriginator, moveOriginatorAET, moveOriginatorID);
+            hasMoveOriginator, moveOriginatorAET, moveOriginatorID, ignoreErrors);
     }
     else
     {
@@ -639,7 +660,7 @@
         else
         {
           Store(sopClassUid, sopInstanceUid, transcoded.GetParsed(),
-                hasMoveOriginator, moveOriginatorAET, moveOriginatorID);
+                hasMoveOriginator, moveOriginatorAET, moveOriginatorID, ignoreErrors);
         }
       }
       else
@@ -669,10 +690,11 @@
                                            size_t size,
                                            bool hasMoveOriginator,
                                            const std::string& moveOriginatorAET,
-                                           uint16_t moveOriginatorID)
+                                           uint16_t moveOriginatorID,
+                                           bool ignoreErrors)
   {
     Transcode(sopClassUid, sopInstanceUid, transcoder, buffer, size, DicomTransferSyntax_LittleEndianExplicit,
-              hasMoveOriginator, moveOriginatorAET, moveOriginatorID);
+              hasMoveOriginator, moveOriginatorAET, moveOriginatorID, ignoreErrors);
   }
 #endif
 }
diff -r 866defb5f95a -r bfae0fc2ea1b OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.h
--- a/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.h	Mon Dec 09 10:04:34 2024 +0100
+++ b/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.h	Mon Dec 09 10:07:19 2024 +0100
@@ -130,7 +130,8 @@
                DcmFileFormat& dicom,
                bool hasMoveOriginator,
                const std::string& moveOriginatorAET,
-               uint16_t moveOriginatorID);
+               uint16_t moveOriginatorID,
+               bool ignoreErrors);
 
     void Store(std::string& sopClassUid,
                std::string& sopInstanceUid,
@@ -138,7 +139,8 @@
                size_t size,
                bool hasMoveOriginator,
                const std::string& moveOriginatorAET,
-               uint16_t moveOriginatorID);
+               uint16_t moveOriginatorID,
+               bool ignoreErrors);
 
     void LookupParameters(std::string& sopClassUid,
                           std::string& sopInstanceUid,
@@ -154,7 +156,8 @@
                    DicomTransferSyntax preferredTransferSyntax,
                    bool hasMoveOriginator,
                    const std::string& moveOriginatorAET,
-                   uint16_t moveOriginatorID);
+                   uint16_t moveOriginatorID,
+                   bool errorsAsWarning);
 #endif
     
 #if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1
@@ -165,7 +168,8 @@
                    size_t size,
                    bool hasMoveOriginator,
                    const std::string& moveOriginatorAET,
-                   uint16_t moveOriginatorID);
+                   uint16_t moveOriginatorID,
+                   bool errorsAsWarning);
 #endif
   };
 }
diff -r 866defb5f95a -r bfae0fc2ea1b OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp
--- a/OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp	Mon Dec 09 10:04:34 2024 +0100
+++ b/OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp	Mon Dec 09 10:07:19 2024 +0100
@@ -3583,7 +3583,7 @@
         try
         {
           scu.Transcode(c, k, transcoder, source.c_str(), source.size(),
-                        DicomTransferSyntax_LittleEndianExplicit, false, "", 0);
+                        DicomTransferSyntax_LittleEndianExplicit, false, "", 0, false);
         }
         catch (OrthancException& e)
         {
diff -r 866defb5f95a -r bfae0fc2ea1b OrthancServer/Sources/OrthancGetRequestHandler.cpp
--- a/OrthancServer/Sources/OrthancGetRequestHandler.cpp	Mon Dec 09 10:04:34 2024 +0100
+++ b/OrthancServer/Sources/OrthancGetRequestHandler.cpp	Mon Dec 09 10:07:19 2024 +0100
@@ -250,10 +250,9 @@
     {
       failedCount_++;
       AddFailedUIDInstance(sopInstanceUid);
-      throw OrthancException(ErrorCode_NetworkProtocol,
-                             "C-GET SCP: storeSCU: No presentation context for: (" +
-                             std::string(dcmSOPClassUIDToModality(sopClassUid.c_str(), "OT")) +
-                             ") " + sopClassUid);
+      LOG(WARNING) << "C-GET SCP: storeSCU: No presentation context for: (" 
+                   << dcmSOPClassUIDToModality(sopClassUid.c_str(), "OT") << ") " << sopClassUid;
+      return true;
     }
     else
     {
diff -r 866defb5f95a -r bfae0fc2ea1b OrthancServer/Sources/OrthancMoveRequestHandler.cpp
--- a/OrthancServer/Sources/OrthancMoveRequestHandler.cpp	Mon Dec 09 10:04:34 2024 +0100
+++ b/OrthancServer/Sources/OrthancMoveRequestHandler.cpp	Mon Dec 09 10:07:19 2024 +0100
@@ -110,7 +110,7 @@
 
         std::string sopClassUid, sopInstanceUid;  // Unused
         context_.StoreWithTranscoding(sopClassUid, sopInstanceUid, *connection_, dicom,
-                                      true, originatorAet_, originatorId_);
+                                      true, originatorAet_, originatorId_, false); // TODO: ignoreErrors
 
         return Status_Success;
       }
diff -r 866defb5f95a -r bfae0fc2ea1b OrthancServer/Sources/OrthancRestApi/OrthancRestModalities.cpp
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestModalities.cpp	Mon Dec 09 10:04:34 2024 +0100
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestModalities.cpp	Mon Dec 09 10:07:19 2024 +0100
@@ -1577,7 +1577,7 @@
     connection.Store(sopClassUid, sopInstanceUid, call.GetBodyData(),
                      call.GetBodySize(), 
                      false /* Not a C-MOVE */, 
-                     "", 0);
+                     "", 0, false);
 
     Json::Value answer = Json::objectValue;
     answer[SOP_CLASS_UID] = sopClassUid;
diff -r 866defb5f95a -r bfae0fc2ea1b OrthancServer/Sources/ServerContext.cpp
--- a/OrthancServer/Sources/ServerContext.cpp	Mon Dec 09 10:04:34 2024 +0100
+++ b/OrthancServer/Sources/ServerContext.cpp	Mon Dec 09 10:07:19 2024 +0100
@@ -2007,7 +2007,8 @@
                                            const std::string& dicom,
                                            bool hasMoveOriginator,
                                            const std::string& moveOriginatorAet,
-                                           uint16_t moveOriginatorId)
+                                           uint16_t moveOriginatorId,
+                                           bool ignoreErrors)
   {
     const void* data = dicom.empty() ? NULL : dicom.c_str();
     const RemoteModalityParameters& modality = connection.GetParameters().GetRemoteModality();
@@ -2016,12 +2017,12 @@
         !modality.IsTranscodingAllowed())
     {
       connection.Store(sopClassUid, sopInstanceUid, data, dicom.size(),
-                       hasMoveOriginator, moveOriginatorAet, moveOriginatorId);
+                       hasMoveOriginator, moveOriginatorAet, moveOriginatorId, ignoreErrors);
     }
     else
     {
       connection.Transcode(sopClassUid, sopInstanceUid, *this, data, dicom.size(), preferredTransferSyntax_,
-                           hasMoveOriginator, moveOriginatorAet, moveOriginatorId);
+                           hasMoveOriginator, moveOriginatorAet, moveOriginatorId, ignoreErrors);
     }
   }
 
diff -r 866defb5f95a -r bfae0fc2ea1b OrthancServer/Sources/ServerContext.h
--- a/OrthancServer/Sources/ServerContext.h	Mon Dec 09 10:04:34 2024 +0100
+++ b/OrthancServer/Sources/ServerContext.h	Mon Dec 09 10:07:19 2024 +0100
@@ -577,7 +577,8 @@
                               const std::string& dicom,
                               bool hasMoveOriginator,
                               const std::string& moveOriginatorAet,
-                              uint16_t moveOriginatorId);
+                              uint16_t moveOriginatorId,
+                              bool ignoreErrors);
 
     // This method can be used even if the global option
     // "TranscodeDicomProtocol" is set to "false"
diff -r 866defb5f95a -r bfae0fc2ea1b OrthancServer/Sources/ServerJobs/DicomModalityStoreJob.cpp
--- a/OrthancServer/Sources/ServerJobs/DicomModalityStoreJob.cpp	Mon Dec 09 10:04:34 2024 +0100
+++ b/OrthancServer/Sources/ServerJobs/DicomModalityStoreJob.cpp	Mon Dec 09 10:07:19 2024 +0100
@@ -65,7 +65,7 @@
 
     std::string sopClassUid, sopInstanceUid;
     context_.StoreWithTranscoding(sopClassUid, sopInstanceUid, *connection_, dicom,
-                                  HasMoveOriginator(), moveOriginatorAet_, moveOriginatorId_);
+                                  HasMoveOriginator(), moveOriginatorAet_, moveOriginatorId_, IsPermissive());
 
     if (storageCommitment_)
     {
diff -r 866defb5f95a -r bfae0fc2ea1b OrthancServer/Sources/ServerJobs/Operations/StoreScuOperation.cpp
--- a/OrthancServer/Sources/ServerJobs/Operations/StoreScuOperation.cpp	Mon Dec 09 10:04:34 2024 +0100
+++ b/OrthancServer/Sources/ServerJobs/Operations/StoreScuOperation.cpp	Mon Dec 09 10:07:19 2024 +0100
@@ -56,7 +56,7 @@
 
       std::string sopClassUid, sopInstanceUid;  // Unused
       context_.StoreWithTranscoding(sopClassUid, sopInstanceUid, lock.GetConnection(), dicom,
-                                    false /* Not a C-MOVE */, "", 0);
+                                    false /* Not a C-MOVE */, "", 0, false);  // TODO: get "permissive from job"
     }
     catch (OrthancException& e)
     {