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"),
519 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
522 dcp::CertificateChain::List all = _get()->root_to_leaf ();
523 dcp::CertificateChain::List::iterator j = all.begin ();
524 for (int k = 0; k < i; ++k) {
528 if (d->ShowModal () == wxID_OK) {
529 boost::filesystem::path path (wx_to_std(d->GetPath()));
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);
543 CertificateChainEditor::update_certificate_list ()
545 _certificates->DeleteAllItems ();
547 dcp::CertificateChain::List certs = _get()->root_to_leaf ();
548 BOOST_FOREACH (dcp::Certificate const & i, certs) {
551 _certificates->InsertItem (item);
552 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
555 _certificates->SetItem (n, 0, _("Root"));
556 } else if (n == (certs.size() - 1)) {
557 _certificates->SetItem (n, 0, _("Leaf"));
559 _certificates->SetItem (n, 0, _("Intermediate"));
565 static wxColour normal = _private_key_bad->GetForegroundColour ();
567 if (_get()->private_key_valid()) {
568 _private_key_bad->Hide ();
569 _private_key_bad->SetForegroundColour (normal);
571 _private_key_bad->Show ();
572 _private_key_bad->SetForegroundColour (wxColour (255, 0, 0));
577 CertificateChainEditor::remake_certificates ()
579 shared_ptr<const dcp::CertificateChain> chain = _get();
581 string subject_organization_name;
582 string subject_organizational_unit_name;
583 string root_common_name;
584 string intermediate_common_name;
585 string leaf_common_name;
587 dcp::CertificateChain::List all = chain->root_to_leaf ();
589 if (all.size() >= 1) {
591 subject_organization_name = chain->root().subject_organization_name ();
592 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
593 root_common_name = chain->root().subject_common_name ();
596 if (all.size() >= 2) {
598 leaf_common_name = chain->leaf().subject_common_name ();
601 if (all.size() >= 3) {
602 /* Have an intermediate */
603 dcp::CertificateChain::List::iterator i = all.begin ();
605 intermediate_common_name = i->subject_common_name ();
609 /* Cancel was clicked */
613 MakeChainDialog* d = new MakeChainDialog (
615 subject_organization_name,
616 subject_organizational_unit_name,
618 intermediate_common_name,
622 if (d->ShowModal () == wxID_OK) {
624 shared_ptr<dcp::CertificateChain> (
625 new dcp::CertificateChain (
628 d->organisational_unit (),
629 d->root_common_name (),
630 d->intermediate_common_name (),
631 d->leaf_common_name ()
636 update_certificate_list ();
637 update_private_key ();
644 CertificateChainEditor::update_sensitivity ()
646 /* We can only remove the leaf certificate */
647 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) == (_certificates->GetItemCount() - 1));
648 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
652 CertificateChainEditor::update_private_key ()
654 checked_set (_private_key, dcp::private_key_fingerprint (_get()->key().get()));
659 CertificateChainEditor::import_private_key ()
661 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
663 if (d->ShowModal() == wxID_OK) {
665 boost::filesystem::path p (wx_to_std (d->GetPath ()));
666 if (boost::filesystem::file_size (p) > 8192) {
669 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
674 shared_ptr<dcp::CertificateChain> chain(new dcp::CertificateChain(*_get().get()));
675 chain->set_key (dcp::file_to_string (p));
677 update_private_key ();
678 } catch (dcp::MiscError& e) {
679 error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what()));
685 update_sensitivity ();
689 CertificateChainEditor::export_private_key ()
691 optional<string> key = _get()->key();
696 wxFileDialog* d = new wxFileDialog (
697 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
698 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
701 if (d->ShowModal () == wxID_OK) {
702 boost::filesystem::path path (wx_to_std(d->GetPath()));
703 FILE* f = fopen_boost (path, "w");
705 throw OpenFileError (path, errno, false);
708 string const s = _get()->key().get ();
709 fwrite (s.c_str(), 1, s.length(), f);
716 KeysPage::GetName () const
724 wxFont subheading_font (*wxNORMAL_FONT);
725 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
727 wxSizer* sizer = _panel->GetSizer();
730 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Decrypting KDMs"));
731 m->SetFont (subheading_font);
732 sizer->Add (m, 0, wxALL, _border);
735 wxButton* export_decryption_certificate = new wxButton (_panel, wxID_ANY, _("Export KDM decryption certificate..."));
736 sizer->Add (export_decryption_certificate, 0, wxLEFT, _border);
737 wxButton* export_decryption_chain = new wxButton (_panel, wxID_ANY, _("Export KDM decryption chain..."));
738 sizer->Add (export_decryption_chain, 0, wxLEFT, _border);
739 wxButton* export_settings = new wxButton (_panel, wxID_ANY, _("Export all KDM decryption settings..."));
740 sizer->Add (export_settings, 0, wxLEFT, _border);
741 wxButton* import_settings = new wxButton (_panel, wxID_ANY, _("Import all KDM decryption settings..."));
742 sizer->Add (import_settings, 0, wxLEFT, _border);
743 wxButton* decryption_advanced = new wxButton (_panel, wxID_ANY, _("Advanced..."));
744 sizer->Add (decryption_advanced, 0, wxALL, _border);
746 export_decryption_certificate->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_certificate, this));
747 export_decryption_chain->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_chain, this));
748 export_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_chain_and_key, this));
749 import_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::import_decryption_chain_and_key, this));
750 decryption_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::decryption_advanced, this));
753 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Signing DCPs and KDMs"));
754 m->SetFont (subheading_font);
755 sizer->Add (m, 0, wxALL, _border);
758 wxButton* signing_advanced = new wxButton (_panel, wxID_ANY, _("Advanced..."));
759 sizer->Add (signing_advanced, 0, wxLEFT, _border);
760 signing_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::signing_advanced, this));
764 KeysPage::decryption_advanced ()
766 CertificateChainEditor* c = new CertificateChainEditor (
767 _panel, _("Decrypting KDMs"), _border,
768 bind (&Config::set_decryption_chain, Config::instance (), _1),
769 bind (&Config::decryption_chain, Config::instance ()),
770 bind (&KeysPage::nag_remake_decryption_chain, this)
777 KeysPage::signing_advanced ()
779 CertificateChainEditor* c = new CertificateChainEditor (
780 _panel, _("Signing DCPs and KDMs"), _border,
781 bind (&Config::set_signer_chain, Config::instance (), _1),
782 bind (&Config::signer_chain, Config::instance ()),
790 KeysPage::export_decryption_chain_and_key ()
792 wxFileDialog* d = new wxFileDialog (
793 _panel, _("Select Export File"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom"),
794 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
797 if (d->ShowModal () == wxID_OK) {
798 boost::filesystem::path path (wx_to_std(d->GetPath()));
799 FILE* f = fopen_boost (path, "w");
801 throw OpenFileError (path, errno, false);
804 string const chain = Config::instance()->decryption_chain()->chain();
805 fwrite (chain.c_str(), 1, chain.length(), f);
806 optional<string> const key = Config::instance()->decryption_chain()->key();
807 DCPOMATIC_ASSERT (key);
808 fwrite (key->c_str(), 1, key->length(), f);
816 KeysPage::import_decryption_chain_and_key ()
818 wxFileDialog* d = new wxFileDialog (
819 _panel, _("Select File To Import"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom")
822 if (d->ShowModal () == wxID_OK) {
823 shared_ptr<dcp::CertificateChain> new_chain(new dcp::CertificateChain());
825 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "r");
827 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
833 if (fgets (buffer, 128, f) == 0) {
837 if (strncmp (buffer, "-----END CERTIFICATE-----", 25) == 0) {
838 new_chain->add (dcp::Certificate (current));
840 } else if (strncmp (buffer, "-----END RSA PRIVATE KEY-----", 29) == 0) {
841 new_chain->set_key (current);
847 if (new_chain->chain_valid() && new_chain->private_key_valid()) {
848 Config::instance()->set_decryption_chain (new_chain);
850 error_dialog (_panel, _("Invalid DCP-o-matic export file"));
857 KeysPage::nag_remake_decryption_chain ()
859 return NagDialog::maybe_nag (
861 Config::NAG_REMAKE_DECRYPTION_CHAIN,
862 _("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!"),
868 KeysPage::export_decryption_chain ()
870 wxFileDialog* d = new wxFileDialog (
871 _panel, _("Select Chain File"), wxEmptyString, _("dcpomatic_kdm_decryption_chain.pem"), wxT ("PEM files (*.pem)|*.pem"),
872 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
875 if (d->ShowModal () == wxID_OK) {
876 boost::filesystem::path path (wx_to_std(d->GetPath()));
877 FILE* f = fopen_boost (path, "w");
879 throw OpenFileError (path, errno, false);
882 string const s = Config::instance()->decryption_chain()->chain();
883 fwrite (s.c_str(), 1, s.length(), f);
890 KeysPage::export_decryption_certificate ()
892 wxFileDialog* d = new wxFileDialog (
893 _panel, _("Select Certificate File"), wxEmptyString, _("dcpomatic_kdm_decryption_cert.pem"), wxT ("PEM files (*.pem)|*.pem"),
894 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
897 if (d->ShowModal () == wxID_OK) {
898 boost::filesystem::path path (wx_to_std(d->GetPath()));
899 FILE* f = fopen_boost (path, "w");
901 throw OpenFileError (path, errno, false);
904 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
905 fwrite (s.c_str(), 1, s.length(), f);