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