1 | /* |
2 | * Copyright (C) 2003-2005 Justin Karneges <justin@affinix.com> |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library; if not, write to the Free Software |
16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
17 | * |
18 | */ |
19 | |
20 | #include "gpgop.h" |
21 | #include "gpgaction.h" |
22 | #include "gpgop_p.h" |
23 | |
24 | namespace gpgQCAPlugin { |
25 | |
26 | //---------------------------------------------------------------------------- |
27 | // GpgOp |
28 | //---------------------------------------------------------------------------- |
29 | GpgOp::Private::Private(GpgOp *_q) |
30 | : QObject(_q) |
31 | , sync(_q) |
32 | , q(_q) |
33 | , act(nullptr) |
34 | , waiting(false) |
35 | { |
36 | reset(mode: ResetAll); |
37 | } |
38 | |
39 | GpgOp::Private::~Private() |
40 | { |
41 | reset(mode: ResetAll); |
42 | } |
43 | |
44 | void GpgOp::Private::reset(ResetMode mode) |
45 | { |
46 | if (act) { |
47 | act->disconnect(receiver: this); |
48 | act->setParent(nullptr); |
49 | act->deleteLater(); |
50 | |
51 | act = nullptr; |
52 | } |
53 | |
54 | if (mode >= ResetSessionAndData) { |
55 | output = GpgAction::Output(); |
56 | result.clear(); |
57 | diagnosticText = QString(); |
58 | eventList.clear(); |
59 | } |
60 | |
61 | if (mode >= ResetAll) { |
62 | opt_ascii = false; |
63 | opt_noagent = false; |
64 | opt_alwaystrust = false; |
65 | opt_pubfile = QString(); |
66 | opt_secfile = QString(); |
67 | } |
68 | } |
69 | |
70 | void GpgOp::Private::make_act(GpgOp::Type _op) |
71 | { |
72 | reset(mode: ResetSessionAndData); |
73 | |
74 | op = _op; |
75 | |
76 | act = new GpgAction(this); |
77 | |
78 | connect(sender: act, signal: &GpgAction::readyRead, context: this, slot: &GpgOp::Private::act_readyRead); |
79 | connect(sender: act, signal: &GpgAction::bytesWritten, context: this, slot: &GpgOp::Private::act_bytesWritten); |
80 | connect(sender: act, signal: &GpgAction::needPassphrase, context: this, slot: &GpgOp::Private::act_needPassphrase); |
81 | connect(sender: act, signal: &GpgAction::needCard, context: this, slot: &GpgOp::Private::act_needCard); |
82 | connect(sender: act, signal: &GpgAction::finished, context: this, slot: &GpgOp::Private::act_finished); |
83 | connect(sender: act, signal: &GpgAction::readyReadDiagnosticText, context: this, slot: &GpgOp::Private::act_readyReadDiagnosticText); |
84 | |
85 | act->input.bin = bin; |
86 | act->input.op = op; |
87 | act->input.opt_ascii = opt_ascii; |
88 | act->input.opt_noagent = opt_noagent; |
89 | act->input.opt_alwaystrust = opt_alwaystrust; |
90 | act->input.opt_pubfile = opt_pubfile; |
91 | act->input.opt_secfile = opt_secfile; |
92 | } |
93 | |
94 | void GpgOp::Private::eventReady(const GpgOp::Event &e) |
95 | { |
96 | eventList += e; |
97 | sync.conditionMet(); |
98 | } |
99 | |
100 | void GpgOp::Private::eventReady(GpgOp::Event::Type type) |
101 | { |
102 | GpgOp::Event e; |
103 | e.type = type; |
104 | eventReady(e); |
105 | } |
106 | |
107 | void GpgOp::Private::eventReady(GpgOp::Event::Type type, int written) |
108 | { |
109 | GpgOp::Event e; |
110 | e.type = type; |
111 | e.written = written; |
112 | eventReady(e); |
113 | } |
114 | |
115 | void GpgOp::Private::eventReady(GpgOp::Event::Type type, const QString &keyId) |
116 | { |
117 | GpgOp::Event e; |
118 | e.type = type; |
119 | e.keyId = keyId; |
120 | eventReady(e); |
121 | } |
122 | |
123 | void GpgOp::Private::act_readyRead() |
124 | { |
125 | if (waiting) |
126 | eventReady(type: GpgOp::Event::ReadyRead); |
127 | else |
128 | emit q->readyRead(); |
129 | } |
130 | |
131 | void GpgOp::Private::act_bytesWritten(int bytes) |
132 | { |
133 | if (waiting) |
134 | eventReady(type: GpgOp::Event::BytesWritten, written: bytes); |
135 | else |
136 | emit q->bytesWritten(bytes); |
137 | } |
138 | |
139 | void GpgOp::Private::act_needPassphrase(const QString &keyId) |
140 | { |
141 | if (waiting) |
142 | eventReady(type: GpgOp::Event::NeedPassphrase, keyId); |
143 | else |
144 | emit q->needPassphrase(keyId); |
145 | } |
146 | |
147 | void GpgOp::Private::act_needCard() |
148 | { |
149 | if (waiting) |
150 | eventReady(type: GpgOp::Event::NeedCard); |
151 | else |
152 | emit q->needCard(); |
153 | } |
154 | |
155 | void GpgOp::Private::act_readyReadDiagnosticText() |
156 | { |
157 | const QString s = act->readDiagnosticText(); |
158 | // printf("dtext ready: [%s]\n", qPrintable(s)); |
159 | diagnosticText += s; |
160 | |
161 | if (waiting) |
162 | eventReady(type: GpgOp::Event::ReadyReadDiagnosticText); |
163 | else |
164 | emit q->readyReadDiagnosticText(); |
165 | } |
166 | |
167 | void GpgOp::Private::act_finished() |
168 | { |
169 | #ifdef GPG_PROFILE |
170 | if (op == GpgOp::Encrypt) |
171 | printf("<< doEncrypt: %d >>\n" , timer.elapsed()); |
172 | #endif |
173 | |
174 | result = act->read(); |
175 | diagnosticText += act->readDiagnosticText(); |
176 | output = act->output; |
177 | |
178 | QMap<int, QString> errmap; |
179 | errmap[GpgOp::ErrorProcess] = QStringLiteral("ErrorProcess" ); |
180 | errmap[GpgOp::ErrorPassphrase] = QStringLiteral("ErrorPassphrase" ); |
181 | errmap[GpgOp::ErrorFormat] = QStringLiteral("ErrorFormat" ); |
182 | errmap[GpgOp::ErrorSignerExpired] = QStringLiteral("ErrorSignerExpired" ); |
183 | errmap[GpgOp::ErrorEncryptExpired] = QStringLiteral("ErrorEncryptExpired" ); |
184 | errmap[GpgOp::ErrorEncryptUntrusted] = QStringLiteral("ErrorEncryptUntrusted" ); |
185 | errmap[GpgOp::ErrorEncryptInvalid] = QStringLiteral("ErrorEncryptInvalid" ); |
186 | errmap[GpgOp::ErrorDecryptNoKey] = QStringLiteral("ErrorDecryptNoKey" ); |
187 | errmap[GpgOp::ErrorUnknown] = QStringLiteral("ErrorUnknown" ); |
188 | if (output.success) |
189 | diagnosticText += QStringLiteral("GpgAction success\n" ); |
190 | else |
191 | diagnosticText += QStringLiteral("GpgAction error: %1\n" ).arg(a: errmap[output.errorCode]); |
192 | |
193 | if (output.wasSigned) { |
194 | QString s; |
195 | if (output.verifyResult == GpgOp::VerifyGood) |
196 | s = QStringLiteral("VerifyGood" ); |
197 | else if (output.verifyResult == GpgOp::VerifyBad) |
198 | s = QStringLiteral("VerifyBad" ); |
199 | else |
200 | s = QStringLiteral("VerifyNoKey" ); |
201 | diagnosticText += QStringLiteral("wasSigned: verifyResult: %1\n" ).arg(a: s); |
202 | } |
203 | |
204 | // printf("diagnosticText:\n%s", qPrintable(diagnosticText)); |
205 | |
206 | reset(mode: ResetSession); |
207 | |
208 | if (waiting) |
209 | eventReady(type: GpgOp::Event::Finished); |
210 | else |
211 | emit q->finished(); |
212 | } |
213 | |
214 | GpgOp::GpgOp(const QString &bin, QObject *parent) |
215 | : QObject(parent) |
216 | { |
217 | d = new Private(this); |
218 | d->bin = bin; |
219 | } |
220 | |
221 | GpgOp::~GpgOp() |
222 | { |
223 | delete d; |
224 | } |
225 | |
226 | void GpgOp::reset() |
227 | { |
228 | d->reset(mode: ResetAll); |
229 | } |
230 | |
231 | bool GpgOp::isActive() const |
232 | { |
233 | return (d->act ? true : false); |
234 | } |
235 | |
236 | GpgOp::Type GpgOp::op() const |
237 | { |
238 | return d->op; |
239 | } |
240 | |
241 | void GpgOp::setAsciiFormat(bool b) |
242 | { |
243 | d->opt_ascii = b; |
244 | } |
245 | |
246 | void GpgOp::setDisableAgent(bool b) |
247 | { |
248 | d->opt_noagent = b; |
249 | } |
250 | |
251 | void GpgOp::setAlwaysTrust(bool b) |
252 | { |
253 | d->opt_alwaystrust = b; |
254 | } |
255 | |
256 | void GpgOp::setKeyrings(const QString &pubfile, const QString &secfile) |
257 | { |
258 | d->opt_pubfile = pubfile; |
259 | d->opt_secfile = secfile; |
260 | } |
261 | |
262 | void GpgOp::doCheck() |
263 | { |
264 | d->make_act(op: Check); |
265 | d->act->start(); |
266 | } |
267 | |
268 | void GpgOp::doSecretKeyringFile() |
269 | { |
270 | d->make_act(op: SecretKeyringFile); |
271 | d->act->start(); |
272 | } |
273 | |
274 | void GpgOp::doPublicKeyringFile() |
275 | { |
276 | d->make_act(op: PublicKeyringFile); |
277 | d->act->start(); |
278 | } |
279 | |
280 | void GpgOp::doSecretKeys() |
281 | { |
282 | d->make_act(op: SecretKeys); |
283 | d->act->start(); |
284 | } |
285 | |
286 | void GpgOp::doPublicKeys() |
287 | { |
288 | d->make_act(op: PublicKeys); |
289 | d->act->start(); |
290 | } |
291 | |
292 | void GpgOp::doEncrypt(const QStringList &recip_ids) |
293 | { |
294 | #ifdef GPG_PROFILE |
295 | d->timer.start(); |
296 | printf("<< doEncrypt >>\n" ); |
297 | #endif |
298 | |
299 | d->make_act(op: Encrypt); |
300 | d->act->input.recip_ids = recip_ids; |
301 | d->act->start(); |
302 | } |
303 | |
304 | void GpgOp::doDecrypt() |
305 | { |
306 | d->make_act(op: Decrypt); |
307 | d->act->start(); |
308 | } |
309 | |
310 | void GpgOp::doSign(const QString &signer_id) |
311 | { |
312 | d->make_act(op: Sign); |
313 | d->act->input.signer_id = signer_id; |
314 | d->act->start(); |
315 | } |
316 | |
317 | void GpgOp::doSignAndEncrypt(const QString &signer_id, const QStringList &recip_ids) |
318 | { |
319 | d->make_act(op: SignAndEncrypt); |
320 | d->act->input.signer_id = signer_id; |
321 | d->act->input.recip_ids = recip_ids; |
322 | d->act->start(); |
323 | } |
324 | |
325 | void GpgOp::doSignClearsign(const QString &signer_id) |
326 | { |
327 | d->make_act(op: SignClearsign); |
328 | d->act->input.signer_id = signer_id; |
329 | d->act->start(); |
330 | } |
331 | |
332 | void GpgOp::doSignDetached(const QString &signer_id) |
333 | { |
334 | d->make_act(op: SignDetached); |
335 | d->act->input.signer_id = signer_id; |
336 | d->act->start(); |
337 | } |
338 | |
339 | void GpgOp::doVerify() |
340 | { |
341 | d->make_act(op: Verify); |
342 | d->act->start(); |
343 | } |
344 | |
345 | void GpgOp::doVerifyDetached(const QByteArray &sig) |
346 | { |
347 | d->make_act(op: VerifyDetached); |
348 | d->act->input.sig = sig; |
349 | d->act->start(); |
350 | } |
351 | |
352 | void GpgOp::doImport(const QByteArray &in) |
353 | { |
354 | d->make_act(op: Import); |
355 | d->act->input.inkey = in; |
356 | d->act->start(); |
357 | } |
358 | |
359 | void GpgOp::doExport(const QString &key_id) |
360 | { |
361 | d->make_act(op: Export); |
362 | d->act->input.export_key_id = key_id; |
363 | d->act->start(); |
364 | } |
365 | |
366 | void GpgOp::doDeleteKey(const QString &key_fingerprint) |
367 | { |
368 | d->make_act(op: DeleteKey); |
369 | d->act->input.delete_key_fingerprint = key_fingerprint; |
370 | d->act->start(); |
371 | } |
372 | |
373 | #ifdef QPIPE_SECURE |
374 | void GpgOp::submitPassphrase(const QCA::SecureArray &a) |
375 | #else |
376 | void GpgOp::submitPassphrase(const QByteArray &a) |
377 | #endif |
378 | { |
379 | d->act->submitPassphrase(a); |
380 | } |
381 | |
382 | void GpgOp::cardOkay() |
383 | { |
384 | d->act->cardOkay(); |
385 | } |
386 | |
387 | QByteArray GpgOp::read() |
388 | { |
389 | if (d->act) { |
390 | return d->act->read(); |
391 | } else { |
392 | const QByteArray a = d->result; |
393 | d->result.clear(); |
394 | return a; |
395 | } |
396 | } |
397 | |
398 | void GpgOp::write(const QByteArray &in) |
399 | { |
400 | d->act->write(in); |
401 | } |
402 | |
403 | void GpgOp::endWrite() |
404 | { |
405 | d->act->endWrite(); |
406 | } |
407 | |
408 | QString GpgOp::readDiagnosticText() |
409 | { |
410 | QString s = d->diagnosticText; |
411 | d->diagnosticText = QString(); |
412 | return s; |
413 | } |
414 | |
415 | GpgOp::Event GpgOp::waitForEvent(int msecs) |
416 | { |
417 | if (!d->eventList.isEmpty()) |
418 | return d->eventList.takeFirst(); |
419 | |
420 | if (!d->act) |
421 | return GpgOp::Event(); |
422 | |
423 | d->waiting = true; |
424 | d->sync.waitForCondition(msecs); |
425 | d->waiting = false; |
426 | if (!d->eventList.isEmpty()) |
427 | return d->eventList.takeFirst(); |
428 | else |
429 | return GpgOp::Event(); |
430 | } |
431 | |
432 | bool GpgOp::success() const |
433 | { |
434 | return d->output.success; |
435 | } |
436 | |
437 | GpgOp::Error GpgOp::errorCode() const |
438 | { |
439 | return d->output.errorCode; |
440 | } |
441 | |
442 | GpgOp::KeyList GpgOp::keys() const |
443 | { |
444 | return d->output.keys; |
445 | } |
446 | |
447 | QString GpgOp::keyringFile() const |
448 | { |
449 | return d->output.keyringFile; |
450 | } |
451 | |
452 | QString GpgOp::homeDir() const |
453 | { |
454 | return d->output.homeDir; |
455 | } |
456 | |
457 | QString GpgOp::encryptedToId() const |
458 | { |
459 | return d->output.encryptedToId; |
460 | } |
461 | |
462 | bool GpgOp::wasSigned() const |
463 | { |
464 | return d->output.wasSigned; |
465 | } |
466 | |
467 | QString GpgOp::signerId() const |
468 | { |
469 | return d->output.signerId; |
470 | } |
471 | |
472 | QDateTime GpgOp::timestamp() const |
473 | { |
474 | return d->output.timestamp; |
475 | } |
476 | |
477 | GpgOp::VerifyResult GpgOp::verifyResult() const |
478 | { |
479 | return d->output.verifyResult; |
480 | } |
481 | |
482 | } |
483 | |