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