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