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