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