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