1 | #include"gpgop.h"
|
---|
2 |
|
---|
3 | #include<qstringlist.h>
|
---|
4 | #include<qtimer.h>
|
---|
5 | #include<qdatetime.h>
|
---|
6 | #include<stdlib.h>
|
---|
7 | #include"gpgproc/gpgproc.h"
|
---|
8 |
|
---|
9 | static QByteArray stringToArray(const QString &str)
|
---|
10 | {
|
---|
11 | QCString cs = str.utf8();
|
---|
12 | QByteArray a(cs.length());
|
---|
13 | memcpy(a.data(), cs.data(), a.size());
|
---|
14 | return a;
|
---|
15 | }
|
---|
16 |
|
---|
17 | class GpgOp::Private
|
---|
18 | {
|
---|
19 | public:
|
---|
20 | Private() {}
|
---|
21 |
|
---|
22 | QString bin;
|
---|
23 | int op;
|
---|
24 | GPGProc *proc;
|
---|
25 | bool tryAgent;
|
---|
26 |
|
---|
27 | QByteArray outbuf, errbuf;
|
---|
28 | bool didPassphrase;
|
---|
29 | QString sigKeyID;
|
---|
30 | QDateTime sigTS;
|
---|
31 | int verType;
|
---|
32 |
|
---|
33 | OpenPGP::KeyList keys;
|
---|
34 | QString keyring;
|
---|
35 | bool badpp;
|
---|
36 |
|
---|
37 | QString enc;
|
---|
38 | QByteArray dec;
|
---|
39 | };
|
---|
40 |
|
---|
41 | GpgOp::GpgOp(const QString &bin, QObject *parent)
|
---|
42 | :QObject(parent)
|
---|
43 | {
|
---|
44 | d = new Private;
|
---|
45 | d->bin = bin;
|
---|
46 | d->proc = 0;
|
---|
47 | d->op = -1;
|
---|
48 | d->tryAgent = true;
|
---|
49 | }
|
---|
50 |
|
---|
51 | GpgOp::~GpgOp()
|
---|
52 | {
|
---|
53 | reset();
|
---|
54 | delete d;
|
---|
55 | }
|
---|
56 |
|
---|
57 | void GpgOp::reset()
|
---|
58 | {
|
---|
59 | if(d->proc) {
|
---|
60 | d->proc->disconnect(this);
|
---|
61 | d->proc->deleteLater();
|
---|
62 | d->proc = 0;
|
---|
63 | }
|
---|
64 |
|
---|
65 | d->sigKeyID = "";
|
---|
66 | d->sigTS = QDateTime();
|
---|
67 | d->didPassphrase = false;
|
---|
68 | d->outbuf.resize(0);
|
---|
69 | d->errbuf.resize(0);
|
---|
70 | d->keys.clear();
|
---|
71 | d->keyring = "";
|
---|
72 | d->verType = OpenPGP::VerifyError;
|
---|
73 | d->badpp = false;
|
---|
74 | d->enc = "";
|
---|
75 | d->dec.resize(0);
|
---|
76 | }
|
---|
77 |
|
---|
78 | void GpgOp::stop()
|
---|
79 | {
|
---|
80 | reset();
|
---|
81 | }
|
---|
82 |
|
---|
83 | bool GpgOp::isActive() const
|
---|
84 | {
|
---|
85 | return (d->proc ? true: false);
|
---|
86 | }
|
---|
87 |
|
---|
88 | int GpgOp::op() const
|
---|
89 | {
|
---|
90 | return d->op;
|
---|
91 | }
|
---|
92 |
|
---|
93 | const OpenPGP::KeyList & GpgOp::keys() const
|
---|
94 | {
|
---|
95 | return d->keys;
|
---|
96 | }
|
---|
97 |
|
---|
98 | const QString & GpgOp::keyringFile() const
|
---|
99 | {
|
---|
100 | return d->keyring;
|
---|
101 | }
|
---|
102 |
|
---|
103 | const QString & GpgOp::keyID() const
|
---|
104 | {
|
---|
105 | return d->sigKeyID;
|
---|
106 | }
|
---|
107 |
|
---|
108 | const QDateTime & GpgOp::timestamp() const
|
---|
109 | {
|
---|
110 | return d->sigTS;
|
---|
111 | }
|
---|
112 |
|
---|
113 | int GpgOp::verifyResult() const
|
---|
114 | {
|
---|
115 | return d->verType;
|
---|
116 | }
|
---|
117 |
|
---|
118 | bool GpgOp::badPassphrase() const
|
---|
119 | {
|
---|
120 | return d->badpp;
|
---|
121 | }
|
---|
122 |
|
---|
123 | const QString & GpgOp::encrypted() const
|
---|
124 | {
|
---|
125 | return d->enc;
|
---|
126 | }
|
---|
127 |
|
---|
128 | const QByteArray & GpgOp::decrypted() const
|
---|
129 | {
|
---|
130 | return d->dec;
|
---|
131 | }
|
---|
132 |
|
---|
133 | const QString & GpgOp::signature() const
|
---|
134 | {
|
---|
135 | return d->enc;
|
---|
136 | }
|
---|
137 |
|
---|
138 | void GpgOp::setTryAgent(bool b)
|
---|
139 | {
|
---|
140 | d->tryAgent = b;
|
---|
141 | }
|
---|
142 |
|
---|
143 | void GpgOp::doCheck()
|
---|
144 | {
|
---|
145 | reset();
|
---|
146 |
|
---|
147 | d->op = Check;
|
---|
148 | QStringList args;
|
---|
149 | args += "--version";
|
---|
150 | if(!launchGPG(args, false)) {
|
---|
151 | QTimer::singleShot(0, this, SLOT(doFail()));
|
---|
152 | return;
|
---|
153 | }
|
---|
154 | }
|
---|
155 |
|
---|
156 | void GpgOp::doSecretKeyringFile()
|
---|
157 | {
|
---|
158 | reset();
|
---|
159 |
|
---|
160 | d->op = SecretKeyringFile;
|
---|
161 | QStringList args;
|
---|
162 | args += "--list-secret-keys";
|
---|
163 | if(!launchGPG(args, false)) {
|
---|
164 | QTimer::singleShot(0, this, SLOT(doFail()));
|
---|
165 | return;
|
---|
166 | }
|
---|
167 | }
|
---|
168 |
|
---|
169 | void GpgOp::doPublicKeyringFile()
|
---|
170 | {
|
---|
171 | reset();
|
---|
172 |
|
---|
173 | d->op = PublicKeyringFile;
|
---|
174 | QStringList args;
|
---|
175 | args += "--list-public-keys";
|
---|
176 | if(!launchGPG(args, false)) {
|
---|
177 | QTimer::singleShot(0, this, SLOT(doFail()));
|
---|
178 | return;
|
---|
179 | }
|
---|
180 | }
|
---|
181 |
|
---|
182 | void GpgOp::doSecretKeys()
|
---|
183 | {
|
---|
184 | reset();
|
---|
185 |
|
---|
186 | d->op = SecretKeys;
|
---|
187 | QStringList args;
|
---|
188 | args += "--fixed-list-mode";
|
---|
189 | args += "--with-colons";
|
---|
190 | args += "--list-secret-keys";
|
---|
191 | if(!launchGPG(args, false)) {
|
---|
192 | QTimer::singleShot(0, this, SLOT(doFail()));
|
---|
193 | return;
|
---|
194 | }
|
---|
195 | }
|
---|
196 |
|
---|
197 | void GpgOp::doPublicKeys()
|
---|
198 | {
|
---|
199 | reset();
|
---|
200 |
|
---|
201 | d->op = PublicKeys;
|
---|
202 | QStringList args;
|
---|
203 | args += "--fixed-list-mode";
|
---|
204 | args += "--with-colons";
|
---|
205 | args += "--list-public-keys";
|
---|
206 | if(!launchGPG(args, false)) {
|
---|
207 | QTimer::singleShot(0, this, SLOT(doFail()));
|
---|
208 | return;
|
---|
209 | }
|
---|
210 | }
|
---|
211 |
|
---|
212 | void GpgOp::doEncrypt(const QByteArray &in, const QStringList &keys)
|
---|
213 | {
|
---|
214 | reset();
|
---|
215 |
|
---|
216 | d->op = Encrypt;
|
---|
217 | QStringList args;
|
---|
218 | args += "--armor";
|
---|
219 | args += "--always-trust";
|
---|
220 | args += "--encrypt";
|
---|
221 |
|
---|
222 | // recipients
|
---|
223 | for(QStringList::ConstIterator it = keys.begin(); it != keys.end(); ++it) {
|
---|
224 | args += "--recipient";
|
---|
225 | args += QString("0x") + *it;
|
---|
226 | }
|
---|
227 |
|
---|
228 | if(!launchGPG(args)) {
|
---|
229 | QTimer::singleShot(0, this, SLOT(doFail()));
|
---|
230 | return;
|
---|
231 | }
|
---|
232 |
|
---|
233 | if(!in.isEmpty())
|
---|
234 | d->proc->writeToStdin(in);
|
---|
235 | else
|
---|
236 | d->proc->closeStdin();
|
---|
237 | }
|
---|
238 |
|
---|
239 | void GpgOp::doDecrypt(const QString &in)
|
---|
240 | {
|
---|
241 | reset();
|
---|
242 |
|
---|
243 | d->op = Decrypt;
|
---|
244 | QStringList args;
|
---|
245 | if(!d->tryAgent)
|
---|
246 | args += "--no-use-agent";
|
---|
247 | args += "--armor";
|
---|
248 | args += "--decrypt";
|
---|
249 | if(!launchGPG(args)) {
|
---|
250 | QTimer::singleShot(0, this, SLOT(doFail()));
|
---|
251 | return;
|
---|
252 | }
|
---|
253 |
|
---|
254 | if(!in.isEmpty())
|
---|
255 | d->proc->writeToStdin(stringToArray(fixOutgoingLines(in)));
|
---|
256 | else
|
---|
257 | d->proc->closeStdin();
|
---|
258 | }
|
---|
259 |
|
---|
260 | void GpgOp::doSign(const QByteArray &in, const QString &keyID)
|
---|
261 | {
|
---|
262 | reset();
|
---|
263 |
|
---|
264 | d->op = Sign;
|
---|
265 | QStringList args;
|
---|
266 | if(!d->tryAgent)
|
---|
267 | args += "--no-use-agent";
|
---|
268 | args += "--armor";
|
---|
269 | args += "--default-key";
|
---|
270 | args += QString("0x") + keyID;
|
---|
271 | args += "--detach-sign";
|
---|
272 | if(!launchGPG(args)) {
|
---|
273 | QTimer::singleShot(0, this, SLOT(doFail()));
|
---|
274 | return;
|
---|
275 | }
|
---|
276 |
|
---|
277 | if(!in.isEmpty())
|
---|
278 | d->proc->writeToStdin(in);
|
---|
279 | else
|
---|
280 | d->proc->closeStdin();
|
---|
281 | }
|
---|
282 |
|
---|
283 | void GpgOp::doVerify(const QByteArray &in, const QString &sig)
|
---|
284 | {
|
---|
285 | reset();
|
---|
286 |
|
---|
287 | d->op = Verify;
|
---|
288 | d->verType = OpenPGP::VerifyError;
|
---|
289 | QStringList args;
|
---|
290 | args += "--armor";
|
---|
291 | args += "--verify";
|
---|
292 | args += "-";
|
---|
293 | args += "-&?";
|
---|
294 |
|
---|
295 | if(!launchGPG(args)) {
|
---|
296 | QTimer::singleShot(0, this, SLOT(doFail()));
|
---|
297 | return;
|
---|
298 | }
|
---|
299 |
|
---|
300 | // sig goes into stdin
|
---|
301 | if(!sig.isEmpty())
|
---|
302 | d->proc->writeToStdin(stringToArray(fixOutgoingLines(sig)));
|
---|
303 | else
|
---|
304 | d->proc->closeStdin();
|
---|
305 |
|
---|
306 | // data goes into aux
|
---|
307 | d->proc->writeToAux(in);
|
---|
308 | d->proc->closeAux();
|
---|
309 | }
|
---|
310 |
|
---|
311 | void GpgOp::submitPassphrase(const QString &pp)
|
---|
312 | {
|
---|
313 | QCString cs = pp.local8Bit() + '\n';
|
---|
314 | QByteArray a(cs.length());
|
---|
315 | memcpy(a.data(), cs.data(), a.size());
|
---|
316 | d->proc->writeToCommand(a);
|
---|
317 | }
|
---|
318 |
|
---|
319 | void GpgOp::doFail()
|
---|
320 | {
|
---|
321 | finished(false);
|
---|
322 | }
|
---|
323 |
|
---|
324 | bool GpgOp::launchGPG(const QStringList &args, bool useExtra)
|
---|
325 | {
|
---|
326 | d->proc = new GPGProc;
|
---|
327 | connect(d->proc, SIGNAL(readyReadStdout()), SLOT(proc_readyReadStdout()));
|
---|
328 | connect(d->proc, SIGNAL(readyReadStderr()), SLOT(proc_readyReadStderr()));
|
---|
329 | connect(d->proc, SIGNAL(processExited()), SLOT(proc_processExited()));
|
---|
330 | connect(d->proc, SIGNAL(wroteToStdin()), SLOT(proc_wroteToStdin()));
|
---|
331 | connect(d->proc, SIGNAL(statusLine(const QString &)), SLOT(proc_statusLine(const QString &)));
|
---|
332 |
|
---|
333 | if(!d->proc->start(d->bin, args, useExtra)) {
|
---|
334 | d->proc->disconnect(this);
|
---|
335 | d->proc->deleteLater();
|
---|
336 | d->proc = 0;
|
---|
337 | return false;
|
---|
338 | }
|
---|
339 |
|
---|
340 | return true;
|
---|
341 | }
|
---|
342 |
|
---|
343 | void GpgOp::proc_readyReadStdout()
|
---|
344 | {
|
---|
345 | QByteArray block = d->proc->readStdout();
|
---|
346 | int oldsize = d->outbuf.size();
|
---|
347 | d->outbuf.resize(oldsize + block.size());
|
---|
348 | memcpy(d->outbuf.data() + oldsize, block.data(), block.size());
|
---|
349 | }
|
---|
350 |
|
---|
351 | void GpgOp::proc_readyReadStderr()
|
---|
352 | {
|
---|
353 | QByteArray block = d->proc->readStderr();
|
---|
354 | int oldsize = d->errbuf.size();
|
---|
355 | d->errbuf.resize(oldsize + block.size());
|
---|
356 | memcpy(d->errbuf.data() + oldsize, block.data(), block.size());
|
---|
357 | }
|
---|
358 |
|
---|
359 | void GpgOp::proc_wroteToStdin()
|
---|
360 | {
|
---|
361 | d->proc->closeStdin();
|
---|
362 | }
|
---|
363 |
|
---|
364 | void GpgOp::proc_statusLine(const QString &str)
|
---|
365 | {
|
---|
366 | #ifdef GPG_DEBUG
|
---|
367 | qDebug("### {%s}", str.latin1());
|
---|
368 | #endif
|
---|
369 | QString s, rest;
|
---|
370 | int n = str.find(' ');
|
---|
371 | if(n == -1) {
|
---|
372 | s = str;
|
---|
373 | rest = "";
|
---|
374 | }
|
---|
375 | else {
|
---|
376 | s = str.mid(0, n);
|
---|
377 | rest = str.mid(n+1);
|
---|
378 | }
|
---|
379 |
|
---|
380 | if(s == "NEED_PASSPHRASE") {
|
---|
381 | if(!(d->tryAgent && getenv("GPG_AGENT_INFO"))) {
|
---|
382 | if(!d->didPassphrase) {
|
---|
383 | d->didPassphrase = true;
|
---|
384 | needPassphrase();
|
---|
385 | }
|
---|
386 | else {
|
---|
387 | QByteArray a(1);
|
---|
388 | a[0] = '\n';
|
---|
389 | d->proc->writeToCommand(a);
|
---|
390 | }
|
---|
391 | }
|
---|
392 | }
|
---|
393 | else if(s == "BAD_PASSPHRASE") {
|
---|
394 | d->badpp = true;
|
---|
395 | }
|
---|
396 | else if(s == "GOOD_PASSPHRASE") {
|
---|
397 | d->badpp = false;
|
---|
398 | }
|
---|
399 | else if(s == "GOODSIG") {
|
---|
400 | QString keyID;
|
---|
401 | int n = rest.find(' ');
|
---|
402 | if(n == -1)
|
---|
403 | keyID = rest;
|
---|
404 | else
|
---|
405 | keyID = rest.mid(0, n);
|
---|
406 | d->sigKeyID = keyID;
|
---|
407 | d->verType = OpenPGP::VerifyGood;
|
---|
408 | }
|
---|
409 | else if(s == "BADSIG") {
|
---|
410 | QString keyID;
|
---|
411 | int n = rest.find(' ');
|
---|
412 | if(n == -1)
|
---|
413 | keyID = rest;
|
---|
414 | else
|
---|
415 | keyID = rest.mid(0, n);
|
---|
416 | d->sigKeyID = keyID;
|
---|
417 | d->verType = OpenPGP::VerifyBad;
|
---|
418 | }
|
---|
419 | else if(s == "ERRSIG") {
|
---|
420 | QStringList list = QStringList::split(' ', rest, false);
|
---|
421 | d->sigKeyID = list[0];
|
---|
422 | d->sigTS.setTime_t(list[4].toInt());
|
---|
423 | d->verType = OpenPGP::VerifyNoKey;
|
---|
424 | }
|
---|
425 | else if(s == "VALIDSIG") {
|
---|
426 | QStringList list = QStringList::split(' ', rest, false);
|
---|
427 | d->sigTS.setTime_t(list[2].toInt());
|
---|
428 | }
|
---|
429 | }
|
---|
430 |
|
---|
431 | void GpgOp::proc_processExited()
|
---|
432 | {
|
---|
433 | if(!d->proc)
|
---|
434 | return;
|
---|
435 |
|
---|
436 | #ifdef GPG_DEBUG
|
---|
437 | qDebug("### GPG Finished: ");
|
---|
438 | #endif
|
---|
439 |
|
---|
440 | bool clean = true;
|
---|
441 | int exitStatus = -1;
|
---|
442 | if(!d->proc->normalExit()) {
|
---|
443 | clean = false;
|
---|
444 | #ifdef GPG_DEBUG
|
---|
445 | qDebug("### bad exit.. crash?");
|
---|
446 | #endif
|
---|
447 | }
|
---|
448 | else {
|
---|
449 | exitStatus = d->proc->exitStatus();
|
---|
450 | #ifdef GPG_DEBUG
|
---|
451 | qDebug("### exitStatus=%d", exitStatus);
|
---|
452 | #endif
|
---|
453 | }
|
---|
454 |
|
---|
455 | d->proc->disconnect(this);
|
---|
456 | d->proc->deleteLater();
|
---|
457 | d->proc = 0;
|
---|
458 |
|
---|
459 | processResult(clean, exitStatus, d->outbuf, d->errbuf);
|
---|
460 | }
|
---|
461 |
|
---|
462 | void GpgOp::processResult(bool clean, int code, const QByteArray &out, const QByteArray &err)
|
---|
463 | {
|
---|
464 | // put stdout and stderr into QStrings
|
---|
465 | QCString cs;
|
---|
466 | cs.resize(out.size()+1);
|
---|
467 | memcpy(cs.data(), out.data(), out.size());
|
---|
468 | QString outstr = QString::fromLatin1(cs);
|
---|
469 | cs.resize(err.size()+1);
|
---|
470 | memcpy(cs.data(), err.data(), err.size());
|
---|
471 | QString errstr = QString::fromLatin1(cs);
|
---|
472 |
|
---|
473 | #ifdef GPG_DEBUG
|
---|
474 | qDebug("### stdout: [%s]", outstr.latin1());
|
---|
475 | qDebug("### stderr: [%s]", errstr.latin1());
|
---|
476 | #endif
|
---|
477 |
|
---|
478 | if(d->op == Check) {
|
---|
479 | if(!clean || code != 0) {
|
---|
480 | doFail();
|
---|
481 | return;
|
---|
482 | }
|
---|
483 | finished(true);
|
---|
484 | }
|
---|
485 | else if(d->op == SecretKeyringFile || d->op == PublicKeyringFile) {
|
---|
486 | if(!clean || code != 0) {
|
---|
487 | doFail();
|
---|
488 | return;
|
---|
489 | }
|
---|
490 | if(!findKeyringFilename(fixIncomingLines(outstr), &d->keyring)) {
|
---|
491 | doFail();
|
---|
492 | return;
|
---|
493 | }
|
---|
494 | finished(true);
|
---|
495 | }
|
---|
496 | else if(d->op == SecretKeys || d->op == PublicKeys) {
|
---|
497 | if(!clean || code != 0) {
|
---|
498 | doFail();
|
---|
499 | return;
|
---|
500 | }
|
---|
501 | if(!stringToKeyList(fixIncomingLines(outstr), &d->keys, &d->keyring)) {
|
---|
502 | doFail();
|
---|
503 | return;
|
---|
504 | }
|
---|
505 | finished(true);
|
---|
506 | }
|
---|
507 | else if(d->op == Encrypt) {
|
---|
508 | if(!clean || code != 0) {
|
---|
509 | doFail();
|
---|
510 | return;
|
---|
511 | }
|
---|
512 | d->enc = fixIncomingLines(outstr);
|
---|
513 | finished(true);
|
---|
514 | }
|
---|
515 | else if(d->op == Decrypt) {
|
---|
516 | if(!clean || code != 0) {
|
---|
517 | doFail();
|
---|
518 | return;
|
---|
519 | }
|
---|
520 | d->dec = out;
|
---|
521 | finished(true);
|
---|
522 | }
|
---|
523 | else if(d->op == Sign) {
|
---|
524 | if(!clean || code != 0) {
|
---|
525 | doFail();
|
---|
526 | return;
|
---|
527 | }
|
---|
528 | d->enc = fixIncomingLines(outstr);
|
---|
529 | finished(true);
|
---|
530 | }
|
---|
531 | else if(d->op == Verify) {
|
---|
532 | if(!clean || code != 0) {
|
---|
533 | doFail();
|
---|
534 | return;
|
---|
535 | }
|
---|
536 | finished(true);
|
---|
537 | }
|
---|
538 | }
|
---|
539 |
|
---|
540 | QString GpgOp::fixIncomingLines(const QString &str)
|
---|
541 | {
|
---|
542 | #if defined(Q_WS_WIN) || defined(Q_OS_OS2)
|
---|
543 | QString out;
|
---|
544 | for(int n = 0; n < (int)str.length(); ++n) {
|
---|
545 | if(str.at(n) == '\r' && (n + 1) < (int)str.length() && str.at(n+1) == '\n') {
|
---|
546 | out += '\n';
|
---|
547 | ++n;
|
---|
548 | }
|
---|
549 | else
|
---|
550 | out += str.at(n);
|
---|
551 | }
|
---|
552 | return out;
|
---|
553 | #else
|
---|
554 | return str;
|
---|
555 | #endif
|
---|
556 | }
|
---|
557 |
|
---|
558 | QString GpgOp::fixOutgoingLines(const QString &str)
|
---|
559 | {
|
---|
560 | #if defined(Q_WS_WIN) || defined(Q_OS_OS2)
|
---|
561 | QString out;
|
---|
562 | for(int n = 0; n < (int)str.length(); ++n) {
|
---|
563 | if(str.at(n) == '\n' && (n == 0 || str.at(n-1) != '\r'))
|
---|
564 | out += "\r\n";
|
---|
565 | else
|
---|
566 | out += str.at(n);
|
---|
567 | }
|
---|
568 | return out;
|
---|
569 | #else
|
---|
570 | return str;
|
---|
571 | #endif
|
---|
572 | }
|
---|
573 |
|
---|
574 | bool GpgOp::stringToKeyList(const QString &outstr, OpenPGP::KeyList *_keylist, QString *_keyring)
|
---|
575 | {
|
---|
576 | OpenPGP::KeyList keyList;
|
---|
577 | QStringList lines = QStringList::split('\n', outstr, true);
|
---|
578 |
|
---|
579 | if(lines.count() < 1)
|
---|
580 | return false;
|
---|
581 |
|
---|
582 | QStringList::ConstIterator it = lines.begin();
|
---|
583 |
|
---|
584 | // first line is keyring file
|
---|
585 | QString keyring = *(it++);
|
---|
586 |
|
---|
587 | // if the second line isn't a divider, we are dealing
|
---|
588 | // with a new version of gnupg that doesn't give us
|
---|
589 | // the keyring file on gpg --list-keys --with-colons
|
---|
590 | if(it == lines.end() || (*it).at(0) != '-') {
|
---|
591 | // first line wasn't the keyring name...
|
---|
592 | keyring = "";
|
---|
593 | // ...so read the first line again
|
---|
594 | it--;
|
---|
595 | }
|
---|
596 | else {
|
---|
597 | // this was the divider line - skip it
|
---|
598 | it++;
|
---|
599 | }
|
---|
600 |
|
---|
601 | OpenPGP::Key *k = 0;
|
---|
602 | for(; it != lines.end(); ++it) {
|
---|
603 | QStringList f = QStringList::split(':', *it, true);
|
---|
604 | QString type = f[0];
|
---|
605 |
|
---|
606 | if(type == "pub") {
|
---|
607 | if(k) {
|
---|
608 | keyList += (*k);
|
---|
609 | delete k;
|
---|
610 | k = 0;
|
---|
611 | }
|
---|
612 | k = new OpenPGP::Key;
|
---|
613 |
|
---|
614 | k->setKeyID(f[4]);
|
---|
615 | }
|
---|
616 | else if(type == "sec") {
|
---|
617 | if(k) {
|
---|
618 | keyList += (*k);
|
---|
619 | delete k;
|
---|
620 | k = 0;
|
---|
621 | }
|
---|
622 | k = new OpenPGP::Key;
|
---|
623 |
|
---|
624 | k->setKeyID(f[4]);
|
---|
625 | }
|
---|
626 | else if(type == "uid") {
|
---|
627 | if(!k)
|
---|
628 | continue;
|
---|
629 | // ignore a uid if we already have one
|
---|
630 | if(!k->userID().isEmpty())
|
---|
631 | continue;
|
---|
632 | QString s = f[9];
|
---|
633 | QCString uid;
|
---|
634 | // convert the "backslash" C-string syntax
|
---|
635 | for(int n = 0; n < (int)s.length(); ++n) {
|
---|
636 | if(s.at(n) == '\\' && n + 1 < (int)s.length()) {
|
---|
637 | ++n;
|
---|
638 | unsigned char c = (unsigned char)s.at(n).latin1();
|
---|
639 | if(c == '\\')
|
---|
640 | uid += '\\';
|
---|
641 | else if(c == 'x' && n + 2 < (int)s.length()) {
|
---|
642 | ++n;
|
---|
643 | QString hex = s.mid(n, 2);
|
---|
644 | bool ok;
|
---|
645 | uint val = hex.toInt(&ok, 16);
|
---|
646 | uid += (unsigned char)val;
|
---|
647 | ++n; // only skip one, the for-loop will skip the next
|
---|
648 | }
|
---|
649 | }
|
---|
650 | else {
|
---|
651 | uid += (unsigned char)s.at(n).latin1();
|
---|
652 | }
|
---|
653 | }
|
---|
654 | k->setUserID(QString::fromUtf8(uid));
|
---|
655 | }
|
---|
656 | }
|
---|
657 | if(k) {
|
---|
658 | keyList += (*k);
|
---|
659 | delete k;
|
---|
660 | k = 0;
|
---|
661 | }
|
---|
662 |
|
---|
663 | if(_keylist)
|
---|
664 | *_keylist = keyList;
|
---|
665 | if(_keyring)
|
---|
666 | *_keyring = keyring;
|
---|
667 |
|
---|
668 | return true;
|
---|
669 | }
|
---|
670 |
|
---|
671 | bool GpgOp::findKeyringFilename(const QString &outstr, QString *_keyring)
|
---|
672 | {
|
---|
673 | QStringList lines = QStringList::split('\n', outstr, true);
|
---|
674 | if(lines.count() < 1)
|
---|
675 | return false;
|
---|
676 |
|
---|
677 | *_keyring = lines[0];
|
---|
678 | return true;
|
---|
679 | }
|
---|
680 |
|
---|