Add a new "Add DKDM" dialogue (#1637).
authorCarl Hetherington <cth@carlh.net>
Wed, 6 May 2020 22:02:26 +0000 (00:02 +0200)
committerCarl Hetherington <cth@carlh.net>
Wed, 6 May 2020 22:02:26 +0000 (00:02 +0200)
The basic motivation here is to avoid having to tell people to
"just" create a cinema with a screen in it just to be able to make
a DKDM.  Here you can just have a recipient, with emails etc.
and make DKDMs for them.  I hope this makes things clearer from the
user POV even if it does muddy the waters a bit with respect to
DKDMs just being KDMs (really).

34 files changed:
src/lib/cinema_kdms.cc [deleted file]
src/lib/cinema_kdms.h [deleted file]
src/lib/config.cc
src/lib/config.h
src/lib/film.cc
src/lib/film.h
src/lib/kdm_recipient.cc [new file with mode: 0644]
src/lib/kdm_recipient.h [new file with mode: 0644]
src/lib/kdm_with_metadata.cc [new file with mode: 0644]
src/lib/kdm_with_metadata.h [new file with mode: 0644]
src/lib/screen.cc
src/lib/screen.h
src/lib/screen_kdm.cc [deleted file]
src/lib/screen_kdm.h [deleted file]
src/lib/send_kdm_email_job.cc
src/lib/send_kdm_email_job.h
src/lib/trusted_device.cc [new file with mode: 0644]
src/lib/trusted_device.h [new file with mode: 0644]
src/lib/wscript
src/tools/dcpomatic.cc
src/tools/dcpomatic_kdm.cc
src/tools/dcpomatic_kdm_cli.cc
src/wx/cinema_dialog.cc
src/wx/cinema_dialog.h
src/wx/confirm_kdm_email_dialog.cc
src/wx/kdm_dialog.cc
src/wx/kdm_output_panel.cc
src/wx/kdm_output_panel.h
src/wx/recreate_chain_dialog.cc
src/wx/wscript
src/wx/wx_util.cc
src/wx/wx_util.h
test/kdm_naming_test.cc [new file with mode: 0644]
test/wscript

diff --git a/src/lib/cinema_kdms.cc b/src/lib/cinema_kdms.cc
deleted file mode 100644 (file)
index 3af1e0d..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
-    Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
-
-    This file is part of DCP-o-matic.
-
-    DCP-o-matic is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    DCP-o-matic is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#include "exceptions.h"
-#include "cinema_kdms.h"
-#include "cinema.h"
-#include "screen.h"
-#include "config.h"
-#include "util.h"
-#include "emailer.h"
-#include "compose.hpp"
-#include "log.h"
-#include "zipper.h"
-#include "dcpomatic_log.h"
-#include <boost/foreach.hpp>
-
-#include "i18n.h"
-
-using std::list;
-using std::cout;
-using std::string;
-using std::runtime_error;
-using boost::shared_ptr;
-using boost::function;
-
-void
-CinemaKDMs::make_zip_file (boost::filesystem::path zip_file, dcp::NameFormat name_format, dcp::NameFormat::Map name_values) const
-{
-       Zipper zipper (zip_file);
-
-       name_values['c'] = cinema->name;
-
-       BOOST_FOREACH (shared_ptr<ScreenKDM> i, screen_kdms) {
-               name_values['s'] = i->screen->name;
-               name_values['i'] = i->kdm_id ();
-               string const name = careful_string_filter(name_format.get(name_values, ".xml"));
-               zipper.add (name, i->kdm_as_xml());
-       }
-
-       zipper.close ();
-}
-
-/** Collect a list of ScreenKDMs into a list of CinemaKDMs so that each
- *  CinemaKDM contains the KDMs for its cinema.
- */
-list<CinemaKDMs>
-CinemaKDMs::collect (list<shared_ptr<ScreenKDM> > screen_kdms)
-{
-       list<CinemaKDMs> cinema_kdms;
-
-       while (!screen_kdms.empty ()) {
-
-               /* Get all the screens from a single cinema */
-
-               CinemaKDMs ck;
-
-               list<shared_ptr<ScreenKDM> >::iterator i = screen_kdms.begin ();
-               ck.cinema = (*i)->screen->cinema;
-               ck.screen_kdms.push_back (*i);
-               list<shared_ptr<ScreenKDM> >::iterator j = i;
-               ++i;
-               screen_kdms.remove (*j);
-
-               while (i != screen_kdms.end ()) {
-                       if ((*i)->screen->cinema == ck.cinema) {
-                               ck.screen_kdms.push_back (*i);
-                               list<shared_ptr<ScreenKDM> >::iterator j = i;
-                               ++i;
-                               screen_kdms.remove (*j);
-                       } else {
-                               ++i;
-                       }
-               }
-
-               cinema_kdms.push_back (ck);
-       }
-
-       return cinema_kdms;
-}
-
-/** Write one directory per cinema into another directory */
-int
-CinemaKDMs::write_directories (
-       list<CinemaKDMs> cinema_kdms,
-       boost::filesystem::path directory,
-       dcp::NameFormat container_name_format,
-       dcp::NameFormat filename_format,
-       dcp::NameFormat::Map name_values,
-       function<bool (boost::filesystem::path)> confirm_overwrite
-       )
-{
-       /* No specific screen */
-       name_values['s'] = "";
-
-       int written = 0;
-
-       BOOST_FOREACH (CinemaKDMs const & i, cinema_kdms) {
-               boost::filesystem::path path = directory;
-               name_values['c'] = i.cinema->name;
-               path /= container_name_format.get(name_values, "");
-               if (!boost::filesystem::exists (path) || confirm_overwrite (path)) {
-                       boost::filesystem::create_directories (path);
-                       ScreenKDM::write_files (i.screen_kdms, path, filename_format, name_values, confirm_overwrite);
-               }
-               written += i.screen_kdms.size();
-       }
-
-       return written;
-}
-
-/** Write one ZIP file per cinema into a directory */
-int
-CinemaKDMs::write_zip_files (
-       list<CinemaKDMs> cinema_kdms,
-       boost::filesystem::path directory,
-       dcp::NameFormat container_name_format,
-       dcp::NameFormat filename_format,
-       dcp::NameFormat::Map name_values,
-       function<bool (boost::filesystem::path)> confirm_overwrite
-       )
-{
-       /* No specific screen */
-       name_values['s'] = "";
-
-       int written = 0;
-
-       BOOST_FOREACH (CinemaKDMs const & i, cinema_kdms) {
-               boost::filesystem::path path = directory;
-               name_values['c'] = i.cinema->name;
-               path /= container_name_format.get(name_values, ".zip");
-               if (!boost::filesystem::exists (path) || confirm_overwrite (path)) {
-                       if (boost::filesystem::exists (path)) {
-                               /* Creating a new zip file over an existing one is an error */
-                               boost::filesystem::remove (path);
-                       }
-                       i.make_zip_file (path, filename_format, name_values);
-                       written += i.screen_kdms.size();
-               }
-       }
-
-       return written;
-}
-
-/** Email one ZIP file per cinema to the cinema.
- *  @param cinema_kdms KDMS to email.
- *  @param container_name_format Format of folder / ZIP to use.
- *  @param filename_format Format of filenames to use.
- *  @param name_values Values to substitute into \p container_name_format and \p filename_format.
- *  @param cpl_name Name of the CPL that the KDMs are for.
- */
-void
-CinemaKDMs::email (
-       list<CinemaKDMs> cinema_kdms,
-       dcp::NameFormat container_name_format,
-       dcp::NameFormat filename_format,
-       dcp::NameFormat::Map name_values,
-       string cpl_name
-       )
-{
-       Config* config = Config::instance ();
-
-       if (config->mail_server().empty()) {
-               throw NetworkError (_("No mail server configured in preferences"));
-       }
-
-       /* No specific screen */
-       name_values['s'] = "";
-
-       BOOST_FOREACH (CinemaKDMs const & i, cinema_kdms) {
-
-               if (i.cinema->emails.empty()) {
-                       continue;
-               }
-
-               name_values['c'] = i.cinema->name;
-
-               boost::filesystem::path zip_file = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
-               boost::filesystem::create_directories (zip_file);
-               zip_file /= container_name_format.get(name_values, ".zip");
-               i.make_zip_file (zip_file, filename_format, name_values);
-
-               string subject = config->kdm_subject();
-               boost::algorithm::replace_all (subject, "$CPL_NAME", cpl_name);
-               boost::algorithm::replace_all (subject, "$START_TIME", name_values['b']);
-               boost::algorithm::replace_all (subject, "$END_TIME", name_values['e']);
-               boost::algorithm::replace_all (subject, "$CINEMA_NAME", i.cinema->name);
-
-               string body = config->kdm_email().c_str();
-               boost::algorithm::replace_all (body, "$CPL_NAME", cpl_name);
-               boost::algorithm::replace_all (body, "$START_TIME", name_values['b']);
-               boost::algorithm::replace_all (body, "$END_TIME", name_values['e']);
-               boost::algorithm::replace_all (body, "$CINEMA_NAME", i.cinema->name);
-
-               string screens;
-               BOOST_FOREACH (shared_ptr<ScreenKDM> j, i.screen_kdms) {
-                       screens += j->screen->name + ", ";
-               }
-               boost::algorithm::replace_all (body, "$SCREENS", screens.substr (0, screens.length() - 2));
-
-               Emailer email (config->kdm_from(), i.cinema->emails, subject, body);
-
-               BOOST_FOREACH (string i, config->kdm_cc()) {
-                       email.add_cc (i);
-               }
-               if (!config->kdm_bcc().empty ()) {
-                       email.add_bcc (config->kdm_bcc ());
-               }
-
-               email.add_attachment (zip_file, container_name_format.get(name_values, ".zip"), "application/zip");
-
-               Config* c = Config::instance ();
-
-               try {
-                       email.send (c->mail_server(), c->mail_port(), c->mail_protocol(), c->mail_user(), c->mail_password());
-               } catch (...) {
-                       boost::filesystem::remove (zip_file);
-                       dcpomatic_log->log ("Email content follows", LogEntry::TYPE_DEBUG_EMAIL);
-                       dcpomatic_log->log (email.email(), LogEntry::TYPE_DEBUG_EMAIL);
-                       dcpomatic_log->log ("Email session follows", LogEntry::TYPE_DEBUG_EMAIL);
-                       dcpomatic_log->log (email.notes(), LogEntry::TYPE_DEBUG_EMAIL);
-                       throw;
-               }
-
-               boost::filesystem::remove (zip_file);
-
-               dcpomatic_log->log ("Email content follows", LogEntry::TYPE_DEBUG_EMAIL);
-               dcpomatic_log->log (email.email(), LogEntry::TYPE_DEBUG_EMAIL);
-               dcpomatic_log->log ("Email session follows", LogEntry::TYPE_DEBUG_EMAIL);
-               dcpomatic_log->log (email.notes(), LogEntry::TYPE_DEBUG_EMAIL);
-       }
-}
diff --git a/src/lib/cinema_kdms.h b/src/lib/cinema_kdms.h
deleted file mode 100644 (file)
index 2b82cda..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-    Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
-
-    This file is part of DCP-o-matic.
-
-    DCP-o-matic is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    DCP-o-matic is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#include "screen_kdm.h"
-
-class Cinema;
-class Job;
-class Log;
-
-class CinemaKDMs
-{
-public:
-       void make_zip_file (boost::filesystem::path zip_file, dcp::NameFormat name_format, dcp::NameFormat::Map name_values) const;
-
-       static std::list<CinemaKDMs> collect (std::list<boost::shared_ptr<ScreenKDM> > kdms);
-
-       static int write_directories (
-               std::list<CinemaKDMs> cinema_kdms,
-               boost::filesystem::path directory,
-               dcp::NameFormat container_name_format,
-               dcp::NameFormat filename_format,
-               dcp::NameFormat::Map name_values,
-               boost::function<bool (boost::filesystem::path)> confirm_overwrite
-               );
-
-       static int write_zip_files (
-               std::list<CinemaKDMs> cinema_kdms,
-               boost::filesystem::path directory,
-               dcp::NameFormat container_name_format,
-               dcp::NameFormat filename_format,
-               dcp::NameFormat::Map name_values,
-               boost::function<bool (boost::filesystem::path)> confirm_overwrite
-               );
-
-       static void email (
-               std::list<CinemaKDMs> cinema_kdms,
-               dcp::NameFormat container_name_format,
-               dcp::NameFormat filename_format,
-               dcp::NameFormat::Map name_values,
-               std::string cpl_name
-               );
-
-       boost::shared_ptr<Cinema> cinema;
-       std::list<boost::shared_ptr<ScreenKDM> > screen_kdms;
-};
index 7364a122c4998c877a7970331840e240c50ec146..ebb6ece931f0bed3899e734f17c0baefdb2f4dad 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -32,6 +32,7 @@
 #include "dkdm_wrapper.h"
 #include "compose.hpp"
 #include "crypto.h"
+#include "dkdm_recipient.h"
 #include <dcp/raw_convert.h>
 #include <dcp/name_format.h>
 #include <dcp/certificate_chain.h>
@@ -127,10 +128,12 @@ Config::set_defaults ()
        _win32_console = false;
 #endif
        _cinemas_file = path ("cinemas.xml");
+       _dkdm_recipients_file = path ("dkdm_recipients.xml");
        _show_hints_before_make_dcp = true;
        _confirm_kdm_email = true;
        _kdm_container_name_format = dcp::NameFormat ("KDM %f %c");
        _kdm_filename_format = dcp::NameFormat ("KDM %f %c %s");
+       _dkdm_filename_format = dcp::NameFormat ("DKDM %f %c %s");
        _dcp_metadata_filename_format = dcp::NameFormat ("%t");
        _dcp_asset_filename_format = dcp::NameFormat ("%t");
        _jump_to_selected = true;
@@ -232,6 +235,7 @@ Config::backup ()
 
                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));
