5401839e37743fbe88551e4b5386b852a17f3f6f
[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         /* [XML] DCPIssuer Issuer text to write into CPL files. */
774         cxml::add_text_child(root, "DCPIssuer", _dcp_issuer);
775         /* [XML] DCPCreator Creator text to write into CPL files. */
776         cxml::add_text_child(root, "DCPCreator", _dcp_creator);
777         /* [XML] Company name to write into MXF files. */
778         cxml::add_text_child(root, "DCPCompanyName", _dcp_company_name);
779         /* [XML] Product name to write into MXF files. */
780         cxml::add_text_child(root, "DCPProductName", _dcp_product_name);
781         /* [XML] Product version to write into MXF files. */
782         cxml::add_text_child(root, "DCPProductVersion", _dcp_product_version);
783         /* [XML] Comment to write into JPEG2000 data. */
784         cxml::add_text_child(root, "DCPJ2KComment", _dcp_j2k_comment);
785         /* [XML] UploadAfterMakeDCP 1 to upload to a TMS after making a DCP, 0 for no upload. */
786         cxml::add_text_child(root, "UploadAfterMakeDCP", _upload_after_make_dcp ? "1" : "0");
787
788         /* [XML] DefaultStillLength Default length (in seconds) for still images in new films. */
789         cxml::add_text_child(root, "DefaultStillLength", raw_convert<string>(_default_still_length));
790         /* [XML] DefaultJ2KVideoBitRate Default bitrate (in bits per second) for JPEG2000 data in new films. */
791         cxml::add_text_child(root, "DefaultJ2KVideoBitRate", raw_convert<string>(_default_video_bit_rate[VideoEncoding::JPEG2000]));
792         /* [XML] DefaultMPEG2VideoBitRate Default bitrate (in bits per second) for MPEG2 data in new films. */
793         cxml::add_text_child(root, "DefaultMPEG2VideoBitRate", raw_convert<string>(_default_video_bit_rate[VideoEncoding::MPEG2]));
794         /* [XML] DefaultAudioDelay Default delay to apply to audio (positive moves audio later) in milliseconds. */
795         cxml::add_text_child(root, "DefaultAudioDelay", raw_convert<string>(_default_audio_delay));
796         /* [XML] DefaultInterop 1 to default new films to Interop, 0 for SMPTE. */
797         cxml::add_text_child(root, "DefaultInterop", _default_interop ? "1" : "0");
798         if (_default_audio_language) {
799                 /* [XML] DefaultAudioLanguage Default audio language to use for new films */
800                 cxml::add_text_child(root, "DefaultAudioLanguage", _default_audio_language->to_string());
801         }
802         if (_default_territory) {
803                 /* [XML] DefaultTerritory Default territory to use for new films */
804                 cxml::add_text_child(root, "DefaultTerritory", _default_territory->subtag());
805         }
806         for (auto const& i: _default_metadata) {
807                 auto c = cxml::add_child(root, "DefaultMetadata");
808                 c->set_attribute("key", i.first);
809                 c->add_child_text(i.second);
810         }
811         if (_default_kdm_directory) {
812                 /* [XML:opt] DefaultKDMDirectory Default directory to write KDMs to. */
813                 cxml::add_text_child(root, "DefaultKDMDirectory", _default_kdm_directory->string ());
814         }
815         _default_kdm_duration.as_xml(cxml::add_child(root, "DefaultKDMDuration"));
816         /* [XML] MailServer Hostname of SMTP server to use. */
817         cxml::add_text_child(root, "MailServer", _mail_server);
818         /* [XML] MailPort Port number to use on SMTP server. */
819         cxml::add_text_child(root, "MailPort", raw_convert<string>(_mail_port));
820         /* [XML] MailProtocol Protocol to use on SMTP server (Auto, Plain, STARTTLS or SSL) */
821         switch (_mail_protocol) {
822         case EmailProtocol::AUTO:
823                 cxml::add_text_child(root, "MailProtocol", "Auto");
824                 break;
825         case EmailProtocol::PLAIN:
826                 cxml::add_text_child(root, "MailProtocol", "Plain");
827                 break;
828         case EmailProtocol::STARTTLS:
829                 cxml::add_text_child(root, "MailProtocol", "STARTTLS");
830                 break;
831         case EmailProtocol::SSL:
832                 cxml::add_text_child(root, "MailProtocol", "SSL");
833                 break;
834         }
835         /* [XML] MailUser Username to use on SMTP server. */
836         cxml::add_text_child(root, "MailUser", _mail_user);
837         /* [XML] MailPassword Password to use on SMTP server. */
838         cxml::add_text_child(root, "MailPassword", _mail_password);
839
840         /* [XML] KDMSubject Subject to use for KDM emails. */
841         cxml::add_text_child(root, "KDMSubject", _kdm_subject);
842         /* [XML] KDMFrom From address to use for KDM emails. */
843         cxml::add_text_child(root, "KDMFrom", _kdm_from);
844         for (auto i: _kdm_cc) {
845                 /* [XML] KDMCC CC address to use for KDM emails; you can use as many of these tags as you like. */
846                 cxml::add_text_child(root, "KDMCC", i);
847         }
848         /* [XML] KDMBCC BCC address to use for KDM emails. */
849         cxml::add_text_child(root, "KDMBCC", _kdm_bcc);
850         /* [XML] KDMEmail Text of KDM email. */
851         cxml::add_text_child(root, "KDMEmail", _kdm_email);
852
853         /* [XML] NotificationSubject Subject to use for notification emails. */
854         cxml::add_text_child(root, "NotificationSubject", _notification_subject);
855         /* [XML] NotificationFrom From address to use for notification emails. */
856         cxml::add_text_child(root, "NotificationFrom", _notification_from);
857         /* [XML] NotificationFrom To address to use for notification emails. */
858         cxml::add_text_child(root, "NotificationTo", _notification_to);
859         for (auto i: _notification_cc) {
860                 /* [XML] NotificationCC CC address to use for notification emails; you can use as many of these tags as you like. */
861                 cxml::add_text_child(root, "NotificationCC", i);
862         }
863         /* [XML] NotificationBCC BCC address to use for notification emails. */
864         cxml::add_text_child(root, "NotificationBCC", _notification_bcc);
865         /* [XML] NotificationEmail Text of notification email. */
866         cxml::add_text_child(root, "NotificationEmail", _notification_email);
867
868         /* [XML] CheckForUpdates 1 to check dcpomatic.com for new versions, 0 to check only on request. */
869         cxml::add_text_child(root, "CheckForUpdates", _check_for_updates ? "1" : "0");
870         /* [XML] CheckForUpdates 1 to check dcpomatic.com for new text versions, 0 to check only on request. */
871         cxml::add_text_child(root, "CheckForTestUpdates", _check_for_test_updates ? "1" : "0");
872
873         /* [XML] MaximumJ2KVideoBitRate Maximum video bit rate (in bits per second) that can be specified in the GUI for JPEG2000 encodes. */
874         cxml::add_text_child(root, "MaximumJ2KVideoBitRate", raw_convert<string>(_maximum_video_bit_rate[VideoEncoding::JPEG2000]));
875         /* [XML] MaximumMPEG2VideoBitRate Maximum video bit rate (in bits per second) that can be specified in the GUI for MPEG2 encodes. */
876         cxml::add_text_child(root, "MaximumMPEG2VideoBitRate", raw_convert<string>(_maximum_video_bit_rate[VideoEncoding::MPEG2]));
877         /* [XML] AllowAnyDCPFrameRate 1 to allow users to specify any frame rate when creating DCPs, 0 to limit the GUI to standard rates. */
878         cxml::add_text_child(root, "AllowAnyDCPFrameRate", _allow_any_dcp_frame_rate ? "1" : "0");
879         /* [XML] AllowAnyContainer 1 to allow users to user any container ratio for their DCP, 0 to limit the GUI to DCI Flat/Scope */
880         cxml::add_text_child(root, "AllowAnyContainer", _allow_any_container ? "1" : "0");
881         /* [XML] Allow96kHzAudio 1 to allow users to make DCPs with 96kHz audio, 0 to always make 48kHz DCPs */
882         cxml::add_text_child(root, "Allow96kHzAudio", _allow_96khz_audio ? "1" : "0");
883         /* [XML] UseAllAudioChannels 1 to allow users to map audio to all 16 DCP channels, 0 to limit to the channels used in standard DCPs */
884         cxml::add_text_child(root, "UseAllAudioChannels", _use_all_audio_channels ? "1" : "0");
885         /* [XML] ShowExperimentalAudioProcessors 1 to offer users the (experimental) audio upmixer processors, 0 to hide them */
886         cxml::add_text_child(root, "ShowExperimentalAudioProcessors", _show_experimental_audio_processors ? "1" : "0");
887         /* [XML] LogTypes Types of logging to write; a bitfield where 1 is general notes, 2 warnings, 4 errors, 8 debug information related
888            to 3D, 16 debug information related to encoding, 32 debug information for timing purposes, 64 debug information related
889            to sending email, 128 debug information related to the video view, 256 information about disk writing, 512 debug information
890            related to the player, 1024 debug information related to audio analyses.
891         */
892         cxml::add_text_child(root, "LogTypes", raw_convert<string> (_log_types));
893         /* [XML] AnalyseEBUR128 1 to do EBUR128 analyses when analysing audio, otherwise 0. */
894         cxml::add_text_child(root, "AnalyseEBUR128", _analyse_ebur128 ? "1" : "0");
895         /* [XML] AutomaticAudioAnalysis 1 to run audio analysis automatically when audio content is added to the film, otherwise 0. */
896         cxml::add_text_child(root, "AutomaticAudioAnalysis", _automatic_audio_analysis ? "1" : "0");
897 #ifdef DCPOMATIC_WINDOWS
898         if (_win32_console) {
899                 /* [XML] Win32Console 1 to open a console when running on Windows, otherwise 0.
900                  * We only write this if it's true, which is a bit of a hack to allow unit tests to work
901                  * more easily on Windows (without a platform-specific reference in config_write_utf8_test)
902                  */
903                 cxml::add_text_child(root, "Win32Console", "1");
904         }
905 #endif
906
907         /* [XML] Signer Certificate chain and private key to use when signing DCPs and KDMs.  Should contain <code>&lt;Certificate&gt;</code>
908            tags in order and a <code>&lt;PrivateKey&gt;</code> tag all containing PEM-encoded certificates or private keys as appropriate.
909         */
910         auto signer = cxml::add_child(root, "Signer");
911         DCPOMATIC_ASSERT (_signer_chain);
912         for (auto const& i: _signer_chain->unordered()) {
913                 cxml::add_text_child(signer, "Certificate", i.certificate (true));
914         }
915         cxml::add_text_child(signer, "PrivateKey", _signer_chain->key().get ());
916
917         /* [XML] Decryption Certificate chain and private key to use when decrypting KDMs */
918         auto decryption = cxml::add_child(root, "Decryption");
919         DCPOMATIC_ASSERT (_decryption_chain);
920         for (auto const& i: _decryption_chain->unordered()) {
921                 cxml::add_text_child(decryption, "Certificate", i.certificate (true));
922         }
923         cxml::add_text_child(decryption, "PrivateKey", _decryption_chain->key().get());
924
925         /* [XML] History Filename of DCP to present in the <guilabel>File</guilabel> menu of the GUI; there can be more than one
926            of these tags.
927         */
928         for (auto i: _history) {
929                 cxml::add_text_child(root, "History", i.string());
930         }
931
932         /* [XML] History Filename of DCP to present in the <guilabel>File</guilabel> menu of the player; there can be more than one
933            of these tags.
934         */
935         for (auto i: _player_history) {
936                 cxml::add_text_child(root, "PlayerHistory", i.string());
937         }
938
939         /* [XML] DKDMGroup A group of DKDMs, each with a <code>Name</code> attribute, containing other <code>&lt;DKDMGroup&gt;</code>
940            or <code>&lt;DKDM&gt;</code> tags.
941         */
942         /* [XML] DKDM A DKDM as XML */
943         _dkdms->as_xml (root);
944
945         /* [XML] CinemasFile Filename of cinemas list file. */
946         cxml::add_text_child(root, "CinemasFile", _cinemas_file.string());
947         /* [XML] DKDMRecipientsFile Filename of DKDM recipients list file. */
948         cxml::add_text_child(root, "DKDMRecipientsFile", _dkdm_recipients_file.string());
949         /* [XML] ShowHintsBeforeMakeDCP 1 to show hints in the GUI before making a DCP, otherwise 0. */
950         cxml::add_text_child(root, "ShowHintsBeforeMakeDCP", _show_hints_before_make_dcp ? "1" : "0");
951         /* [XML] ConfirmKDMEmail 1 to confirm before sending KDM emails in the GUI, otherwise 0. */
952         cxml::add_text_child(root, "ConfirmKDMEmail", _confirm_kdm_email ? "1" : "0");
953         /* [XML] KDMFilenameFormat Format for KDM filenames. */
954         cxml::add_text_child(root, "KDMFilenameFormat", _kdm_filename_format.specification());
955         /* [XML] KDMFilenameFormat Format for DKDM filenames. */
956         cxml::add_text_child(root, "DKDMFilenameFormat", _dkdm_filename_format.specification());
957         /* [XML] KDMContainerNameFormat Format for KDM containers (directories or ZIP files). */
958         cxml::add_text_child(root, "KDMContainerNameFormat", _kdm_container_name_format.specification());
959         /* [XML] DCPMetadataFilenameFormat Format for DCP metadata filenames. */
960         cxml::add_text_child(root, "DCPMetadataFilenameFormat", _dcp_metadata_filename_format.specification());
961         /* [XML] DCPAssetFilenameFormat Format for DCP asset filenames. */
962         cxml::add_text_child(root, "DCPAssetFilenameFormat", _dcp_asset_filename_format.specification());
963         /* [XML] JumpToSelected 1 to make the GUI jump to the start of content when it is selected, otherwise 0. */
964         cxml::add_text_child(root, "JumpToSelected", _jump_to_selected ? "1" : "0");
965         /* [XML] Nagged 1 if a particular nag screen has been shown and should not be shown again, otherwise 0. */
966         for (int i = 0; i < NAG_COUNT; ++i) {
967                 auto e = cxml::add_child(root, "Nagged");
968                 e->set_attribute("id", raw_convert<string>(i));
969                 e->add_child_text (_nagged[i] ? "1" : "0");
970         }
971         /* [XML] PreviewSound 1 to use sound in the GUI preview and player, otherwise 0. */
972         cxml::add_text_child(root, "PreviewSound", _sound ? "1" : "0");
973         if (_sound_output) {
974                 /* [XML:opt] PreviewSoundOutput Name of the audio output to use. */
975                 cxml::add_text_child(root, "PreviewSoundOutput", _sound_output.get());
976         }
977         /* [XML] CoverSheet Text of the cover sheet to write when making DCPs. */
978         cxml::add_text_child(root, "CoverSheet", _cover_sheet);
979         if (_last_player_load_directory) {
980                 cxml::add_text_child(root, "LastPlayerLoadDirectory", _last_player_load_directory->string());
981         }
982         /* [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. */
983         if (_last_kdm_write_type) {
984                 switch (_last_kdm_write_type.get()) {
985                 case KDM_WRITE_FLAT:
986                         cxml::add_text_child(root, "LastKDMWriteType", "flat");
987                         break;
988                 case KDM_WRITE_FOLDER:
989                         cxml::add_text_child(root, "LastKDMWriteType", "folder");
990                         break;
991                 case KDM_WRITE_ZIP:
992                         cxml::add_text_child(root, "LastKDMWriteType", "zip");
993                         break;
994                 }
995         }
996         /* [XML] LastDKDMWriteType Last type of DKDM-write: <code>file</code> for a file, <code>internal</code> to add to DCP-o-matic's list. */
997         if (_last_dkdm_write_type) {
998                 switch (_last_dkdm_write_type.get()) {
999                 case DKDM_WRITE_INTERNAL:
1000                         cxml::add_text_child(root, "LastDKDMWriteType", "internal");
1001                         break;
1002                 case DKDM_WRITE_FILE:
1003                         cxml::add_text_child(root, "LastDKDMWriteType", "file");
1004                         break;
1005                 }
1006         }
1007         /* [XML] FramesInMemoryMultiplier value to multiply the encoding threads count by to get the maximum number of
1008            frames to be held in memory at once.
1009         */
1010         cxml::add_text_child(root, "FramesInMemoryMultiplier", raw_convert<string>(_frames_in_memory_multiplier));
1011
1012         /* [XML] DecodeReduction power of 2 to reduce DCP images by before decoding in the player. */
1013         if (_decode_reduction) {
1014                 cxml::add_text_child(root, "DecodeReduction", raw_convert<string>(_decode_reduction.get()));
1015         }
1016
1017         /* [XML] DefaultNotify 1 to default jobs to notify when complete, otherwise 0. */
1018         cxml::add_text_child(root, "DefaultNotify", _default_notify ? "1" : "0");
1019
1020         /* [XML] Notification 1 if a notification type is enabled, otherwise 0. */
1021         for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
1022                 auto e = cxml::add_child(root, "Notification");
1023                 e->set_attribute ("id", raw_convert<string>(i));
1024                 e->add_child_text (_notification[i] ? "1" : "0");
1025         }
1026
1027         if (_barco_username) {
1028                 /* [XML] BarcoUsername Username for logging into Barco's servers when downloading server certificates. */
1029                 cxml::add_text_child(root, "BarcoUsername", *_barco_username);
1030         }
1031         if (_barco_password) {
1032                 /* [XML] BarcoPassword Password for logging into Barco's servers when downloading server certificates. */
1033                 cxml::add_text_child(root, "BarcoPassword", *_barco_password);
1034         }
1035
1036         if (_christie_username) {
1037                 /* [XML] ChristieUsername Username for logging into Christie's servers when downloading server certificates. */
1038                 cxml::add_text_child(root, "ChristieUsername", *_christie_username);
1039         }
1040         if (_christie_password) {
1041                 /* [XML] ChristiePassword Password for logging into Christie's servers when downloading server certificates. */
1042                 cxml::add_text_child(root, "ChristiePassword", *_christie_password);
1043         }
1044
1045         if (_gdc_username) {
1046                 /* [XML] GDCUsername Username for logging into GDC's servers when downloading server certificates. */
1047                 cxml::add_text_child(root, "GDCUsername", *_gdc_username);
1048         }
1049         if (_gdc_password) {
1050                 /* [XML] GDCPassword Password for logging into GDC's servers when downloading server certificates. */
1051                 cxml::add_text_child(root, "GDCPassword", *_gdc_password);
1052         }
1053
1054         /* [XML] PlayerMode <code>window</code> for a single window, <code>full</code> for full-screen and <code>dual</code> for full screen playback
1055            with separate (advanced) controls.
1056         */
1057         switch (_player_mode) {
1058         case PLAYER_MODE_WINDOW:
1059                 cxml::add_text_child(root, "PlayerMode", "window");
1060                 break;
1061         case PLAYER_MODE_FULL:
1062                 cxml::add_text_child(root, "PlayerMode", "full");
1063                 break;
1064         case PLAYER_MODE_DUAL:
1065                 cxml::add_text_child(root, "PlayerMode", "dual");
1066                 break;
1067         }
1068
1069         if (_player_restricted_menus) {
1070                 cxml::add_text_child(root, "PlayerRestrictedMenus", "1");
1071         }
1072
1073         if (_playlist_editor_restricted_menus) {
1074                 cxml::add_text_child(root, "PlaylistEditorRestrictedMenus", "1");
1075         }
1076
1077         /* [XML] ImageDisplay Screen number to put image on in dual-screen player mode. */
1078         cxml::add_text_child(root, "ImageDisplay", raw_convert<string>(_image_display));
1079         switch (_video_view_type) {
1080         case VIDEO_VIEW_SIMPLE:
1081                 cxml::add_text_child(root, "VideoViewType", "simple");
1082                 break;
1083         case VIDEO_VIEW_OPENGL:
1084                 cxml::add_text_child(root, "VideoViewType", "opengl");
1085                 break;
1086         }
1087         /* [XML] RespectKDMValidityPeriods 1 to refuse to use KDMs that are out of date, 0 to ignore KDM dates. */
1088         cxml::add_text_child(root, "RespectKDMValidityPeriods", _respect_kdm_validity_periods ? "1" : "0");
1089         if (_player_debug_log_file) {
1090                 /* [XML] PlayerLogFile Filename to use for player debug logs. */
1091                 cxml::add_text_child(root, "PlayerDebugLogFile", _player_debug_log_file->string());
1092         }
1093         if (_player_content_directory) {
1094                 /* [XML] PlayerContentDirectory Directory to use for player content in the dual-screen mode. */
1095                 cxml::add_text_child(root, "PlayerContentDirectory", _player_content_directory->string());
1096         }
1097         if (_player_playlist_directory) {
1098                 /* [XML] PlayerPlaylistDirectory Directory to use for player playlists in the dual-screen mode. */
1099                 cxml::add_text_child(root, "PlayerPlaylistDirectory", _player_playlist_directory->string());
1100         }
1101         if (_player_kdm_directory) {
1102                 /* [XML] PlayerKDMDirectory Directory to use for player KDMs in the dual-screen mode. */
1103                 cxml::add_text_child(root, "PlayerKDMDirectory", _player_kdm_directory->string());
1104         }
1105         if (_audio_mapping) {
1106                 _audio_mapping->as_xml(cxml::add_child(root, "AudioMapping"));
1107         }
1108         for (auto const& i: _custom_languages) {
1109                 cxml::add_text_child(root, "CustomLanguage", i.to_string());
1110         }
1111         for (auto const& initial: _initial_paths) {
1112                 if (initial.second) {
1113                         cxml::add_text_child(root, initial.first, initial.second->string());
1114                 }
1115         }
1116         cxml::add_text_child(root, "UseISDCFNameByDefault", _use_isdcf_name_by_default ? "1" : "0");
1117         cxml::add_text_child(root, "WriteKDMsToDisk", _write_kdms_to_disk ? "1" : "0");
1118         cxml::add_text_child(root, "EmailKDMs", _email_kdms ? "1" : "0");
1119         cxml::add_text_child(root, "DefaultKDMType", dcp::formulation_to_string(_default_kdm_type));
1120         cxml::add_text_child(root, "AutoCropThreshold", raw_convert<string>(_auto_crop_threshold));
1121         if (_last_release_notes_version) {
1122                 cxml::add_text_child(root, "LastReleaseNotesVersion", *_last_release_notes_version);
1123         }
1124         if (_main_divider_sash_position) {
1125                 cxml::add_text_child(root, "MainDividerSashPosition", raw_convert<string>(*_main_divider_sash_position));
1126         }
1127         if (_main_content_divider_sash_position) {
1128                 cxml::add_text_child(root, "MainContentDividerSashPosition", raw_convert<string>(*_main_content_divider_sash_position));
1129         }
1130
1131         cxml::add_text_child(root, "DefaultAddFileLocation",
1132                 _default_add_file_location == DefaultAddFileLocation::SAME_AS_LAST_TIME ? "last" : "project"
1133                 );
1134
1135         /* [XML] AllowSMPTEBv20 1 to allow the user to choose SMPTE (Bv2.0 only) as a standard, otherwise 0 */
1136         cxml::add_text_child(root, "AllowSMPTEBv20", _allow_smpte_bv20 ? "1" : "0");
1137         /* [XML] ISDCFNamePartLength Maximum length of the "name" part of an ISDCF name, which should be 14 according to the standard */
1138         cxml::add_text_child(root, "ISDCFNamePartLength", raw_convert<string>(_isdcf_name_part_length));
1139
1140 #ifdef DCPOMATIC_GROK
1141         if (_grok) {
1142                 _grok->as_xml(cxml::add_child(root, "Grok"));
1143         }
1144 #endif
1145
1146         _export.write(cxml::add_child(root, "Export"));
1147
1148         auto target = config_write_file();
1149
1150         try {
1151                 auto const s = doc.write_to_string_formatted ();
1152                 boost::filesystem::path tmp (string(target.string()).append(".tmp"));
1153                 dcp::File f(tmp, "w");
1154                 if (!f) {
1155                         throw FileError (_("Could not open file for writing"), tmp);
1156                 }
1157                 f.checked_write(s.c_str(), s.bytes());
1158                 f.close();
1159                 dcp::filesystem::remove(target);
1160                 dcp::filesystem::rename(tmp, target);
1161         } catch (xmlpp::exception& e) {
1162                 string s = e.what ();
1163                 trim (s);
1164                 throw FileError (s, target);
1165         }
1166 }
1167
1168
1169 template <class T>
1170 void
1171 write_file (string root_node, string node, string version, list<shared_ptr<T>> things, boost::filesystem::path file)
1172 {
1173         xmlpp::Document doc;
1174         auto root = doc.create_root_node (root_node);
1175         cxml::add_text_child(root, "Version", version);
1176
1177         for (auto i: things) {
1178                 i->as_xml(cxml::add_child(root, node));
1179         }
1180
1181         try {
1182                 doc.write_to_file_formatted (file.string() + ".tmp");
1183                 dcp::filesystem::remove(file);
1184                 dcp::filesystem::rename(file.string() + ".tmp", file);
1185         } catch (xmlpp::exception& e) {
1186                 string s = e.what ();
1187                 trim (s);
1188                 throw FileError (s, file);
1189         }
1190 }
1191
1192
1193 boost::filesystem::path
1194 Config::default_directory_or (boost::filesystem::path a) const
1195 {
1196         return directory_or (_default_directory, a);
1197 }
1198
1199 boost::filesystem::path
1200 Config::default_kdm_directory_or (boost::filesystem::path a) const
1201 {
1202         return directory_or (_default_kdm_directory, a);
1203 }
1204
1205 boost::filesystem::path
1206 Config::directory_or (optional<boost::filesystem::path> dir, boost::filesystem::path a) const
1207 {
1208         if (!dir) {
1209                 return a;
1210         }
1211
1212         boost::system::error_code ec;
1213         auto const e = dcp::filesystem::exists(*dir, ec);
1214         if (ec || !e) {
1215                 return a;
1216         }
1217
1218         return *dir;
1219 }
1220
1221 void
1222 Config::drop ()
1223 {
1224         delete _instance;
1225         _instance = nullptr;
1226 }
1227
1228 void
1229 Config::changed (Property what)
1230 {
1231         Changed (what);
1232 }
1233
1234 void
1235 Config::set_kdm_email_to_default ()
1236 {
1237         _kdm_subject = _("KDM delivery: $CPL_NAME");
1238
1239         _kdm_email = variant::insert_dcpomatic(_(
1240                 "Dear Projectionist\n\n"
1241                 "Please find attached KDMs for $CPL_NAME.\n\n"
1242                 "Cinema: $CINEMA_NAME\n"
1243                 "Screen(s): $SCREENS\n\n"
1244                 "The KDMs are valid from $START_TIME until $END_TIME.\n\n"
1245                 "Best regards,\n%1"
1246                 ));
1247 }
1248
1249 void
1250 Config::set_notification_email_to_default ()
1251 {
1252         _notification_subject = variant::insert_dcpomatic(_("%1 notification"));
1253
1254         _notification_email = _(
1255                 "$JOB_NAME: $JOB_STATUS"
1256                 );
1257 }
1258
1259 void
1260 Config::reset_kdm_email ()
1261 {
1262         set_kdm_email_to_default ();
1263         changed ();
1264 }
1265
1266 void
1267 Config::reset_notification_email ()
1268 {
1269         set_notification_email_to_default ();
1270         changed ();
1271 }
1272
1273 void
1274 Config::set_cover_sheet_to_default ()
1275 {
1276         _cover_sheet = _(
1277                 "$CPL_NAME\n\n"
1278                 "CPL Filename: $CPL_FILENAME\n"
1279                 "Type: $TYPE\n"
1280                 "Format: $CONTAINER\n"
1281                 "Audio: $AUDIO\n"
1282                 "Audio Language: $AUDIO_LANGUAGE\n"
1283                 "Subtitle Language: $SUBTITLE_LANGUAGE\n"
1284                 "Length: $LENGTH\n"
1285                 "Size: $SIZE\n"
1286                 );
1287 }
1288
1289 void
1290 Config::add_to_history (boost::filesystem::path p)
1291 {
1292         add_to_history_internal (_history, p);
1293 }
1294
1295 /** Remove non-existent items from the history */
1296 void
1297 Config::clean_history ()
1298 {
1299         clean_history_internal (_history);
1300 }
1301
1302 void
1303 Config::add_to_player_history (boost::filesystem::path p)
1304 {
1305         add_to_history_internal (_player_history, p);
1306 }
1307
1308 /** Remove non-existent items from the player history */
1309 void
1310 Config::clean_player_history ()
1311 {
1312         clean_history_internal (_player_history);
1313 }
1314
1315 void
1316 Config::add_to_history_internal (vector<boost::filesystem::path>& h, boost::filesystem::path p)
1317 {
1318         /* Remove existing instances of this path in the history */
1319         h.erase (remove (h.begin(), h.end(), p), h.end ());
1320
1321         h.insert (h.begin (), p);
1322         if (h.size() > HISTORY_SIZE) {
1323                 h.resize(HISTORY_SIZE);
1324         }
1325
1326         changed (HISTORY);
1327 }
1328
1329 void
1330 Config::clean_history_internal (vector<boost::filesystem::path>& h)
1331 {
1332         auto old = h;
1333         h.clear ();
1334         for (auto i: old) {
1335                 try {
1336                         if (dcp::filesystem::is_directory(i)) {
1337                                 h.push_back (i);
1338                         }
1339                 } catch (...) {
1340                         /* We couldn't find out if it's a directory for some reason; just ignore it */
1341                 }
1342         }
1343 }
1344
1345
1346 bool
1347 Config::have_existing (string file)
1348 {
1349         return dcp::filesystem::exists(read_path(file));
1350 }
1351
1352
1353 void
1354 Config::set_cinemas_file (boost::filesystem::path file)
1355 {
1356         if (file == _cinemas_file) {
1357                 return;
1358         }
1359
1360         _cinemas_file = file;
1361
1362         changed (OTHER);
1363 }
1364
1365
1366 void
1367 Config::set_dkdm_recipients_file(boost::filesystem::path file)
1368 {
1369         if (file == _dkdm_recipients_file) {
1370                 return;
1371         }
1372
1373         _dkdm_recipients_file = file;
1374
1375         changed(OTHER);
1376 }
1377
1378
1379 void
1380 Config::save_default_template(shared_ptr<const Film> film) const
1381 {
1382         film->write_template(write_path("default.xml"));
1383 }
1384
1385
1386 void
1387 Config::save_template (shared_ptr<const Film> film, string name) const
1388 {
1389         film->write_template (template_write_path(name));
1390 }
1391
1392
1393 vector<string>
1394 Config::templates () const
1395 {
1396         if (!dcp::filesystem::exists(read_path("templates"))) {
1397                 return {};
1398         }
1399
1400         vector<string> n;
1401         for (auto const& i: dcp::filesystem::directory_iterator(read_path("templates"))) {
1402                 n.push_back (i.path().filename().string());
1403         }
1404         return n;
1405 }
1406
1407 bool
1408 Config::existing_template (string name) const
1409 {
1410         return dcp::filesystem::exists(template_read_path(name));
1411 }
1412
1413
1414 boost::filesystem::path
1415 Config::template_read_path (string name) const
1416 {
1417         return read_path("templates") / tidy_for_filename (name);
1418 }
1419
1420
1421 boost::filesystem::path
1422 Config::default_template_read_path() const
1423 {
1424         if (!boost::filesystem::exists(read_path("default.xml"))) {
1425                 auto film = std::make_shared<const Film>(optional<boost::filesystem::path>());
1426                 save_default_template(film);
1427         }
1428
1429         return read_path("default.xml");
1430 }
1431
1432
1433 boost::filesystem::path
1434 Config::template_write_path (string name) const
1435 {
1436         return write_path("templates") / tidy_for_filename (name);
1437 }
1438
1439
1440 void
1441 Config::rename_template (string old_name, string new_name) const
1442 {
1443         dcp::filesystem::rename(template_read_path(old_name), template_write_path(new_name));
1444 }
1445
1446 void
1447 Config::delete_template (string name) const
1448 {
1449         dcp::filesystem::remove(template_write_path(name));
1450 }
1451
1452 /** @return Path to the config.xml containing the actual settings, following a link if required */
1453 boost::filesystem::path
1454 config_file (boost::filesystem::path main)
1455 {
1456         cxml::Document f ("Config");
1457         if (!dcp::filesystem::exists(main)) {
1458                 /* It doesn't exist, so there can't be any links; just return it */
1459                 return main;
1460         }
1461
1462         /* See if there's a link */
1463         try {
1464                 f.read_file(dcp::filesystem::fix_long_path(main));
1465                 auto link = f.optional_string_child("Link");
1466                 if (link) {
1467                         return *link;
1468                 }
1469         } catch (xmlpp::exception& e) {
1470                 /* There as a problem reading the main configuration file,
1471                    so there can't be a link.
1472                 */
1473         }
1474
1475         return main;
1476 }
1477
1478
1479 boost::filesystem::path
1480 Config::config_read_file ()
1481 {
1482         return config_file (read_path("config.xml"));
1483 }
1484
1485
1486 boost::filesystem::path
1487 Config::config_write_file ()
1488 {
1489         return config_file (write_path("config.xml"));
1490 }
1491
1492
1493 void
1494 Config::reset_cover_sheet ()
1495 {
1496         set_cover_sheet_to_default ();
1497         changed ();
1498 }
1499
1500 void
1501 Config::link (boost::filesystem::path new_file) const
1502 {
1503         xmlpp::Document doc;
1504         cxml::add_text_child(doc.create_root_node("Config"), "Link", new_file.string());
1505         try {
1506                 doc.write_to_file_formatted(write_path("config.xml").string());
1507         } catch (xmlpp::exception& e) {
1508                 string s = e.what ();
1509                 trim (s);
1510                 throw FileError (s, write_path("config.xml"));
1511         }
1512 }
1513
1514 void
1515 Config::copy_and_link (boost::filesystem::path new_file) const
1516 {
1517         write ();
1518         dcp::filesystem::copy_file(config_read_file(), new_file, boost::filesystem::copy_option::overwrite_if_exists);
1519         link (new_file);
1520 }
1521
1522 bool
1523 Config::have_write_permission () const
1524 {
1525         dcp::File f(config_write_file(), "r+");
1526         return static_cast<bool>(f);
1527 }
1528
1529 /** @param  output_channels Number of output channels in use.
1530  *  @return Audio mapping for this output channel count (may be a default).
1531  */
1532 AudioMapping
1533 Config::audio_mapping (int output_channels)
1534 {
1535         if (!_audio_mapping || _audio_mapping->output_channels() != output_channels) {
1536                 /* Set up a default */
1537                 _audio_mapping = AudioMapping (MAX_DCP_AUDIO_CHANNELS, output_channels);
1538                 if (output_channels == 2) {
1539                         /* Special case for stereo output.
1540                            Map so that Lt = L(-3dB) + Ls(-3dB) + C(-6dB) + Lfe(-10dB)
1541                            Rt = R(-3dB) + Rs(-3dB) + C(-6dB) + Lfe(-10dB)
1542                         */
1543                         _audio_mapping->set (dcp::Channel::LEFT,   0, 1 / sqrt(2));  // L   -> Lt
1544                         _audio_mapping->set (dcp::Channel::RIGHT,  1, 1 / sqrt(2));  // R   -> Rt
1545                         _audio_mapping->set (dcp::Channel::CENTRE, 0, 1 / 2.0);      // C   -> Lt
1546                         _audio_mapping->set (dcp::Channel::CENTRE, 1, 1 / 2.0);      // C   -> Rt
1547                         _audio_mapping->set (dcp::Channel::LFE,    0, 1 / sqrt(10)); // Lfe -> Lt
1548                         _audio_mapping->set (dcp::Channel::LFE,    1, 1 / sqrt(10)); // Lfe -> Rt
1549                         _audio_mapping->set (dcp::Channel::LS,     0, 1 / sqrt(2));  // Ls  -> Lt
1550                         _audio_mapping->set (dcp::Channel::RS,     1, 1 / sqrt(2));  // Rs  -> Rt
1551                 } else {
1552                         /* 1:1 mapping */
1553                         for (int i = 0; i < min (MAX_DCP_AUDIO_CHANNELS, output_channels); ++i) {
1554                                 _audio_mapping->set (i, i, 1);
1555                         }
1556                 }
1557         }
1558
1559         return *_audio_mapping;
1560 }
1561
1562 void
1563 Config::set_audio_mapping (AudioMapping m)
1564 {
1565         _audio_mapping = m;
1566         changed (AUDIO_MAPPING);
1567 }
1568
1569 void
1570 Config::set_audio_mapping_to_default ()
1571 {
1572         DCPOMATIC_ASSERT (_audio_mapping);
1573         auto const ch = _audio_mapping->output_channels ();
1574         _audio_mapping = boost::none;
1575         _audio_mapping = audio_mapping (ch);
1576         changed (AUDIO_MAPPING);
1577 }
1578
1579
1580 void
1581 Config::add_custom_language (dcp::LanguageTag tag)
1582 {
1583         if (find(_custom_languages.begin(), _custom_languages.end(), tag) == _custom_languages.end()) {
1584                 _custom_languages.push_back (tag);
1585                 changed ();
1586         }
1587 }
1588
1589
1590 optional<Config::BadReason>
1591 Config::check_certificates () const
1592 {
1593         optional<BadReason> bad;
1594
1595         for (auto const& i: _signer_chain->unordered()) {
1596                 if (i.has_utf8_strings()) {
1597                         bad = BAD_SIGNER_UTF8_STRINGS;
1598                 }
1599                 if ((i.not_after().year() - i.not_before().year()) > 15) {
1600                         bad = BAD_SIGNER_VALIDITY_TOO_LONG;
1601                 }
1602                 if (dcp::escape_digest(i.subject_dn_qualifier()) != dcp::public_key_digest(i.public_key())) {
1603                         bad = BAD_SIGNER_DN_QUALIFIER;
1604                 }
1605         }
1606
1607         if (!_signer_chain->chain_valid() || !_signer_chain->private_key_valid()) {
1608                 bad = BAD_SIGNER_INCONSISTENT;
1609         }
1610
1611         if (!_decryption_chain->chain_valid() || !_decryption_chain->private_key_valid()) {
1612                 bad = BAD_DECRYPTION_INCONSISTENT;
1613         }
1614
1615         return bad;
1616 }
1617
1618
1619 void
1620 save_all_config_as_zip (boost::filesystem::path zip_file)
1621 {
1622         Zipper zipper (zip_file);
1623
1624         auto config = Config::instance();
1625         zipper.add ("config.xml", dcp::file_to_string(config->config_read_file()));
1626         if (dcp::filesystem::exists(config->cinemas_file())) {
1627                 zipper.add("cinemas.sqlite3", dcp::file_to_string(config->cinemas_file()));
1628         }
1629         if (dcp::filesystem::exists(config->dkdm_recipients_file())) {
1630                 zipper.add("dkdm_recipients.sqlite3", dcp::file_to_string(config->dkdm_recipients_file()));
1631         }
1632
1633         zipper.close ();
1634 }
1635
1636
1637 void
1638 Config::load_from_zip(boost::filesystem::path zip_file, CinemasAction action)
1639 {
1640         backup();
1641
1642         auto const current_cinemas = cinemas_file();
1643         /* This is (unfortunately) a full path, and the user can't change it, so
1644          * we always want to use that same path in the future no matter what is in the
1645          * config.xml that we are about to load.
1646          */
1647         auto const current_dkdm_recipients = dkdm_recipients_file();
1648
1649         Unzipper unzipper(zip_file);
1650         dcp::write_string_to_file(unzipper.get("config.xml"), config_write_file());
1651
1652         if (action == CinemasAction::WRITE_TO_PATH_IN_ZIPPED_CONFIG) {
1653                 /* Read the zipped config, so that the cinemas file path is the new one and
1654                  * we write the cinemas to it.
1655                  */
1656                 read();
1657                 boost::filesystem::create_directories(cinemas_file().parent_path());
1658                 set_dkdm_recipients_file(current_dkdm_recipients);
1659         }
1660
1661         if (unzipper.contains("cinemas.xml") && action != CinemasAction::IGNORE) {
1662                 CinemaList cinemas;
1663                 cinemas.clear();
1664                 cinemas.read_legacy_string(unzipper.get("cinemas.xml"));
1665         }
1666
1667         if (unzipper.contains("dkdm_recipients.xml")) {
1668                 DKDMRecipientList recipients;
1669                 recipients.clear();
1670                 recipients.read_legacy_string(unzipper.get("dkdm_recipients.xml"));
1671         }
1672
1673         if (unzipper.contains("cinemas.sqlite3") && action != CinemasAction::IGNORE) {
1674                 dcp::write_string_to_file(unzipper.get("cinemas.sqlite3"), cinemas_file());
1675         }
1676
1677         if (unzipper.contains("dkdm_recipients.sqlite3")) {
1678                 dcp::write_string_to_file(unzipper.get("dkdm_recipients.sqlite3"), dkdm_recipients_file());
1679         }
1680
1681         if (action != CinemasAction::WRITE_TO_PATH_IN_ZIPPED_CONFIG) {
1682                 /* Read the zipped config, then reset the cinemas file to be the old one */
1683                 read();
1684                 set_cinemas_file(current_cinemas);
1685                 set_dkdm_recipients_file(current_dkdm_recipients);
1686         }
1687
1688         changed(Property::USE_ANY_SERVERS);
1689         changed(Property::SERVERS);
1690         changed(Property::SOUND);
1691         changed(Property::SOUND_OUTPUT);
1692         changed(Property::PLAYER_CONTENT_DIRECTORY);
1693         changed(Property::PLAYER_PLAYLIST_DIRECTORY);
1694         changed(Property::PLAYER_DEBUG_LOG);
1695         changed(Property::HISTORY);
1696         changed(Property::SHOW_EXPERIMENTAL_AUDIO_PROCESSORS);
1697         changed(Property::AUDIO_MAPPING);
1698         changed(Property::AUTO_CROP_THRESHOLD);
1699         changed(Property::ALLOW_SMPTE_BV20);
1700         changed(Property::ISDCF_NAME_PART_LENGTH);
1701         changed(Property::OTHER);
1702 }
1703
1704
1705 void
1706 Config::set_initial_path(string id, boost::filesystem::path path)
1707 {
1708         auto iter = _initial_paths.find(id);
1709         DCPOMATIC_ASSERT(iter != _initial_paths.end());
1710         iter->second = path;
1711         changed();
1712 }
1713
1714
1715 optional<boost::filesystem::path>
1716 Config::initial_path(string id) const
1717 {
1718         auto iter = _initial_paths.find(id);
1719         if (iter == _initial_paths.end()) {
1720                 return {};
1721         }
1722         return iter->second;
1723 }
1724
1725
1726 bool
1727 Config::zip_contains_cinemas(boost::filesystem::path zip)
1728 {
1729         Unzipper unzipper(zip);
1730         return unzipper.contains("cinemas.sqlite3") || unzipper.contains("cinemas.xml");
1731 }
1732
1733
1734 boost::filesystem::path
1735 Config::cinemas_file_from_zip(boost::filesystem::path zip)
1736 {
1737         Unzipper unzipper(zip);
1738         DCPOMATIC_ASSERT(unzipper.contains("config.xml"));
1739         cxml::Document document("Config");
1740         document.read_string(unzipper.get("config.xml"));
1741         return document.string_child("CinemasFile");
1742 }
1743
1744
1745 #ifdef DCPOMATIC_GROK
1746
1747 Config::Grok::Grok(cxml::ConstNodePtr node)
1748         : enable(node->bool_child("Enable"))
1749         , binary_location(node->string_child("BinaryLocation"))
1750         , selected(node->number_child<int>("Selected"))
1751         , licence_server(node->string_child("LicenceServer"))
1752         , licence_port(node->number_child<int>("LicencePort"))
1753         , licence(node->string_child("Licence"))
1754 {
1755
1756 }
1757
1758
1759 void
1760 Config::Grok::as_xml(xmlpp::Element* node) const
1761 {
1762         node->add_child("BinaryLocation")->add_child_text(binary_location.string());
1763         node->add_child("Enable")->add_child_text((enable ? "1" : "0"));
1764         node->add_child("Selected")->add_child_text(raw_convert<string>(selected));
1765         node->add_child("LicenceServer")->add_child_text(licence_server);
1766         node->add_child("LicencePort")->add_child_text(raw_convert<string>(licence_port));
1767         node->add_child("Licence")->add_child_text(licence);
1768 }
1769
1770
1771 void
1772 Config::set_grok(Grok const& grok)
1773 {
1774         _grok = grok;
1775         changed(GROK);
1776 }
1777
1778 #endif