1 /*
2  *
3  *  Copyright (C) 1998-2018, OFFIS e.V.
4  *  All rights reserved.  See COPYRIGHT file for details.
5  *
6  *  This software and supporting documentation were developed by
7  *
8  *    OFFIS e.V.
9  *    R&D Division Health
10  *    Escherweg 2
11  *    D-26121 Oldenburg, Germany
12  *
13  *
14  *  Module: dcmpstat
15  *
16  *  Author: Marco Eichelberg
17  *
18  *  Purpose:
19  *    classes: DVPSPrintMessageHandler
20  *
21  */
22 
23 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
24 
25 #include "dcmtk/ofstd/ofstring.h"
26 #include "dcmtk/ofstd/ofstd.h"
27 #include "dcmtk/dcmpstat/dvpsdef.h"
28 #include "dcmtk/dcmpstat/dvpspr.h"
29 
30 /* --------------- class DVPSPrintMessageHandler --------------- */
31 
DVPSPrintMessageHandler()32 DVPSPrintMessageHandler::DVPSPrintMessageHandler()
33 : assoc(NULL)
34 , net(NULL)
35 , eventHandler(NULL)
36 , blockMode(DIMSE_BLOCKING)
37 , timeout(0)
38 {
39 }
40 
~DVPSPrintMessageHandler()41 DVPSPrintMessageHandler::~DVPSPrintMessageHandler()
42 {
43   abortAssociation(); // won't do any harm if there is no association in place
44 }
45 
dumpNMessage(T_DIMSE_Message & msg,DcmItem * dataset,OFBool outgoing)46 void DVPSPrintMessageHandler::dumpNMessage(T_DIMSE_Message &msg, DcmItem *dataset, OFBool outgoing)
47 {
48     OFString str;
49     if (outgoing) {
50         DIMSE_dumpMessage(str, msg, DIMSE_OUTGOING, dataset);
51     } else {
52         DIMSE_dumpMessage(str, msg, DIMSE_INCOMING, dataset);
53     }
54     DCMPSTAT_DUMP(str);
55 }
56 
sendNRequest(T_ASC_PresentationContextID presId,T_DIMSE_Message & request,DcmDataset * rqDataSet,T_DIMSE_Message & response,DcmDataset * & statusDetail,DcmDataset * & rspDataset)57 OFCondition DVPSPrintMessageHandler::sendNRequest(
58     T_ASC_PresentationContextID presId,
59     T_DIMSE_Message &request,
60     DcmDataset *rqDataSet,
61     T_DIMSE_Message &response,
62     DcmDataset* &statusDetail,
63     DcmDataset* &rspDataset)
64 {
65     OFCondition cond = EC_Normal;
66     T_DIMSE_Command expectedResponse;
67     DIC_US expectedMessageID=0;
68     if (assoc == NULL)
69     {
70       return DIMSE_ILLEGALASSOCIATION;
71     }
72 
73     T_DIMSE_DataSetType datasetType = DIMSE_DATASET_NULL;
74     if (rqDataSet && (rqDataSet->card() > 0)) datasetType = DIMSE_DATASET_PRESENT;
75 
76     switch(request.CommandField)
77     {
78       case DIMSE_N_GET_RQ:
79         request.msg.NGetRQ.DataSetType = datasetType;
80         expectedResponse = DIMSE_N_GET_RSP;
81         expectedMessageID = request.msg.NGetRQ.MessageID;
82         break;
83       case DIMSE_N_SET_RQ:
84         request.msg.NSetRQ.DataSetType = datasetType;
85         expectedResponse = DIMSE_N_SET_RSP;
86         expectedMessageID = request.msg.NSetRQ.MessageID;
87         break;
88       case DIMSE_N_ACTION_RQ:
89         request.msg.NActionRQ.DataSetType = datasetType;
90         expectedResponse = DIMSE_N_ACTION_RSP;
91         expectedMessageID = request.msg.NActionRQ.MessageID;
92         break;
93       case DIMSE_N_CREATE_RQ:
94         request.msg.NCreateRQ.DataSetType = datasetType;
95         expectedResponse = DIMSE_N_CREATE_RSP;
96         expectedMessageID = request.msg.NCreateRQ.MessageID;
97         break;
98       case DIMSE_N_DELETE_RQ:
99         request.msg.NDeleteRQ.DataSetType = datasetType;
100         expectedResponse = DIMSE_N_DELETE_RSP;
101         expectedMessageID = request.msg.NDeleteRQ.MessageID;
102         break;
103       default:
104         return DIMSE_BADCOMMANDTYPE;
105         /* break; */
106     }
107 
108     dumpNMessage(request, rqDataSet, OFTrue);
109     cond = DIMSE_sendMessageUsingMemoryData(assoc, presId, &request, NULL, rqDataSet, NULL, NULL);
110     if (cond.bad()) return cond;
111 
112     T_ASC_PresentationContextID thisPresId;
113     T_DIMSE_Message eventReportRsp;
114     DIC_US eventReportStatus;
115     do
116     {
117         thisPresId = presId;
118         statusDetail = NULL;
119         cond = DIMSE_receiveCommand(assoc, blockMode, timeout, &thisPresId, &response, &statusDetail);
120         if (cond.bad()) return cond;
121 
122         if (response.CommandField == DIMSE_N_EVENT_REPORT_RQ)
123         {
124           /* handle N-EVENT-REPORT-RQ */
125           rspDataset = NULL;
126           if (response.msg.NEventReportRQ.DataSetType == DIMSE_DATASET_PRESENT)
127           {
128             cond = DIMSE_receiveDataSetInMemory(assoc, blockMode, timeout, &thisPresId, &rspDataset, NULL, NULL);
129             if (cond.bad()) return cond;
130           }
131           dumpNMessage(response, rspDataset, OFFalse);
132           // call event handler if registered
133           eventReportStatus = STATUS_Success;
134           if (eventHandler) eventReportStatus = eventHandler->handleEvent(response.msg.NEventReportRQ, rspDataset, statusDetail);
135           if (rspDataset) delete rspDataset;
136           rspDataset = NULL;
137           if (statusDetail) delete statusDetail;
138           statusDetail = NULL;
139 
140           // send back N-EVENT-REPORT-RSP */
141           eventReportRsp.CommandField = DIMSE_N_EVENT_REPORT_RSP;
142           eventReportRsp.msg.NEventReportRSP.MessageIDBeingRespondedTo = response.msg.NEventReportRQ.MessageID;
143           eventReportRsp.msg.NEventReportRSP.EventTypeID = response.msg.NEventReportRQ.EventTypeID;
144           eventReportRsp.msg.NEventReportRSP.DimseStatus = eventReportStatus;
145           eventReportRsp.msg.NEventReportRSP.DataSetType = DIMSE_DATASET_NULL;
146           eventReportRsp.msg.NEventReportRSP.opts = O_NEVENTREPORT_EVENTTYPEID;
147           eventReportRsp.msg.NEventReportRSP.AffectedSOPClassUID[0] = 0;
148           eventReportRsp.msg.NEventReportRSP.AffectedSOPInstanceUID[0] = 0;
149           dumpNMessage(eventReportRsp, NULL, OFTrue);
150           cond = DIMSE_sendMessageUsingMemoryData(assoc, thisPresId, &eventReportRsp, NULL, NULL, NULL, NULL);
151           if (cond.bad()) return cond;
152         } else {
153           /* No N-EVENT-REPORT-RQ. Check if this message is what we expected */
154           if (response.CommandField != expectedResponse)
155           {
156             char buf1[256];
157             sprintf(buf1, "DIMSE: Unexpected Response Command Field: 0x%x", (unsigned)response.CommandField);
158             return makeDcmnetCondition(DIMSEC_UNEXPECTEDRESPONSE, OF_error, buf1);
159           }
160           T_DIMSE_DataSetType responseDataset = DIMSE_DATASET_NULL;
161           DIC_US responseMessageID = 0;
162           /** change request to response */
163           switch(expectedResponse)
164           {
165             case DIMSE_N_GET_RSP:
166               responseDataset = response.msg.NGetRSP.DataSetType;
167               responseMessageID = response.msg.NGetRSP.MessageIDBeingRespondedTo;
168               break;
169             case DIMSE_N_SET_RSP:
170               responseDataset = response.msg.NSetRSP.DataSetType;
171               responseMessageID = response.msg.NSetRSP.MessageIDBeingRespondedTo;
172               break;
173             case DIMSE_N_ACTION_RSP:
174               responseDataset = response.msg.NActionRSP.DataSetType;
175               responseMessageID = response.msg.NActionRSP.MessageIDBeingRespondedTo;
176               break;
177             case DIMSE_N_CREATE_RSP:
178               responseDataset = response.msg.NCreateRSP.DataSetType;
179               responseMessageID = response.msg.NCreateRSP.MessageIDBeingRespondedTo;
180               break;
181             case DIMSE_N_DELETE_RSP:
182               responseDataset = response.msg.NDeleteRSP.DataSetType;
183               responseMessageID = response.msg.NDeleteRSP.MessageIDBeingRespondedTo;
184               break;
185             default:
186               {
187                 char buf1[256];
188                 sprintf(buf1, "DIMSE: Unexpected Response Command Field: 0x%x", (unsigned)response.CommandField);
189                 return makeDcmnetCondition(DIMSEC_UNEXPECTEDRESPONSE, OF_error, buf1);
190               }
191               /* break; */
192           }
193           if (responseMessageID != expectedMessageID)
194           {
195             char buf1[256];
196             sprintf(buf1, "DIMSE: Unexpected Response Command Field: 0x%x", (unsigned)response.CommandField);
197             return makeDcmnetCondition(DIMSEC_UNEXPECTEDRESPONSE, OF_error, buf1);
198           }
199           rspDataset = NULL;
200           if (responseDataset == DIMSE_DATASET_PRESENT)
201           {
202             cond = DIMSE_receiveDataSetInMemory(assoc, blockMode, timeout, &thisPresId, &rspDataset, NULL, NULL);
203             if (cond.bad()) return cond;
204           }
205           dumpNMessage(response, rspDataset, OFFalse);
206         }
207     } while (response.CommandField == DIMSE_N_EVENT_REPORT_RQ);
208     return EC_Normal;
209 }
210 
createRQ(const char * sopclassUID,OFString & sopinstanceUID,DcmDataset * attributeListIn,Uint16 & status,DcmDataset * & attributeListOut)211 OFCondition DVPSPrintMessageHandler::createRQ(
212     const char *sopclassUID,
213     OFString& sopinstanceUID,
214     DcmDataset *attributeListIn,
215     Uint16& status,
216     DcmDataset* &attributeListOut)
217 {
218   if (assoc == NULL)
219   {
220     return DIMSE_ILLEGALASSOCIATION;
221   }
222   if (sopclassUID==NULL)
223   {
224     return DIMSE_NULLKEY;
225   }
226 
227   T_ASC_PresentationContextID presCtx = findAcceptedPC(sopclassUID);
228   if (presCtx == 0)
229   {
230     return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
231   }
232 
233   T_DIMSE_Message request;
234   T_DIMSE_Message response;
235   DcmDataset *statusDetail = NULL;
236 
237   // construct N-CREATE-RQ
238   request.CommandField = DIMSE_N_CREATE_RQ;
239   request.msg.NCreateRQ.MessageID = assoc->nextMsgID++;
240   OFStandard::strlcpy(request.msg.NCreateRQ.AffectedSOPClassUID, sopclassUID, sizeof(request.msg.NCreateRQ.AffectedSOPClassUID));
241   if (sopinstanceUID.size() > 0)
242   {
243     OFStandard::strlcpy(request.msg.NCreateRQ.AffectedSOPInstanceUID, sopinstanceUID.c_str(), sizeof(request.msg.NCreateRQ.AffectedSOPInstanceUID));
244     request.msg.NCreateRQ.opts = O_NCREATE_AFFECTEDSOPINSTANCEUID;
245   } else {
246     request.msg.NCreateRQ.AffectedSOPInstanceUID[0] = 0;
247     request.msg.NCreateRQ.opts = 0;
248   }
249 
250   OFCondition cond = sendNRequest(presCtx, request, attributeListIn, response, statusDetail, attributeListOut);
251   if (cond.good())
252   {
253     status = response.msg.NCreateRSP.DimseStatus;
254     // if response contains SOP Instance UID, copy it.
255     if (response.msg.NCreateRSP.opts & O_NCREATE_AFFECTEDSOPINSTANCEUID)
256     {
257       sopinstanceUID = response.msg.NCreateRSP.AffectedSOPInstanceUID;
258     }
259   }
260   if (statusDetail) delete statusDetail;
261   return cond;
262 }
263 
setRQ(const char * sopclassUID,const char * sopinstanceUID,DcmDataset * modificationList,Uint16 & status,DcmDataset * & attributeListOut)264 OFCondition DVPSPrintMessageHandler::setRQ(
265     const char *sopclassUID,
266     const char *sopinstanceUID,
267     DcmDataset *modificationList,
268     Uint16& status,
269     DcmDataset* &attributeListOut)
270 {
271   if (assoc == NULL)
272   {
273     return DIMSE_ILLEGALASSOCIATION;
274   }
275   if ((sopclassUID==NULL)||(sopinstanceUID==NULL)||(modificationList==NULL))
276   {
277     return DIMSE_NULLKEY;
278   }
279 
280   T_ASC_PresentationContextID presCtx = findAcceptedPC(sopclassUID);
281   if (presCtx == 0)
282   {
283     return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
284   }
285 
286   T_DIMSE_Message request;
287   T_DIMSE_Message response;
288   DcmDataset *statusDetail = NULL;
289 
290   // construct N-SET-RQ
291   request.CommandField = DIMSE_N_SET_RQ;
292   request.msg.NSetRQ.MessageID = assoc->nextMsgID++;
293   OFStandard::strlcpy(request.msg.NSetRQ.RequestedSOPClassUID, sopclassUID, sizeof(request.msg.NSetRQ.RequestedSOPClassUID));
294   OFStandard::strlcpy(request.msg.NSetRQ.RequestedSOPInstanceUID, sopinstanceUID, sizeof(request.msg.NSetRQ.RequestedSOPInstanceUID));
295 
296   OFCondition cond = sendNRequest(presCtx, request, modificationList, response, statusDetail, attributeListOut);
297   if (cond.good()) status = response.msg.NSetRSP.DimseStatus;
298   if (statusDetail) delete statusDetail;
299   return cond;
300 }
301 
getRQ(const char * sopclassUID,const char * sopinstanceUID,const Uint16 * attributeIdentifierList,size_t numShorts,Uint16 & status,DcmDataset * & attributeListOut)302 OFCondition DVPSPrintMessageHandler::getRQ(
303     const char *sopclassUID,
304     const char *sopinstanceUID,
305     const Uint16 *attributeIdentifierList,
306     size_t numShorts,
307     Uint16& status,
308     DcmDataset* &attributeListOut)
309 {
310   if (assoc == NULL)
311   {
312     return DIMSE_ILLEGALASSOCIATION;
313   }
314   if ((sopclassUID==NULL)||(sopinstanceUID==NULL))
315   {
316     return DIMSE_NULLKEY;
317   }
318 
319   T_ASC_PresentationContextID presCtx = findAcceptedPC(sopclassUID);
320   if (presCtx == 0)
321   {
322     return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
323   }
324 
325   T_DIMSE_Message request;
326   T_DIMSE_Message response;
327   DcmDataset *statusDetail = NULL;
328 
329   // construct N-GET-RQ
330   request.CommandField = DIMSE_N_GET_RQ;
331   request.msg.NGetRQ.MessageID = assoc->nextMsgID++;
332   OFStandard::strlcpy(request.msg.NGetRQ.RequestedSOPClassUID, sopclassUID, sizeof(request.msg.NGetRQ.RequestedSOPClassUID));
333   OFStandard::strlcpy(request.msg.NGetRQ.RequestedSOPInstanceUID, sopinstanceUID, sizeof(request.msg.NGetRQ.RequestedSOPInstanceUID));
334   request.msg.NGetRQ.ListCount = 0;
335   if (attributeIdentifierList) request.msg.NGetRQ.ListCount = (int)numShorts;
336   request.msg.NGetRQ.AttributeIdentifierList = (DIC_US *)attributeIdentifierList;
337 
338   OFCondition cond = sendNRequest(presCtx, request, NULL, response, statusDetail, attributeListOut);
339   if (cond.good()) status = response.msg.NGetRSP.DimseStatus;
340   if (statusDetail) delete statusDetail;
341   return cond;
342 }
343 
344 
actionRQ(const char * sopclassUID,const char * sopinstanceUID,Uint16 actionTypeID,DcmDataset * actionInformation,Uint16 & status,DcmDataset * & actionReply)345 OFCondition DVPSPrintMessageHandler::actionRQ(
346     const char *sopclassUID,
347     const char *sopinstanceUID,
348     Uint16 actionTypeID,
349     DcmDataset *actionInformation,
350     Uint16& status,
351     DcmDataset* &actionReply)
352 {
353   if (assoc == NULL)
354   {
355     return DIMSE_ILLEGALASSOCIATION;
356   }
357   if ((sopclassUID==NULL)||(sopinstanceUID==NULL))
358   {
359     return DIMSE_NULLKEY;
360   }
361 
362   T_ASC_PresentationContextID presCtx = findAcceptedPC(sopclassUID);
363   if (presCtx == 0)
364   {
365     return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
366   }
367 
368   T_DIMSE_Message request;
369   T_DIMSE_Message response;
370   DcmDataset *statusDetail = NULL;
371 
372   // construct N-ACTION-RQ
373   request.CommandField = DIMSE_N_ACTION_RQ;
374   request.msg.NActionRQ.MessageID = assoc->nextMsgID++;
375   OFStandard::strlcpy(request.msg.NActionRQ.RequestedSOPClassUID, sopclassUID, sizeof(request.msg.NActionRQ.RequestedSOPClassUID));
376   OFStandard::strlcpy(request.msg.NActionRQ.RequestedSOPInstanceUID, sopinstanceUID, sizeof(request.msg.NActionRQ.RequestedSOPInstanceUID));
377   request.msg.NActionRQ.ActionTypeID = (DIC_US)actionTypeID;
378 
379   OFCondition cond = sendNRequest(presCtx, request, actionInformation, response, statusDetail, actionReply);
380   if (cond.good()) status = response.msg.NActionRSP.DimseStatus;
381   if (statusDetail) delete statusDetail;
382   return cond;
383 }
384 
deleteRQ(const char * sopclassUID,const char * sopinstanceUID,Uint16 & status)385 OFCondition DVPSPrintMessageHandler::deleteRQ(
386     const char *sopclassUID,
387     const char *sopinstanceUID,
388     Uint16& status)
389 {
390   if (assoc == NULL)
391   {
392     return DIMSE_ILLEGALASSOCIATION;
393   }
394   if ((sopclassUID==NULL)||(sopinstanceUID==NULL))
395   {
396     return DIMSE_NULLKEY;
397   }
398 
399   T_ASC_PresentationContextID presCtx = findAcceptedPC(sopclassUID);
400   if (presCtx == 0)
401   {
402     return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
403   }
404 
405   T_DIMSE_Message request;
406   T_DIMSE_Message response;
407   DcmDataset *statusDetail = NULL;
408   DcmDataset *attributeListOut = NULL;
409 
410   // construct N-DELETE-RQ
411   request.CommandField = DIMSE_N_DELETE_RQ;
412   request.msg.NDeleteRQ.MessageID = assoc->nextMsgID++;
413   OFStandard::strlcpy(request.msg.NDeleteRQ.RequestedSOPClassUID, sopclassUID, sizeof(request.msg.NDeleteRQ.RequestedSOPClassUID));
414   OFStandard::strlcpy(request.msg.NDeleteRQ.RequestedSOPInstanceUID, sopinstanceUID, sizeof(request.msg.NDeleteRQ.RequestedSOPInstanceUID));
415 
416   OFCondition cond = sendNRequest(presCtx, request, NULL, response, statusDetail, attributeListOut);
417   if (cond.good()) status = response.msg.NDeleteRSP.DimseStatus;
418   if (statusDetail) delete statusDetail;
419   if (attributeListOut) delete attributeListOut;  // should never happen
420   return cond;
421 }
422 
releaseAssociation()423 OFCondition DVPSPrintMessageHandler::releaseAssociation()
424 {
425   OFCondition result = EC_Normal;
426   if (assoc)
427   {
428     result = ASC_releaseAssociation(assoc);
429     ASC_destroyAssociation(&assoc);
430     ASC_dropNetwork(&net);
431     assoc = NULL;
432     net = NULL;
433   }
434   return result;
435 }
436 
abortAssociation()437 OFCondition DVPSPrintMessageHandler::abortAssociation()
438 {
439   OFCondition result = EC_Normal;
440   if (assoc)
441   {
442     result = ASC_abortAssociation(assoc);
443     ASC_destroyAssociation(&assoc);
444     ASC_dropNetwork(&net);
445     assoc = NULL;
446     net = NULL;
447   }
448   return result;
449 }
450 
findAcceptedPC(const char * sopclassuid)451 T_ASC_PresentationContextID DVPSPrintMessageHandler::findAcceptedPC(const char *sopclassuid)
452 {
453   if ((assoc==NULL)||(sopclassuid==NULL)) return 0;
454 
455   // if the SOP class is one of the Basic Grayscale Print Management Meta SOP Classes,
456   // look for a presentation context for Basic Grayscale Print.
457   OFString sopclass(sopclassuid);
458   if ((sopclass == UID_BasicFilmSessionSOPClass) ||
459       (sopclass == UID_BasicFilmBoxSOPClass) ||
460       (sopclass == UID_BasicGrayscaleImageBoxSOPClass) ||
461       (sopclass == UID_PrinterSOPClass)) sopclassuid = UID_BasicGrayscalePrintManagementMetaSOPClass;
462   return ASC_findAcceptedPresentationContextID(assoc, sopclassuid);
463 }
464 
465 
negotiateAssociation(DcmTransportLayer * tlayer,const char * myAEtitle,const char * peerAEtitle,const char * peerHost,int peerPort,long peerMaxPDU,OFBool negotiatePresentationLUT,OFBool negotiateAnnotationBox,OFBool implicitOnly)466 OFCondition DVPSPrintMessageHandler::negotiateAssociation(
467   DcmTransportLayer *tlayer,
468   const char *myAEtitle,
469   const char *peerAEtitle,
470   const char *peerHost,
471   int peerPort,
472   long peerMaxPDU,
473   OFBool negotiatePresentationLUT,
474   OFBool negotiateAnnotationBox,
475   OFBool implicitOnly)
476 {
477   if (assoc)
478   {
479     return makeDcmnetCondition(DIMSEC_ILLEGALASSOCIATION, OF_error, "association already in place");
480   }
481   if ((myAEtitle==NULL)||(peerAEtitle==NULL)||(peerHost==NULL))
482   {
483     return DIMSE_NULLKEY;
484   }
485 
486   T_ASC_Parameters *params=NULL;
487   DIC_NODENAME dnpeerHost;
488 
489   OFCondition cond = ASC_initializeNetwork(NET_REQUESTOR, 0, 30, &net);
490   if (cond.good()) cond = ASC_createAssociationParameters(&params, peerMaxPDU);
491 
492   if (tlayer && cond.good())
493   {
494     cond = ASC_setTransportLayer(net, tlayer, 0);
495     if (cond.good()) cond = ASC_setTransportLayerType(params, OFTrue /* use TLS */);
496   }
497 
498   if (cond.bad()) return cond;
499 
500   ASC_setAPTitles(params, myAEtitle, peerAEtitle, NULL);
501   sprintf(dnpeerHost, "%s:%d", peerHost, peerPort);
502   ASC_setPresentationAddresses(params, OFStandard::getHostName().c_str(), dnpeerHost);
503 
504   /* presentation contexts */
505   const char* transferSyntaxes[3];
506   int transferSyntaxCount = 0;
507 
508   if (implicitOnly)
509   {
510       transferSyntaxes[0] = UID_LittleEndianImplicitTransferSyntax;
511       transferSyntaxCount = 1;
512   } else {
513       /* gLocalByteOrder is defined in dcxfer.h */
514       if (gLocalByteOrder == EBO_LittleEndian) {
515           /* we are on a little endian machine */
516           transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax;
517           transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax;
518       } else {
519           /* we are on a big endian machine */
520           transferSyntaxes[0] = UID_BigEndianExplicitTransferSyntax;
521           transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
522       }
523       transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
524       transferSyntaxCount = 3;
525   }
526 
527   /* we always propose basic grayscale, presentation LUT and annotation box*/
528   if (cond.good()) cond = ASC_addPresentationContext(params, 1, UID_BasicGrayscalePrintManagementMetaSOPClass, transferSyntaxes, transferSyntaxCount);
529   if (negotiatePresentationLUT)
530   {
531     if (cond.good()) cond = ASC_addPresentationContext(params, 3, UID_PresentationLUTSOPClass, transferSyntaxes, transferSyntaxCount);
532   }
533 
534   if (negotiateAnnotationBox)
535   {
536     if (cond.good()) cond = ASC_addPresentationContext(params, 5, UID_BasicAnnotationBoxSOPClass, transferSyntaxes, transferSyntaxCount);
537   }
538 
539   /* create association */
540   DCMPSTAT_INFO("Requesting Association");
541 
542   if (cond.good())
543   {
544     cond = ASC_requestAssociation(net, params, &assoc);
545 
546     if (cond == DUL_ASSOCIATIONREJECTED)
547     {
548       OFString temp_str;
549       T_ASC_RejectParameters rej;
550       ASC_getRejectParameters(params, &rej);
551       DCMPSTAT_WARN("Association Rejected" << OFendl << ASC_printRejectParameters(temp_str, &rej));
552     } else {
553       if (cond.bad())
554       {
555         // if assoc is non-NULL, then params has already been moved into the
556         // assoc structure. Make sure we only delete once!
557         if (assoc) ASC_destroyAssociation(&assoc);
558         else if (params) ASC_destroyAssociationParameters(&params);
559 
560         if (net) ASC_dropNetwork(&net);
561         assoc = NULL;
562         net = NULL;
563         return cond;
564       }
565     }
566   }
567 
568   if ((cond.good()) && (0 == ASC_findAcceptedPresentationContextID(assoc, UID_BasicGrayscalePrintManagementMetaSOPClass)))
569   {
570     DCMPSTAT_WARN("Peer does not support Basic Grayscale Print Management, aborting association.");
571     abortAssociation();
572     cond = DIMSE_NOVALIDPRESENTATIONCONTEXTID;
573   }
574 
575   if (cond.good())
576   {
577     DCMPSTAT_INFO("Association accepted (Max Send PDV: " << assoc->sendPDVLength << ")");
578   } else {
579     // params is now an alias to assoc->params. Don't call ASC_destroyAssociationParameters.
580     if (assoc) ASC_destroyAssociation(&assoc);
581     if (net) ASC_dropNetwork(&net);
582     assoc = NULL;
583     net = NULL;
584   }
585 
586   return cond;
587 }
588 
printerSupportsPresentationLUT()589 OFBool DVPSPrintMessageHandler::printerSupportsPresentationLUT()
590 {
591   if ((assoc)&&(0 != ASC_findAcceptedPresentationContextID(assoc, UID_PresentationLUTSOPClass))) return OFTrue;
592   return OFFalse;
593 }
594 
printerSupportsAnnotationBox()595 OFBool DVPSPrintMessageHandler::printerSupportsAnnotationBox()
596 {
597   if ((assoc)&&(0 != ASC_findAcceptedPresentationContextID(assoc, UID_BasicAnnotationBoxSOPClass))) return OFTrue;
598   return OFFalse;
599 }
600