+               boost::filesystem::copy_file(path("dkdm_recipients.xml", false), path(String::compose("dkdm_recipients.xml.%1", n), false));
        } catch (...) {}
 }
 
@@ -334,7 +338,9 @@ try
        _default_interop = f.optional_bool_child("DefaultInterop").get_value_or (false);
        _default_kdm_directory = f.optional_string_child("DefaultKDMDirectory");
 
-       /* Load any cinemas from config.xml */
+       /* Read any cinemas that are still lying around in the config file
+        * from an old version.
+        */
        read_cinemas (f);
 
        _mail_server = f.string_child ("MailServer");
@@ -513,10 +519,12 @@ try
                }
        }
        _cinemas_file = f.optional_string_child("CinemasFile").get_value_or (path ("cinemas.xml").string ());
+       _dkdm_recipients_file = f.optional_string_child("DKDMRecipientsFile").get_value_or (path("dkdm_recipients.xml").string());
        _show_hints_before_make_dcp = f.optional_bool_child("ShowHintsBeforeMakeDCP").get_value_or (true);
        _confirm_kdm_email = f.optional_bool_child("ConfirmKDMEmail").get_value_or (true);
        _kdm_container_name_format = dcp::NameFormat (f.optional_string_child("KDMContainerNameFormat").get_value_or ("KDM %f %c"));
        _kdm_filename_format = dcp::NameFormat (f.optional_string_child("KDMFilenameFormat").get_value_or ("KDM %f %c %s"));
+       _dkdm_filename_format = dcp::NameFormat (f.optional_string_child("DKDMFilenameFormat").get_value_or("DKDM %f %c %s"));
        _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);
@@ -608,12 +616,17 @@ try
        _player_lock_file = f.optional_string_child("PlayerLockFile");
 #endif
 
-       /* Replace any cinemas from config.xml with those from the configured file */
        if (boost::filesystem::exists (_cinemas_file)) {
                cxml::Document f ("Cinemas");
                f.read_file (_cinemas_file);
                read_cinemas (f);
        }
+
+       if (boost::filesystem::exists (_dkdm_recipients_file)) {
+               cxml::Document f ("DKDMRecipients");
+               f.read_file (_dkdm_recipients_file);
+               read_dkdm_recipients (f);
+       }
 }
 catch (...) {
        if (have_existing ("config.xml")) {
@@ -647,6 +660,7 @@ Config::write () const
 {
        write_config ();
        write_cinemas ();
+       write_dkdm_recipients ();
 }
 
 void
@@ -883,12 +897,16 @@ Config::write_config () const
 
        /* [XML] CinemasFile Filename of cinemas list file. */
        root->add_child("CinemasFile")->add_child_text (_cinemas_file.string());
+       /* [XML] DKDMRecipientsFile Filename of DKDM recipients list file. */
+       root->add_child("DKDMRecipientsFile")->add_child_text (_dkdm_recipients_file.string());
        /* [XML] ShowHintsBeforeMakeDCP 1 to show hints in the GUI before making a DCP, otherwise 0. */
        root->add_child("ShowHintsBeforeMakeDCP")->add_child_text (_show_hints_before_make_dcp ? "1" : "0");
        /* [XML] ConfirmKDMEmail 1 to confirm before sending KDM emails in the GUI, otherwise 0. */
        root->add_child("ConfirmKDMEmail")->add_child_text (_confirm_kdm_email ? "1" : "0");
        /* [XML] KDMFilenameFormat Format for KDM filenames. */
        root->add_child("KDMFilenameFormat")->add_child_text (_kdm_filename_format.specification ());
+       /* [XML] KDMFilenameFormat Format for DKDM filenames. */
+       root->add_child("DKDMFilenameFormat")->add_child_text(_dkdm_filename_format.specification());
        /* [XML] KDMContainerNameFormat Format for KDM containers (directories or ZIP files). */
        root->add_child("KDMContainerNameFormat")->add_child_text (_kdm_container_name_format.specification ());
        /* [XML] DCPMetadataFilenameFormat Format for DCP metadata filenames. */
@@ -1080,28 +1098,45 @@ Config::write_config () const
        }
 }
 
+
+template <class T>
 void
