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 optional<boost::filesystem::path> path = path_from_file_dialog (d, "pem");
531 FILE* f = fopen_boost (*path, "w");
533 throw OpenFileError (*path, errno, false);
536 string const s = j->certificate (true);
537 fwrite (s.c_str(), 1, s.length(), f);
545 CertificateChainEditor::update_certificate_list ()
547 _certificates->DeleteAllItems ();
549 dcp::CertificateChain::List certs = _get()->root_to_leaf ();
550 BOOST_FOREACH (dcp::Certificate const & i, certs) {
553 _certificates->InsertItem (item);
554 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
557 _certificates->SetItem (n, 0, _("Root"));
558 } else if (n == (certs.size() - 1)) {
559 _certificates->SetItem (n, 0, _("Leaf"));
561 _certificates->SetItem (n, 0, _("Intermediate"));
567 static wxColour normal = _private_key_bad->GetForegroundColour ();
569 if (_get()->private_key_valid()) {
570 _private_key_bad->Hide ();
571 _private_key_bad->SetForegroundColour (normal);
573 _private_key_bad->Show ();
574 _private_key_bad->SetForegroundColour (wxColour (255, 0, 0));
579 CertificateChainEditor::remake_certificates ()
581 shared_ptr<const dcp::CertificateChain> chain = _get();
583 string subject_organization_name;
584 string subject_organizational_unit_name;
585 string root_common_name;
586 string intermediate_common_name;
587 string leaf_common_name;
589 dcp::CertificateChain::List all = chain->root_to_leaf ();
591 if (all.size() >= 1) {
593 subject_organization_name = chain->root().subject_organization_name ();
594 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
595 root_common_name = chain->root().subject_common_name ();
598 if (all.size() >= 2) {
600 leaf_common_name = chain->leaf().subject_common_name ();
603 if (all.size() >= 3) {
604 /* Have an intermediate */
605 dcp::CertificateChain::List::iterator i = all.begin ();
607 intermediate_common_name = i->subject_common_name ();
611 /* Cancel was clicked */
615 MakeChainDialog* d = new MakeChainDialog (
617 subject_organization_name,
618 subject_organizational_unit_name,
620 intermediate_common_name,
624 if (d->ShowModal () == wxID_OK) {
626 shared_ptr<dcp::CertificateChain> (
627 new dcp::CertificateChain (
630 d->organisational_unit (),
631 d->root_common_name (),
632 d->intermediate_common_name (),
633 d->leaf_common_name ()
638 update_certificate_list ();
639 update_private_key ();
646 CertificateChainEditor::update_sensitivity ()
648 /* We can only remove the leaf certificate */
649 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) == (_certificates->GetItemCount() - 1));
650 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
654 CertificateChainEditor::update_private_key ()
656 checked_set (_private_key, dcp::private_key_fingerprint (_get()->key().get()));
661 CertificateChainEditor::import_private_key ()
663 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
665 if (d->ShowModal() == wxID_OK) {
667 boost::filesystem::path p (wx_to_std (d->GetPath ()));
668 if (boost::filesystem::file_size (p) > 8192) {
671 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
676 shared_ptr<dcp::CertificateChain> chain(new dcp::CertificateChain(*_get().get()));
677 chain->set_key (dcp::file_to_string (p));
679 update_private_key ();
680 } catch (dcp::MiscError& e) {
681 error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what()));
687 update_sensitivity ();
691 CertificateChainEditor::export_private_key ()
693 optional<string> key = _get()->key();
698 wxFileDialog* d = new wxFileDialog (
699 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
700 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
703 if (d->ShowModal () == wxID_OK) {
704 optional<boost::filesystem::path> path = path_from_file_dialog (d, "pem");
706 FILE* f = fopen_boost (*path, "w");
708 throw OpenFileError (*path, errno, false);
711 string const s = _get()->key().get ();
712 fwrite (s.c_str(), 1, s.length(), f);
720 KeysPage::GetName () const
728 wxFont subheading_font (*wxNORMAL_FONT);
729 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
731 wxSizer* sizer = _panel->GetSizer();
734 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Decrypting KDMs"));
735 m->SetFont (subheading_font);
736 sizer->Add (m, 0, wxALL, _border);
739 wxButton* export_decryption_certificate = new wxButton (_panel, wxID_ANY, _("Export KDM decryption certificate..."));
740 sizer->Add (export_decryption_certificate, 0, wxLEFT, _border);
741 wxButton* export_decryption_chain = new wxButton (_panel, wxID_ANY, _("Export KDM decryption chain..."));
742 sizer->Add (export_decryption_chain, 0, wxLEFT, _border);
743 wxButton* export_settings = new wxButton (_panel, wxID_ANY, _("Export all KDM decryption settings..."));
744 sizer->Add (export_settings, 0, wxLEFT, _border);
745 wxButton* import_settings = new wxButton (_panel, wxID_ANY, _("Import all KDM decryption settings..."));
746 sizer->Add (import_settings, 0, wxLEFT, _border);
747 wxButton* decryption_advanced = new wxButton (_panel, wxID_ANY, _("Advanced..."));
748 sizer->Add (decryption_advanced, 0, wxALL, _border);
750 export_decryption_certificate->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_certificate, this));
751 export_decryption_chain->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_chain, this));
752 export_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_chain_and_key, this));
753 import_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::import_decryption_chain_and_key, this));
754 decryption_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::decryption_advanced, this));
757 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Signing DCPs and KDMs"));
758 m->SetFont (subheading_font);
759 sizer->Add (m, 0, wxALL, _border);
762 wxButton* signing_advanced = new wxButton (_panel, wxID_ANY, _("Advanced..."));
763 sizer->Add (signing_advanced, 0, wxLEFT, _border);
764 signing_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::signing_advanced, this));
768 KeysPage::decryption_advanced ()
770 CertificateChainEditor* c = new CertificateChainEditor (
771 _panel, _("Decrypting KDMs"), _border,
772 bind (&Config::set_decryption_chain, Config::instance (), _1),
773 bind (&Config::decryption_chain, Config::instance ()),
774 bind (&KeysPage::nag_remake_decryption_chain, this)
781 KeysPage::signing_advanced ()
783 CertificateChainEditor* c = new CertificateChainEditor (
784 _panel, _("Signing DCPs and KDMs"), _border,
785 bind (&Config::set_signer_chain, Config::instance (), _1),
786 bind (&Config::signer_chain, Config::instance ()),
794 KeysPage::export_decryption_chain_and_key ()
796 wxFileDialog* d = new wxFileDialog (
797 _panel, _("Select Export File"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom"),
798 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
801 if (d->ShowModal () == wxID_OK) {
802 optional<boost::filesystem::path> path = path_from_file_dialog (d, "dom");
804 FILE* f = fopen_boost (*path, "w");
806 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
809 string const chain = Config::instance()->decryption_chain()->chain();
810 fwrite (chain.c_str(), 1, chain.length(), f);
811 optional<string> const key = Config::instance()->decryption_chain()->key();
812 DCPOMATIC_ASSERT (key);
813 fwrite (key->c_str(), 1, key->length(), f);
822 KeysPage::import_decryption_chain_and_key ()
824 wxFileDialog* d = new wxFileDialog (
825 _panel, _("Select File To Import"), wxEmptyString, wxEmptyString, wxT ("DOM files (*.dom)|*.dom")
828 if (d->ShowModal () == wxID_OK) {
829 shared_ptr<dcp::CertificateChain> new_chain(new dcp::CertificateChain());
831 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "r");
833 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
839 if (fgets (buffer, 128, f) == 0) {
843 if (strncmp (buffer, "-----END CERTIFICATE-----", 25) == 0) {
844 new_chain->add (dcp::Certificate (current));
846 } else if (strncmp (buffer, "-----END RSA PRIVATE KEY-----", 29) == 0) {
847 new_chain->set_key (current);
853 if (new_chain->chain_valid() && new_chain->private_key_valid()) {
854 Config::instance()->set_decryption_chain (new_chain);
856 error_dialog (_panel, _("Invalid DCP-o-matic export file"));
863 KeysPage::nag_remake_decryption_chain ()
865 return NagDialog::maybe_nag (
867 Config::NAG_REMAKE_DECRYPTION_CHAIN,
868 _("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!"),
874 KeysPage::export_decryption_chain ()
876 wxFileDialog* d = new wxFileDialog (
877 _panel, _("Select Chain File"), wxEmptyString, _("dcpomatic_kdm_decryption_chain.pem"), wxT ("PEM files (*.pem)|*.pem"),
878 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
881 if (d->ShowModal () == wxID_OK) {
882 optional<boost::filesystem::path> path = path_from_file_dialog (d, "pem");
884 FILE* f = fopen_boost (*path, "w");
886 throw OpenFileError (*path, errno, false);
889 string const s = Config::instance()->decryption_chain()->chain();
890 fwrite (s.c_str(), 1, s.length(), f);
898 KeysPage::export_decryption_certificate ()
900 wxFileDialog* d = new wxFileDialog (
901 _panel, _("Select Certificate File"), wxEmptyString, _("dcpomatic_kdm_decryption_cert.pem"), wxT ("PEM files (*.pem)|*.pem"),
902 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
905 if (d->ShowModal () == wxID_OK) {
906 optional<boost::filesystem::path> path = path_from_file_dialog (d, "pem");
908 FILE* f = fopen_boost (*path, "w");
910 throw OpenFileError (*path, errno, false);
913 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
914 fwrite (s.c_str(), 1, s.length(), f);