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