-Config::write_cinemas () const
+write_file (string root_node, string node, string version, list<shared_ptr<T> > things, boost::filesystem::path file)
 {
        xmlpp::Document doc;
-       xmlpp::Element* root = doc.create_root_node ("Cinemas");
-       root->add_child("Version")->add_child_text ("1");
+       xmlpp::Element* root = doc.create_root_node (root_node);
+       root->add_child("Version")->add_child_text(version);
 
-       BOOST_FOREACH (shared_ptr<Cinema> i, _cinemas) {
-               i->as_xml (root->add_child ("Cinema"));
+       BOOST_FOREACH (shared_ptr<T> i, things) {
+               i->as_xml (root->add_child(node));
        }
 
        try {
-               doc.write_to_file_formatted (_cinemas_file.string() + ".tmp");
-               boost::filesystem::remove (_cinemas_file);
-               boost::filesystem::rename (_cinemas_file.string() + ".tmp", _cinemas_file);
+               doc.write_to_file_formatted (file.string() + ".tmp");
+               boost::filesystem::remove (file);
+               boost::filesystem::rename (file.string() + ".tmp", file);
        } catch (xmlpp::exception& e) {
                string s = e.what ();
                trim (s);
-               throw FileError (s, _cinemas_file);
+               throw FileError (s, file);
        }
 }
 
+
+void
+Config::write_cinemas () const
+{
+       write_file ("Cinemas", "Cinema", "1", _cinemas, _cinemas_file);
+}
+
+
+void
+Config::write_dkdm_recipients () const
+{
+       write_file ("DKDMRecipients", "DKDMRecipient", "1", _dkdm_recipients, _dkdm_recipients_file);
+}
+
+
 boost::filesystem::path
 Config::default_directory_or (boost::filesystem::path a) const
 {
@@ -1293,6 +1328,37 @@ Config::set_cinemas_file (boost::filesystem::path file)
        changed (OTHER);
 }
 
+
+void
+Config::read_dkdm_recipients (cxml::Document const & f)
+{
+       _dkdm_recipients.clear ();
+       list<cxml::NodePtr> cin = f.node_children ("DKDMRecipient");
+       BOOST_FOREACH (cxml::ConstNodePtr i, f.node_children("DKDMRecipient")) {
+               _dkdm_recipients.push_back (shared_ptr<DKDMRecipient>(new DKDMRecipient(i)));
+       }
+}
+
+void
+Config::set_dkdm_recipients_file (boost::filesystem::path file)
+{
+       if (file == _dkdm_recipients_file) {
+               return;
+       }
+
+       _dkdm_recipients_file = file;
+
+       if (boost::filesystem::exists (_dkdm_recipients_file)) {
+               /* Existing file; read it in */
+               cxml::Document f ("DKDMRecipients");
+               f.read_file (_dkdm_recipients_file);
+               read_dkdm_recipients (f);
+       }
+
+       changed (OTHER);
+}
+
+
 void
 Config::save_template (shared_ptr<const Film> film, string name) const
 {
index 7494074036c0fb01772d0c25cb4a0749a1b3ed50..f54ca3814043abf5c8fa51c619c975cf87591113 100644 (file)
@@ -44,6 +44,7 @@ class Ratio;
 class Cinema;
 class Film;
 class DKDMGroup;
+class DKDMRecipient;
 
 /** @class Config
  *  @brief A singleton class holding configuration.
@@ -76,6 +77,7 @@ public:
                USE_ANY_SERVERS,
                SERVERS,
                CINEMAS,
+               DKDM_RECIPIENTS,
                SOUND,
                SOUND_OUTPUT,
                INTERFACE_COMPLEXITY,
@@ -148,6 +150,10 @@ public:
                return _cinemas;
        }
 
+       std::list<boost::shared_ptr<DKDMRecipient> > dkdm_recipients () const {
+               return _dkdm_recipients;
+       }
+
        std::list<int> allowed_dcp_frame_rates () const {
                return _allowed_dcp_frame_rates;
        }
@@ -342,6 +348,10 @@ public:
                return _cinemas_file;
        }
 
+       boost::filesystem::path dkdm_recipients_file () const {
+               return _dkdm_recipients_file;
+       }
+
        bool show_hints_before_make_dcp () const {
                return _show_hints_before_make_dcp;
        }
@@ -358,6 +368,10 @@ public:
                return _kdm_filename_format;
        }
 
+       dcp::NameFormat dkdm_filename_format () const {
+               return _dkdm_filename_format;
+       }
+
        dcp::NameFormat dcp_metadata_filename_format () const {
                return _dcp_metadata_filename_format;
        }
@@ -617,6 +631,16 @@ public:
                changed (CINEMAS);
        }
 
+       void add_dkdm_recipient (boost::shared_ptr<DKDMRecipient> c) {
+               _dkdm_recipients.push_back (c);
+               changed (DKDM_RECIPIENTS);
+       }
+
+       void remove_dkdm_recipient (boost::shared_ptr<DKDMRecipient> c) {
+               _dkdm_recipients.remove (c);
+               changed (DKDM_RECIPIENTS);
+       }
+
        void set_allowed_dcp_frame_rates (std::list<int> const & r) {
                maybe_set (_allowed_dcp_frame_rates, r);
        }
@@ -814,6 +838,8 @@ public:
 
        void set_cinemas_file (boost::filesystem::path file);
 
+       void set_dkdm_recipients_file (boost::filesystem::path file);
+
        void set_show_hints_before_make_dcp (bool s) {
                maybe_set (_show_hints_before_make_dcp, s);
        }
@@ -859,6 +885,10 @@ public:
                maybe_set (_kdm_filename_format, n);
        }
 
+       void set_dkdm_filename_format (dcp::NameFormat n) {
+               maybe_set (_dkdm_filename_format, n);
+       }
+
        void set_dcp_metadata_filename_format (dcp::NameFormat n) {
                maybe_set (_dcp_metadata_filename_format, n);
        }
@@ -1111,6 +1141,7 @@ public:
        void write () const;
        void write_config () const;
        void write_cinemas () const;
+       void write_dkdm_recipients () const;
        void link (boost::filesystem::path new_file) const;
        void copy_and_link (boost::filesystem::path new_file) const;
        bool have_write_permission () const;
@@ -1136,6 +1167,7 @@ private:
        void set_notification_email_to_default ();
        void set_cover_sheet_to_default ();
        void read_cinemas (cxml::Document const & f);
+       void read_dkdm_recipients (cxml::Document const & f);
        boost::shared_ptr<dcp::CertificateChain> create_certificate_chain ();
        boost::filesystem::path directory_or (boost::optional<boost::filesystem::path> dir, boost::filesystem::path a) const;
        void add_to_history_internal (std::vector<boost::filesystem::path>& h, boost::filesystem::path p);
@@ -1215,6 +1247,7 @@ private:
        boost::optional<boost::filesystem::path> _default_kdm_directory;
        bool _default_upload_after_make_dcp;
        std::list<boost::shared_ptr<Cinema> > _cinemas;
+       std::list<boost::shared_ptr<DKDMRecipient> > _dkdm_recipients;
        std::string _mail_server;
        int _mail_port;
        EmailProtocol _mail_protocol;
@@ -1257,9 +1290,11 @@ private:
        std::vector<boost::filesystem::path> _player_history;
        boost::shared_ptr<DKDMGroup> _dkdms;
        boost::filesystem::path _cinemas_file;
+       boost::filesystem::path _dkdm_recipients_file;
        bool _show_hints_before_make_dcp;
        bool _confirm_kdm_email;
        dcp::NameFormat _kdm_filename_format;
+       dcp::NameFormat _dkdm_filename_format;
        dcp::NameFormat _kdm_container_name_format;
        dcp::NameFormat _dcp_metadata_filename_format;
        dcp::NameFormat _dcp_asset_filename_format;
index a24e9aa30046b316408a810e9b5a2d31d3c3164c..b233e5ee690a5ccf984aac7f730dd04ad8c13f94 100644 (file)
@@ -50,7 +50,7 @@
 #include "text_content.h"
 #include "ffmpeg_content.h"
 #include "dcp_content.h"
-#include "screen_kdm.h"
+#include "kdm_with_metadata.h"
 #include "cinema.h"
 #include "change_signaller.h"
 #include "check_content_change_job.h"
@@ -1502,47 +1502,6 @@ Film::make_kdm (
                ).encrypt (signer, recipient, trusted_devices, formulation, disable_forensic_marking_picture, disable_forensic_marking_audio);
 }
 
-/** @param screens Screens to make KDMs for.
- *  @param cpl_file Path to CPL to make KDMs for.
- *  @param from KDM from time expressed as a local time in the time zone of the Screen's Cinema.
- *  @param until KDM to time expressed as a local time in the time zone of the Screen's Cinema.
- *  @param formulation KDM formulation to use.
- *  @param disable_forensic_marking_picture true to disable forensic marking of picture.
- *  @param disable_forensic_marking_audio if not set, don't disable forensic marking of audio.  If set to 0,
- *  disable all forensic marking; if set above 0, disable forensic marking above that channel.
- */
-list<shared_ptr<ScreenKDM> >
-Film::make_kdms (
-       list<shared_ptr<Screen> > screens,
-       boost::filesystem::path cpl_file,
-       boost::posix_time::ptime from,
-       boost::posix_time::ptime until,
-       dcp::Formulation formulation,
-       bool disable_forensic_marking_picture,
-       optional<int> disable_forensic_marking_audio
-       ) const
-{
-       list<shared_ptr<ScreenKDM> > kdms;
-
-       BOOST_FOREACH (shared_ptr<Screen> i, screens) {
-               if (i->recipient) {
-                       dcp::EncryptedKDM const kdm = make_kdm (
-                               i->recipient.get(),
-                               i->trusted_device_thumbprints(),
-                               cpl_file,
-                               dcp::LocalTime (from,  i->cinema ? i->cinema->utc_offset_hour() : 0, i->cinema ? i->cinema->utc_offset_minute() : 0),
-                               dcp::LocalTime (until, i->cinema ? i->cinema->utc_offset_hour() : 0, i->cinema ? i->cinema->utc_offset_minute() : 0),
-                               formulation,
-                               disable_forensic_marking_picture,
-                               disable_forensic_marking_audio
-                               );
-
-                       kdms.push_back (shared_ptr<ScreenKDM>(new DCPScreenKDM(i, kdm)));
-               }
-       }
-
-       return kdms;
-}
 
 /** @return The approximate disk space required to encode a DCP of this film with the
  *  current settings, in bytes.
index 6cce07c17f3fa23bcb047f660582e02b553e7efa..40d366f8f68c8a331ee7840c9bf37ee944515f89 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -60,7 +60,6 @@ class AudioProcessor;
 class AudioMapping;
 class Ratio;
 class Job;
-class ScreenKDM;
 class Film;
 struct isdcf_name_test;
 
@@ -169,16 +168,6 @@ public:
                boost::optional<int> disable_forensic_marking_audio
                ) const;
 
-       std::list<boost::shared_ptr<ScreenKDM> > make_kdms (
-               std::list<boost::shared_ptr<dcpomatic::Screen> > screens,
-               boost::filesystem::path cpl_file,
-               boost::posix_time::ptime from,
-               boost::posix_time::ptime until,
-               dcp::Formulation formulation,
-               bool disable_forensic_marking_picture,
-               boost::optional<int> disable_forensic_marking_audio
-               ) const;
-
        int state_version () const {
                return _state_version;
        }
diff --git a/src/lib/kdm_recipient.cc b/src/lib/kdm_recipient.cc
new file mode 100644 (file)
index 0000000..d05192a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "kdm_recipient.h"
+
+KDMRecipient::KDMRecipient (cxml::ConstNodePtr node)
+       : name (node->string_child("Name"))
+       , notes (node->optional_string_child("Notes").get_value_or (""))
+{
+       if (node->optional_string_child("Certificate")) {
+               recipient = dcp::Certificate (node->string_child("Certificate"));
+       } else if (node->optional_string_child("Recipient")) {
+               recipient = dcp::Certificate (node->string_child("Recipient"));
+       }
+}
+
+
+void
+KDMRecipient::as_xml (xmlpp::Element* parent) const
+{
+       parent->add_child("Name")->add_child_text(name);
+       if (recipient) {
+               parent->add_child("Recipient")->add_child_text(recipient->certificate(true));
+       }
+
+       parent->add_child("Notes")->add_child_text(notes);
+}
+
diff --git a/src/lib/kdm_recipient.h b/src/lib/kdm_recipient.h
new file mode 100644 (file)
index 0000000..c0533da
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+    Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef DCPOMATIC_KDM_RECIPIENT_H
+#define DCPOMATIC_KDM_RECIPIENT_H
+
+#include <dcp/certificate.h>
+#include <libcxml/cxml.h>
+#include <libxml++/libxml++.h>
+#include <boost/optional.hpp>
+#include <string>
+
+class KDMRecipient
+{
+public:
+       KDMRecipient (std::string const& name_, std::string const& notes_, boost::optional<dcp::Certificate> recipient_)
+               : name (name_)
+               , notes (notes_)
+               , recipient (recipient_)
+       {}
+
+       explicit KDMRecipient (cxml::ConstNodePtr);
+
+       virtual void as_xml (xmlpp::Element *) const;
+
+       std::string name;
+       std::string notes;
+       boost::optional<dcp::Certificate> recipient;
+};
+
+#endif
diff --git a/src/lib/kdm_with_metadata.cc b/src/lib/kdm_with_metadata.cc
new file mode 100644 (file)
index 0000000..0ef1b8f
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+    Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "kdm_with_metadata.h"
+#include "cinema.h"
+#include "screen.h"
+#include "util.h"
+#include "zipper.h"
+#include "config.h"
+#include "dcpomatic_log.h"
+#include "emailer.h"
+#include <boost/foreach.hpp>
+#include <boost/function.hpp>
+#include <boost/function.hpp>
+
+#include "i18n.h"
+
+using std::string;
+using std::cout;
+using std::list;
+using boost::shared_ptr;
+using boost::optional;
+using boost::function;
+
+int
+write_files (
+       list<KDMWithMetadataPtr> kdms,
+       boost::filesystem::path directory,
+       dcp::NameFormat name_format,
+       boost::function<bool (boost::filesystem::path)> confirm_overwrite
+       )
+{
+       int written = 0;
+
+       if (directory == "-") {
+               /* Write KDMs to the stdout */
+               BOOST_FOREACH (KDMWithMetadataPtr i, kdms) {
+                       cout << i->kdm_as_xml ();
+                       ++written;
+               }
+
+               return written;
+       }
+
+       if (!boost::filesystem::exists (directory)) {
+               boost::filesystem::create_directories (directory);
+       }
+
+       /* Write KDMs to the specified directory */
+       BOOST_FOREACH (KDMWithMetadataPtr i, kdms) {
+               boost::filesystem::path out = directory / careful_string_filter(name_format.get(i->name_values(), ".xml"));
+               if (!boost::filesystem::exists (out) || confirm_overwrite (out)) {
+                       i->kdm_as_xml (out);
+                       ++written;
+               }
+       }
+
+       return written;
+}
+
+
+optional<string>
+KDMWithMetadata::get (char k) const
+{
+       dcp::NameFormat::Map::const_iterator i = _name_values.find (k);
+       if (i == _name_values.end()) {
+               return optional<string>();
+       }
+
+       return i->second;
+}
+
+
+void
+make_zip_file (list<KDMWithMetadataPtr> kdms, boost::filesystem::path zip_file, dcp::NameFormat name_format)
+{
+       Zipper zipper (zip_file);
+
+       BOOST_FOREACH (KDMWithMetadataPtr i, kdms) {
+               string const name = careful_string_filter(name_format.get(i->name_values(), ".xml"));
+               zipper.add (name, i->kdm_as_xml());
+       }
+
+       zipper.close ();
+}
+
+
+/** Collect a list of KDMWithMetadatas into a list of lists so that
+ *  each list contains the KDMs for one list.
+ */
+list<list<KDMWithMetadataPtr> >
+collect (list<KDMWithMetadataPtr> kdms)
+{
+       list<list<KDMWithMetadataPtr> > grouped;
+
+       BOOST_FOREACH (KDMWithMetadataPtr i, kdms) {
+
+               list<list<KDMWithMetadataPtr> >::iterator j = grouped.begin ();
+
+               while (j != grouped.end()) {
+                       if (j->front()->group() == i->group()) {
+                               j->push_back (i);
+                               break;
+                       }
+                       ++j;
+               }
+
+               if (j == grouped.end()) {
+                       grouped.push_back (list<KDMWithMetadataPtr>());
+                       grouped.back().push_back (i);
+               }
+       }
+
+       return grouped;
+}
+
+
+/** Write one directory per list into another directory */
+int
+write_directories (
+       list<list<KDMWithMetadataPtr> > kdms,
+       boost::filesystem::path directory,
+       dcp::NameFormat container_name_format,
+       dcp::NameFormat filename_format,
+       function<bool (boost::filesystem::path)> confirm_overwrite
+       )
+{
+       int written = 0;
+
+       BOOST_FOREACH (list<KDMWithMetadataPtr> const & i, kdms) {
+               boost::filesystem::path path = directory;
+               path /= container_name_format.get(i.front()->name_values(), "", "s");
+               if (!boost::filesystem::exists (path) || confirm_overwrite (path)) {
+                       boost::filesystem::create_directories (path);
+                       write_files (i, path, filename_format, confirm_overwrite);
+               }
+               written += i.size();
+       }
+
+       return written;
+}
+
+
+/** Write one ZIP file per cinema into a directory */
+int
+write_zip_files (
+       list<list<KDMWithMetadataPtr> > kdms,
+       boost::filesystem::path directory,
+       dcp::NameFormat container_name_format,
+       dcp::NameFormat filename_format,
+       function<bool (boost::filesystem::path)> confirm_overwrite
+       )
+{
+       int written = 0;
+
+       BOOST_FOREACH (list<KDMWithMetadataPtr> const & i, kdms) {
+               boost::filesystem::path path = directory;
+               path /= container_name_format.get(i.front()->name_values(), ".zip", "s");
+               if (!boost::filesystem::exists (path) || confirm_overwrite (path)) {
+                       if (boost::filesystem::exists (path)) {
+                               /* Creating a new zip file over an existing one is an error */
+                               boost::filesystem::remove (path);
+                       }
+                       make_zip_file (i, path, filename_format);
+                       written += i.size();
+               }
+       }
+
+       return written;
+}
+
+
+/** Email one ZIP file per cinema to the cinema.
+ *  @param kdms KDMs to email.
+ *  @param container_name_format Format of folder / ZIP to use.
+ *  @param filename_format Format of filenames to use.
+ *  @param name_values Values to substitute into \p container_name_format and \p filename_format.
+ *  @param cpl_name Name of the CPL that the KDMs are for.
+ */
+void
+email (
+       list<list<KDMWithMetadataPtr> > kdms,
+       dcp::NameFormat container_name_format,
+       dcp::NameFormat filename_format,
+       string cpl_name
+       )
+{
+       Config* config = Config::instance ();
+
+       if (config->mail_server().empty()) {
+               throw NetworkError (_("No mail server configured in preferences"));
+       }
+
+       BOOST_FOREACH (list<KDMWithMetadataPtr> const & i, kdms) {
+
+               if (i.front()->emails().empty()) {
+                       continue;
+               }
+
+               boost::filesystem::path zip_file = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
+               boost::filesystem::create_directories (zip_file);
+               zip_file /= container_name_format.get(i.front()->name_values(), ".zip");
+               make_zip_file (i, zip_file, filename_format);
+
+               string subject = config->kdm_subject();
+               boost::algorithm::replace_all (subject, "$CPL_NAME", cpl_name);
+               boost::algorithm::replace_all (subject, "$START_TIME", i.front()->get('b').get_value_or(""));
+               boost::algorithm::replace_all (subject, "$END_TIME", i.front()->get('e').get_value_or(""));
+               boost::algorithm::replace_all (subject, "$CINEMA_NAME", i.front()->get('c').get_value_or(""));
+
+               string body = config->kdm_email().c_str();
+               boost::algorithm::replace_all (body, "$CPL_NAME", cpl_name);
+               boost::algorithm::replace_all (body, "$START_TIME", i.front()->get('b').get_value_or(""));
+               boost::algorithm::replace_all (body, "$END_TIME", i.front()->get('e').get_value_or(""));
+               boost::algorithm::replace_all (body, "$CINEMA_NAME", i.front()->get('c').get_value_or(""));
+
+               string screens;
+               BOOST_FOREACH (KDMWithMetadataPtr j, i) {
+                       optional<string> screen_name = j->get('n');
+                       if (screen_name) {
+                               screens += *screen_name + ", ";
+                       }
+               }
+               boost::algorithm::replace_all (body, "$SCREENS", screens.substr (0, screens.length() - 2));
+
+               Emailer email (config->kdm_from(), i.front()->emails(), subject, body);
+
+               BOOST_FOREACH (string i, config->kdm_cc()) {
+                       email.add_cc (i);
+               }
+               if (!config->kdm_bcc().empty ()) {
+                       email.add_bcc (config->kdm_bcc ());
+               }
+
+               email.add_attachment (zip_file, container_name_format.get(i.front()->name_values(), ".zip"), "application/zip");
+
+               Config* c = Config::instance ();
+
+               try {
+                       email.send (c->mail_server(), c->mail_port(), c->mail_protocol(), c->mail_user(), c->mail_password());
+               } catch (...) {
+                       boost::filesystem::remove (zip_file);
+                       dcpomatic_log->log ("Email content follows", LogEntry::TYPE_DEBUG_EMAIL);
+                       dcpomatic_log->log (email.email(), LogEntry::TYPE_DEBUG_EMAIL);
+                       dcpomatic_log->log ("Email session follows", LogEntry::TYPE_DEBUG_EMAIL);
+                       dcpomatic_log->log (email.notes(), LogEntry::TYPE_DEBUG_EMAIL);
+                       throw;
+               }
+
+               boost::filesystem::remove (zip_file);
+
+               dcpomatic_log->log ("Email content follows", LogEntry::TYPE_DEBUG_EMAIL);
+               dcpomatic_log->log (email.email(), LogEntry::TYPE_DEBUG_EMAIL);
+               dcpomatic_log->log ("Email session follows", LogEntry::TYPE_DEBUG_EMAIL);
+               dcpomatic_log->log (email.notes(), LogEntry::TYPE_DEBUG_EMAIL);
+       }
+}
diff --git a/src/lib/kdm_with_metadata.h b/src/lib/kdm_with_metadata.h
new file mode 100644 (file)
index 0000000..b6bec1c
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+    Copyright (C) 2013-2019 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef DCPOMATIC_KDM_WITH_METADATA_H
+#define DCPOMATIC_KDM_WITH_METADATA_H
+
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+#include "encrypted_ecinema_kdm.h"
+#endif
+#include <dcp/encrypted_kdm.h>
+#include <dcp/name_format.h>
+#include <boost/shared_ptr.hpp>
+
+class Cinema;
+
+class KDMWithMetadata
+{
+public:
+       KDMWithMetadata (dcp::NameFormat::Map const& name_values, void const* group, std::list<std::string> emails)
+               : _name_values (name_values)
+               , _group (group)
+               , _emails (emails)
+       {}
+
+       virtual ~KDMWithMetadata () {}
+
+       virtual std::string kdm_as_xml () const = 0;
+       virtual void kdm_as_xml (boost::filesystem::path out) const = 0;
+
+       dcp::NameFormat::Map const& name_values () const {
+               return _name_values;
+       }
+
+       boost::optional<std::string> get (char k) const;
+
+       void const* group () const {
+               return _group;
+       }
+
+       std::list<std::string> emails () const {
+               return _emails;
+       }
+
+private:
+       dcp::NameFormat::Map _name_values;
+       void const* _group;
+       std::list<std::string> _emails;
+};
+
+
+typedef boost::shared_ptr<KDMWithMetadata> KDMWithMetadataPtr;
+
+
+int write_files (
+       std::list<KDMWithMetadataPtr> screen_kdms, boost::filesystem::path directory,
+       dcp::NameFormat name_format, boost::function<bool (boost::filesystem::path)> confirm_overwrite
+       );
+
+
+void make_zip_file (std::list<KDMWithMetadataPtr> kdms, boost::filesystem::path zip_file, dcp::NameFormat name_format);
+
+
+std::list<std::list<KDMWithMetadataPtr> > collect (std::list<KDMWithMetadataPtr> kdms);
+
+
+int write_directories (
+               std::list<std::list<KDMWithMetadataPtr> > kdms,
+               boost::filesystem::path directory,
+               dcp::NameFormat container_name_format,
+               dcp::NameFormat filename_format,
+               boost::function<bool (boost::filesystem::path)> confirm_overwrite
+               );
+
+
+int write_zip_files (
+               std::list<std::list<KDMWithMetadataPtr> > kdms,
+               boost::filesystem::path directory,
+               dcp::NameFormat container_name_format,
+               dcp::NameFormat filename_format,
+               boost::function<bool (boost::filesystem::path)> confirm_overwrite
+               );
+
+
+void email (
+               std::list<std::list<KDMWithMetadataPtr> > kdms,
+               dcp::NameFormat container_name_format,
+               dcp::NameFormat filename_format,
+               std::string cpl_name
+               );
+
+
+template <class T>
+class SpecialKDMWithMetadata : public KDMWithMetadata
+{
+public:
+       SpecialKDMWithMetadata (dcp::NameFormat::Map const& name_values, void const* group, std::list<std::string> emails, T k)
+               : KDMWithMetadata (name_values, group, emails)
+               , kdm (k)
+       {}
+
+       std::string kdm_as_xml () const {
+               return kdm.as_xml ();
+       }
+
+       void kdm_as_xml (boost::filesystem::path out) const {
+               return kdm.as_xml (out);
+       }
+
+       T kdm;
+};
+
+typedef SpecialKDMWithMetadata<dcp::EncryptedKDM> DCPKDMWithMetadata;
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+typedef SpecialKDMWithMetadata<EncryptedECinemaKDM> ECinemaKDMWithMetadata;
+#endif
+
+#endif
+
index fe62a5e6cdd9841394e03760601aea466f80065c..61a27f2bc46a2afe864e55acfb77f3fce7fc5af1 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2020 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
 */
 
 #include "screen.h"
