return libdcp::Size ();
}
-void
+list<libdcp::KDM>
Film::make_kdms (
list<shared_ptr<Screen> > screens,
boost::posix_time::ptime from,
- boost::posix_time::ptime until,
- string directory
+ boost::posix_time::ptime until
) const
{
boost::filesystem::path const sd = Config::instance()->signer_chain_directory ();
throw KDMError (_("More than one possible DCP to make KDM for"));
}
+ list<libdcp::KDM> kdms;
+
for (list<shared_ptr<Screen> >::iterator i = screens.begin(); i != screens.end(); ++i) {
libdcp::DCP dcp (dcps.front ());
string const issue_date = libdcp::tm_to_string (tm);
dcp.cpls().front()->set_mxf_keys (key ());
-
- libdcp::KDM kdm (
- dcp.cpls().front(), signer, (*i)->certificate, from, until, "DCP-o-matic", issue_date
- );
- boost::filesystem::path out = directory;
- out /= tidy_for_filename ((*i)->cinema->name) + "_" + tidy_for_filename ((*i)->name) + ".kdm.xml";
- kdm.as_xml (out);
+ kdms.push_back (libdcp::KDM (dcp.cpls().front(), signer, (*i)->certificate, from, until, "DCP-o-matic", issue_date));
}
+
+ return kdms;
}
#include <boost/enable_shared_from_this.hpp>
#include <boost/filesystem.hpp>
#include <libdcp/key.h>
+#include <libdcp/kdm.h>
#include "util.h"
#include "types.h"
#include "dci_metadata.h"
bool has_subtitles () const;
OutputVideoFrame best_video_frame_rate () const;
- void make_kdms (
+ std::list<libdcp::KDM> make_kdms (
std::list<boost::shared_ptr<Screen> >,
boost::posix_time::ptime from,
- boost::posix_time::ptime until,
- std::string directory
+ boost::posix_time::ptime until
) const;
libdcp::Key key () const {
#include <libpostproc/postprocess.h>
#include <libavutil/pixfmt.h>
}
-#include <curl/curl.h>
#include "util.h"
#include "exceptions.h"
#include "scaler.h"
return t;
}
-
-struct EmailState
-{
- string message;
- int done;
-};
-
-static size_t
-send_email_function (void* ptr, size_t size, size_t nmemb, void* userdata)
-{
- EmailState* state = reinterpret_cast<EmailState*> (userdata);
-
- int const now = min (size * nmemb, state->message.length() - state->done);
-
- memcpy (ptr, state->message.c_str() + state->done, now);
- state->done += now;
-
- return now;
-}
-
-bool
-send_email (string from, string to, string message)
-{
- CURL* curl = curl_easy_init ();
- if (!curl) {
- return true;
- }
-
- string const url = "smtp://" + Config::instance()->mail_server();
-
- curl_easy_setopt (curl, CURLOPT_URL, url.c_str ());
- curl_easy_setopt (curl, CURLOPT_MAIL_FROM, from.c_str ());
- struct curl_slist* recipients = 0;
- recipients = curl_slist_append (recipients, to.c_str ());
- curl_easy_setopt (curl, CURLOPT_READFUNCTION, send_email_function);
-
- EmailState state;
- state.message = message;
- state.done = 0;
- curl_easy_setopt (curl, CURLOPT_READDATA, &state);
-
- if (curl_easy_perform (curl) != CURLE_OK) {
- return true;
- }
-
- curl_slist_free_all (recipients);
- curl_easy_cleanup (curl);
-
- return false;
-}
#include <wx/generic/aboutdlgg.h>
#include <wx/stdpaths.h>
#include <wx/cmdline.h>
+#include <quickmail.h>
+#include <zip.h>
#include "wx/film_viewer.h"
#include "wx/film_editor.h"
#include "wx/job_manager_view.h"
#include "lib/job_manager.h"
#include "lib/transcode_job.h"
#include "lib/exceptions.h"
+#include "lib/cinema.h"
using std::cout;
using std::string;
m->Append (help, _("&Help"));
}
+struct ScreenKDM
+{
+ ScreenKDM (shared_ptr<Screen> s, libdcp::KDM k)
+ : screen (s)
+ , kdm (k)
+ {}
+
+ shared_ptr<Screen> screen;
+ libdcp::KDM kdm;
+};
+
+/* Not complete but sufficient for our purposes (we're using
+ ScreenKDM in a list where all the screens will be unique).
+*/
+bool operator== (ScreenKDM const & a, ScreenKDM const & b)
+{
+ return a.screen == b.screen;
+}
+
class Frame : public wxFrame
{
public:
}
KDMDialog* d = new KDMDialog (this);
- if (d->ShowModal () == wxID_OK) {
- try {
- film->make_kdms (
- d->screens (),
- d->from (),
- d->until (),
- d->directory ()
- );
- } catch (KDMError& e) {
- error_dialog (this, e.what ());
- }
+ if (d->ShowModal () != wxID_OK) {
+ d->Destroy ();
+ return;
}
+ try {
+ list<shared_ptr<Screen> > screens = d->screens ();
+ list<libdcp::KDM> kdms = film->make_kdms (
+ screens,
+ d->from (),
+ d->until ()
+ );
+
+ list<ScreenKDM> screen_kdms;
+
+ list<shared_ptr<Screen> >::iterator i = screens.begin ();
+ list<libdcp::KDM>::iterator j = kdms.begin ();
+ while (i != screens.end() && j != kdms.end ()) {
+ screen_kdms.push_back (ScreenKDM (*i, *j));
+ ++i;
+ ++j;
+ }
+
+ if (d->write_to ()) {
+ /* Write KDMs to the specified directory */
+ for (list<ScreenKDM>::iterator i = screen_kdms.begin(); i != screen_kdms.end(); ++i) {
+ boost::filesystem::path out = d->directory ();
+ out /= tidy_for_filename (i->screen->cinema->name) + "_" + tidy_for_filename (i->screen->name) + ".kdm.xml";
+ i->kdm.as_xml (out);
+ }
+ } else {
+ while (!screen_kdms.empty ()) {
+
+ /* Get all the screens from a single cinema */
+
+ shared_ptr<Cinema> cinema;
+ list<ScreenKDM> cinema_screen_kdms;
+
+ list<ScreenKDM>::iterator i = screen_kdms.begin ();
+ cinema = i->screen->cinema;
+ cinema_screen_kdms.push_back (*i);
+ list<ScreenKDM>::iterator j = i;
+ ++i;
+ screen_kdms.remove (*j);
+
+ while (i != screen_kdms.end ()) {
+ if (i->screen->cinema == cinema) {
+ cinema_screen_kdms.push_back (*i);
+ list<ScreenKDM>::iterator j = i;
+ ++i;
+ screen_kdms.remove (*j);
+ } else {
+ ++i;
+ }
+ }
+
+ /* Make a ZIP file of this cinema's KDMs */
+
+ boost::filesystem::path zip_file = boost::filesystem::temp_directory_path ();
+ zip_file /= boost::filesystem::unique_path().string() + ".zip";
+ struct zip* zip = zip_open (zip_file.c_str(), ZIP_CREATE | ZIP_EXCL, 0);
+ if (!zip) {
+ throw FileError ("could not create ZIP file", zip_file);
+ }
+
+ list<shared_ptr<string> > kdm_strings;
+
+ for (list<ScreenKDM>::const_iterator i = cinema_screen_kdms.begin(); i != cinema_screen_kdms.end(); ++i) {
+ shared_ptr<string> kdm (new string (i->kdm.as_xml ()));
+ kdm_strings.push_back (kdm);
+
+ struct zip_source* source = zip_source_buffer (zip, kdm->c_str(), kdm->length(), 0);
+ if (!source) {
+ throw StringError ("could not create ZIP source");
+ }
+
+ string const name = tidy_for_filename (i->screen->cinema->name) + "_" +
+ tidy_for_filename (i->screen->name) + ".kdm.xml";
+
+ if (zip_add (zip, name.c_str(), source) == -1) {
+ throw StringError ("failed to add KDM to ZIP archive");
+ }
+ }
+
+ if (zip_close (zip) == -1) {
+ throw StringError ("failed to close ZIP archive");
+ }
+
+ /* Send email */
+
+ quickmail_initialize ();
+ quickmail mail = quickmail_create (Config::instance()->kdm_from().c_str(), "KDM delivery");
+ quickmail_add_to (mail, cinema->email.c_str ());
+
+ string body = Config::instance()->kdm_email().c_str();
+ boost::algorithm::replace_all (body, "$DCP_NAME", film->dcp_name ());
+
+ quickmail_set_body (mail, body.c_str());
+ quickmail_add_attachment_file (mail, zip_file.c_str());
+ char const* error = quickmail_send (mail, Config::instance()->mail_server().c_str(), 25, "", "");
+ if (error) {
+ quickmail_destroy (mail);
+ throw StringError (String::compose ("Failed to send KDM email (%1)", error));
+ }
+ quickmail_destroy (mail);
+
+ film->log()->log (String::compose ("Send KDM email to %1", cinema->email));
+ }
+ }
+
+ } catch (KDMError& e) {
+ error_dialog (this, e.what ());
+ }
+
d->Destroy ();
}
if not bld.env.DISABLE_GUI:
for t in ['dcpomatic', 'dcpomatic_batch', 'dcpomatic_server']:
obj = bld(features = 'cxx cxxprogram')
- obj.uselib = 'DCP OPENJPEG AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC CXML WXWIDGETS'
+ obj.uselib = 'DCP OPENJPEG AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC CXML WXWIDGETS ZIP QUICKMAIL'
if bld.env.STATIC:
obj.uselib += ' GTK'
obj.includes = ['..']
{
return wx_to_std (_folder->GetPath ());
}
+
+bool
+KDMDialog::write_to () const
+{
+ return _write_to->GetValue ();
+}
boost::posix_time::ptime from () const;
boost::posix_time::ptime until () const;
std::string directory () const;
+ bool write_to () const;
private:
void add_cinema (boost::shared_ptr<Cinema>);
conf.env.STLIB_POSTPROC = ['postproc']
conf.env.STLIB_SWRESAMPLE = ['swresample']
conf.env.STLIB_OPENJPEG = ['openjpeg']
+ conf.env.STLIB_QUICKMAIL = ['quickmail']
+ else:
+ conf.check_cxx(fragment="""
+ #include <quickmail.h>
+ int main(void) { quickmail_initialize (); }
+ """,
+ mandatory=True,
+ msg='Checking for quickmail',
+ libpath='/usr/local/lib',
+ lib='quickmail',
+ uselib_store='QUICKMAIL')
# Dependencies which are always dynamically linked
conf.check_cfg(package='sndfile', args='--cflags --libs', uselib_store='SNDFILE', mandatory=True)
conf.check_cfg(package='libxml++-2.6', args='--cflags --libs', uselib_store='XML++', mandatory=True)
conf.check_cfg(package='libcurl', args='--cflags --libs', uselib_store='CURL', mandatory=True)
+ conf.check_cxx(fragment="""
+ #include <zip.h>
+ int main(void) { zip_open ("foo", 0, 0); }
+ """,
+ mandatory=True,
+ msg='Checking for libzip',
+ lib='zip',
+ uselib_store='ZIP')
+
conf.check_cxx(fragment="""
#include <boost/version.hpp>\n
#if BOOST_VERSION < 104500\n