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