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