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