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