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"
34 using boost::optional;
35 using boost::shared_ptr;
36 using boost::function;
45 Page::Page (wxSize panel_size, int border)
48 , _panel_size (panel_size)
49 , _window_exists (false)
51 _config_connection = Config::instance()->Changed.connect (bind (&Page::config_changed_wrapper, this));
55 Page::create_window (wxWindow* parent)
57 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
58 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
62 _window_exists = true;
65 _panel->Bind (wxEVT_DESTROY, bind (&Page::window_destroyed, this));
71 Page::config_changed_wrapper ()
79 Page::window_destroyed ()
81 _window_exists = false;
85 StockPage::StockPage (Kind kind, wxSize panel_size, int border)
86 : wxStockPreferencesPage (kind)
87 , Page (panel_size, border)
93 StockPage::CreateWindow (wxWindow* parent)
95 return create_window (parent);
98 StandardPage::StandardPage (wxSize panel_size, int border)
99 : Page (panel_size, border)
105 StandardPage::CreateWindow (wxWindow* parent)
107 return create_window (parent);
110 GeneralPage::GeneralPage (wxSize panel_size, int border)
111 : StockPage (Kind_General, panel_size, border)
117 GeneralPage::add_language_controls (wxGridBagSizer* table, int& r)
119 _set_language = new CheckBox (_panel, _("Set language"));
120 table->Add (_set_language, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
121 _language = new wxChoice (_panel, wxID_ANY);
122 vector<pair<string, string> > languages;
123 languages.push_back (make_pair ("Čeština", "cs_CZ"));
124 languages.push_back (make_pair ("汉语/漢語", "zh_CN"));
125 languages.push_back (make_pair ("Dansk", "da_DK"));
126 languages.push_back (make_pair ("Deutsch", "de_DE"));
127 languages.push_back (make_pair ("English", "en_GB"));
128 languages.push_back (make_pair ("Español", "es_ES"));
129 languages.push_back (make_pair ("Français", "fr_FR"));
130 languages.push_back (make_pair ("Italiano", "it_IT"));
131 languages.push_back (make_pair ("Nederlands", "nl_NL"));
132 languages.push_back (make_pair ("Русский", "ru_RU"));
133 languages.push_back (make_pair ("Polski", "pl_PL"));
134 languages.push_back (make_pair ("Português europeu", "pt_PT"));
135 languages.push_back (make_pair ("Português do Brasil", "pt_BR"));
136 languages.push_back (make_pair ("Svenska", "sv_SE"));
137 languages.push_back (make_pair ("Slovenský jazyk", "sk_SK"));
138 languages.push_back (make_pair ("Türkçe", "tr_TR"));
139 languages.push_back (make_pair ("українська мова", "uk_UA"));
140 checked_set (_language, languages);
141 table->Add (_language, wxGBPosition (r, 1));
144 wxStaticText* restart = add_label_to_sizer (
145 table, _panel, _("(restart DCP-o-matic to see language changes)"), false, wxGBPosition (r, 0), wxGBSpan (1, 2)
147 wxFont font = restart->GetFont();
148 font.SetStyle (wxFONTSTYLE_ITALIC);
149 font.SetPointSize (font.GetPointSize() - 1);
150 restart->SetFont (font);
153 _set_language->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::set_language_changed, this));
154 _language->Bind (wxEVT_CHOICE, bind (&GeneralPage::language_changed, this));
158 GeneralPage::add_play_sound_controls (wxGridBagSizer* table, int& r)
160 _sound = new CheckBox (_panel, _("Play sound via"));
161 table->Add (_sound, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
162 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
163 _sound_output = new wxChoice (_panel, wxID_ANY);
164 s->Add (_sound_output, 0);
165 _sound_output_details = new wxStaticText (_panel, wxID_ANY, wxT(""));
166 s->Add (_sound_output_details, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, DCPOMATIC_SIZER_X_GAP);
167 table->Add (s, wxGBPosition(r, 1));
170 wxFont font = _sound_output_details->GetFont();
171 font.SetStyle (wxFONTSTYLE_ITALIC);
172 font.SetPointSize (font.GetPointSize() - 1);
173 _sound_output_details->SetFont (font);
175 RtAudio audio (DCPOMATIC_RTAUDIO_API);
176 for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) {
177 RtAudio::DeviceInfo dev = audio.getDeviceInfo (i);
178 if (dev.probed && dev.outputChannels > 0) {
179 _sound_output->Append (std_to_wx (dev.name));
183 _sound->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::sound_changed, this));
184 _sound_output->Bind (wxEVT_CHOICE, bind (&GeneralPage::sound_output_changed, this));
188 GeneralPage::add_update_controls (wxGridBagSizer* table, int& r)
190 _check_for_updates = new CheckBox (_panel, _("Check for updates on startup"));
191 table->Add (_check_for_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
194 _check_for_test_updates = new CheckBox (_panel, _("Check for testing updates on startup"));
195 table->Add (_check_for_test_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
198 _check_for_updates->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::check_for_updates_changed, this));
199 _check_for_test_updates->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::check_for_test_updates_changed, this));
203 GeneralPage::config_changed ()
205 Config* config = Config::instance ();
207 checked_set (_set_language, static_cast<bool>(config->language()));
209 /* Backwards compatibility of config file */
211 map<string, string> compat_map;
212 compat_map["fr"] = "fr_FR";
213 compat_map["it"] = "it_IT";
214 compat_map["es"] = "es_ES";
215 compat_map["sv"] = "sv_SE";
216 compat_map["de"] = "de_DE";
217 compat_map["nl"] = "nl_NL";
218 compat_map["ru"] = "ru_RU";
219 compat_map["pl"] = "pl_PL";
220 compat_map["da"] = "da_DK";
221 compat_map["pt"] = "pt_PT";
222 compat_map["sk"] = "sk_SK";
223 compat_map["cs"] = "cs_CZ";
224 compat_map["uk"] = "uk_UA";
226 string lang = config->language().get_value_or ("en_GB");
227 if (compat_map.find (lang) != compat_map.end ()) {
228 lang = compat_map[lang];
231 checked_set (_language, lang);
233 checked_set (_check_for_updates, config->check_for_updates ());
234 checked_set (_check_for_test_updates, config->check_for_test_updates ());
236 checked_set (_sound, config->sound ());
238 optional<string> const current_so = get_sound_output ();
239 optional<string> configured_so;
241 if (config->sound_output()) {
242 configured_so = config->sound_output().get();
244 /* No configured output means we should use the default */
245 RtAudio audio (DCPOMATIC_RTAUDIO_API);
247 configured_so = audio.getDeviceInfo(audio.getDefaultOutputDevice()).name;
248 } catch (RtAudioError& e) {
249 /* Probably no audio devices at all */
253 if (configured_so && current_so != configured_so) {
254 /* Update _sound_output with the configured value */
256 while (i < _sound_output->GetCount()) {
257 if (_sound_output->GetString(i) == std_to_wx(*configured_so)) {
258 _sound_output->SetSelection (i);
265 RtAudio audio (DCPOMATIC_RTAUDIO_API);
267 map<int, wxString> apis;
268 apis[RtAudio::MACOSX_CORE] = _("CoreAudio");
269 apis[RtAudio::WINDOWS_ASIO] = _("ASIO");
270 apis[RtAudio::WINDOWS_DS] = _("Direct Sound");
271 apis[RtAudio::WINDOWS_WASAPI] = _("WASAPI");
272 apis[RtAudio::UNIX_JACK] = _("JACK");
273 apis[RtAudio::LINUX_ALSA] = _("ALSA");
274 apis[RtAudio::LINUX_PULSE] = _("PulseAudio");
275 apis[RtAudio::LINUX_OSS] = _("OSS");
276 apis[RtAudio::RTAUDIO_DUMMY] = _("Dummy");
280 for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) {
281 RtAudio::DeviceInfo info = audio.getDeviceInfo(i);
282 if (info.name == *configured_so && info.outputChannels > 0) {
283 channels = info.outputChannels;
288 _sound_output_details->SetLabel (
289 wxString::Format(_("%d channels on %s"), channels, apis[audio.getCurrentApi()])
292 setup_sensitivity ();
296 GeneralPage::setup_sensitivity ()
298 _language->Enable (_set_language->GetValue ());
299 _check_for_test_updates->Enable (_check_for_updates->GetValue ());
300 _sound_output->Enable (_sound->GetValue ());
303 /** @return Currently-selected preview sound output in the dialogue */
305 GeneralPage::get_sound_output ()
307 int const sel = _sound_output->GetSelection ();
308 if (sel == wxNOT_FOUND) {
309 return optional<string> ();
312 return wx_to_std (_sound_output->GetString (sel));
316 GeneralPage::set_language_changed ()
318 setup_sensitivity ();
319 if (_set_language->GetValue ()) {
322 Config::instance()->unset_language ();
327 GeneralPage::language_changed ()
329 int const sel = _language->GetSelection ();
331 Config::instance()->set_language (string_client_data (_language->GetClientObject (sel)));
333 Config::instance()->unset_language ();
338 GeneralPage::check_for_updates_changed ()
340 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
344 GeneralPage::check_for_test_updates_changed ()
346 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
350 GeneralPage::sound_changed ()
352 Config::instance()->set_sound (_sound->GetValue ());
356 GeneralPage::sound_output_changed ()
358 RtAudio audio (DCPOMATIC_RTAUDIO_API);
359 optional<string> const so = get_sound_output();
360 if (!so || *so == audio.getDeviceInfo(audio.getDefaultOutputDevice()).name) {
361 Config::instance()->unset_sound_output ();
363 Config::instance()->set_sound_output (*so);
367 CertificateChainEditor::CertificateChainEditor (
371 function<void (shared_ptr<dcp::CertificateChain>)> set,
372 function<shared_ptr<const dcp::CertificateChain> (void)> get,
373 function<bool (void)> nag_alter
375 : wxDialog (parent, wxID_ANY, title)
378 , _nag_alter (nag_alter)
380 wxFont subheading_font (*wxNORMAL_FONT);
381 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
383 _sizer = new wxBoxSizer (wxVERTICAL);
386 wxStaticText* m = new StaticText (this, title);
387 m->SetFont (subheading_font);
388 _sizer->Add (m, 0, wxALL, border);
391 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
392 _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
394 _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
399 ip.SetText (_("Type"));
401 _certificates->InsertColumn (0, ip);
407 ip.SetText (_("Thumbprint"));
410 wxFont font = ip.GetFont ();
411 font.SetFamily (wxFONTFAMILY_TELETYPE);
414 _certificates->InsertColumn (1, ip);
417 certificates_sizer->Add (_certificates, 1, wxEXPAND);
420 wxSizer* s = new wxBoxSizer (wxVERTICAL);
421 _add_certificate = new Button (this, _("Add..."));
422 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
423 _remove_certificate = new Button (this, _("Remove"));
424 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
425 _export_certificate = new Button (this, _("Export"));
426 s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
427 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
430 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
431 _sizer->Add (table, 1, wxALL | wxEXPAND, border);
434 add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
435 _private_key = new StaticText (this, wxT(""));
436 wxFont font = _private_key->GetFont ();
437 font.SetFamily (wxFONTFAMILY_TELETYPE);
438 _private_key->SetFont (font);
439 table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
440 _import_private_key = new Button (this, _("Import..."));
441 table->Add (_import_private_key, wxGBPosition (r, 2));
442 _export_private_key = new Button (this, _("Export..."));
443 table->Add (_export_private_key, wxGBPosition (r, 3));
446 _button_sizer = new wxBoxSizer (wxHORIZONTAL);
447 _remake_certificates = new Button (this, _("Re-make certificates and key..."));
448 _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
449 _export_chain = new Button (this, _("Export chain..."));
450 _button_sizer->Add (_export_chain, 1, wxRIGHT, border);
451 table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
454 _private_key_bad = new StaticText (this, _("Leaf private key does not match leaf certificate!"));
455 font = *wxSMALL_FONT;
456 font.SetWeight (wxFONTWEIGHT_BOLD);
457 _private_key_bad->SetFont (font);
458 table->Add (_private_key_bad, wxGBPosition (r, 0), wxGBSpan (1, 3));
461 _add_certificate->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::add_certificate, this));
462 _remove_certificate->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::remove_certificate, this));
463 _export_certificate->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::export_certificate, this));
464 _certificates->Bind (wxEVT_LIST_ITEM_SELECTED, bind (&CertificateChainEditor::update_sensitivity, this));
465 _certificates->Bind (wxEVT_LIST_ITEM_DESELECTED, bind (&CertificateChainEditor::update_sensitivity, this));
466 _remake_certificates->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::remake_certificates, this));
467 _export_chain->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::export_chain, this));
468 _import_private_key->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::import_private_key, this));
469 _export_private_key->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::export_private_key, this));
471 wxSizer* buttons = CreateSeparatedButtonSizer (wxCLOSE);
473 _sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
476 SetSizerAndFit (_sizer);
478 update_certificate_list ();
479 update_private_key ();
480 update_sensitivity ();
484 CertificateChainEditor::add_button (wxWindow* button)
486 _button_sizer->Add (button, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
491 CertificateChainEditor::add_certificate ()
493 wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
495 if (d->ShowModal() == wxID_OK) {
500 extra = c.read_string (dcp::file_to_string (wx_to_std (d->GetPath ())));
501 } catch (boost::filesystem::filesystem_error& e) {
502 error_dialog (this, _("Could not import certificate (%s)"), d->GetPath());
507 if (!extra.empty ()) {
510 _("This file contains other certificates (or other data) after its first certificate. "
511 "Only the first certificate will be used.")
514 shared_ptr<dcp::CertificateChain> chain(new dcp::CertificateChain(*_get().get()));
516 if (!chain->chain_valid ()) {
519 _("Adding this certificate would make the chain inconsistent, so it will not be added. "
520 "Add certificates in order from root to intermediate to leaf.")
525 update_certificate_list ();
527 } catch (dcp::MiscError& e) {
528 error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what()));
534 update_sensitivity ();
538 CertificateChainEditor::remove_certificate ()
541 /* Cancel was clicked */
545 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
550 _certificates->DeleteItem (i);
551 shared_ptr<dcp::CertificateChain> chain(new dcp::CertificateChain(*_get().get()));
555 update_sensitivity ();
559 CertificateChainEditor::export_certificate ()
561 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
566 wxFileDialog* d = new wxFileDialog (
567 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
568 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
571 dcp::CertificateChain::List all = _get()->root_to_leaf ();
572 dcp::CertificateChain::List::iterator j = all.begin ();
573 for (int k = 0; k < i; ++k) {
577 if (d->ShowModal () == wxID_OK) {
578 boost::filesystem::path path (wx_to_std(d->GetPath()));
579 FILE* f = fopen_boost (path, "w");
581 throw OpenFileError (path, errno, false);
584 string const s = j->certificate (true);
585 checked_fwrite (s.c_str(), s.length(), f, path);
592 CertificateChainEditor::export_chain ()
594 wxFileDialog* d = new wxFileDialog (
595 this, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT("PEM files (*.pem)|*.pem"),
596 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
599 if (d->ShowModal () == wxID_OK) {
600 boost::filesystem::path path (wx_to_std(d->GetPath()));
601 FILE* f = fopen_boost (path, "w");
603 throw OpenFileError (path, errno, false);
606 string const s = _get()->chain();
607 checked_fwrite (s.c_str(), s.length(), f, path);
615 CertificateChainEditor::update_certificate_list ()
617 _certificates->DeleteAllItems ();
619 dcp::CertificateChain::List certs = _get()->root_to_leaf ();
620 BOOST_FOREACH (dcp::Certificate const & i, certs) {
623 _certificates->InsertItem (item);
624 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
627 _certificates->SetItem (n, 0, _("Root"));
628 } else if (n == (certs.size() - 1)) {
629 _certificates->SetItem (n, 0, _("Leaf"));
631 _certificates->SetItem (n, 0, _("Intermediate"));
637 static wxColour normal = _private_key_bad->GetForegroundColour ();
639 if (_get()->private_key_valid()) {
640 _private_key_bad->Hide ();
641 _private_key_bad->SetForegroundColour (normal);
643 _private_key_bad->Show ();
644 _private_key_bad->SetForegroundColour (wxColour (255, 0, 0));
649 CertificateChainEditor::remake_certificates ()
651 shared_ptr<const dcp::CertificateChain> chain = _get();
653 string subject_organization_name;
654 string subject_organizational_unit_name;
655 string root_common_name;
656 string intermediate_common_name;
657 string leaf_common_name;
659 dcp::CertificateChain::List all = chain->root_to_leaf ();
661 if (all.size() >= 1) {
663 subject_organization_name = chain->root().subject_organization_name ();
664 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
665 root_common_name = chain->root().subject_common_name ();
668 if (all.size() >= 2) {
670 leaf_common_name = chain->leaf().subject_common_name ();
673 if (all.size() >= 3) {
674 /* Have an intermediate */
675 dcp::CertificateChain::List::iterator i = all.begin ();
677 intermediate_common_name = i->subject_common_name ();
681 /* Cancel was clicked */
685 MakeChainDialog* d = new MakeChainDialog (
687 subject_organization_name,
688 subject_organizational_unit_name,
690 intermediate_common_name,
694 if (d->ShowModal () == wxID_OK) {
696 shared_ptr<dcp::CertificateChain> (
697 new dcp::CertificateChain (
700 d->organisational_unit (),
701 d->root_common_name (),
702 d->intermediate_common_name (),
703 d->leaf_common_name ()
708 update_certificate_list ();
709 update_private_key ();
716 CertificateChainEditor::update_sensitivity ()
718 /* We can only remove the leaf certificate */
719 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) == (_certificates->GetItemCount() - 1));
720 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
724 CertificateChainEditor::update_private_key ()
726 checked_set (_private_key, dcp::private_key_fingerprint (_get()->key().get()));
731 CertificateChainEditor::import_private_key ()
733 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
735 if (d->ShowModal() == wxID_OK) {
737 boost::filesystem::path p (wx_to_std (d->GetPath ()));
738 if (boost::filesystem::file_size (p) > 8192) {
741 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
746 shared_ptr<dcp::CertificateChain> chain(new dcp::CertificateChain(*_get().get()));
747 chain->set_key (dcp::file_to_string (p));
749 update_private_key ();
750 } catch (dcp::MiscError& e) {
751 error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what()));
757 update_sensitivity ();
761 CertificateChainEditor::export_private_key ()
763 optional<string> key = _get()->key();
768 wxFileDialog* d = new wxFileDialog (
769 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
770 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
773 if (d->ShowModal () == wxID_OK) {
774 boost::filesystem::path path (wx_to_std(d->GetPath()));
775 FILE* f = fopen_boost (path, "w");
777 throw OpenFileError (path, errno, false);
780 string const s = _get()->key().get ();
781 checked_fwrite (s.c_str(), s.length(), f, path);
788 KeysPage::GetName () const
796 wxFont subheading_font (*wxNORMAL_FONT);
797 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
799 wxSizer* sizer = _panel->GetSizer();
802 wxStaticText* m = new StaticText (_panel, _("Decrypting KDMs"));
803 m->SetFont (subheading_font);
804 sizer->Add (m, 0, wxALL, _border);
807 wxButton* export_decryption_certificate = new Button (_panel, _("Export KDM decryption certificate..."));
808 sizer->Add (export_decryption_certificate, 0, wxLEFT, _border);
809 wxButton* export_settings = new Button (_panel, _("Export all KDM decryption settings..."));
810 sizer->Add (export_settings, 0, wxLEFT, _border);
811 wxButton* import_settings = new Button (_panel, _("Import all KDM decryption settings..."));
812 sizer->Add (import_settings, 0, wxLEFT, _border);
813 wxButton* decryption_advanced = new Button (_panel, _("Advanced..."));
814 sizer->Add (decryption_advanced, 0, wxALL, _border);
816 export_decryption_certificate->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_certificate, this));
817 export_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_chain_and_key, this));
818 import_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::import_decryption_chain_and_key, this));
819 decryption_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::decryption_advanced, this));
822 wxStaticText* m = new StaticText (_panel, _("Signing DCPs and KDMs"));
823 m->SetFont (subheading_font);
824 sizer->Add (m, 0, wxALL, _border);
827 wxButton* signing_advanced = new Button (_panel, _("Advanced..."));
828 sizer->Add (signing_advanced, 0, wxLEFT, _border);
829 signing_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::signing_advanced, this));
833 KeysPage::decryption_advanced ()
835 CertificateChainEditor* c = new CertificateChainEditor (
836 _panel, _("Decrypting KDMs"), _border,
837 bind (&Config::set_decryption_chain, Config::instance (), _1),
838 bind (&Config::decryption_chain, Config::instance ()),
839 bind (&KeysPage::nag_alter_decryption_chain, this)
846 KeysPage::signing_advanced ()
848 CertificateChainEditor* c = new CertificateChainEditor (
849 _panel, _("Signing DCPs and KDMs"), _border,
850 bind (&Config::set_signer_chain, Config::instance (), _1),
851 bind (&Config::signer_chain, Config::instance ()),
859 KeysPage::export_decryption_chain_and_key ()
861 wxFileDialog* d = new wxFileDialog (
862 _panel, _("Select Export File"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom"),
863 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
866 if (d->ShowModal () == wxID_OK) {
867 boost::filesystem::path path (wx_to_std(d->GetPath()));
868 FILE* f = fopen_boost (path, "w");
870 throw OpenFileError (path, errno, false);
873 string const chain = Config::instance()->decryption_chain()->chain();
874 checked_fwrite (chain.c_str(), chain.length(), f, path);
875 optional<string> const key = Config::instance()->decryption_chain()->key();
876 DCPOMATIC_ASSERT (key);
877 checked_fwrite (key->c_str(), key->length(), f, path);
885 KeysPage::import_decryption_chain_and_key ()
887 if (NagDialog::maybe_nag (
889 Config::NAG_IMPORT_DECRYPTION_CHAIN,
890 _("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!"),
896 wxFileDialog* d = new wxFileDialog (
897 _panel, _("Select File To Import"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom")
900 if (d->ShowModal () == wxID_OK) {
901 shared_ptr<dcp::CertificateChain> new_chain(new dcp::CertificateChain());
903 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "r");
905 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
911 if (fgets (buffer, 128, f) == 0) {
915 if (strncmp (buffer, "-----END CERTIFICATE-----", 25) == 0) {
916 new_chain->add (dcp::Certificate (current));
918 } else if (strncmp (buffer, "-----END RSA PRIVATE KEY-----", 29) == 0) {
919 new_chain->set_key (current);
925 if (new_chain->chain_valid() && new_chain->private_key_valid()) {
926 Config::instance()->set_decryption_chain (new_chain);
928 error_dialog (_panel, _("Invalid DCP-o-matic export file"));
935 KeysPage::nag_alter_decryption_chain ()
937 return NagDialog::maybe_nag (
939 Config::NAG_ALTER_DECRYPTION_CHAIN,
940 _("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!"),
946 KeysPage::export_decryption_certificate ()
948 wxFileDialog* d = new wxFileDialog (
949 _panel, _("Select Certificate File"), wxEmptyString, _("dcpomatic_kdm_decryption_cert.pem"), wxT ("PEM files (*.pem)|*.pem"),
950 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
953 if (d->ShowModal () == wxID_OK) {
954 boost::filesystem::path path (wx_to_std(d->GetPath()));
955 FILE* f = fopen_boost (path, "w");
957 throw OpenFileError (path, errno, false);
960 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
961 checked_fwrite (s.c_str(), s.length(), f, path);