1 /*========================================================================= 2 3 Program: GDCM (Grassroots DICOM). A DICOM library 4 5 Copyright (c) 2006-2014 Mathieu Malaterre 6 All rights reserved. 7 See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. 8 9 This software is distributed WITHOUT ANY WARRANTY; without even 10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 11 PURPOSE. See the above copyright notice for more information. 12 13 =========================================================================*/ 14 15 #include "gdcmNormalizedNetworkFunctions.h" 16 17 #include <socket++/echo.h> 18 19 #include "gdcmReader.h" 20 #include "gdcmPrinter.h" 21 #include "gdcmAttribute.h" 22 #include "gdcmULConnectionManager.h" 23 #include "gdcmULConnection.h" 24 #include "gdcmDataSet.h" 25 #include "gdcmVersion.h" 26 #include "gdcmGlobal.h" 27 #include "gdcmSystem.h" 28 #include "gdcmUIDGenerator.h" 29 #include "gdcmWriter.h" 30 #include "gdcmSimpleSubjectWatcher.h" 31 #include "gdcmProgressEvent.h" 32 #include "gdcmQueryFactory.h" 33 #include "gdcmULWritingCallback.h" 34 #include "gdcmULBasicCallback.h" 35 #include "gdcmPresentationContextGenerator.h" 36 37 namespace gdcm 38 { 39 BaseQuery* ConstructQuery(const std::string & sopInstanceUID,const DataSet & queryds,ENQueryType queryType)40 NormalizedNetworkFunctions::ConstructQuery( const std::string & sopInstanceUID, 41 const DataSet& queryds, ENQueryType queryType /*= eMMPS*/ ) 42 { 43 BaseQuery* outQuery = nullptr ; 44 if( queryType == eCreateMMPS || queryType == eSetMMPS ) 45 outQuery = QueryFactory::ProduceQuery( sopInstanceUID, queryType ); 46 47 if (!outQuery) 48 { 49 gdcmErrorMacro( "Specify the query" ); 50 return nullptr; 51 } 52 53 outQuery->AddQueryDataSet(queryds); 54 55 // setup the special character set 56 std::vector<ECharSet> inCharSetType; 57 inCharSetType.push_back( QueryFactory::GetCharacterFromCurrentLocale() ); 58 DataElement de = QueryFactory::ProduceCharacterSetDataElement(inCharSetType); 59 std::string param ( de.GetByteValue()->GetPointer(), 60 de.GetByteValue()->GetLength() ); 61 outQuery->SetSearchParameter(de.GetTag(), param ); 62 63 // Print info: 64 if (Trace::GetDebugFlag()) 65 { 66 outQuery->Print( Trace::GetStream() ); 67 } 68 69 return outQuery; 70 } 71 72 bool NEventReport(const char * remote,uint16_t portno,const BaseQuery * query,std::vector<DataSet> & retDataSets,const char * aetitle,const char * call)73 NormalizedNetworkFunctions::NEventReport( const char *remote, uint16_t portno, 74 const BaseQuery* query, std::vector<DataSet> &retDataSets, 75 const char *aetitle, const char *call ) 76 { 77 (void)remote; (void)portno; (void)query; (void)retDataSets; (void)aetitle; (void)call; 78 return false ; 79 } 80 bool NGet(const char * remote,uint16_t portno,const BaseQuery * query,std::vector<DataSet> & retDataSets,const char * aetitle,const char * call)81 NormalizedNetworkFunctions::NGet( const char *remote, uint16_t portno, 82 const BaseQuery* query, std::vector<DataSet> &retDataSets, 83 const char *aetitle, const char *call ) 84 { 85 (void)remote; (void)portno; (void)query; (void)retDataSets; (void)aetitle; (void)call; 86 return false ; 87 } 88 bool NSet(const char * remote,uint16_t portno,const BaseQuery * query,std::vector<DataSet> & retDataSets,const char * aetitle,const char * call)89 NormalizedNetworkFunctions::NSet( const char *remote, uint16_t portno, 90 const BaseQuery* query, std::vector<DataSet> &retDataSets, 91 const char *aetitle, const char *call ) 92 { 93 if( !remote ) return false; 94 if( !aetitle ) 95 { 96 aetitle = "GDCMSCU"; 97 } 98 if( !call ) 99 { 100 call = "ANY-SCP"; 101 } 102 103 // $ findscu -v -d --aetitle ACME1 --call ACME_STORE -P -k 0010,0010="X*" 104 // dhcp-67-183 5678 patqry.dcm 105 // Add a query: 106 107 // Generate the PresentationContext array from the query UID: 108 PresentationContextGenerator generator; 109 if( !generator.GenerateFromUID( query->GetAbstractSyntaxUID() ) ) 110 { 111 gdcmErrorMacro( "Failed to generate pres context." ); 112 return false; 113 } 114 115 network::ULConnectionManager theManager; 116 if (!theManager.EstablishConnection(aetitle, call, remote, 0, portno, 1000, 117 generator.GetPresentationContexts())) 118 { 119 gdcmErrorMacro( "Failed to establish connection." ); 120 return false; 121 } 122 std::vector<DataSet> theDataSets; 123 std::vector<DataSet> theResponses; 124 network::ULBasicCallback theCallback; 125 theManager.SendNSet(query, &theCallback); 126 theDataSets = theCallback.GetDataSets(); 127 theResponses = theCallback.GetResponses(); 128 129 bool ret = false; // by default an error 130 if( theResponses.empty() ) 131 { 132 gdcmErrorMacro( "Failed to GetResponses." ); 133 return false; 134 } 135 assert( theResponses.size() >= 1 ); 136 // take the last one: 137 const DataSet &ds = theResponses[ theResponses.size() - 1 ]; // FIXME 138 assert ( ds.FindDataElement(Tag(0x0, 0x0900)) ); 139 Attribute<0x0,0x0900> at; 140 at.SetFromDataSet( ds ); 141 142 // Table CC.2.1-2 143 // STATUS VALUES 144 const uint16_t theVal = at.GetValue(); 145 switch( theVal ) 146 { 147 case 0x0: 148 gdcmDebugMacro( "The requested modification of the attribute values is performed." ); 149 // Append the new DataSet to the ret one: 150 retDataSets.insert( retDataSets.end(), theDataSets.begin(), theDataSets.end() ); 151 ret = true; 152 break; 153 case 0x1: 154 { 155 gdcmWarningMacro( "Requested optional Attributes are not supported." ); 156 } 157 break; 158 case 0xB305: 159 { 160 gdcmWarningMacro( "The UPS is already in the requested state of COMPLETED" ); 161 } 162 break; 163 case 0xC310: 164 { 165 gdcmErrorMacro( "Refused: The UPS is not in the \"IN PROGRESS\" state " ); 166 } 167 break; 168 case 0xC301: 169 { 170 gdcmErrorMacro( "Refused: The correct Transaction UID was not provided " ); 171 } 172 break; 173 case 0xC300: 174 { 175 gdcmErrorMacro( "Refused: The UPS may no longer be updated " ); 176 } 177 break; 178 case 0xC307: 179 { 180 gdcmErrorMacro( "Specified SOP Instance UID does not exist or is not a UPS Instance managed by this SCP " ); 181 } 182 break; 183 default: 184 break ; 185 } 186 theManager.BreakConnection(-1);//wait for a while for the connection to break, ie, infinite 187 188 return ret; 189 } 190 bool NAction(const char * remote,uint16_t portno,const BaseQuery * query,std::vector<DataSet> & retDataSets,const char * aetitle,const char * call)191 NormalizedNetworkFunctions::NAction( const char *remote, uint16_t portno, 192 const BaseQuery* query, std::vector<DataSet> &retDataSets, 193 const char *aetitle, const char *call ) 194 { 195 (void)remote; (void)portno; (void)query; (void)retDataSets; (void)aetitle; (void)call; 196 return false ; 197 } 198 bool NCreate(const char * remote,uint16_t portno,BaseQuery * query,std::vector<DataSet> & retDataSets,const char * aetitle,const char * call)199 NormalizedNetworkFunctions::NCreate( const char *remote, uint16_t portno, 200 BaseQuery* query, std::vector<DataSet> &retDataSets, 201 const char *aetitle, const char *call ) 202 { 203 if( !remote ) return false; 204 if( !aetitle ) 205 { 206 aetitle = "GDCMSCU"; 207 } 208 if( !call ) 209 { 210 call = "ANY-SCP"; 211 } 212 213 // $ findscu -v -d --aetitle ACME1 --call ACME_STORE -P -k 0010,0010="X*" 214 // dhcp-67-183 5678 patqry.dcm 215 // Add a query: 216 217 // Generate the PresentationContext array from the query UID: 218 PresentationContextGenerator generator; 219 if( !generator.GenerateFromUID( query->GetAbstractSyntaxUID() ) ) 220 { 221 gdcmErrorMacro( "Failed to generate pres context." ); 222 return false; 223 } 224 225 network::ULConnectionManager theManager; 226 if (!theManager.EstablishConnection(aetitle, call, remote, 0, portno, 1000, 227 generator.GetPresentationContexts())) 228 { 229 gdcmErrorMacro( "Failed to establish connection." ); 230 return false; 231 } 232 std::vector<DataSet> theDataSets; 233 std::vector<DataSet> theResponses; 234 //theDataSets = theManager.SendFind( query ); 235 network::ULBasicCallback theCallback; 236 theManager.SendNCreate(query, &theCallback); 237 theDataSets = theCallback.GetDataSets(); 238 theResponses = theCallback.GetResponses(); 239 240 bool ret = false; // by default an error 241 if( theResponses.empty() ) 242 { 243 gdcmErrorMacro( "Failed to GetResponses." ); 244 return false; 245 } 246 assert( theResponses.size() >= 1 ); 247 // take the last one: 248 const DataSet &ds = theResponses[ theResponses.size() - 1 ]; // FIXME 249 assert ( ds.FindDataElement(Tag(0x0, 0x0900)) ); 250 Attribute<0x0,0x0900> at; 251 at.SetFromDataSet( ds ); 252 253 // Table CC.2.1-2 254 // STATUS VALUES 255 const uint16_t theVal = at.GetValue(); 256 switch( theVal ) 257 { 258 case 0x0: // The requested state change was performed 259 gdcmDebugMacro( "The requested state change was performed." ); 260 // Append the new DataSet to the ret one: 261 retDataSets.insert( retDataSets.end(), theDataSets.begin(), theDataSets.end() ); 262 { 263 Attribute<0x0000,0x1000> sopInstanceUIDAt; 264 sopInstanceUIDAt.SetFromDataSet( ds ); 265 query->SetSOPInstanceUID( sopInstanceUIDAt.GetValue() ); 266 } 267 ret = true; 268 break; 269 case 0xB304: // The UPS is already in the requested state of CANCELED 270 { 271 gdcmWarningMacro( "Offending Element: The UPS is already in the requested state of CANCELED" ); 272 } 273 break; 274 case 0xB306: // The UPS is already in the requested state of COMPLETED 275 { 276 gdcmWarningMacro( "The UPS is already in the requested state of COMPLETED" ); 277 } 278 break; 279 case 0xC300: 280 { 281 gdcmErrorMacro( "Refused: The UPS may no longer be updated " ); 282 } 283 break; 284 case 0xC301: 285 { 286 gdcmErrorMacro( "Refused: The correct Transaction UID was not provided " ); 287 } 288 break; 289 case 0xC302: 290 { 291 gdcmErrorMacro( "Refused: The UPS is already IN PROGRESS " ); 292 } 293 break; 294 case 0xC303: 295 { 296 gdcmErrorMacro( "Refused: The UPS may only become SCHEDULED via NCREATE, not N-SET or N-ACTION " ); 297 } 298 break; 299 case 0xC304: 300 { 301 gdcmErrorMacro( "Refused: The UPS has not met final state requirements for the requested state change " ); 302 } 303 break; 304 case 0xC307: 305 { 306 gdcmErrorMacro( "Specified SOP Instance UID does not exist or is not a UPS Instance managed by this SCP " ); 307 } 308 break; 309 case 0xC310: 310 { 311 gdcmErrorMacro( "Refused: The UPS is not yet in the \"IN PROGRESS\" state " ); 312 } 313 break; 314 315 default: 316 break ; 317 } 318 theManager.BreakConnection(-1);//wait for a while for the connection to break, ie, infinite 319 320 return ret; 321 } 322 323 bool NDelete(const char * remote,uint16_t portno,const BaseQuery * query,std::vector<DataSet> & retDataSets,const char * aetitle,const char * call)324 NormalizedNetworkFunctions::NDelete( const char *remote, uint16_t portno, 325 const BaseQuery* query, std::vector<DataSet> &retDataSets, 326 const char *aetitle, const char *call ) 327 { 328 (void)remote; (void)portno; (void)query; (void)retDataSets; (void)aetitle; (void)call; 329 return false ; 330 } 331 } // end namespace gdcm 332