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