Use FileDialog for saving preferences ZIPs.
[dcpomatic.git] / src / lib / config.cc
1 /*
2     Copyright (C) 2012-2022 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
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.
10
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.
15
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/>.
18
19 */
20
21
22 #include "cinema.h"
23 #include "colour_conversion.h"
24 #include "compose.hpp"
25 #include "config.h"
26 #include "constants.h"
27 #include "cross.h"
28 #include "dcp_content_type.h"
29 #include "dkdm_recipient.h"
30 #include "dkdm_wrapper.h"
31 #include "film.h"
32 #include "filter.h"
33 #include "log.h"
34 #include "ratio.h"
35 #include "zipper.h"
36 #include <dcp/certificate_chain.h>
37 #include <dcp/name_format.h>
38 #include <dcp/raw_convert.h>
39 #include <libcxml/cxml.h>
40 #include <glib.h>
41 #include <libxml++/libxml++.h>
42 #include <boost/filesystem.hpp>
43 #include <boost/algorithm/string.hpp>
44 #include <boost/thread.hpp>
45 #include <cstdlib>
46 #include <fstream>
47 #include <iostream>
48
49 #include "i18n.h"
50
51
52 using std::cout;
53 using std::dynamic_pointer_cast;
54 using std::ifstream;
55 using std::list;
56 using std::make_shared;
57 using std::max;
58 using std::min;
59 using std::remove;
60 using std::shared_ptr;
61 using std::string;
62 using std::vector;
63 using boost::algorithm::trim;
64 using boost::optional;
65 using dcp::raw_convert;
66
67
68 Config* Config::_instance = 0;
69 int const Config::_current_version = 3;
70 boost::signals2::signal<void (Config::LoadFailure)> Config::FailedToLoad;
71 boost::signals2::signal<void (string)> Config::Warning;
72 boost::signals2::signal<bool (Config::BadReason)> Config::Bad;
73
74
75 /** Construct default configuration */
76 Config::Config ()
77         /* DKDMs are not considered a thing to reset on set_defaults() */
78         : _dkdms (new DKDMGroup ("root"))
79         , _default_kdm_duration (1, RoughDuration::Unit::WEEKS)
80         , _export(this)
81 {
82         set_defaults ();
83 }
84
85 void
86 Config::set_defaults ()
87 {
88         _master_encoding_threads = max (2U, boost::thread::hardware_concurrency ());
89         _server_encoding_threads = max (2U, boost::thread::hardware_concurrency ());
90         _server_port_base = 6192;
91         _use_any_servers = true;
92         _servers.clear ();
93         _only_servers_encode = false;
94         _tms_protocol = FileTransferProtocol::SCP;
95         _tms_passive = true;
96         _tms_ip = "";
97         _tms_path = ".";
98         _tms_user = "";
99         _tms_password = "";
100         _allow_any_dcp_frame_rate = false;
101         _allow_any_container = false;
102         _allow_96khz_audio = false;
103         _use_all_audio_channels = false;
104         _show_experimental_audio_processors = false;
105         _language = optional<string> ();
106         _default_still_length = 10;
107         _default_dcp_content_type = DCPContentType::from_isdcf_name ("FTR");
108         _default_dcp_audio_channels = 8;
109         _default_j2k_bandwidth = 150000000;
110         _default_audio_delay = 0;
111         _default_interop = false;
112         _default_metadata.clear ();
113         _upload_after_make_dcp = false;
114         _mail_server = "";
115         _mail_port = 25;
116         _mail_protocol = EmailProtocol::AUTO;
117         _mail_user = "";
118         _mail_password = "";
119         _kdm_from = "";
120         _kdm_cc.clear ();
121         _kdm_bcc = "";
122         _notification_from = "";
123         _notification_to = "";
124         _notification_cc.clear ();
125         _notification_bcc = "";
126         _check_for_updates = false;
127         _check_for_test_updates = false;
128         _maximum_j2k_bandwidth = 250000000;
129         _log_types = LogEntry::TYPE_GENERAL | LogEntry::TYPE_WARNING | LogEntry::TYPE_ERROR | LogEntry::TYPE_DISK;
130         _analyse_ebur128 = true;
131         _automatic_audio_analysis = false;
132 #ifdef DCPOMATIC_WINDOWS
133         _win32_console = false;
134 #endif
135         /* At the moment we don't write these files anywhere new after a version change, so they will be read from
136          * ~/.config/dcpomatic2 (or equivalent) and written back there.
137          */
138         _cinemas_file = read_path ("cinemas.xml");
139         _dkdm_recipients_file = read_path ("dkdm_recipients.xml");
140         _show_hints_before_make_dcp = true;
141         _confirm_kdm_email = true;
142         _kdm_container_name_format = dcp::NameFormat("KDM_%f_%c");
143         _kdm_filename_format = dcp::NameFormat("KDM_%f_%c_%s");
144         _dkdm_filename_format = dcp::NameFormat("DKDM_%f_%c_%s");
145         _dcp_metadata_filename_format = dcp::NameFormat ("%t");
146         _dcp_asset_filename_format = dcp::NameFormat ("%t");
147         _jump_to_selected = true;
148         for (int i = 0; i < NAG_COUNT; ++i) {
149                 _nagged[i] = false;
150         }
151         _sound = true;
152         _sound_output = optional<string> ();
153         _last_kdm_write_type = KDM_WRITE_FLAT;
154         _last_dkdm_write_type = DKDM_WRITE_INTERNAL;
155         _default_add_file_location = DefaultAddFileLocation::SAME_AS_LAST_TIME;
156
157         /* I think the scaling factor here should be the ratio of the longest frame
158            encode time to the shortest; if the thread count is T, longest time is L
159            and the shortest time S we could encode L/S frames per thread whilst waiting
160            for the L frame to encode so we might have to store LT/S frames.
161
162            However we don't want to use too much memory, so keep it a bit lower than we'd
163            perhaps like.  A J2K frame is typically about 1Mb so 3 here will mean we could
164            use about 240Mb with 72 encoding threads.
165         */
166         _frames_in_memory_multiplier = 3;
167         _decode_reduction = optional<int>();
168         _default_notify = false;
169         for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
170                 _notification[i] = false;
171         }
172         _barco_username = optional<string>();
173         _barco_password = optional<string>();
174         _christie_username = optional<string>();
175         _christie_password = optional<string>();
176         _gdc_username = optional<string>();
177         _gdc_password = optional<string>();
178         _player_mode = PLAYER_MODE_WINDOW;
179         _image_display = 0;
180         _video_view_type = VIDEO_VIEW_SIMPLE;
181         _respect_kdm_validity_periods = true;
182         _player_debug_log_file = boost::none;
183         _player_content_directory = boost::none;
184         _player_playlist_directory = boost::none;
185         _player_kdm_directory = boost::none;
186         _audio_mapping = boost::none;
187         _custom_languages.clear ();
188         _initial_paths.clear();
189         _initial_paths["AddFilesPath"] = boost::none;
190         _initial_paths["AddKDMPath"] = boost::none;
191         _initial_paths["AddDKDMPath"] = boost::none;
192         _initial_paths["SelectCertificatePath"] = boost::none;
193         _initial_paths["AddCombinerInputPath"] = boost::none;
194         _initial_paths["ExportSubtitlesPath"] = boost::none;
195         _initial_paths["ExportVideoPath"] = boost::none;
196         _initial_paths["DebugLogPath"] = boost::none;
197         _initial_paths["CinemaDatabasePath"] = boost::none;
198         _initial_paths["ConfigFilePath"] = boost::none;
199         _initial_paths["Preferences"] = boost::none;
200         _use_isdcf_name_by_default = true;
201         _write_kdms_to_disk = true;
202         _email_kdms = false;
203         _default_kdm_type = dcp::Formulation::MODIFIED_TRANSITIONAL_1;
204         _default_kdm_duration = RoughDuration(1, RoughDuration::Unit::WEEKS);
205         _auto_crop_threshold = 0.1;
206         _last_release_notes_version = boost::none;
207         _allow_smpte_bv20 = false;
208         _isdcf_name_part_length = 14;
209
210         _allowed_dcp_frame_rates.clear ();
211         _allowed_dcp_frame_rates.push_back (24);
212         _allowed_dcp_frame_rates.push_back (25);
213         _allowed_dcp_frame_rates.push_back (30);
214         _allowed_dcp_frame_rates.push_back (48);
215         _allowed_dcp_frame_rates.push_back (50);
216         _allowed_dcp_frame_rates.push_back (60);
217
218         set_kdm_email_to_default ();
219         set_notification_email_to_default ();
220         set_cover_sheet_to_default ();
221
222         _main_divider_sash_position = {};
223         _main_content_divider_sash_position = {};
224
225         _export.set_defaults();
226 }
227
228 void
229 Config::restore_defaults ()
230 {
231         Config::instance()->set_defaults ();
232         Config::instance()->changed ();
233 }
234
235 shared_ptr<dcp::CertificateChain>
236 Config::create_certificate_chain ()
237 {
238         return make_shared<dcp::CertificateChain> (
239                 openssl_path(),
240                 CERTIFICATE_VALIDITY_PERIOD,
241                 "dcpomatic.com",
242                 "dcpomatic.com",
243                 ".dcpomatic.smpte-430-2.ROOT",
244                 ".dcpomatic.smpte-430-2.INTERMEDIATE",
245                 "CS.dcpomatic.smpte-430-2.LEAF"
246                 );
247 }
248
249 void
250 Config::backup ()
251 {
252         using namespace boost::filesystem;
253
254         auto copy_adding_number = [](path const& path_to_copy) {
255
256                 auto add_number = [](path const& path, int number) {
257                         return String::compose("%1.%2", path, number);
258                 };
259
260                 int n = 1;
261                 while (n < 100 && exists(add_number(path_to_copy, n))) {
262                         ++n;
263                 }
264                 boost::system::error_code ec;
265                 copy_file(path_to_copy, add_number(path_to_copy, n), ec);
266         };
267
268         /* Make a backup copy of any config.xml, cinemas.xml, dkdm_recipients.xml that we might be about
269          * to write over.  This is more intended for the situation where we have a corrupted config.xml,
270          * and decide to overwrite it with a new one (possibly losing important details in the corrupted
271          * file).  But we might as well back up the other files while we're about it.
272          */
273
274         /* This uses the State::write_path stuff so, e.g. for a current version 2.16 we might copy
275          * ~/.config/dcpomatic2/2.16/config.xml to ~/.config/dcpomatic2/2.16/config.xml.1
276          */
277         copy_adding_number (config_write_file());
278
279         /* These do not use State::write_path, so whatever path is in the Config we will copy
280          * adding a number.
281          */
282         copy_adding_number (_cinemas_file);
283         copy_adding_number (_dkdm_recipients_file);
284 }
285
286 void
287 Config::read ()
288 {
289         read_config();
290         read_cinemas();
291         read_dkdm_recipients();
292 }
293
294
295 void
296 Config::read_config()
297 try
298 {
299         cxml::Document f ("Config");
300         f.read_file(dcp::filesystem::fix_long_path(config_read_file()));
301
302         auto version = f.optional_number_child<int> ("Version");
303         if (version && *version < _current_version) {
304                 /* Back up the old config before we re-write it in a back-incompatible way */
305                 backup ();
306         }
307
308         if (f.optional_number_child<int>("NumLocalEncodingThreads")) {
309                 _master_encoding_threads = _server_encoding_threads = f.optional_number_child<int>("NumLocalEncodingThreads").get();
310         } else {
311                 _master_encoding_threads = f.number_child<int>("MasterEncodingThreads");
312                 _server_encoding_threads = f.number_child<int>("ServerEncodingThreads");
313         }
314
315         _default_directory = f.optional_string_child ("DefaultDirectory");
316         if (_default_directory && _default_directory->empty ()) {
317                 /* We used to store an empty value for this to mean "none set" */
318                 _default_directory = boost::optional<boost::filesystem::path> ();
319         }
320
321         auto b = f.optional_number_child<int> ("ServerPort");
322         if (!b) {
323                 b = f.optional_number_child<int> ("ServerPortBase");
324         }
325         _server_port_base = b.get ();
326
327         auto u = f.optional_bool_child ("UseAnyServers");
328         _use_any_servers = u.get_value_or (true);
329
330         for (auto i: f.node_children("Server")) {
331                 if (i->node_children("HostName").size() == 1) {
332                         _servers.push_back (i->string_child ("HostName"));
333                 } else {
334                         _servers.push_back (i->content ());
335                 }
336         }
337
338         _only_servers_encode = f.optional_bool_child ("OnlyServersEncode").get_value_or (false);
339         _tms_protocol = static_cast<FileTransferProtocol>(f.optional_number_child<int>("TMSProtocol").get_value_or(static_cast<int>(FileTransferProtocol::SCP)));
340         _tms_passive = f.optional_bool_child("TMSPassive").get_value_or(true);
341         _tms_ip = f.string_child ("TMSIP");
342         _tms_path = f.string_child ("TMSPath");
343         _tms_user = f.string_child ("TMSUser");
344         _tms_password = f.string_child ("TMSPassword");
345
346         _language = f.optional_string_child ("Language");
347
348         _default_dcp_content_type = DCPContentType::from_isdcf_name(f.optional_string_child("DefaultDCPContentType").get_value_or("FTR"));
349         _default_dcp_audio_channels = f.optional_number_child<int>("DefaultDCPAudioChannels").get_value_or (6);
350
351         if (f.optional_string_child ("DCPMetadataIssuer")) {
352                 _dcp_issuer = f.string_child ("DCPMetadataIssuer");
353         } else if (f.optional_string_child ("DCPIssuer")) {
354                 _dcp_issuer = f.string_child ("DCPIssuer");
355         }
356
357         auto up = f.optional_bool_child("UploadAfterMakeDCP");
358         if (!up) {
359                 up = f.optional_bool_child("DefaultUploadAfterMakeDCP");
360         }
361         _upload_after_make_dcp = up.get_value_or (false);
362         _dcp_creator = f.optional_string_child ("DCPCreator").get_value_or ("");
363         _dcp_company_name = f.optional_string_child("DCPCompanyName").get_value_or("");
364         _dcp_product_name = f.optional_string_child("DCPProductName").get_value_or("");
365         _dcp_product_version = f.optional_string_child("DCPProductVersion").get_value_or("");
366         _dcp_j2k_comment = f.optional_string_child("DCPJ2KComment").get_value_or("");
367
368         _default_still_length = f.optional_number_child<int>("DefaultStillLength").get_value_or (10);
369         _default_j2k_bandwidth = f.optional_number_child<int>("DefaultJ2KBandwidth").get_value_or (200000000);
370         _default_audio_delay = f.optional_number_child<int>("DefaultAudioDelay").get_value_or (0);
371         _default_interop = f.optional_bool_child("DefaultInterop").get_value_or (false);
372
373         try {
374                 auto al = f.optional_string_child("DefaultAudioLanguage");
375                 if (al) {
376                         _default_audio_language = dcp::LanguageTag(*al);
377                 }
378         } catch (std::runtime_error&) {}
379
380         try {
381                 auto te = f.optional_string_child("DefaultTerritory");
382                 if (te) {
383                         _default_territory = dcp::LanguageTag::RegionSubtag(*te);
384                 }
385         } catch (std::runtime_error&) {}
386
387         for (auto const& i: f.node_children("DefaultMetadata")) {
388                 _default_metadata[i->string_attribute("key")] = i->content();
389         }
390
391         _default_kdm_directory = f.optional_string_child("DefaultKDMDirectory");
392
393         /* Read any cinemas that are still lying around in the config file
394          * from an old version.
395          */
396         read_cinemas (f);
397
398         _mail_server = f.string_child ("MailServer");
399         _mail_port = f.optional_number_child<int> ("MailPort").get_value_or (25);
400
401         {
402                 /* Make sure this matches the code in write_config */
403                 string const protocol = f.optional_string_child("MailProtocol").get_value_or("Auto");
404                 if (protocol == "Auto") {
405                         _mail_protocol = EmailProtocol::AUTO;
406                 } else if (protocol == "Plain") {
407                         _mail_protocol = EmailProtocol::PLAIN;
408                 } else if (protocol == "STARTTLS") {
409                         _mail_protocol = EmailProtocol::STARTTLS;
410                 } else if (protocol == "SSL") {
411                         _mail_protocol = EmailProtocol::SSL;
412                 }
413         }
414
415         _mail_user = f.optional_string_child("MailUser").get_value_or ("");
416         _mail_password = f.optional_string_child("MailPassword").get_value_or ("");
417
418         _kdm_subject = f.optional_string_child ("KDMSubject").get_value_or (_("KDM delivery: $CPL_NAME"));
419         _kdm_from = f.string_child ("KDMFrom");
420         for (auto i: f.node_children("KDMCC")) {
421                 if (!i->content().empty()) {
422                         _kdm_cc.push_back (i->content ());
423                 }
424         }
425         _kdm_bcc = f.optional_string_child ("KDMBCC").get_value_or ("");
426         _kdm_email = f.string_child ("KDMEmail");
427
428         _notification_subject = f.optional_string_child("NotificationSubject").get_value_or(_("DCP-o-matic notification"));
429         _notification_from = f.optional_string_child("NotificationFrom").get_value_or("");
430         _notification_to = f.optional_string_child("NotificationTo").get_value_or("");
431         for (auto i: f.node_children("NotificationCC")) {
432                 if (!i->content().empty()) {
433                         _notification_cc.push_back (i->content ());
434                 }
435         }
436         _notification_bcc = f.optional_string_child("NotificationBCC").get_value_or("");
437         if (f.optional_string_child("NotificationEmail")) {
438                 _notification_email = f.string_child("NotificationEmail");
439         }
440
441         _check_for_updates = f.optional_bool_child("CheckForUpdates").get_value_or (false);
442         _check_for_test_updates = f.optional_bool_child("CheckForTestUpdates").get_value_or (false);
443
444         _maximum_j2k_bandwidth = f.optional_number_child<int> ("MaximumJ2KBandwidth").get_value_or (250000000);
445         _allow_any_dcp_frame_rate = f.optional_bool_child ("AllowAnyDCPFrameRate").get_value_or (false);
446         _allow_any_container = f.optional_bool_child ("AllowAnyContainer").get_value_or (false);
447         _allow_96khz_audio = f.optional_bool_child("Allow96kHzAudio").get_value_or(false);
448         _use_all_audio_channels = f.optional_bool_child("UseAllAudioChannels").get_value_or(false);
449         _show_experimental_audio_processors = f.optional_bool_child ("ShowExperimentalAudioProcessors").get_value_or (false);
450
451         _log_types = f.optional_number_child<int> ("LogTypes").get_value_or (LogEntry::TYPE_GENERAL | LogEntry::TYPE_WARNING | LogEntry::TYPE_ERROR);
452         _analyse_ebur128 = f.optional_bool_child("AnalyseEBUR128").get_value_or (true);
453         _automatic_audio_analysis = f.optional_bool_child ("AutomaticAudioAnalysis").get_value_or (false);
454 #ifdef DCPOMATIC_WINDOWS
455         _win32_console = f.optional_bool_child ("Win32Console").get_value_or (false);
456 #endif
457
458         for (auto i: f.node_children("History")) {
459                 _history.push_back (i->content ());
460         }
461
462         for (auto i: f.node_children("PlayerHistory")) {
463                 _player_history.push_back (i->content ());
464         }
465
466         auto signer = f.optional_node_child ("Signer");
467         if (signer) {
468                 auto c = make_shared<dcp::CertificateChain>();
469                 /* Read the signing certificates and private key in from the config file */
470                 for (auto i: signer->node_children ("Certificate")) {
471                         c->add (dcp::Certificate (i->content ()));
472                 }
473                 c->set_key (signer->string_child ("PrivateKey"));
474                 _signer_chain = c;
475         } else {
476                 /* Make a new set of signing certificates and key */
477                 _signer_chain = create_certificate_chain ();
478         }
479
480         auto decryption = f.optional_node_child ("Decryption");
481         if (decryption) {
482                 auto c = make_shared<dcp::CertificateChain>();
483                 for (auto i: decryption->node_children ("Certificate")) {
484                         c->add (dcp::Certificate (i->content ()));
485                 }
486                 c->set_key (decryption->string_child ("PrivateKey"));
487                 _decryption_chain = c;
488         } else {
489                 _decryption_chain = create_certificate_chain ();
490         }
491
492         /* These must be done before we call Bad as that might set one
493            of the nags.
494         */
495         for (auto i: f.node_children("Nagged")) {
496                 auto const id = i->number_attribute<int>("Id");
497                 if (id >= 0 && id < NAG_COUNT) {
498                         _nagged[id] = raw_convert<int>(i->content());
499                 }
500         }
501
502         auto bad = check_certificates ();
503         if (bad) {
504                 auto const remake = Bad(*bad);
505                 if (remake && *remake) {
506                         switch (*bad) {
507                         case BAD_SIGNER_UTF8_STRINGS:
508                         case BAD_SIGNER_INCONSISTENT:
509                         case BAD_SIGNER_VALIDITY_TOO_LONG:
510                         case BAD_SIGNER_DN_QUALIFIER:
511                                 _signer_chain = create_certificate_chain ();
512                                 break;
513                         case BAD_DECRYPTION_INCONSISTENT:
514                                 _decryption_chain = create_certificate_chain ();
515                                 break;
516                         }
517                 }
518         }
519
520         if (f.optional_node_child("DKDMGroup")) {
521                 /* New-style: all DKDMs in a group */
522                 _dkdms = dynamic_pointer_cast<DKDMGroup> (DKDMBase::read (f.node_child("DKDMGroup")));
523         } else {
524                 /* Old-style: one or more DKDM nodes */
525                 _dkdms = make_shared<DKDMGroup>("root");
526                 for (auto i: f.node_children("DKDM")) {
527                         _dkdms->add (DKDMBase::read (i));
528                 }
529         }
530         _cinemas_file = f.optional_string_child("CinemasFile").get_value_or(read_path("cinemas.xml").string());
531         _dkdm_recipients_file = f.optional_string_child("DKDMRecipientsFile").get_value_or(read_path("dkdm_recipients.xml").string());
532         _show_hints_before_make_dcp = f.optional_bool_child("ShowHintsBeforeMakeDCP").get_value_or (true);
533         _confirm_kdm_email = f.optional_bool_child("ConfirmKDMEmail").get_value_or (true);
534         _kdm_container_name_format = dcp::NameFormat (f.optional_string_child("KDMContainerNameFormat").get_value_or ("KDM %f %c"));
535         _kdm_filename_format = dcp::NameFormat (f.optional_string_child("KDMFilenameFormat").get_value_or ("KDM %f %c %s"));
536         _dkdm_filename_format = dcp::NameFormat (f.optional_string_child("DKDMFilenameFormat").get_value_or("DKDM %f %c %s"));
537         _dcp_metadata_filename_format = dcp::NameFormat (f.optional_string_child("DCPMetadataFilenameFormat").get_value_or ("%t"));
538         _dcp_asset_filename_format = dcp::NameFormat (f.optional_string_child("DCPAssetFilenameFormat").get_value_or ("%t"));
539         _jump_to_selected = f.optional_bool_child("JumpToSelected").get_value_or (true);
540         /* The variable was renamed but not the XML tag */
541         _sound = f.optional_bool_child("PreviewSound").get_value_or (true);
542         _sound_output = f.optional_string_child("PreviewSoundOutput");
543         if (f.optional_string_child("CoverSheet")) {
544                 _cover_sheet = f.optional_string_child("CoverSheet").get();
545         }
546         _last_player_load_directory = f.optional_string_child("LastPlayerLoadDirectory");
547         if (f.optional_string_child("LastKDMWriteType")) {
548                 if (f.optional_string_child("LastKDMWriteType").get() == "flat") {
549                         _last_kdm_write_type = KDM_WRITE_FLAT;
550                 } else if (f.optional_string_child("LastKDMWriteType").get() == "folder") {
551                         _last_kdm_write_type = KDM_WRITE_FOLDER;
552                 } else if (f.optional_string_child("LastKDMWriteType").get() == "zip") {
553                         _last_kdm_write_type = KDM_WRITE_ZIP;
554                 }
555         }
556         if (f.optional_string_child("LastDKDMWriteType")) {
557                 if (f.optional_string_child("LastDKDMWriteType").get() == "internal") {
558                         _last_dkdm_write_type = DKDM_WRITE_INTERNAL;
559                 } else if (f.optional_string_child("LastDKDMWriteType").get() == "file") {
560                         _last_dkdm_write_type = DKDM_WRITE_FILE;
561                 }
562         }
563         _frames_in_memory_multiplier = f.optional_number_child<int>("FramesInMemoryMultiplier").get_value_or(3);
564         _decode_reduction = f.optional_number_child<int>("DecodeReduction");
565         _default_notify = f.optional_bool_child("DefaultNotify").get_value_or(false);
566
567         for (auto i: f.node_children("Notification")) {
568                 int const id = i->number_attribute<int>("Id");
569                 if (id >= 0 && id < NOTIFICATION_COUNT) {
570                         _notification[id] = raw_convert<int>(i->content());
571                 }
572         }
573
574         _barco_username = f.optional_string_child("BarcoUsername");
575         _barco_password = f.optional_string_child("BarcoPassword");
576         _christie_username = f.optional_string_child("ChristieUsername");
577         _christie_password = f.optional_string_child("ChristiePassword");
578         _gdc_username = f.optional_string_child("GDCUsername");
579         _gdc_password = f.optional_string_child("GDCPassword");
580
581         auto pm = f.optional_string_child("PlayerMode");
582         if (pm && *pm == "window") {
583                 _player_mode = PLAYER_MODE_WINDOW;
584         } else if (pm && *pm == "full") {
585                 _player_mode = PLAYER_MODE_FULL;
586         } else if (pm && *pm == "dual") {
587                 _player_mode = PLAYER_MODE_DUAL;
588         }
589
590         _image_display = f.optional_number_child<int>("ImageDisplay").get_value_or(0);
591         auto vc = f.optional_string_child("VideoViewType");
592         if (vc && *vc == "opengl") {
593                 _video_view_type = VIDEO_VIEW_OPENGL;
594         } else if (vc && *vc == "simple") {
595                 _video_view_type = VIDEO_VIEW_SIMPLE;
596         }
597         _respect_kdm_validity_periods = f.optional_bool_child("RespectKDMValidityPeriods").get_value_or(true);
598         _player_debug_log_file = f.optional_string_child("PlayerDebugLogFile");
599         _player_content_directory = f.optional_string_child("PlayerContentDirectory");
600         _player_playlist_directory = f.optional_string_child("PlayerPlaylistDirectory");
601         _player_kdm_directory = f.optional_string_child("PlayerKDMDirectory");
602
603         if (f.optional_node_child("AudioMapping")) {
604                 _audio_mapping = AudioMapping (f.node_child("AudioMapping"), Film::current_state_version);
605         }
606
607         for (auto i: f.node_children("CustomLanguage")) {
608                 try {
609                         /* This will fail if it's called before dcp::init() as it won't recognise the
610                          * tag.  That's OK because the Config will be reloaded again later.
611                          */
612                         _custom_languages.push_back (dcp::LanguageTag(i->content()));
613                 } catch (std::runtime_error& e) {}
614         }
615
616         for (auto& initial: _initial_paths) {
617                 initial.second = f.optional_string_child(initial.first);
618         }
619         _use_isdcf_name_by_default = f.optional_bool_child("UseISDCFNameByDefault").get_value_or(true);
620         _write_kdms_to_disk = f.optional_bool_child("WriteKDMsToDisk").get_value_or(true);
621         _email_kdms = f.optional_bool_child("EmailKDMs").get_value_or(false);
622         _default_kdm_type = dcp::string_to_formulation(f.optional_string_child("DefaultKDMType").get_value_or("modified-transitional-1"));
623         if (auto duration = f.optional_node_child("DefaultKDMDuration")) {
624                 _default_kdm_duration = RoughDuration(duration);
625         } else {
626                 _default_kdm_duration = RoughDuration(1, RoughDuration::Unit::WEEKS);
627         }
628         _auto_crop_threshold = f.optional_number_child<double>("AutoCropThreshold").get_value_or(0.1);
629         _last_release_notes_version = f.optional_string_child("LastReleaseNotesVersion");
630         _main_divider_sash_position = f.optional_number_child<int>("MainDividerSashPosition");
631         _main_content_divider_sash_position = f.optional_number_child<int>("MainContentDividerSashPosition");
632
633         if (auto loc = f.optional_string_child("DefaultAddFileLocation")) {
634                 if (*loc == "last") {
635                         _default_add_file_location = DefaultAddFileLocation::SAME_AS_LAST_TIME;
636                 } else if (*loc == "project") {
637                         _default_add_file_location = DefaultAddFileLocation::SAME_AS_PROJECT;
638                 }
639         }
640
641         _allow_smpte_bv20 = f.optional_bool_child("AllowSMPTEBv20").get_value_or(false);
642         _isdcf_name_part_length = f.optional_number_child<int>("ISDCFNamePartLength").get_value_or(14);
643
644         _export.read(f.optional_node_child("Export"));
645 }
646 catch (...) {
647         if (have_existing("config.xml")) {
648                 backup ();
649                 /* We have a config file but it didn't load */
650                 FailedToLoad(LoadFailure::CONFIG);
651         }
652         set_defaults ();
653         /* Make a new set of signing certificates and key */
654         _signer_chain = create_certificate_chain ();
655         /* And similar for decryption of KDMs */
656         _decryption_chain = create_certificate_chain ();
657         write_config();
658 }
659
660
661 void
662 Config::read_cinemas()
663 {
664         if (dcp::filesystem::exists(_cinemas_file)) {
665                 try {
666                         cxml::Document f("Cinemas");
667                         f.read_file(dcp::filesystem::fix_long_path(_cinemas_file));
668                         read_cinemas(f);
669                 } catch (...) {
670                         backup();
671                         FailedToLoad(LoadFailure::CINEMAS);
672                         write_cinemas();
673                 }
674         }
675 }
676
677
678 void
679 Config::read_dkdm_recipients()
680 {
681         if (dcp::filesystem::exists(_dkdm_recipients_file)) {
682                 try {
683                         cxml::Document f("DKDMRecipients");
684                         f.read_file(dcp::filesystem::fix_long_path(_dkdm_recipients_file));
685                         read_dkdm_recipients(f);
686                 } catch (...) {
687                         backup();
688                         FailedToLoad(LoadFailure::DKDM_RECIPIENTS);
689                         write_dkdm_recipients();
690                 }
691         }
692 }
693
694
695 /** @return Singleton instance */
696 Config *
697 Config::instance ()
698 {
699         if (_instance == nullptr) {
700                 _instance = new Config;
701                 _instance->read ();
702         }
703
704         return _instance;
705 }
706
707 /** Write our configuration to disk */
708 void
709 Config::write () const
710 {
711         write_config ();
712         write_cinemas ();
713         write_dkdm_recipients ();
714 }
715
716 void
717 Config::write_config () const
718 {
719         xmlpp::Document doc;
720         auto root = doc.create_root_node ("Config");
721
722         /* [XML] Version The version number of the configuration file format. */
723         root->add_child("Version")->add_child_text (raw_convert<string>(_current_version));
724         /* [XML] MasterEncodingThreads Number of encoding threads to use when running as master. */
725         root->add_child("MasterEncodingThreads")->add_child_text (raw_convert<string> (_master_encoding_threads));
726         /* [XML] ServerEncodingThreads Number of encoding threads to use when running as server. */
727         root->add_child("ServerEncodingThreads")->add_child_text (raw_convert<string> (_server_encoding_threads));
728         if (_default_directory) {
729                 /* [XML:opt] DefaultDirectory Default directory when creating a new film in the GUI. */
730                 root->add_child("DefaultDirectory")->add_child_text (_default_directory->string ());
731         }
732         /* [XML] ServerPortBase Port number to use for frame encoding requests.  <code>ServerPortBase</code> + 1 and
733            <code>ServerPortBase</code> + 2 are used for querying servers.  <code>ServerPortBase</code> + 3 is used
734            by the batch converter to listen for job requests.
735         */
736         root->add_child("ServerPortBase")->add_child_text (raw_convert<string> (_server_port_base));
737         /* [XML] UseAnyServers 1 to broadcast to look for encoding servers to use, 0 to use only those configured. */
738         root->add_child("UseAnyServers")->add_child_text (_use_any_servers ? "1" : "0");
739
740         for (auto i: _servers) {
741                 /* [XML:opt] Server IP address or hostname of an encoding server to use; you can use as many of these tags
742                    as you like.
743                 */
744                 root->add_child("Server")->add_child_text (i);
745         }
746
747         /* [XML] OnlyServersEncode 1 to set the master to do decoding of source content no JPEG2000 encoding; all encoding
748            is done by the encoding servers.  0 to set the master to do some encoding as well as coordinating the job.
749         */
750         root->add_child("OnlyServersEncode")->add_child_text (_only_servers_encode ? "1" : "0");
751         /* [XML] TMSProtocol Protocol to use to copy files to a TMS; 0 to use SCP, 1 for FTP. */
752         root->add_child("TMSProtocol")->add_child_text (raw_convert<string> (static_cast<int> (_tms_protocol)));
753         /* [XML] TMSPassive True to use PASV mode with TMS FTP connections. */
754         root->add_child("TMSPassive")->add_child_text(_tms_passive ? "1" : "0");
755         /* [XML] TMSIP IP address of TMS. */
756         root->add_child("TMSIP")->add_child_text (_tms_ip);
757         /* [XML] TMSPath Path on the TMS to copy files to. */
758         root->add_child("TMSPath")->add_child_text (_tms_path);
759         /* [XML] TMSUser Username to log into the TMS with. */
760         root->add_child("TMSUser")->add_child_text (_tms_user);
761         /* [XML] TMSPassword Password to log into the TMS with. */
762         root->add_child("TMSPassword")->add_child_text (_tms_password);
763         if (_language) {
764                 /* [XML:opt] Language Language to use in the GUI e.g. <code>fr_FR</code>. */
765                 root->add_child("Language")->add_child_text (_language.get());
766         }
767         if (_default_dcp_content_type) {
768                 /* [XML:opt] DefaultDCPContentType Default content type to use when creating new films (<code>FTR</code>, <code>SHR</code>,
769                    <code>TLR</code>, <code>TST</code>, <code>XSN</code>, <code>RTG</code>, <code>TSR</code>, <code>POL</code>,
770                    <code>PSA</code> or <code>ADV</code>). */
771                 root->add_child("DefaultDCPContentType")->add_child_text (_default_dcp_content_type->isdcf_name ());
772         }
773         /* [XML] DefaultDCPAudioChannels Default number of audio channels to use when creating new films. */
774         root->add_child("DefaultDCPAudioChannels")->add_child_text (raw_convert<string> (_default_dcp_audio_channels));
775         /* [XML] DCPIssuer Issuer text to write into CPL files. */
776         root->add_child("DCPIssuer")->add_child_text (_dcp_issuer);
777         /* [XML] DCPCreator Creator text to write into CPL files. */
778         root->add_child("DCPCreator")->add_child_text (_dcp_creator);
779         /* [XML] Company name to write into MXF files. */
780         root->add_child("DCPCompanyName")->add_child_text (_dcp_company_name);
781         /* [XML] Product name to write into MXF files. */
782         root->add_child("DCPProductName")->add_child_text (_dcp_product_name);
783         /* [XML] Product version to write into MXF files. */
784         root->add_child("DCPProductVersion")->add_child_text (_dcp_product_version);
785         /* [XML] Comment to write into JPEG2000 data. */
786         root->add_child("DCPJ2KComment")->add_child_text (_dcp_j2k_comment);
787         /* [XML] UploadAfterMakeDCP 1 to upload to a TMS after making a DCP, 0 for no upload. */
788         root->add_child("UploadAfterMakeDCP")->add_child_text (_upload_after_make_dcp ? "1" : "0");
789
790         /* [XML] DefaultStillLength Default length (in seconds) for still images in new films. */
791         root->add_child("DefaultStillLength")->add_child_text (raw_convert<string> (_default_still_length));
792         /* [XML] DefaultJ2KBandwidth Default bitrate (in bits per second) for JPEG2000 data in new films. */
793         root->add_child("DefaultJ2KBandwidth")->add_child_text (raw_convert<string> (_default_j2k_bandwidth));
794         /* [XML] DefaultAudioDelay Default delay to apply to audio (positive moves audio later) in milliseconds. */
795         root->add_child("DefaultAudioDelay")->add_child_text (raw_convert<string> (_default_audio_delay));
796         /* [XML] DefaultInterop 1 to default new films to Interop, 0 for SMPTE. */
797         root->add_child("DefaultInterop")->add_child_text (_default_interop ? "1" : "0");
798         if (_default_audio_language) {
799                 /* [XML] DefaultAudioLanguage Default audio language to use for new films */
800                 root->add_child("DefaultAudioLanguage")->add_child_text(_default_audio_language->to_string());
801         }
802         if (_default_territory) {
803                 /* [XML] DefaultTerritory Default territory to use for new films */
804                 root->add_child("DefaultTerritory")->add_child_text(_default_territory->subtag());
805         }
806         for (auto const& i: _default_metadata) {
807                 auto c = root->add_child("DefaultMetadata");
808                 c->set_attribute("key", i.first);
809                 c->add_child_text(i.second);
810         }
811         if (_default_kdm_directory) {
812                 /* [XML:opt] DefaultKDMDirectory Default directory to write KDMs to. */
813                 root->add_child("DefaultKDMDirectory")->add_child_text (_default_kdm_directory->string ());
814         }
815         _default_kdm_duration.as_xml(root->add_child("DefaultKDMDuration"));
816         /* [XML] MailServer Hostname of SMTP server to use. */
817         root->add_child("MailServer")->add_child_text (_mail_server);
818         /* [XML] MailPort Port number to use on SMTP server. */
819         root->add_child("MailPort")->add_child_text (raw_convert<string> (_mail_port));
820         /* [XML] MailProtocol Protocol to use on SMTP server (Auto, Plain, STARTTLS or SSL) */
821         switch (_mail_protocol) {
822         case EmailProtocol::AUTO:
823                 root->add_child("MailProtocol")->add_child_text("Auto");
824                 break;
825         case EmailProtocol::PLAIN:
826                 root->add_child("MailProtocol")->add_child_text("Plain");
827                 break;
828         case EmailProtocol::STARTTLS:
829                 root->add_child("MailProtocol")->add_child_text("STARTTLS");
830                 break;
831         case EmailProtocol::SSL:
832                 root->add_child("MailProtocol")->add_child_text("SSL");
833                 break;
834         }
835         /* [XML] MailUser Username to use on SMTP server. */
836         root->add_child("MailUser")->add_child_text (_mail_user);
837         /* [XML] MailPassword Password to use on SMTP server. */
838         root->add_child("MailPassword")->add_child_text (_mail_password);
839
840         /* [XML] KDMSubject Subject to use for KDM emails. */
841         root->add_child("KDMSubject")->add_child_text (_kdm_subject);
842         /* [XML] KDMFrom From address to use for KDM emails. */
843         root->add_child("KDMFrom")->add_child_text (_kdm_from);
844         for (auto i: _kdm_cc) {
845                 /* [XML] KDMCC CC address to use for KDM emails; you can use as many of these tags as you like. */
846                 root->add_child("KDMCC")->add_child_text (i);
847         }
848         /* [XML] KDMBCC BCC address to use for KDM emails. */
849         root->add_child("KDMBCC")->add_child_text (_kdm_bcc);
850         /* [XML] KDMEmail Text of KDM email. */
851         root->add_child("KDMEmail")->add_child_text (_kdm_email);
852
853         /* [XML] NotificationSubject Subject to use for notification emails. */
854         root->add_child("NotificationSubject")->add_child_text (_notification_subject);
855         /* [XML] NotificationFrom From address to use for notification emails. */
856         root->add_child("NotificationFrom")->add_child_text (_notification_from);
857         /* [XML] NotificationFrom To address to use for notification emails. */
858         root->add_child("NotificationTo")->add_child_text (_notification_to);
859         for (auto i: _notification_cc) {
860                 /* [XML] NotificationCC CC address to use for notification emails; you can use as many of these tags as you like. */
861                 root->add_child("NotificationCC")->add_child_text (i);
862         }
863         /* [XML] NotificationBCC BCC address to use for notification emails. */
864         root->add_child("NotificationBCC")->add_child_text (_notification_bcc);
865         /* [XML] NotificationEmail Text of notification email. */
866         root->add_child("NotificationEmail")->add_child_text (_notification_email);
867
868         /* [XML] CheckForUpdates 1 to check dcpomatic.com for new versions, 0 to check only on request. */
869         root->add_child("CheckForUpdates")->add_child_text (_check_for_updates ? "1" : "0");
870         /* [XML] CheckForUpdates 1 to check dcpomatic.com for new text versions, 0 to check only on request. */
871         root->add_child("CheckForTestUpdates")->add_child_text (_check_for_test_updates ? "1" : "0");
872
873         /* [XML] MaximumJ2KBandwidth Maximum J2K bandwidth (in bits per second) that can be specified in the GUI. */
874         root->add_child("MaximumJ2KBandwidth")->add_child_text (raw_convert<string> (_maximum_j2k_bandwidth));
875         /* [XML] AllowAnyDCPFrameRate 1 to allow users to specify any frame rate when creating DCPs, 0 to limit the GUI to standard rates. */
876         root->add_child("AllowAnyDCPFrameRate")->add_child_text (_allow_any_dcp_frame_rate ? "1" : "0");
877         /* [XML] AllowAnyContainer 1 to allow users to user any container ratio for their DCP, 0 to limit the GUI to DCI Flat/Scope */
878         root->add_child("AllowAnyContainer")->add_child_text (_allow_any_container ? "1" : "0");
879         /* [XML] Allow96kHzAudio 1 to allow users to make DCPs with 96kHz audio, 0 to always make 48kHz DCPs */
880         root->add_child("Allow96kHzAudio")->add_child_text(_allow_96khz_audio ? "1" : "0");
881         /* [XML] UseAllAudioChannels 1 to allow users to map audio to all 16 DCP channels, 0 to limit to the channels used in standard DCPs */
882         root->add_child("UseAllAudioChannels")->add_child_text(_use_all_audio_channels ? "1" : "0");
883         /* [XML] ShowExperimentalAudioProcessors 1 to offer users the (experimental) audio upmixer processors, 0 to hide them */
884         root->add_child("ShowExperimentalAudioProcessors")->add_child_text (_show_experimental_audio_processors ? "1" : "0");
885         /* [XML] LogTypes Types of logging to write; a bitfield where 1 is general notes, 2 warnings, 4 errors, 8 debug information related
886            to 3D, 16 debug information related to encoding, 32 debug information for timing purposes, 64 debug information related
887            to sending email, 128 debug information related to the video view, 256 information about disk writing, 512 debug information
888            related to the player, 1024 debug information related to audio analyses.
889         */
890         root->add_child("LogTypes")->add_child_text (raw_convert<string> (_log_types));
891         /* [XML] AnalyseEBUR128 1 to do EBUR128 analyses when analysing audio, otherwise 0. */
892         root->add_child("AnalyseEBUR128")->add_child_text (_analyse_ebur128 ? "1" : "0");
893         /* [XML] AutomaticAudioAnalysis 1 to run audio analysis automatically when audio content is added to the film, otherwise 0. */
894         root->add_child("AutomaticAudioAnalysis")->add_child_text (_automatic_audio_analysis ? "1" : "0");
895 #ifdef DCPOMATIC_WINDOWS
896         if (_win32_console) {
897                 /* [XML] Win32Console 1 to open a console when running on Windows, otherwise 0.
898                  * We only write this if it's true, which is a bit of a hack to allow unit tests to work
899                  * more easily on Windows (without a platform-specific reference in config_write_utf8_test)
900                  */
901                 root->add_child("Win32Console")->add_child_text ("1");
902         }
903 #endif
904
905         /* [XML] Signer Certificate chain and private key to use when signing DCPs and KDMs.  Should contain <code>&lt;Certificate&gt;</code>
906            tags in order and a <code>&lt;PrivateKey&gt;</code> tag all containing PEM-encoded certificates or private keys as appropriate.
907         */
908         auto signer = root->add_child ("Signer");
909         DCPOMATIC_ASSERT (_signer_chain);
910         for (auto const& i: _signer_chain->unordered()) {
911                 signer->add_child("Certificate")->add_child_text (i.certificate (true));
912         }
913         signer->add_child("PrivateKey")->add_child_text (_signer_chain->key().get ());
914
915         /* [XML] Decryption Certificate chain and private key to use when decrypting KDMs */
916         auto decryption = root->add_child ("Decryption");
917         DCPOMATIC_ASSERT (_decryption_chain);
918         for (auto const& i: _decryption_chain->unordered()) {
919                 decryption->add_child("Certificate")->add_child_text (i.certificate (true));
920         }
921         decryption->add_child("PrivateKey")->add_child_text (_decryption_chain->key().get ());
922
923         /* [XML] History Filename of DCP to present in the <guilabel>File</guilabel> menu of the GUI; there can be more than one
924            of these tags.
925         */
926         for (auto i: _history) {
927                 root->add_child("History")->add_child_text (i.string ());
928         }
929
930         /* [XML] History Filename of DCP to present in the <guilabel>File</guilabel> menu of the player; there can be more than one
931            of these tags.
932         */
933         for (auto i: _player_history) {
934                 root->add_child("PlayerHistory")->add_child_text (i.string ());
935         }
936
937         /* [XML] DKDMGroup A group of DKDMs, each with a <code>Name</code> attribute, containing other <code>&lt;DKDMGroup&gt;</code>
938            or <code>&lt;DKDM&gt;</code> tags.
939         */
940         /* [XML] DKDM A DKDM as XML */
941         _dkdms->as_xml (root);
942
943         /* [XML] CinemasFile Filename of cinemas list file. */
944         root->add_child("CinemasFile")->add_child_text (_cinemas_file.string());
945         /* [XML] DKDMRecipientsFile Filename of DKDM recipients list file. */
946         root->add_child("DKDMRecipientsFile")->add_child_text (_dkdm_recipients_file.string());
947         /* [XML] ShowHintsBeforeMakeDCP 1 to show hints in the GUI before making a DCP, otherwise 0. */
948         root->add_child("ShowHintsBeforeMakeDCP")->add_child_text (_show_hints_before_make_dcp ? "1" : "0");
949         /* [XML] ConfirmKDMEmail 1 to confirm before sending KDM emails in the GUI, otherwise 0. */
950         root->add_child("ConfirmKDMEmail")->add_child_text (_confirm_kdm_email ? "1" : "0");
951         /* [XML] KDMFilenameFormat Format for KDM filenames. */
952         root->add_child("KDMFilenameFormat")->add_child_text (_kdm_filename_format.specification ());
953         /* [XML] KDMFilenameFormat Format for DKDM filenames. */
954         root->add_child("DKDMFilenameFormat")->add_child_text(_dkdm_filename_format.specification());
955         /* [XML] KDMContainerNameFormat Format for KDM containers (directories or ZIP files). */
956         root->add_child("KDMContainerNameFormat")->add_child_text (_kdm_container_name_format.specification ());
957         /* [XML] DCPMetadataFilenameFormat Format for DCP metadata filenames. */
958         root->add_child("DCPMetadataFilenameFormat")->add_child_text (_dcp_metadata_filename_format.specification ());
959         /* [XML] DCPAssetFilenameFormat Format for DCP asset filenames. */
960         root->add_child("DCPAssetFilenameFormat")->add_child_text (_dcp_asset_filename_format.specification ());
961         /* [XML] JumpToSelected 1 to make the GUI jump to the start of content when it is selected, otherwise 0. */
962         root->add_child("JumpToSelected")->add_child_text (_jump_to_selected ? "1" : "0");
963         /* [XML] Nagged 1 if a particular nag screen has been shown and should not be shown again, otherwise 0. */
964         for (int i = 0; i < NAG_COUNT; ++i) {
965                 xmlpp::Element* e = root->add_child ("Nagged");
966                 e->set_attribute ("Id", raw_convert<string>(i));
967                 e->add_child_text (_nagged[i] ? "1" : "0");
968         }
969         /* [XML] PreviewSound 1 to use sound in the GUI preview and player, otherwise 0. */
970         root->add_child("PreviewSound")->add_child_text (_sound ? "1" : "0");
971         if (_sound_output) {
972                 /* [XML:opt] PreviewSoundOutput Name of the audio output to use. */
973                 root->add_child("PreviewSoundOutput")->add_child_text (_sound_output.get());
974         }
975         /* [XML] CoverSheet Text of the cover sheet to write when making DCPs. */
976         root->add_child("CoverSheet")->add_child_text (_cover_sheet);
977         if (_last_player_load_directory) {
978                 root->add_child("LastPlayerLoadDirectory")->add_child_text(_last_player_load_directory->string());
979         }
980         /* [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. */
981         if (_last_kdm_write_type) {
982                 switch (_last_kdm_write_type.get()) {
983                 case KDM_WRITE_FLAT:
984                         root->add_child("LastKDMWriteType")->add_child_text("flat");
985                         break;
986                 case KDM_WRITE_FOLDER:
987                         root->add_child("LastKDMWriteType")->add_child_text("folder");
988                         break;
989                 case KDM_WRITE_ZIP:
990                         root->add_child("LastKDMWriteType")->add_child_text("zip");
991                         break;
992                 }
993         }
994         /* [XML] LastDKDMWriteType Last type of DKDM-write: <code>file</code> for a file, <code>internal</code> to add to DCP-o-matic's list. */
995         if (_last_dkdm_write_type) {
996                 switch (_last_dkdm_write_type.get()) {
997                 case DKDM_WRITE_INTERNAL:
998                         root->add_child("LastDKDMWriteType")->add_child_text("internal");
999                         break;
1000                 case DKDM_WRITE_FILE:
1001                         root->add_child("LastDKDMWriteType")->add_child_text("file");
1002                         break;
1003                 }
1004         }
1005         /* [XML] FramesInMemoryMultiplier value to multiply the encoding threads count by to get the maximum number of
1006            frames to be held in memory at once.
1007         */
1008         root->add_child("FramesInMemoryMultiplier")->add_child_text(raw_convert<string>(_frames_in_memory_multiplier));
1009
1010         /* [XML] DecodeReduction power of 2 to reduce DCP images by before decoding in the player. */
1011         if (_decode_reduction) {
1012                 root->add_child("DecodeReduction")->add_child_text(raw_convert<string>(_decode_reduction.get()));
1013         }
1014
1015         /* [XML] DefaultNotify 1 to default jobs to notify when complete, otherwise 0. */
1016         root->add_child("DefaultNotify")->add_child_text(_default_notify ? "1" : "0");
1017
1018         /* [XML] Notification 1 if a notification type is enabled, otherwise 0. */
1019         for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
1020                 xmlpp::Element* e = root->add_child ("Notification");
1021                 e->set_attribute ("Id", raw_convert<string>(i));
1022                 e->add_child_text (_notification[i] ? "1" : "0");
1023         }
1024
1025         if (_barco_username) {
1026                 /* [XML] BarcoUsername Username for logging into Barco's servers when downloading server certificates. */
1027                 root->add_child("BarcoUsername")->add_child_text(*_barco_username);
1028         }
1029         if (_barco_password) {
1030                 /* [XML] BarcoPassword Password for logging into Barco's servers when downloading server certificates. */
1031                 root->add_child("BarcoPassword")->add_child_text(*_barco_password);
1032         }
1033
1034         if (_christie_username) {
1035                 /* [XML] ChristieUsername Username for logging into Christie's servers when downloading server certificates. */
1036                 root->add_child("ChristieUsername")->add_child_text(*_christie_username);
1037         }
1038         if (_christie_password) {
1039                 /* [XML] ChristiePassword Password for logging into Christie's servers when downloading server certificates. */
1040                 root->add_child("ChristiePassword")->add_child_text(*_christie_password);
1041         }
1042
1043         if (_gdc_username) {
1044                 /* [XML] GDCUsername Username for logging into GDC's servers when downloading server certificates. */
1045                 root->add_child("GDCUsername")->add_child_text(*_gdc_username);
1046         }
1047         if (_gdc_password) {
1048                 /* [XML] GDCPassword Password for logging into GDC's servers when downloading server certificates. */
1049                 root->add_child("GDCPassword")->add_child_text(*_gdc_password);
1050         }
1051
1052         /* [XML] PlayerMode <code>window</code> for a single window, <code>full</code> for full-screen and <code>dual</code> for full screen playback
1053            with separate (advanced) controls.
1054         */
1055         switch (_player_mode) {
1056         case PLAYER_MODE_WINDOW:
1057                 root->add_child("PlayerMode")->add_child_text("window");
1058                 break;
1059         case PLAYER_MODE_FULL:
1060                 root->add_child("PlayerMode")->add_child_text("full");
1061                 break;
1062         case PLAYER_MODE_DUAL:
1063                 root->add_child("PlayerMode")->add_child_text("dual");
1064                 break;
1065         }
1066
1067         /* [XML] ImageDisplay Screen number to put image on in dual-screen player mode. */
1068         root->add_child("ImageDisplay")->add_child_text(raw_convert<string>(_image_display));
1069         switch (_video_view_type) {
1070         case VIDEO_VIEW_SIMPLE:
1071                 root->add_child("VideoViewType")->add_child_text("simple");
1072                 break;
1073         case VIDEO_VIEW_OPENGL:
1074                 root->add_child("VideoViewType")->add_child_text("opengl");
1075                 break;
1076         }
1077         /* [XML] RespectKDMValidityPeriods 1 to refuse to use KDMs that are out of date, 0 to ignore KDM dates. */
1078         root->add_child("RespectKDMValidityPeriods")->add_child_text(_respect_kdm_validity_periods ? "1" : "0");
1079         if (_player_debug_log_file) {
1080                 /* [XML] PlayerLogFile Filename to use for player debug logs. */
1081                 root->add_child("PlayerDebugLogFile")->add_child_text(_player_debug_log_file->string());
1082         }
1083         if (_player_content_directory) {
1084                 /* [XML] PlayerContentDirectory Directory to use for player content in the dual-screen mode. */
1085                 root->add_child("PlayerContentDirectory")->add_child_text(_player_content_directory->string());
1086         }
1087         if (_player_playlist_directory) {
1088                 /* [XML] PlayerPlaylistDirectory Directory to use for player playlists in the dual-screen mode. */
1089                 root->add_child("PlayerPlaylistDirectory")->add_child_text(_player_playlist_directory->string());
1090         }
1091         if (_player_kdm_directory) {
1092                 /* [XML] PlayerKDMDirectory Directory to use for player KDMs in the dual-screen mode. */
1093                 root->add_child("PlayerKDMDirectory")->add_child_text(_player_kdm_directory->string());
1094         }
1095         if (_audio_mapping) {
1096                 _audio_mapping->as_xml (root->add_child("AudioMapping"));
1097         }
1098         for (auto const& i: _custom_languages) {
1099                 root->add_child("CustomLanguage")->add_child_text(i.to_string());
1100         }
1101         for (auto const& initial: _initial_paths) {
1102                 if (initial.second) {
1103                         root->add_child(initial.first)->add_child_text(initial.second->string());
1104                 }
1105         }
1106         root->add_child("UseISDCFNameByDefault")->add_child_text(_use_isdcf_name_by_default ? "1" : "0");
1107         root->add_child("WriteKDMsToDisk")->add_child_text(_write_kdms_to_disk ? "1" : "0");
1108         root->add_child("EmailKDMs")->add_child_text(_email_kdms ? "1" : "0");
1109         root->add_child("DefaultKDMType")->add_child_text(dcp::formulation_to_string(_default_kdm_type));
1110         root->add_child("AutoCropThreshold")->add_child_text(raw_convert<string>(_auto_crop_threshold));
1111         if (_last_release_notes_version) {
1112                 root->add_child("LastReleaseNotesVersion")->add_child_text(*_last_release_notes_version);
1113         }
1114         if (_main_divider_sash_position) {
1115                 root->add_child("MainDividerSashPosition")->add_child_text(raw_convert<string>(*_main_divider_sash_position));
1116         }
1117         if (_main_content_divider_sash_position) {
1118                 root->add_child("MainContentDividerSashPosition")->add_child_text(raw_convert<string>(*_main_content_divider_sash_position));
1119         }
1120
1121         root->add_child("DefaultAddFileLocation")->add_child_text(
1122                 _default_add_file_location == DefaultAddFileLocation::SAME_AS_LAST_TIME ? "last" : "project"
1123                 );
1124
1125         /* [XML] AllowSMPTEBv20 1 to allow the user to choose SMPTE (Bv2.0 only) as a standard, otherwise 0 */
1126         root->add_child("AllowSMPTEBv20")->add_child_text(_allow_smpte_bv20 ? "1" : "0");
1127         /* [XML] ISDCFNamePartLength Maximum length of the "name" part of an ISDCF name, which should be 14 according to the standard */
1128         root->add_child("ISDCFNamePartLength")->add_child_text(raw_convert<string>(_isdcf_name_part_length));
1129
1130         _export.write(root->add_child("Export"));
1131
1132         auto target = config_write_file();
1133
1134         try {
1135                 auto const s = doc.write_to_string_formatted ();
1136                 boost::filesystem::path tmp (string(target.string()).append(".tmp"));
1137                 dcp::File f(tmp, "w");
1138                 if (!f) {
1139                         throw FileError (_("Could not open file for writing"), tmp);
1140                 }
1141                 f.checked_write(s.c_str(), s.bytes());
1142                 f.close();
1143                 dcp::filesystem::remove(target);
1144                 dcp::filesystem::rename(tmp, target);
1145         } catch (xmlpp::exception& e) {
1146                 string s = e.what ();
1147                 trim (s);
1148                 throw FileError (s, target);
1149         }
1150 }
1151
1152
1153 template <class T>
1154 void
1155 write_file (string root_node, string node, string version, list<shared_ptr<T>> things, boost::filesystem::path file)
1156 {
1157         xmlpp::Document doc;
1158         auto root = doc.create_root_node (root_node);
1159         root->add_child("Version")->add_child_text(version);
1160
1161         for (auto i: things) {
1162                 i->as_xml (root->add_child(node));
1163         }
1164
1165         try {
1166                 doc.write_to_file_formatted (file.string() + ".tmp");
1167                 dcp::filesystem::remove(file);
1168                 dcp::filesystem::rename(file.string() + ".tmp", file);
1169         } catch (xmlpp::exception& e) {
1170                 string s = e.what ();
1171                 trim (s);
1172                 throw FileError (s, file);
1173         }
1174 }
1175
1176
1177 void
1178 Config::write_cinemas () const
1179 {
1180         write_file ("Cinemas", "Cinema", "1", _cinemas, _cinemas_file);
1181 }
1182
1183
1184 void
1185 Config::write_dkdm_recipients () const
1186 {
1187         write_file ("DKDMRecipients", "DKDMRecipient", "1", _dkdm_recipients, _dkdm_recipients_file);
1188 }
1189
1190
1191 boost::filesystem::path
1192 Config::default_directory_or (boost::filesystem::path a) const
1193 {
1194         return directory_or (_default_directory, a);
1195 }
1196
1197 boost::filesystem::path
1198 Config::default_kdm_directory_or (boost::filesystem::path a) const
1199 {
1200         return directory_or (_default_kdm_directory, a);
1201 }
1202
1203 boost::filesystem::path
1204 Config::directory_or (optional<boost::filesystem::path> dir, boost::filesystem::path a) const
1205 {
1206         if (!dir) {
1207                 return a;
1208         }
1209
1210         boost::system::error_code ec;
1211         auto const e = dcp::filesystem::exists(*dir, ec);
1212         if (ec || !e) {
1213                 return a;
1214         }
1215
1216         return *dir;
1217 }
1218
1219 void
1220 Config::drop ()
1221 {
1222         delete _instance;
1223         _instance = nullptr;
1224 }
1225
1226 void
1227 Config::changed (Property what)
1228 {
1229         Changed (what);
1230 }
1231
1232 void
1233 Config::set_kdm_email_to_default ()
1234 {
1235         _kdm_subject = _("KDM delivery: $CPL_NAME");
1236
1237         _kdm_email = _(
1238                 "Dear Projectionist\n\n"
1239                 "Please find attached KDMs for $CPL_NAME.\n\n"
1240                 "Cinema: $CINEMA_NAME\n"
1241                 "Screen(s): $SCREENS\n\n"
1242                 "The KDMs are valid from $START_TIME until $END_TIME.\n\n"
1243                 "Best regards,\nDCP-o-matic"
1244                 );
1245 }
1246
1247 void
1248 Config::set_notification_email_to_default ()
1249 {
1250         _notification_subject = _("DCP-o-matic notification");
1251
1252         _notification_email = _(
1253                 "$JOB_NAME: $JOB_STATUS"
1254                 );
1255 }
1256
1257 void
1258 Config::reset_kdm_email ()
1259 {
1260         set_kdm_email_to_default ();
1261         changed ();
1262 }
1263
1264 void
1265 Config::reset_notification_email ()
1266 {
1267         set_notification_email_to_default ();
1268         changed ();
1269 }
1270
1271 void
1272 Config::set_cover_sheet_to_default ()
1273 {
1274         _cover_sheet = _(
1275                 "$CPL_NAME\n\n"
1276                 "CPL Filename: $CPL_FILENAME\n"
1277                 "Type: $TYPE\n"
1278                 "Format: $CONTAINER\n"
1279                 "Audio: $AUDIO\n"
1280                 "Audio Language: $AUDIO_LANGUAGE\n"
1281                 "Subtitle Language: $SUBTITLE_LANGUAGE\n"
1282                 "Length: $LENGTH\n"
1283                 "Size: $SIZE\n"
1284                 );
1285 }
1286
1287 void
1288 Config::add_to_history (boost::filesystem::path p)
1289 {
1290         add_to_history_internal (_history, p);
1291 }
1292
1293 /** Remove non-existent items from the history */
1294 void
1295 Config::clean_history ()
1296 {
1297         clean_history_internal (_history);
1298 }
1299
1300 void
1301 Config::add_to_player_history (boost::filesystem::path p)
1302 {
1303         add_to_history_internal (_player_history, p);
1304 }
1305
1306 /** Remove non-existent items from the player history */
1307 void
1308 Config::clean_player_history ()
1309 {
1310         clean_history_internal (_player_history);
1311 }
1312
1313 void
1314 Config::add_to_history_internal (vector<boost::filesystem::path>& h, boost::filesystem::path p)
1315 {
1316         /* Remove existing instances of this path in the history */
1317         h.erase (remove (h.begin(), h.end(), p), h.end ());
1318
1319         h.insert (h.begin (), p);
1320         if (h.size() > HISTORY_SIZE) {
1321                 h.pop_back ();
1322         }
1323
1324         changed (HISTORY);
1325 }
1326
1327 void
1328 Config::clean_history_internal (vector<boost::filesystem::path>& h)
1329 {
1330         auto old = h;
1331         h.clear ();
1332         for (auto i: old) {
1333                 try {
1334                         if (dcp::filesystem::is_directory(i)) {
1335                                 h.push_back (i);
1336                         }
1337                 } catch (...) {
1338                         /* We couldn't find out if it's a directory for some reason; just ignore it */
1339                 }
1340         }
1341 }
1342
1343
1344 bool
1345 Config::have_existing (string file)
1346 {
1347         return dcp::filesystem::exists(read_path(file));
1348 }
1349
1350
1351 void
1352 Config::read_cinemas (cxml::Document const & f)
1353 {
1354         _cinemas.clear ();
1355         for (auto i: f.node_children("Cinema")) {
1356                 /* Slightly grotty two-part construction of Cinema here so that we can use
1357                    shared_from_this.
1358                 */
1359                 auto cinema = make_shared<Cinema>(i);
1360                 cinema->read_screens (i);
1361                 _cinemas.push_back (cinema);
1362         }
1363 }
1364
1365 void
1366 Config::set_cinemas_file (boost::filesystem::path file)
1367 {
1368         if (file == _cinemas_file) {
1369                 return;
1370         }
1371
1372         _cinemas_file = file;
1373
1374         if (dcp::filesystem::exists(_cinemas_file)) {
1375                 /* Existing file; read it in */
1376                 cxml::Document f ("Cinemas");
1377                 f.read_file(dcp::filesystem::fix_long_path(_cinemas_file));
1378                 read_cinemas (f);
1379         }
1380
1381         changed (CINEMAS);
1382         changed (OTHER);
1383 }
1384
1385
1386 void
1387 Config::read_dkdm_recipients (cxml::Document const & f)
1388 {
1389         _dkdm_recipients.clear ();
1390         for (auto i: f.node_children("DKDMRecipient")) {
1391                 _dkdm_recipients.push_back (make_shared<DKDMRecipient>(i));
1392         }
1393 }
1394
1395
1396 void
1397 Config::save_template (shared_ptr<const Film> film, string name) const
1398 {
1399         film->write_template (template_write_path(name));
1400 }
1401
1402
1403 list<string>
1404 Config::templates () const
1405 {
1406         if (!dcp::filesystem::exists(read_path("templates"))) {
1407                 return {};
1408         }
1409
1410         list<string> n;
1411         for (auto const& i: dcp::filesystem::directory_iterator(read_path("templates"))) {
1412                 n.push_back (i.path().filename().string());
1413         }
1414         return n;
1415 }
1416
1417 bool
1418 Config::existing_template (string name) const
1419 {
1420         return dcp::filesystem::exists(template_read_path(name));
1421 }
1422
1423
1424 boost::filesystem::path
1425 Config::template_read_path (string name) const
1426 {
1427         return read_path("templates") / tidy_for_filename (name);
1428 }
1429
1430
1431 boost::filesystem::path
1432 Config::template_write_path (string name) const
1433 {
1434         return write_path("templates") / tidy_for_filename (name);
1435 }
1436
1437
1438 void
1439 Config::rename_template (string old_name, string new_name) const
1440 {
1441         dcp::filesystem::rename(template_read_path(old_name), template_write_path(new_name));
1442 }
1443
1444 void
1445 Config::delete_template (string name) const
1446 {
1447         dcp::filesystem::remove(template_write_path(name));
1448 }
1449
1450 /** @return Path to the config.xml containing the actual settings, following a link if required */
1451 boost::filesystem::path
1452 config_file (boost::filesystem::path main)
1453 {
1454         cxml::Document f ("Config");
1455         if (!dcp::filesystem::exists(main)) {
1456                 /* It doesn't exist, so there can't be any links; just return it */
1457                 return main;
1458         }
1459
1460         /* See if there's a link */
1461         try {
1462                 f.read_file(dcp::filesystem::fix_long_path(main));
1463                 auto link = f.optional_string_child("Link");
1464                 if (link) {
1465                         return *link;
1466                 }
1467         } catch (xmlpp::exception& e) {
1468                 /* There as a problem reading the main configuration file,
1469                    so there can't be a link.
1470                 */
1471         }
1472
1473         return main;
1474 }
1475
1476
1477 boost::filesystem::path
1478 Config::config_read_file ()
1479 {
1480         return config_file (read_path("config.xml"));
1481 }
1482
1483
1484 boost::filesystem::path
1485 Config::config_write_file ()
1486 {
1487         return config_file (write_path("config.xml"));
1488 }
1489
1490
1491 void
1492 Config::reset_cover_sheet ()
1493 {
1494         set_cover_sheet_to_default ();
1495         changed ();
1496 }
1497
1498 void
1499 Config::link (boost::filesystem::path new_file) const
1500 {
1501         xmlpp::Document doc;
1502         doc.create_root_node("Config")->add_child("Link")->add_child_text(new_file.string());
1503         try {
1504                 doc.write_to_file_formatted(write_path("config.xml").string());
1505         } catch (xmlpp::exception& e) {
1506                 string s = e.what ();
1507                 trim (s);
1508                 throw FileError (s, write_path("config.xml"));
1509         }
1510 }
1511
1512 void
1513 Config::copy_and_link (boost::filesystem::path new_file) const
1514 {
1515         write ();
1516         dcp::filesystem::copy_file(config_read_file(), new_file, boost::filesystem::copy_option::overwrite_if_exists);
1517         link (new_file);
1518 }
1519
1520 bool
1521 Config::have_write_permission () const
1522 {
1523         dcp::File f(config_write_file(), "r+");
1524         return static_cast<bool>(f);
1525 }
1526
1527 /** @param  output_channels Number of output channels in use.
1528  *  @return Audio mapping for this output channel count (may be a default).
1529  */
1530 AudioMapping
1531 Config::audio_mapping (int output_channels)
1532 {
1533         if (!_audio_mapping || _audio_mapping->output_channels() != output_channels) {
1534                 /* Set up a default */
1535                 _audio_mapping = AudioMapping (MAX_DCP_AUDIO_CHANNELS, output_channels);
1536                 if (output_channels == 2) {
1537                         /* Special case for stereo output.
1538                            Map so that Lt = L(-3dB) + Ls(-3dB) + C(-6dB) + Lfe(-10dB)
1539                            Rt = R(-3dB) + Rs(-3dB) + C(-6dB) + Lfe(-10dB)
1540                         */
1541                         _audio_mapping->set (dcp::Channel::LEFT,   0, 1 / sqrt(2));  // L   -> Lt
1542                         _audio_mapping->set (dcp::Channel::RIGHT,  1, 1 / sqrt(2));  // R   -> Rt
1543                         _audio_mapping->set (dcp::Channel::CENTRE, 0, 1 / 2.0);      // C   -> Lt
1544                         _audio_mapping->set (dcp::Channel::CENTRE, 1, 1 / 2.0);      // C   -> Rt
1545                         _audio_mapping->set (dcp::Channel::LFE,    0, 1 / sqrt(10)); // Lfe -> Lt
1546                         _audio_mapping->set (dcp::Channel::LFE,    1, 1 / sqrt(10)); // Lfe -> Rt
1547                         _audio_mapping->set (dcp::Channel::LS,     0, 1 / sqrt(2));  // Ls  -> Lt
1548                         _audio_mapping->set (dcp::Channel::RS,     1, 1 / sqrt(2));  // Rs  -> Rt
1549                 } else {
1550                         /* 1:1 mapping */
1551                         for (int i = 0; i < min (MAX_DCP_AUDIO_CHANNELS, output_channels); ++i) {
1552                                 _audio_mapping->set (i, i, 1);
1553                         }
1554                 }
1555         }
1556
1557         return *_audio_mapping;
1558 }
1559
1560 void
1561 Config::set_audio_mapping (AudioMapping m)
1562 {
1563         _audio_mapping = m;
1564         changed (AUDIO_MAPPING);
1565 }
1566
1567 void
1568 Config::set_audio_mapping_to_default ()
1569 {
1570         DCPOMATIC_ASSERT (_audio_mapping);
1571         auto const ch = _audio_mapping->output_channels ();
1572         _audio_mapping = boost::none;
1573         _audio_mapping = audio_mapping (ch);
1574         changed (AUDIO_MAPPING);
1575 }
1576
1577
1578 void
1579 Config::add_custom_language (dcp::LanguageTag tag)
1580 {
1581         if (find(_custom_languages.begin(), _custom_languages.end(), tag) == _custom_languages.end()) {
1582                 _custom_languages.push_back (tag);
1583                 changed ();
1584         }
1585 }
1586
1587
1588 optional<Config::BadReason>
1589 Config::check_certificates () const
1590 {
1591         optional<BadReason> bad;
1592
1593         for (auto const& i: _signer_chain->unordered()) {
1594                 if (i.has_utf8_strings()) {
1595                         bad = BAD_SIGNER_UTF8_STRINGS;
1596                 }
1597                 if ((i.not_after().year() - i.not_before().year()) > 15) {
1598                         bad = BAD_SIGNER_VALIDITY_TOO_LONG;
1599                 }
1600                 if (dcp::escape_digest(i.subject_dn_qualifier()) != dcp::public_key_digest(i.public_key())) {
1601                         bad = BAD_SIGNER_DN_QUALIFIER;
1602                 }
1603         }
1604
1605         if (!_signer_chain->chain_valid() || !_signer_chain->private_key_valid()) {
1606                 bad = BAD_SIGNER_INCONSISTENT;
1607         }
1608
1609         if (!_decryption_chain->chain_valid() || !_decryption_chain->private_key_valid()) {
1610                 bad = BAD_DECRYPTION_INCONSISTENT;
1611         }
1612
1613         return bad;
1614 }
1615
1616
1617 void
1618 save_all_config_as_zip (boost::filesystem::path zip_file)
1619 {
1620         Zipper zipper (zip_file);
1621
1622         auto config = Config::instance();
1623         zipper.add ("config.xml", dcp::file_to_string(config->config_read_file()));
1624         if (dcp::filesystem::exists(config->cinemas_file())) {
1625                 zipper.add ("cinemas.xml", dcp::file_to_string(config->cinemas_file()));
1626         }
1627         if (dcp::filesystem::exists(config->dkdm_recipients_file())) {
1628                 zipper.add ("dkdm_recipients.xml", dcp::file_to_string(config->dkdm_recipients_file()));
1629         }
1630
1631         zipper.close ();
1632 }
1633
1634
1635 void
1636 Config::set_initial_path(string id, boost::filesystem::path path)
1637 {
1638         auto iter = _initial_paths.find(id);
1639         DCPOMATIC_ASSERT(iter != _initial_paths.end());
1640         iter->second = path;
1641         changed();
1642 }
1643
1644
1645 optional<boost::filesystem::path>
1646 Config::initial_path(string id) const
1647 {
1648         auto iter = _initial_paths.find(id);
1649         if (iter == _initial_paths.end()) {
1650                 return {};
1651         }
1652         return iter->second;
1653 }
1654