Supporters update.
[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 "unzipper.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 = 8;
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["AddKDMPath"] = boost::none;
192         _initial_paths["AddDKDMPath"] = boost::none;
193         _initial_paths["SelectCertificatePath"] = boost::none;
194         _initial_paths["AddCombinerInputPath"] = boost::none;
195         _initial_paths["ExportSubtitlesPath"] = boost::none;
196         _initial_paths["ExportVideoPath"] = boost::none;
197         _initial_paths["DebugLogPath"] = boost::none;
198         _initial_paths["CinemaDatabasePath"] = boost::none;
199         _initial_paths["ConfigFilePath"] = boost::none;
200         _initial_paths["Preferences"] = boost::none;
201         _use_isdcf_name_by_default = true;
202         _write_kdms_to_disk = true;
203         _email_kdms = false;
204         _default_kdm_type = dcp::Formulation::MODIFIED_TRANSITIONAL_1;
205         _default_kdm_duration = RoughDuration(1, RoughDuration::Unit::WEEKS);
206         _auto_crop_threshold = 0.1;
207         _last_release_notes_version = boost::none;
208         _allow_smpte_bv20 = false;
209         _isdcf_name_part_length = 14;
210
211         _allowed_dcp_frame_rates.clear ();
212         _allowed_dcp_frame_rates.push_back (24);
213         _allowed_dcp_frame_rates.push_back (25);
214         _allowed_dcp_frame_rates.push_back (30);
215         _allowed_dcp_frame_rates.push_back (48);
216         _allowed_dcp_frame_rates.push_back (50);
217         _allowed_dcp_frame_rates.push_back (60);
218
219         set_kdm_email_to_default ();
220         set_notification_email_to_default ();
221         set_cover_sheet_to_default ();
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(dcp::filesystem::fix_long_path(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                         case BAD_SIGNER_DN_QUALIFIER:
512                                 _signer_chain = create_certificate_chain ();
513                                 break;
514                         case BAD_DECRYPTION_INCONSISTENT:
515                                 _decryption_chain = create_certificate_chain ();
516                                 break;
517                         }
518                 }
519         }
520
521         if (f.optional_node_child("DKDMGroup")) {
522                 /* New-style: all DKDMs in a group */
523                 _dkdms = dynamic_pointer_cast<DKDMGroup> (DKDMBase::read (f.node_child("DKDMGroup")));
524         } else {
525                 /* Old-style: one or more DKDM nodes */
526                 _dkdms = make_shared<DKDMGroup>("root");
527                 for (auto i: f.node_children("DKDM")) {
528                         _dkdms->add (DKDMBase::read (i));
529                 }
530         }
531         _cinemas_file = f.optional_string_child("CinemasFile").get_value_or(read_path("cinemas.xml").string());
532         _dkdm_recipients_file = f.optional_string_child("DKDMRecipientsFile").get_value_or(read_path("dkdm_recipients.xml").string());
533         _show_hints_before_make_dcp = f.optional_bool_child("ShowHintsBeforeMakeDCP").get_value_or (true);
534         _confirm_kdm_email = f.optional_bool_child("ConfirmKDMEmail").get_value_or (true);
535         _kdm_container_name_format = dcp::NameFormat (f.optional_string_child("KDMContainerNameFormat").get_value_or ("KDM %f %c"));
536         _kdm_filename_format = dcp::NameFormat (f.optional_string_child("KDMFilenameFormat").get_value_or ("KDM %f %c %s"));
537         _dkdm_filename_format = dcp::NameFormat (f.optional_string_child("DKDMFilenameFormat").get_value_or("DKDM %f %c %s"));
538         _dcp_metadata_filename_format = dcp::NameFormat (f.optional_string_child("DCPMetadataFilenameFormat").get_value_or ("%t"));
539         _dcp_asset_filename_format = dcp::NameFormat (f.optional_string_child("DCPAssetFilenameFormat").get_value_or ("%t"));
540         _jump_to_selected = f.optional_bool_child("JumpToSelected").get_value_or (true);
541         /* The variable was renamed but not the XML tag */
542         _sound = f.optional_bool_child("PreviewSound").get_value_or (true);
543         _sound_output = f.optional_string_child("PreviewSoundOutput");
544         if (f.optional_string_child("CoverSheet")) {
545                 _cover_sheet = f.optional_string_child("CoverSheet").get();
546         }
547         _last_player_load_directory = f.optional_string_child("LastPlayerLoadDirectory");
548         if (f.optional_string_child("LastKDMWriteType")) {
549                 if (f.optional_string_child("LastKDMWriteType").get() == "flat") {
550                         _last_kdm_write_type = KDM_WRITE_FLAT;
551                 } else if (f.optional_string_child("LastKDMWriteType").get() == "folder") {
552                         _last_kdm_write_type = KDM_WRITE_FOLDER;
553                 } else if (f.optional_string_child("LastKDMWriteType").get() == "zip") {
554                         _last_kdm_write_type = KDM_WRITE_ZIP;
555                 }
556         }
557         if (f.optional_string_child("LastDKDMWriteType")) {
558                 if (f.optional_string_child("LastDKDMWriteType").get() == "internal") {
559                         _last_dkdm_write_type = DKDM_WRITE_INTERNAL;
560                 } else if (f.optional_string_child("LastDKDMWriteType").get() == "file") {
561                         _last_dkdm_write_type = DKDM_WRITE_FILE;
562                 }
563         }
564         _frames_in_memory_multiplier = f.optional_number_child<int>("FramesInMemoryMultiplier").get_value_or(3);
565         _decode_reduction = f.optional_number_child<int>("DecodeReduction");
566         _default_notify = f.optional_bool_child("DefaultNotify").get_value_or(false);
567
568         for (auto i: f.node_children("Notification")) {
569                 int const id = i->number_attribute<int>("Id");
570                 if (id >= 0 && id < NOTIFICATION_COUNT) {
571                         _notification[id] = raw_convert<int>(i->content());
572                 }
573         }
574
575         _barco_username = f.optional_string_child("BarcoUsername");
576         _barco_password = f.optional_string_child("BarcoPassword");
577         _christie_username = f.optional_string_child("ChristieUsername");
578         _christie_password = f.optional_string_child("ChristiePassword");
579         _gdc_username = f.optional_string_child("GDCUsername");
580         _gdc_password = f.optional_string_child("GDCPassword");
581
582         auto pm = f.optional_string_child("PlayerMode");
583         if (pm && *pm == "window") {
584                 _player_mode = PLAYER_MODE_WINDOW;
585         } else if (pm && *pm == "full") {
586                 _player_mode = PLAYER_MODE_FULL;
587         } else if (pm && *pm == "dual") {
588                 _player_mode = PLAYER_MODE_DUAL;
589         }
590
591         _image_display = f.optional_number_child<int>("ImageDisplay").get_value_or(0);
592         auto vc = f.optional_string_child("VideoViewType");
593         if (vc && *vc == "opengl") {
594                 _video_view_type = VIDEO_VIEW_OPENGL;
595         } else if (vc && *vc == "simple") {
596                 _video_view_type = VIDEO_VIEW_SIMPLE;
597         }
598         _respect_kdm_validity_periods = f.optional_bool_child("RespectKDMValidityPeriods").get_value_or(true);
599         _player_debug_log_file = f.optional_string_child("PlayerDebugLogFile");
600         _player_content_directory = f.optional_string_child("PlayerContentDirectory");
601         _player_playlist_directory = f.optional_string_child("PlayerPlaylistDirectory");
602         _player_kdm_directory = f.optional_string_child("PlayerKDMDirectory");
603
604         if (f.optional_node_child("AudioMapping")) {
605                 _audio_mapping = AudioMapping (f.node_child("AudioMapping"), Film::current_state_version);
606         }
607
608         for (auto i: f.node_children("CustomLanguage")) {
609                 try {
610                         /* This will fail if it's called before dcp::init() as it won't recognise the
611                          * tag.  That's OK because the Config will be reloaded again later.
612                          */
613                         _custom_languages.push_back (dcp::LanguageTag(i->content()));
614                 } catch (std::runtime_error& e) {}
615         }
616
617         for (auto& initial: _initial_paths) {
618                 initial.second = f.optional_string_child(initial.first);
619         }
620         _use_isdcf_name_by_default = f.optional_bool_child("UseISDCFNameByDefault").get_value_or(true);
621         _write_kdms_to_disk = f.optional_bool_child("WriteKDMsToDisk").get_value_or(true);
622         _email_kdms = f.optional_bool_child("EmailKDMs").get_value_or(false);
623         _default_kdm_type = dcp::string_to_formulation(f.optional_string_child("DefaultKDMType").get_value_or("modified-transitional-1"));
624         if (auto duration = f.optional_node_child("DefaultKDMDuration")) {
625                 _default_kdm_duration = RoughDuration(duration);
626         } else {
627                 _default_kdm_duration = RoughDuration(1, RoughDuration::Unit::WEEKS);
628         }
629         _auto_crop_threshold = f.optional_number_child<double>("AutoCropThreshold").get_value_or(0.1);
630         _last_release_notes_version = f.optional_string_child("LastReleaseNotesVersion");
631         _main_divider_sash_position = f.optional_number_child<int>("MainDividerSashPosition");
632         _main_content_divider_sash_position = f.optional_number_child<int>("MainContentDividerSashPosition");
633
634         if (auto loc = f.optional_string_child("DefaultAddFileLocation")) {
635                 if (*loc == "last") {
636                         _default_add_file_location = DefaultAddFileLocation::SAME_AS_LAST_TIME;
637                 } else if (*loc == "project") {
638                         _default_add_file_location = DefaultAddFileLocation::SAME_AS_PROJECT;
639                 }
640         }
641
642         _allow_smpte_bv20 = f.optional_bool_child("AllowSMPTEBv20").get_value_or(false);
643         _isdcf_name_part_length = f.optional_number_child<int>("ISDCFNamePartLength").get_value_or(14);
644
645         _export.read(f.optional_node_child("Export"));
646 }
647 catch (...) {
648         if (have_existing("config.xml")) {
649                 backup ();
650                 /* We have a config file but it didn't load */
651                 FailedToLoad(LoadFailure::CONFIG);
652         }
653         set_defaults ();
654         /* Make a new set of signing certificates and key */
655         _signer_chain = create_certificate_chain ();
656         /* And similar for decryption of KDMs */
657         _decryption_chain = create_certificate_chain ();
658         write_config();
659 }
660
661
662 void
663 Config::read_cinemas()
664 {
665         if (dcp::filesystem::exists(_cinemas_file)) {
666                 try {
667                         cxml::Document f("Cinemas");
668                         f.read_file(dcp::filesystem::fix_long_path(_cinemas_file));
669                         read_cinemas(f);
670                 } catch (...) {
671                         backup();
672                         FailedToLoad(LoadFailure::CINEMAS);
673                         write_cinemas();
674                 }
675         }
676 }
677
678
679 void
680 Config::read_dkdm_recipients()
681 {
682         if (dcp::filesystem::exists(_dkdm_recipients_file)) {
683                 try {
684                         cxml::Document f("DKDMRecipients");
685                         f.read_file(dcp::filesystem::fix_long_path(_dkdm_recipients_file));
686                         read_dkdm_recipients(f);
687                 } catch (...) {
688                         backup();
689                         FailedToLoad(LoadFailure::DKDM_RECIPIENTS);
690                         write_dkdm_recipients();
691                 }
692         }
693 }
694
695
696 /** @return Singleton instance */
697 Config *
698 Config::instance ()
699 {
700         if (_instance == nullptr) {
701                 _instance = new Config;
702                 _instance->read ();
703         }
704
705         return _instance;
706 }
707
708 /** Write our configuration to disk */
709 void
710 Config::write () const
711 {
712         write_config ();
713         write_cinemas ();
714         write_dkdm_recipients ();
715 }
716
717 void
718 Config::write_config () const
719 {
720         xmlpp::Document doc;
721         auto root = doc.create_root_node ("Config");
722
723         /* [XML] Version The version number of the configuration file format. */
724         root->add_child("Version")->add_child_text (raw_convert<string>(_current_version));
725         /* [XML] MasterEncodingThreads Number of encoding threads to use when running as master. */
726         root->add_child("MasterEncodingThreads")->add_child_text (raw_convert<string> (_master_encoding_threads));
727         /* [XML] ServerEncodingThreads Number of encoding threads to use when running as server. */
728         root->add_child("ServerEncodingThreads")->add_child_text (raw_convert<string> (_server_encoding_threads));
729         if (_default_directory) {
730                 /* [XML:opt] DefaultDirectory Default directory when creating a new film in the GUI. */
731                 root->add_child("DefaultDirectory")->add_child_text (_default_directory->string ());
732         }
733         /* [XML] ServerPortBase Port number to use for frame encoding requests.  <code>ServerPortBase</code> + 1 and
734            <code>ServerPortBase</code> + 2 are used for querying servers.  <code>ServerPortBase</code> + 3 is used
735            by the batch converter to listen for job requests.
736         */
737         root->add_child("ServerPortBase")->add_child_text (raw_convert<string> (_server_port_base));
738         /* [XML] UseAnyServers 1 to broadcast to look for encoding servers to use, 0 to use only those configured. */
739         root->add_child("UseAnyServers")->add_child_text (_use_any_servers ? "1" : "0");
740
741         for (auto i: _servers) {
742                 /* [XML:opt] Server IP address or hostname of an encoding server to use; you can use as many of these tags
743                    as you like.
744                 */
745                 root->add_child("Server")->add_child_text (i);
746         }
747
748         /* [XML] OnlyServersEncode 1 to set the master to do decoding of source content no JPEG2000 encoding; all encoding
749            is done by the encoding servers.  0 to set the master to do some encoding as well as coordinating the job.
750         */
751         root->add_child("OnlyServersEncode")->add_child_text (_only_servers_encode ? "1" : "0");
752         /* [XML] TMSProtocol Protocol to use to copy files to a TMS; 0 to use SCP, 1 for FTP. */
753         root->add_child("TMSProtocol")->add_child_text (raw_convert<string> (static_cast<int> (_tms_protocol)));
754         /* [XML] TMSPassive True to use PASV mode with TMS FTP connections. */
755         root->add_child("TMSPassive")->add_child_text(_tms_passive ? "1" : "0");
756         /* [XML] TMSIP IP address of TMS. */
757         root->add_child("TMSIP")->add_child_text (_tms_ip);
758         /* [XML] TMSPath Path on the TMS to copy files to. */
759         root->add_child("TMSPath")->add_child_text (_tms_path);
760         /* [XML] TMSUser Username to log into the TMS with. */
761         root->add_child("TMSUser")->add_child_text (_tms_user);
762         /* [XML] TMSPassword Password to log into the TMS with. */
763         root->add_child("TMSPassword")->add_child_text (_tms_password);
764         if (_language) {
765                 /* [XML:opt] Language Language to use in the GUI e.g. <code>fr_FR</code>. */
766                 root->add_child("Language")->add_child_text (_language.get());
767         }
768         if (_default_dcp_content_type) {
769                 /* [XML:opt] DefaultDCPContentType Default content type to use when creating new films (<code>FTR</code>, <code>SHR</code>,
770                    <code>TLR</code>, <code>TST</code>, <code>XSN</code>, <code>RTG</code>, <code>TSR</code>, <code>POL</code>,
771                    <code>PSA</code> or <code>ADV</code>). */
772                 root->add_child("DefaultDCPContentType")->add_child_text (_default_dcp_content_type->isdcf_name ());
773         }
774         /* [XML] DefaultDCPAudioChannels Default number of audio channels to use when creating new films. */
775         root->add_child("DefaultDCPAudioChannels")->add_child_text (raw_convert<string> (_default_dcp_audio_channels));
776         /* [XML] DCPIssuer Issuer text to write into CPL files. */
777         root->add_child("DCPIssuer")->add_child_text (_dcp_issuer);
778         /* [XML] DCPCreator Creator text to write into CPL files. */
779         root->add_child("DCPCreator")->add_child_text (_dcp_creator);
780         /* [XML] Company name to write into MXF files. */
781         root->add_child("DCPCompanyName")->add_child_text (_dcp_company_name);
782         /* [XML] Product name to write into MXF files. */
783         root->add_child("DCPProductName")->add_child_text (_dcp_product_name);
784         /* [XML] Product version to write into MXF files. */
785         root->add_child("DCPProductVersion")->add_child_text (_dcp_product_version);
786         /* [XML] Comment to write into JPEG2000 data. */
787         root->add_child("DCPJ2KComment")->add_child_text (_dcp_j2k_comment);
788         /* [XML] UploadAfterMakeDCP 1 to upload to a TMS after making a DCP, 0 for no upload. */
789         root->add_child("UploadAfterMakeDCP")->add_child_text (_upload_after_make_dcp ? "1" : "0");
790
791         /* [XML] DefaultStillLength Default length (in seconds) for still images in new films. */
792         root->add_child("DefaultStillLength")->add_child_text (raw_convert<string> (_default_still_length));
793         /* [XML] DefaultJ2KBandwidth Default bitrate (in bits per second) for JPEG2000 data in new films. */
794         root->add_child("DefaultJ2KBandwidth")->add_child_text (raw_convert<string> (_default_j2k_bandwidth));
795         /* [XML] DefaultAudioDelay Default delay to apply to audio (positive moves audio later) in milliseconds. */
796         root->add_child("DefaultAudioDelay")->add_child_text (raw_convert<string> (_default_audio_delay));
797         /* [XML] DefaultInterop 1 to default new films to Interop, 0 for SMPTE. */
798         root->add_child("DefaultInterop")->add_child_text (_default_interop ? "1" : "0");
799         if (_default_audio_language) {
800                 /* [XML] DefaultAudioLanguage Default audio language to use for new films */
801                 root->add_child("DefaultAudioLanguage")->add_child_text(_default_audio_language->to_string());
802         }
803         if (_default_territory) {
804                 /* [XML] DefaultTerritory Default territory to use for new films */
805                 root->add_child("DefaultTerritory")->add_child_text(_default_territory->subtag());
806         }
807         for (auto const& i: _default_metadata) {
808                 auto c = root->add_child("DefaultMetadata");
809                 c->set_attribute("key", i.first);
810                 c->add_child_text(i.second);
811         }
812         if (_default_kdm_directory) {
813                 /* [XML:opt] DefaultKDMDirectory Default directory to write KDMs to. */
814                 root->add_child("DefaultKDMDirectory")->add_child_text (_default_kdm_directory->string ());
815         }
816         _default_kdm_duration.as_xml(root->add_child("DefaultKDMDuration"));
817         /* [XML] MailServer Hostname of SMTP server to use. */
818         root->add_child("MailServer")->add_child_text (_mail_server);
819         /* [XML] MailPort Port number to use on SMTP server. */
820         root->add_child("MailPort")->add_child_text (raw_convert<string> (_mail_port));
821         /* [XML] MailProtocol Protocol to use on SMTP server (Auto, Plain, STARTTLS or SSL) */
822         switch (_mail_protocol) {
823         case EmailProtocol::AUTO:
824                 root->add_child("MailProtocol")->add_child_text("Auto");
825                 break;
826         case EmailProtocol::PLAIN:
827                 root->add_child("MailProtocol")->add_child_text("Plain");
828                 break;
829         case EmailProtocol::STARTTLS:
830                 root->add_child("MailProtocol")->add_child_text("STARTTLS");
831                 break;
832         case EmailProtocol::SSL:
833                 root->add_child("MailProtocol")->add_child_text("SSL");
834                 break;
835         }
836         /* [XML] MailUser Username to use on SMTP server. */
837         root->add_child("MailUser")->add_child_text (_mail_user);
838         /* [XML] MailPassword Password to use on SMTP server. */
839         root->add_child("MailPassword")->add_child_text (_mail_password);
840
841         /* [XML] KDMSubject Subject to use for KDM emails. */
842         root->add_child("KDMSubject")->add_child_text (_kdm_subject);
843         /* [XML] KDMFrom From address to use for KDM emails. */
844         root->add_child("KDMFrom")->add_child_text (_kdm_from);
845         for (auto i: _kdm_cc) {
846                 /* [XML] KDMCC CC address to use for KDM emails; you can use as many of these tags as you like. */
847                 root->add_child("KDMCC")->add_child_text (i);
848         }
849         /* [XML] KDMBCC BCC address to use for KDM emails. */
850         root->add_child("KDMBCC")->add_child_text (_kdm_bcc);
851         /* [XML] KDMEmail Text of KDM email. */
852         root->add_child("KDMEmail")->add_child_text (_kdm_email);
853
854         /* [XML] NotificationSubject Subject to use for notification emails. */
855         root->add_child("NotificationSubject")->add_child_text (_notification_subject);
856         /* [XML] NotificationFrom From address to use for notification emails. */
857         root->add_child("NotificationFrom")->add_child_text (_notification_from);
858         /* [XML] NotificationFrom To address to use for notification emails. */
859         root->add_child("NotificationTo")->add_child_text (_notification_to);
860         for (auto i: _notification_cc) {
861                 /* [XML] NotificationCC CC address to use for notification emails; you can use as many of these tags as you like. */
862                 root->add_child("NotificationCC")->add_child_text (i);
863         }
864         /* [XML] NotificationBCC BCC address to use for notification emails. */
865         root->add_child("NotificationBCC")->add_child_text (_notification_bcc);
866         /* [XML] NotificationEmail Text of notification email. */
867         root->add_child("NotificationEmail")->add_child_text (_notification_email);
868
869         /* [XML] CheckForUpdates 1 to check dcpomatic.com for new versions, 0 to check only on request. */
870         root->add_child("CheckForUpdates")->add_child_text (_check_for_updates ? "1" : "0");
871         /* [XML] CheckForUpdates 1 to check dcpomatic.com for new text versions, 0 to check only on request. */
872         root->add_child("CheckForTestUpdates")->add_child_text (_check_for_test_updates ? "1" : "0");
873
874         /* [XML] MaximumJ2KBandwidth Maximum J2K bandwidth (in bits per second) that can be specified in the GUI. */
875         root->add_child("MaximumJ2KBandwidth")->add_child_text (raw_convert<string> (_maximum_j2k_bandwidth));
876         /* [XML] AllowAnyDCPFrameRate 1 to allow users to specify any frame rate when creating DCPs, 0 to limit the GUI to standard rates. */
877         root->add_child("AllowAnyDCPFrameRate")->add_child_text (_allow_any_dcp_frame_rate ? "1" : "0");
878         /* [XML] AllowAnyContainer 1 to allow users to user any container ratio for their DCP, 0 to limit the GUI to DCI Flat/Scope */
879         root->add_child("AllowAnyContainer")->add_child_text (_allow_any_container ? "1" : "0");
880         /* [XML] Allow96kHzAudio 1 to allow users to make DCPs with 96kHz audio, 0 to always make 48kHz DCPs */
881         root->add_child("Allow96kHzAudio")->add_child_text(_allow_96khz_audio ? "1" : "0");
882         /* [XML] UseAllAudioChannels 1 to allow users to map audio to all 16 DCP channels, 0 to limit to the channels used in standard DCPs */
883         root->add_child("UseAllAudioChannels")->add_child_text(_use_all_audio_channels ? "1" : "0");
884         /* [XML] ShowExperimentalAudioProcessors 1 to offer users the (experimental) audio upmixer processors, 0 to hide them */
885         root->add_child("ShowExperimentalAudioProcessors")->add_child_text (_show_experimental_audio_processors ? "1" : "0");
886         /* [XML] LogTypes Types of logging to write; a bitfield where 1 is general notes, 2 warnings, 4 errors, 8 debug information related
887            to 3D, 16 debug information related to encoding, 32 debug information for timing purposes, 64 debug information related
888            to sending email, 128 debug information related to the video view, 256 information about disk writing, 512 debug information
889            related to the player, 1024 debug information related to audio analyses.
890         */
891         root->add_child("LogTypes")->add_child_text (raw_convert<string> (_log_types));
892         /* [XML] AnalyseEBUR128 1 to do EBUR128 analyses when analysing audio, otherwise 0. */
893         root->add_child("AnalyseEBUR128")->add_child_text (_analyse_ebur128 ? "1" : "0");
894         /* [XML] AutomaticAudioAnalysis 1 to run audio analysis automatically when audio content is added to the film, otherwise 0. */
895         root->add_child("AutomaticAudioAnalysis")->add_child_text (_automatic_audio_analysis ? "1" : "0");
896 #ifdef DCPOMATIC_WINDOWS
897         if (_win32_console) {
898                 /* [XML] Win32Console 1 to open a console when running on Windows, otherwise 0.
899                  * We only write this if it's true, which is a bit of a hack to allow unit tests to work
900                  * more easily on Windows (without a platform-specific reference in config_write_utf8_test)
901                  */
902                 root->add_child("Win32Console")->add_child_text ("1");
903         }
904 #endif
905
906         /* [XML] Signer Certificate chain and private key to use when signing DCPs and KDMs.  Should contain <code>&lt;Certificate&gt;</code>
907            tags in order and a <code>&lt;PrivateKey&gt;</code> tag all containing PEM-encoded certificates or private keys as appropriate.
908         */
909         auto signer = root->add_child ("Signer");
910         DCPOMATIC_ASSERT (_signer_chain);
911         for (auto const& i: _signer_chain->unordered()) {
912                 signer->add_child("Certificate")->add_child_text (i.certificate (true));
913         }
914         signer->add_child("PrivateKey")->add_child_text (_signer_chain->key().get ());
915
916         /* [XML] Decryption Certificate chain and private key to use when decrypting KDMs */
917         auto decryption = root->add_child ("Decryption");
918         DCPOMATIC_ASSERT (_decryption_chain);
919         for (auto const& i: _decryption_chain->unordered()) {
920                 decryption->add_child("Certificate")->add_child_text (i.certificate (true));
921         }
922         decryption->add_child("PrivateKey")->add_child_text (_decryption_chain->key().get ());
923
924         /* [XML] History Filename of DCP to present in the <guilabel>File</guilabel> menu of the GUI; there can be more than one
925            of these tags.
926         */
927         for (auto i: _history) {
928                 root->add_child("History")->add_child_text (i.string ());
929         }
930
931         /* [XML] History Filename of DCP to present in the <guilabel>File</guilabel> menu of the player; there can be more than one
932            of these tags.
933         */
934         for (auto i: _player_history) {
935                 root->add_child("PlayerHistory")->add_child_text (i.string ());
936         }
937
938         /* [XML] DKDMGroup A group of DKDMs, each with a <code>Name</code> attribute, containing other <code>&lt;DKDMGroup&gt;</code>
939            or <code>&lt;DKDM&gt;</code> tags.
940         */
941         /* [XML] DKDM A DKDM as XML */
942         _dkdms->as_xml (root);
943
944         /* [XML] CinemasFile Filename of cinemas list file. */
945         root->add_child("CinemasFile")->add_child_text (_cinemas_file.string());
946         /* [XML] DKDMRecipientsFile Filename of DKDM recipients list file. */
947         root->add_child("DKDMRecipientsFile")->add_child_text (_dkdm_recipients_file.string());
948         /* [XML] ShowHintsBeforeMakeDCP 1 to show hints in the GUI before making a DCP, otherwise 0. */
949         root->add_child("ShowHintsBeforeMakeDCP")->add_child_text (_show_hints_before_make_dcp ? "1" : "0");
950         /* [XML] ConfirmKDMEmail 1 to confirm before sending KDM emails in the GUI, otherwise 0. */
951         root->add_child("ConfirmKDMEmail")->add_child_text (_confirm_kdm_email ? "1" : "0");
952         /* [XML] KDMFilenameFormat Format for KDM filenames. */
953         root->add_child("KDMFilenameFormat")->add_child_text (_kdm_filename_format.specification ());
954         /* [XML] KDMFilenameFormat Format for DKDM filenames. */
955         root->add_child("DKDMFilenameFormat")->add_child_text(_dkdm_filename_format.specification());
956         /* [XML] KDMContainerNameFormat Format for KDM containers (directories or ZIP files). */
957         root->add_child("KDMContainerNameFormat")->add_child_text (_kdm_container_name_format.specification ());
958         /* [XML] DCPMetadataFilenameFormat Format for DCP metadata filenames. */
959         root->add_child("DCPMetadataFilenameFormat")->add_child_text (_dcp_metadata_filename_format.specification ());
960         /* [XML] DCPAssetFilenameFormat Format for DCP asset filenames. */
961         root->add_child("DCPAssetFilenameFormat")->add_child_text (_dcp_asset_filename_format.specification ());
962         /* [XML] JumpToSelected 1 to make the GUI jump to the start of content when it is selected, otherwise 0. */
963         root->add_child("JumpToSelected")->add_child_text (_jump_to_selected ? "1" : "0");
964         /* [XML] Nagged 1 if a particular nag screen has been shown and should not be shown again, otherwise 0. */
965         for (int i = 0; i < NAG_COUNT; ++i) {
966                 xmlpp::Element* e = root->add_child ("Nagged");
967                 e->set_attribute ("Id", raw_convert<string>(i));
968                 e->add_child_text (_nagged[i] ? "1" : "0");
969         }
970         /* [XML] PreviewSound 1 to use sound in the GUI preview and player, otherwise 0. */
971         root->add_child("PreviewSound")->add_child_text (_sound ? "1" : "0");
972         if (_sound_output) {
973                 /* [XML:opt] PreviewSoundOutput Name of the audio output to use. */
974                 root->add_child("PreviewSoundOutput")->add_child_text (_sound_output.get());
975         }
976         /* [XML] CoverSheet Text of the cover sheet to write when making DCPs. */
977         root->add_child("CoverSheet")->add_child_text (_cover_sheet);
978         if (_last_player_load_directory) {
979                 root->add_child("LastPlayerLoadDirectory")->add_child_text(_last_player_load_directory->string());
980         }
981         /* [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. */
982         if (_last_kdm_write_type) {
983                 switch (_last_kdm_write_type.get()) {
984                 case KDM_WRITE_FLAT:
985                         root->add_child("LastKDMWriteType")->add_child_text("flat");
986                         break;
987                 case KDM_WRITE_FOLDER:
988                         root->add_child("LastKDMWriteType")->add_child_text("folder");
989                         break;
990                 case KDM_WRITE_ZIP:
991                         root->add_child("LastKDMWriteType")->add_child_text("zip");
992                         break;
993                 }
994         }
995         /* [XML] LastDKDMWriteType Last type of DKDM-write: <code>file</code> for a file, <code>internal</code> to add to DCP-o-matic's list. */
996         if (_last_dkdm_write_type) {
997                 switch (_last_dkdm_write_type.get()) {
998                 case DKDM_WRITE_INTERNAL:
999                         root->add_child("LastDKDMWriteType")->add_child_text("internal");
1000                         break;
1001                 case DKDM_WRITE_FILE:
1002                         root->add_child("LastDKDMWriteType")->add_child_text("file");
1003                         break;
1004                 }
1005         }
1006         /* [XML] FramesInMemoryMultiplier value to multiply the encoding threads count by to get the maximum number of
1007            frames to be held in memory at once.
1008         */
1009         root->add_child("FramesInMemoryMultiplier")->add_child_text(raw_convert<string>(_frames_in_memory_multiplier));
1010
1011         /* [XML] DecodeReduction power of 2 to reduce DCP images by before decoding in the player. */
1012         if (_decode_reduction) {
1013                 root->add_child("DecodeReduction")->add_child_text(raw_convert<string>(_decode_reduction.get()));
1014         }
1015
1016         /* [XML] DefaultNotify 1 to default jobs to notify when complete, otherwise 0. */
1017         root->add_child("DefaultNotify")->add_child_text(_default_notify ? "1" : "0");
1018
1019         /* [XML] Notification 1 if a notification type is enabled, otherwise 0. */
1020         for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
1021                 xmlpp::Element* e = root->add_child ("Notification");
1022                 e->set_attribute ("Id", raw_convert<string>(i));
1023                 e->add_child_text (_notification[i] ? "1" : "0");
1024         }
1025
1026         if (_barco_username) {
1027                 /* [XML] BarcoUsername Username for logging into Barco's servers when downloading server certificates. */
1028                 root->add_child("BarcoUsername")->add_child_text(*_barco_username);
1029         }
1030         if (_barco_password) {
1031                 /* [XML] BarcoPassword Password for logging into Barco's servers when downloading server certificates. */
1032                 root->add_child("BarcoPassword")->add_child_text(*_barco_password);
1033         }
1034
1035         if (_christie_username) {
1036                 /* [XML] ChristieUsername Username for logging into Christie's servers when downloading server certificates. */
1037                 root->add_child("ChristieUsername")->add_child_text(*_christie_username);
1038         }
1039         if (_christie_password) {
1040                 /* [XML] ChristiePassword Password for logging into Christie's servers when downloading server certificates. */
1041                 root->add_child("ChristiePassword")->add_child_text(*_christie_password);
1042         }
1043
1044         if (_gdc_username) {
1045                 /* [XML] GDCUsername Username for logging into GDC's servers when downloading server certificates. */
1046                 root->add_child("GDCUsername")->add_child_text(*_gdc_username);
1047         }
1048         if (_gdc_password) {
1049                 /* [XML] GDCPassword Password for logging into GDC's servers when downloading server certificates. */
1050                 root->add_child("GDCPassword")->add_child_text(*_gdc_password);
1051         }
1052
1053         /* [XML] PlayerMode <code>window</code> for a single window, <code>full</code> for full-screen and <code>dual</code> for full screen playback
1054            with separate (advanced) controls.
1055         */
1056         switch (_player_mode) {
1057         case PLAYER_MODE_WINDOW:
1058                 root->add_child("PlayerMode")->add_child_text("window");
1059                 break;
1060         case PLAYER_MODE_FULL:
1061                 root->add_child("PlayerMode")->add_child_text("full");
1062                 break;
1063         case PLAYER_MODE_DUAL:
1064                 root->add_child("PlayerMode")->add_child_text("dual");
1065                 break;
1066         }
1067
1068         /* [XML] ImageDisplay Screen number to put image on in dual-screen player mode. */
1069         root->add_child("ImageDisplay")->add_child_text(raw_convert<string>(_image_display));
1070         switch (_video_view_type) {
1071         case VIDEO_VIEW_SIMPLE:
1072                 root->add_child("VideoViewType")->add_child_text("simple");
1073                 break;
1074         case VIDEO_VIEW_OPENGL:
1075                 root->add_child("VideoViewType")->add_child_text("opengl");
1076                 break;
1077         }
1078         /* [XML] RespectKDMValidityPeriods 1 to refuse to use KDMs that are out of date, 0 to ignore KDM dates. */
1079         root->add_child("RespectKDMValidityPeriods")->add_child_text(_respect_kdm_validity_periods ? "1" : "0");
1080         if (_player_debug_log_file) {
1081                 /* [XML] PlayerLogFile Filename to use for player debug logs. */
1082                 root->add_child("PlayerDebugLogFile")->add_child_text(_player_debug_log_file->string());
1083         }
1084         if (_player_content_directory) {
1085                 /* [XML] PlayerContentDirectory Directory to use for player content in the dual-screen mode. */
1086                 root->add_child("PlayerContentDirectory")->add_child_text(_player_content_directory->string());
1087         }
1088         if (_player_playlist_directory) {
1089                 /* [XML] PlayerPlaylistDirectory Directory to use for player playlists in the dual-screen mode. */
1090                 root->add_child("PlayerPlaylistDirectory")->add_child_text(_player_playlist_directory->string());
1091         }
1092         if (_player_kdm_directory) {
1093                 /* [XML] PlayerKDMDirectory Directory to use for player KDMs in the dual-screen mode. */
1094                 root->add_child("PlayerKDMDirectory")->add_child_text(_player_kdm_directory->string());
1095         }
1096         if (_audio_mapping) {
1097                 _audio_mapping->as_xml (root->add_child("AudioMapping"));
1098         }
1099         for (auto const& i: _custom_languages) {
1100                 root->add_child("CustomLanguage")->add_child_text(i.to_string());
1101         }
1102         for (auto const& initial: _initial_paths) {
1103                 if (initial.second) {
1104                         root->add_child(initial.first)->add_child_text(initial.second->string());
1105                 }
1106         }
1107         root->add_child("UseISDCFNameByDefault")->add_child_text(_use_isdcf_name_by_default ? "1" : "0");
1108         root->add_child("WriteKDMsToDisk")->add_child_text(_write_kdms_to_disk ? "1" : "0");
1109         root->add_child("EmailKDMs")->add_child_text(_email_kdms ? "1" : "0");
1110         root->add_child("DefaultKDMType")->add_child_text(dcp::formulation_to_string(_default_kdm_type));
1111         root->add_child("AutoCropThreshold")->add_child_text(raw_convert<string>(_auto_crop_threshold));
1112         if (_last_release_notes_version) {
1113                 root->add_child("LastReleaseNotesVersion")->add_child_text(*_last_release_notes_version);
1114         }
1115         if (_main_divider_sash_position) {
1116                 root->add_child("MainDividerSashPosition")->add_child_text(raw_convert<string>(*_main_divider_sash_position));
1117         }
1118         if (_main_content_divider_sash_position) {
1119                 root->add_child("MainContentDividerSashPosition")->add_child_text(raw_convert<string>(*_main_content_divider_sash_position));
1120         }
1121
1122         root->add_child("DefaultAddFileLocation")->add_child_text(
1123                 _default_add_file_location == DefaultAddFileLocation::SAME_AS_LAST_TIME ? "last" : "project"
1124                 );
1125
1126         /* [XML] AllowSMPTEBv20 1 to allow the user to choose SMPTE (Bv2.0 only) as a standard, otherwise 0 */
1127         root->add_child("AllowSMPTEBv20")->add_child_text(_allow_smpte_bv20 ? "1" : "0");
1128         /* [XML] ISDCFNamePartLength Maximum length of the "name" part of an ISDCF name, which should be 14 according to the standard */
1129         root->add_child("ISDCFNamePartLength")->add_child_text(raw_convert<string>(_isdcf_name_part_length));
1130
1131         _export.write(root->add_child("Export"));
1132
1133         auto target = config_write_file();
1134
1135         try {
1136                 auto const s = doc.write_to_string_formatted ();
1137                 boost::filesystem::path tmp (string(target.string()).append(".tmp"));
1138                 dcp::File f(tmp, "w");
1139                 if (!f) {
1140                         throw FileError (_("Could not open file for writing"), tmp);
1141                 }
1142                 f.checked_write(s.c_str(), s.bytes());
1143                 f.close();
1144                 dcp::filesystem::remove(target);
1145                 dcp::filesystem::rename(tmp, target);
1146         } catch (xmlpp::exception& e) {
1147                 string s = e.what ();
1148                 trim (s);
1149                 throw FileError (s, target);
1150         }
1151 }
1152
1153
1154 template <class T>
1155 void
1156 write_file (string root_node, string node, string version, list<shared_ptr<T>> things, boost::filesystem::path file)
1157 {
1158         xmlpp::Document doc;
1159         auto root = doc.create_root_node (root_node);
1160         root->add_child("Version")->add_child_text(version);
1161
1162         for (auto i: things) {
1163                 i->as_xml (root->add_child(node));
1164         }
1165
1166         try {
1167                 doc.write_to_file_formatted (file.string() + ".tmp");
1168                 dcp::filesystem::remove(file);
1169                 dcp::filesystem::rename(file.string() + ".tmp", file);
1170         } catch (xmlpp::exception& e) {
1171                 string s = e.what ();
1172                 trim (s);
1173                 throw FileError (s, file);
1174         }
1175 }
1176
1177
1178 void
1179 Config::write_cinemas () const
1180 {
1181         write_file ("Cinemas", "Cinema", "1", _cinemas, _cinemas_file);
1182 }
1183
1184
1185 void
1186 Config::write_dkdm_recipients () const
1187 {
1188         write_file ("DKDMRecipients", "DKDMRecipient", "1", _dkdm_recipients, _dkdm_recipients_file);
1189 }
1190
1191
1192 boost::filesystem::path
1193 Config::default_directory_or (boost::filesystem::path a) const
1194 {
1195         return directory_or (_default_directory, a);
1196 }
1197
1198 boost::filesystem::path
1199 Config::default_kdm_directory_or (boost::filesystem::path a) const
1200 {
1201         return directory_or (_default_kdm_directory, a);
1202 }
1203
1204 boost::filesystem::path
1205 Config::directory_or (optional<boost::filesystem::path> dir, boost::filesystem::path a) const
1206 {
1207         if (!dir) {
1208                 return a;
1209         }
1210
1211         boost::system::error_code ec;
1212         auto const e = dcp::filesystem::exists(*dir, ec);
1213         if (ec || !e) {
1214                 return a;
1215         }
1216
1217         return *dir;
1218 }
1219
1220 void
1221 Config::drop ()
1222 {
1223         delete _instance;
1224         _instance = nullptr;
1225 }
1226
1227 void
1228 Config::changed (Property what)
1229 {
1230         Changed (what);
1231 }
1232
1233 void
1234 Config::set_kdm_email_to_default ()
1235 {
1236         _kdm_subject = _("KDM delivery: $CPL_NAME");
1237
1238         _kdm_email = _(
1239                 "Dear Projectionist\n\n"
1240                 "Please find attached KDMs for $CPL_NAME.\n\n"
1241                 "Cinema: $CINEMA_NAME\n"
1242                 "Screen(s): $SCREENS\n\n"
1243                 "The KDMs are valid from $START_TIME until $END_TIME.\n\n"
1244                 "Best regards,\nDCP-o-matic"
1245                 );
1246 }
1247
1248 void
1249 Config::set_notification_email_to_default ()
1250 {
1251         _notification_subject = _("DCP-o-matic notification");
1252
1253         _notification_email = _(
1254                 "$JOB_NAME: $JOB_STATUS"
1255                 );
1256 }
1257
1258 void
1259 Config::reset_kdm_email ()
1260 {
1261         set_kdm_email_to_default ();
1262         changed ();
1263 }
1264
1265 void
1266 Config::reset_notification_email ()
1267 {
1268         set_notification_email_to_default ();
1269         changed ();
1270 }
1271
1272 void
1273 Config::set_cover_sheet_to_default ()
1274 {
1275         _cover_sheet = _(
1276                 "$CPL_NAME\n\n"
1277                 "CPL Filename: $CPL_FILENAME\n"
1278                 "Type: $TYPE\n"
1279                 "Format: $CONTAINER\n"
1280                 "Audio: $AUDIO\n"
1281                 "Audio Language: $AUDIO_LANGUAGE\n"
1282                 "Subtitle Language: $SUBTITLE_LANGUAGE\n"
1283                 "Length: $LENGTH\n"
1284                 "Size: $SIZE\n"
1285                 );
1286 }
1287
1288 void
1289 Config::add_to_history (boost::filesystem::path p)
1290 {
1291         add_to_history_internal (_history, p);
1292 }
1293
1294 /** Remove non-existent items from the history */
1295 void
1296 Config::clean_history ()
1297 {
1298         clean_history_internal (_history);
1299 }
1300
1301 void
1302 Config::add_to_player_history (boost::filesystem::path p)
1303 {
1304         add_to_history_internal (_player_history, p);
1305 }
1306
1307 /** Remove non-existent items from the player history */
1308 void
1309 Config::clean_player_history ()
1310 {
1311         clean_history_internal (_player_history);
1312 }
1313
1314 void
1315 Config::add_to_history_internal (vector<boost::filesystem::path>& h, boost::filesystem::path p)
1316 {
1317         /* Remove existing instances of this path in the history */
1318         h.erase (remove (h.begin(), h.end(), p), h.end ());
1319
1320         h.insert (h.begin (), p);
1321         if (h.size() > HISTORY_SIZE) {
1322                 h.pop_back ();
1323         }
1324
1325         changed (HISTORY);
1326 }
1327
1328 void
1329 Config::clean_history_internal (vector<boost::filesystem::path>& h)
1330 {
1331         auto old = h;
1332         h.clear ();
1333         for (auto i: old) {
1334                 try {
1335                         if (dcp::filesystem::is_directory(i)) {
1336                                 h.push_back (i);
1337                         }
1338                 } catch (...) {
1339                         /* We couldn't find out if it's a directory for some reason; just ignore it */
1340                 }
1341         }
1342 }
1343
1344
1345 bool
1346 Config::have_existing (string file)
1347 {
1348         return dcp::filesystem::exists(read_path(file));
1349 }
1350
1351
1352 void
1353 Config::read_cinemas (cxml::Document const & f)
1354 {
1355         _cinemas.clear ();
1356         for (auto i: f.node_children("Cinema")) {
1357                 /* Slightly grotty two-part construction of Cinema here so that we can use
1358                    shared_from_this.
1359                 */
1360                 auto cinema = make_shared<Cinema>(i);
1361                 cinema->read_screens (i);
1362                 _cinemas.push_back (cinema);
1363         }
1364 }
1365
1366 void
1367 Config::set_cinemas_file (boost::filesystem::path file)
1368 {
1369         if (file == _cinemas_file) {
1370                 return;
1371         }
1372
1373         _cinemas_file = file;
1374
1375         if (dcp::filesystem::exists(_cinemas_file)) {
1376                 /* Existing file; read it in */
1377                 cxml::Document f ("Cinemas");
1378                 f.read_file(dcp::filesystem::fix_long_path(_cinemas_file));
1379                 read_cinemas (f);
1380         }
1381
1382         changed (CINEMAS);
1383         changed (OTHER);
1384 }
1385
1386
1387 void
1388 Config::read_dkdm_recipients (cxml::Document const & f)
1389 {
1390         _dkdm_recipients.clear ();
1391         for (auto i: f.node_children("DKDMRecipient")) {
1392                 _dkdm_recipients.push_back (make_shared<DKDMRecipient>(i));
1393         }
1394 }
1395
1396
1397 void
1398 Config::save_template (shared_ptr<const Film> film, string name) const
1399 {
1400         film->write_template (template_write_path(name));
1401 }
1402
1403
1404 list<string>
1405 Config::templates () const
1406 {
1407         if (!dcp::filesystem::exists(read_path("templates"))) {
1408                 return {};
1409         }
1410
1411         list<string> n;
1412         for (auto const& i: dcp::filesystem::directory_iterator(read_path("templates"))) {
1413                 n.push_back (i.path().filename().string());
1414         }
1415         return n;
1416 }
1417
1418 bool
1419 Config::existing_template (string name) const
1420 {
1421         return dcp::filesystem::exists(template_read_path(name));
1422 }
1423
1424
1425 boost::filesystem::path
1426 Config::template_read_path (string name) const
1427 {
1428         return read_path("templates") / tidy_for_filename (name);
1429 }
1430
1431
1432 boost::filesystem::path
1433 Config::template_write_path (string name) const
1434 {
1435         return write_path("templates") / tidy_for_filename (name);
1436 }
1437
1438
1439 void
1440 Config::rename_template (string old_name, string new_name) const
1441 {
1442         dcp::filesystem::rename(template_read_path(old_name), template_write_path(new_name));
1443 }
1444
1445 void
1446 Config::delete_template (string name) const
1447 {
1448         dcp::filesystem::remove(template_write_path(name));
1449 }
1450
1451 /** @return Path to the config.xml containing the actual settings, following a link if required */
1452 boost::filesystem::path
1453 config_file (boost::filesystem::path main)
1454 {
1455         cxml::Document f ("Config");
1456         if (!dcp::filesystem::exists(main)) {
1457                 /* It doesn't exist, so there can't be any links; just return it */
1458                 return main;
1459         }
1460
1461         /* See if there's a link */
1462         try {
1463                 f.read_file(dcp::filesystem::fix_long_path(main));
1464                 auto link = f.optional_string_child("Link");
1465                 if (link) {
1466                         return *link;
1467                 }
1468         } catch (xmlpp::exception& e) {
1469                 /* There as a problem reading the main configuration file,
1470                    so there can't be a link.
1471                 */
1472         }
1473
1474         return main;
1475 }
1476
1477
1478 boost::filesystem::path
1479 Config::config_read_file ()
1480 {
1481         return config_file (read_path("config.xml"));
1482 }
1483
1484
1485 boost::filesystem::path
1486 Config::config_write_file ()
1487 {
1488         return config_file (write_path("config.xml"));
1489 }
1490
1491
1492 void
1493 Config::reset_cover_sheet ()
1494 {
1495         set_cover_sheet_to_default ();
1496         changed ();
1497 }
1498
1499 void
1500 Config::link (boost::filesystem::path new_file) const
1501 {
1502         xmlpp::Document doc;
1503         doc.create_root_node("Config")->add_child("Link")->add_child_text(new_file.string());
1504         try {
1505                 doc.write_to_file_formatted(write_path("config.xml").string());
1506         } catch (xmlpp::exception& e) {
1507                 string s = e.what ();
1508                 trim (s);
1509                 throw FileError (s, write_path("config.xml"));
1510         }
1511 }
1512
1513 void
1514 Config::copy_and_link (boost::filesystem::path new_file) const
1515 {
1516         write ();
1517         dcp::filesystem::copy_file(config_read_file(), new_file, boost::filesystem::copy_option::overwrite_if_exists);
1518         link (new_file);
1519 }
1520
1521 bool
1522 Config::have_write_permission () const
1523 {
1524         dcp::File f(config_write_file(), "r+");
1525         return static_cast<bool>(f);
1526 }
1527
1528 /** @param  output_channels Number of output channels in use.
1529  *  @return Audio mapping for this output channel count (may be a default).
1530  */
1531 AudioMapping
1532 Config::audio_mapping (int output_channels)
1533 {
1534         if (!_audio_mapping || _audio_mapping->output_channels() != output_channels) {
1535                 /* Set up a default */
1536                 _audio_mapping = AudioMapping (MAX_DCP_AUDIO_CHANNELS, output_channels);
1537                 if (output_channels == 2) {
1538                         /* Special case for stereo output.
1539                            Map so that Lt = L(-3dB) + Ls(-3dB) + C(-6dB) + Lfe(-10dB)
1540                            Rt = R(-3dB) + Rs(-3dB) + C(-6dB) + Lfe(-10dB)
1541                         */
1542                         _audio_mapping->set (dcp::Channel::LEFT,   0, 1 / sqrt(2));  // L   -> Lt
1543                         _audio_mapping->set (dcp::Channel::RIGHT,  1, 1 / sqrt(2));  // R   -> Rt
1544                         _audio_mapping->set (dcp::Channel::CENTRE, 0, 1 / 2.0);      // C   -> Lt
1545                         _audio_mapping->set (dcp::Channel::CENTRE, 1, 1 / 2.0);      // C   -> Rt
1546                         _audio_mapping->set (dcp::Channel::LFE,    0, 1 / sqrt(10)); // Lfe -> Lt
1547                         _audio_mapping->set (dcp::Channel::LFE,    1, 1 / sqrt(10)); // Lfe -> Rt
1548                         _audio_mapping->set (dcp::Channel::LS,     0, 1 / sqrt(2));  // Ls  -> Lt
1549                         _audio_mapping->set (dcp::Channel::RS,     1, 1 / sqrt(2));  // Rs  -> Rt
1550                 } else {
1551                         /* 1:1 mapping */
1552                         for (int i = 0; i < min (MAX_DCP_AUDIO_CHANNELS, output_channels); ++i) {
1553                                 _audio_mapping->set (i, i, 1);
1554                         }
1555                 }
1556         }
1557
1558         return *_audio_mapping;
1559 }
1560
1561 void
1562 Config::set_audio_mapping (AudioMapping m)
1563 {
1564         _audio_mapping = m;
1565         changed (AUDIO_MAPPING);
1566 }
1567
1568 void
1569 Config::set_audio_mapping_to_default ()
1570 {
1571         DCPOMATIC_ASSERT (_audio_mapping);
1572         auto const ch = _audio_mapping->output_channels ();
1573         _audio_mapping = boost::none;
1574         _audio_mapping = audio_mapping (ch);
1575         changed (AUDIO_MAPPING);
1576 }
1577
1578
1579 void
1580 Config::add_custom_language (dcp::LanguageTag tag)
1581 {
1582         if (find(_custom_languages.begin(), _custom_languages.end(), tag) == _custom_languages.end()) {
1583                 _custom_languages.push_back (tag);
1584                 changed ();
1585         }
1586 }
1587
1588
1589 optional<Config::BadReason>
1590 Config::check_certificates () const
1591 {
1592         optional<BadReason> bad;
1593
1594         for (auto const& i: _signer_chain->unordered()) {
1595                 if (i.has_utf8_strings()) {
1596                         bad = BAD_SIGNER_UTF8_STRINGS;
1597                 }
1598                 if ((i.not_after().year() - i.not_before().year()) > 15) {
1599                         bad = BAD_SIGNER_VALIDITY_TOO_LONG;
1600                 }
1601                 if (dcp::escape_digest(i.subject_dn_qualifier()) != dcp::public_key_digest(i.public_key())) {
1602                         bad = BAD_SIGNER_DN_QUALIFIER;
1603                 }
1604         }
1605
1606         if (!_signer_chain->chain_valid() || !_signer_chain->private_key_valid()) {
1607                 bad = BAD_SIGNER_INCONSISTENT;
1608         }
1609
1610         if (!_decryption_chain->chain_valid() || !_decryption_chain->private_key_valid()) {
1611                 bad = BAD_DECRYPTION_INCONSISTENT;
1612         }
1613
1614         return bad;
1615 }
1616
1617
1618 void
1619 save_all_config_as_zip (boost::filesystem::path zip_file)
1620 {
1621         Zipper zipper (zip_file);
1622
1623         auto config = Config::instance();
1624         zipper.add ("config.xml", dcp::file_to_string(config->config_read_file()));
1625         if (dcp::filesystem::exists(config->cinemas_file())) {
1626                 zipper.add ("cinemas.xml", dcp::file_to_string(config->cinemas_file()));
1627         }
1628         if (dcp::filesystem::exists(config->dkdm_recipients_file())) {
1629                 zipper.add ("dkdm_recipients.xml", dcp::file_to_string(config->dkdm_recipients_file()));
1630         }
1631
1632         zipper.close ();
1633 }
1634
1635
1636 void
1637 Config::load_from_zip(boost::filesystem::path zip_file)
1638 {
1639         Unzipper unzipper(zip_file);
1640         dcp::write_string_to_file(unzipper.get("config.xml"), config_write_file());
1641
1642         try {
1643                 dcp::write_string_to_file(unzipper.get("cinemas.xml"), cinemas_file());
1644                 dcp::write_string_to_file(unzipper.get("dkdm_recipient.xml"), dkdm_recipients_file());
1645         } catch (std::runtime_error&) {}
1646
1647         read();
1648
1649         changed(Property::USE_ANY_SERVERS);
1650         changed(Property::SERVERS);
1651         changed(Property::CINEMAS);
1652         changed(Property::DKDM_RECIPIENTS);
1653         changed(Property::SOUND);
1654         changed(Property::SOUND_OUTPUT);
1655         changed(Property::PLAYER_CONTENT_DIRECTORY);
1656         changed(Property::PLAYER_PLAYLIST_DIRECTORY);
1657         changed(Property::PLAYER_DEBUG_LOG);
1658         changed(Property::HISTORY);
1659         changed(Property::SHOW_EXPERIMENTAL_AUDIO_PROCESSORS);
1660         changed(Property::AUDIO_MAPPING);
1661         changed(Property::AUTO_CROP_THRESHOLD);
1662         changed(Property::ALLOW_SMPTE_BV20);
1663         changed(Property::ISDCF_NAME_PART_LENGTH);
1664         changed(Property::OTHER);
1665 }
1666
1667
1668 void
1669 Config::set_initial_path(string id, boost::filesystem::path path)
1670 {
1671         auto iter = _initial_paths.find(id);
1672         DCPOMATIC_ASSERT(iter != _initial_paths.end());
1673         iter->second = path;
1674         changed();
1675 }
1676
1677
1678 optional<boost::filesystem::path>
1679 Config::initial_path(string id) const
1680 {
1681         auto iter = _initial_paths.find(id);
1682         if (iter == _initial_paths.end()) {
1683                 return {};
1684         }
1685         return iter->second;
1686 }
1687