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