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 ();
519 update_certificate_list ();
523 CertificateChainEditor::export_certificate ()
525 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
530 wxFileDialog* d = new wxFileDialog (
531 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
532 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
535 dcp::CertificateChain::List all = _get()->root_to_leaf ();
536 dcp::CertificateChain::List::iterator j = all.begin ();
537 for (int k = 0; k < i; ++k) {
541 if (d->ShowModal () == wxID_OK) {
542 boost::filesystem::path path (wx_to_std(d->GetPath()));
543 FILE* f = fopen_boost (path, "w");
545 throw OpenFileError (path, errno, false);
548 string const s = j->certificate (true);
549 checked_fwrite (s.c_str(), s.length(), f, path);
556 CertificateChainEditor::export_chain ()
558 wxFileDialog* d = new wxFileDialog (
559 this, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT("PEM files (*.pem)|*.pem"),
560 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
563 if (d->ShowModal () == wxID_OK) {
564 boost::filesystem::path path (wx_to_std(d->GetPath()));
565 FILE* f = fopen_boost (path, "w");
567 throw OpenFileError (path, errno, false);
570 string const s = _get()->chain();
571 checked_fwrite (s.c_str(), s.length(), f, path);
579 CertificateChainEditor::update_certificate_list ()
581 _certificates->DeleteAllItems ();
583 dcp::CertificateChain::List certs = _get()->root_to_leaf ();
584 BOOST_FOREACH (dcp::Certificate const & i, certs) {
587 _certificates->InsertItem (item);
588 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
591 _certificates->SetItem (n, 0, _("Root"));
592 } else if (n == (certs.size() - 1)) {
593 _certificates->SetItem (n, 0, _("Leaf"));
595 _certificates->SetItem (n, 0, _("Intermediate"));
601 static wxColour normal = _private_key_bad->GetForegroundColour ();
603 if (_get()->private_key_valid()) {
604 _private_key_bad->Hide ();
605 _private_key_bad->SetForegroundColour (normal);
607 _private_key_bad->Show ();
608 _private_key_bad->SetForegroundColour (wxColour (255, 0, 0));
613 CertificateChainEditor::remake_certificates ()
615 shared_ptr<const dcp::CertificateChain> chain = _get();
617 string subject_organization_name;
618 string subject_organizational_unit_name;
619 string root_common_name;
620 string intermediate_common_name;
621 string leaf_common_name;
623 dcp::CertificateChain::List all = chain->root_to_leaf ();
625 if (all.size() >= 1) {
627 subject_organization_name = chain->root().subject_organization_name ();
628 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
629 root_common_name = chain->root().subject_common_name ();
632 if (all.size() >= 2) {
634 leaf_common_name = chain->leaf().subject_common_name ();
637 if (all.size() >= 3) {
638 /* Have an intermediate */
639 dcp::CertificateChain::List::iterator i = all.begin ();
641 intermediate_common_name = i->subject_common_name ();
645 /* Cancel was clicked */
649 MakeChainDialog* d = new MakeChainDialog (
651 subject_organization_name,
652 subject_organizational_unit_name,
654 intermediate_common_name,
658 if (d->ShowModal () == wxID_OK) {
660 shared_ptr<dcp::CertificateChain> (
661 new dcp::CertificateChain (
664 d->organisational_unit (),
665 d->root_common_name (),
666 d->intermediate_common_name (),
667 d->leaf_common_name ()
672 update_certificate_list ();
673 update_private_key ();
680 CertificateChainEditor::update_sensitivity ()
682 /* We can only remove the leaf certificate */
683 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) == (_certificates->GetItemCount() - 1));
684 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
688 CertificateChainEditor::update_private_key ()
690 checked_set (_private_key, dcp::private_key_fingerprint (_get()->key().get()));
695 CertificateChainEditor::import_private_key ()
697 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
699 if (d->ShowModal() == wxID_OK) {
701 boost::filesystem::path p (wx_to_std (d->GetPath ()));
702 if (boost::filesystem::file_size (p) > 8192) {
705 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
710 shared_ptr<dcp::CertificateChain> chain(new dcp::CertificateChain(*_get().get()));
711 chain->set_key (dcp::file_to_string (p));
713 update_private_key ();
714 } catch (dcp::MiscError& e) {
715 error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what()));
721 update_sensitivity ();
725 CertificateChainEditor::export_private_key ()
727 optional<string> key = _get()->key();
732 wxFileDialog* d = new wxFileDialog (
733 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
734 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
737 if (d->ShowModal () == wxID_OK) {
738 boost::filesystem::path path (wx_to_std(d->GetPath()));
739 FILE* f = fopen_boost (path, "w");
741 throw OpenFileError (path, errno, false);
744 string const s = _get()->key().get ();
745 checked_fwrite (s.c_str(), s.length(), f, path);
752 KeysPage::GetName () const
760 wxFont subheading_font (*wxNORMAL_FONT);
761 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
763 wxSizer* sizer = _panel->GetSizer();
766 wxStaticText* m = new StaticText (_panel, _("Decrypting KDMs"));
767 m->SetFont (subheading_font);
768 sizer->Add (m, 0, wxALL, _border);
771 wxButton* export_decryption_certificate = new Button (_panel, _("Export KDM decryption certificate..."));
772 sizer->Add (export_decryption_certificate, 0, wxLEFT, _border);
773 wxButton* export_settings = new Button (_panel, _("Export all KDM decryption settings..."));
774 sizer->Add (export_settings, 0, wxLEFT, _border);
775 wxButton* import_settings = new Button (_panel, _("Import all KDM decryption settings..."));
776 sizer->Add (import_settings, 0, wxLEFT, _border);
777 wxButton* decryption_advanced = new Button (_panel, _("Advanced..."));
778 sizer->Add (decryption_advanced, 0, wxALL, _border);
780 export_decryption_certificate->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_certificate, this));
781 export_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_chain_and_key, this));
782 import_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::import_decryption_chain_and_key, this));
783 decryption_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::decryption_advanced, this));
786 wxStaticText* m = new StaticText (_panel, _("Signing DCPs and KDMs"));
787 m->SetFont (subheading_font);
788 sizer->Add (m, 0, wxALL, _border);
791 wxButton* signing_advanced = new Button (_panel, _("Advanced..."));
792 sizer->Add (signing_advanced, 0, wxLEFT, _border);
793 signing_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::signing_advanced, this));
797 KeysPage::decryption_advanced ()
799 CertificateChainEditor* c = new CertificateChainEditor (
800 _panel, _("Decrypting KDMs"), _border,
801 bind (&Config::set_decryption_chain, Config::instance (), _1),
802 bind (&Config::decryption_chain, Config::instance ()),
803 bind (&KeysPage::nag_alter_decryption_chain, this)
810 KeysPage::signing_advanced ()
812 CertificateChainEditor* c = new CertificateChainEditor (
813 _panel, _("Signing DCPs and KDMs"), _border,
814 bind (&Config::set_signer_chain, Config::instance (), _1),
815 bind (&Config::signer_chain, Config::instance ()),
823 KeysPage::export_decryption_chain_and_key ()
825 wxFileDialog* d = new wxFileDialog (
826 _panel, _("Select Export File"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom"),
827 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
830 if (d->ShowModal () == wxID_OK) {
831 boost::filesystem::path path (wx_to_std(d->GetPath()));
832 FILE* f = fopen_boost (path, "w");
834 throw OpenFileError (path, errno, false);
837 string const chain = Config::instance()->decryption_chain()->chain();
838 checked_fwrite (chain.c_str(), chain.length(), f, path);
839 optional<string> const key = Config::instance()->decryption_chain()->key();
840 DCPOMATIC_ASSERT (key);
841 checked_fwrite (key->c_str(), key->length(), f, path);
849 KeysPage::import_decryption_chain_and_key ()
851 if (NagDialog::maybe_nag (
853 Config::NAG_IMPORT_DECRYPTION_CHAIN,
854 _("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!"),
860 wxFileDialog* d = new wxFileDialog (
861 _panel, _("Select File To Import"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom")
864 if (d->ShowModal () == wxID_OK) {
865 shared_ptr<dcp::CertificateChain> new_chain(new dcp::CertificateChain());
867 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "r");
869 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
875 if (fgets (buffer, 128, f) == 0) {
879 if (strncmp (buffer, "-----END CERTIFICATE-----", 25) == 0) {
880 new_chain->add (dcp::Certificate (current));
882 } else if (strncmp (buffer, "-----END RSA PRIVATE KEY-----", 29) == 0) {
883 new_chain->set_key (current);
889 if (new_chain->chain_valid() && new_chain->private_key_valid()) {
890 Config::instance()->set_decryption_chain (new_chain);
892 error_dialog (_panel, _("Invalid DCP-o-matic export file"));
899 KeysPage::nag_alter_decryption_chain ()
901 return NagDialog::maybe_nag (
903 Config::NAG_ALTER_DECRYPTION_CHAIN,
904 _("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!"),
910 KeysPage::export_decryption_certificate ()
912 wxFileDialog* d = new wxFileDialog (
913 _panel, _("Select Certificate File"), wxEmptyString, _("dcpomatic_kdm_decryption_cert.pem"), wxT ("PEM files (*.pem)|*.pem"),
914 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
917 if (d->ShowModal () == wxID_OK) {
918 boost::filesystem::path path (wx_to_std(d->GetPath()));
919 FILE* f = fopen_boost (path, "w");
921 throw OpenFileError (path, errno, false);
924 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
925 checked_fwrite (s.c_str(), s.length(), f, path);