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