2 Copyright (C) 2012-2022 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
23 #include "colour_conversion.h"
24 #include "compose.hpp"
28 #include "dcp_content_type.h"
29 #include "dkdm_recipient.h"
30 #include "dkdm_wrapper.h"
38 #include <dcp/certificate_chain.h>
39 #include <dcp/name_format.h>
40 #include <dcp/raw_convert.h>
41 #include <libcxml/cxml.h>
43 #include <libxml++/libxml++.h>
44 #include <boost/filesystem.hpp>
45 #include <boost/algorithm/string.hpp>
46 #include <boost/thread.hpp>
55 using std::dynamic_pointer_cast;
58 using std::make_shared;
62 using std::shared_ptr;
65 using boost::algorithm::trim;
66 using boost::optional;
67 using dcp::raw_convert;
70 Config* Config::_instance = 0;
71 int const Config::_current_version = 3;
72 boost::signals2::signal<void (Config::LoadFailure)> Config::FailedToLoad;
73 boost::signals2::signal<void (string)> Config::Warning;
74 boost::signals2::signal<bool (Config::BadReason)> Config::Bad;
77 /** Construct default configuration */
79 /* DKDMs are not considered a thing to reset on set_defaults() */
80 : _dkdms (new DKDMGroup ("root"))
81 , _default_kdm_duration (1, RoughDuration::Unit::WEEKS)
88 Config::set_defaults ()
90 _master_encoding_threads = max (2U, boost::thread::hardware_concurrency ());
91 _server_encoding_threads = max (2U, boost::thread::hardware_concurrency ());
92 _server_port_base = 6192;
93 _use_any_servers = true;
95 _only_servers_encode = false;
96 _tms_protocol = FileTransferProtocol::SCP;
102 _allow_any_dcp_frame_rate = false;
103 _allow_any_container = false;
104 _allow_96khz_audio = false;
105 _use_all_audio_channels = false;
106 _show_experimental_audio_processors = false;
107 _language = optional<string> ();
108 _default_still_length = 10;
109 _default_container = Ratio::from_id ("185");
110 _default_dcp_content_type = DCPContentType::from_isdcf_name ("FTR");
111 _default_dcp_audio_channels = 6;
112 _default_j2k_bandwidth = 150000000;
113 _default_audio_delay = 0;
114 _default_interop = false;
115 _default_metadata.clear ();
116 _upload_after_make_dcp = false;
119 _mail_protocol = EmailProtocol::AUTO;
125 _notification_from = "";
126 _notification_to = "";
127 _notification_cc.clear ();
128 _notification_bcc = "";
129 _check_for_updates = false;
130 _check_for_test_updates = false;
131 _maximum_j2k_bandwidth = 250000000;
132 _log_types = LogEntry::TYPE_GENERAL | LogEntry::TYPE_WARNING | LogEntry::TYPE_ERROR | LogEntry::TYPE_DISK;
133 _analyse_ebur128 = true;
134 _automatic_audio_analysis = false;
135 #ifdef DCPOMATIC_WINDOWS
136 _win32_console = false;
138 /* At the moment we don't write these files anywhere new after a version change, so they will be read from
139 * ~/.config/dcpomatic2 (or equivalent) and written back there.
141 _cinemas_file = read_path ("cinemas.xml");
142 _dkdm_recipients_file = read_path ("dkdm_recipients.xml");
143 _show_hints_before_make_dcp = true;
144 _confirm_kdm_email = true;
145 _kdm_container_name_format = dcp::NameFormat ("KDM %f %c");
146 _kdm_filename_format = dcp::NameFormat ("KDM %f %c %s");
147 _dkdm_filename_format = dcp::NameFormat ("DKDM %f %c %s");
148 _dcp_metadata_filename_format = dcp::NameFormat ("%t");
149 _dcp_asset_filename_format = dcp::NameFormat ("%t");
150 _jump_to_selected = true;
151 for (int i = 0; i < NAG_COUNT; ++i) {
155 _sound_output = optional<string> ();
156 _last_kdm_write_type = KDM_WRITE_FLAT;
157 _last_dkdm_write_type = DKDM_WRITE_INTERNAL;
159 /* I think the scaling factor here should be the ratio of the longest frame
160 encode time to the shortest; if the thread count is T, longest time is L
161 and the shortest time S we could encode L/S frames per thread whilst waiting
162 for the L frame to encode so we might have to store LT/S frames.
164 However we don't want to use too much memory, so keep it a bit lower than we'd
165 perhaps like. A J2K frame is typically about 1Mb so 3 here will mean we could
166 use about 240Mb with 72 encoding threads.
168 _frames_in_memory_multiplier = 3;
169 _decode_reduction = optional<int>();
170 _default_notify = false;
171 for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
172 _notification[i] = false;
174 _barco_username = optional<string>();
175 _barco_password = optional<string>();
176 _christie_username = optional<string>();
177 _christie_password = optional<string>();
178 _gdc_username = optional<string>();
179 _gdc_password = optional<string>();
180 _player_mode = PLAYER_MODE_WINDOW;
182 _video_view_type = VIDEO_VIEW_SIMPLE;
183 _respect_kdm_validity_periods = true;
184 _player_debug_log_file = boost::none;
185 _player_content_directory = boost::none;
186 _player_playlist_directory = boost::none;
187 _player_kdm_directory = boost::none;
188 _audio_mapping = boost::none;
189 _custom_languages.clear ();
190 _add_files_path = boost::none;
191 _use_isdcf_name_by_default = true;
192 _write_kdms_to_disk = true;
194 _default_kdm_type = dcp::Formulation::MODIFIED_TRANSITIONAL_1;
195 _default_kdm_duration = RoughDuration(1, RoughDuration::Unit::WEEKS);
196 _auto_crop_threshold = 0.1;
197 _last_release_notes_version = boost::none;
199 _allowed_dcp_frame_rates.clear ();
200 _allowed_dcp_frame_rates.push_back (24);
201 _allowed_dcp_frame_rates.push_back (25);
202 _allowed_dcp_frame_rates.push_back (30);
203 _allowed_dcp_frame_rates.push_back (48);
204 _allowed_dcp_frame_rates.push_back (50);
205 _allowed_dcp_frame_rates.push_back (60);
207 set_kdm_email_to_default ();
208 set_notification_email_to_default ();
209 set_cover_sheet_to_default ();
211 _main_divider_sash_position = {};
212 _main_content_divider_sash_position = {};
214 _export.set_defaults();
218 Config::restore_defaults ()
220 Config::instance()->set_defaults ();
221 Config::instance()->changed ();
224 shared_ptr<dcp::CertificateChain>
225 Config::create_certificate_chain ()
227 return make_shared<dcp::CertificateChain> (
229 CERTIFICATE_VALIDITY_PERIOD,
232 ".dcpomatic.smpte-430-2.ROOT",
233 ".dcpomatic.smpte-430-2.INTERMEDIATE",
234 "CS.dcpomatic.smpte-430-2.LEAF"
241 using namespace boost::filesystem;
243 auto copy_adding_number = [](path const& path_to_copy) {
245 auto add_number = [](path const& path, int number) {
246 return String::compose("%1.%2", path, number);
250 while (n < 100 && exists(add_number(path_to_copy, n))) {
253 boost::system::error_code ec;
254 copy_file(path_to_copy, add_number(path_to_copy, n), ec);
257 /* Make a backup copy of any config.xml, cinemas.xml, dkdm_recipients.xml that we might be about
258 * to write over. This is more intended for the situation where we have a corrupted config.xml,
259 * and decide to overwrite it with a new one (possibly losing important details in the corrupted
260 * file). But we might as well back up the other files while we're about it.
263 /* This uses the State::write_path stuff so, e.g. for a current version 2.16 we might copy
264 * ~/.config/dcpomatic2/2.16/config.xml to ~/.config/dcpomatic2/2.16/config.xml.1
266 copy_adding_number (config_write_file());
268 /* These do not use State::write_path, so whatever path is in the Config we will copy
271 copy_adding_number (_cinemas_file);
272 copy_adding_number (_dkdm_recipients_file);
280 read_dkdm_recipients();
285 Config::read_config()
288 cxml::Document f ("Config");
289 f.read_file (config_read_file());
291 auto version = f.optional_number_child<int> ("Version");
292 if (version && *version < _current_version) {
293 /* Back up the old config before we re-write it in a back-incompatible way */
297 if (f.optional_number_child<int>("NumLocalEncodingThreads")) {
298 _master_encoding_threads = _server_encoding_threads = f.optional_number_child<int>("NumLocalEncodingThreads").get();
300 _master_encoding_threads = f.number_child<int>("MasterEncodingThreads");
301 _server_encoding_threads = f.number_child<int>("ServerEncodingThreads");
304 _default_directory = f.optional_string_child ("DefaultDirectory");
305 if (_default_directory && _default_directory->empty ()) {
306 /* We used to store an empty value for this to mean "none set" */
307 _default_directory = boost::optional<boost::filesystem::path> ();
310 auto b = f.optional_number_child<int> ("ServerPort");
312 b = f.optional_number_child<int> ("ServerPortBase");
314 _server_port_base = b.get ();
316 auto u = f.optional_bool_child ("UseAnyServers");
317 _use_any_servers = u.get_value_or (true);
319 for (auto i: f.node_children("Server")) {
320 if (i->node_children("HostName").size() == 1) {
321 _servers.push_back (i->string_child ("HostName"));
323 _servers.push_back (i->content ());
327 _only_servers_encode = f.optional_bool_child ("OnlyServersEncode").get_value_or (false);
328 _tms_protocol = static_cast<FileTransferProtocol>(f.optional_number_child<int>("TMSProtocol").get_value_or(static_cast<int>(FileTransferProtocol::SCP)));
329 _tms_passive = f.optional_bool_child("TMSPassive").get_value_or(true);
330 _tms_ip = f.string_child ("TMSIP");
331 _tms_path = f.string_child ("TMSPath");
332 _tms_user = f.string_child ("TMSUser");
333 _tms_password = f.string_child ("TMSPassword");
335 _language = f.optional_string_child ("Language");
337 auto c = f.optional_string_child ("DefaultContainer");
339 _default_container = Ratio::from_id (c.get ());
342 if (_default_container && !_default_container->used_for_container()) {
343 Warning (_("Your default container is not valid and has been changed to Flat (1.85:1)"));
344 _default_container = Ratio::from_id ("185");
347 _default_dcp_content_type = DCPContentType::from_isdcf_name(f.optional_string_child("DefaultDCPContentType").get_value_or("FTR"));
348 _default_dcp_audio_channels = f.optional_number_child<int>("DefaultDCPAudioChannels").get_value_or (6);
350 if (f.optional_string_child ("DCPMetadataIssuer")) {
351 _dcp_issuer = f.string_child ("DCPMetadataIssuer");
352 } else if (f.optional_string_child ("DCPIssuer")) {
353 _dcp_issuer = f.string_child ("DCPIssuer");
356 auto up = f.optional_bool_child("UploadAfterMakeDCP");
358 up = f.optional_bool_child("DefaultUploadAfterMakeDCP");
360 _upload_after_make_dcp = up.get_value_or (false);
361 _dcp_creator = f.optional_string_child ("DCPCreator").get_value_or ("");
362 _dcp_company_name = f.optional_string_child("DCPCompanyName").get_value_or("");
363 _dcp_product_name = f.optional_string_child("DCPProductName").get_value_or("");
364 _dcp_product_version = f.optional_string_child("DCPProductVersion").get_value_or("");
365 _dcp_j2k_comment = f.optional_string_child("DCPJ2KComment").get_value_or("");
367 _default_still_length = f.optional_number_child<int>("DefaultStillLength").get_value_or (10);
368 _default_j2k_bandwidth = f.optional_number_child<int>("DefaultJ2KBandwidth").get_value_or (200000000);
369 _default_audio_delay = f.optional_number_child<int>("DefaultAudioDelay").get_value_or (0);
370 _default_interop = f.optional_bool_child("DefaultInterop").get_value_or (false);
372 for (auto const& i: f.node_children("DefaultMetadata")) {
373 _default_metadata[i->string_attribute("key")] = i->content();
376 _default_kdm_directory = f.optional_string_child("DefaultKDMDirectory");
378 /* Read any cinemas that are still lying around in the config file
379 * from an old version.
383 _mail_server = f.string_child ("MailServer");
384 _mail_port = f.optional_number_child<int> ("MailPort").get_value_or (25);
387 /* Make sure this matches the code in write_config */
388 string const protocol = f.optional_string_child("MailProtocol").get_value_or("Auto");
389 if (protocol == "Auto") {
390 _mail_protocol = EmailProtocol::AUTO;
391 } else if (protocol == "Plain") {
392 _mail_protocol = EmailProtocol::PLAIN;
393 } else if (protocol == "STARTTLS") {
394 _mail_protocol = EmailProtocol::STARTTLS;
395 } else if (protocol == "SSL") {
396 _mail_protocol = EmailProtocol::SSL;
400 _mail_user = f.optional_string_child("MailUser").get_value_or ("");
401 _mail_password = f.optional_string_child("MailPassword").get_value_or ("");
403 _kdm_subject = f.optional_string_child ("KDMSubject").get_value_or (_("KDM delivery: $CPL_NAME"));
404 _kdm_from = f.string_child ("KDMFrom");
405 for (auto i: f.node_children("KDMCC")) {
406 if (!i->content().empty()) {
407 _kdm_cc.push_back (i->content ());
410 _kdm_bcc = f.optional_string_child ("KDMBCC").get_value_or ("");
411 _kdm_email = f.string_child ("KDMEmail");
413 _notification_subject = f.optional_string_child("NotificationSubject").get_value_or(_("DCP-o-matic notification"));
414 _notification_from = f.optional_string_child("NotificationFrom").get_value_or("");
415 _notification_to = f.optional_string_child("NotificationTo").get_value_or("");
416 for (auto i: f.node_children("NotificationCC")) {
417 if (!i->content().empty()) {
418 _notification_cc.push_back (i->content ());
421 _notification_bcc = f.optional_string_child("NotificationBCC").get_value_or("");
422 if (f.optional_string_child("NotificationEmail")) {
423 _notification_email = f.string_child("NotificationEmail");
426 _check_for_updates = f.optional_bool_child("CheckForUpdates").get_value_or (false);
427 _check_for_test_updates = f.optional_bool_child("CheckForTestUpdates").get_value_or (false);
429 _maximum_j2k_bandwidth = f.optional_number_child<int> ("MaximumJ2KBandwidth").get_value_or (250000000);
430 _allow_any_dcp_frame_rate = f.optional_bool_child ("AllowAnyDCPFrameRate").get_value_or (false);
431 _allow_any_container = f.optional_bool_child ("AllowAnyContainer").get_value_or (false);
432 _allow_96khz_audio = f.optional_bool_child("Allow96kHzAudio").get_value_or(false);
433 _use_all_audio_channels = f.optional_bool_child("UseAllAudioChannels").get_value_or(false);
434 _show_experimental_audio_processors = f.optional_bool_child ("ShowExperimentalAudioProcessors").get_value_or (false);
436 _log_types = f.optional_number_child<int> ("LogTypes").get_value_or (LogEntry::TYPE_GENERAL | LogEntry::TYPE_WARNING | LogEntry::TYPE_ERROR);
437 _analyse_ebur128 = f.optional_bool_child("AnalyseEBUR128").get_value_or (true);
438 _automatic_audio_analysis = f.optional_bool_child ("AutomaticAudioAnalysis").get_value_or (false);
439 #ifdef DCPOMATIC_WINDOWS
440 _win32_console = f.optional_bool_child ("Win32Console").get_value_or (false);
443 for (auto i: f.node_children("History")) {
444 _history.push_back (i->content ());
447 for (auto i: f.node_children("PlayerHistory")) {
448 _player_history.push_back (i->content ());
451 auto signer = f.optional_node_child ("Signer");
453 auto c = make_shared<dcp::CertificateChain>();
454 /* Read the signing certificates and private key in from the config file */
455 for (auto i: signer->node_children ("Certificate")) {
456 c->add (dcp::Certificate (i->content ()));
458 c->set_key (signer->string_child ("PrivateKey"));
461 /* Make a new set of signing certificates and key */
462 _signer_chain = create_certificate_chain ();
465 auto decryption = f.optional_node_child ("Decryption");
467 auto c = make_shared<dcp::CertificateChain>();
468 for (auto i: decryption->node_children ("Certificate")) {
469 c->add (dcp::Certificate (i->content ()));
471 c->set_key (decryption->string_child ("PrivateKey"));
472 _decryption_chain = c;
474 _decryption_chain = create_certificate_chain ();
477 /* These must be done before we call Bad as that might set one
480 for (auto i: f.node_children("Nagged")) {
481 auto const id = i->number_attribute<int>("Id");
482 if (id >= 0 && id < NAG_COUNT) {
483 _nagged[id] = raw_convert<int>(i->content());
487 auto bad = check_certificates ();
489 auto const remake = Bad(*bad);
490 if (remake && *remake) {
492 case BAD_SIGNER_UTF8_STRINGS:
493 case BAD_SIGNER_INCONSISTENT:
494 case BAD_SIGNER_VALIDITY_TOO_LONG:
495 _signer_chain = create_certificate_chain ();
497 case BAD_DECRYPTION_INCONSISTENT:
498 _decryption_chain = create_certificate_chain ();
504 if (f.optional_node_child("DKDMGroup")) {
505 /* New-style: all DKDMs in a group */
506 _dkdms = dynamic_pointer_cast<DKDMGroup> (DKDMBase::read (f.node_child("DKDMGroup")));
508 /* Old-style: one or more DKDM nodes */
509 _dkdms = make_shared<DKDMGroup>("root");
510 for (auto i: f.node_children("DKDM")) {
511 _dkdms->add (DKDMBase::read (i));
514 _cinemas_file = f.optional_string_child("CinemasFile").get_value_or(read_path("cinemas.xml").string());
515 _dkdm_recipients_file = f.optional_string_child("DKDMRecipientsFile").get_value_or(read_path("dkdm_recipients.xml").string());
516 _show_hints_before_make_dcp = f.optional_bool_child("ShowHintsBeforeMakeDCP").get_value_or (true);
517 _confirm_kdm_email = f.optional_bool_child("ConfirmKDMEmail").get_value_or (true);
518 _kdm_container_name_format = dcp::NameFormat (f.optional_string_child("KDMContainerNameFormat").get_value_or ("KDM %f %c"));
519 _kdm_filename_format = dcp::NameFormat (f.optional_string_child("KDMFilenameFormat").get_value_or ("KDM %f %c %s"));
520 _dkdm_filename_format = dcp::NameFormat (f.optional_string_child("DKDMFilenameFormat").get_value_or("DKDM %f %c %s"));
521 _dcp_metadata_filename_format = dcp::NameFormat (f.optional_string_child("DCPMetadataFilenameFormat").get_value_or ("%t"));
522 _dcp_asset_filename_format = dcp::NameFormat (f.optional_string_child("DCPAssetFilenameFormat").get_value_or ("%t"));
523 _jump_to_selected = f.optional_bool_child("JumpToSelected").get_value_or (true);
524 /* The variable was renamed but not the XML tag */
525 _sound = f.optional_bool_child("PreviewSound").get_value_or (true);
526 _sound_output = f.optional_string_child("PreviewSoundOutput");
527 if (f.optional_string_child("CoverSheet")) {
528 _cover_sheet = f.optional_string_child("CoverSheet").get();
530 _last_player_load_directory = f.optional_string_child("LastPlayerLoadDirectory");
531 if (f.optional_string_child("LastKDMWriteType")) {
532 if (f.optional_string_child("LastKDMWriteType").get() == "flat") {
533 _last_kdm_write_type = KDM_WRITE_FLAT;
534 } else if (f.optional_string_child("LastKDMWriteType").get() == "folder") {
535 _last_kdm_write_type = KDM_WRITE_FOLDER;
536 } else if (f.optional_string_child("LastKDMWriteType").get() == "zip") {
537 _last_kdm_write_type = KDM_WRITE_ZIP;
540 if (f.optional_string_child("LastDKDMWriteType")) {
541 if (f.optional_string_child("LastDKDMWriteType").get() == "internal") {
542 _last_dkdm_write_type = DKDM_WRITE_INTERNAL;
543 } else if (f.optional_string_child("LastDKDMWriteType").get() == "file") {
544 _last_dkdm_write_type = DKDM_WRITE_FILE;
547 _frames_in_memory_multiplier = f.optional_number_child<int>("FramesInMemoryMultiplier").get_value_or(3);
548 _decode_reduction = f.optional_number_child<int>("DecodeReduction");
549 _default_notify = f.optional_bool_child("DefaultNotify").get_value_or(false);
551 for (auto i: f.node_children("Notification")) {
552 int const id = i->number_attribute<int>("Id");
553 if (id >= 0 && id < NOTIFICATION_COUNT) {
554 _notification[id] = raw_convert<int>(i->content());
558 _barco_username = f.optional_string_child("BarcoUsername");
559 _barco_password = f.optional_string_child("BarcoPassword");
560 _christie_username = f.optional_string_child("ChristieUsername");
561 _christie_password = f.optional_string_child("ChristiePassword");
562 _gdc_username = f.optional_string_child("GDCUsername");
563 _gdc_password = f.optional_string_child("GDCPassword");
565 auto pm = f.optional_string_child("PlayerMode");
566 if (pm && *pm == "window") {
567 _player_mode = PLAYER_MODE_WINDOW;
568 } else if (pm && *pm == "full") {
569 _player_mode = PLAYER_MODE_FULL;
570 } else if (pm && *pm == "dual") {
571 _player_mode = PLAYER_MODE_DUAL;
574 _image_display = f.optional_number_child<int>("ImageDisplay").get_value_or(0);
575 auto vc = f.optional_string_child("VideoViewType");
576 if (vc && *vc == "opengl") {
577 _video_view_type = VIDEO_VIEW_OPENGL;
578 } else if (vc && *vc == "simple") {
579 _video_view_type = VIDEO_VIEW_SIMPLE;
581 _respect_kdm_validity_periods = f.optional_bool_child("RespectKDMValidityPeriods").get_value_or(true);
582 _player_debug_log_file = f.optional_string_child("PlayerDebugLogFile");
583 _player_content_directory = f.optional_string_child("PlayerContentDirectory");
584 _player_playlist_directory = f.optional_string_child("PlayerPlaylistDirectory");
585 _player_kdm_directory = f.optional_string_child("PlayerKDMDirectory");
587 if (f.optional_node_child("AudioMapping")) {
588 _audio_mapping = AudioMapping (f.node_child("AudioMapping"), Film::current_state_version);
591 for (auto i: f.node_children("CustomLanguage")) {
593 /* This will fail if it's called before dcp::init() as it won't recognise the
594 * tag. That's OK because the Config will be reloaded again later.
596 _custom_languages.push_back (dcp::LanguageTag(i->content()));
597 } catch (std::runtime_error& e) {}
600 _add_files_path = f.optional_string_child("AddFilesPath");
601 _use_isdcf_name_by_default = f.optional_bool_child("UseISDCFNameByDefault").get_value_or(true);
602 _write_kdms_to_disk = f.optional_bool_child("WriteKDMsToDisk").get_value_or(true);
603 _email_kdms = f.optional_bool_child("EmailKDMs").get_value_or(false);
604 _default_kdm_type = dcp::string_to_formulation(f.optional_string_child("DefaultKDMType").get_value_or("modified-transitional-1"));
605 if (auto duration = f.optional_node_child("DefaultKDMDuration")) {
606 _default_kdm_duration = RoughDuration(duration);
608 _default_kdm_duration = RoughDuration(1, RoughDuration::Unit::WEEKS);
610 _auto_crop_threshold = f.optional_number_child<double>("AutoCropThreshold").get_value_or(0.1);
611 _last_release_notes_version = f.optional_string_child("LastReleaseNotesVersion");
612 _main_divider_sash_position = f.optional_number_child<int>("MainDividerSashPosition");
613 _main_content_divider_sash_position = f.optional_number_child<int>("MainContentDividerSashPosition");
615 _export.read(f.optional_node_child("Export"));
618 if (have_existing("config.xml")) {
620 /* We have a config file but it didn't load */
621 FailedToLoad(LoadFailure::CONFIG);
624 /* Make a new set of signing certificates and key */
625 _signer_chain = create_certificate_chain ();
626 /* And similar for decryption of KDMs */
627 _decryption_chain = create_certificate_chain ();
633 Config::read_cinemas()
635 if (boost::filesystem::exists (_cinemas_file)) {
637 cxml::Document f("Cinemas");
638 f.read_file(_cinemas_file);
642 FailedToLoad(LoadFailure::CINEMAS);
650 Config::read_dkdm_recipients()
652 if (boost::filesystem::exists (_dkdm_recipients_file)) {
654 cxml::Document f("DKDMRecipients");
655 f.read_file(_dkdm_recipients_file);
656 read_dkdm_recipients(f);
659 FailedToLoad(LoadFailure::DKDM_RECIPIENTS);
660 write_dkdm_recipients();
666 /** @return Singleton instance */
670 if (_instance == nullptr) {
671 _instance = new Config;
678 /** Write our configuration to disk */
680 Config::write () const
684 write_dkdm_recipients ();
688 Config::write_config () const
691 auto root = doc.create_root_node ("Config");
693 /* [XML] Version The version number of the configuration file format. */
694 root->add_child("Version")->add_child_text (raw_convert<string>(_current_version));
695 /* [XML] MasterEncodingThreads Number of encoding threads to use when running as master. */
696 root->add_child("MasterEncodingThreads")->add_child_text (raw_convert<string> (_master_encoding_threads));
697 /* [XML] ServerEncodingThreads Number of encoding threads to use when running as server. */
698 root->add_child("ServerEncodingThreads")->add_child_text (raw_convert<string> (_server_encoding_threads));
699 if (_default_directory) {
700 /* [XML:opt] DefaultDirectory Default directory when creating a new film in the GUI. */
701 root->add_child("DefaultDirectory")->add_child_text (_default_directory->string ());
703 /* [XML] ServerPortBase Port number to use for frame encoding requests. <code>ServerPortBase</code> + 1 and
704 <code>ServerPortBase</code> + 2 are used for querying servers. <code>ServerPortBase</code> + 3 is used
705 by the batch converter to listen for job requests.
707 root->add_child("ServerPortBase")->add_child_text (raw_convert<string> (_server_port_base));
708 /* [XML] UseAnyServers 1 to broadcast to look for encoding servers to use, 0 to use only those configured. */
709 root->add_child("UseAnyServers")->add_child_text (_use_any_servers ? "1" : "0");
711 for (auto i: _servers) {
712 /* [XML:opt] Server IP address or hostname of an encoding server to use; you can use as many of these tags
715 root->add_child("Server")->add_child_text (i);
718 /* [XML] OnlyServersEncode 1 to set the master to do decoding of source content no JPEG2000 encoding; all encoding
719 is done by the encoding servers. 0 to set the master to do some encoding as well as coordinating the job.
721 root->add_child("OnlyServersEncode")->add_child_text (_only_servers_encode ? "1" : "0");
722 /* [XML] TMSProtocol Protocol to use to copy files to a TMS; 0 to use SCP, 1 for FTP. */
723 root->add_child("TMSProtocol")->add_child_text (raw_convert<string> (static_cast<int> (_tms_protocol)));
724 /* [XML] TMSPassive True to use PASV mode with TMS FTP connections. */
725 root->add_child("TMSPassive")->add_child_text(_tms_passive ? "1" : "0");
726 /* [XML] TMSIP IP address of TMS. */
727 root->add_child("TMSIP")->add_child_text (_tms_ip);
728 /* [XML] TMSPath Path on the TMS to copy files to. */
729 root->add_child("TMSPath")->add_child_text (_tms_path);
730 /* [XML] TMSUser Username to log into the TMS with. */
731 root->add_child("TMSUser")->add_child_text (_tms_user);
732 /* [XML] TMSPassword Password to log into the TMS with. */
733 root->add_child("TMSPassword")->add_child_text (_tms_password);
735 /* [XML:opt] Language Language to use in the GUI e.g. <code>fr_FR</code>. */
736 root->add_child("Language")->add_child_text (_language.get());
738 if (_default_container) {
739 /* [XML:opt] DefaultContainer ID of default container
740 to use when creating new films (<code>185</code>,<code>239</code> or
743 root->add_child("DefaultContainer")->add_child_text (_default_container->id ());
745 if (_default_dcp_content_type) {
746 /* [XML:opt] DefaultDCPContentType Default content type to use when creating new films (<code>FTR</code>, <code>SHR</code>,
747 <code>TLR</code>, <code>TST</code>, <code>XSN</code>, <code>RTG</code>, <code>TSR</code>, <code>POL</code>,
748 <code>PSA</code> or <code>ADV</code>). */
749 root->add_child("DefaultDCPContentType")->add_child_text (_default_dcp_content_type->isdcf_name ());
751 /* [XML] DefaultDCPAudioChannels Default number of audio channels to use when creating new films. */
752 root->add_child("DefaultDCPAudioChannels")->add_child_text (raw_convert<string> (_default_dcp_audio_channels));
753 /* [XML] DCPIssuer Issuer text to write into CPL files. */
754 root->add_child("DCPIssuer")->add_child_text (_dcp_issuer);
755 /* [XML] DCPCreator Creator text to write into CPL files. */
756 root->add_child("DCPCreator")->add_child_text (_dcp_creator);
757 /* [XML] Company name to write into MXF files. */
758 root->add_child("DCPCompanyName")->add_child_text (_dcp_company_name);
759 /* [XML] Product name to write into MXF files. */
760 root->add_child("DCPProductName")->add_child_text (_dcp_product_name);
761 /* [XML] Product version to write into MXF files. */
762 root->add_child("DCPProductVersion")->add_child_text (_dcp_product_version);
763 /* [XML] Comment to write into JPEG2000 data. */
764 root->add_child("DCPJ2KComment")->add_child_text (_dcp_j2k_comment);
765 /* [XML] UploadAfterMakeDCP 1 to upload to a TMS after making a DCP, 0 for no upload. */
766 root->add_child("UploadAfterMakeDCP")->add_child_text (_upload_after_make_dcp ? "1" : "0");
768 /* [XML] DefaultStillLength Default length (in seconds) for still images in new films. */
769 root->add_child("DefaultStillLength")->add_child_text (raw_convert<string> (_default_still_length));
770 /* [XML] DefaultJ2KBandwidth Default bitrate (in bits per second) for JPEG2000 data in new films. */
771 root->add_child("DefaultJ2KBandwidth")->add_child_text (raw_convert<string> (_default_j2k_bandwidth));
772 /* [XML] DefaultAudioDelay Default delay to apply to audio (positive moves audio later) in milliseconds. */
773 root->add_child("DefaultAudioDelay")->add_child_text (raw_convert<string> (_default_audio_delay));
774 /* [XML] DefaultInterop 1 to default new films to Interop, 0 for SMPTE. */
775 root->add_child("DefaultInterop")->add_child_text (_default_interop ? "1" : "0");
776 for (auto const& i: _default_metadata) {
777 auto c = root->add_child("DefaultMetadata");
778 c->set_attribute("key", i.first);
779 c->add_child_text(i.second);
781 if (_default_kdm_directory) {
782 /* [XML:opt] DefaultKDMDirectory Default directory to write KDMs to. */
783 root->add_child("DefaultKDMDirectory")->add_child_text (_default_kdm_directory->string ());
785 _default_kdm_duration.as_xml(root->add_child("DefaultKDMDuration"));
786 /* [XML] MailServer Hostname of SMTP server to use. */
787 root->add_child("MailServer")->add_child_text (_mail_server);
788 /* [XML] MailPort Port number to use on SMTP server. */
789 root->add_child("MailPort")->add_child_text (raw_convert<string> (_mail_port));
790 /* [XML] MailProtocol Protocol to use on SMTP server (Auto, Plain, STARTTLS or SSL) */
791 switch (_mail_protocol) {
792 case EmailProtocol::AUTO:
793 root->add_child("MailProtocol")->add_child_text("Auto");
795 case EmailProtocol::PLAIN:
796 root->add_child("MailProtocol")->add_child_text("Plain");
798 case EmailProtocol::STARTTLS:
799 root->add_child("MailProtocol")->add_child_text("STARTTLS");
801 case EmailProtocol::SSL:
802 root->add_child("MailProtocol")->add_child_text("SSL");
805 /* [XML] MailUser Username to use on SMTP server. */
806 root->add_child("MailUser")->add_child_text (_mail_user);
807 /* [XML] MailPassword Password to use on SMTP server. */
808 root->add_child("MailPassword")->add_child_text (_mail_password);
810 /* [XML] KDMSubject Subject to use for KDM emails. */
811 root->add_child("KDMSubject")->add_child_text (_kdm_subject);
812 /* [XML] KDMFrom From address to use for KDM emails. */
813 root->add_child("KDMFrom")->add_child_text (_kdm_from);
814 for (auto i: _kdm_cc) {
815 /* [XML] KDMCC CC address to use for KDM emails; you can use as many of these tags as you like. */
816 root->add_child("KDMCC")->add_child_text (i);
818 /* [XML] KDMBCC BCC address to use for KDM emails. */
819 root->add_child("KDMBCC")->add_child_text (_kdm_bcc);
820 /* [XML] KDMEmail Text of KDM email. */
821 root->add_child("KDMEmail")->add_child_text (_kdm_email);
823 /* [XML] NotificationSubject Subject to use for notification emails. */
824 root->add_child("NotificationSubject")->add_child_text (_notification_subject);
825 /* [XML] NotificationFrom From address to use for notification emails. */
826 root->add_child("NotificationFrom")->add_child_text (_notification_from);
827 /* [XML] NotificationFrom To address to use for notification emails. */
828 root->add_child("NotificationTo")->add_child_text (_notification_to);
829 for (auto i: _notification_cc) {
830 /* [XML] NotificationCC CC address to use for notification emails; you can use as many of these tags as you like. */
831 root->add_child("NotificationCC")->add_child_text (i);
833 /* [XML] NotificationBCC BCC address to use for notification emails. */
834 root->add_child("NotificationBCC")->add_child_text (_notification_bcc);
835 /* [XML] NotificationEmail Text of notification email. */
836 root->add_child("NotificationEmail")->add_child_text (_notification_email);
838 /* [XML] CheckForUpdates 1 to check dcpomatic.com for new versions, 0 to check only on request. */
839 root->add_child("CheckForUpdates")->add_child_text (_check_for_updates ? "1" : "0");
840 /* [XML] CheckForUpdates 1 to check dcpomatic.com for new text versions, 0 to check only on request. */
841 root->add_child("CheckForTestUpdates")->add_child_text (_check_for_test_updates ? "1" : "0");
843 /* [XML] MaximumJ2KBandwidth Maximum J2K bandwidth (in bits per second) that can be specified in the GUI. */
844 root->add_child("MaximumJ2KBandwidth")->add_child_text (raw_convert<string> (_maximum_j2k_bandwidth));
845 /* [XML] AllowAnyDCPFrameRate 1 to allow users to specify any frame rate when creating DCPs, 0 to limit the GUI to standard rates. */
846 root->add_child("AllowAnyDCPFrameRate")->add_child_text (_allow_any_dcp_frame_rate ? "1" : "0");
847 /* [XML] AllowAnyContainer 1 to allow users to user any container ratio for their DCP, 0 to limit the GUI to DCI Flat/Scope */
848 root->add_child("AllowAnyContainer")->add_child_text (_allow_any_container ? "1" : "0");
849 /* [XML] Allow96kHzAudio 1 to allow users to make DCPs with 96kHz audio, 0 to always make 48kHz DCPs */
850 root->add_child("Allow96kHzAudio")->add_child_text(_allow_96khz_audio ? "1" : "0");
851 /* [XML] UseAllAudioChannels 1 to allow users to map audio to all 16 DCP channels, 0 to limit to the channels used in standard DCPs */
852 root->add_child("UseAllAudioChannels")->add_child_text(_use_all_audio_channels ? "1" : "0");
853 /* [XML] ShowExperimentalAudioProcessors 1 to offer users the (experimental) audio upmixer processors, 0 to hide them */
854 root->add_child("ShowExperimentalAudioProcessors")->add_child_text (_show_experimental_audio_processors ? "1" : "0");
855 /* [XML] LogTypes Types of logging to write; a bitfield where 1 is general notes, 2 warnings, 4 errors, 8 debug information related
856 to 3D, 16 debug information related to encoding, 32 debug information for timing purposes, 64 debug information related
857 to sending email, 128 debug information related to the video view, 256 information about disk writing, 512 debug information
858 related to the player, 1024 debug information related to audio analyses.
860 root->add_child("LogTypes")->add_child_text (raw_convert<string> (_log_types));
861 /* [XML] AnalyseEBUR128 1 to do EBUR128 analyses when analysing audio, otherwise 0. */
862 root->add_child("AnalyseEBUR128")->add_child_text (_analyse_ebur128 ? "1" : "0");
863 /* [XML] AutomaticAudioAnalysis 1 to run audio analysis automatically when audio content is added to the film, otherwise 0. */
864 root->add_child("AutomaticAudioAnalysis")->add_child_text (_automatic_audio_analysis ? "1" : "0");
865 #ifdef DCPOMATIC_WINDOWS
866 if (_win32_console) {
867 /* [XML] Win32Console 1 to open a console when running on Windows, otherwise 0.
868 * We only write this if it's true, which is a bit of a hack to allow unit tests to work
869 * more easily on Windows (without a platform-specific reference in config_write_utf8_test)
871 root->add_child("Win32Console")->add_child_text ("1");
875 /* [XML] Signer Certificate chain and private key to use when signing DCPs and KDMs. Should contain <code><Certificate></code>
876 tags in order and a <code><PrivateKey></code> tag all containing PEM-encoded certificates or private keys as appropriate.
878 auto signer = root->add_child ("Signer");
879 DCPOMATIC_ASSERT (_signer_chain);
880 for (auto const& i: _signer_chain->unordered()) {
881 signer->add_child("Certificate")->add_child_text (i.certificate (true));
883 signer->add_child("PrivateKey")->add_child_text (_signer_chain->key().get ());
885 /* [XML] Decryption Certificate chain and private key to use when decrypting KDMs */
886 auto decryption = root->add_child ("Decryption");
887 DCPOMATIC_ASSERT (_decryption_chain);
888 for (auto const& i: _decryption_chain->unordered()) {
889 decryption->add_child("Certificate")->add_child_text (i.certificate (true));
891 decryption->add_child("PrivateKey")->add_child_text (_decryption_chain->key().get ());
893 /* [XML] History Filename of DCP to present in the <guilabel>File</guilabel> menu of the GUI; there can be more than one
896 for (auto i: _history) {
897 root->add_child("History")->add_child_text (i.string ());
900 /* [XML] History Filename of DCP to present in the <guilabel>File</guilabel> menu of the player; there can be more than one
903 for (auto i: _player_history) {
904 root->add_child("PlayerHistory")->add_child_text (i.string ());
907 /* [XML] DKDMGroup A group of DKDMs, each with a <code>Name</code> attribute, containing other <code><DKDMGroup></code>
908 or <code><DKDM></code> tags.
910 /* [XML] DKDM A DKDM as XML */
911 _dkdms->as_xml (root);
913 /* [XML] CinemasFile Filename of cinemas list file. */
914 root->add_child("CinemasFile")->add_child_text (_cinemas_file.string());
915 /* [XML] DKDMRecipientsFile Filename of DKDM recipients list file. */
916 root->add_child("DKDMRecipientsFile")->add_child_text (_dkdm_recipients_file.string());
917 /* [XML] ShowHintsBeforeMakeDCP 1 to show hints in the GUI before making a DCP, otherwise 0. */
918 root->add_child("ShowHintsBeforeMakeDCP")->add_child_text (_show_hints_before_make_dcp ? "1" : "0");
919 /* [XML] ConfirmKDMEmail 1 to confirm before sending KDM emails in the GUI, otherwise 0. */
920 root->add_child("ConfirmKDMEmail")->add_child_text (_confirm_kdm_email ? "1" : "0");
921 /* [XML] KDMFilenameFormat Format for KDM filenames. */
922 root->add_child("KDMFilenameFormat")->add_child_text (_kdm_filename_format.specification ());
923 /* [XML] KDMFilenameFormat Format for DKDM filenames. */
924 root->add_child("DKDMFilenameFormat")->add_child_text(_dkdm_filename_format.specification());
925 /* [XML] KDMContainerNameFormat Format for KDM containers (directories or ZIP files). */
926 root->add_child("KDMContainerNameFormat")->add_child_text (_kdm_container_name_format.specification ());
927 /* [XML] DCPMetadataFilenameFormat Format for DCP metadata filenames. */
928 root->add_child("DCPMetadataFilenameFormat")->add_child_text (_dcp_metadata_filename_format.specification ());
929 /* [XML] DCPAssetFilenameFormat Format for DCP asset filenames. */
930 root->add_child("DCPAssetFilenameFormat")->add_child_text (_dcp_asset_filename_format.specification ());
931 /* [XML] JumpToSelected 1 to make the GUI jump to the start of content when it is selected, otherwise 0. */
932 root->add_child("JumpToSelected")->add_child_text (_jump_to_selected ? "1" : "0");
933 /* [XML] Nagged 1 if a particular nag screen has been shown and should not be shown again, otherwise 0. */
934 for (int i = 0; i < NAG_COUNT; ++i) {
935 xmlpp::Element* e = root->add_child ("Nagged");
936 e->set_attribute ("Id", raw_convert<string>(i));
937 e->add_child_text (_nagged[i] ? "1" : "0");
939 /* [XML] PreviewSound 1 to use sound in the GUI preview and player, otherwise 0. */
940 root->add_child("PreviewSound")->add_child_text (_sound ? "1" : "0");
942 /* [XML:opt] PreviewSoundOutput Name of the audio output to use. */
943 root->add_child("PreviewSoundOutput")->add_child_text (_sound_output.get());
945 /* [XML] CoverSheet Text of the cover sheet to write when making DCPs. */
946 root->add_child("CoverSheet")->add_child_text (_cover_sheet);
947 if (_last_player_load_directory) {
948 root->add_child("LastPlayerLoadDirectory")->add_child_text(_last_player_load_directory->string());
950 /* [XML] LastKDMWriteType Last type of KDM-write: <code>flat</code> for a flat file, <code>folder</code> for a folder or <code>zip</code> for a ZIP file. */
951 if (_last_kdm_write_type) {
952 switch (_last_kdm_write_type.get()) {
954 root->add_child("LastKDMWriteType")->add_child_text("flat");
956 case KDM_WRITE_FOLDER:
957 root->add_child("LastKDMWriteType")->add_child_text("folder");
960 root->add_child("LastKDMWriteType")->add_child_text("zip");
964 /* [XML] LastDKDMWriteType Last type of DKDM-write: <code>file</code> for a file, <code>internal</code> to add to DCP-o-matic's list. */
965 if (_last_dkdm_write_type) {
966 switch (_last_dkdm_write_type.get()) {
967 case DKDM_WRITE_INTERNAL:
968 root->add_child("LastDKDMWriteType")->add_child_text("internal");
970 case DKDM_WRITE_FILE:
971 root->add_child("LastDKDMWriteType")->add_child_text("file");
975 /* [XML] FramesInMemoryMultiplier value to multiply the encoding threads count by to get the maximum number of
976 frames to be held in memory at once.
978 root->add_child("FramesInMemoryMultiplier")->add_child_text(raw_convert<string>(_frames_in_memory_multiplier));
980 /* [XML] DecodeReduction power of 2 to reduce DCP images by before decoding in the player. */
981 if (_decode_reduction) {
982 root->add_child("DecodeReduction")->add_child_text(raw_convert<string>(_decode_reduction.get()));
985 /* [XML] DefaultNotify 1 to default jobs to notify when complete, otherwise 0. */
986 root->add_child("DefaultNotify")->add_child_text(_default_notify ? "1" : "0");
988 /* [XML] Notification 1 if a notification type is enabled, otherwise 0. */
989 for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
990 xmlpp::Element* e = root->add_child ("Notification");
991 e->set_attribute ("Id", raw_convert<string>(i));
992 e->add_child_text (_notification[i] ? "1" : "0");
995 if (_barco_username) {
996 /* [XML] BarcoUsername Username for logging into Barco's servers when downloading server certificates. */
997 root->add_child("BarcoUsername")->add_child_text(*_barco_username);
999 if (_barco_password) {
1000 /* [XML] BarcoPassword Password for logging into Barco's servers when downloading server certificates. */
1001 root->add_child("BarcoPassword")->add_child_text(*_barco_password);
1004 if (_christie_username) {
1005 /* [XML] ChristieUsername Username for logging into Christie's servers when downloading server certificates. */
1006 root->add_child("ChristieUsername")->add_child_text(*_christie_username);
1008 if (_christie_password) {
1009 /* [XML] ChristiePassword Password for logging into Christie's servers when downloading server certificates. */
1010 root->add_child("ChristiePassword")->add_child_text(*_christie_password);
1013 if (_gdc_username) {
1014 /* [XML] GDCUsername Username for logging into GDC's servers when downloading server certificates. */
1015 root->add_child("GDCUsername")->add_child_text(*_gdc_username);
1017 if (_gdc_password) {
1018 /* [XML] GDCPassword Password for logging into GDC's servers when downloading server certificates. */
1019 root->add_child("GDCPassword")->add_child_text(*_gdc_password);
1022 /* [XML] PlayerMode <code>window</code> for a single window, <code>full</code> for full-screen and <code>dual</code> for full screen playback
1023 with controls on another monitor.
1025 switch (_player_mode) {
1026 case PLAYER_MODE_WINDOW:
1027 root->add_child("PlayerMode")->add_child_text("window");
1029 case PLAYER_MODE_FULL:
1030 root->add_child("PlayerMode")->add_child_text("full");
1032 case PLAYER_MODE_DUAL:
1033 root->add_child("PlayerMode")->add_child_text("dual");
1037 /* [XML] ImageDisplay Screen number to put image on in dual-screen player mode. */
1038 root->add_child("ImageDisplay")->add_child_text(raw_convert<string>(_image_display));
1039 switch (_video_view_type) {
1040 case VIDEO_VIEW_SIMPLE:
1041 root->add_child("VideoViewType")->add_child_text("simple");
1043 case VIDEO_VIEW_OPENGL:
1044 root->add_child("VideoViewType")->add_child_text("opengl");
1047 /* [XML] RespectKDMValidityPeriods 1 to refuse to use KDMs that are out of date, 0 to ignore KDM dates. */
1048 root->add_child("RespectKDMValidityPeriods")->add_child_text(_respect_kdm_validity_periods ? "1" : "0");
1049 if (_player_debug_log_file) {
1050 /* [XML] PlayerLogFile Filename to use for player debug logs. */
1051 root->add_child("PlayerDebugLogFile")->add_child_text(_player_debug_log_file->string());
1053 if (_player_content_directory) {
1054 /* [XML] PlayerContentDirectory Directory to use for player content in the dual-screen mode. */
1055 root->add_child("PlayerContentDirectory")->add_child_text(_player_content_directory->string());
1057 if (_player_playlist_directory) {
1058 /* [XML] PlayerPlaylistDirectory Directory to use for player playlists in the dual-screen mode. */
1059 root->add_child("PlayerPlaylistDirectory")->add_child_text(_player_playlist_directory->string());
1061 if (_player_kdm_directory) {
1062 /* [XML] PlayerKDMDirectory Directory to use for player KDMs in the dual-screen mode. */
1063 root->add_child("PlayerKDMDirectory")->add_child_text(_player_kdm_directory->string());
1065 if (_audio_mapping) {
1066 _audio_mapping->as_xml (root->add_child("AudioMapping"));
1068 for (auto const& i: _custom_languages) {
1069 root->add_child("CustomLanguage")->add_child_text(i.to_string());
1071 if (_add_files_path) {
1072 /* [XML] AddFilesPath The default path that will be offered in the picker when adding files to a film. */
1073 root->add_child("AddFilesPath")->add_child_text(_add_files_path->string());
1075 root->add_child("UseISDCFNameByDefault")->add_child_text(_use_isdcf_name_by_default ? "1" : "0");
1076 root->add_child("WriteKDMsToDisk")->add_child_text(_write_kdms_to_disk ? "1" : "0");
1077 root->add_child("EmailKDMs")->add_child_text(_email_kdms ? "1" : "0");
1078 root->add_child("DefaultKDMType")->add_child_text(dcp::formulation_to_string(_default_kdm_type));
1079 root->add_child("AutoCropThreshold")->add_child_text(raw_convert<string>(_auto_crop_threshold));
1080 if (_last_release_notes_version) {
1081 root->add_child("LastReleaseNotesVersion")->add_child_text(*_last_release_notes_version);
1083 if (_main_divider_sash_position) {
1084 root->add_child("MainDividerSashPosition")->add_child_text(raw_convert<string>(*_main_divider_sash_position));
1086 if (_main_content_divider_sash_position) {
1087 root->add_child("MainContentDividerSashPosition")->add_child_text(raw_convert<string>(*_main_content_divider_sash_position));
1090 _export.write(root->add_child("Export"));
1092 auto target = config_write_file();
1095 auto const s = doc.write_to_string_formatted ();
1096 boost::filesystem::path tmp (string(target.string()).append(".tmp"));
1097 dcp::File f(tmp, "w");
1099 throw FileError (_("Could not open file for writing"), tmp);
1101 f.checked_write(s.c_str(), s.bytes());
1103 boost::filesystem::remove (target);
1104 boost::filesystem::rename (tmp, target);
1105 } catch (xmlpp::exception& e) {
1106 string s = e.what ();
1108 throw FileError (s, target);
1115 write_file (string root_node, string node, string version, list<shared_ptr<T>> things, boost::filesystem::path file)
1117 xmlpp::Document doc;
1118 auto root = doc.create_root_node (root_node);
1119 root->add_child("Version")->add_child_text(version);
1121 for (auto i: things) {
1122 i->as_xml (root->add_child(node));
1126 doc.write_to_file_formatted (file.string() + ".tmp");
1127 boost::filesystem::remove (file);
1128 boost::filesystem::rename (file.string() + ".tmp", file);
1129 } catch (xmlpp::exception& e) {
1130 string s = e.what ();
1132 throw FileError (s, file);
1138 Config::write_cinemas () const
1140 write_file ("Cinemas", "Cinema", "1", _cinemas, _cinemas_file);
1145 Config::write_dkdm_recipients () const
1147 write_file ("DKDMRecipients", "DKDMRecipient", "1", _dkdm_recipients, _dkdm_recipients_file);
1151 boost::filesystem::path
1152 Config::default_directory_or (boost::filesystem::path a) const
1154 return directory_or (_default_directory, a);
1157 boost::filesystem::path
1158 Config::default_kdm_directory_or (boost::filesystem::path a) const
1160 return directory_or (_default_kdm_directory, a);
1163 boost::filesystem::path
1164 Config::directory_or (optional<boost::filesystem::path> dir, boost::filesystem::path a) const
1170 boost::system::error_code ec;
1171 auto const e = boost::filesystem::exists (*dir, ec);
1187 Config::changed (Property what)
1193 Config::set_kdm_email_to_default ()
1195 _kdm_subject = _("KDM delivery: $CPL_NAME");
1198 "Dear Projectionist\n\n"
1199 "Please find attached KDMs for $CPL_NAME.\n\n"
1200 "Cinema: $CINEMA_NAME\n"
1201 "Screen(s): $SCREENS\n\n"
1202 "The KDMs are valid from $START_TIME until $END_TIME.\n\n"
1203 "Best regards,\nDCP-o-matic"
1208 Config::set_notification_email_to_default ()
1210 _notification_subject = _("DCP-o-matic notification");
1212 _notification_email = _(
1213 "$JOB_NAME: $JOB_STATUS"
1218 Config::reset_kdm_email ()
1220 set_kdm_email_to_default ();
1225 Config::reset_notification_email ()
1227 set_notification_email_to_default ();
1232 Config::set_cover_sheet_to_default ()
1236 "CPL Filename: $CPL_FILENAME\n"
1238 "Format: $CONTAINER\n"
1240 "Audio Language: $AUDIO_LANGUAGE\n"
1241 "Subtitle Language: $SUBTITLE_LANGUAGE\n"
1248 Config::add_to_history (boost::filesystem::path p)
1250 add_to_history_internal (_history, p);
1253 /** Remove non-existent items from the history */
1255 Config::clean_history ()
1257 clean_history_internal (_history);
1261 Config::add_to_player_history (boost::filesystem::path p)
1263 add_to_history_internal (_player_history, p);
1266 /** Remove non-existant items from the player history */
1268 Config::clean_player_history ()
1270 clean_history_internal (_player_history);
1274 Config::add_to_history_internal (vector<boost::filesystem::path>& h, boost::filesystem::path p)
1276 /* Remove existing instances of this path in the history */
1277 h.erase (remove (h.begin(), h.end(), p), h.end ());
1279 h.insert (h.begin (), p);
1280 if (h.size() > HISTORY_SIZE) {
1288 Config::clean_history_internal (vector<boost::filesystem::path>& h)
1294 if (boost::filesystem::is_directory(i)) {
1298 /* We couldn't find out if it's a directory for some reason; just ignore it */
1305 Config::have_existing (string file)
1307 return boost::filesystem::exists (read_path(file));
1312 Config::read_cinemas (cxml::Document const & f)
1315 for (auto i: f.node_children("Cinema")) {
1316 /* Slightly grotty two-part construction of Cinema here so that we can use
1319 auto cinema = make_shared<Cinema>(i);
1320 cinema->read_screens (i);
1321 _cinemas.push_back (cinema);
1326 Config::set_cinemas_file (boost::filesystem::path file)
1328 if (file == _cinemas_file) {
1332 _cinemas_file = file;
1334 if (boost::filesystem::exists (_cinemas_file)) {
1335 /* Existing file; read it in */
1336 cxml::Document f ("Cinemas");
1337 f.read_file (_cinemas_file);
1347 Config::read_dkdm_recipients (cxml::Document const & f)
1349 _dkdm_recipients.clear ();
1350 for (auto i: f.node_children("DKDMRecipient")) {
1351 _dkdm_recipients.push_back (make_shared<DKDMRecipient>(i));
1357 Config::save_template (shared_ptr<const Film> film, string name) const
1359 film->write_template (template_write_path(name));
1364 Config::templates () const
1366 if (!boost::filesystem::exists(read_path("templates"))) {
1371 for (auto const& i: boost::filesystem::directory_iterator(read_path("templates"))) {
1372 n.push_back (i.path().filename().string());
1378 Config::existing_template (string name) const
1380 return boost::filesystem::exists (template_read_path(name));
1384 boost::filesystem::path
1385 Config::template_read_path (string name) const
1387 return read_path("templates") / tidy_for_filename (name);
1391 boost::filesystem::path
1392 Config::template_write_path (string name) const
1394 return write_path("templates") / tidy_for_filename (name);
1399 Config::rename_template (string old_name, string new_name) const
1401 boost::filesystem::rename (template_read_path(old_name), template_write_path(new_name));
1405 Config::delete_template (string name) const
1407 boost::filesystem::remove (template_write_path(name));
1410 /** @return Path to the config.xml containing the actual settings, following a link if required */
1411 boost::filesystem::path
1412 config_file (boost::filesystem::path main)
1414 cxml::Document f ("Config");
1415 if (!boost::filesystem::exists (main)) {
1416 /* It doesn't exist, so there can't be any links; just return it */
1420 /* See if there's a link */
1423 auto link = f.optional_string_child("Link");
1427 } catch (xmlpp::exception& e) {
1428 /* There as a problem reading the main configuration file,
1429 so there can't be a link.
1437 boost::filesystem::path
1438 Config::config_read_file ()
1440 return config_file (read_path("config.xml"));
1444 boost::filesystem::path
1445 Config::config_write_file ()
1447 return config_file (write_path("config.xml"));
1452 Config::reset_cover_sheet ()
1454 set_cover_sheet_to_default ();
1459 Config::link (boost::filesystem::path new_file) const
1461 xmlpp::Document doc;
1462 doc.create_root_node("Config")->add_child("Link")->add_child_text(new_file.string());
1464 doc.write_to_file_formatted(write_path("config.xml").string());
1465 } catch (xmlpp::exception& e) {
1466 string s = e.what ();
1468 throw FileError (s, write_path("config.xml"));
1473 Config::copy_and_link (boost::filesystem::path new_file) const
1476 boost::filesystem::copy_file (config_read_file(), new_file, boost::filesystem::copy_option::overwrite_if_exists);
1481 Config::have_write_permission () const
1483 dcp::File f(config_write_file(), "r+");
1484 return static_cast<bool>(f);
1487 /** @param output_channels Number of output channels in use.
1488 * @return Audio mapping for this output channel count (may be a default).
1491 Config::audio_mapping (int output_channels)
1493 if (!_audio_mapping || _audio_mapping->output_channels() != output_channels) {
1494 /* Set up a default */
1495 _audio_mapping = AudioMapping (MAX_DCP_AUDIO_CHANNELS, output_channels);
1496 if (output_channels == 2) {
1497 /* Special case for stereo output.
1498 Map so that Lt = L(-3dB) + Ls(-3dB) + C(-6dB) + Lfe(-10dB)
1499 Rt = R(-3dB) + Rs(-3dB) + C(-6dB) + Lfe(-10dB)
1501 _audio_mapping->set (dcp::Channel::LEFT, 0, 1 / sqrt(2)); // L -> Lt
1502 _audio_mapping->set (dcp::Channel::RIGHT, 1, 1 / sqrt(2)); // R -> Rt
1503 _audio_mapping->set (dcp::Channel::CENTRE, 0, 1 / 2.0); // C -> Lt
1504 _audio_mapping->set (dcp::Channel::CENTRE, 1, 1 / 2.0); // C -> Rt
1505 _audio_mapping->set (dcp::Channel::LFE, 0, 1 / sqrt(10)); // Lfe -> Lt
1506 _audio_mapping->set (dcp::Channel::LFE, 1, 1 / sqrt(10)); // Lfe -> Rt
1507 _audio_mapping->set (dcp::Channel::LS, 0, 1 / sqrt(2)); // Ls -> Lt
1508 _audio_mapping->set (dcp::Channel::RS, 1, 1 / sqrt(2)); // Rs -> Rt
1511 for (int i = 0; i < min (MAX_DCP_AUDIO_CHANNELS, output_channels); ++i) {
1512 _audio_mapping->set (i, i, 1);
1517 return *_audio_mapping;
1521 Config::set_audio_mapping (AudioMapping m)
1524 changed (AUDIO_MAPPING);
1528 Config::set_audio_mapping_to_default ()
1530 DCPOMATIC_ASSERT (_audio_mapping);
1531 auto const ch = _audio_mapping->output_channels ();
1532 _audio_mapping = boost::none;
1533 _audio_mapping = audio_mapping (ch);
1534 changed (AUDIO_MAPPING);
1539 Config::add_custom_language (dcp::LanguageTag tag)
1541 if (find(_custom_languages.begin(), _custom_languages.end(), tag) == _custom_languages.end()) {
1542 _custom_languages.push_back (tag);
1548 optional<Config::BadReason>
1549 Config::check_certificates () const
1551 optional<BadReason> bad;
1553 for (auto const& i: _signer_chain->unordered()) {
1554 if (i.has_utf8_strings()) {
1555 bad = BAD_SIGNER_UTF8_STRINGS;
1557 if ((i.not_after().year() - i.not_before().year()) > 15) {
1558 bad = BAD_SIGNER_VALIDITY_TOO_LONG;
1562 if (!_signer_chain->chain_valid() || !_signer_chain->private_key_valid()) {
1563 bad = BAD_SIGNER_INCONSISTENT;
1566 if (!_decryption_chain->chain_valid() || !_decryption_chain->private_key_valid()) {
1567 bad = BAD_DECRYPTION_INCONSISTENT;
1575 save_all_config_as_zip (boost::filesystem::path zip_file)
1577 Zipper zipper (zip_file);
1579 auto config = Config::instance();
1580 zipper.add ("config.xml", dcp::file_to_string(config->config_read_file()));
1581 if (boost::filesystem::exists(config->cinemas_file())) {
1582 zipper.add ("cinemas.xml", dcp::file_to_string(config->cinemas_file()));
1584 if (boost::filesystem::exists(config->dkdm_recipients_file())) {
1585 zipper.add ("dkdm_recipients.xml", dcp::file_to_string(config->dkdm_recipients_file()));