+#include "kdm_with_metadata.h"
+#include "film.h"
+#include "cinema.h"
 #include <libxml++/libxml++.h>
 #include <boost/foreach.hpp>
 #include <boost/algorithm/string.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
 
 using std::string;
 using std::vector;
+using std::list;
+using boost::shared_ptr;
+using boost::optional;
 using namespace dcpomatic;
 
 Screen::Screen (cxml::ConstNodePtr node)
-       : name (node->string_child("Name"))
-       , notes (node->optional_string_child("Notes").get_value_or (""))
+       : KDMRecipient (node)
 {
-       if (node->optional_string_child ("Certificate")) {
-               recipient = dcp::Certificate (node->string_child ("Certificate"));
-       } else if (node->optional_string_child ("Recipient")) {
-               recipient = dcp::Certificate (node->string_child ("Recipient"));
-       }
-
        BOOST_FOREACH (cxml::ConstNodePtr i, node->node_children ("TrustedDevice")) {
                if (boost::algorithm::starts_with(i->content(), "-----BEGIN CERTIFICATE-----")) {
                        trusted_devices.push_back (TrustedDevice(dcp::Certificate(i->content())));
@@ -49,13 +49,7 @@ Screen::Screen (cxml::ConstNodePtr node)
 void
 Screen::as_xml (xmlpp::Element* parent) const
 {
-       parent->add_child("Name")->add_child_text (name);
-       if (recipient) {
-               parent->add_child("Recipient")->add_child_text (recipient->certificate (true));
-       }
-
-       parent->add_child("Notes")->add_child_text (notes);
-
+       KDMRecipient::as_xml (parent);
        BOOST_FOREACH (TrustedDevice i, trusted_devices) {
                parent->add_child("TrustedDevice")->add_child_text(i.as_string());
        }
@@ -71,34 +65,48 @@ Screen::trusted_device_thumbprints () const
        return t;
 }
 
-TrustedDevice::TrustedDevice (string thumbprint)
-       : _thumbprint (thumbprint)
-{
-
-}
-
-TrustedDevice::TrustedDevice (dcp::Certificate certificate)
-       : _certificate (certificate)
-{
-
-}
 
-string
-TrustedDevice::as_string () const
+KDMWithMetadataPtr
+kdm_for_screen (
+       shared_ptr<const Film> film,
+       boost::filesystem::path cpl,
+       shared_ptr<const dcpomatic::Screen> screen,
+       boost::posix_time::ptime valid_from,
+       boost::posix_time::ptime valid_to,
+       dcp::Formulation formulation,
+       bool disable_forensic_marking_picture,
+       optional<int> disable_forensic_marking_audio
+       )
 {
-       if (_certificate) {
-               return _certificate->certificate(true);
+       if (!screen->recipient) {
+               return KDMWithMetadataPtr();
        }
 
-       return *_thumbprint;
-}
-
-string
-TrustedDevice::thumbprint () const
-{
-       if (_certificate) {
-               return _certificate->thumbprint ();
+       shared_ptr<const Cinema> cinema = screen->cinema;
+       dcp::LocalTime const begin(valid_from, cinema ? cinema->utc_offset_hour() : 0, cinema ? cinema->utc_offset_minute() : 0);
+       dcp::LocalTime const end  (valid_to,   cinema ? cinema->utc_offset_hour() : 0, cinema ? cinema->utc_offset_minute() : 0);
+
+       dcp::EncryptedKDM const kdm = film->make_kdm (
+                       screen->recipient.get(),
+                       screen->trusted_device_thumbprints(),
+                       cpl,
+                       begin,
+                       end,
+                       formulation,
+                       disable_forensic_marking_picture,
+                       disable_forensic_marking_audio
+                       );
+
+       dcp::NameFormat::Map name_values;
+       if (cinema) {
+               name_values['c'] = cinema->name;
        }
+       name_values['s'] = screen->name;
+       name_values['f'] = film->name();
+       name_values['b'] = begin.date() + " " + begin.time_of_day(true, false);
+       name_values['e'] = end.date() + " " + end.time_of_day(true, false);
+       name_values['i'] = kdm.cpl_id();
 
-       return *_thumbprint;
+       return KDMWithMetadataPtr(new DCPKDMWithMetadata(name_values, cinema.get(), cinema ? cinema->emails : list<string>(), kdm));
 }
+
index 40990b684e04a4f6eac4e86c717e749032977e4d..013afff856627f43bfd477921418c0b6dfde67cc 100644 (file)
 #ifndef DCPOMATIC_SCREEN_H
 #define DCPOMATIC_SCREEN_H
 
+#include "kdm_with_metadata.h"
+#include "kdm_recipient.h"
+#include "trusted_device.h"
 #include <dcp/certificate.h>
 #include <libcxml/cxml.h>
 #include <boost/optional.hpp>
 #include <string>
 
 class Cinema;
-
-class TrustedDevice
-{
-public:
-       explicit TrustedDevice (std::string);
-       explicit TrustedDevice (dcp::Certificate);
-
-       boost::optional<dcp::Certificate> certificate () const {
-               return _certificate;
-       }
-
-       std::string thumbprint () const;
-       std::string as_string () const;
-
-private:
-       boost::optional<dcp::Certificate> _certificate;
-       boost::optional<std::string> _thumbprint;
-};
+class Film;
 
 namespace dcpomatic {
 
@@ -55,14 +41,12 @@ namespace dcpomatic {
  *  `recipient' (i.e. the mediablock) and the certificates/thumbprints
  *  of any trusted devices.
  */
-class Screen
+class Screen : public KDMRecipient
 {
 public:
-       Screen (std::string const & na, std::string const & no, boost::optional<dcp::Certificate> rec, std::vector<TrustedDevice> td)
-               : name (na)
-               , notes (no)
-               , recipient (rec)
-               , trusted_devices (td)
+       Screen (std::string const & name_, std::string const & notes_, boost::optional<dcp::Certificate> recipient_, std::vector<TrustedDevice> trusted_devices_)
+               : KDMRecipient (name_, notes_, recipient_)
+               , trusted_devices (trusted_devices_)
        {}
 
        explicit Screen (cxml::ConstNodePtr);
@@ -71,12 +55,22 @@ public:
        std::vector<std::string> trusted_device_thumbprints () const;
 
        boost::shared_ptr<Cinema> cinema;
-       std::string name;
-       std::string notes;
-       boost::optional<dcp::Certificate> recipient;
        std::vector<TrustedDevice> trusted_devices;
 };
 
 }
 
+KDMWithMetadataPtr
+kdm_for_screen (
+       boost::shared_ptr<const Film> film,
+       boost::filesystem::path cpl,
+       boost::shared_ptr<const dcpomatic::Screen> screen,
+       boost::posix_time::ptime valid_from,
+       boost::posix_time::ptime valid_to,
+       dcp::Formulation formulation,
+       bool disable_forensic_marking_picture,
+       boost::optional<int> disable_forensic_marking_audio
+       );
+
+
 #endif
diff --git a/src/lib/screen_kdm.cc b/src/lib/screen_kdm.cc
deleted file mode 100644 (file)
index f9a3fa3..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-    Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
-
-    This file is part of DCP-o-matic.
-
-    DCP-o-matic is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    DCP-o-matic is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#include "screen_kdm.h"
-#include "cinema.h"
-#include "screen.h"
-#include "util.h"
-#include <boost/foreach.hpp>
-
-using std::string;
-using std::cout;
-using std::list;
-using boost::shared_ptr;
-
-int
-ScreenKDM::write_files (
-       list<shared_ptr<ScreenKDM> > screen_kdms,
-       boost::filesystem::path directory,
-       dcp::NameFormat name_format,
-       dcp::NameFormat::Map name_values,
-       boost::function<bool (boost::filesystem::path)> confirm_overwrite
-       )
-{
-       int written = 0;
-
-       if (directory == "-") {
-               /* Write KDMs to the stdout */
-               BOOST_FOREACH (shared_ptr<ScreenKDM> i, screen_kdms) {
-                       cout << i->kdm_as_xml ();
-                       ++written;
-               }
-
-               return written;
-       }
-
-       if (!boost::filesystem::exists (directory)) {
-               boost::filesystem::create_directories (directory);
-       }
-
-       /* Write KDMs to the specified directory */
-       BOOST_FOREACH (shared_ptr<ScreenKDM> i, screen_kdms) {
-               name_values['c'] = i->screen->cinema ? i->screen->cinema->name : "";
-               name_values['s'] = i->screen->name;
-               name_values['i'] = i->kdm_id ();
-               boost::filesystem::path out = directory / careful_string_filter(name_format.get(name_values, ".xml"));
-               if (!boost::filesystem::exists (out) || confirm_overwrite (out)) {
-                       i->kdm_as_xml (out);
-                       ++written;
-               }
-       }
-
-       return written;
-}
diff --git a/src/lib/screen_kdm.h b/src/lib/screen_kdm.h
deleted file mode 100644 (file)
index a1e3624..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
-    Copyright (C) 2013-2019 Carl Hetherington <cth@carlh.net>
-
-    This file is part of DCP-o-matic.
-
-    DCP-o-matic is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    DCP-o-matic is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#ifndef DCPOMATIC_SCREEN_KDM_H
-#define DCPOMATIC_SCREEN_KDM_H
-
-#ifdef DCPOMATIC_VARIANT_SWAROOP
-#include "encrypted_ecinema_kdm.h"
-#endif
-#include <dcp/encrypted_kdm.h>
-#include <dcp/name_format.h>
-#include <boost/shared_ptr.hpp>
-
-namespace dcpomatic {
-       class Screen;
-}
-
-/** Simple class to collect a screen and an encrypted KDM */
-class ScreenKDM
-{
-public:
-       ScreenKDM (boost::shared_ptr<dcpomatic::Screen> s)
-               : screen (s)
-       {}
-
-       virtual ~ScreenKDM () {}
-
-       virtual std::string kdm_as_xml () const = 0;
-       virtual void kdm_as_xml (boost::filesystem::path out) const = 0;
-       virtual std::string kdm_id () const = 0;
-
-       static int write_files (
-               std::list<boost::shared_ptr<ScreenKDM> > screen_kdms, boost::filesystem::path directory,
-               dcp::NameFormat name_format, dcp::NameFormat::Map name_values,
-               boost::function<bool (boost::filesystem::path)> confirm_overwrite
-               );
-
-       boost::shared_ptr<dcpomatic::Screen> screen;
-};
-
-class DCPScreenKDM : public ScreenKDM
-{
-public:
-       DCPScreenKDM (boost::shared_ptr<dcpomatic::Screen> s, dcp::EncryptedKDM k)
-               : ScreenKDM (s)
-               , kdm (k)
-       {}
-
-       std::string kdm_as_xml () const {
-               return kdm.as_xml ();
-       }
-
-       void kdm_as_xml (boost::filesystem::path out) const {
-               return kdm.as_xml (out);
-       }
-
-       std::string kdm_id () const {
-               return kdm.cpl_id ();
-       }
-
-       dcp::EncryptedKDM kdm;
-};
-
-#ifdef DCPOMATIC_VARIANT_SWAROOP
-class ECinemaScreenKDM : public ScreenKDM
-{
-public:
-       ECinemaScreenKDM (boost::shared_ptr<dcpomatic::Screen> s, EncryptedECinemaKDM k)
-               : ScreenKDM (s)
-               , kdm (k)
-       {}
-
-       std::string kdm_as_xml () const {
-               return kdm.as_xml ();
-       }
-
-       void kdm_as_xml (boost::filesystem::path out) const {
-               return kdm.as_xml (out);
-       }
-
-       std::string kdm_id () const {
-               return kdm.id ();
-       }
-
-       EncryptedECinemaKDM kdm;
-};
-#endif
-
-#endif
index 1b476fa63e7312a1ea67710a45e2fc0a6c88b384..55a1718114a2566c29ec6ad5680c0be174dfcb59 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2020 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -20,8 +20,8 @@
 
 #include "send_kdm_email_job.h"
 #include "compose.hpp"
+#include "kdm_with_metadata.h"
 #include "film.h"
-#include "cinema_kdms.h"
 #include <list>
 
 #include "i18n.h"
 using std::string;
 using std::list;
 using boost::shared_ptr;
+using boost::optional;
 
-/** @param cinema_kdms KDMs to email.
+SendKDMEmailJob::SendKDMEmailJob (
+       list<KDMWithMetadataPtr> kdms,
+       dcp::NameFormat container_name_format,
+       dcp::NameFormat filename_format,
+       string cpl_name
+       )
+       : Job (shared_ptr<Film>())
+       , _container_name_format (container_name_format)
+       , _filename_format (filename_format)
+       , _cpl_name (cpl_name)
+{
+       BOOST_FOREACH (KDMWithMetadataPtr i, kdms) {
+               list<KDMWithMetadataPtr> s;
+               s.push_back (i);
+               _kdms.push_back (s);
+       }
+}
+
+/** @param kdms KDMs to email.
  *  @param container_name_format Format to ues for folders / ZIP files.
  *  @param filename_format Format to use for filenames.
  *  @param name_values Values to substitute into \p container_name_format and \p filename_format.
  *  @param cpl_name Name of the CPL that the KDMs are for.
  */
 SendKDMEmailJob::SendKDMEmailJob (
-       list<CinemaKDMs> cinema_kdms,
+       list<list<KDMWithMetadataPtr> > kdms,
        dcp::NameFormat container_name_format,
        dcp::NameFormat filename_format,
-       dcp::NameFormat::Map name_values,
        string cpl_name
        )
        : Job (shared_ptr<Film>())
        , _container_name_format (container_name_format)
        , _filename_format (filename_format)
-       , _name_values (name_values)
        , _cpl_name (cpl_name)
-       , _cinema_kdms (cinema_kdms)
+       , _kdms (kdms)
 {
 
 }
@@ -61,12 +78,12 @@ SendKDMEmailJob::~SendKDMEmailJob ()
 string
 SendKDMEmailJob::name () const
 {
-       dcp::NameFormat::Map::const_iterator i = _name_values.find ('f');
-       if (i == _name_values.end() || i->second.empty ()) {
+       optional<string> f = _kdms.front().front()->get('f');
+       if (!f || f->empty()) {
                return _("Email KDMs");
        }
 
-       return String::compose (_("Email KDMs for %1"), i->second);
+       return String::compose (_("Email KDMs for %2"), *f);
 }
 
 string
@@ -79,7 +96,7 @@ void
 SendKDMEmailJob::run ()
 {
        set_progress_unknown ();
-       CinemaKDMs::email (_cinema_kdms, _container_name_format, _filename_format, _name_values, _cpl_name);
+       email (_kdms, _container_name_format, _filename_format, _cpl_name);
        set_progress (1);
        set_state (FINISHED_OK);
 }
index a7196fe15ca679e1c20d1c2e04a20556987e9fc6..fa409edaaed9041793cb7f7c3f9f742cb1dad04f 100644 (file)
@@ -19,6 +19,7 @@
 */
 
 #include "job.h"
+#include "kdm_with_metadata.h"
 #include <dcp/types.h>
 #include <dcp/name_format.h>
 #include <boost/filesystem.hpp>
@@ -27,19 +28,25 @@ namespace dcpomatic {
        class Screen;
 }
 
-class CinemaKDMs;
 class Log;
 
 class SendKDMEmailJob : public Job
 {
 public:
        SendKDMEmailJob (
-               std::list<CinemaKDMs> cinema_kdms,
+               std::list<KDMWithMetadataPtr> kdms,
                dcp::NameFormat container_name_format,
                dcp::NameFormat filename_format,
-               dcp::NameFormat::Map name_values,
                std::string cpl_name
                );
+
+       SendKDMEmailJob (
+               std::list<std::list<KDMWithMetadataPtr> > kdms,
+               dcp::NameFormat container_name_format,
+               dcp::NameFormat filename_format,
+               std::string cpl_name
+               );
+
        ~SendKDMEmailJob ();
 
        std::string name () const;
@@ -49,7 +56,6 @@ public:
 private:
        dcp::NameFormat _container_name_format;
        dcp::NameFormat _filename_format;
-       dcp::NameFormat::Map _name_values;
        std::string _cpl_name;
-       std::list<CinemaKDMs> _cinema_kdms;
+       std::list<std::list<KDMWithMetadataPtr> > _kdms;
 };
diff --git a/src/lib/trusted_device.cc b/src/lib/trusted_device.cc
new file mode 100644 (file)
index 0000000..5849b8f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+    Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "trusted_device.h"
+
+using std::string;
+
+TrustedDevice::TrustedDevice (string thumbprint)
+       : _thumbprint (thumbprint)
+{
+
+}
+
+TrustedDevice::TrustedDevice (dcp::Certificate certificate)
+       : _certificate (certificate)
+{
+
+}
+
+string
+TrustedDevice::as_string () const
+{
+       if (_certificate) {
+               return _certificate->certificate(true);
+       }
+
+       return *_thumbprint;
+}
+
+string
+TrustedDevice::thumbprint () const
+{
+       if (_certificate) {
+               return _certificate->thumbprint ();
+       }
+
+       return *_thumbprint;
+}
+
diff --git a/src/lib/trusted_device.h b/src/lib/trusted_device.h
new file mode 100644 (file)
index 0000000..7c6af3e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+    Copyright (C) 2013-2019 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef DCPOMATIC_TRUSTED_DEVICE_H
+#define DCPOMATIC_TRUSTED_DEVICE_H
+
+#include <dcp/certificate.h>
+#include <boost/optional.hpp>
+#include <string>
+
+class TrustedDevice
+{
+public:
+       explicit TrustedDevice (std::string);
+       explicit TrustedDevice (dcp::Certificate);
+
+       boost::optional<dcp::Certificate> certificate () const {
+               return _certificate;
+       }
+
+       std::string thumbprint () const;
+       std::string as_string () const;
+
+private:
+       boost::optional<dcp::Certificate> _certificate;
+       boost::optional<std::string> _thumbprint;
+};
+
+#endif
index ea52079d03dc0d5bf255584bc98e7a2677f64dca..0f2a5d1975d8feccef0548f218b2daf812e76d34 100644 (file)
@@ -47,7 +47,6 @@ sources = """
           checker.cc
           check_content_change_job.cc
           cinema.cc
-          cinema_kdms.cc
           cinema_sound_processor.cc
           colour_conversion.cc
           config.cc
@@ -78,6 +77,7 @@ sources = """
           decoder_part.cc
           decrypted_ecinema_kdm.cc
           digester.cc
+          dkdm_recipient.cc
           dkdm_wrapper.cc
           dolby_cp750.cc
           edid.cc
@@ -125,6 +125,8 @@ sources = """
           job_manager.cc
           j2k_encoder.cc
           json_server.cc
+          kdm_with_metadata.cc
+          kdm_recipient.cc
           lock_file_checker.cc
           log.cc
           log_entry.cc
@@ -145,7 +147,6 @@ sources = """
           scoped_temporary.cc
           scp_uploader.cc
           screen.cc
-          screen_kdm.cc
           send_kdm_email_job.cc
           send_notification_email_job.cc
           send_problem_report_job.cc
@@ -163,6 +164,7 @@ sources = """
           text_ring_buffers.cc
           timer.cc
           transcode_job.cc
+          trusted_device.cc
           types.cc
           signal_manager.cc
           stdout_log.cc
index aea058d8048c72f50d969ce5f67385ad1b83f846..f69ab5a6a5d7eefb73a05b414968790de62a1bcf 100644 (file)
@@ -33,6 +33,7 @@
 #include "wx/recreate_chain_dialog.h"
 #include "wx/about_dialog.h"
 #include "wx/kdm_dialog.h"
+#include "wx/dkdm_dialog.h"
 #include "wx/self_dkdm_dialog.h"
 #include "wx/servers_list_dialog.h"
 #include "wx/hints_dialog.h"
 #include "lib/job_manager.h"
 #include "lib/exceptions.h"
 #include "lib/cinema.h"
-#include "lib/screen_kdm.h"
+#include "lib/kdm_with_metadata.h"
 #include "lib/send_kdm_email_job.h"
 #include "lib/encode_server_finder.h"
 #include "lib/update_checker.h"
 #include "lib/cross.h"
 #include "lib/content_factory.h"
 #include "lib/compose.hpp"
-#include "lib/cinema_kdms.h"
 #include "lib/dcpomatic_socket.h"
 #include "lib/hints.h"
 #include "lib/dcp_content.h"
@@ -227,6 +227,7 @@ enum {
        ID_jobs_make_dcp,
        ID_jobs_make_dcp_batch,
        ID_jobs_make_kdms,
+       ID_jobs_make_dkdms,
        ID_jobs_make_self_dkdm,
        ID_jobs_export,
        ID_jobs_send_dcp_to_tms,
@@ -262,6 +263,7 @@ public:
                , _servers_list_dialog (0)
                , _config_dialog (0)
                , _kdm_dialog (0)
+               , _dkdm_dialog (0)
                , _templates_dialog (0)
                , _file_menu (0)
                , _history_items (0)
@@ -318,6 +320,7 @@ public:
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::content_scale_to_fit_height, this), ID_content_scale_to_fit_height);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_dcp, this),           ID_jobs_make_dcp);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_kdms, this),          ID_jobs_make_kdms);
+               Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_dkdms, this),         ID_jobs_make_dkdms);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_dcp_batch, this),     ID_jobs_make_dcp_batch);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_self_dkdm, this),     ID_jobs_make_self_dkdm);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_export, this),             ID_jobs_export);
@@ -797,6 +800,21 @@ private:
                _kdm_dialog->Show ();
        }
 
+       void jobs_make_dkdms ()
+       {
+               if (!_film) {
+                       return;
+               }
+
+               if (_dkdm_dialog) {
+                       _dkdm_dialog->Destroy ();
+                       _dkdm_dialog = 0;
+               }
+
+               _dkdm_dialog = new DKDMDialog (this, _film);
+               _dkdm_dialog->Show ();
+       }
+
        /** @return false if we succeeded, true if not */
        bool send_to_other_tool (int port, function<void(boost::filesystem::path)> start, string message)
        {
@@ -1314,6 +1332,7 @@ private:
                add_item (jobs_menu, _("Make DCP in &batch converter\tCtrl-B"), ID_jobs_make_dcp_batch, NEEDS_FILM | NOT_DURING_DCP_CREATION);
                jobs_menu->AppendSeparator ();
                add_item (jobs_menu, _("Make &KDMs...\tCtrl-K"), ID_jobs_make_kdms, NEEDS_FILM);
+               add_item (jobs_menu, _("Make &DKDMs...\tCtrl-D"), ID_jobs_make_dkdms, NEEDS_FILM);
                add_item (jobs_menu, _("Make DKDM for DCP-o-matic..."), ID_jobs_make_self_dkdm, NEEDS_FILM | NEEDS_ENCRYPTION);
                jobs_menu->AppendSeparator ();
                add_item (jobs_menu, _("Export...\tCtrl-E"), ID_jobs_export, NEEDS_FILM);
@@ -1485,6 +1504,7 @@ private:
        ServersListDialog* _servers_list_dialog;
        wxPreferencesEditor* _config_dialog;
        KDMDialog* _kdm_dialog;
+       DKDMDialog* _dkdm_dialog;
        TemplatesDialog* _templates_dialog;
        wxMenu* _file_menu;
        shared_ptr<Film> _film;
index ef6b783f4fa0045bb753b2fdfc8f4aefe1509d80..117e756c72e93df587b325817fd181e9ec03f2f7 100644 (file)
@@ -38,9 +38,8 @@
 #include "lib/util.h"
 #include "lib/screen.h"
 #include "lib/job_manager.h"
-#include "lib/screen_kdm.h"
+#include "lib/kdm_with_metadata.h"
 #include "lib/exceptions.h"
-#include "lib/cinema_kdms.h"
 #include "lib/send_kdm_email_job.h"
 #include "lib/compose.hpp"
 #include "lib/cinema.h"
@@ -303,7 +302,7 @@ private:
                                return;
                        }
 
-                       list<shared_ptr<ScreenKDM> > screen_kdms;
+                       list<KDMWithMetadataPtr> kdms;
                        string title;
 
 #ifdef DCPOMATIC_VARIANT_SWAROOP
@@ -318,18 +317,29 @@ private:
                                                continue;
                                        }
 
+                                       dcp::LocalTime begin(_timing->from(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute());
+                                       dcp::LocalTime end(_timing->until(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute());
+
                                        DecryptedECinemaKDM kdm (
                                                decrypted.id(),
                                                decrypted.name(),
                                                decrypted.key(),
-                                               dcp::LocalTime (_timing->from(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
-                                               dcp::LocalTime (_timing->until(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute())
+                                               begin,
+                                               end
                                                );
 
+                                       dcp::NameFormat::Map name_values;
+                                       name_values['c'] = i->cinema->name;
+                                       name_values['s'] = i->name;
+                                       name_values['f'] = title;
+                                       name_values['b'] = begin.date() + " " + begin.time_of_day(true, false);
+                                       name_values['e'] = end.date() + " " + end.time_of_day(true, false);
+                                       name_values['i'] = kdm.id();
+
                                        /* Encrypt */
-                                       screen_kdms.push_back (
-                                               shared_ptr<ScreenKDM>(
-                                                       new ECinemaScreenKDM(i, kdm.encrypt(i->recipient.get()))
+                                       kdms.push_back (
+                                               KDMWithMetadataPtr(
+                                                       new ECinemaKDMWithMetadata(name_values, i->cinema, kdm.encrypt(i->recipient.get()))
                                                        )
                                                );
                                }
@@ -355,10 +365,13 @@ private:
                                                continue;
                                        }
 
+                                       dcp::LocalTime begin(_timing->from(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute());
+                                       dcp::LocalTime end(_timing->until(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute());
+
                                        /* Make an empty KDM */
                                        dcp::DecryptedKDM kdm (
-                                               dcp::LocalTime (_timing->from(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
-                                               dcp::LocalTime (_timing->until(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
+                                               begin,
+                                               end,
                                                decrypted.annotation_text().get_value_or (""),
                                                decrypted.content_title_text(),
                                                dcp::LocalTime().as_string()
@@ -369,27 +382,34 @@ private:
                                                kdm.add_key (j);
                                        }
 
+                                       dcp::EncryptedKDM const encrypted = kdm.encrypt(
+                                                       signer, i->recipient.get(), i->trusted_device_thumbprints(), _output->formulation(),
+                                                       !_output->forensic_mark_video(), _output->forensic_mark_audio() ? boost::optional<int>() : 0
+                                                       );
+
+                                       dcp::NameFormat::Map name_values;
+                                       name_values['c'] = i->cinema->name;
+                                       name_values['s'] = i->name;
+                                       name_values['f'] = title;
+                                       name_values['b'] = begin.date() + " " + begin.time_of_day(true, false);
+                                       name_values['e'] = end.date() + " " + end.time_of_day(true, false);
+                                       name_values['i'] = encrypted.cpl_id ();
+
                                        /* Encrypt */
-                                       screen_kdms.push_back (
-                                               shared_ptr<ScreenKDM>(
-                                                       new DCPScreenKDM(
-                                                               i,
-                                                               kdm.encrypt(
-                                                                       signer, i->recipient.get(), i->trusted_device_thumbprints(), _output->formulation(),
-                                                                       !_output->forensic_mark_video(), _output->forensic_mark_audio() ? boost::optional<int>() : 0
-                                                                       )
-                                                               )
+                                       kdms.push_back (
+                                               KDMWithMetadataPtr(
+                                                       new DCPKDMWithMetadata(name_values, i->cinema.get(), i->cinema->emails, encrypted)
                                                        )
                                                );
                                }
                        }
 
-                       if (screen_kdms.empty()) {
+                       if (kdms.empty()) {
                                return;
                        }
 
                        pair<shared_ptr<Job>, int> result = _output->make (
-                               screen_kdms, title, _timing, bind (&DOMFrame::confirm_overwrite, this, _1)
+                               kdms, title, bind (&DOMFrame::confirm_overwrite, this, _1)
                                );
 
                        if (result.first) {
index 166b22285a741f8cd5cdc491982042c78d3f8f8a..adb14f49e8bb588938f0a5d52c35cd659367346b 100644 (file)
@@ -24,8 +24,7 @@
 
 #include "lib/film.h"
 #include "lib/cinema.h"
-#include "lib/screen_kdm.h"
-#include "lib/cinema_kdms.h"
+#include "lib/kdm_with_metadata.h"
 #include "lib/config.h"
 #include "lib/exceptions.h"
 #include "lib/emailer.h"
@@ -130,22 +129,20 @@ always_overwrite ()
 
 void
 write_files (
-       list<shared_ptr<ScreenKDM> > screen_kdms,
+       list<KDMWithMetadataPtr> kdms,
        bool zip,
        boost::filesystem::path output,
        dcp::NameFormat container_name_format,
        dcp::NameFormat filename_format,
-       dcp::NameFormat::Map values,
        bool verbose
        )
 {
        if (zip) {
-               int const N = CinemaKDMs::write_zip_files (
-                       CinemaKDMs::collect (screen_kdms),
+               int const N = write_zip_files (
+                       collect (kdms),
                        output,
                        container_name_format,
                        filename_format,
-                       values,
                        bind (&always_overwrite)
                        );
 
@@ -153,8 +150,8 @@ write_files (
                        cout << "Wrote " << N << " ZIP files to " << output << "\n";
                }
        } else {
-               int const N = ScreenKDM::write_files (
-                       screen_kdms, output, filename_format, values,
+               int const N = write_files (
+                       kdms, output, filename_format,
                        bind (&always_overwrite)
                        );
 
@@ -223,17 +220,15 @@ from_film (
 
        boost::filesystem::path cpl = cpls.front().cpl_file;
 
-       dcp::NameFormat::Map values;
-       values['f'] = film->name();
-       values['b'] = dcp::LocalTime(valid_from).date() + " " + dcp::LocalTime(valid_from).time_of_day(true, false);
-       values['e'] = dcp::LocalTime(valid_to).date() + " " + dcp::LocalTime(valid_to).time_of_day(true, false);
-
        try {
-               list<shared_ptr<ScreenKDM> > screen_kdms = film->make_kdms (
-                       screens, cpl, valid_from, valid_to, formulation, disable_forensic_marking_picture, disable_forensic_marking_audio
-                       );
-
-               write_files (screen_kdms, zip, output, container_name_format, filename_format, values, verbose);
+               list<KDMWithMetadataPtr> kdms;
+               BOOST_FOREACH (shared_ptr<Screen> i, screens) {
+                       KDMWithMetadataPtr p = kdm_for_screen (film, cpl, i, valid_from, valid_to, formulation, disable_forensic_marking_picture, disable_forensic_marking_audio);
+                       if (p) {
+                               kdms.push_back (p);
+                       }
+               }
+               write_files (kdms, zip, output, container_name_format, filename_format, verbose);
        } catch (FileError& e) {
                cerr << program_name << ": " << e.what() << " (" << e.file().string() << ")\n";
                exit (EXIT_FAILURE);
@@ -325,36 +320,39 @@ from_dkdm (
        )
 {
        dcp::NameFormat::Map values;
-       values['f'] = dkdm.annotation_text().get_value_or("");
-       values['b'] = dcp::LocalTime(valid_from).date() + " " + dcp::LocalTime(valid_from).time_of_day(true, false);
-       values['e'] = dcp::LocalTime(valid_to).date() + " " + dcp::LocalTime(valid_to).time_of_day(true, false);
 
        try {
-               list<shared_ptr<ScreenKDM> > screen_kdms;
+               list<KDMWithMetadataPtr> kdms;
                BOOST_FOREACH (shared_ptr<Screen> i, screens) {
                        if (!i->recipient) {
                                continue;
                        }
 
-                       screen_kdms.push_back (
-                               shared_ptr<ScreenKDM>(
-                                       new DCPScreenKDM(
-                                               i,
-                                               kdm_from_dkdm(
+                       dcp::LocalTime begin(valid_from, i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute());
+                       dcp::LocalTime end(valid_to, i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute());
+
+                       dcp::EncryptedKDM const kdm = kdm_from_dkdm(
                                                        dkdm,
                                                        i->recipient.get(),
                                                        i->trusted_device_thumbprints(),
-                                                       dcp::LocalTime(valid_from, i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
-                                                       dcp::LocalTime(valid_to, i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
+                                                       begin,
+                                                       end,
                                                        formulation,
                                                        disable_forensic_marking_picture,
                                                        disable_forensic_marking_audio
-                                                       )
-                                               )
-                                       )
-                               );
+                                                       );
+
+                       dcp::NameFormat::Map name_values;
+                       name_values['c'] = i->cinema->name;
+                       name_values['s'] = i->name;
+                       name_values['f'] = dkdm.annotation_text().get_value_or("");
+                       name_values['b'] = begin.date() + " " + begin.time_of_day(true, false);
+                       name_values['e'] = end.date() + " " + end.time_of_day(true, false);
+                       name_values['i'] = kdm.cpl_id();
+
+                       kdms.push_back (KDMWithMetadataPtr(new DCPKDMWithMetadata(name_values, i->cinema.get(), i->cinema->emails, kdm)));
                }
-               write_files (screen_kdms, zip, output, container_name_format, filename_format, values, verbose);
+               write_files (kdms, zip, output, container_name_format, filename_format, verbose);
        } catch (FileError& e) {
                cerr << program_name << ": " << e.what() << " (" << e.file().string() << ")\n";
                exit (EXIT_FAILURE);
index ff5d1faf61976b43ed4d0bc36853cbfcf3eba458..31e6ebe79d0612ff4fedf2b776468b188a0e9a62 100644 (file)
@@ -83,37 +83,8 @@ CinemaDialog::CinemaDialog (wxWindow* parent, wxString title, string name, list<
                overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
        }
 
-       _offsets.push_back (Offset (_("UTC-11"),  -11,  0));
-       _offsets.push_back (Offset (_("UTC-10"),  -10,  0));
-       _offsets.push_back (Offset (_("UTC-9"),    -9,  0));
-       _offsets.push_back (Offset (_("UTC-8"),    -8,  0));
-       _offsets.push_back (Offset (_("UTC-7"),    -7,  0));
-       _offsets.push_back (Offset (_("UTC-6"),    -6,  0));
-       _offsets.push_back (Offset (_("UTC-5"),    -5,  0));
-       _offsets.push_back (Offset (_("UTC-4:30"), -4, 30));
-       _offsets.push_back (Offset (_("UTC-4"),    -4,  0));
-       _offsets.push_back (Offset (_("UTC-3:30"), -3, 30));
-       _offsets.push_back (Offset (_("UTC-3"),    -3,  0));
-       _offsets.push_back (Offset (_("UTC-2"),    -2,  0));
-       _offsets.push_back (Offset (_("UTC-1"),    -1,  0));
-       _offsets.push_back (Offset (_("UTC")  ,     0,  0));
-       _offsets.push_back (Offset (_("UTC+1"),     1,  0));
-       _offsets.push_back (Offset (_("UTC+2"),     2,  0));
-       _offsets.push_back (Offset (_("UTC+3"),     3,  0));
-       _offsets.push_back (Offset (_("UTC+4"),     4,  0));
-       _offsets.push_back (Offset (_("UTC+5"),     5,  0));
-       _offsets.push_back (Offset (_("UTC+5:30"),  5, 30));
-       _offsets.push_back (Offset (_("UTC+6"),     6,  0));
-       _offsets.push_back (Offset (_("UTC+7"),     7,  0));
-       _offsets.push_back (Offset (_("UTC+8"),     8,  0));
-       _offsets.push_back (Offset (_("UTC+9"),     9,  0));
-       _offsets.push_back (Offset (_("UTC+9:30"),  9, 30));
-       _offsets.push_back (Offset (_("UTC+10"),   10,  0));
-       _offsets.push_back (Offset (_("UTC+11"),   11,  0));
-       _offsets.push_back (Offset (_("UTC+12"),   12,  0));
-
        /* Default to UTC */
-       size_t sel = 13;
+       size_t sel = get_offsets (_offsets);
        for (size_t i = 0; i < _offsets.size(); ++i) {
                _utc_offset->Append (_offsets[i].name);
                if (_offsets[i].hour == utc_offset_hour && _offsets[i].minute == utc_offset_minute) {
index 9cb0a65dc151509c182b50df7752078ff3bf3195..d16b0ba9ce13d3f208b2060e2ac0ce8f78a8d8cb 100644 (file)
@@ -53,19 +53,5 @@ private:
        EditableList<std::string, EmailDialog>* _email_list;
        std::vector<std::string> _emails;
        wxChoice* _utc_offset;
-
-       struct Offset
-       {
-               Offset (wxString n, int h, int m)
-                       : name (n)
-                       , hour (h)
-                       , minute (m)
-               {}
-
-               wxString name;
-               int hour;
-               int minute;
-       };
-
        std::vector<Offset> _offsets;
 };
index eca34b5cfb1ff5901bcac03590ae78b74821d3ce..df6131fe1d05005b88631c6ed0460acd0ccd4df3 100644 (file)
@@ -23,7 +23,6 @@
 #include "static_text.h"
 #include "check_box.h"
 #include "lib/config.h"
-#include "lib/cinema_kdms.h"
 #include <boost/foreach.hpp>
 
 using std::list;
index 8682fe82f92a460aef24350e665875f981c8f2d4..d3bbf02c998e164ec4f317a00db7c80a04d9718c 100644 (file)
@@ -29,9 +29,8 @@
 #include "dcpomatic_button.h"
 #include "lib/film.h"
 #include "lib/screen.h"
-#include "lib/screen_kdm.h"
+#include "lib/kdm_with_metadata.h"
 #include "lib/job_manager.h"
-#include "lib/cinema_kdms.h"
 #include "lib/config.h"
 #include "lib/cinema.h"
 #include <libcxml/cxml.h>
@@ -150,7 +149,7 @@ KDMDialog::make_clicked ()
        shared_ptr<const Film> film = _film.lock ();
        DCPOMATIC_ASSERT (film);
 
-       list<shared_ptr<ScreenKDM> > screen_kdms;
+       list<KDMWithMetadataPtr> kdms;
        try {
                /* Start off by enabling forensic marking for all */
                optional<int> for_audio;
@@ -161,11 +160,13 @@ KDMDialog::make_clicked ()
                        /* Forensic mark up to this channel; disabled on channels greater than this */
                        for_audio = _output->forensic_mark_audio_up_to();
                }
-               screen_kdms = film->make_kdms (
-                       _screens->screens(), _cpl->cpl(), _timing->from(), _timing->until(), _output->formulation(),
-                       !_output->forensic_mark_video(), for_audio
-                       );
 
+               BOOST_FOREACH (shared_ptr<dcpomatic::Screen> i, _screens->screens()) {
+                       KDMWithMetadataPtr p = kdm_for_screen (film, _cpl->cpl(), i, _timing->from(), _timing->until(), _output->formulation(), !_output->forensic_mark_video(), for_audio);
+                       if (p) {
+                               kdms.push_back (p);
+                       }
+               }
        } catch (dcp::BadKDMDateError& e) {
                if (e.starts_too_early()) {
                        error_dialog (this, _("The KDM start period is before (or close to) the start of the signing certificate's validity period.  Use a later start time for this KDM."));
@@ -178,7 +179,7 @@ KDMDialog::make_clicked ()
                return;
        }
 
-       pair<shared_ptr<Job>, int> result = _output->make (screen_kdms, film->name(), _timing, bind (&KDMDialog::confirm_overwrite, this, _1));
+       pair<shared_ptr<Job>, int> result = _output->make (kdms, film->name(), bind (&KDMDialog::confirm_overwrite, this, _1));
        if (result.first) {
                JobManager::instance()->add (result.first);
        }
index d76a2735902d97923466f8ce1bac34b7ad391b1e..a345d0e963b62ed37dc6acde857f80998f11bd87 100644 (file)
@@ -20,7 +20,6 @@
 
 #include "lib/config.h"
 #include "lib/cinema.h"
-#include "lib/cinema_kdms.h"
 #include "lib/send_kdm_email_job.h"
 #include "kdm_output_panel.h"
 #include "kdm_timing_panel.h"
@@ -54,6 +53,7 @@ KDMOutputPanel::KDMOutputPanel (wxWindow* parent, bool interop)
        , _forensic_mark_audio_up_to (12)
 {
        wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, 0);
+       table->AddGrowableCol (1);
 
        add_label_to_sizer (table, this, _("KDM type"), true);
 
@@ -183,10 +183,10 @@ KDMOutputPanel::kdm_write_type_changed ()
 
 pair<shared_ptr<Job>, int>
 KDMOutputPanel::make (
-       list<shared_ptr<ScreenKDM> > screen_kdms, string name, KDMTimingPanel* timing, function<bool (boost::filesystem::path)> confirm_overwrite
+       list<KDMWithMetadataPtr> kdms, string name, function<bool (boost::filesystem::path)> confirm_overwrite
        )
 {
-       list<CinemaKDMs> const cinema_kdms = CinemaKDMs::collect (screen_kdms);
+       list<list<KDMWithMetadataPtr> > const cinema_kdms = collect (kdms);
 
        /* Decide whether to proceed */
 
@@ -200,8 +200,8 @@ KDMOutputPanel::make (
                }
 
                bool cinemas_with_no_email = false;
-               BOOST_FOREACH (CinemaKDMs i, cinema_kdms) {
-                       if (i.cinema->emails.empty ()) {
+               BOOST_FOREACH (list<KDMWithMetadataPtr> i, cinema_kdms) {
+                       if (i.front()->emails().empty()) {
                                cinemas_with_no_email = true;
                        }
                }
@@ -215,8 +215,8 @@ KDMOutputPanel::make (
 
                if (proceed && Config::instance()->confirm_kdm_email ()) {
                        list<string> emails;
-                       BOOST_FOREACH (CinemaKDMs i, cinema_kdms) {
-                               BOOST_FOREACH (string j, i.cinema->emails) {
+                       BOOST_FOREACH (list<KDMWithMetadataPtr> const& i, cinema_kdms) {
+                               BOOST_FOREACH (string j, i.front()->emails()) {
                                        emails.push_back (j);
                                }
                        }
@@ -240,36 +240,29 @@ KDMOutputPanel::make (
        shared_ptr<Job> job;
 
        try {
-               dcp::NameFormat::Map name_values;
-               name_values['f'] = name;
-               name_values['b'] = dcp::LocalTime(timing->from()).date() + " " + dcp::LocalTime(timing->from()).time_of_day(false, false);
-               name_values['e'] = dcp::LocalTime(timing->until()).date() + " " + dcp::LocalTime(timing->until()).time_of_day(false, false);
 
                if (_write_to->GetValue()) {
                        if (_write_flat->GetValue()) {
-                               written = ScreenKDM::write_files (
-                                       screen_kdms,
+                               written = write_files (
+                                       kdms,
                                        directory(),
                                        _filename_format->get(),
-                                       name_values,
                                        confirm_overwrite
                                        );
                        } else if (_write_folder->GetValue()) {
-                               written = CinemaKDMs::write_directories (
-                                       CinemaKDMs::collect (screen_kdms),
+                               written = write_directories (
+                                       collect (kdms),
                                        directory(),
                                        _container_name_format->get(),
                                        _filename_format->get(),
-                                       name_values,
                                        confirm_overwrite
                                        );
                        } else if (_write_zip->GetValue()) {
-                               written = CinemaKDMs::write_zip_files (
-                                       CinemaKDMs::collect (screen_kdms),
+                               written = write_zip_files (
+                                       collect (kdms),
                                        directory(),
                                        _container_name_format->get(),
                                        _filename_format->get(),
-                                       name_values,
                                        confirm_overwrite
                                        );
                        }
@@ -281,7 +274,6 @@ KDMOutputPanel::make (
                                        cinema_kdms,
                                        _container_name_format->get(),
                                        _filename_format->get(),
-                                       name_values,
                                        name
                                        )
                                );
index 7b931507170122d8ba7f78ffcfea864e26f2518c..0281b26d0d8253ab2d24d0fedd9aeee61f0cba15 100644 (file)
@@ -18,7 +18,7 @@
 
 */
 
-#include "lib/screen_kdm.h"
+#include "lib/kdm_with_metadata.h"
 #include "wx_util.h"
 #include "name_format_editor.h"
 #include <dcp/types.h>
@@ -52,9 +52,8 @@ public:
        }
 
        std::pair<boost::shared_ptr<Job>, int> make (
-               std::list<boost::shared_ptr<ScreenKDM> > screen_kdms,
+               std::list<KDMWithMetadataPtr > screen_kdms,
                std::string name,
-               KDMTimingPanel* timing,
                boost::function<bool (boost::filesystem::path)> confirm_overwrite
                );
 
index e477cdc1f1e19cb1799c5dd79e1974d90b33e184..ae6afdd08d46c5bf10dfb588ed48a4619da3a4bb 100644 (file)
@@ -23,7 +23,6 @@
 #include "static_text.h"
 #include "check_box.h"
 #include "lib/config.h"
-#include "lib/cinema_kdms.h"
 #include <boost/foreach.hpp>
 
 using std::list;
index f78a8c61762ba71fda5a59ebf19c63b2b42ad698..22d9f0db6a18938d045c6446feaa6f121a5630c8 100644 (file)
@@ -52,12 +52,14 @@ sources = """
           dcp_panel.cc
           dcpomatic_button.cc
           disk_warning_dialog.cc
+          dkdm_output_panel.cc
           drive_wipe_warning_dialog.cc
           email_dialog.cc
           image_sequence_dialog.cc
           isdcf_metadata_dialog.cc
           dcp_text_track_dialog.cc
           dir_picker_ctrl.cc
+          dkdm_dialog.cc
           dolby_doremi_certificate_panel.cc
           download_certificate_dialog.cc
           download_certificate_panel.cc
@@ -110,6 +112,8 @@ sources = """
           question_dialog.cc
           rating_dialog.cc
           qube_certificate_panel.cc
+          recipients_panel.cc
+          recipient_dialog.cc
           recreate_chain_dialog.cc
           repeat_dialog.cc
           report_problem_dialog.cc
index 28f79431a5147171626e1b45b90d51630b4420c9..6eef0d14795020f0cab6481e76e98ba9687e6567 100644 (file)
@@ -530,3 +530,40 @@ display_progress (wxString title, wxString task)
 
        return ok;
 }
+
+
+int
+get_offsets (vector<Offset>& offsets)
+{
+       offsets.push_back (Offset(_("UTC-11"),  -11,  0));
+       offsets.push_back (Offset(_("UTC-10"),  -10,  0));
+       offsets.push_back (Offset(_("UTC-9"),    -9,  0));
+       offsets.push_back (Offset(_("UTC-8"),    -8,  0));
+       offsets.push_back (Offset(_("UTC-7"),    -7,  0));
+       offsets.push_back (Offset(_("UTC-6"),    -6,  0));
+       offsets.push_back (Offset(_("UTC-5"),    -5,  0));
+       offsets.push_back (Offset(_("UTC-4:30"), -4, 30));
+       offsets.push_back (Offset(_("UTC-4"),    -4,  0));
+       offsets.push_back (Offset(_("UTC-3:30"), -3, 30));
+       offsets.push_back (Offset(_("UTC-3"),    -3,  0));
+       offsets.push_back (Offset(_("UTC-2"),    -2,  0));
+       offsets.push_back (Offset(_("UTC-1"),    -1,  0));
+       int utc = offsets.size();
+       offsets.push_back (Offset(_("UTC")  ,     0,  0));
+       offsets.push_back (Offset(_("UTC+1"),     1,  0));
+       offsets.push_back (Offset(_("UTC+2"),     2,  0));
+       offsets.push_back (Offset(_("UTC+3"),     3,  0));
+       offsets.push_back (Offset(_("UTC+4"),     4,  0));
+       offsets.push_back (Offset(_("UTC+5"),     5,  0));
+       offsets.push_back (Offset(_("UTC+5:30"),  5, 30));
+       offsets.push_back (Offset(_("UTC+6"),     6,  0));
+       offsets.push_back (Offset(_("UTC+7"),     7,  0));
+       offsets.push_back (Offset(_("UTC+8"),     8,  0));
+       offsets.push_back (Offset(_("UTC+9"),     9,  0));
+       offsets.push_back (Offset(_("UTC+9:30"),  9, 30));
+       offsets.push_back (Offset(_("UTC+10"),   10,  0));
+       offsets.push_back (Offset(_("UTC+11"),   11,  0));
+       offsets.push_back (Offset(_("UTC+12"),   12,  0));
+
+       return utc;
+}
index af25ce0f5e1851ba1ca1fdcf086ff6564b3f10da..8e0befba92d606a4da09cb5302c3b691ea19c69d 100644 (file)
@@ -88,6 +88,23 @@ extern double calculate_mark_interval (double start);
 extern bool display_progress (wxString title, wxString task);
 extern bool report_errors_from_last_job (wxWindow* parent);
 
+
+struct Offset
+{
+       Offset (wxString n, int h, int m)
+               : name (n)
+               , hour (h)
+               , minute (m)
+       {}
+
+       wxString name;
+       int hour;
+       int minute;
+};
+
+extern int get_offsets (std::vector<Offset>& offsets);
+
+
 extern void checked_set (FilePickerCtrl* widget, boost::filesystem::path value);
 extern void checked_set (wxDirPickerCtrl* widget, boost::filesystem::path value);
 extern void checked_set (wxSpinCtrl* widget, int value);
diff --git a/test/kdm_naming_test.cc b/test/kdm_naming_test.cc
new file mode 100644 (file)
index 0000000..35188d5
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+    Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "lib/cinema.h"
+#include "lib/screen.h"
+#include "lib/config.h"
+#include "lib/content_factory.h"
+#include "lib/film.h"
+#include "lib/kdm_with_metadata.h"
+#include "test.h"
+#include <boost/test/unit_test.hpp>
+#include <boost/shared_ptr.hpp>
+
+using std::list;
+using std::string;
+using std::vector;
+using boost::shared_ptr;
+using boost::optional;
+using boost::dynamic_pointer_cast;
+
+static
+bool
+confirm_overwrite (boost::filesystem::path)
+{
+       return true;
+}
+
+static shared_ptr<dcpomatic::Screen> cinema_a_screen_1;
+static shared_ptr<dcpomatic::Screen> cinema_a_screen_2;
+static shared_ptr<dcpomatic::Screen> cinema_b_screen_x;
+static shared_ptr<dcpomatic::Screen> cinema_b_screen_y;
+static shared_ptr<dcpomatic::Screen> cinema_b_screen_z;
+
+BOOST_AUTO_TEST_CASE (single_kdm_naming_test)
+{
+       Config* c = Config::instance();
+
+       dcp::Certificate cert = c->decryption_chain()->leaf();
+
+       /* Cinema A: UTC +4:30 */
+       shared_ptr<Cinema> cinema_a (new Cinema("Cinema A", list<string>(), "", 4, 30));
+       cinema_a_screen_1.reset(new dcpomatic::Screen("Screen 1", "", cert, vector<TrustedDevice>()));
+       cinema_a->add_screen (cinema_a_screen_1);
+       cinema_a_screen_2.reset(new dcpomatic::Screen("Screen 2", "", cert, vector<TrustedDevice>()));
+       cinema_a->add_screen (cinema_a_screen_2);
+       c->add_cinema (cinema_a);
+
+       /* Cinema B: UTC -1:00 */
+       shared_ptr<Cinema> cinema_b (new Cinema("Cinema B", list<string>(), "", -1, 0));
+       cinema_b_screen_x.reset(new dcpomatic::Screen("Screen X", "", cert, vector<TrustedDevice>()));
+       cinema_b->add_screen (cinema_b_screen_x);
+       cinema_b_screen_y.reset(new dcpomatic::Screen("Screen Y", "", cert, vector<TrustedDevice>()));
+       cinema_b->add_screen (cinema_b_screen_y);
+       cinema_b_screen_z.reset(new dcpomatic::Screen("Screen Z", "", cert, vector<TrustedDevice>()));
+       cinema_b->add_screen (cinema_b_screen_z);
+       c->add_cinema (cinema_a);
+
+       /* Film */
+       boost::filesystem::remove_all ("build/test/single_kdm_naming_test");
+       shared_ptr<Film> film = new_test_film2 ("single_kdm_naming_test");
+       film->set_name ("my_great_film");
+       film->examine_and_add_content (content_factory("test/data/flat_black.png").front());
+       BOOST_REQUIRE (!wait_for_jobs());
+       film->set_encrypted (true);
+       film->make_dcp ();
+       BOOST_REQUIRE (!wait_for_jobs());
+       film->write_metadata ();
+       vector<CPLSummary> cpls = film->cpls ();
+       BOOST_REQUIRE(cpls.size() == 1);
+
+       dcp::LocalTime from (cert.not_before());
+       from.add_months (2);
+       dcp::LocalTime until (cert.not_after());
+       until.add_months (-2);
+
+       string const from_string = from.date() + " " + from.time_of_day(true, false);
+       string const until_string = until.date() + " " + until.time_of_day(true, false);
+
+       boost::filesystem::path cpl = cpls.front().cpl_file;
+       KDMWithMetadataPtr kdm = kdm_for_screen (
+                       film,
+                       cpls.front().cpl_file,
+                       cinema_a_screen_1,
+                       boost::posix_time::time_from_string(from_string),
+                       boost::posix_time::time_from_string(until_string),
+                       dcp::MODIFIED_TRANSITIONAL_1,
+                       false,
+                       optional<int>()
+                       );
+
+       list<KDMWithMetadataPtr> kdms;
+       kdms.push_back (kdm);
+
+       write_files (
+               kdms,
+               boost::filesystem::path("build/test/single_kdm_naming_test"),
+               dcp::NameFormat("KDM %c - %s - %f - %b - %e"),
+               &confirm_overwrite
+               );
+
+       string from_time = from.time_of_day (true, false);
+       boost::algorithm::replace_all (from_time, ":", "-");
+       string until_time = until.time_of_day (true, false);
+       boost::algorithm::replace_all (until_time, ":", "-");
+
+       string const ref = String::compose("KDM_Cinema_A_-_Screen_1_-_my_great_film_-_%1_%2_-_%3_%4.xml", from.date(), from_time, until.date(), until_time);
+       BOOST_CHECK_MESSAGE (boost::filesystem::exists("build/test/single_kdm_naming_test/" + ref), "File " << ref << " not found");
+}
+
+
+BOOST_AUTO_TEST_CASE (directory_kdm_naming_test, * boost::unit_test::depends_on("single_kdm_naming_test"))
+{
+       using boost::filesystem::path;
+
+       dcp::Certificate cert = Config::instance()->decryption_chain()->leaf();
+
+       /* Film */
+       boost::filesystem::remove_all ("build/test/directory_kdm_naming_test");
+       shared_ptr<Film> film = new_test_film2 ("directory_kdm_naming_test");
+       film->set_name ("my_great_film");
+       film->examine_and_add_content (content_factory("test/data/flat_black.png").front());
+       BOOST_REQUIRE (!wait_for_jobs());
+       film->set_encrypted (true);
+       film->make_dcp ();
+       BOOST_REQUIRE (!wait_for_jobs());
+       film->write_metadata ();
+       vector<CPLSummary> cpls = film->cpls ();
+       BOOST_REQUIRE(cpls.size() == 1);
+
+       dcp::LocalTime from (cert.not_before());
+       from.add_months (2);
+       dcp::LocalTime until (cert.not_after());
+       until.add_months (-2);
+
+       string const from_string = from.date() + " " + from.time_of_day(true, false);
+       string const until_string = until.date() + " " + until.time_of_day(true, false);
+
+       list<shared_ptr<dcpomatic::Screen> > screens;
+       screens.push_back (cinema_a_screen_2);
+       screens.push_back (cinema_b_screen_x);
+       screens.push_back (cinema_a_screen_1);
+       screens.push_back (cinema_b_screen_z);
+
+       path const cpl = cpls.front().cpl_file;
+       string const cpl_id = cpls.front().cpl_id;
+
+       list<KDMWithMetadataPtr> kdms;
+       BOOST_FOREACH (shared_ptr<dcpomatic::Screen> i, screens) {
+               KDMWithMetadataPtr kdm = kdm_for_screen (
+                               film,
+                               cpls.front().cpl_file,
+                               i,
+                               boost::posix_time::time_from_string(from_string),
+                               boost::posix_time::time_from_string(until_string),
+                               dcp::MODIFIED_TRANSITIONAL_1,
+                               false,
+                               optional<int>()
+                               );
+
+               kdms.push_back (kdm);
+       }
+
+       write_directories (
+               collect(kdms),
+               path("build/test/directory_kdm_naming_test"),
+               dcp::NameFormat("%c - %s - %f - %b - %e"),
+               dcp::NameFormat("KDM %c - %s - %f - %b - %e - %i"),
+               &confirm_overwrite
+               );
+
+       string from_time = from.time_of_day (true, false);
+       boost::algorithm::replace_all (from_time, ":", "-");
+       string until_time = until.time_of_day (true, false);
+       boost::algorithm::replace_all (until_time, ":", "-");
+
+       path const base = "build/test/directory_kdm_naming_test";
+
+       path dir_a = String::compose("Cinema_A_-_%s_-_my_great_film_-_%1_%2_-_%3_%4", from.date(), from_time, until.date(), until_time);
+       BOOST_CHECK_MESSAGE (boost::filesystem::exists(base / dir_a), "Directory " << dir_a << " not found");
+       path dir_b = String::compose("Cinema_B_-_%s_-_my_great_film_-_%1_%2_-_%3_%4", from.date(), from_time, until.date(), until_time);
+       BOOST_CHECK_MESSAGE (boost::filesystem::exists(base / dir_b), "Directory " << dir_b << " not found");
+
+       path ref = String::compose("KDM_Cinema_A_-_Screen_2_-_my_great_film_-_%1_%2_-_%3_%4_-_%5.xml", from.date(), from_time, until.date(), until_time, cpl_id);
+       BOOST_CHECK_MESSAGE (boost::filesystem::exists(base / dir_a / ref), "File " << ref << " not found");
+
+       ref = String::compose("KDM_Cinema_B_-_Screen_X_-_my_great_film_-_%1_%2_-_%3_%4_-_%5.xml", from.date(), from_time, until.date(), until_time, cpl_id);
+       BOOST_CHECK_MESSAGE (boost::filesystem::exists(base / dir_b / ref), "File " << ref << " not found");
+
+       ref = String::compose("KDM_Cinema_A_-_Screen_1_-_my_great_film_-_%1_%2_-_%3_%4_-_%5.xml", from.date(), from_time, until.date(), until_time, cpl_id);
+       BOOST_CHECK_MESSAGE (boost::filesystem::exists(base / dir_a / ref), "File " << ref << " not found");
+
+       ref = String::compose("KDM_Cinema_B_-_Screen_Z_-_my_great_film_-_%1_%2_-_%3_%4_-_%5.xml", from.date(), from_time, until.date(), until_time, cpl_id);
+       BOOST_CHECK_MESSAGE (boost::filesystem::exists(base / dir_b / ref), "File " << ref << " not found");
+}
+
index 29f1e1db34ef884c44c80ab8d6722b03f18c27ee..1c3d750c32269fbddae7f57104e80d13aaba2236 100644 (file)
@@ -92,6 +92,7 @@ def build(bld):
                  isdcf_name_test.cc
                  j2k_bandwidth_test.cc
                  job_test.cc
+                 kdm_naming_test.cc
                  make_black_test.cc
                  optimise_stills_test.cc
                  pixel_formats_test.cc