2 Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
21 #include "config_dialog.h"
22 #include "nag_dialog.h"
30 using boost::optional;
31 using boost::shared_ptr;
32 using boost::function;
41 Page::Page (wxSize panel_size, int border)
44 , _panel_size (panel_size)
45 , _window_exists (false)
47 _config_connection = Config::instance()->Changed.connect (bind (&Page::config_changed_wrapper, this));
51 Page::create_window (wxWindow* parent)
53 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
54 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
58 _window_exists = true;
61 _panel->Bind (wxEVT_DESTROY, bind (&Page::window_destroyed, this));
67 Page::config_changed_wrapper ()
75 Page::window_destroyed ()
77 _window_exists = false;
81 StockPage::StockPage (Kind kind, wxSize panel_size, int border)
82 : wxStockPreferencesPage (kind)
83 , Page (panel_size, border)
89 StockPage::CreateWindow (wxWindow* parent)
91 return create_window (parent);
94 StandardPage::StandardPage (wxSize panel_size, int border)
95 : Page (panel_size, border)
101 StandardPage::CreateWindow (wxWindow* parent)
103 return create_window (parent);
106 GeneralPage::GeneralPage (wxSize panel_size, int border)
107 : StockPage (Kind_General, panel_size, border)
113 GeneralPage::add_language_controls (wxGridBagSizer* table, int& r)
115 _set_language = new wxCheckBox (_panel, wxID_ANY, _("Set language"));
116 table->Add (_set_language, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
117 _language = new wxChoice (_panel, wxID_ANY);
118 vector<pair<string, string> > languages;
119 languages.push_back (make_pair ("Čeština", "cs_CZ"));
120 languages.push_back (make_pair ("汉语/漢語", "zh_CN"));
121 languages.push_back (make_pair ("Dansk", "da_DK"));
122 languages.push_back (make_pair ("Deutsch", "de_DE"));
123 languages.push_back (make_pair ("English", "en_GB"));
124 languages.push_back (make_pair ("Español", "es_ES"));
125 languages.push_back (make_pair ("Français", "fr_FR"));
126 languages.push_back (make_pair ("Italiano", "it_IT"));
127 languages.push_back (make_pair ("Nederlands", "nl_NL"));
128 languages.push_back (make_pair ("Русский", "ru_RU"));
129 languages.push_back (make_pair ("Polski", "pl_PL"));
130 languages.push_back (make_pair ("Português europeu", "pt_PT"));
131 languages.push_back (make_pair ("Português do Brasil", "pt_BR"));
132 languages.push_back (make_pair ("Svenska", "sv_SE"));
133 languages.push_back (make_pair ("Slovenský jazyk", "sk_SK"));
134 languages.push_back (make_pair ("українська мова", "uk_UA"));
135 checked_set (_language, languages);
136 table->Add (_language, wxGBPosition (r, 1));
139 wxStaticText* restart = add_label_to_sizer (
140 table, _panel, _("(restart DCP-o-matic to see language changes)"), false, wxGBPosition (r, 0), wxGBSpan (1, 2)
142 wxFont font = restart->GetFont();
143 font.SetStyle (wxFONTSTYLE_ITALIC);
144 font.SetPointSize (font.GetPointSize() - 1);
145 restart->SetFont (font);
148 _set_language->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::set_language_changed, this));
149 _language->Bind (wxEVT_CHOICE, bind (&GeneralPage::language_changed, this));
153 GeneralPage::add_play_sound_controls (wxGridBagSizer* table, int& r)
155 _sound = new wxCheckBox (_panel, wxID_ANY, _("Play sound via"));
156 table->Add (_sound, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
157 _sound_output = new wxChoice (_panel, wxID_ANY);
158 table->Add (_sound_output, wxGBPosition (r, 1));
161 RtAudio audio (DCPOMATIC_RTAUDIO_API);
162 for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) {
163 RtAudio::DeviceInfo dev = audio.getDeviceInfo (i);
164 if (dev.probed && dev.outputChannels > 0) {
165 _sound_output->Append (std_to_wx (dev.name));
169 _sound->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::sound_changed, this));
170 _sound_output->Bind (wxEVT_CHOICE, bind (&GeneralPage::sound_output_changed, this));
174 GeneralPage::add_update_controls (wxGridBagSizer* table, int& r)
176 _check_for_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for updates on startup"));
177 table->Add (_check_for_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
180 _check_for_test_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for testing updates on startup"));
181 table->Add (_check_for_test_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
184 _check_for_updates->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::check_for_updates_changed, this));
185 _check_for_test_updates->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::check_for_test_updates_changed, this));
189 GeneralPage::config_changed ()
191 Config* config = Config::instance ();
193 checked_set (_set_language, static_cast<bool>(config->language()));
195 /* Backwards compatibility of config file */
197 map<string, string> compat_map;
198 compat_map["fr"] = "fr_FR";
199 compat_map["it"] = "it_IT";
200 compat_map["es"] = "es_ES";
201 compat_map["sv"] = "sv_SE";
202 compat_map["de"] = "de_DE";
203 compat_map["nl"] = "nl_NL";
204 compat_map["ru"] = "ru_RU";
205 compat_map["pl"] = "pl_PL";
206 compat_map["da"] = "da_DK";
207 compat_map["pt"] = "pt_PT";
208 compat_map["sk"] = "sk_SK";
209 compat_map["cs"] = "cs_CZ";
210 compat_map["uk"] = "uk_UA";
212 string lang = config->language().get_value_or ("en_GB");
213 if (compat_map.find (lang) != compat_map.end ()) {
214 lang = compat_map[lang];
217 checked_set (_language, lang);
219 checked_set (_check_for_updates, config->check_for_updates ());
220 checked_set (_check_for_test_updates, config->check_for_test_updates ());
222 checked_set (_sound, config->sound ());
224 optional<string> const current_so = get_sound_output ();
225 optional<string> configured_so;
227 if (config->sound_output()) {
228 configured_so = config->sound_output().get();
230 /* No configured output means we should use the default */
231 RtAudio audio (DCPOMATIC_RTAUDIO_API);
233 configured_so = audio.getDeviceInfo(audio.getDefaultOutputDevice()).name;
234 } catch (RtAudioError& e) {
235 /* Probably no audio devices at all */
239 if (configured_so && current_so != configured_so) {
240 /* Update _sound_output with the configured value */
242 while (i < _sound_output->GetCount()) {
243 if (_sound_output->GetString(i) == std_to_wx(*configured_so)) {
244 _sound_output->SetSelection (i);
251 setup_sensitivity ();
255 GeneralPage::setup_sensitivity ()
257 _language->Enable (_set_language->GetValue ());
258 _check_for_test_updates->Enable (_check_for_updates->GetValue ());
259 _sound_output->Enable (_sound->GetValue ());
262 /** @return Currently-selected preview sound output in the dialogue */
264 GeneralPage::get_sound_output ()
266 int const sel = _sound_output->GetSelection ();
267 if (sel == wxNOT_FOUND) {
268 return optional<string> ();
271 return wx_to_std (_sound_output->GetString (sel));
275 GeneralPage::set_language_changed ()
277 setup_sensitivity ();
278 if (_set_language->GetValue ()) {
281 Config::instance()->unset_language ();
286 GeneralPage::language_changed ()
288 int const sel = _language->GetSelection ();
290 Config::instance()->set_language (string_client_data (_language->GetClientObject (sel)));
292 Config::instance()->unset_language ();
297 GeneralPage::check_for_updates_changed ()
299 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
303 GeneralPage::check_for_test_updates_changed ()
305 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
309 GeneralPage::sound_changed ()
311 Config::instance()->set_sound (_sound->GetValue ());
315 GeneralPage::sound_output_changed ()
317 RtAudio audio (DCPOMATIC_RTAUDIO_API);
318 optional<string> const so = get_sound_output();
319 if (!so || *so == audio.getDeviceInfo(audio.getDefaultOutputDevice()).name) {
320 Config::instance()->unset_sound_output ();
322 Config::instance()->set_sound_output (*so);
326 CertificateChainEditor::CertificateChainEditor (
330 function<void (shared_ptr<dcp::CertificateChain>)> set,
331 function<shared_ptr<const dcp::CertificateChain> (void)> get,
332 function<bool (void)> nag_remake
334 : wxDialog (parent, wxID_ANY, title)
337 , _nag_remake (nag_remake)
339 wxFont subheading_font (*wxNORMAL_FONT);
340 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
342 _sizer = new wxBoxSizer (wxVERTICAL);
345 wxStaticText* m = new wxStaticText (this, wxID_ANY, title);
346 m->SetFont (subheading_font);
347 _sizer->Add (m, 0, wxALL, border);
350 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
351 _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
353 _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
358 ip.SetText (_("Type"));
360 _certificates->InsertColumn (0, ip);
366 ip.SetText (_("Thumbprint"));
369 wxFont font = ip.GetFont ();
370 font.SetFamily (wxFONTFAMILY_TELETYPE);
373 _certificates->InsertColumn (1, ip);
376 certificates_sizer->Add (_certificates, 1, wxEXPAND);
379 wxSizer* s = new wxBoxSizer (wxVERTICAL);
380 _add_certificate = new wxButton (this, wxID_ANY, _("Add..."));
381 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
382 _remove_certificate = new wxButton (this, wxID_ANY, _("Remove"));
383 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
384 _export_certificate = new wxButton (this, wxID_ANY, _("Export"));
385 s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
386 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
389 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
390 _sizer->Add (table, 1, wxALL | wxEXPAND, border);
393 add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
394 _private_key = new wxStaticText (this, wxID_ANY, wxT (""));
395 wxFont font = _private_key->GetFont ();
396 font.SetFamily (wxFONTFAMILY_TELETYPE);
397 _private_key->SetFont (font);
398 table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
399 _import_private_key = new wxButton (this, wxID_ANY, _("Import..."));
400 table->Add (_import_private_key, wxGBPosition (r, 2));
401 _export_private_key = new wxButton (this, wxID_ANY, _("Export..."));
402 table->Add (_export_private_key, wxGBPosition (r, 3));
405 _button_sizer = new wxBoxSizer (wxHORIZONTAL);
406 _remake_certificates = new wxButton (this, wxID_ANY, _("Re-make certificates and key..."));
407 _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
408 table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
411 _private_key_bad = new wxStaticText (this, wxID_ANY, _("Leaf private key does not match leaf certificate!"));
412 font = *wxSMALL_FONT;
413 font.SetWeight (wxFONTWEIGHT_BOLD);
414 _private_key_bad->SetFont (font);
415 table->Add (_private_key_bad, wxGBPosition (r, 0), wxGBSpan (1, 3));
418 _add_certificate->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::add_certificate, this));
419 _remove_certificate->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::remove_certificate, this));
420 _export_certificate->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::export_certificate, this));
421 _certificates->Bind (wxEVT_LIST_ITEM_SELECTED, bind (&CertificateChainEditor::update_sensitivity, this));
422 _certificates->Bind (wxEVT_LIST_ITEM_DESELECTED, bind (&CertificateChainEditor::update_sensitivity, this));
423 _remake_certificates->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::remake_certificates, this));
424 _import_private_key->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::import_private_key, this));
425 _export_private_key->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::export_private_key, this));
427 wxSizer* buttons = CreateSeparatedButtonSizer (wxCLOSE);
429 _sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
432 SetSizerAndFit (_sizer);
434 update_certificate_list ();
435 update_private_key ();
436 update_sensitivity ();
440 CertificateChainEditor::add_button (wxWindow* button)
442 _button_sizer->Add (button, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
447 CertificateChainEditor::add_certificate ()
449 wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
451 if (d->ShowModal() == wxID_OK) {
456 extra = c.read_string (dcp::file_to_string (wx_to_std (d->GetPath ())));
457 } catch (boost::filesystem::filesystem_error& e) {
458 error_dialog (this, _("Could not import certificate (%s)"), d->GetPath());
463 if (!extra.empty ()) {
466 _("This file contains other certificates (or other data) after its first certificate. "
467 "Only the first certificate will be used.")
470 shared_ptr<dcp::CertificateChain> chain(new dcp::CertificateChain(*_get().get()));
472 if (!chain->chain_valid ()) {
475 _("Adding this certificate would make the chain inconsistent, so it will not be added. "
476 "Add certificates in order from root to intermediate to leaf.")
481 update_certificate_list ();
483 } catch (dcp::MiscError& e) {
484 error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what()));
490 update_sensitivity ();
494 CertificateChainEditor::remove_certificate ()
496 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
501 _certificates->DeleteItem (i);
502 shared_ptr<dcp::CertificateChain> chain(new dcp::CertificateChain(*_get().get()));
506 update_sensitivity ();
510 CertificateChainEditor::export_certificate ()
512 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
517 wxFileDialog* d = new wxFileDialog (
518 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"), wxFD_SAVE
521 dcp::CertificateChain::List all = _get()->root_to_leaf ();
522 dcp::CertificateChain::List::iterator j = all.begin ();
523 for (int k = 0; k < i; ++k) {
527 if (d->ShowModal () == wxID_OK) {
528 optional<boost::filesystem::path> path = path_from_file_dialog (d, "pem");
530 FILE* f = fopen_boost (*path, "w");
532 throw OpenFileError (*path, errno, false);
535 string const s = j->certificate (true);
536 fwrite (s.c_str(), 1, s.length(), f);
544 CertificateChainEditor::update_certificate_list ()
546 _certificates->DeleteAllItems ();
548 dcp::CertificateChain::List certs = _get()->root_to_leaf ();
549 BOOST_FOREACH (dcp::Certificate const & i, certs) {
552 _certificates->InsertItem (item);
553 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
556 _certificates->SetItem (n, 0, _("Root"));
557 } else if (n == (certs.size() - 1)) {
558 _certificates->SetItem (n, 0, _("Leaf"));
560 _certificates->SetItem (n, 0, _("Intermediate"));
566 static wxColour normal = _private_key_bad->GetForegroundColour ();
568 if (_get()->private_key_valid()) {
569 _private_key_bad->Hide ();
570 _private_key_bad->SetForegroundColour (normal);
572 _private_key_bad->Show ();
573 _private_key_bad->SetForegroundColour (wxColour (255, 0, 0));
578 CertificateChainEditor::remake_certificates ()
580 shared_ptr<const dcp::CertificateChain> chain = _get();
582 string subject_organization_name;
583 string subject_organizational_unit_name;
584 string root_common_name;
585 string intermediate_common_name;
586 string leaf_common_name;
588 dcp::CertificateChain::List all = chain->root_to_leaf ();
590 if (all.size() >= 1) {
592 subject_organization_name = chain->root().subject_organization_name ();
593 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
594 root_common_name = chain->root().subject_common_name ();
597 if (all.size() >= 2) {
599 leaf_common_name = chain->leaf().subject_common_name ();
602 if (all.size() >= 3) {
603 /* Have an intermediate */
604 dcp::CertificateChain::List::iterator i = all.begin ();
606 intermediate_common_name = i->subject_common_name ();
610 /* Cancel was clicked */
614 MakeChainDialog* d = new MakeChainDialog (
616 subject_organization_name,
617 subject_organizational_unit_name,
619 intermediate_common_name,
623 if (d->ShowModal () == wxID_OK) {
625 shared_ptr<dcp::CertificateChain> (
626 new dcp::CertificateChain (
629 d->organisational_unit (),
630 d->root_common_name (),
631 d->intermediate_common_name (),
632 d->leaf_common_name ()
637 update_certificate_list ();
638 update_private_key ();
645 CertificateChainEditor::update_sensitivity ()
647 /* We can only remove the leaf certificate */
648 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) == (_certificates->GetItemCount() - 1));
649 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
653 CertificateChainEditor::update_private_key ()
655 checked_set (_private_key, dcp::private_key_fingerprint (_get()->key().get()));
660 CertificateChainEditor::import_private_key ()
662 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
664 if (d->ShowModal() == wxID_OK) {
666 boost::filesystem::path p (wx_to_std (d->GetPath ()));
667 if (boost::filesystem::file_size (p) > 8192) {
670 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
675 shared_ptr<dcp::CertificateChain> chain(new dcp::CertificateChain(*_get().get()));
676 chain->set_key (dcp::file_to_string (p));
678 update_private_key ();
679 } catch (dcp::MiscError& e) {
680 error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what()));
686 update_sensitivity ();
690 CertificateChainEditor::export_private_key ()
692 optional<string> key = _get()->key();
697 wxFileDialog* d = new wxFileDialog (
698 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"), wxFD_SAVE
701 if (d->ShowModal () == wxID_OK) {
702 optional<boost::filesystem::path> path = path_from_file_dialog (d, "pem");
704 FILE* f = fopen_boost (*path, "w");
706 throw OpenFileError (*path, errno, false);
709 string const s = _get()->key().get ();
710 fwrite (s.c_str(), 1, s.length(), f);
718 KeysPage::GetName () const
726 wxFont subheading_font (*wxNORMAL_FONT);
727 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
729 wxSizer* sizer = _panel->GetSizer();
732 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Decrypting KDMs"));
733 m->SetFont (subheading_font);
734 sizer->Add (m, 0, wxALL, _border);
737 wxButton* export_decryption_certificate = new wxButton (_panel, wxID_ANY, _("Export KDM decryption certificate..."));
738 sizer->Add (export_decryption_certificate, 0, wxLEFT, _border);
739 wxButton* export_decryption_chain = new wxButton (_panel, wxID_ANY, _("Export KDM decryption chain..."));
740 sizer->Add (export_decryption_chain, 0, wxLEFT, _border);
741 wxButton* export_settings = new wxButton (_panel, wxID_ANY, _("Export all KDM decryption settings..."));
742 sizer->Add (export_settings, 0, wxLEFT, _border);
743 wxButton* import_settings = new wxButton (_panel, wxID_ANY, _("Import all KDM decryption settings..."));
744 sizer->Add (import_settings, 0, wxLEFT, _border);
745 wxButton* decryption_advanced = new wxButton (_panel, wxID_ANY, _("Advanced..."));
746 sizer->Add (decryption_advanced, 0, wxALL, _border);
748 export_decryption_certificate->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_certificate, this));
749 export_decryption_chain->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_chain, this));
750 export_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_chain_and_key, this));
751 import_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::import_decryption_chain_and_key, this));
752 decryption_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::decryption_advanced, this));
755 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Signing DCPs and KDMs"));
756 m->SetFont (subheading_font);
757 sizer->Add (m, 0, wxALL, _border);
760 wxButton* signing_advanced = new wxButton (_panel, wxID_ANY, _("Advanced..."));
761 sizer->Add (signing_advanced, 0, wxLEFT, _border);
762 signing_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::signing_advanced, this));
766 KeysPage::decryption_advanced ()
768 CertificateChainEditor* c = new CertificateChainEditor (
769 _panel, _("Decrypting KDMs"), _border,
770 bind (&Config::set_decryption_chain, Config::instance (), _1),
771 bind (&Config::decryption_chain, Config::instance ()),
772 bind (&KeysPage::nag_remake_decryption_chain, this)
779 KeysPage::signing_advanced ()
781 CertificateChainEditor* c = new CertificateChainEditor (
782 _panel, _("Signing DCPs and KDMs"), _border,
783 bind (&Config::set_signer_chain, Config::instance (), _1),
784 bind (&Config::signer_chain, Config::instance ()),
792 KeysPage::export_decryption_chain_and_key ()
794 wxFileDialog* d = new wxFileDialog (
795 _panel, _("Select Export File"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom"), wxFD_SAVE
798 if (d->ShowModal () == wxID_OK) {
799 optional<boost::filesystem::path> path = path_from_file_dialog (d, "dom");
801 FILE* f = fopen_boost (*path, "w");
803 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
806 string const chain = Config::instance()->decryption_chain()->chain();
807 fwrite (chain.c_str(), 1, chain.length(), f);
808 optional<string> const key = Config::instance()->decryption_chain()->key();
809 DCPOMATIC_ASSERT (key);
810 fwrite (key->c_str(), 1, key->length(), f);
819 KeysPage::import_decryption_chain_and_key ()
821 wxFileDialog* d = new wxFileDialog (
822 _panel, _("Select File To Import"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom")
825 if (d->ShowModal () == wxID_OK) {
826 shared_ptr<dcp::CertificateChain> new_chain(new dcp::CertificateChain());
828 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "r");
830 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
836 if (fgets (buffer, 128, f) == 0) {
840 if (strncmp (buffer, "-----END CERTIFICATE-----", 25) == 0) {
841 new_chain->add (dcp::Certificate (current));
843 } else if (strncmp (buffer, "-----END RSA PRIVATE KEY-----", 29) == 0) {
844 new_chain->set_key (current);
850 if (new_chain->chain_valid() && new_chain->private_key_valid()) {
851 Config::instance()->set_decryption_chain (new_chain);
853 error_dialog (_panel, _("Invalid DCP-o-matic export file"));
860 KeysPage::nag_remake_decryption_chain ()
862 return NagDialog::maybe_nag (
864 Config::NAG_REMAKE_DECRYPTION_CHAIN,
865 _("If you continue with this operation you will no longer be able to use any DKDMs that you have created. Also, any KDMs that have been sent to you will become useless. Proceed with caution!"),
871 KeysPage::export_decryption_chain ()
873 wxFileDialog* d = new wxFileDialog (
874 _panel, _("Select Chain File"), wxEmptyString, _("dcpomatic_kdm_decryption_chain.pem"), wxT ("PEM files (*.pem)|*.pem"), wxFD_SAVE
877 if (d->ShowModal () == wxID_OK) {
878 optional<boost::filesystem::path> path = path_from_file_dialog (d, "pem");
880 FILE* f = fopen_boost (*path, "w");
882 throw OpenFileError (*path, errno, false);
885 string const s = Config::instance()->decryption_chain()->chain();
886 fwrite (s.c_str(), 1, s.length(), f);
894 KeysPage::export_decryption_certificate ()
896 wxFileDialog* d = new wxFileDialog (
897 _panel, _("Select Certificate File"), wxEmptyString, _("dcpomatic_kdm_decryption_cert.pem"), wxT ("PEM files (*.pem)|*.pem"), wxFD_SAVE
900 if (d->ShowModal () == wxID_OK) {
901 optional<boost::filesystem::path> path = path_from_file_dialog (d, "pem");
903 FILE* f = fopen_boost (*path, "w");
905 throw OpenFileError (*path, errno, false);
908 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
909 fwrite (s.c_str(), 1, s.length(), f);