1 /** 2 * Orthanc - A Lightweight, RESTful DICOM Store 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 4 * Department, University Hospital of Liege, Belgium 5 * Copyright (C) 2017-2020 Osimis S.A., Belgium 6 * 7 * This program is free software: you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation, either version 3 of the 10 * License, or (at your option) any later version. 11 * 12 * In addition, as a special exception, the copyright holders of this 13 * program give permission to link the code of its release with the 14 * OpenSSL project's "OpenSSL" library (or with modified versions of it 15 * that use the same license as the "OpenSSL" library), and distribute 16 * the linked executables. You must obey the GNU General Public License 17 * in all respects for all of the code used other than "OpenSSL". If you 18 * modify file(s) with this exception, you may extend this exception to 19 * your version of the file(s), but you are not obligated to do so. If 20 * you do not wish to do so, delete this exception statement from your 21 * version. If you delete this exception statement from all source files 22 * in the program, then also delete it here. 23 * 24 * This program is distributed in the hope that it will be useful, but 25 * WITHOUT ANY WARRANTY; without even the implied warranty of 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 * General Public License for more details. 28 * 29 * You should have received a copy of the GNU General Public License 30 * along with this program. If not, see <http://www.gnu.org/licenses/>. 31 **/ 32 33 34 #include "PrecompiledHeadersServer.h" 35 #include "OrthancConfiguration.h" 36 37 #include "../../OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h" 38 #include "../../OrthancFramework/Sources/HttpServer/HttpServer.h" 39 #include "../../OrthancFramework/Sources/Logging.h" 40 #include "../../OrthancFramework/Sources/OrthancException.h" 41 #include "../../OrthancFramework/Sources/SystemToolbox.h" 42 #include "../../OrthancFramework/Sources/TemporaryFile.h" 43 #include "../../OrthancFramework/Sources/Toolbox.h" 44 45 #include "ServerIndex.h" 46 47 48 static const char* const DICOM_MODALITIES = "DicomModalities"; 49 static const char* const DICOM_MODALITIES_IN_DB = "DicomModalitiesInDatabase"; 50 static const char* const ORTHANC_PEERS = "OrthancPeers"; 51 static const char* const ORTHANC_PEERS_IN_DB = "OrthancPeersInDatabase"; 52 static const char* const TEMPORARY_DIRECTORY = "TemporaryDirectory"; 53 54 namespace Orthanc 55 { AddFileToConfiguration(Json::Value & target,const boost::filesystem::path & path)56 static void AddFileToConfiguration(Json::Value& target, 57 const boost::filesystem::path& path) 58 { 59 std::map<std::string, std::string> env; 60 SystemToolbox::GetEnvironmentVariables(env); 61 62 LOG(WARNING) << "Reading the configuration from: " << path; 63 64 Json::Value config; 65 66 { 67 std::string content; 68 SystemToolbox::ReadFile(content, path.string()); 69 70 content = Toolbox::SubstituteVariables(content, env); 71 72 Json::Value tmp; 73 Json::Reader reader; 74 if (!reader.parse(content, tmp) || 75 tmp.type() != Json::objectValue) 76 { 77 throw OrthancException(ErrorCode_BadJson, 78 "The configuration file does not follow the JSON syntax: " + path.string()); 79 } 80 81 Toolbox::CopyJsonWithoutComments(config, tmp); 82 } 83 84 if (target.size() == 0) 85 { 86 target = config; 87 } 88 else 89 { 90 // Merge the newly-added file with the previous content of "target" 91 Json::Value::Members members = config.getMemberNames(); 92 for (Json::Value::ArrayIndex i = 0; i < members.size(); i++) 93 { 94 if (target.isMember(members[i])) 95 { 96 throw OrthancException(ErrorCode_BadFileFormat, 97 "The configuration section \"" + members[i] + 98 "\" is defined in 2 different configuration files"); 99 } 100 else 101 { 102 target[members[i]] = config[members[i]]; 103 } 104 } 105 } 106 } 107 108 ScanFolderForConfiguration(Json::Value & target,const char * folder)109 static void ScanFolderForConfiguration(Json::Value& target, 110 const char* folder) 111 { 112 using namespace boost::filesystem; 113 114 LOG(WARNING) << "Scanning folder \"" << folder << "\" for configuration files"; 115 116 directory_iterator end_it; // default construction yields past-the-end 117 for (directory_iterator it(folder); 118 it != end_it; 119 ++it) 120 { 121 if (!is_directory(it->status())) 122 { 123 std::string extension = boost::filesystem::extension(it->path()); 124 Toolbox::ToLowerCase(extension); 125 126 if (extension == ".json") 127 { 128 AddFileToConfiguration(target, it->path().string()); 129 } 130 } 131 } 132 } 133 134 ReadConfiguration(Json::Value & target,const char * configurationFile)135 static void ReadConfiguration(Json::Value& target, 136 const char* configurationFile) 137 { 138 target = Json::objectValue; 139 140 if (configurationFile != NULL) 141 { 142 if (!boost::filesystem::exists(configurationFile)) 143 { 144 throw OrthancException(ErrorCode_InexistentFile, 145 "Inexistent path to configuration: " + 146 std::string(configurationFile)); 147 } 148 149 if (boost::filesystem::is_directory(configurationFile)) 150 { 151 ScanFolderForConfiguration(target, configurationFile); 152 } 153 else 154 { 155 AddFileToConfiguration(target, configurationFile); 156 } 157 } 158 else 159 { 160 #if ORTHANC_STANDALONE == 1 161 // No default path for the standalone configuration 162 LOG(WARNING) << "Using the default Orthanc configuration"; 163 return; 164 165 #else 166 // In a non-standalone build, we use the 167 // "Resources/Configuration.json" from the Orthanc source code 168 169 boost::filesystem::path p = ORTHANC_PATH; 170 p /= "Resources"; 171 p /= "Configuration.json"; 172 173 AddFileToConfiguration(target, p); 174 #endif 175 } 176 } 177 178 CheckAlphanumeric(const std::string & s)179 static void CheckAlphanumeric(const std::string& s) 180 { 181 for (size_t j = 0; j < s.size(); j++) 182 { 183 if (!isalnum(s[j]) && 184 s[j] != '-' && s[j] != '_') 185 { 186 throw OrthancException(ErrorCode_BadFileFormat, 187 "Only alphanumeric, dash characters and underscores are allowed " 188 "in the names of modalities/peers, but found: " + s); 189 } 190 } 191 } 192 193 LoadModalitiesFromJson(const Json::Value & source)194 void OrthancConfiguration::LoadModalitiesFromJson(const Json::Value& source) 195 { 196 modalities_.clear(); 197 198 if (source.type() != Json::objectValue) 199 { 200 throw OrthancException(ErrorCode_BadFileFormat, 201 "Bad format of the \"" + std::string(DICOM_MODALITIES) + 202 "\" configuration section"); 203 } 204 205 Json::Value::Members members = source.getMemberNames(); 206 207 for (size_t i = 0; i < members.size(); i++) 208 { 209 const std::string& name = members[i]; 210 CheckAlphanumeric(name); 211 212 RemoteModalityParameters modality; 213 modality.Unserialize(source[name]); 214 modalities_[name] = modality; 215 } 216 } 217 218 LoadPeersFromJson(const Json::Value & source)219 void OrthancConfiguration::LoadPeersFromJson(const Json::Value& source) 220 { 221 peers_.clear(); 222 223 if (source.type() != Json::objectValue) 224 { 225 throw OrthancException(ErrorCode_BadFileFormat, 226 "Bad format of the \"" + std::string(ORTHANC_PEERS) + 227 "\" configuration section"); 228 } 229 230 Json::Value::Members members = source.getMemberNames(); 231 232 for (size_t i = 0; i < members.size(); i++) 233 { 234 const std::string& name = members[i]; 235 CheckAlphanumeric(name); 236 237 WebServiceParameters peer; 238 peer.Unserialize(source[name]); 239 peers_[name] = peer; 240 } 241 } 242 243 LoadModalities()244 void OrthancConfiguration::LoadModalities() 245 { 246 if (GetBooleanParameter(DICOM_MODALITIES_IN_DB, false)) 247 { 248 // Modalities are stored in the database 249 if (serverIndex_ == NULL) 250 { 251 throw Orthanc::OrthancException(ErrorCode_BadSequenceOfCalls); 252 } 253 else 254 { 255 std::string property = serverIndex_->GetGlobalProperty(GlobalProperty_Modalities, "{}"); 256 257 Json::Reader reader; 258 Json::Value modalities; 259 if (reader.parse(property, modalities)) 260 { 261 LoadModalitiesFromJson(modalities); 262 } 263 else 264 { 265 throw OrthancException(ErrorCode_InternalError, 266 "Cannot unserialize the list of modalities from the Orthanc database"); 267 } 268 } 269 } 270 else 271 { 272 // Modalities are stored in the configuration files 273 if (json_.isMember(DICOM_MODALITIES)) 274 { 275 LoadModalitiesFromJson(json_[DICOM_MODALITIES]); 276 } 277 else 278 { 279 modalities_.clear(); 280 } 281 } 282 } 283 LoadPeers()284 void OrthancConfiguration::LoadPeers() 285 { 286 if (GetBooleanParameter(ORTHANC_PEERS_IN_DB, false)) 287 { 288 // Peers are stored in the database 289 if (serverIndex_ == NULL) 290 { 291 throw Orthanc::OrthancException(ErrorCode_BadSequenceOfCalls); 292 } 293 else 294 { 295 std::string property = serverIndex_->GetGlobalProperty(GlobalProperty_Peers, "{}"); 296 297 Json::Reader reader; 298 Json::Value peers; 299 if (reader.parse(property, peers)) 300 { 301 LoadPeersFromJson(peers); 302 } 303 else 304 { 305 throw OrthancException(ErrorCode_InternalError, 306 "Cannot unserialize the list of peers from the Orthanc database"); 307 } 308 } 309 } 310 else 311 { 312 // Peers are stored in the configuration files 313 if (json_.isMember(ORTHANC_PEERS)) 314 { 315 LoadPeersFromJson(json_[ORTHANC_PEERS]); 316 } 317 else 318 { 319 peers_.clear(); 320 } 321 } 322 } 323 324 SaveModalitiesToJson(Json::Value & target)325 void OrthancConfiguration::SaveModalitiesToJson(Json::Value& target) 326 { 327 target = Json::objectValue; 328 329 for (Modalities::const_iterator it = modalities_.begin(); it != modalities_.end(); ++it) 330 { 331 Json::Value modality; 332 it->second.Serialize(modality, true /* force advanced format */); 333 334 target[it->first] = modality; 335 } 336 } 337 338 SavePeersToJson(Json::Value & target)339 void OrthancConfiguration::SavePeersToJson(Json::Value& target) 340 { 341 target = Json::objectValue; 342 343 for (Peers::const_iterator it = peers_.begin(); it != peers_.end(); ++it) 344 { 345 Json::Value peer; 346 it->second.Serialize(peer, 347 false /* use simple format if possible */, 348 true /* include passwords */); 349 350 target[it->first] = peer; 351 } 352 } 353 354 SaveModalities()355 void OrthancConfiguration::SaveModalities() 356 { 357 if (GetBooleanParameter(DICOM_MODALITIES_IN_DB, false)) 358 { 359 // Modalities are stored in the database 360 if (serverIndex_ == NULL) 361 { 362 throw Orthanc::OrthancException(ErrorCode_BadSequenceOfCalls); 363 } 364 else 365 { 366 Json::Value modalities; 367 SaveModalitiesToJson(modalities); 368 369 Json::FastWriter writer; 370 std::string s = writer.write(modalities); 371 372 serverIndex_->SetGlobalProperty(GlobalProperty_Modalities, s); 373 } 374 } 375 else 376 { 377 // Modalities are stored in the configuration files 378 if (!modalities_.empty() || 379 json_.isMember(DICOM_MODALITIES)) 380 { 381 SaveModalitiesToJson(json_[DICOM_MODALITIES]); 382 } 383 } 384 } 385 386 SavePeers()387 void OrthancConfiguration::SavePeers() 388 { 389 if (GetBooleanParameter(ORTHANC_PEERS_IN_DB, false)) 390 { 391 // Peers are stored in the database 392 if (serverIndex_ == NULL) 393 { 394 throw Orthanc::OrthancException(ErrorCode_BadSequenceOfCalls); 395 } 396 else 397 { 398 Json::Value peers; 399 SavePeersToJson(peers); 400 401 Json::FastWriter writer; 402 std::string s = writer.write(peers); 403 404 serverIndex_->SetGlobalProperty(GlobalProperty_Peers, s); 405 } 406 } 407 else 408 { 409 // Peers are stored in the configuration files 410 if (!peers_.empty() || 411 json_.isMember(ORTHANC_PEERS)) 412 { 413 SavePeersToJson(json_[ORTHANC_PEERS]); 414 } 415 } 416 } 417 418 GetInstance()419 OrthancConfiguration& OrthancConfiguration::GetInstance() 420 { 421 static OrthancConfiguration configuration; 422 return configuration; 423 } 424 425 LookupStringParameter(std::string & target,const std::string & parameter) const426 bool OrthancConfiguration::LookupStringParameter(std::string& target, 427 const std::string& parameter) const 428 { 429 if (json_.isMember(parameter)) 430 { 431 if (json_[parameter].type() != Json::stringValue) 432 { 433 throw OrthancException(ErrorCode_BadParameterType, 434 "The configuration option \"" + parameter + "\" must be a string"); 435 } 436 else 437 { 438 target = json_[parameter].asString(); 439 return true; 440 } 441 } 442 else 443 { 444 return false; 445 } 446 } 447 448 GetStringParameter(const std::string & parameter,const std::string & defaultValue) const449 std::string OrthancConfiguration::GetStringParameter(const std::string& parameter, 450 const std::string& defaultValue) const 451 { 452 std::string value; 453 if (LookupStringParameter(value, parameter)) 454 { 455 return value; 456 } 457 else 458 { 459 return defaultValue; 460 } 461 } 462 463 GetIntegerParameter(const std::string & parameter,int defaultValue) const464 int OrthancConfiguration::GetIntegerParameter(const std::string& parameter, 465 int defaultValue) const 466 { 467 if (json_.isMember(parameter)) 468 { 469 if (json_[parameter].type() != Json::intValue) 470 { 471 throw OrthancException(ErrorCode_BadParameterType, 472 "The configuration option \"" + parameter + "\" must be an integer"); 473 } 474 else 475 { 476 return json_[parameter].asInt(); 477 } 478 } 479 else 480 { 481 return defaultValue; 482 } 483 } 484 485 GetUnsignedIntegerParameter(const std::string & parameter,unsigned int defaultValue) const486 unsigned int OrthancConfiguration::GetUnsignedIntegerParameter( 487 const std::string& parameter, 488 unsigned int defaultValue) const 489 { 490 int v = GetIntegerParameter(parameter, defaultValue); 491 492 if (v < 0) 493 { 494 throw OrthancException(ErrorCode_ParameterOutOfRange, 495 "The configuration option \"" + parameter + "\" must be a positive integer"); 496 } 497 else 498 { 499 return static_cast<unsigned int>(v); 500 } 501 } 502 503 LookupBooleanParameter(bool & target,const std::string & parameter) const504 bool OrthancConfiguration::LookupBooleanParameter(bool& target, 505 const std::string& parameter) const 506 { 507 if (json_.isMember(parameter)) 508 { 509 if (json_[parameter].type() != Json::booleanValue) 510 { 511 throw OrthancException(ErrorCode_BadParameterType, 512 "The configuration option \"" + parameter + 513 "\" must be a Boolean (true or false)"); 514 } 515 else 516 { 517 target = json_[parameter].asBool(); 518 return true; 519 } 520 } 521 else 522 { 523 return false; 524 } 525 } 526 527 GetBooleanParameter(const std::string & parameter,bool defaultValue) const528 bool OrthancConfiguration::GetBooleanParameter(const std::string& parameter, 529 bool defaultValue) const 530 { 531 bool value; 532 if (LookupBooleanParameter(value, parameter)) 533 { 534 return value; 535 } 536 else 537 { 538 return defaultValue; 539 } 540 } 541 542 Read(const char * configurationFile)543 void OrthancConfiguration::Read(const char* configurationFile) 544 { 545 // Read the content of the configuration 546 configurationFileArg_ = configurationFile; 547 ReadConfiguration(json_, configurationFile); 548 549 // Adapt the paths to the configurations 550 defaultDirectory_ = boost::filesystem::current_path(); 551 configurationAbsolutePath_ = ""; 552 553 if (configurationFile) 554 { 555 if (boost::filesystem::is_directory(configurationFile)) 556 { 557 defaultDirectory_ = boost::filesystem::path(configurationFile); 558 configurationAbsolutePath_ = boost::filesystem::absolute(configurationFile).parent_path().string(); 559 } 560 else 561 { 562 defaultDirectory_ = boost::filesystem::path(configurationFile).parent_path(); 563 configurationAbsolutePath_ = boost::filesystem::absolute(configurationFile).string(); 564 } 565 } 566 else 567 { 568 #if ORTHANC_STANDALONE != 1 569 // In a non-standalone build, we use the 570 // "Resources/Configuration.json" from the Orthanc source code 571 572 boost::filesystem::path p = ORTHANC_PATH; 573 p /= "Resources"; 574 p /= "Configuration.json"; 575 configurationAbsolutePath_ = boost::filesystem::absolute(p).string(); 576 #endif 577 } 578 } 579 580 LoadModalitiesAndPeers()581 void OrthancConfiguration::LoadModalitiesAndPeers() 582 { 583 LoadModalities(); 584 LoadPeers(); 585 } 586 587 RegisterFont(ServerResources::FileResourceId resource)588 void OrthancConfiguration::RegisterFont(ServerResources::FileResourceId resource) 589 { 590 std::string content; 591 ServerResources::GetFileResource(content, resource); 592 fontRegistry_.AddFromMemory(content); 593 } 594 595 GetDicomModalityUsingSymbolicName(RemoteModalityParameters & modality,const std::string & name) const596 void OrthancConfiguration::GetDicomModalityUsingSymbolicName( 597 RemoteModalityParameters& modality, 598 const std::string& name) const 599 { 600 Modalities::const_iterator found = modalities_.find(name); 601 602 if (found == modalities_.end()) 603 { 604 throw OrthancException(ErrorCode_InexistentItem, 605 "No modality with symbolic name: " + name); 606 } 607 else 608 { 609 modality = found->second; 610 } 611 } 612 613 LookupOrthancPeer(WebServiceParameters & peer,const std::string & name) const614 bool OrthancConfiguration::LookupOrthancPeer(WebServiceParameters& peer, 615 const std::string& name) const 616 { 617 Peers::const_iterator found = peers_.find(name); 618 619 if (found == peers_.end()) 620 { 621 LOG(ERROR) << "No peer with symbolic name: " << name; 622 return false; 623 } 624 else 625 { 626 peer = found->second; 627 return true; 628 } 629 } 630 631 GetListOfDicomModalities(std::set<std::string> & target) const632 void OrthancConfiguration::GetListOfDicomModalities(std::set<std::string>& target) const 633 { 634 target.clear(); 635 636 for (Modalities::const_iterator 637 it = modalities_.begin(); it != modalities_.end(); ++it) 638 { 639 target.insert(it->first); 640 } 641 } 642 643 GetListOfOrthancPeers(std::set<std::string> & target) const644 void OrthancConfiguration::GetListOfOrthancPeers(std::set<std::string>& target) const 645 { 646 target.clear(); 647 648 for (Peers::const_iterator it = peers_.begin(); it != peers_.end(); ++it) 649 { 650 target.insert(it->first); 651 } 652 } 653 654 SetupRegisteredUsers(HttpServer & httpServer) const655 bool OrthancConfiguration::SetupRegisteredUsers(HttpServer& httpServer) const 656 { 657 httpServer.ClearUsers(); 658 659 if (!json_.isMember("RegisteredUsers")) 660 { 661 return false; 662 } 663 664 const Json::Value& users = json_["RegisteredUsers"]; 665 if (users.type() != Json::objectValue) 666 { 667 throw OrthancException(ErrorCode_BadFileFormat, "Badly formatted list of users"); 668 } 669 670 bool hasUser = false; 671 Json::Value::Members usernames = users.getMemberNames(); 672 for (size_t i = 0; i < usernames.size(); i++) 673 { 674 const std::string& username = usernames[i]; 675 std::string password = users[username].asString(); 676 httpServer.RegisterUser(username.c_str(), password.c_str()); 677 hasUser = true; 678 } 679 680 return hasUser; 681 } 682 683 InterpretStringParameterAsPath(const std::string & parameter) const684 std::string OrthancConfiguration::InterpretStringParameterAsPath( 685 const std::string& parameter) const 686 { 687 return SystemToolbox::InterpretRelativePath(defaultDirectory_.string(), parameter); 688 } 689 690 GetListOfStringsParameter(std::list<std::string> & target,const std::string & key) const691 void OrthancConfiguration::GetListOfStringsParameter(std::list<std::string>& target, 692 const std::string& key) const 693 { 694 target.clear(); 695 696 if (!json_.isMember(key)) 697 { 698 return; 699 } 700 701 const Json::Value& lst = json_[key]; 702 703 if (lst.type() != Json::arrayValue) 704 { 705 throw OrthancException(ErrorCode_BadFileFormat, "Badly formatted list of strings"); 706 } 707 708 for (Json::Value::ArrayIndex i = 0; i < lst.size(); i++) 709 { 710 target.push_back(lst[i].asString()); 711 } 712 } 713 714 IsSameAETitle(const std::string & aet1,const std::string & aet2) const715 bool OrthancConfiguration::IsSameAETitle(const std::string& aet1, 716 const std::string& aet2) const 717 { 718 if (GetBooleanParameter("StrictAetComparison", false)) 719 { 720 // Case-sensitive matching 721 return aet1 == aet2; 722 } 723 else 724 { 725 // Case-insensitive matching (default) 726 std::string tmp1, tmp2; 727 Toolbox::ToLowerCase(tmp1, aet1); 728 Toolbox::ToLowerCase(tmp2, aet2); 729 return tmp1 == tmp2; 730 } 731 } 732 733 LookupDicomModalityUsingAETitle(RemoteModalityParameters & modality,const std::string & aet) const734 bool OrthancConfiguration::LookupDicomModalityUsingAETitle(RemoteModalityParameters& modality, 735 const std::string& aet) const 736 { 737 for (Modalities::const_iterator it = modalities_.begin(); it != modalities_.end(); ++it) 738 { 739 if (IsSameAETitle(aet, it->second.GetApplicationEntityTitle())) 740 { 741 modality = it->second; 742 return true; 743 } 744 } 745 746 return false; 747 } 748 LookupDicomModalitiesUsingAETitle(std::list<RemoteModalityParameters> & modalities,const std::string & aet) const749 bool OrthancConfiguration::LookupDicomModalitiesUsingAETitle(std::list<RemoteModalityParameters>& modalities, 750 const std::string& aet) const 751 { 752 modalities.clear(); 753 754 for (Modalities::const_iterator it = modalities_.begin(); it != modalities_.end(); ++it) 755 { 756 if (IsSameAETitle(aet, it->second.GetApplicationEntityTitle())) 757 { 758 modalities.push_back(it->second); 759 } 760 } 761 762 return modalities.size() > 0; 763 } 764 765 766 IsKnownAETitle(const std::string & aet,const std::string & ip) const767 bool OrthancConfiguration::IsKnownAETitle(const std::string& aet, 768 const std::string& ip) const 769 { 770 RemoteModalityParameters modality; 771 772 if (!LookupDicomModalityUsingAETitle(modality, aet)) 773 { 774 LOG(WARNING) << "Modality \"" << aet 775 << "\" is not listed in the \"DicomModalities\" configuration option"; 776 return false; 777 } 778 else if (!GetBooleanParameter("DicomCheckModalityHost", false) || 779 ip == modality.GetHost()) 780 { 781 return true; 782 } 783 else 784 { 785 LOG(WARNING) << "Forbidding access from AET \"" << aet 786 << "\" given its hostname (" << ip << ") does not match " 787 << "the \"DicomModalities\" configuration option (" 788 << modality.GetHost() << " was expected)"; 789 return false; 790 } 791 } 792 793 794 RemoteModalityParameters GetModalityUsingSymbolicName(const std::string & name) const795 OrthancConfiguration::GetModalityUsingSymbolicName(const std::string& name) const 796 { 797 RemoteModalityParameters modality; 798 GetDicomModalityUsingSymbolicName(modality, name); 799 800 return modality; 801 } 802 803 804 RemoteModalityParameters GetModalityUsingAet(const std::string & aet) const805 OrthancConfiguration::GetModalityUsingAet(const std::string& aet) const 806 { 807 RemoteModalityParameters modality; 808 809 if (LookupDicomModalityUsingAETitle(modality, aet)) 810 { 811 return modality; 812 } 813 else 814 { 815 throw OrthancException(ErrorCode_InexistentItem, 816 "Unknown modality for AET: " + aet); 817 } 818 } 819 820 UpdateModality(const std::string & symbolicName,const RemoteModalityParameters & modality)821 void OrthancConfiguration::UpdateModality(const std::string& symbolicName, 822 const RemoteModalityParameters& modality) 823 { 824 CheckAlphanumeric(symbolicName); 825 826 modalities_[symbolicName] = modality; 827 SaveModalities(); 828 } 829 830 RemoveModality(const std::string & symbolicName)831 void OrthancConfiguration::RemoveModality(const std::string& symbolicName) 832 { 833 if (modalities_.find(symbolicName) == modalities_.end()) 834 { 835 throw OrthancException(ErrorCode_InexistentItem, 836 "Unknown DICOM modality with symbolic name: " + symbolicName); 837 } 838 else 839 { 840 modalities_.erase(symbolicName); 841 SaveModalities(); 842 } 843 } 844 845 UpdatePeer(const std::string & symbolicName,const WebServiceParameters & peer)846 void OrthancConfiguration::UpdatePeer(const std::string& symbolicName, 847 const WebServiceParameters& peer) 848 { 849 CheckAlphanumeric(symbolicName); 850 851 peer.CheckClientCertificate(); 852 853 peers_[symbolicName] = peer; 854 SavePeers(); 855 } 856 857 RemovePeer(const std::string & symbolicName)858 void OrthancConfiguration::RemovePeer(const std::string& symbolicName) 859 { 860 if (peers_.find(symbolicName) == peers_.end()) 861 { 862 throw OrthancException(ErrorCode_InexistentItem, 863 "Unknown Orthanc peer: " + symbolicName); 864 } 865 else 866 { 867 peers_.erase(symbolicName); 868 SavePeers(); 869 } 870 } 871 872 Format(std::string & result) const873 void OrthancConfiguration::Format(std::string& result) const 874 { 875 Json::StyledWriter w; 876 result = w.write(json_); 877 } 878 879 SetDefaultEncoding(Encoding encoding)880 void OrthancConfiguration::SetDefaultEncoding(Encoding encoding) 881 { 882 SetDefaultDicomEncoding(encoding); 883 884 // Propagate the encoding to the configuration file that is 885 // stored in memory 886 json_["DefaultEncoding"] = EnumerationToString(encoding); 887 } 888 889 HasConfigurationChanged() const890 bool OrthancConfiguration::HasConfigurationChanged() const 891 { 892 Json::Value current; 893 ReadConfiguration(current, configurationFileArg_); 894 895 Json::FastWriter writer; 896 std::string a = writer.write(json_); 897 std::string b = writer.write(current); 898 899 return a != b; 900 } 901 902 SetServerIndex(ServerIndex & index)903 void OrthancConfiguration::SetServerIndex(ServerIndex& index) 904 { 905 serverIndex_ = &index; 906 } 907 908 ResetServerIndex()909 void OrthancConfiguration::ResetServerIndex() 910 { 911 serverIndex_ = NULL; 912 } 913 914 CreateTemporaryFile() const915 TemporaryFile* OrthancConfiguration::CreateTemporaryFile() const 916 { 917 if (json_.isMember(TEMPORARY_DIRECTORY)) 918 { 919 return new TemporaryFile(InterpretStringParameterAsPath(GetStringParameter(TEMPORARY_DIRECTORY, ".")), ""); 920 } 921 else 922 { 923 return new TemporaryFile; 924 } 925 } 926 927 GetDefaultPrivateCreator() const928 std::string OrthancConfiguration::GetDefaultPrivateCreator() const 929 { 930 // New configuration option in Orthanc 1.6.0 931 return GetStringParameter("DefaultPrivateCreator", ""); 932 } 933 934 DefaultExtractDicomSummary(DicomMap & target,const ParsedDicomFile & dicom)935 void OrthancConfiguration::DefaultExtractDicomSummary(DicomMap& target, 936 const ParsedDicomFile& dicom) 937 { 938 std::set<DicomTag> ignoreTagLength; 939 dicom.ExtractDicomSummary(target, ORTHANC_MAXIMUM_TAG_LENGTH, ignoreTagLength); 940 } 941 942 DefaultDicomDatasetToJson(Json::Value & target,const ParsedDicomFile & dicom)943 void OrthancConfiguration::DefaultDicomDatasetToJson(Json::Value& target, 944 const ParsedDicomFile& dicom) 945 { 946 std::set<DicomTag> ignoreTagLength; 947 DefaultDicomDatasetToJson(target, dicom, ignoreTagLength); 948 } 949 950 DefaultDicomDatasetToJson(Json::Value & target,const ParsedDicomFile & dicom,const std::set<DicomTag> & ignoreTagLength)951 void OrthancConfiguration::DefaultDicomDatasetToJson(Json::Value& target, 952 const ParsedDicomFile& dicom, 953 const std::set<DicomTag>& ignoreTagLength) 954 { 955 dicom.DatasetToJson(target, DicomToJsonFormat_Full, DicomToJsonFlags_Default, 956 ORTHANC_MAXIMUM_TAG_LENGTH, ignoreTagLength); 957 } 958 959 DefaultDicomHeaderToJson(Json::Value & target,const ParsedDicomFile & dicom)960 void OrthancConfiguration::DefaultDicomHeaderToJson(Json::Value& target, 961 const ParsedDicomFile& dicom) 962 { 963 dicom.HeaderToJson(target, DicomToJsonFormat_Full); 964 } 965 } 966