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