2 Copyright (C) 2012-2019 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 "static_text.h"
23 #include "check_box.h"
24 #include "nag_dialog.h"
25 #include "dcpomatic_button.h"
33 using boost::optional;
34 using boost::shared_ptr;
35 using boost::function;
44 Page::Page (wxSize panel_size, int border)
47 , _panel_size (panel_size)
48 , _window_exists (false)
50 _config_connection = Config::instance()->Changed.connect (bind (&Page::config_changed_wrapper, this));
54 Page::create_window (wxWindow* parent)
56 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
57 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
61 _window_exists = true;
64 _panel->Bind (wxEVT_DESTROY, bind (&Page::window_destroyed, this));
70 Page::config_changed_wrapper ()
78 Page::window_destroyed ()
80 _window_exists = false;
84 StockPage::StockPage (Kind kind, wxSize panel_size, int border)
85 : wxStockPreferencesPage (kind)
86 , Page (panel_size, border)
92 StockPage::CreateWindow (wxWindow* parent)
94 return create_window (parent);
97 StandardPage::StandardPage (wxSize panel_size, int border)
98 : Page (panel_size, border)
104 StandardPage::CreateWindow (wxWindow* parent)
106 return create_window (parent);
109 GeneralPage::GeneralPage (wxSize panel_size, int border)
110 : StockPage (Kind_General, panel_size, border)
116 GeneralPage::add_language_controls (wxGridBagSizer* table, int& r)
118 _set_language = new CheckBox (_panel, _("Set language"));
119 table->Add (_set_language, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
120 _language = new wxChoice (_panel, wxID_ANY);
121 vector<pair<string, string> > languages;
122 languages.push_back (make_pair ("Čeština", "cs_CZ"));
123 languages.push_back (make_pair ("汉语/漢語", "zh_CN"));
124 languages.push_back (make_pair ("Dansk", "da_DK"));
125 languages.push_back (make_pair ("Deutsch", "de_DE"));
126 languages.push_back (make_pair ("English", "en_GB"));
127 languages.push_back (make_pair ("Español", "es_ES"));
128 languages.push_back (make_pair ("Français", "fr_FR"));
129 languages.push_back (make_pair ("Italiano", "it_IT"));
130 languages.push_back (make_pair ("Nederlands", "nl_NL"));
131 languages.push_back (make_pair ("Русский", "ru_RU"));
132 languages.push_back (make_pair ("Polski", "pl_PL"));
133 languages.push_back (make_pair ("Português europeu", "pt_PT"));
134 languages.push_back (make_pair ("Português do Brasil", "pt_BR"));
135 languages.push_back (make_pair ("Svenska", "sv_SE"));
136 languages.push_back (make_pair ("Slovenský jazyk", "sk_SK"));
137 languages.push_back (make_pair ("Türkçe", "tr_TR"));
138 languages.push_back (make_pair ("українська мова", "uk_UA"));
139 checked_set (_language, languages);
140 table->Add (_language, wxGBPosition (r, 1));
143 wxStaticText* restart = add_label_to_sizer (
144 table, _panel, _("(restart DCP-o-matic to see language changes)"), false, wxGBPosition (r, 0), wxGBSpan (1, 2)
146 wxFont font = restart->GetFont();
147 font.SetStyle (wxFONTSTYLE_ITALIC);
148 font.SetPointSize (font.GetPointSize() - 1);
149 restart->SetFont (font);
152 _set_language->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::set_language_changed, this));
153 _language->Bind (wxEVT_CHOICE, bind (&GeneralPage::language_changed, this));
157 GeneralPage::add_play_sound_controls (wxGridBagSizer* table, int& r)
159 _sound = new CheckBox (_panel, _("Play sound via"));
160 table->Add (_sound, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
161 _sound_output = new wxChoice (_panel, wxID_ANY);
162 table->Add (_sound_output, wxGBPosition (r, 1));
165 RtAudio audio (DCPOMATIC_RTAUDIO_API);
166 for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) {
167 RtAudio::DeviceInfo dev = audio.getDeviceInfo (i);
168 if (dev.probed && dev.outputChannels > 0) {
169 _sound_output->Append (std_to_wx (dev.name));
173 _sound->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::sound_changed, this));
174 _sound_output->Bind (wxEVT_CHOICE, bind (&GeneralPage::sound_output_changed, this));
178 GeneralPage::add_update_controls (wxGridBagSizer* table, int& r)
180 _check_for_updates = new CheckBox (_panel, _("Check for updates on startup"));
181 table->Add (_check_for_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
184 _check_for_test_updates = new CheckBox (_panel, _("Check for testing updates on startup"));
185 table->Add (_check_for_test_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
188 _check_for_updates->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::check_for_updates_changed, this));
189 _check_for_test_updates->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::check_for_test_updates_changed, this));
193 GeneralPage::config_changed ()
195 Config* config = Config::instance ();
197 checked_set (_set_language, static_cast<bool>(config->language()));
199 /* Backwards compatibility of config file */
201 map<string, string> compat_map;
202 compat_map["fr"] = "fr_FR";
203 compat_map["it"] = "it_IT";
204 compat_map["es"] = "es_ES";
205 compat_map["sv"] = "sv_SE";
206 compat_map["de"] = "de_DE";
207 compat_map["nl"] = "nl_NL";
208 compat_map["ru"] = "ru_RU";
209 compat_map["pl"] = "pl_PL";
210 compat_map["da"] = "da_DK";
211 compat_map["pt"] = "pt_PT";
212 compat_map["sk"] = "sk_SK";
213 compat_map["cs"] = "cs_CZ";
214 compat_map["uk"] = "uk_UA";
216 string lang = config->language().get_value_or ("en_GB");
217 if (compat_map.find (lang) != compat_map.end ()) {
218 lang = compat_map[lang];
221 checked_set (_language, lang);
223 checked_set (_check_for_updates, config->check_for_updates ());
224 checked_set (_check_for_test_updates, config->check_for_test_updates ());
226 checked_set (_sound, config->sound ());
228 optional<string> const current_so = get_sound_output ();
229 optional<string> configured_so;
231 if (config->sound_output()) {
232 configured_so = config->sound_output().get();
234 /* No configured output means we should use the default */
235 RtAudio audio (DCPOMATIC_RTAUDIO_API);
237 configured_so = audio.getDeviceInfo(audio.getDefaultOutputDevice()).name;
238 } catch (RtAudioError& e) {
239 /* Probably no audio devices at all */
243 if (configured_so && current_so != configured_so) {
244 /* Update _sound_output with the configured value */
246 while (i < _sound_output->GetCount()) {
247 if (_sound_output->GetString(i) == std_to_wx(*configured_so)) {
248 _sound_output->SetSelection (i);
255 setup_sensitivity ();
259 GeneralPage::setup_sensitivity ()
261 _language->Enable (_set_language->GetValue ());
262 _check_for_test_updates->Enable (_check_for_updates->GetValue ());
263 _sound_output->Enable (_sound->GetValue ());
266 /** @return Currently-selected preview sound output in the dialogue */
268 GeneralPage::get_sound_output ()
270 int const sel = _sound_output->GetSelection ();
271 if (sel == wxNOT_FOUND) {
272 return optional<string> ();
275 return wx_to_std (_sound_output->GetString (sel));
279 GeneralPage::set_language_changed ()
281 setup_sensitivity ();
282 if (_set_language->GetValue ()) {
285 Config::instance()->unset_language ();
290 GeneralPage::language_changed ()
292 int const sel = _language->GetSelection ();
294 Config::instance()->set_language (string_client_data (_language->GetClientObject (sel)));
296 Config::instance()->unset_language ();
301 GeneralPage::check_for_updates_changed ()
303 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
307 GeneralPage::check_for_test_updates_changed ()
309 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
313 GeneralPage::sound_changed ()
315 Config::instance()->set_sound (_sound->GetValue ());
319 GeneralPage::sound_output_changed ()
321 RtAudio audio (DCPOMATIC_RTAUDIO_API);
322 optional<string> const so = get_sound_output();
323 if (!so || *so == audio.getDeviceInfo(audio.getDefaultOutputDevice()).name) {
324 Config::instance()->unset_sound_output ();
326 Config::instance()->set_sound_output (*so);
330 CertificateChainEditor::CertificateChainEditor (
334 function<void (shared_ptr<dcp::CertificateChain>)> set,
335 function<shared_ptr<const dcp::CertificateChain> (void)> get,
336 function<bool (void)> nag_alter
338 : wxDialog (parent, wxID_ANY, title)
341 , _nag_alter (nag_alter)
343 wxFont subheading_font (*wxNORMAL_FONT);
344 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
346 _sizer = new wxBoxSizer (wxVERTICAL);
349 wxStaticText* m = new StaticText (this, title);
350 m->SetFont (subheading_font);
351 _sizer->Add (m, 0, wxALL, border);
354 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
355 _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
357 _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
362 ip.SetText (_("Type"));
364 _certificates->InsertColumn (0, ip);
370 ip.SetText (_("Thumbprint"));
373 wxFont font = ip.GetFont ();
374 font.SetFamily (wxFONTFAMILY_TELETYPE);
377 _certificates->InsertColumn (1, ip);
380 certificates_sizer->Add (_certificates, 1, wxEXPAND);
383 wxSizer* s = new wxBoxSizer (wxVERTICAL);
384 _add_certificate = new Button (this, _("Add..."));
385 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
386 _remove_certificate = new Button (this, _("Remove"));
387 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
388 _export_certificate = new Button (this, _("Export"));
389 s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
390 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
393 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
394 _sizer->Add (table, 1, wxALL | wxEXPAND, border);
397 add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
398 _private_key = new StaticText (this, wxT(""));
399 wxFont font = _private_key->GetFont ();
400 font.SetFamily (wxFONTFAMILY_TELETYPE);
401 _private_key->SetFont (font);
402 table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
403 _import_private_key = new Button (this, _("Import..."));
404 table->Add (_import_private_key, wxGBPosition (r, 2));
405 _export_private_key = new Button (this, _("Export..."));
406 table->Add (_export_private_key, wxGBPosition (r, 3));
409 _button_sizer = new wxBoxSizer (wxHORIZONTAL);
410 _remake_certificates = new Button (this, _("Re-make certificates and key..."));
411 _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
412 _export_chain = new Button (this, _("Export chain..."));
413 _button_sizer->Add (_export_chain, 1, wxRIGHT, border);
414 table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
417 _private_key_bad = new StaticText (this, _("Leaf private key does not match leaf certificate!"));
418 font = *wxSMALL_FONT;
419 font.SetWeight (wxFONTWEIGHT_BOLD);
420 _private_key_bad->SetFont (font);
421 table->Add (_private_key_bad, wxGBPosition (r, 0), wxGBSpan (1, 3));
424 _add_certificate->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::add_certificate, this));
425 _remove_certificate->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::remove_certificate, this));
426 _export_certificate->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::export_certificate, this));
427 _certificates->Bind (wxEVT_LIST_ITEM_SELECTED, bind (&CertificateChainEditor::update_sensitivity, this));
428 _certificates->Bind (wxEVT_LIST_ITEM_DESELECTED, bind (&CertificateChainEditor::update_sensitivity, this));
429 _remake_certificates->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::remake_certificates, this));
430 _export_chain->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::export_chain, this));
431 _import_private_key->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::import_private_key, this));
432 _export_private_key->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::export_private_key, this));
434 wxSizer* buttons = CreateSeparatedButtonSizer (wxCLOSE);
436 _sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
439 SetSizerAndFit (_sizer);
441 update_certificate_list ();
442 update_private_key ();
443 update_sensitivity ();
447 CertificateChainEditor::add_button (wxWindow* button)
449 _button_sizer->Add (button, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
454 CertificateChainEditor::add_certificate ()
456 wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
458 if (d->ShowModal() == wxID_OK) {
463 extra = c.read_string (dcp::file_to_string (wx_to_std (d->GetPath ())));
464 } catch (boost::filesystem::filesystem_error& e) {
465 error_dialog (this, _("Could not import certificate (%s)"), d->GetPath());
470 if (!extra.empty ()) {
473 _("This file contains other certificates (or other data) after its first certificate. "
474 "Only the first certificate will be used.")
477 shared_ptr<dcp::CertificateChain> chain(new dcp::CertificateChain(*_get().get()));
479 if (!chain->chain_valid ()) {
482 _("Adding this certificate would make the chain inconsistent, so it will not be added. "
483 "Add certificates in order from root to intermediate to leaf.")
488 update_certificate_list ();
490 } catch (dcp::MiscError& e) {
491 error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what()));
497 update_sensitivity ();
501 CertificateChainEditor::remove_certificate ()
504 /* Cancel was clicked */
508 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
513 _certificates->DeleteItem (i);
514 shared_ptr<dcp::CertificateChain> chain(new dcp::CertificateChain(*_get().get()));
518 update_sensitivity ();
522 CertificateChainEditor::export_certificate ()
524 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
529 wxFileDialog* d = new wxFileDialog (
530 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
531 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
534 dcp::CertificateChain::List all = _get()->root_to_leaf ();
535 dcp::CertificateChain::List::iterator j = all.begin ();
536 for (int k = 0; k < i; ++k) {
540 if (d->ShowModal () == wxID_OK) {
541 boost::filesystem::path path (wx_to_std(d->GetPath()));
542 FILE* f = fopen_boost (path, "w");
544 throw OpenFileError (path, errno, false);
547 string const s = j->certificate (true);
548 checked_fwrite (s.c_str(), s.length(), f, path);
555 CertificateChainEditor::export_chain ()
557 wxFileDialog* d = new wxFileDialog (
558 this, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT("PEM files (*.pem)|*.pem"),
559 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
562 if (d->ShowModal () == wxID_OK) {
563 boost::filesystem::path path (wx_to_std(d->GetPath()));
564 FILE* f = fopen_boost (path, "w");
566 throw OpenFileError (path, errno, false);
569 string const s = _get()->chain();
570 checked_fwrite (s.c_str(), s.length(), f, path);
578 CertificateChainEditor::update_certificate_list ()
580 _certificates->DeleteAllItems ();
582 dcp::CertificateChain::List certs = _get()->root_to_leaf ();
583 BOOST_FOREACH (dcp::Certificate const & i, certs) {
586 _certificates->InsertItem (item);
587 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
590 _certificates->SetItem (n, 0, _("Root"));
591 } else if (n == (certs.size() - 1)) {
592 _certificates->SetItem (n, 0, _("Leaf"));
594 _certificates->SetItem (n, 0, _("Intermediate"));
600 static wxColour normal = _private_key_bad->GetForegroundColour ();
602 if (_get()->private_key_valid()) {
603 _private_key_bad->Hide ();
604 _private_key_bad->SetForegroundColour (normal);
606 _private_key_bad->Show ();
607 _private_key_bad->SetForegroundColour (wxColour (255, 0, 0));
612 CertificateChainEditor::remake_certificates ()
614 shared_ptr<const dcp::CertificateChain> chain = _get();
616 string subject_organization_name;
617 string subject_organizational_unit_name;
618 string root_common_name;
619 string intermediate_common_name;
620 string leaf_common_name;
622 dcp::CertificateChain::List all = chain->root_to_leaf ();
624 if (all.size() >= 1) {
626 subject_organization_name = chain->root().subject_organization_name ();
627 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
628 root_common_name = chain->root().subject_common_name ();
631 if (all.size() >= 2) {
633 leaf_common_name = chain->leaf().subject_common_name ();
636 if (all.size() >= 3) {
637 /* Have an intermediate */
638 dcp::CertificateChain::List::iterator i = all.begin ();
640 intermediate_common_name = i->subject_common_name ();
644 /* Cancel was clicked */
648 MakeChainDialog* d = new MakeChainDialog (
650 subject_organization_name,
651 subject_organizational_unit_name,
653 intermediate_common_name,
657 if (d->ShowModal () == wxID_OK) {
659 shared_ptr<dcp::CertificateChain> (
660 new dcp::CertificateChain (
663 d->organisational_unit (),
664 d->root_common_name (),
665 d->intermediate_common_name (),
666 d->leaf_common_name ()
671 update_certificate_list ();
672 update_private_key ();
679 CertificateChainEditor::update_sensitivity ()
681 /* We can only remove the leaf certificate */
682 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) == (_certificates->GetItemCount() - 1));
683 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
687 CertificateChainEditor::update_private_key ()
689 checked_set (_private_key, dcp::private_key_fingerprint (_get()->key().get()));
694 CertificateChainEditor::import_private_key ()
696 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
698 if (d->ShowModal() == wxID_OK) {
700 boost::filesystem::path p (wx_to_std (d->GetPath ()));
701 if (boost::filesystem::file_size (p) > 8192) {
704 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
709 shared_ptr<dcp::CertificateChain> chain(new dcp::CertificateChain(*_get().get()));
710 chain->set_key (dcp::file_to_string (p));
712 update_private_key ();
713 } catch (dcp::MiscError& e) {
714 error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what()));
720 update_sensitivity ();
724 CertificateChainEditor::export_private_key ()
726 optional<string> key = _get()->key();
731 wxFileDialog* d = new wxFileDialog (
732 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
733 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
736 if (d->ShowModal () == wxID_OK) {
737 boost::filesystem::path path (wx_to_std(d->GetPath()));
738 FILE* f = fopen_boost (path, "w");
740 throw OpenFileError (path, errno, false);
743 string const s = _get()->key().get ();
744 checked_fwrite (s.c_str(), s.length(), f, path);
751 KeysPage::GetName () const
759 wxFont subheading_font (*wxNORMAL_FONT);
760 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
762 wxSizer* sizer = _panel->GetSizer();
765 wxStaticText* m = new StaticText (_panel, _("Decrypting KDMs"));
766 m->SetFont (subheading_font);
767 sizer->Add (m, 0, wxALL, _border);
770 wxButton* export_decryption_certificate = new Button (_panel, _("Export KDM decryption certificate..."));
771 sizer->Add (export_decryption_certificate, 0, wxLEFT, _border);
772 wxButton* export_settings = new Button (_panel, _("Export all KDM decryption settings..."));
773 sizer->Add (export_settings, 0, wxLEFT, _border);
774 wxButton* import_settings = new Button (_panel, _("Import all KDM decryption settings..."));
775 sizer->Add (import_settings, 0, wxLEFT, _border);
776 wxButton* decryption_advanced = new Button (_panel, _("Advanced..."));
777 sizer->Add (decryption_advanced, 0, wxALL, _border);
779 export_decryption_certificate->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_certificate, this));
780 export_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_chain_and_key, this));
781 import_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::import_decryption_chain_and_key, this));
782 decryption_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::decryption_advanced, this));
785 wxStaticText* m = new StaticText (_panel, _("Signing DCPs and KDMs"));
786 m->SetFont (subheading_font);
787 sizer->Add (m, 0, wxALL, _border);
790 wxButton* signing_advanced = new Button (_panel, _("Advanced..."));
791 sizer->Add (signing_advanced, 0, wxLEFT, _border);
792 signing_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::signing_advanced, this));
796 KeysPage::decryption_advanced ()
798 CertificateChainEditor* c = new CertificateChainEditor (
799 _panel, _("Decrypting KDMs"), _border,
800 bind (&Config::set_decryption_chain, Config::instance (), _1),
801 bind (&Config::decryption_chain, Config::instance ()),
802 bind (&KeysPage::nag_alter_decryption_chain, this)
809 KeysPage::signing_advanced ()
811 CertificateChainEditor* c = new CertificateChainEditor (
812 _panel, _("Signing DCPs and KDMs"), _border,
813 bind (&Config::set_signer_chain, Config::instance (), _1),
814 bind (&Config::signer_chain, Config::instance ()),
822 KeysPage::export_decryption_chain_and_key ()
824 wxFileDialog* d = new wxFileDialog (
825 _panel, _("Select Export File"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom"),
826 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
829 if (d->ShowModal () == wxID_OK) {
830 boost::filesystem::path path (wx_to_std(d->GetPath()));
831 FILE* f = fopen_boost (path, "w");
833 throw OpenFileError (path, errno, false);
836 string const chain = Config::instance()->decryption_chain()->chain();
837 checked_fwrite (chain.c_str(), chain.length(), f, path);
838 optional<string> const key = Config::instance()->decryption_chain()->key();
839 DCPOMATIC_ASSERT (key);
840 checked_fwrite (key->c_str(), key->length(), f, path);
848 KeysPage::import_decryption_chain_and_key ()
850 if (NagDialog::maybe_nag (
852 Config::NAG_IMPORT_DECRYPTION_CHAIN,
853 _("If you continue with this operation you will no longer be able to use any DKDMs that you have created with the current certificates and key. Also, any KDMs that have been sent to you for those certificates will become useless. Proceed with caution!"),
859 wxFileDialog* d = new wxFileDialog (
860 _panel, _("Select File To Import"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom")
863 if (d->ShowModal () == wxID_OK) {
864 shared_ptr<dcp::CertificateChain> new_chain(new dcp::CertificateChain());
866 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "r");
868 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
874 if (fgets (buffer, 128, f) == 0) {
878 if (strncmp (buffer, "-----END CERTIFICATE-----", 25) == 0) {
879 new_chain->add (dcp::Certificate (current));
881 } else if (strncmp (buffer, "-----END RSA PRIVATE KEY-----", 29) == 0) {
882 new_chain->set_key (current);
888 if (new_chain->chain_valid() && new_chain->private_key_valid()) {
889 Config::instance()->set_decryption_chain (new_chain);
891 error_dialog (_panel, _("Invalid DCP-o-matic export file"));
898 KeysPage::nag_alter_decryption_chain ()
900 return NagDialog::maybe_nag (
902 Config::NAG_ALTER_DECRYPTION_CHAIN,
903 _("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!"),
909 KeysPage::export_decryption_certificate ()
911 wxFileDialog* d = new wxFileDialog (
912 _panel, _("Select Certificate File"), wxEmptyString, _("dcpomatic_kdm_decryption_cert.pem"), wxT ("PEM files (*.pem)|*.pem"),
913 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
916 if (d->ShowModal () == wxID_OK) {
917 boost::filesystem::path path (wx_to_std(d->GetPath()));
918 FILE* f = fopen_boost (path, "w");
920 throw OpenFileError (path, errno, false);
923 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
924 checked_fwrite (s.c_str(), s.length(), f, path);