Allow multiple recipients of KDM emails (#745).
authorCarl Hetherington <cth@carlh.net>
Fri, 13 Nov 2015 13:07:16 +0000 (13:07 +0000)
committerCarl Hetherington <cth@carlh.net>
Fri, 13 Nov 2015 13:07:16 +0000 (13:07 +0000)
15 files changed:
ChangeLog
src/lib/cinema.cc
src/lib/cinema.h
src/lib/cinema_kdms.cc
src/lib/emailer.cc
src/lib/emailer.h
src/lib/send_problem_report_job.cc
src/tools/dcpomatic_kdm_cli.cc
src/wx/cinema_dialog.cc
src/wx/cinema_dialog.h
src/wx/editable_list.h
src/wx/email_dialog.cc [new file with mode: 0644]
src/wx/email_dialog.h [new file with mode: 0644]
src/wx/screens_panel.cc
src/wx/wscript

index c0cce1c0368fb84b5ef3bd6a8dc557b153b3c3cf..a1c4e053ad5cbf98c13ee5160c16e9f913839d71 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2015-11-13  c.hetherington  <cth@carlh.net>
+
+       * Allow multiple recipients of KDM emails (#745).
+
 2015-11-12  Carl Hetherington  <cth@carlh.net>
 
        * Version 2.5.2 released.
index 11bc888da32127ef4a6e2cd917026496aaa206d9..ebd7160098df67d6657016427e09ca6037b47451 100644 (file)
 #include "screen.h"
 #include <libcxml/cxml.h>
 #include <libxml++/libxml++.h>
+#include <boost/foreach.hpp>
 
 using std::list;
+using std::string;
 using boost::shared_ptr;
 
 Cinema::Cinema (cxml::ConstNodePtr node)
        : name (node->string_child ("Name"))
-       , email (node->string_child ("Email"))
 {
-
+       BOOST_FOREACH (cxml::ConstNodePtr i, node->node_children("Email")) {
+               emails.push_back (i->content ());
+       }
 }
 
 /* This is necessary so that we can use shared_from_this in add_screen (which cannot be done from
@@ -48,10 +51,13 @@ void
 Cinema::as_xml (xmlpp::Element* parent) const
 {
        parent->add_child("Name")->add_child_text (name);
-       parent->add_child("Email")->add_child_text (email);
 
-       for (list<shared_ptr<Screen> >::const_iterator i = _screens.begin(); i != _screens.end(); ++i) {
-               (*i)->as_xml (parent->add_child ("Screen"));
+       BOOST_FOREACH (string i, emails) {
+               parent->add_child("Email")->add_child_text (i);
+       }
+
+       BOOST_FOREACH (shared_ptr<Screen> i, _screens) {
+               i->as_xml (parent->add_child ("Screen"));
        }
 }
 
index 3bf958d82b451d5f49e0183730c5ef2a22d864dd..aec4c83eca5ac25346a9754d62f69a61700565e6 100644 (file)
@@ -33,15 +33,15 @@ class Screen;
 /** @class Cinema
  *  @brief A description of a Cinema for KDM generation.
  *
- *  This is a cinema name, contact email address and a list of
+ *  This is a cinema name, contact email addresses and a list of
  *  Screen objects.
  */
 class Cinema : public boost::enable_shared_from_this<Cinema>
 {
 public:
-       Cinema (std::string const & n, std::string const & e)
+       Cinema (std::string const & n, std::list<std::string> const & e)
                : name (n)
-               , email (e)
+               , emails (e)
        {}
 
        Cinema (cxml::ConstNodePtr);
@@ -54,7 +54,7 @@ public:
        void remove_screen (boost::shared_ptr<Screen>);
 
        std::string name;
-       std::string email;
+       std::list<std::string> emails;
        std::list<boost::shared_ptr<Screen> > screens () const {
                return _screens;
        }
index eb71b3202747ce862ca0977993749a7aed24df54..15aaaa731316b6c8ee0eeda6d0ce09ca6ab8c3f6 100644 (file)
@@ -152,7 +152,7 @@ CinemaKDMs::email (
                }
                boost::algorithm::replace_all (body, "$SCREENS", screens.str().substr (0, screens.str().length() - 2));
 
-               Emailer email (config->kdm_from(), i.cinema->email, subject, body);
+               Emailer email (config->kdm_from(), i.cinema->emails, subject, body);
 
                if (!config->kdm_cc().empty ()) {
                        email.add_cc (config->kdm_cc ());
index 916d1718248a08cf5921204469a723979d45d555..885171e2fac3408a153fd57276e0e090d89a08a4 100644 (file)
@@ -38,7 +38,7 @@ using std::cout;
 using std::pair;
 using boost::shared_ptr;
 
-Emailer::Emailer (string from, string to, string subject, string body)
+Emailer::Emailer (string from, list<string> to, string subject, string body)
        : _from (from)
        , _to (to)
        , _subject (subject)
@@ -106,7 +106,7 @@ Emailer::send (shared_ptr<Job> job)
        stringstream email;
 
        email << "Date: " << date_buffer << "\r\n"
-             << "To: " << _to << "\r\n"
+             << "To: " << address_list (_to) << "\r\n"
              << "From: " << _from << "\r\n";
 
        if (!_cc.empty ()) {
@@ -194,7 +194,10 @@ Emailer::send (shared_ptr<Job> job)
 
        curl_easy_setopt (curl, CURLOPT_MAIL_FROM, _from.c_str());
 
-       struct curl_slist* recipients = curl_slist_append (0, _to.c_str());
+       struct curl_slist* recipients = 0;
+       BOOST_FOREACH (string i, _to) {
+               curl_slist_append (recipients, i.c_str());
+       }
        BOOST_FOREACH (string i, _cc) {
                recipients = curl_slist_append (recipients, i.c_str());
        }
@@ -251,7 +254,7 @@ Emailer::send (shared_ptr<Job> job)
                CURLMcode mc = curl_multi_fdset (mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);
 
                if (mc != CURLM_OK) {
-                       throw KDMError (String::compose ("Failed to send KDM email to %1", _to));
+                       throw KDMError (String::compose ("Failed to send KDM email to %1", address_list (_to)));
                }
 
                int rc;
index 89993ca48f4923cd6668e29aa923370102c13a9f..c8ebac7b6c1a1fac883d2a463005349f05fba727 100644 (file)
@@ -23,7 +23,7 @@
 class Emailer
 {
 public:
-       Emailer (std::string from, std::string to, std::string subject, std::string body);
+       Emailer (std::string from, std::list<std::string> to, std::string subject, std::string body);
 
        void add_cc (std::string cc);
        void add_bcc (std::string bcc);
@@ -38,11 +38,12 @@ public:
        size_t get_data (void* ptr, size_t size, size_t nmemb);
        int debug (CURL* curl, curl_infotype type, char* data, size_t size);
 
-private:
        static std::string address_list (std::list<std::string> addresses);
 
+private:
+
        std::string _from;
-       std::string _to;
+       std::list<std::string> _to;
        std::string _subject;
        std::string _body;
        std::list<std::string> _cc;
index f0c34f590bca5f823dadabbfdc70863d9d5a84a1..8142b173c3d42e89171ed6fbafb5b5e7c1e79aed 100644 (file)
@@ -81,7 +81,10 @@ SendProblemReportJob::run ()
                add_file (body, "metadata.xml");
        }
 
-       Emailer emailer (_from, "carl@dcpomatic.com", "DCP-o-matic problem report", body);
+       list<string> to;
+       to.push_back ("carl@dcpomatic.com");
+
+       Emailer emailer (_from, to, "DCP-o-matic problem report", body);
        emailer.send (shared_from_this ());
 
        set_progress (1);
index aa3022c30a5c205edb037732b62befc9ee108f46..c49642c8e9459b5c390e1b4fe3725d5437e26b8e 100644 (file)
@@ -27,6 +27,7 @@
 #include "lib/cinema_kdms.h"
 #include "lib/config.h"
 #include "lib/exceptions.h"
+#include "lib/emailer.h"
 #include "lib/safe_stringstream.h"
 #include <dcp/certificate.h>
 #include <getopt.h>
@@ -189,7 +190,7 @@ int main (int argc, char* argv[])
        if (cinemas) {
                list<boost::shared_ptr<Cinema> > cinemas = Config::instance()->cinemas ();
                for (list<boost::shared_ptr<Cinema> >::const_iterator i = cinemas.begin(); i != cinemas.end(); ++i) {
-                       cout << (*i)->name << " (" << (*i)->email << ")\n";
+                       cout << (*i)->name << " (" << Emailer::address_list ((*i)->emails) << ")\n";
                }
                exit (EXIT_SUCCESS);
        }
@@ -263,7 +264,11 @@ int main (int argc, char* argv[])
 
                list<shared_ptr<Cinema> > cinemas = Config::instance()->cinemas ();
                list<shared_ptr<Cinema> >::const_iterator i = cinemas.begin();
-               while (i != cinemas.end() && (*i)->name != cinema_name && (*i)->email != cinema_name) {
+               while (
+                       i != cinemas.end() &&
+                       (*i)->name != cinema_name &&
+                       find ((*i)->emails.begin(), (*i)->emails.end(), cinema_name) == (*i)->emails.end()) {
+
                        ++i;
                }
 
index a54dd733577b00b4e45a0bb62e4b5ac2de7eef27..e3dff8a488278a6a3bcd23dfe3b35c7a82dee2c1 100644 (file)
 
 #include "cinema_dialog.h"
 #include "wx_util.h"
+#include <boost/foreach.hpp>
 
 using std::string;
+using std::vector;
+using std::copy;
+using std::back_inserter;
+using std::list;
+using std::cout;
+using boost::bind;
 
-CinemaDialog::CinemaDialog (wxWindow* parent, string title, string name, string email)
-       : TableDialog (parent, std_to_wx (title), 2, 1, true)
+static string
+column (string s)
 {
-       add (_("Name"), true);
-       _name = add (new wxTextCtrl (this, wxID_ANY, std_to_wx (name), wxDefaultPosition, wxSize (256, -1)));
+       return s;
+}
+
+CinemaDialog::CinemaDialog (wxWindow* parent, string title, string name, list<string> emails)
+       : wxDialog (parent, wxID_ANY, std_to_wx (title))
+{
+       wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
+       SetSizer (overall_sizer);
+
+       wxGridBagSizer* sizer = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+       int r = 0;
+
+       add_label_to_sizer (sizer, this, _("Name"), true, wxGBPosition (r, 0));
+       _name = new wxTextCtrl (this, wxID_ANY, std_to_wx (name), wxDefaultPosition, wxSize (500, -1));
+       sizer->Add (_name, wxGBPosition (r, 1));
+       ++r;
+
+       add_label_to_sizer (sizer, this, _("Email addresses for KDM delivery"), true, wxGBPosition (r, 0), wxGBSpan (1, 2));
+       ++r;
+
+       copy (emails.begin(), emails.end(), back_inserter (_emails));
+
+       vector<string> columns;
+       columns.push_back (wx_to_std (_("Address")));
+       _email_list = new EditableList<string, EmailDialog> (
+               this, columns, bind (&CinemaDialog::get_emails, this), bind (&CinemaDialog::set_emails, this, _1), bind (&column, _1)
+               );
+
+       sizer->Add (_email_list, wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND);
+       ++r;
 
-       add (_("Email address for KDM delivery"), true);
-       _email = add (new wxTextCtrl (this, wxID_ANY, std_to_wx (email), wxDefaultPosition, wxSize (256, -1)));
+       overall_sizer->Add (sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
 
-       layout ();
+       wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
+       if (buttons) {
+               overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
+       }
+
+       overall_sizer->Layout ();
+       overall_sizer->SetSizeHints (this);
 }
 
 string
@@ -40,8 +80,22 @@ CinemaDialog::name () const
        return wx_to_std (_name->GetValue());
 }
 
-string
-CinemaDialog::email () const
+void
+CinemaDialog::set_emails (vector<string> e)
+{
+       _emails = e;
+}
+
+vector<string>
+CinemaDialog::get_emails () const
+{
+       return _emails;
+}
+
+list<string>
+CinemaDialog::emails () const
 {
-       return wx_to_std (_email->GetValue());
+       list<string> e;
+       copy (_emails.begin(), _emails.end(), back_inserter (e));
+       return e;
 }
index 56beaa5bd1a8cb94d2d6b7af9f3245cd941f5ad8..7d27bd94b473492cfc8dd90fc605bf20f19a3977 100644 (file)
 
 */
 
-#include <wx/wx.h>
 #include "table_dialog.h"
+#include "editable_list.h"
+#include "email_dialog.h"
+#include <wx/wx.h>
+#include <list>
+#include <vector>
 
-class CinemaDialog : public TableDialog
+class CinemaDialog : public wxDialog
 {
 public:
-       CinemaDialog (wxWindow *, std::string, std::string name = "", std::string email = "");
+       CinemaDialog (wxWindow *, std::string, std::string name = "", std::list<std::string> emails = std::list<std::string> ());
 
        std::string name () const;
-       std::string email () const;
+       std::list<std::string> emails () const;
 
 private:
+       std::vector<std::string> get_emails () const;
+       void set_emails (std::vector<std::string>);
+
        wxTextCtrl* _name;
-       wxTextCtrl* _email;
+       EditableList<std::string, EmailDialog>* _email_list;
+       std::vector<std::string> _emails;
 };
index be79f67e66597dd2e437ab16c51b55c50017dd1a..bb749a4a44bc76a2de44cd5dc61b7b6b5351e734 100644 (file)
 
 */
 
+#include "wx_util.h"
 #include <wx/wx.h>
 #include <wx/listctrl.h>
+#include <boost/function.hpp>
+#include <vector>
 
+/** @param T type of things being edited.
+ *  @param S dialog to edit a thing.
+ */
 template<class T, class S>
 class EditableList : public wxPanel
 {
@@ -78,8 +84,9 @@ public:
                _list->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&EditableList::selection_changed, this));
                _list->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&EditableList::selection_changed, this));
                _list->Bind (wxEVT_SIZE, boost::bind (&EditableList::resized, this, _1));
-               selection_changed ();
 
+               refresh ();
+               selection_changed ();
        }
 
        void refresh ()
diff --git a/src/wx/email_dialog.cc b/src/wx/email_dialog.cc
new file mode 100644 (file)
index 0000000..fa9e319
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    Copyright (C) 2015 Carl Hetherington <cth@carlh.net>
+
+    This program 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.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "email_dialog.h"
+#include "wx_util.h"
+
+using std::string;
+using boost::shared_ptr;
+
+EmailDialog::EmailDialog (wxWindow* parent)
+       : TableDialog (parent, _("Email address"), 2, 1, true)
+{
+       add (_("Email address"), true);
+       _email = add (new wxTextCtrl (this, wxID_ANY, wxT (""), wxDefaultPosition, wxSize (400, -1)));
+
+       layout ();
+}
+
+void
+EmailDialog::set (string address)
+{
+       _email->SetValue (std_to_wx (address));
+}
+
+string
+EmailDialog::get () const
+{
+       return wx_to_std (_email->GetValue ());
+}
diff --git a/src/wx/email_dialog.h b/src/wx/email_dialog.h
new file mode 100644 (file)
index 0000000..698cbef
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+    Copyright (C) 2015 Carl Hetherington <cth@carlh.net>
+
+    This program 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.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "table_dialog.h"
+
+class EmailDialog : public TableDialog
+{
+public:
+       EmailDialog (wxWindow *);
+
+       void set (std::string);
+       std::string get () const;
+
+private:
+       wxTextCtrl* _email;
+};
index 5bdfe6c6ca061fc2f75f0ec33e9a05941626a6f4..4f8e3ad4da21956e909099e2d9d5fc131381c881 100644 (file)
@@ -171,7 +171,7 @@ ScreensPanel::add_cinema_clicked ()
 {
        CinemaDialog* d = new CinemaDialog (this, "Add Cinema");
        if (d->ShowModal () == wxID_OK) {
-               shared_ptr<Cinema> c (new Cinema (d->name(), d->email()));
+               shared_ptr<Cinema> c (new Cinema (d->name(), d->emails()));
                Config::instance()->add_cinema (c);
                add_cinema (c);
        }
@@ -188,10 +188,10 @@ ScreensPanel::edit_cinema_clicked ()
 
        pair<wxTreeItemId, shared_ptr<Cinema> > c = selected_cinemas().front();
 
-       CinemaDialog* d = new CinemaDialog (this, "Edit cinema", c.second->name, c.second->email);
+       CinemaDialog* d = new CinemaDialog (this, "Edit cinema", c.second->name, c.second->emails);
        if (d->ShowModal () == wxID_OK) {
                c.second->name = d->name ();
-               c.second->email = d->email ();
+               c.second->emails = d->emails ();
                _targets->SetItemText (c.first, std_to_wx (d->name()));
                Config::instance()->changed ();
        }
index 3b61eb5c6e87428eaec9d6d8be49f66795790bf6..821043b403f6c3deb94ef28cd496fa6768ac81fe 100644 (file)
@@ -39,6 +39,7 @@ sources = """
           content_properties_dialog.cc
           content_sub_panel.cc
           dcp_panel.cc
+          email_dialog.cc
           image_sequence_dialog.cc
           isdcf_metadata_dialog.cc
           dir_picker_ctrl.cc