Allow + in DCP names for ISDCF RU rating strings.
[dcpomatic.git] / src / lib / config.cc
index 503ca9c5f30f14e26ad209a62151b2ff81362202..2ae7939a9e7bcf7ad725c2ec6176d6f29ffce4cc 100644 (file)
@@ -64,8 +64,10 @@ using boost::algorithm::trim;
 using dcp::raw_convert;
 
 Config* Config::_instance = 0;
+int const Config::_current_version = 3;
 boost::signals2::signal<void ()> Config::FailedToLoad;
 boost::signals2::signal<void (string)> Config::Warning;
+boost::signals2::signal<bool (void)> Config::BadSignerChain;
 boost::optional<boost::filesystem::path> Config::test_path;
 
 /** Construct default configuration */
@@ -180,6 +182,21 @@ Config::create_certificate_chain ()
                );
 }
 
+void
+Config::backup ()
+{
+       /* Make a copy of the configuration */
+       try {
+               int n = 1;
+               while (n < 100 && boost::filesystem::exists(path(String::compose("config.xml.%1", n)))) {
+                       ++n;
+               }
+
+               boost::filesystem::copy_file(path("config.xml", false), path(String::compose("config.xml.%1", n), false));
+               boost::filesystem::copy_file(path("cinemas.xml", false), path(String::compose("cinemas.xml.%1", n), false));
+       } catch (...) {}
+}
+
 void
 Config::read ()
 try
@@ -188,6 +205,10 @@ try
        f.read_file (config_file ());
 
        optional<int> version = f.optional_number_child<int> ("Version");
+       if (version && *version < _current_version) {
+               /* Back up the old config before we re-write it in a back-incompatible way */
+               backup ();
+       }
 
        if (f.optional_number_child<int>("NumLocalEncodingThreads")) {
                _master_encoding_threads = _server_encoding_threads = f.optional_number_child<int>("NumLocalEncodingThreads").get();
@@ -329,6 +350,30 @@ try
                _signer_chain = create_certificate_chain ();
        }
 
+       /* These must be done before we call BadSignerChain as that might set one
+          of the nags.
+       */
+       BOOST_FOREACH (cxml::NodePtr i, f.node_children("Nagged")) {
+               int const id = i->number_attribute<int>("Id");
+               if (id >= 0 && id < NAG_COUNT) {
+                       _nagged[id] = raw_convert<int>(i->content());
+               }
+       }
+
+       bool bad_signer_chain = false;
+       BOOST_FOREACH (dcp::Certificate const & i, _signer_chain->unordered()) {
+               if (i.has_utf8_strings()) {
+                       bad_signer_chain = true;
+               }
+       }
+
+       if (bad_signer_chain) {
+               optional<bool> const remake = BadSignerChain();
+               if (remake && *remake) {
+                       _signer_chain = create_certificate_chain ();
+               }
+       }
+
        cxml::NodePtr decryption = f.optional_node_child ("Decryption");
        if (decryption) {
                shared_ptr<dcp::CertificateChain> c (new dcp::CertificateChain ());
@@ -359,12 +404,6 @@ try
        _dcp_metadata_filename_format = dcp::NameFormat (f.optional_string_child("DCPMetadataFilenameFormat").get_value_or ("%t"));
        _dcp_asset_filename_format = dcp::NameFormat (f.optional_string_child("DCPAssetFilenameFormat").get_value_or ("%t"));
        _jump_to_selected = f.optional_bool_child("JumpToSelected").get_value_or (true);
-       BOOST_FOREACH (cxml::NodePtr i, f.node_children("Nagged")) {
-               int const id = i->number_attribute<int>("Id");
-               if (id >= 0 && id < NAG_COUNT) {
-                       _nagged[id] = raw_convert<int>(i->content());
-               }
-       }
        /* The variable was renamed but not the XML tag */
        _sound = f.optional_bool_child("PreviewSound").get_value_or (true);
        _sound_output = f.optional_string_child("PreviewSoundOutput");
@@ -400,18 +439,7 @@ try
 }
 catch (...) {
        if (have_existing ("config.xml")) {
-
-               /* Make a copy of the configuration */
-               try {
-                       int n = 1;
-                       while (n < 100 && boost::filesystem::exists(path(String::compose("config.xml.%1", n)))) {
-                               ++n;
-                       }
-
-                       boost::filesystem::copy_file(path("config.xml", false), path(String::compose("config.xml.%1", n), false));
-                       boost::filesystem::copy_file(path("cinemas.xml", false), path(String::compose("cinemas.xml.%1", n), false));
-               } catch (...) {}
-
+               backup ();
                /* We have a config file but it didn't load */
                FailedToLoad ();
        }
@@ -476,8 +504,8 @@ Config::write_config () const
        xmlpp::Document doc;
        xmlpp::Element* root = doc.create_root_node ("Config");
 
-       /* [XML] Version The version number of the configuration file format; currently 2. */
-       root->add_child("Version")->add_child_text ("2");
+       /* [XML] Version The version number of the configuration file format */
+       root->add_child("Version")->add_child_text (String::compose ("%1", _current_version));
        /* [XML] MasterEncodingThreads Number of encoding threads to use when running as master. */
        root->add_child("MasterEncodingThreads")->add_child_text (raw_convert<string> (_master_encoding_threads));
        /* [XML] ServerEncodingThreads Number of encoding threads to use when running as server. */