PACSRequestStatus::RetrieveRequestStatus RetrieveDICOMFilesFromPACS::retrieve(const QString &studyInstanceUID, const QString &seriesInstanceUID, const QString &sopInstanceUID)
{
    T_ASC_PresentationContextID presentationContextID;
    T_DIMSE_C_MoveRSP moveResponse;
    DcmDataset *statusDetail = NULL;
    m_pacsConnection = new PACSConnection(m_pacs);
    PACSRequestStatus::RetrieveRequestStatus retrieveRequestStatus;
    MoveSCPCallbackData moveSCPCallbackData;
    DcmDataset *dcmDatasetToRetrieve = getDcmDatasetOfImagesToRetrieve(studyInstanceUID, seriesInstanceUID, sopInstanceUID);
    m_numberOfImagesRetrieved = 0;

    // TODO S'hauria de comprovar que es tracti d'un PACS amb el servei de retrieve configurat
    if (!m_pacsConnection->connectToPACS(PACSConnection::RetrieveDICOMFiles))
    {
        ERROR_LOG("S'ha produit un error al intentar connectar al PACS per fer un retrieve. AE Title: " + m_pacs.getAETitle());
        return PACSRequestStatus::RetrieveCanNotConnectToPACS;
    }

    // Which presentation context should be used, It's important that the connection has MoveStudyRoot level
    T_ASC_Association *association = m_pacsConnection->getConnection();
    presentationContextID = ASC_findAcceptedPresentationContextID(association, MoveAbstractSyntax);
    if (presentationContextID == 0)
    {
        ERROR_LOG("No s'ha trobat cap presentation context valid");
        return PACSRequestStatus::RetrieveFailureOrRefused;
    }

    moveSCPCallbackData.association = association;
    moveSCPCallbackData.presentationContextId = presentationContextID;
    moveSCPCallbackData.retrieveDICOMFilesFromPACS = this;

    // Set the destination of the images to us
    T_DIMSE_C_MoveRQ moveRequest = getConfiguredMoveRequest(association);
    ASC_getAPTitles(association->params, moveRequest.MoveDestination, NULL, NULL);

    OFCondition condition = DIMSE_moveUser(association, presentationContextID, &moveRequest, dcmDatasetToRetrieve, moveCallback, &moveSCPCallbackData,
                                           DIMSE_BLOCKING, 0, m_pacsConnection->getNetwork(), subOperationCallback, this, &moveResponse, &statusDetail,
                                           NULL /*responseIdentifiers*/);

    if (condition.bad())
    {
        ERROR_LOG(QString("El metode descarrega no ha finalitzat correctament. Codi error: %1, descripcio error: %2").arg(condition.code())
                     .arg(condition.text()));
    }

    m_pacsConnection->disconnect();

    retrieveRequestStatus = getDIMSEStatusCodeAsRetrieveRequestStatus(moveResponse.DimseStatus);
    processServiceClassProviderResponseStatus(moveResponse.DimseStatus, statusDetail);
    
    // Dump status detail information if there is some
    if (statusDetail != NULL)
    {
        delete statusDetail;
    }

    delete dcmDatasetToRetrieve;

    return retrieveRequestStatus;
}
Ejemplo n.º 2
0
    CommandDispatcher* AcceptAssociation(const DicomServer& server, T_ASC_Network *net)
    {
      DcmAssociationConfiguration asccfg;
      char buf[BUFSIZ];
      T_ASC_Association *assoc;
      OFCondition cond;
      OFString sprofile;
      OFString temp_str;

      std::vector<const char*> knownAbstractSyntaxes;

      // For C-STORE
      if (server.HasStoreRequestHandlerFactory())
      {
        knownAbstractSyntaxes.push_back(UID_VerificationSOPClass);
      }

      // For C-FIND
      if (server.HasFindRequestHandlerFactory())
      {
        knownAbstractSyntaxes.push_back(UID_FINDPatientRootQueryRetrieveInformationModel);
        knownAbstractSyntaxes.push_back(UID_FINDStudyRootQueryRetrieveInformationModel);
      }

      // For C-MOVE
      if (server.HasMoveRequestHandlerFactory())
      {
        knownAbstractSyntaxes.push_back(UID_MOVEStudyRootQueryRetrieveInformationModel);
      }

      const char* transferSyntaxes[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
      int numTransferSyntaxes = 0;

      cond = ASC_receiveAssociation(net, &assoc, 
                                    /*opt_maxPDU*/ ASC_DEFAULTMAXPDU, 
                                    NULL, NULL,
                                    /*opt_secureConnection*/ OFFalse,
                                    DUL_NOBLOCK, 1);

      if (cond == DUL_NOASSOCIATIONREQUEST)
      {
        // Timeout
        AssociationCleanup(assoc);
        return NULL;
      }

      // if some kind of error occured, take care of it
      if (cond.bad())
      {
        LOG(ERROR) << "Receiving Association failed: " << cond.text();
        // no matter what kind of error occurred, we need to do a cleanup
        AssociationCleanup(assoc);
        return NULL;
      }

      LOG(INFO) << "Association Received";

      transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax;
      transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax;
      transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
      numTransferSyntaxes = 3;

      /* accept the Verification SOP Class if presented */
      cond = ASC_acceptContextsWithPreferredTransferSyntaxes( assoc->params, &knownAbstractSyntaxes[0], knownAbstractSyntaxes.size(), transferSyntaxes, numTransferSyntaxes);
      if (cond.bad())
      {
        LOG(INFO) << cond.text();
        AssociationCleanup(assoc);
        return NULL;
      }

      /* the array of Storage SOP Class UIDs comes from dcuid.h */
      cond = ASC_acceptContextsWithPreferredTransferSyntaxes( assoc->params, dcmAllStorageSOPClassUIDs, numberOfAllDcmStorageSOPClassUIDs, transferSyntaxes, numTransferSyntaxes);
      if (cond.bad())
      {
        LOG(INFO) << cond.text();
        AssociationCleanup(assoc);
        return NULL;
      }

      /* set our app title */
      ASC_setAPTitles(assoc->params, NULL, NULL, server.GetApplicationEntityTitle().c_str());

      /* acknowledge or reject this association */
      cond = ASC_getApplicationContextName(assoc->params, buf);
      if ((cond.bad()) || strcmp(buf, UID_StandardApplicationContext) != 0)
      {
        /* reject: the application context name is not supported */
        T_ASC_RejectParameters rej =
          {
            ASC_RESULT_REJECTEDPERMANENT,
            ASC_SOURCE_SERVICEUSER,
            ASC_REASON_SU_APPCONTEXTNAMENOTSUPPORTED
          };

        LOG(INFO) << "Association Rejected: Bad Application Context Name: " << buf;
        cond = ASC_rejectAssociation(assoc, &rej);
        if (cond.bad())
        {
          LOG(INFO) << cond.text();
        }
        AssociationCleanup(assoc);
        return NULL;
      }
  
      /* check the AETs */
      {
        DIC_AE callingTitle_C;
        DIC_AE calledTitle_C;
        DIC_AE callingIP_C;
        DIC_AE calledIP_C;
        if (ASC_getAPTitles(assoc->params, callingTitle_C, calledTitle_C, NULL).bad() ||
            ASC_getPresentationAddresses(assoc->params, callingIP_C, calledIP_C).bad())
        {
          T_ASC_RejectParameters rej =
            {
              ASC_RESULT_REJECTEDPERMANENT,
              ASC_SOURCE_SERVICEUSER,
              ASC_REASON_SU_NOREASON
            };
          ASC_rejectAssociation(assoc, &rej);
          AssociationCleanup(assoc);
          return NULL;
        }

        std::string callingIP(/*OFSTRING_GUARD*/(callingIP_C));
        std::string callingTitle(/*OFSTRING_GUARD*/(callingTitle_C));
        std::string calledTitle(/*OFSTRING_GUARD*/(calledTitle_C));
        Toolbox::ToUpperCase(callingIP);
        Toolbox::ToUpperCase(callingTitle);
        Toolbox::ToUpperCase(calledTitle);

        if (server.HasCalledApplicationEntityTitleCheck() &&
            calledTitle != server.GetApplicationEntityTitle())
        {
          T_ASC_RejectParameters rej =
            {
              ASC_RESULT_REJECTEDPERMANENT,
              ASC_SOURCE_SERVICEUSER,
              ASC_REASON_SU_CALLEDAETITLENOTRECOGNIZED
            };
          ASC_rejectAssociation(assoc, &rej);
          AssociationCleanup(assoc);
          return NULL;
        }

        if (server.HasApplicationEntityFilter() &&
            !server.GetApplicationEntityFilter().IsAllowed(callingIP, callingTitle))
        {
          T_ASC_RejectParameters rej =
            {
              ASC_RESULT_REJECTEDPERMANENT,
              ASC_SOURCE_SERVICEUSER,
              ASC_REASON_SU_CALLINGAETITLENOTRECOGNIZED
            };
          ASC_rejectAssociation(assoc, &rej);
          AssociationCleanup(assoc);
          return NULL;
        }
      }

      if (opt_rejectWithoutImplementationUID && strlen(assoc->params->theirImplementationClassUID) == 0)
      {
        /* reject: the no implementation Class UID provided */
        T_ASC_RejectParameters rej =
          {
            ASC_RESULT_REJECTEDPERMANENT,
            ASC_SOURCE_SERVICEUSER,
            ASC_REASON_SU_NOREASON
          };

        LOG(INFO) << "Association Rejected: No Implementation Class UID provided";
        cond = ASC_rejectAssociation(assoc, &rej);
        if (cond.bad())
        {
          LOG(INFO) << cond.text();
        }
        AssociationCleanup(assoc);
        return NULL;
      }

      {
        cond = ASC_acknowledgeAssociation(assoc);
        if (cond.bad())
        {
          LOG(ERROR) << cond.text();
          AssociationCleanup(assoc);
          return NULL;
        }
        LOG(INFO) << "Association Acknowledged (Max Send PDV: " << assoc->sendPDVLength << ")";
        if (ASC_countAcceptedPresentationContexts(assoc->params) == 0)
          LOG(INFO) << "    (but no valid presentation contexts)";
      }

      return new CommandDispatcher(server, assoc);
    }