Cleanup: stack-allocated dialogs.
[dcpomatic.git] / src / wx / dolby_doremi_certificate_panel.cc
1 /*
2     Copyright (C) 2014-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
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.
10
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.
15
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/>.
18
19 */
20
21
22 #include "dolby_doremi_certificate_panel.h"
23 #include "download_certificate_dialog.h"
24 #include "wx_util.h"
25 #include "lib/compose.hpp"
26 #include "lib/internet.h"
27 #include "lib/signal_manager.h"
28 #include "lib/util.h"
29 #include <dcp/raw_convert.h>
30 #include <curl/curl.h>
31 #include <zip.h>
32 #include <boost/algorithm/string.hpp>
33
34
35 using std::function;
36 using std::string;
37 using std::vector;
38 using namespace boost::algorithm;
39 using boost::optional;
40 #if BOOST_VERSION >= 106100
41 using namespace boost::placeholders;
42 #endif
43 using dcp::raw_convert;
44
45
46 class Location
47 {
48 public:
49         Location(string url_, string file_)
50                 : url(url_)
51                 , file(file_)
52         {}
53
54         string url;
55         string file;
56 };
57
58
59 DolbyDoremiCertificatePanel::DolbyDoremiCertificatePanel (DownloadCertificateDialog* dialog)
60         : DownloadCertificatePanel (dialog)
61 {
62
63 }
64
65
66 static void
67 try_dcp2000(vector<Location>& locations, string prefix, string serial)
68 {
69         locations.push_back({
70                 String::compose("%1%2xxx/Dolby-DCP2000-%3.dcicerts.zip", prefix, serial.substr(0, 3), serial),
71                 String::compose("Dolby-DCP2000-%1.cert.sha256.pem", serial)
72         });
73
74         locations.push_back({
75                 String::compose("%1%2xxx/Dolby-DCP2000-%3.dcicerts.zip", prefix, serial.substr(0, 3), serial),
76                 String::compose("Dolby-DCP2000-%1.cert.sha256.pem", serial)
77         });
78
79         locations.push_back({
80                 String::compose("%1%2xxx/Dolby-DCP2000-%3.certs.zip", prefix, serial.substr(0, 3), serial),
81                 String::compose("Dolby-DCP2000-%1.cert.sha256.pem", serial)
82         });
83
84         locations.push_back({
85                 String::compose("%1%2xxx/dcp2000-%3.dcicerts.zip", prefix, serial.substr(0, 3), serial),
86                 String::compose("dcp2000-%1.cert.sha256.pem", serial)
87         });
88
89         locations.push_back({
90                 String::compose("%1%2xxx/dcp2000-%3.dcicerts.zip", prefix, serial.substr(0, 3), serial),
91                 String::compose("dcp2000-%1.cert.sha256.pem", serial)
92         });
93
94         locations.push_back({
95                 String::compose("%1%2xxx/dcp2000-%3.certs.zip", prefix, serial.substr(0, 3), serial),
96                 String::compose("dcp2000-%1.cert.sha256.pem", serial)
97         });
98 }
99
100
101 static void
102 try_imb(vector<Location>& locations, string prefix, string serial)
103 {
104         locations.push_back({
105                 String::compose("%1%2xxx/imb-%3.dcicerts.zip", prefix, serial.substr(0, 3), serial),
106                 String::compose("imb-%1.cert.sha256.pem", serial)
107         });
108 }
109
110
111 static void
112 try_ims(vector<Location>& locations, string prefix, string serial)
113 {
114         locations.push_back({
115                 String::compose("%1%2xxx/Dolby-IMB-%3.dcicerts.zip", prefix, serial.substr(0, 3), serial),
116                 String::compose("Dolby-IMB-%1.cert.sha256.pem", serial)
117         });
118
119         locations.push_back({
120                 String::compose("%1%2xxx/ims-%3.dcicerts.zip", prefix, serial.substr(0, 3), serial),
121                 String::compose("ims-%1.cert.sha256.pem", serial)
122         });
123 }
124
125
126 static void
127 try_cat862(vector<Location>& locations, string prefix, string serial)
128 {
129         int const serial_int = raw_convert<int> (serial);
130
131         string cat862;
132         if (serial_int <= 510999) {
133                 cat862 = "CAT862_510999_and_lower";
134         } else if (serial_int >= 617000) {
135                 cat862 = "CAT862_617000_and_higher";
136         } else {
137                 int const lower = serial_int - (serial_int % 1000);
138                 cat862 = String::compose ("CAT862_%1-%2", lower, lower + 999);
139         }
140
141         locations.push_back({
142                 String::compose("%1%2/cert_Dolby256-CAT862-%3.zip", prefix, cat862, serial_int),
143                 String::compose("cert_Dolby256-CAT862-%1.pem.crt", serial_int)
144         });
145 }
146
147
148 static void
149 try_dsp100(vector<Location>& locations, string prefix, string serial)
150 {
151         int const serial_int = raw_convert<int>(serial);
152
153         string dsp100;
154         if (serial_int <= 999) {
155                 dsp100 = "DSP100_053_thru_999";
156         } else if (serial_int >= 3000) {
157                 dsp100 = "DSP100_3000_and_higher";
158         } else {
159                 int const lower = serial_int - (serial_int % 1000);
160                 dsp100 = String::compose ("DSP100_%1_thru_%2", lower, lower + 999);
161         }
162
163         locations.push_back({
164                 String::compose("%1%2/cert_Dolby256-DSP100-%3.zip", prefix, dsp100, serial_int),
165                 String::compose("cert_Dolby256-DSP100-%1.pem.crt", serial_int)
166         });
167 }
168
169
170 static void
171 try_cat745(vector<Location>& locations, string prefix, string serial)
172 {
173         int const serial_int = raw_convert<int>(serial.substr (1));
174
175         string cat745;
176         if (serial_int <= 999) {
177                 cat745 = "CAT745_1_thru_999";
178         } else if (serial_int >= 6000) {
179                 cat745 = "CAT745_6000_and_higher";
180         } else {
181                 int const lower = serial_int - (serial_int % 1000);
182                 cat745 = String::compose("CAT745_%1_thru_%2", lower, lower + 999);
183         }
184
185         locations.push_back({
186                 String::compose("%1%2/cert_Dolby-CAT745-%3.zip", prefix, cat745, serial_int),
187                 String::compose("cert_Dolby-CAT745-%1.pem.crt", serial_int)
188         });
189 }
190
191
192 static void
193 try_cp850(vector<Location>& locations, string prefix, string serial)
194 {
195         int const serial_int = raw_convert<int> (serial.substr (1));
196
197         int const lower = serial_int - (serial_int % 1000);
198         locations.push_back({
199                 String::compose ("%1CP850_CAT1600_F%2-F%3/cert_RMB_SPB_MDE_FMA.Dolby-CP850-F%4.zip", prefix, lower, lower + 999, serial_int),
200                 String::compose ("cert_RMB_SPB_MDE_FMA.Dolby-CP850-F%1.pem.crt", serial_int)
201         });
202 }
203
204
205 static void
206 try_ims3000(vector<Location>& locations, string prefix, string serial)
207 {
208         locations.push_back({
209                 String::compose ("%1%2xxx/cert_Dolby-IMS3000-%3-SMPTE.zip", prefix, serial.substr(0, 3), serial),
210                 String::compose("cert_Dolby-IMS3000-%1-SMPTE.pem", serial)
211         });
212 }
213
214
215 void
216 DolbyDoremiCertificatePanel::do_download ()
217 {
218         string serial = wx_to_std(_serial->GetValue());
219         trim(serial);
220
221         /* Try dcp2000, imb and ims prefixes (see mantis #375) */
222
223         string const prefix = "ftp://ftp.cinema.dolby.com/Certificates/";
224         vector<Location> locations;
225
226         bool starts_with_digit = false;
227         optional<char> starting_char;
228
229         if (!serial.empty()) {
230                 if (isdigit (serial[0])) {
231                         starts_with_digit = true;
232                 } else {
233                         starting_char = serial[0];
234                 }
235         }
236
237         vector<string> errors;
238
239         if (starts_with_digit) {
240                 try_dcp2000(locations, prefix, serial);
241                 try_imb(locations, prefix, serial);
242                 try_ims(locations, prefix, serial);
243                 try_cat862(locations, prefix, serial);
244                 try_dsp100(locations, prefix, serial);
245                 try_ims3000(locations, prefix, serial);
246         } else if (starting_char == 'H') {
247                 try_cat745(locations, prefix, serial);
248         } else if (starting_char == 'F') {
249                 try_cp850(locations, prefix, serial);
250         } else {
251                 errors.push_back(wx_to_std(_("Unrecognised serial number format (does not start with a number, H or F)")));
252         }
253
254         bool ok = false;
255         auto location = locations.begin();
256         while (!ok && location != locations.end()) {
257                 auto error = get_from_zip_url(location->url, location->file, true, true, boost::bind(&DownloadCertificatePanel::load_certificate, this, _1, _2));
258                 ++location;
259                 if (error) {
260                         errors.push_back (error.get ());
261                 } else {
262                         ok = true;
263                 }
264         }
265
266         if (ok) {
267                 _dialog->message()->SetLabel (_("Certificate downloaded"));
268                 _dialog->setup_sensitivity ();
269         } else {
270                 _dialog->message()->SetLabel (wxT (""));
271
272                 string s;
273                 for (auto e: errors) {
274                         s += e + "\n";
275                 }
276
277                 error_dialog (this, std_to_wx (s));
278         }
279 }
280
281
282 wxString
283 DolbyDoremiCertificatePanel::name () const
284 {
285         return _("Dolby / Doremi");
286 }