1 /*
2 *
3 * Copyright (C) 1993-2020, 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: dcmqrdb
15 *
16 * Author: Marco Eichelberg / Ralph Meyer
17 *
18 * Purpose: class DcmQueryRetrieveConfig
19 *
20 */
21
22
23 #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
24 #include "dcmtk/dcmqrdb/dcmqrcnf.h"
25
26 /* includes */
27 #define INCLUDE_CSTDIO
28 #define INCLUDE_CCTYPE
29 #define INCLUDE_CSTDARG
30 #define INCLUDE_CSTRING
31 #define INCLUDE_CLIMITS
32 #include "dcmtk/ofstd/ofstdinc.h"
33 #include "dcmtk/ofstd/ofcmdln.h"
34 #include "dcmtk/ofstd/ofmap.h"
35 #include "dcmtk/ofstd/ofchrenc.h"
36
37 OFLogger DCM_dcmqrdbLogger = OFLog::getLogger("dcmtk.dcmqrdb");
38
freePeer(OFMap<const void *,OFBool> & pointersToFree,struct DcmQueryRetrieveConfigPeer * entry)39 static void freePeer(OFMap<const void *, OFBool> &pointersToFree, struct DcmQueryRetrieveConfigPeer *entry)
40 {
41 // Hack to make sure we don't double-free
42 pointersToFree[entry->ApplicationTitle] = OFTrue;
43 pointersToFree[entry->HostName] = OFTrue;
44 }
45
freeConfigAEEntry(OFMap<const void *,OFBool> & pointersToFree,struct DcmQueryRetrieveConfigAEEntry * entry)46 static void freeConfigAEEntry(OFMap<const void *, OFBool> &pointersToFree, struct DcmQueryRetrieveConfigAEEntry *entry)
47 {
48 for (int i = 0; i < entry->noOfPeers; i++) {
49 freePeer(pointersToFree, &entry->Peers[i]);
50 }
51 free(OFconst_cast(char *, entry->ApplicationTitle));
52 free(OFconst_cast(char *, entry->StorageArea));
53 free(OFconst_cast(char *, entry->Access));
54 free(entry->StorageQuota);
55 free(entry->Peers);
56 }
57
freeConfigHostEntry(OFMap<const void *,OFBool> & pointersToFree,struct DcmQueryRetrieveConfigHostEntry * entry)58 static void freeConfigHostEntry(OFMap<const void *, OFBool> &pointersToFree, struct DcmQueryRetrieveConfigHostEntry *entry)
59 {
60 for (int i = 0; i< entry->noOfPeers; i++) {
61 freePeer(pointersToFree, &entry->Peers[i]);
62 }
63 free(OFconst_cast(char *, entry->SymbolicName));
64 free(entry->Peers);
65 }
66
DcmQueryRetrieveCharacterSetOptions()67 DcmQueryRetrieveCharacterSetOptions::DcmQueryRetrieveCharacterSetOptions()
68 : characterSet()
69 , flags(0)
70 , conversionFlags(0)
71 {
72
73 }
74
parseOptions(const char * mnemonic,char * valueptr)75 OFBool DcmQueryRetrieveCharacterSetOptions::parseOptions(const char* mnemonic, char* valueptr)
76 {
77 struct RAIIFree
78 {
79 RAIIFree(char* p) : ptr(p) {}
80 ~RAIIFree() {free(ptr);}
81 char* ptr;
82 };
83 if (strcmp(mnemonic,"SpecificCharacterSet") != 0)
84 return OFFalse;
85 characterSet.clear();
86 flags = Configured;
87 conversionFlags = 0;
88 for (char* c = DcmQueryRetrieveConfig::parsevalues(&valueptr); c;
89 c = DcmQueryRetrieveConfig::parsevalues(&valueptr)) {
90 // ensure free is called when this scope is left
91 RAIIFree cleanup(c);
92 if (!strcmp(c, "override")) {
93 flags |= Override;
94 } else if(!strcmp(c, "fallback")) {
95 flags |= Fallback;
96 } else if(!strcmp(c, "abort")) {
97 conversionFlags |= OFCharacterEncoding::AbortTranscodingOnIllegalSequence;
98 } else if(!strcmp(c, "discard")) {
99 conversionFlags |= OFCharacterEncoding::DiscardIllegalSequences;
100 } else if(!strcmp(c, "transliterate")) {
101 conversionFlags |= OFCharacterEncoding::TransliterateIllegalSequences;
102 } else {
103 characterSet = c;
104 }
105 }
106 return OFTrue;
107 }
108
~DcmQueryRetrieveConfig()109 DcmQueryRetrieveConfig::~DcmQueryRetrieveConfig()
110 {
111 // There can be more than one DcmQueryRetrieveConfigPeer which points to the
112 // same strings. To make sure that we don't free them more than once, we use
113 // a std::set<void*> which contains the pointers which we have to free.
114 // This happens in DcmQueryRetrieveConfig::readPeerList() while handling
115 // symbolic names (DcmQueryRetrieveConfigPeer gets copied via memcpy()).
116 //
117 // TODO: Since OFSet and std::set have nothing in common, we have to fake a
118 // set via a map.
119 OFMap<const void *, OFBool> pointersToFree;
120 OFMap<const void *, OFBool>::const_iterator it;
121 int i;
122
123 for (i = 0; i < CNF_Config.noOfAEEntries; i++) {
124 freeConfigAEEntry(pointersToFree, &CNF_Config.AEEntries[i]);
125 }
126 free(CNF_Config.AEEntries);
127
128 for (i = 0; i < CNF_HETable.noOfHostEntries; i++) {
129 freeConfigHostEntry(pointersToFree, &CNF_HETable.HostEntries[i]);
130 }
131 free(CNF_HETable.HostEntries);
132
133 for (i = 0; i < CNF_VendorTable.noOfHostEntries; i++) {
134 freeConfigHostEntry(pointersToFree, &CNF_VendorTable.HostEntries[i]);
135 }
136 free(CNF_VendorTable.HostEntries);
137
138 for (it = pointersToFree.begin(); it != pointersToFree.end(); ++it) {
139 free(OFconst_cast(void *, it->first));
140 }
141 }
142
aeTitlesForPeer(const char * hostName,const char *** aeTitleList) const143 int DcmQueryRetrieveConfig::aeTitlesForPeer(const char *hostName, const char *** aeTitleList) const
144 {
145 int n = 0;
146 int i, j, k;
147 const int chunkSize = 1;
148 int maxAlloc = 0;
149 const char *hname;
150 const char *aetitle;
151 int found;
152
153 *aeTitleList = (const char**)malloc(chunkSize*sizeof(const char*));
154 maxAlloc = chunkSize;
155
156 /* collect up titles for peer, search in host table */
157 for (i=0; i<CNF_HETable.noOfHostEntries; i++) {
158 for (j=0; j<CNF_HETable.HostEntries[i].noOfPeers; j++) {
159 hname = CNF_HETable.HostEntries[i].Peers[j].HostName;
160 aetitle = CNF_HETable.HostEntries[i].Peers[j].ApplicationTitle;
161 #ifdef HAVE_PROTOTYPE_STRCASECMP
162 if (strcasecmp(hname, hostName) == 0) { /* DNS is not case-sensitive */
163 #elif defined(HAVE_PROTOTYPE__STRICMP)
164 if (_stricmp(hname, hostName) == 0) {
165 #else
166 if (strcmp(hname, hostName) == 0) { /* fallback if case insensitive compare is unavailable */
167 #endif
168 /* found an entry for peer host */
169 /* make sure its not already in list */
170 found = 0;
171 for (k=0; !found && k<n; k++) {
172 found = (strcmp((*aeTitleList)[k], aetitle) == 0);
173 }
174 if (!found) {
175 if (n >= maxAlloc) {
176 *aeTitleList = (const char**)realloc(*aeTitleList,
177 (maxAlloc + chunkSize)*sizeof(const char*));
178 maxAlloc += chunkSize;
179 }
180 (*aeTitleList)[n] = aetitle;
181
182 n++;
183 }
184 }
185 }
186 }
187 /* collect up titles for peer, search in AE table */
188 for (i=0; i<CNF_Config.noOfAEEntries; i++) {
189 for (j=0; j<CNF_Config.AEEntries[i].noOfPeers; j++) {
190 hname = CNF_Config.AEEntries[i].Peers[j].HostName;
191 aetitle = CNF_Config.AEEntries[i].Peers[j].ApplicationTitle;
192
193 #ifdef HAVE_PROTOTYPE_STRCASECMP
194 if (strcasecmp(hname, hostName) == 0) { /* DNS is not case-sensitive */
195 #elif defined(HAVE_PROTOTYPE__STRICMP)
196 if (_stricmp(hname, hostName) == 0) {
197 #else
198 if (strcmp(hname, hostName) == 0) { /* fallback if case insensitive compare is unavailable */
199 #endif
200 /* found an entry for peer host */
201 /* make sure its not already in list */
202 found = 0;
203 for (k=0; !found && k<n; k++) {
204 found = (strcmp((*aeTitleList)[k], aetitle) == 0);
205 }
206 if (!found) {
207 if (n >= maxAlloc) {
208 *aeTitleList = (const char**)realloc(*aeTitleList,
209 (maxAlloc + chunkSize)*sizeof(const char*));
210 maxAlloc += chunkSize;
211 }
212 (*aeTitleList)[n] = aetitle;
213
214 n++;
215 }
216 }
217 }
218 }
219
220 if (n == 0) {
221 free(*aeTitleList);
222 *aeTitleList = NULL;
223 }
224 return n;
225 }
226
227
228 int DcmQueryRetrieveConfig::ctnTitles(const char *** ctnTitleList) const
229 {
230 int i;
231 int n = 0;
232
233 n = CNF_Config.noOfAEEntries;
234 *ctnTitleList = (const char**)malloc(n * sizeof(const char*));
235
236 for (i=0; i<n; i++) {
237 (*ctnTitleList)[i] = CNF_Config.AEEntries[i].ApplicationTitle;
238 }
239 return n;
240 }
241
242
243 int DcmQueryRetrieveConfig::aeTitlesForSymbolicName(const char *symbolicName, const char *** aeTitleList) const
244 {
245 int i = 0;
246 int j = 0;
247 int n = 0;
248
249 for (i=0; i<CNF_HETable.noOfHostEntries; i++) {
250 if (strcmp(symbolicName, CNF_HETable.HostEntries[i].SymbolicName)==0) {
251 n = CNF_HETable.HostEntries[i].noOfPeers;
252 *aeTitleList = (const char**)malloc(n * sizeof(const char*));
253 for (j=0; j<n; j++) {
254 (*aeTitleList)[j] =
255 CNF_HETable.HostEntries[i].Peers[j].ApplicationTitle;
256 }
257 return n;
258 }
259 }
260 return 0;
261
262 }
263
264 const char *DcmQueryRetrieveConfig::vendorForPeerAETitle(const char *peerAETitle) const
265 {
266 int i = 0;
267 int j = 0;
268
269 for (i=0; i<CNF_VendorTable.noOfHostEntries; i++) {
270 for (j=0; j<CNF_VendorTable.HostEntries[i].noOfPeers; j++) {
271 if (strcmp(peerAETitle,
272 CNF_VendorTable.HostEntries[i].Peers[j].ApplicationTitle)==0) {
273 return CNF_VendorTable.HostEntries[i].SymbolicName;
274 }
275 }
276 }
277 return NULL;
278 }
279
280 int DcmQueryRetrieveConfig::countCtnTitles() const
281 {
282 return CNF_Config.noOfAEEntries;
283 }
284
285
286 void DcmQueryRetrieveConfig::initConfigStruct()
287 {
288 UserName_ = "";
289 GroupName_ = "";
290 networkTCPPort_ = 104;
291 maxPDUSize_ = 16384;
292 maxAssociations_ = 16;
293 CNF_Config.noOfAEEntries = 0;
294 CNF_HETable.noOfHostEntries = 0;
295 CNF_VendorTable.noOfHostEntries = 0;
296 }
297
298
299 void DcmQueryRetrieveConfig::panic(const char *fmt, ...)
300 {
301 va_list ap;
302 va_start(ap, fmt);
303
304 #if defined(HAVE_VSNPRINTF) && defined(HAVE_PROTOTYPE_VSNPRINTF)
305 char buf[4096];
306
307 #ifdef HAVE_PROTOTYPE_STD__VSNPRINTF
308 std::vsnprintf(buf, sizeof(buf), fmt, ap);
309 #else
310 vsnprintf(buf, sizeof(buf), fmt, ap);
311 #endif
312
313 // Since we can't do anything about a too small buffer for vsnprintf(), we
314 // ignore it. But we do make sure the buffer is null-terminated!
315 buf[4095] = '\0';
316
317 DCMQRDB_ERROR("CONFIG Error: " << buf << "!");
318 #else
319 fprintf(stderr, "CONFIG Error: ");
320 vfprintf(stderr, fmt, ap);
321 fprintf(stderr, "!\n");
322 #endif
323 va_end(ap);
324 }
325
326
327 int DcmQueryRetrieveConfig::readConfigLines(FILE *cnffp)
328 {
329 int lineno = 0, /* line counter */
330 error = 0; /* error flag */
331 char rcline[512], /* line in configuration file */
332 mnemonic[512], /* mnemonic in line */
333 value[512], /* parameter value */
334 *valueptr; /* pointer to value list */
335 char *c;
336
337 // read all lines from configuration file
338 while (fgets(rcline, sizeof(rcline), cnffp)) {
339 lineno++;
340 if (rcline[0] == '#' || rcline[0] == 10 || rcline[0] == 13)
341 continue; /* comment or blank line */
342
343 if (sscanf(rcline, "%s", mnemonic) != 1)
344 continue; /* ignore lines containing only whitespace */
345
346 valueptr = skipmnemonic(rcline);
347
348 if (!strcmp("ApplicationTitle", mnemonic)) {
349 // ignore this entry which was used (really?) in previous versions
350 }
351 else if (!strcmp("ApplicationContext", mnemonic)) {
352 // ignore this entry which was used (really?) in previous versions
353 }
354 else if (!strcmp("ImplementationClass", mnemonic)) {
355 // ignore this entry which was used (really?) in previous versions
356 }
357 else if (!strcmp("ImplementationVersion", mnemonic)) {
358 // ignore this entry which was used (really?) in previous versions
359 }
360 else if (!strcmp("NetworkType", mnemonic)) {
361 // ignore this entry which was used (really?) in previous versions
362 }
363 else if (!strcmp("UserName", mnemonic)) {
364 c = parsevalues(&valueptr);
365 UserName_ = c;
366 free(c);
367 }
368 else if (!strcmp("GroupName", mnemonic)) {
369 c = parsevalues(&valueptr);
370 GroupName_ = c;
371 free(c);
372 }
373 else if (!strcmp("NetworkTCPPort", mnemonic)) {
374 sscanf(valueptr, "%d", &networkTCPPort_);
375 }
376 else if (!strcmp("MaxPDUSize", mnemonic)) {
377 unsigned long ul = 0;
378 sscanf(valueptr, "%lu", &ul);
379 maxPDUSize_ = OFstatic_cast(Uint32, ul);
380 }
381 else if (!strcmp("MaxAssociations", mnemonic)) {
382 sscanf(valueptr, "%d", &maxAssociations_);
383 }
384 else if (!strcmp("Display", mnemonic))
385 {
386 // ignore this entry which was needed for ctndisp
387 }
388 else if (!strcmp("DisplayPort", mnemonic))
389 {
390 // ignore this entry which was needed for ctndisp
391 }
392 else if (characterSetOptions_.parseOptions(mnemonic, valueptr))
393 {
394 // already handled by parseOptions(), nothing else to do
395 }
396 else if (!strcmp("HostTable", mnemonic)) {
397 sscanf(valueptr, "%s", value);
398 if (!strcmp("BEGIN", value)) {
399 if (!readHostTable(cnffp, &lineno))
400 error = 1;
401 }
402 else if (!strcmp("END", value)) {
403 panic("No \"HostTable BEGIN\" before END in configuration file, line %d", lineno);
404 error = 1;
405 }
406 else {
407 panic("Unknown HostTable status \"%s\" in configuration file, line %d", value, lineno);
408 error = 1;
409 }
410 }
411 else if (!strcmp("VendorTable", mnemonic)) {
412 sscanf(valueptr, "%s", value);
413 if (!strcmp("BEGIN", value)) {
414 if (!readVendorTable(cnffp, &lineno))
415 error = 1;
416 }
417 else if (!strcmp("END", value)) {
418 panic("No \"VendorTable BEGIN\" before END in configuration file, line %d", lineno);
419 error = 1;
420 }
421 else {
422 panic("Unknown VendorTable status \"%s\" in configuration file, line %d", value, lineno);
423 error = 1;
424 }
425 }
426 else if (!strcmp("AETable", mnemonic)) {
427 sscanf(valueptr, "%s", value);
428 if (!strcmp("BEGIN", value)) {
429 if (!readAETable(cnffp, &lineno))
430 error = 1;
431 }
432 else if (!strcmp("END", value)) {
433 panic("No \"AETable BEGIN\" before END in configuration file, line %d", lineno);
434 error = 1;
435 }
436 else {
437 panic("Unknown AETable status \"%s\" in configuration file, line %d", value, lineno);
438 error = 1;
439 }
440 }
441 else {
442 panic("Unknown mnemonic \"%s\" in configuration file, line %d", mnemonic, lineno);
443 error = 1;
444 }
445 }
446
447 return(error ? 0 : 1);
448 }
449
450
451 int DcmQueryRetrieveConfig::readHostTable(FILE *cnffp, int *lineno)
452 {
453 int error = 0, /* error flag */
454 end = 0, /* end flag */
455 noOfPeers; /* number of peers for entry */
456 char rcline[512], /* line in configuration file */
457 mnemonic[512], /* mnemonic in line */
458 value[512], /* parameter value */
459 *lineptr; /* pointer to line */
460 DcmQueryRetrieveConfigHostEntry *helpentry;
461
462 // read certain lines from configuration file
463 while (fgets(rcline, sizeof(rcline), cnffp)) {
464 (*lineno)++;
465 if (rcline[0] == '#' || rcline[0] == 10 || rcline[0] == 13)
466 continue; /* comment or blank line */
467
468 sscanf(rcline, "%s %s", mnemonic, value);
469 if (!strcmp("HostTable", mnemonic)) {
470 if (!strcmp("END", value)) {
471 end = 1;
472 break;
473 }
474 else {
475 panic("Illegal HostTable status \"%s\" in configuration file, line %d", value, *lineno);
476 error = 1;
477 break;
478 }
479 }
480
481 lineptr = rcline;
482 CNF_HETable.noOfHostEntries++;
483 if ((helpentry = (DcmQueryRetrieveConfigHostEntry *)malloc(CNF_HETable.noOfHostEntries * sizeof(DcmQueryRetrieveConfigHostEntry))) == NULL)
484 panic("Memory allocation 1 (%d)", CNF_HETable.noOfHostEntries);
485 if (CNF_HETable.noOfHostEntries - 1) {
486 memcpy((char*)helpentry, (char*)CNF_HETable.HostEntries, (CNF_HETable.noOfHostEntries - 1) *sizeof(DcmQueryRetrieveConfigHostEntry));
487 free(CNF_HETable.HostEntries);
488 }
489 CNF_HETable.HostEntries = helpentry;
490
491 CNF_HETable.HostEntries[CNF_HETable.noOfHostEntries - 1].SymbolicName = parsevalues(&lineptr);
492 CNF_HETable.HostEntries[CNF_HETable.noOfHostEntries - 1].Peers = readPeerList(&lineptr, &noOfPeers);
493 CNF_HETable.HostEntries[CNF_HETable.noOfHostEntries - 1].noOfPeers = noOfPeers;
494 if (!noOfPeers)
495 error = 1;
496 }
497
498 if (!end) {
499 error = 1;
500 panic("No \"HostTable END\" in configuration file, line %d", *lineno);
501 }
502 return(error ? 0 : 1);
503 }
504
505
506 int DcmQueryRetrieveConfig::readVendorTable(FILE *cnffp, int *lineno)
507 {
508 int error = 0, /* error flag */
509 end = 0, /* end flag */
510 noOfPeers; /* number of peers for entry */
511 char rcline[512], /* line in configuration file */
512 mnemonic[512], /* mnemonic in line */
513 value[512], /* parameter value */
514 *lineptr; /* pointer to line */
515 DcmQueryRetrieveConfigHostEntry *helpentry;
516
517 // read certain lines from configuration file
518 while (fgets(rcline, sizeof(rcline), cnffp)) {
519 (*lineno)++;
520 if (rcline[0] == '#' || rcline[0] == 10 || rcline[0] == 13)
521 continue; /* comment or blank line */
522
523 sscanf(rcline, "%s %s", mnemonic, value);
524 if (!strcmp("VendorTable", mnemonic)) {
525 if (!strcmp("END", value)) {
526 end = 1;
527 break;
528 }
529 else {
530 panic("Illegal VendorTable status \"%s\" in configuration file, line %d", value, *lineno);
531 error = 1;
532 break;
533 }
534 }
535
536 lineptr = rcline;
537 CNF_VendorTable.noOfHostEntries++;
538 if ((helpentry = (DcmQueryRetrieveConfigHostEntry *)malloc(CNF_VendorTable.noOfHostEntries * sizeof(DcmQueryRetrieveConfigHostEntry))) == NULL)
539 panic("Memory allocation 2 (%d)", CNF_VendorTable.noOfHostEntries);
540 if (CNF_VendorTable.noOfHostEntries - 1) {
541 memcpy((char*)helpentry, (char*)CNF_VendorTable.HostEntries, (CNF_VendorTable.noOfHostEntries - 1) *sizeof(DcmQueryRetrieveConfigHostEntry));
542 free(CNF_VendorTable.HostEntries);
543 }
544 CNF_VendorTable.HostEntries = helpentry;
545
546 CNF_VendorTable.HostEntries[CNF_VendorTable.noOfHostEntries - 1].SymbolicName = parsevalues(&lineptr);
547 CNF_VendorTable.HostEntries[CNF_VendorTable.noOfHostEntries - 1].Peers = readPeerList(&lineptr, &noOfPeers);
548 CNF_VendorTable.HostEntries[CNF_VendorTable.noOfHostEntries - 1].noOfPeers = noOfPeers;
549 if (!noOfPeers)
550 error = 1;
551 }
552
553 if (!end) {
554 error = 1;
555 panic("No \"VendorTable END\" in configuration file, line %d", *lineno);
556 }
557 return(error ? 0 : 1);
558 }
559
560
561 int DcmQueryRetrieveConfig::readAETable(FILE *cnffp, int *lineno)
562 {
563 int error = 0, /* error flag */
564 end = 0, /* end flag */
565 noOfAEEntries = 0; /* number of AE entries */
566 char rcline[512], /* line in configuration file */
567 mnemonic[512], /* mnemonic in line */
568 value[512], /* parameter value */
569 *lineptr; /* pointer to line */
570 DcmQueryRetrieveConfigAEEntry *helpentry;
571
572 // read certain lines from configuration file
573 while (fgets(rcline, sizeof(rcline), cnffp)) {
574 (*lineno)++;
575 if (rcline[0] == '#' || rcline[0] == 10 || rcline[0] == 13)
576 continue; /* comment or blank line */
577
578 sscanf(rcline, "%s %s", mnemonic, value);
579 if (!strcmp("AETable", mnemonic)) {
580 if (!strcmp("END", value)) {
581 end = 1;
582 break;
583 }
584 else {
585 panic("Illegal AETable status \"%s\" in configuration file, line %d", value, *lineno);
586 error = 1;
587 break;
588 }
589 }
590
591 lineptr = rcline;
592 noOfAEEntries++;
593 if ((helpentry = (DcmQueryRetrieveConfigAEEntry *)malloc(noOfAEEntries * sizeof(DcmQueryRetrieveConfigAEEntry))) == NULL)
594 panic("Memory allocation 3 (%d)", noOfAEEntries);
595 if (noOfAEEntries - 1) {
596 memcpy((char*)helpentry, (char*)CNF_Config.AEEntries, (noOfAEEntries - 1) *sizeof(DcmQueryRetrieveConfigAEEntry));
597 free(CNF_Config.AEEntries);
598 }
599 CNF_Config.AEEntries = helpentry;
600
601 CNF_Config.AEEntries[noOfAEEntries - 1].ApplicationTitle = parsevalues(&lineptr);
602 CNF_Config.AEEntries[noOfAEEntries - 1].StorageArea = parsevalues(&lineptr);
603 CNF_Config.AEEntries[noOfAEEntries - 1].Access = parsevalues(&lineptr);
604 CNF_Config.AEEntries[noOfAEEntries - 1].StorageQuota = parseQuota(&lineptr);
605 CNF_Config.AEEntries[noOfAEEntries - 1].Peers = parsePeers(&lineptr, &CNF_Config.AEEntries[noOfAEEntries - 1].noOfPeers);
606
607 // check the validity of the storage quota and peers values before continuing
608 if (CNF_Config.AEEntries[noOfAEEntries - 1].StorageQuota->maxStudies == 0 ||
609 CNF_Config.AEEntries[noOfAEEntries - 1].StorageQuota->maxBytesPerStudy == 0 ||
610 CNF_Config.AEEntries[noOfAEEntries - 1].noOfPeers == 0) {
611 error = 1;
612 }
613 }
614
615 if (!end) {
616 error = 1;
617 panic("No \"AETable END\" in configuration file, line %d", *lineno);
618 }
619 CNF_Config.noOfAEEntries = noOfAEEntries;
620 return(error ? 0 : 1);
621 }
622
623
624 DcmQueryRetrieveConfigQuota *DcmQueryRetrieveConfig::parseQuota(char **valuehandle)
625 {
626 int studies;
627 char *helpvalue,
628 helpval[512];
629 DcmQueryRetrieveConfigQuota *helpquota;
630
631 if ((helpquota = (DcmQueryRetrieveConfigQuota *)malloc(sizeof(DcmQueryRetrieveConfigQuota))) == NULL)
632 panic("Memory allocation 4");
633 helpvalue = parsevalues(valuehandle);
634 if (helpvalue)
635 {
636 sscanf(helpvalue, "%d , %s", &studies, helpval);
637 helpquota->maxStudies = studies;
638 helpquota->maxBytesPerStudy = quota(helpval);
639 } else {
640 helpquota->maxStudies = 0;
641 helpquota->maxBytesPerStudy = 0;
642 }
643 free(helpvalue);
644
645 return(helpquota);
646 }
647
648
649 DcmQueryRetrieveConfigPeer *DcmQueryRetrieveConfig::parsePeers(char **valuehandle, int *peers)
650 {
651 char *helpvalue;
652 char *valueptr = *valuehandle;
653
654 helpvalue = parsevalues(valuehandle);
655
656 if (!helpvalue) {
657 *peers = 0; // indicates error to caller
658 return NULL;
659 }
660
661 if (!strcmp("ANY", helpvalue)) { /* keyword ANY used */
662 free(helpvalue);
663 *peers = -1;
664 return((DcmQueryRetrieveConfigPeer *) 0);
665 }
666
667 free(helpvalue); /* regular peer list */
668 return(readPeerList(&valueptr, peers));
669 }
670
671
672 DcmQueryRetrieveConfigPeer *DcmQueryRetrieveConfig::readPeerList(char **valuehandle, int *peers)
673 {
674 int i,
675 found,
676 noOfPeers = 0;
677 char *helpvalue;
678 DcmQueryRetrieveConfigPeer *helppeer,
679 *peerlist = NULL;
680
681 while((helpvalue = parsevalues(valuehandle)) != NULL) {
682 found = 0;
683 if (strchr(helpvalue, ',') == NULL) { /* symbolic name */
684 if (!CNF_HETable.noOfHostEntries) {
685 panic("No symbolic names defined");
686 *peers = 0;
687 free(helpvalue);
688 return((DcmQueryRetrieveConfigPeer *) 0);
689 }
690 for(i = 0; i < CNF_HETable.noOfHostEntries; i++) {
691 if (!strcmp(CNF_HETable.HostEntries[i].SymbolicName, helpvalue)) {
692 found = 1;
693 break;
694 }
695 }
696 if (!found) {
697 panic("Symbolic name \"%s\" not defined", helpvalue);
698 *peers = 0;
699 free(helpvalue);
700 return((DcmQueryRetrieveConfigPeer *) 0);
701 }
702
703 noOfPeers += CNF_HETable.HostEntries[i].noOfPeers;
704 if ((helppeer = (DcmQueryRetrieveConfigPeer *)malloc(noOfPeers * sizeof(DcmQueryRetrieveConfigPeer))) == NULL)
705 panic("Memory allocation 5 (%d)", noOfPeers);
706 if (noOfPeers - CNF_HETable.HostEntries[i].noOfPeers) {
707 memcpy((char*)helppeer, (char*)peerlist, (noOfPeers - CNF_HETable.HostEntries[i].noOfPeers) * sizeof(DcmQueryRetrieveConfigPeer));
708 free(peerlist);
709 }
710 peerlist = helppeer;
711 memcpy((char*)(peerlist + (noOfPeers - CNF_HETable.HostEntries[i].noOfPeers)), (char*)CNF_HETable.HostEntries[i].Peers, CNF_HETable.HostEntries[i].noOfPeers * sizeof(DcmQueryRetrieveConfigPeer));
712 }
713
714 else { /* peer */
715 noOfPeers++;
716 if ((helppeer = (DcmQueryRetrieveConfigPeer *)malloc(noOfPeers * sizeof(DcmQueryRetrieveConfigPeer))) == NULL)
717 panic("Memory allocation 6 (%d)", noOfPeers);
718 if (noOfPeers - 1) {
719 memcpy((char*)helppeer, (char*)peerlist, (noOfPeers - 1) *sizeof(DcmQueryRetrieveConfigPeer));
720 free(peerlist);
721 }
722 peerlist = helppeer;
723
724 char *tempvalue = helpvalue;
725 peerlist[noOfPeers - 1].ApplicationTitle = parsevalues(&helpvalue);
726 peerlist[noOfPeers - 1].HostName = parsevalues(&helpvalue);
727 peerlist[noOfPeers - 1].PortNumber = atoi(helpvalue);
728 helpvalue = tempvalue;
729 }
730 free(helpvalue);
731 }
732 *peers = noOfPeers;
733 return(peerlist);
734 }
735
736
737 char *DcmQueryRetrieveConfig::skipmnemonic (char *rcline)
738 {
739 char *help = rcline;
740
741 while(*help != '\0') { /* leading spaces */
742 if (isgap(*help)) help++;
743 else break;
744 }
745 while(*help != '\0') {
746 if (!isspace(OFstatic_cast(unsigned char, *help))) help++; /* Mnemonic */
747 else break;
748 }
749 while(*help != '\0') {
750 if (isgap(*help)) help++; /* Gap */
751 else break;
752 }
753 return(help);
754 }
755
756
757 int DcmQueryRetrieveConfig::isgap (char gap)
758 {
759 if (isspace(OFstatic_cast(unsigned char, gap)))
760 return(1);
761 if (gap == '=' || gap == ',' || gap == 10 || gap == 13)
762 return(1);
763 else
764 return(0);
765 }
766
767
768 int DcmQueryRetrieveConfig::isquote (char quote)
769 {
770 if (quote == '"' || quote == '\'' || quote == '(' || quote == ')')
771 return(1);
772 else
773 return(0);
774 }
775
776
777 char *DcmQueryRetrieveConfig::parsevalues (char **valuehandle)
778 {
779 int i,
780 inquotes = 0,
781 count = 0;
782 char *value = NULL;
783 const char *help,
784 *valueptr = *valuehandle;
785
786 if (isquote(*valueptr)) {
787 inquotes = 1;
788 valueptr++;
789 }
790
791 help = valueptr;
792
793 while(*help != '\0') {
794 if (inquotes) {
795 if (isquote(*help)) {
796 if ((value = (char*)malloc(count * sizeof(char) + 1)) == NULL)
797 panic("Memory allocation 7 (%d)", count);
798 for(i = 0; i < count; i++)
799 value[i] = valueptr[i];
800 value[count] = '\0';
801 count++;
802 help++;
803 while (*help != '\0') {
804 if (isgap(*help)) {
805 count++;
806 help++;
807 }
808 else
809 break;
810 }
811 *valuehandle += (count + 1);
812 break;
813 }
814 else {
815 count++;
816 help++;
817 }
818 }
819 else {
820 if (isgap(*help)) {
821 if ((value = (char*)malloc(count * sizeof(char) + 1)) == NULL)
822 panic("Memory allocation 8 (%d)", count);
823 for(i = 0; i < count; i++)
824 value[i] = valueptr[i];
825 value[count] = '\0';
826 while (*help != '\0') {
827 if (isgap(*help)) {
828 count++;
829 help++;
830 }
831 else
832 break;
833 }
834 *valuehandle += count;
835 break;
836 }
837 else {
838 count++;
839 help++;
840 }
841 } /* inquotes */
842 } /* while */
843
844 return(value);
845 }
846
847
848 long DcmQueryRetrieveConfig::quota (const char *value)
849 {
850 int number;
851 long factor;
852 char last = *(value + strlen(value) - 1), /* last character */
853 mult = *(value + strlen(value) - 2); /* multiplier */
854
855 if (last == 'b' || last == 'B') {
856 if (mult == 'k' || mult == 'K') factor = 1024;
857 else if (mult == 'm' || mult == 'M') factor = 1024 * 1024;
858 else if (mult == 'g' || mult == 'G') factor = 1024 * 1024 * 1024;
859 else factor = 1;
860 }
861 else return(-1L);
862
863 number = atoi(value);
864
865 // check for overflow
866 if (number > 0 && factor > LONG_MAX / number)
867 return LONG_MAX;
868
869 return(number * factor);
870 }
871
872
873 int DcmQueryRetrieveConfig::init(const char *ConfigurationFile)
874 {
875 int error = 0; /* error flag */
876 FILE *cnffp; /* configuration file pointer */
877
878 if ((cnffp = fopen(ConfigurationFile, "r")) == NULL) {
879 panic("Unable to open configuration file \"%s\"", ConfigurationFile);
880 return(0);
881 }
882
883 initConfigStruct();
884
885 if (!readConfigLines(cnffp)) {
886 panic("Reading configuration file \"%s\" with errors", ConfigurationFile);
887 error = 1;
888 }
889
890 fclose(cnffp);
891
892 return(error ? 0 : 1);
893 }
894
895
896 void DcmQueryRetrieveConfig::printConfig()
897 {
898 int i,j;
899
900 DCMQRDB_INFO("\nHostTable: " << CNF_HETable.noOfHostEntries);
901 for(i = 0; i < CNF_HETable.noOfHostEntries; i++) {
902 DCMQRDB_INFO(CNF_HETable.HostEntries[i].SymbolicName << " " << CNF_HETable.HostEntries[i].noOfPeers);
903 for(j = 0; j < CNF_HETable.HostEntries[i].noOfPeers; j++) {
904 DCMQRDB_INFO(CNF_HETable.HostEntries[i].Peers[j].ApplicationTitle << " " <<
905 CNF_HETable.HostEntries[i].Peers[j].HostName << " " << CNF_HETable.HostEntries[i].Peers[j].PortNumber);
906 }
907 }
908 DCMQRDB_INFO("\nVendorTable: " << CNF_VendorTable.noOfHostEntries);
909 for(i = 0; i < CNF_VendorTable.noOfHostEntries; i++) {
910 DCMQRDB_INFO(CNF_VendorTable.HostEntries[i].SymbolicName << " " << CNF_VendorTable.HostEntries[i].noOfPeers);
911 for(j = 0; j < CNF_VendorTable.HostEntries[i].noOfPeers; j++) {
912 DCMQRDB_INFO(CNF_VendorTable.HostEntries[i].Peers[j].ApplicationTitle << " " <<
913 CNF_VendorTable.HostEntries[i].Peers[j].HostName << " " << CNF_VendorTable.HostEntries[i].Peers[j].PortNumber);
914 }
915 }
916 DCMQRDB_INFO("\nGlobal Parameters:\n" << networkTCPPort_ << "\n" << OFstatic_cast(unsigned long, maxPDUSize_)
917 << "\n" << maxAssociations_);
918 DCMQRDB_INFO("\nAEEntries: " << CNF_Config.noOfAEEntries);
919 for(i = 0; i < CNF_Config.noOfAEEntries; i++) {
920 DCMQRDB_INFO(CNF_Config.AEEntries[i].ApplicationTitle << "\n" << CNF_Config.AEEntries[i].StorageArea
921 << "\n" << CNF_Config.AEEntries[i].Access << "\n" << CNF_Config.AEEntries[i].StorageQuota->maxStudies
922 << ", " << CNF_Config.AEEntries[i].StorageQuota->maxBytesPerStudy);
923 if (CNF_Config.AEEntries[i].noOfPeers == -1)
924 DCMQRDB_INFO("Peers: ANY");
925 else {
926 DCMQRDB_INFO("Peers: " << CNF_Config.AEEntries[i].noOfPeers);
927 for(j = 0; j < CNF_Config.AEEntries[i].noOfPeers; j++) {
928 DCMQRDB_INFO(CNF_Config.AEEntries[i].Peers[j].ApplicationTitle << " " <<
929 CNF_Config.AEEntries[i].Peers[j].HostName << " " << CNF_Config.AEEntries[i].Peers[j].PortNumber);
930 }
931 }
932 DCMQRDB_INFO("----------------------------------\n");
933 }
934 }
935
936
937 int DcmQueryRetrieveConfig::getNetworkTCPPort() const
938 {
939 return(networkTCPPort_);
940 }
941
942
943 OFCmdUnsignedInt DcmQueryRetrieveConfig::getMaxPDUSize() const
944 {
945 return(maxPDUSize_);
946 }
947
948
949 int DcmQueryRetrieveConfig::getMaxAssociations() const
950 {
951 return(maxAssociations_);
952 }
953
954
955 const char *DcmQueryRetrieveConfig::getStorageArea(const char *AETitle) const
956 {
957 int i;
958
959 for(i = 0; i < CNF_Config.noOfAEEntries; i++) {
960 if (!strcmp(AETitle, CNF_Config.AEEntries[i].ApplicationTitle))
961 return(CNF_Config.AEEntries[i].StorageArea);
962 }
963 return(NULL); /* AETitle not found */
964 }
965
966
967 const char *DcmQueryRetrieveConfig::getAccess(const char *AETitle) const
968 {
969 int i;
970
971 for(i = 0; i < CNF_Config.noOfAEEntries; i++) {
972 if (!strcmp(AETitle, CNF_Config.AEEntries[i].ApplicationTitle))
973 return(CNF_Config.AEEntries[i].Access);
974 }
975 return(NULL); /* AETitle not found */
976 }
977
978
979 int DcmQueryRetrieveConfig::getMaxStudies(const char *AETitle) const
980 {
981 int i;
982
983 for(i = 0; i < CNF_Config.noOfAEEntries; i++) {
984 if (!strcmp(AETitle, CNF_Config.AEEntries[i].ApplicationTitle))
985 return(CNF_Config.AEEntries[i].StorageQuota->maxStudies);
986 }
987 return(0); /* AETitle not found */
988 }
989
990 long DcmQueryRetrieveConfig::getMaxBytesPerStudy(const char *AETitle) const
991 {
992 int i;
993
994 for(i = 0; i < CNF_Config.noOfAEEntries; i++) {
995 if (!strcmp(AETitle, CNF_Config.AEEntries[i].ApplicationTitle))
996 return(CNF_Config.AEEntries[i].StorageQuota->maxBytesPerStudy);
997 }
998 return(0); /* AETitle not found */
999 }
1000
1001
1002 int DcmQueryRetrieveConfig::peerInAETitle(const char *calledAETitle, const char *callingAETitle, const char *HostName) const
1003 {
1004 int i,
1005 j;
1006
1007 for(i = 0; i < CNF_Config.noOfAEEntries; i++) {
1008 if (!strcmp(calledAETitle, CNF_Config.AEEntries[i].ApplicationTitle)) {
1009 if (CNF_Config.AEEntries[i].noOfPeers == -1) /* ANY Peer allowed */
1010 return(1);
1011 for(j = 0; j < CNF_Config.AEEntries[i].noOfPeers; j++) {
1012 if (!strcmp(callingAETitle, CNF_Config.AEEntries[i].Peers[j].ApplicationTitle) &&
1013 #ifdef HAVE_PROTOTYPE_STRCASECMP
1014 /* DNS is not case-sensitive */
1015 !strcasecmp(HostName, CNF_Config.AEEntries[i].Peers[j].HostName))
1016 #elif defined(HAVE_PROTOTYPE__STRICMP)
1017 !_stricmp(HostName, CNF_Config.AEEntries[i].Peers[j].HostName))
1018 #else
1019 /* fallback solution is to do case sensitive comparison on systems
1020 which do not implement strcasecmp or _stricmp */
1021 !strcmp(HostName, CNF_Config.AEEntries[i].Peers[j].HostName))
1022 #endif
1023 return(1); /* Peer found */
1024 }
1025 }
1026 }
1027 return(0); /* Peer not found */
1028 }
1029
1030
1031 int DcmQueryRetrieveConfig::peerForAETitle(const char *AETitle, const char **HostName, int *PortNumber) const
1032 {
1033 int i,
1034 j;
1035
1036 for(i = 0; i < CNF_Config.noOfAEEntries; i++) {
1037 for(j = 0; j < CNF_Config.AEEntries[i].noOfPeers; j++) {
1038 if (!strcmp(AETitle, CNF_Config.AEEntries[i].Peers[j].ApplicationTitle)) {
1039 *HostName = CNF_Config.AEEntries[i].Peers[j].HostName;
1040 *PortNumber = CNF_Config.AEEntries[i].Peers[j].PortNumber;
1041 return(1); /* Peer found in AETable */
1042 }
1043 }
1044 }
1045
1046 for(i = 0; i < CNF_HETable.noOfHostEntries; i++) {
1047 for(j = 0; j < CNF_HETable.HostEntries[i].noOfPeers; j++) {
1048 if (!strcmp(AETitle, CNF_HETable.HostEntries[i].Peers[j].ApplicationTitle)) {
1049 *HostName = CNF_HETable.HostEntries[i].Peers[j].HostName;
1050 *PortNumber = CNF_HETable.HostEntries[i].Peers[j].PortNumber;
1051 return(2); /* Peer found in HostTable */
1052 }
1053 }
1054 }
1055
1056 return(0); /* Peer not found */
1057 }
1058
1059
1060 int DcmQueryRetrieveConfig::checkForSameVendor(const char *AETitle1, const char *AETitle2) const
1061 {
1062 int i,
1063 j,
1064 k,
1065 found = 0;
1066
1067 for(i = 0; i < CNF_VendorTable.noOfHostEntries; i++) {
1068 for(j = 0; j < CNF_VendorTable.HostEntries[i].noOfPeers; j++) {
1069 if (!strcmp(AETitle1, CNF_VendorTable.HostEntries[i].Peers[j].ApplicationTitle)) {
1070 for(k = 0; k < CNF_VendorTable.HostEntries[i].noOfPeers; k++) {
1071 if (!strcmp(AETitle2, CNF_VendorTable.HostEntries[i].Peers[k].ApplicationTitle))
1072 found = 1;
1073 }
1074 }
1075 }
1076 }
1077
1078 return(found);
1079 }
1080
1081
1082 int DcmQueryRetrieveConfig::HostNamesForVendor(const char *Vendor, const char ***HostNameArray) const
1083 {
1084 int i, j,
1085 found = 0;
1086
1087 for(i = 0; i < CNF_VendorTable.noOfHostEntries; i++) {
1088 if (!strcmp(CNF_VendorTable.HostEntries[i].SymbolicName, Vendor)) {
1089 found = 1;
1090 break;
1091 }
1092 }
1093
1094 if (!found)
1095 return(0);
1096
1097 if ((*HostNameArray = (const char**)malloc(CNF_VendorTable.HostEntries[i].noOfPeers * sizeof(const char *))) == NULL) {
1098 panic("Memory allocation A (%d)", CNF_VendorTable.HostEntries[i].noOfPeers);
1099 return(0);
1100 }
1101 for(j = 0; j < CNF_VendorTable.HostEntries[i].noOfPeers; j++)
1102 (*HostNameArray)[j] = CNF_VendorTable.HostEntries[i].Peers[j].HostName;
1103
1104 return(CNF_VendorTable.HostEntries[i].noOfPeers);
1105 }
1106
1107 OFBool DcmQueryRetrieveConfig::writableStorageArea(const char *aeTitle) const
1108 {
1109 const char *axs = getAccess((char*)aeTitle);
1110 if (strcmp(axs, "RW") == 0) return OFTrue;
1111 if (strcmp(axs, "WR") == 0) return OFTrue;
1112 if (strcmp(axs, "W") == 0) return OFTrue;
1113 return OFFalse;
1114 }
1115
1116 const char *DcmQueryRetrieveConfig::getUserName() const
1117 {
1118 return UserName_.c_str();
1119 }
1120
1121 const char *DcmQueryRetrieveConfig::getGroupName() const
1122 {
1123 return GroupName_.c_str();
1124 }
1125
1126 const DcmQueryRetrieveCharacterSetOptions& DcmQueryRetrieveConfig::getCharacterSetOptions() const
1127 {
1128 return characterSetOptions_;
1129 }
1130
1131 DcmQueryRetrieveCharacterSetOptions& DcmQueryRetrieveConfig::getCharacterSetOptions()
1132 {
1133 return characterSetOptions_;
1134 }
1135