00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "gpgop.h"
00021
00022 #include "gpgproc.h"
00023
00024 #include <QTimer>
00025
00026 namespace gpgQCAPlugin {
00027
00028
00029
00030
00031 class LineConverter
00032 {
00033 public:
00034 enum Mode { Read, Write };
00035
00036 void setup(Mode m)
00037 {
00038 state = Normal;
00039 mode = m;
00040 #ifdef Q_OS_WIN
00041 write_conv = true;
00042 #else
00043 write_conv = false;
00044 #endif
00045 prebytes = 0;
00046 list.clear();
00047 }
00048
00049 QByteArray update(const QByteArray &buf)
00050 {
00051 if(mode == Read)
00052 {
00053 QByteArray out;
00054
00055 if(state == Normal)
00056 {
00057 out = buf;
00058 }
00059 else
00060 {
00061 out.resize(buf.size() + 1);
00062 out[0] = '\r';
00063 memcpy(out.data() + 1, buf.data(), buf.size());
00064 }
00065
00066 int n = 0;
00067 while(1)
00068 {
00069 n = out.indexOf('\r', n);
00070
00071 if(n == -1)
00072 {
00073 break;
00074 }
00075
00076 if(n < (buf.size() - 1))
00077 {
00078 if(out[n + 1] == '\n')
00079 {
00080
00081 memmove(out.data() + n, out.data() + n + 1, out.size() - n - 1);
00082 out.resize(out.size() - 1);
00083 }
00084 }
00085
00086 else
00087 {
00088 state = Partial;
00089 break;
00090 }
00091 ++n;
00092 }
00093
00094 return out;
00095 }
00096 else
00097 {
00098 if(write_conv)
00099 {
00100 QByteArray out;
00101 int prev = 0;
00102 int at = 0;
00103
00104 while(1)
00105 {
00106 int n = buf.indexOf('\n', at);
00107 if(n == -1)
00108 break;
00109
00110 int chunksize = n - at;
00111 int oldsize = out.size();
00112 out.resize(oldsize + chunksize + 2);
00113 memcpy(out.data() + oldsize, buf.data() + at, chunksize);
00114 memcpy(out.data() + oldsize + chunksize, "\r\n", 2);
00115
00116 list.append(prebytes + n + 1 - prev);
00117 prebytes = 0;
00118 prev = n;
00119
00120 at = n + 1;
00121 }
00122 if(at < buf.size())
00123 {
00124 int chunksize = buf.size() - at;
00125 int oldsize = out.size();
00126 out.resize(oldsize + chunksize);
00127 memcpy(out.data() + oldsize, buf.data() + at, chunksize);
00128 }
00129
00130 prebytes += buf.size() - prev;
00131 return out;
00132 }
00133 else
00134 return buf;
00135 }
00136 }
00137
00138 QByteArray final()
00139 {
00140 if(mode == Read)
00141 {
00142 QByteArray out;
00143 if(state == Partial)
00144 {
00145 out.resize(1);
00146 out[0] = '\r';
00147 }
00148 return out;
00149 }
00150 else
00151 {
00152 return QByteArray();
00153 }
00154 }
00155
00156 QByteArray process(const QByteArray &buf)
00157 {
00158 return update(buf) + final();
00159 }
00160
00161 int writtenToActual(int bytes)
00162 {
00163 if(write_conv)
00164 {
00165 int n = 0;
00166 int counter = bytes;
00167 while(counter > 0)
00168 {
00169 if(!list.isEmpty() && bytes >= list.first())
00170 {
00171 ++n;
00172 counter -= list.takeFirst();
00173 }
00174 else
00175 {
00176 if(list.isEmpty())
00177 prebytes -= counter;
00178 else
00179 list.first() -= counter;
00180
00181 if(prebytes < 0)
00182 {
00183 bytes += prebytes;
00184 prebytes = 0;
00185 }
00186
00187 break;
00188 }
00189 }
00190 return bytes - n;
00191 }
00192 else
00193 return bytes;
00194 }
00195
00196 private:
00197 enum State { Normal, Partial };
00198 Mode mode;
00199 State state;
00200 bool write_conv;
00201 public:
00202 int prebytes;
00203 QList<int> list;
00204 };
00205
00206
00207
00208
00209 static QDateTime getTimestamp(const QString &s)
00210 {
00211 if(s.isEmpty())
00212 return QDateTime();
00213
00214 if(s.contains('T'))
00215 {
00216 return QDateTime::fromString(s, Qt::ISODate);
00217 }
00218 else
00219 {
00220 QDateTime dt;
00221 dt.setTime_t(s.toInt());
00222 return dt;
00223 }
00224 }
00225
00226 static QByteArray getCString(const QByteArray &a)
00227 {
00228 QByteArray out;
00229
00230
00231 for(int n = 0; n < a.size(); ++n)
00232 {
00233 if(a[n] == '\\' && n + 1 < a.size())
00234 {
00235 ++n;
00236 unsigned char c = (unsigned char)a[n];
00237 if(c == '\\')
00238 {
00239 out += '\\';
00240 }
00241 else if(c == 'x' && n + 2 < a.size())
00242 {
00243 ++n;
00244 QByteArray hex = a.mid(n, 2);
00245 ++n;
00246
00247 bool ok;
00248 uint val = hex.toInt(&ok, 16);
00249 if(ok)
00250 {
00251 out += (unsigned char)val;
00252 }
00253 else
00254 {
00255 out += "\\x";
00256 out += hex;
00257 }
00258 }
00259 }
00260 else
00261 {
00262 out += a[n];
00263 }
00264 }
00265
00266 return out;
00267 }
00268
00269 static bool stringToKeyList(const QString &outstr, GpgOp::KeyList *_keylist, QString *_keyring)
00270 {
00271 GpgOp::KeyList keyList;
00272 QStringList lines = outstr.split('\n');
00273
00274 if(lines.count() < 1)
00275 return false;
00276
00277 QStringList::ConstIterator it = lines.begin();
00278
00279
00280 QString keyring = *(it++);
00281
00282
00283
00284
00285 if(it == lines.end() || (*it).isEmpty() || (*it).at(0) != '-')
00286 {
00287
00288 keyring.clear();
00289
00290 it--;
00291 }
00292 else
00293 {
00294
00295 it++;
00296 }
00297
00298 for(; it != lines.end(); ++it)
00299 {
00300 QStringList f = (*it).split(':');
00301 if(f.count() < 1)
00302 continue;
00303 QString type = f[0];
00304
00305 bool key = false;
00306 bool primary = false;
00307 bool sec = false;
00308
00309 if(type == "pub")
00310 {
00311 key = true;
00312 primary = true;
00313 }
00314 else if(type == "sec")
00315 {
00316 key = true;
00317 primary = true;
00318 sec = true;
00319 }
00320 else if(type == "sub")
00321 {
00322 key = true;
00323 }
00324 else if(type == "ssb")
00325 {
00326 key = true;
00327 sec = true;
00328 }
00329
00330 if(key)
00331 {
00332 if(primary)
00333 {
00334 keyList += GpgOp::Key();
00335
00336 QString trust = f[1];
00337 if(trust == "f" || trust == "u")
00338 keyList.last().isTrusted = true;
00339 }
00340
00341 int key_type = f[3].toInt();
00342 QString caps = f[11];
00343
00344 GpgOp::KeyItem item;
00345 item.bits = f[2].toInt();
00346 if(key_type == 1)
00347 item.type = GpgOp::KeyItem::RSA;
00348 else if(key_type == 16)
00349 item.type = GpgOp::KeyItem::ElGamal;
00350 else if(key_type == 17)
00351 item.type = GpgOp::KeyItem::DSA;
00352 else
00353 item.type = GpgOp::KeyItem::Unknown;
00354 item.id = f[4];
00355 item.creationDate = getTimestamp(f[5]);
00356 item.expirationDate = getTimestamp(f[6]);
00357 if(caps.contains('e'))
00358 item.caps |= GpgOp::KeyItem::Encrypt;
00359 if(caps.contains('s'))
00360 item.caps |= GpgOp::KeyItem::Sign;
00361 if(caps.contains('c'))
00362 item.caps |= GpgOp::KeyItem::Certify;
00363 if(caps.contains('a'))
00364 item.caps |= GpgOp::KeyItem::Auth;
00365
00366 keyList.last().keyItems += item;
00367 }
00368 else if(type == "uid")
00369 {
00370 QByteArray uid = getCString(f[9].toLatin1());
00371 keyList.last().userIds.append(QString::fromUtf8(uid));
00372 }
00373 else if(type == "fpr")
00374 {
00375 QString s = f[9];
00376 keyList.last().keyItems.last().fingerprint = s;
00377 }
00378 }
00379
00380 if(_keylist)
00381 *_keylist = keyList;
00382 if(_keyring)
00383 *_keyring = keyring;
00384
00385 return true;
00386 }
00387
00388 static bool findKeyringFilename(const QString &outstr, QString *_keyring)
00389 {
00390 QStringList lines = outstr.split('\n');
00391 if(lines.count() < 1)
00392 return false;
00393
00394 *_keyring = lines[0];
00395 return true;
00396 }
00397
00398 class GpgAction : public QObject
00399 {
00400 Q_OBJECT
00401 public:
00402 class Input
00403 {
00404 public:
00405 QString bin;
00406 GpgOp::Type op;
00407 bool opt_ascii, opt_noagent, opt_alwaystrust;
00408 QString opt_pubfile, opt_secfile;
00409 QStringList recip_ids;
00410 QString signer_id;
00411 QByteArray sig;
00412 QByteArray inkey;
00413 QString export_key_id;
00414 QString delete_key_fingerprint;
00415
00416 Input() : opt_ascii(false), opt_noagent(false), opt_alwaystrust(false) {}
00417 };
00418
00419 class Output
00420 {
00421 public:
00422 bool success;
00423 GpgOp::Error errorCode;
00424 GpgOp::KeyList keys;
00425 QString keyringFile;
00426 QString encryptedToId;
00427 bool wasSigned;
00428 QString signerId;
00429 QDateTime timestamp;
00430 GpgOp::VerifyResult verifyResult;
00431
00432 Output() : success(false), errorCode(GpgOp::ErrorUnknown), wasSigned(false) {}
00433 };
00434
00435 Input input;
00436 Output output;
00437
00438 GPGProc proc;
00439 bool collectOutput, allowInput;
00440 LineConverter readConv, writeConv;
00441 bool readText, writeText;
00442 QByteArray buf_stdout, buf_stderr;
00443 bool useAux;
00444 QString passphraseKeyId;
00445 bool signing, signPartDone, decryptGood, signGood;
00446 GpgOp::Error curError;
00447 bool badPassphrase;
00448 bool need_submitPassphrase, need_cardOkay;
00449 QString diagnosticText;
00450 SafeTimer dtextTimer;
00451
00452 #ifdef GPG_PROFILE
00453 QTime timer;
00454 #endif
00455
00456 GpgAction(QObject *parent = 0) : QObject(parent), proc(this), dtextTimer(this)
00457 {
00458 dtextTimer.setSingleShot(true);
00459
00460 connect(&proc, SIGNAL(error(gpgQCAPlugin::GPGProc::Error)), SLOT(proc_error(gpgQCAPlugin::GPGProc::Error)));
00461 connect(&proc, SIGNAL(finished(int)), SLOT(proc_finished(int)));
00462 connect(&proc, SIGNAL(readyReadStdout()), SLOT(proc_readyReadStdout()));
00463 connect(&proc, SIGNAL(readyReadStderr()), SLOT(proc_readyReadStderr()));
00464 connect(&proc, SIGNAL(readyReadStatusLines()), SLOT(proc_readyReadStatusLines()));
00465 connect(&proc, SIGNAL(bytesWrittenStdin(int)), SLOT(proc_bytesWrittenStdin(int)));
00466 connect(&proc, SIGNAL(bytesWrittenAux(int)), SLOT(proc_bytesWrittenAux(int)));
00467 connect(&proc, SIGNAL(bytesWrittenCommand(int)), SLOT(proc_bytesWrittenCommand(int)));
00468 connect(&proc, SIGNAL(debug(const QString &)), SLOT(proc_debug(const QString &)));
00469 connect(&dtextTimer, SIGNAL(timeout()), SLOT(t_dtext()));
00470
00471 reset();
00472 }
00473
00474 ~GpgAction()
00475 {
00476 reset();
00477 }
00478
00479 void reset()
00480 {
00481 collectOutput = true;
00482 allowInput = false;
00483 readConv.setup(LineConverter::Read);
00484 writeConv.setup(LineConverter::Write);
00485 readText = false;
00486 writeText = false;
00487 useAux = false;
00488 passphraseKeyId = QString();
00489 signing = false;
00490 signPartDone = false;
00491 decryptGood = false;
00492 signGood = false;
00493 curError = GpgOp::ErrorUnknown;
00494 badPassphrase = false;
00495 need_submitPassphrase = false;
00496 need_cardOkay = false;
00497 diagnosticText = QString();
00498 dtextTimer.stop();
00499
00500 output = Output();
00501
00502 proc.reset();
00503 }
00504
00505 void start()
00506 {
00507 reset();
00508
00509 QStringList args;
00510 bool extra = false;
00511
00512 if(input.opt_ascii)
00513 args += "--armor";
00514
00515 if(input.opt_noagent)
00516 args += "--no-use-agent";
00517
00518 if(input.opt_alwaystrust)
00519 args += "--always-trust";
00520
00521 if(!input.opt_pubfile.isEmpty() && !input.opt_secfile.isEmpty())
00522 {
00523 args += "--no-default-keyring";
00524 args += "--keyring";
00525 args += input.opt_pubfile;
00526 args += "--secret-keyring";
00527 args += input.opt_secfile;
00528 }
00529
00530 switch(input.op)
00531 {
00532 case GpgOp::Check:
00533 {
00534 args += "--version";
00535 readText = true;
00536 break;
00537 }
00538 case GpgOp::SecretKeyringFile:
00539 {
00540 args += "--list-secret-keys";
00541 readText = true;
00542 break;
00543 }
00544 case GpgOp::PublicKeyringFile:
00545 {
00546 args += "--list-public-keys";
00547 readText = true;
00548 break;
00549 }
00550 case GpgOp::SecretKeys:
00551 {
00552 args += "--fixed-list-mode";
00553 args += "--with-colons";
00554 args += "--with-fingerprint";
00555 args += "--with-fingerprint";
00556 args += "--list-secret-keys";
00557 readText = true;
00558 break;
00559 }
00560 case GpgOp::PublicKeys:
00561 {
00562 args += "--fixed-list-mode";
00563 args += "--with-colons";
00564 args += "--with-fingerprint";
00565 args += "--with-fingerprint";
00566 args += "--list-public-keys";
00567 readText = true;
00568 break;
00569 }
00570 case GpgOp::Encrypt:
00571 {
00572 args += "--encrypt";
00573
00574
00575 for(QStringList::ConstIterator it = input.recip_ids.begin(); it != input.recip_ids.end(); ++it)
00576 {
00577 args += "--recipient";
00578 args += QString("0x") + *it;
00579 }
00580 extra = true;
00581 collectOutput = false;
00582 allowInput = true;
00583 if(input.opt_ascii)
00584 readText = true;
00585 break;
00586 }
00587 case GpgOp::Decrypt:
00588 {
00589 args += "--decrypt";
00590 extra = true;
00591 collectOutput = false;
00592 allowInput = true;
00593 if(input.opt_ascii)
00594 writeText = true;
00595 break;
00596 }
00597 case GpgOp::Sign:
00598 {
00599 args += "--default-key";
00600 args += QString("0x") + input.signer_id;
00601 args += "--sign";
00602 extra = true;
00603 collectOutput = false;
00604 allowInput = true;
00605 if(input.opt_ascii)
00606 readText = true;
00607 signing = true;
00608 break;
00609 }
00610 case GpgOp::SignAndEncrypt:
00611 {
00612 args += "--default-key";
00613 args += QString("0x") + input.signer_id;
00614 args += "--sign";
00615 args += "--encrypt";
00616
00617
00618 for(QStringList::ConstIterator it = input.recip_ids.begin(); it != input.recip_ids.end(); ++it)
00619 {
00620 args += "--recipient";
00621 args += QString("0x") + *it;
00622 }
00623 extra = true;
00624 collectOutput = false;
00625 allowInput = true;
00626 if(input.opt_ascii)
00627 readText = true;
00628 signing = true;
00629 break;
00630 }
00631 case GpgOp::SignClearsign:
00632 {
00633 args += "--default-key";
00634 args += QString("0x") + input.signer_id;
00635 args += "--clearsign";
00636 extra = true;
00637 collectOutput = false;
00638 allowInput = true;
00639 if(input.opt_ascii)
00640 readText = true;
00641 signing = true;
00642 break;
00643 }
00644 case GpgOp::SignDetached:
00645 {
00646 args += "--default-key";
00647 args += QString("0x") + input.signer_id;
00648 args += "--detach-sign";
00649 extra = true;
00650 collectOutput = false;
00651 allowInput = true;
00652 if(input.opt_ascii)
00653 readText = true;
00654 signing = true;
00655 break;
00656 }
00657 case GpgOp::Verify:
00658 {
00659 args += "--verify";
00660 args += "-";
00661 extra = true;
00662 allowInput = true;
00663 if(input.opt_ascii)
00664 writeText = true;
00665 break;
00666 }
00667 case GpgOp::VerifyDetached:
00668 {
00669 args += "--verify";
00670 args += "-";
00671 args += "-&?";
00672 extra = true;
00673 allowInput = true;
00674 useAux = true;
00675 break;
00676 }
00677 case GpgOp::Import:
00678 {
00679 args += "--import";
00680 readText = true;
00681 if(input.opt_ascii)
00682 writeText = true;
00683 break;
00684 }
00685 case GpgOp::Export:
00686 {
00687 args += "--export";
00688 args += QString("0x") + input.export_key_id;
00689 collectOutput = false;
00690 if(input.opt_ascii)
00691 readText = true;
00692 break;
00693 }
00694 case GpgOp::DeleteKey:
00695 {
00696 args += "--batch";
00697 args += "--delete-key";
00698 args += QString("0x") + input.delete_key_fingerprint;
00699 break;
00700 }
00701 }
00702
00703 #ifdef GPG_PROFILE
00704 timer.start();
00705 printf("<< launch >>\n");
00706 #endif
00707 proc.start(input.bin, args, extra ? GPGProc::ExtendedMode : GPGProc::NormalMode);
00708
00709
00710 if(input.op == GpgOp::VerifyDetached)
00711 {
00712 QByteArray a = input.sig;
00713 if(input.opt_ascii)
00714 {
00715 LineConverter conv;
00716 conv.setup(LineConverter::Write);
00717 a = conv.process(a);
00718 }
00719 proc.writeStdin(a);
00720 proc.closeStdin();
00721 }
00722
00723
00724 if(input.op == GpgOp::Import)
00725 {
00726 QByteArray a = input.inkey;
00727 if(writeText)
00728 {
00729 LineConverter conv;
00730 conv.setup(LineConverter::Write);
00731 a = conv.process(a);
00732 }
00733 proc.writeStdin(a);
00734 proc.closeStdin();
00735 }
00736 }
00737
00738 #ifdef QPIPE_SECURE
00739 void submitPassphrase(const QCA::SecureArray &a)
00740 #else
00741 void submitPassphrase(const QByteArray &a)
00742 #endif
00743 {
00744 if(!need_submitPassphrase)
00745 return;
00746
00747 need_submitPassphrase = false;
00748
00749 #ifdef QPIPE_SECURE
00750 QCA::SecureArray b;
00751 #else
00752 QByteArray b;
00753 #endif
00754
00755
00756 b.resize(a.size());
00757 int at = 0;
00758 for(int n = 0; n < a.size(); ++n)
00759 {
00760 if(a[n] != '\n')
00761 b[at++] = a[n];
00762 }
00763 b.resize(at);
00764
00765
00766 b.resize(b.size() + 1);
00767 b[b.size() - 1] = '\n';
00768 proc.writeCommand(b);
00769 }
00770
00771 public slots:
00772 QByteArray read()
00773 {
00774 if(collectOutput)
00775 return QByteArray();
00776
00777 QByteArray a = proc.readStdout();
00778 if(readText)
00779 a = readConv.update(a);
00780 if(!proc.isActive())
00781 a += readConv.final();
00782 return a;
00783 }
00784
00785 void write(const QByteArray &in)
00786 {
00787 if(!allowInput)
00788 return;
00789
00790 QByteArray a = in;
00791 if(writeText)
00792 a = writeConv.update(in);
00793
00794 if(useAux)
00795 proc.writeAux(a);
00796 else
00797 proc.writeStdin(a);
00798 }
00799
00800 void endWrite()
00801 {
00802 if(!allowInput)
00803 return;
00804
00805 if(useAux)
00806 proc.closeAux();
00807 else
00808 proc.closeStdin();
00809 }
00810
00811 void cardOkay()
00812 {
00813 if(need_cardOkay)
00814 {
00815 need_cardOkay = false;
00816 submitCommand("\n");
00817 }
00818 }
00819
00820 QString readDiagnosticText()
00821 {
00822 QString s = diagnosticText;
00823 diagnosticText = QString();
00824 return s;
00825 }
00826
00827 signals:
00828 void readyRead();
00829 void bytesWritten(int bytes);
00830 void finished();
00831 void needPassphrase(const QString &keyId);
00832 void needCard();
00833 void readyReadDiagnosticText();
00834
00835 private:
00836 void submitCommand(const QByteArray &a)
00837 {
00838 proc.writeCommand(a);
00839 }
00840
00841
00842 QString nextArg(QString str, QString *rest = 0)
00843 {
00844 QString out;
00845 int n = str.indexOf(' ');
00846 if(n == -1)
00847 {
00848 if(rest)
00849 *rest = QString();
00850 return str;
00851 }
00852 else
00853 {
00854 if(rest)
00855 *rest = str.mid(n + 1);
00856 return str.mid(0, n);
00857 }
00858 }
00859
00860 void processStatusLine(const QString &line)
00861 {
00862 diagnosticText += QString("{") + line + "}\n";
00863 ensureDTextEmit();
00864
00865 if(!proc.isActive())
00866 return;
00867
00868 QString s, rest;
00869 s = nextArg(line, &rest);
00870
00871 if(s == "NODATA")
00872 {
00873
00874 if(curError == GpgOp::ErrorUnknown)
00875 curError = GpgOp::ErrorFormat;
00876 }
00877 else if(s == "UNEXPECTED")
00878 {
00879 if(curError == GpgOp::ErrorUnknown)
00880 curError = GpgOp::ErrorFormat;
00881 }
00882 else if(s == "KEYEXPIRED")
00883 {
00884 if(curError == GpgOp::ErrorUnknown)
00885 {
00886 if(input.op == GpgOp::SignAndEncrypt)
00887 {
00888 if(!signPartDone)
00889 curError = GpgOp::ErrorSignerExpired;
00890 else
00891 curError = GpgOp::ErrorEncryptExpired;
00892 }
00893 else
00894 {
00895 if(signing)
00896 curError = GpgOp::ErrorSignerExpired;
00897 else
00898 curError = GpgOp::ErrorEncryptExpired;
00899 }
00900 }
00901 }
00902 else if(s == "INV_RECP")
00903 {
00904 int r = nextArg(rest).toInt();
00905
00906 if(curError == GpgOp::ErrorUnknown)
00907 {
00908 if(r == 10)
00909 curError = GpgOp::ErrorEncryptUntrusted;
00910 else
00911 curError = GpgOp::ErrorEncryptInvalid;
00912 }
00913 }
00914 else if(s == "NO_SECKEY")
00915 {
00916 output.encryptedToId = nextArg(rest);
00917
00918 if(curError == GpgOp::ErrorUnknown)
00919 curError = GpgOp::ErrorDecryptNoKey;
00920 }
00921 else if(s == "DECRYPTION_OKAY")
00922 {
00923 decryptGood = true;
00924
00925
00926 if(curError == GpgOp::ErrorDecryptNoKey)
00927 curError = GpgOp::ErrorUnknown;
00928 }
00929 else if(s == "SIG_CREATED")
00930 {
00931 signGood = true;
00932 }
00933 else if(s == "USERID_HINT")
00934 {
00935 passphraseKeyId = nextArg(rest);
00936 }
00937 else if(s == "GET_HIDDEN")
00938 {
00939 QString arg = nextArg(rest);
00940 if(arg == "passphrase.enter" || arg == "passphrase.pin.ask")
00941 {
00942 need_submitPassphrase = true;
00943
00944
00945 QMetaObject::invokeMethod(this, "needPassphrase", Qt::QueuedConnection, Q_ARG(QString, passphraseKeyId));
00946 }
00947 }
00948 else if(s == "GET_LINE")
00949 {
00950 QString arg = nextArg(rest);
00951 if(arg == "cardctrl.insert_card.okay")
00952 {
00953 need_cardOkay = true;
00954
00955 QMetaObject::invokeMethod(this, "needCard", Qt::QueuedConnection);
00956 }
00957 }
00958 else if(s == "GET_BOOL")
00959 {
00960 QString arg = nextArg(rest);
00961 if(arg == "untrusted_key.override")
00962 submitCommand("no\n");
00963 }
00964 else if(s == "GOOD_PASSPHRASE")
00965 {
00966 badPassphrase = false;
00967
00968
00969 signPartDone = true;
00970 }
00971 else if(s == "BAD_PASSPHRASE")
00972 {
00973 badPassphrase = true;
00974 }
00975 else if(s == "GOODSIG")
00976 {
00977 output.wasSigned = true;
00978 output.signerId = nextArg(rest);
00979 output.verifyResult = GpgOp::VerifyGood;
00980 }
00981 else if(s == "BADSIG")
00982 {
00983 output.wasSigned = true;
00984 output.signerId = nextArg(rest);
00985 output.verifyResult = GpgOp::VerifyBad;
00986 }
00987 else if(s == "ERRSIG")
00988 {
00989 output.wasSigned = true;
00990 QStringList list = rest.split(' ', QString::SkipEmptyParts);
00991 output.signerId = list[0];
00992 output.timestamp = getTimestamp(list[4]);
00993 output.verifyResult = GpgOp::VerifyNoKey;
00994 }
00995 else if(s == "VALIDSIG")
00996 {
00997 QStringList list = rest.split(' ', QString::SkipEmptyParts);
00998 output.timestamp = getTimestamp(list[2]);
00999 }
01000 }
01001
01002 void processResult(int code)
01003 {
01004 #ifdef GPG_PROFILE
01005 printf("<< launch: %d >>\n", timer.elapsed());
01006 #endif
01007
01008
01009 QString outstr = QString::fromLatin1(buf_stdout);
01010 QString errstr = QString::fromLatin1(buf_stderr);
01011
01012 if(collectOutput)
01013 diagnosticText += QString("stdout: [%1]\n").arg(outstr);
01014 diagnosticText += QString("stderr: [%1]\n").arg(errstr);
01015 ensureDTextEmit();
01016
01017 if(badPassphrase)
01018 {
01019 output.errorCode = GpgOp::ErrorPassphrase;
01020 }
01021 else if(curError != GpgOp::ErrorUnknown)
01022 {
01023 output.errorCode = curError;
01024 }
01025 else if(code == 0)
01026 {
01027 if(input.op == GpgOp::SecretKeyringFile || input.op == GpgOp::PublicKeyringFile)
01028 {
01029 if(findKeyringFilename(outstr, &output.keyringFile))
01030 output.success = true;
01031 }
01032 else if(input.op == GpgOp::SecretKeys || input.op == GpgOp::PublicKeys)
01033 {
01034 if(stringToKeyList(outstr, &output.keys, &output.keyringFile))
01035 output.success = true;
01036 }
01037 else
01038 output.success = true;
01039 }
01040 else
01041 {
01042
01043
01044
01045
01046
01047 if(input.op == GpgOp::Decrypt && decryptGood)
01048 output.success = true;
01049 if(signing && signGood)
01050 output.success = true;
01051
01052
01053
01054
01055 bool signedMakesItGood = false;
01056 if(input.op == GpgOp::Verify || input.op == GpgOp::VerifyDetached)
01057 signedMakesItGood = true;
01058
01059 if(signedMakesItGood && output.wasSigned)
01060 output.success = true;
01061 }
01062
01063 emit finished();
01064 }
01065
01066 void ensureDTextEmit()
01067 {
01068 if(!dtextTimer.isActive())
01069 dtextTimer.start();
01070 }
01071
01072 private slots:
01073 void t_dtext()
01074 {
01075 emit readyReadDiagnosticText();
01076 }
01077
01078 void proc_error(gpgQCAPlugin::GPGProc::Error e)
01079 {
01080 QString str;
01081 if(e == GPGProc::FailedToStart)
01082 str = "FailedToStart";
01083 else if(e == GPGProc::UnexpectedExit)
01084 str = "UnexpectedExit";
01085 else if(e == GPGProc::ErrorWrite)
01086 str = "ErrorWrite";
01087
01088 diagnosticText += QString("GPG Process Error: %1\n").arg(str);
01089 ensureDTextEmit();
01090
01091 output.errorCode = GpgOp::ErrorProcess;
01092 emit finished();
01093 }
01094
01095 void proc_finished(int exitCode)
01096 {
01097 diagnosticText += QString("GPG Process Finished: exitStatus=%1\n").arg(exitCode);
01098 ensureDTextEmit();
01099
01100 processResult(exitCode);
01101 }
01102
01103 void proc_readyReadStdout()
01104 {
01105 if(collectOutput)
01106 {
01107 QByteArray a = proc.readStdout();
01108 if(readText)
01109 a = readConv.update(a);
01110 buf_stdout.append(a);
01111 }
01112 else
01113 emit readyRead();
01114 }
01115
01116 void proc_readyReadStderr()
01117 {
01118 buf_stderr.append(proc.readStderr());
01119 }
01120
01121 void proc_readyReadStatusLines()
01122 {
01123 QStringList lines = proc.readStatusLines();
01124 for(int n = 0; n < lines.count(); ++n)
01125 processStatusLine(lines[n]);
01126 }
01127
01128 void proc_bytesWrittenStdin(int bytes)
01129 {
01130 if(!useAux)
01131 {
01132 int actual = writeConv.writtenToActual(bytes);
01133 emit bytesWritten(actual);
01134 }
01135 }
01136
01137 void proc_bytesWrittenAux(int bytes)
01138 {
01139 if(useAux)
01140 {
01141 int actual = writeConv.writtenToActual(bytes);
01142 emit bytesWritten(actual);
01143 }
01144 }
01145
01146 void proc_bytesWrittenCommand(int)
01147 {
01148
01149 }
01150
01151 void proc_debug(const QString &str)
01152 {
01153 diagnosticText += "GPGProc: " + str + '\n';
01154 ensureDTextEmit();
01155 }
01156 };
01157
01158
01159
01160
01161 enum ResetMode
01162 {
01163 ResetSession = 0,
01164 ResetSessionAndData = 1,
01165 ResetAll = 2
01166 };
01167
01168 class GpgOp::Private : public QObject
01169 {
01170 Q_OBJECT
01171 public:
01172 QCA::Synchronizer sync;
01173 GpgOp *q;
01174 GpgAction *act;
01175 QString bin;
01176 GpgOp::Type op;
01177 GpgAction::Output output;
01178 QByteArray result;
01179 QString diagnosticText;
01180 QList<GpgOp::Event> eventList;
01181 bool waiting;
01182
01183 bool opt_ascii, opt_noagent, opt_alwaystrust;
01184 QString opt_pubfile, opt_secfile;
01185
01186 #ifdef GPG_PROFILE
01187 QTime timer;
01188 #endif
01189
01190 Private(GpgOp *_q) : QObject(_q), sync(_q), q(_q)
01191 {
01192 act = 0;
01193 waiting = false;
01194
01195 reset(ResetAll);
01196 }
01197
01198 ~Private()
01199 {
01200 reset(ResetAll);
01201 }
01202
01203 void reset(ResetMode mode)
01204 {
01205 if(act)
01206 {
01207 releaseAndDeleteLater(this, act);
01208 act = 0;
01209 }
01210
01211 if(mode >= ResetSessionAndData)
01212 {
01213 output = GpgAction::Output();
01214 result.clear();
01215 diagnosticText = QString();
01216 eventList.clear();
01217 }
01218
01219 if(mode >= ResetAll)
01220 {
01221 opt_ascii = false;
01222 opt_noagent = false;
01223 opt_alwaystrust = false;
01224 opt_pubfile = QString();
01225 opt_secfile = QString();
01226 }
01227 }
01228
01229 void make_act(GpgOp::Type _op)
01230 {
01231 reset(ResetSessionAndData);
01232
01233 op = _op;
01234
01235 act = new GpgAction(this);
01236
01237 connect(act, SIGNAL(readyRead()), SLOT(act_readyRead()));
01238 connect(act, SIGNAL(bytesWritten(int)), SLOT(act_bytesWritten(int)));
01239 connect(act, SIGNAL(needPassphrase(const QString &)), SLOT(act_needPassphrase(const QString &)));
01240 connect(act, SIGNAL(needCard()), SLOT(act_needCard()));
01241 connect(act, SIGNAL(finished()), SLOT(act_finished()));
01242 connect(act, SIGNAL(readyReadDiagnosticText()), SLOT(act_readyReadDiagnosticText()));
01243
01244 act->input.bin = bin;
01245 act->input.op = op;
01246 act->input.opt_ascii = opt_ascii;
01247 act->input.opt_noagent = opt_noagent;
01248 act->input.opt_alwaystrust = opt_alwaystrust;
01249 act->input.opt_pubfile = opt_pubfile;
01250 act->input.opt_secfile = opt_secfile;
01251 }
01252
01253 void eventReady(const GpgOp::Event &e)
01254 {
01255 eventList += e;
01256 sync.conditionMet();
01257 }
01258
01259 void eventReady(GpgOp::Event::Type type)
01260 {
01261 GpgOp::Event e;
01262 e.type = type;
01263 eventReady(e);
01264 }
01265
01266 void eventReady(GpgOp::Event::Type type, int written)
01267 {
01268 GpgOp::Event e;
01269 e.type = type;
01270 e.written = written;
01271 eventReady(e);
01272 }
01273
01274 void eventReady(GpgOp::Event::Type type, const QString &keyId)
01275 {
01276 GpgOp::Event e;
01277 e.type = type;
01278 e.keyId = keyId;
01279 eventReady(e);
01280 }
01281
01282 public slots:
01283 void act_readyRead()
01284 {
01285 if(waiting)
01286 eventReady(GpgOp::Event::ReadyRead);
01287 else
01288 emit q->readyRead();
01289 }
01290
01291 void act_bytesWritten(int bytes)
01292 {
01293 if(waiting)
01294 eventReady(GpgOp::Event::BytesWritten, bytes);
01295 else
01296 emit q->bytesWritten(bytes);
01297 }
01298
01299 void act_needPassphrase(const QString &keyId)
01300 {
01301 if(waiting)
01302 eventReady(GpgOp::Event::NeedPassphrase, keyId);
01303 else
01304 emit q->needPassphrase(keyId);
01305 }
01306
01307 void act_needCard()
01308 {
01309 if(waiting)
01310 eventReady(GpgOp::Event::NeedCard);
01311 else
01312 emit q->needCard();
01313 }
01314
01315 void act_readyReadDiagnosticText()
01316 {
01317 QString s = act->readDiagnosticText();
01318
01319 diagnosticText += s;
01320
01321 if(waiting)
01322 eventReady(GpgOp::Event::ReadyReadDiagnosticText);
01323 else
01324 emit q->readyReadDiagnosticText();
01325 }
01326
01327 void act_finished()
01328 {
01329 #ifdef GPG_PROFILE
01330 if(op == GpgOp::Encrypt)
01331 printf("<< doEncrypt: %d >>\n", timer.elapsed());
01332 #endif
01333
01334 result = act->read();
01335 diagnosticText += act->readDiagnosticText();
01336 output = act->output;
01337
01338 QMap<int, QString> errmap;
01339 errmap[GpgOp::ErrorProcess] = "ErrorProcess";
01340 errmap[GpgOp::ErrorPassphrase] = "ErrorPassphrase";
01341 errmap[GpgOp::ErrorFormat] = "ErrorFormat";
01342 errmap[GpgOp::ErrorSignerExpired] = "ErrorSignerExpired";
01343 errmap[GpgOp::ErrorEncryptExpired] = "ErrorEncryptExpired";
01344 errmap[GpgOp::ErrorEncryptUntrusted] = "ErrorEncryptUntrusted";
01345 errmap[GpgOp::ErrorEncryptInvalid] = "ErrorEncryptInvalid";
01346 errmap[GpgOp::ErrorDecryptNoKey] = "ErrorDecryptNoKey";
01347 errmap[GpgOp::ErrorUnknown] = "ErrorUnknown";
01348 if(output.success)
01349 diagnosticText += "GpgAction success\n";
01350 else
01351 diagnosticText += QString("GpgAction error: %1\n").arg(errmap[output.errorCode]);
01352
01353 if(output.wasSigned)
01354 {
01355 QString s;
01356 if(output.verifyResult == GpgOp::VerifyGood)
01357 s = "VerifyGood";
01358 else if(output.verifyResult == GpgOp::VerifyBad)
01359 s = "VerifyBad";
01360 else
01361 s = "VerifyNoKey";
01362 diagnosticText += QString("wasSigned: verifyResult: %1\n").arg(s);
01363 }
01364
01365
01366
01367 reset(ResetSession);
01368
01369 if(waiting)
01370 eventReady(GpgOp::Event::Finished);
01371 else
01372 emit q->finished();
01373 }
01374 };
01375
01376 GpgOp::GpgOp(const QString &bin, QObject *parent)
01377 :QObject(parent)
01378 {
01379 d = new Private(this);
01380 d->bin = bin;
01381 }
01382
01383 GpgOp::~GpgOp()
01384 {
01385 delete d;
01386 }
01387
01388 void GpgOp::reset()
01389 {
01390 d->reset(ResetAll);
01391 }
01392
01393 bool GpgOp::isActive() const
01394 {
01395 return (d->act ? true : false);
01396 }
01397
01398 GpgOp::Type GpgOp::op() const
01399 {
01400 return d->op;
01401 }
01402
01403 void GpgOp::setAsciiFormat(bool b)
01404 {
01405 d->opt_ascii = b;
01406 }
01407
01408 void GpgOp::setDisableAgent(bool b)
01409 {
01410 d->opt_noagent = b;
01411 }
01412
01413 void GpgOp::setAlwaysTrust(bool b)
01414 {
01415 d->opt_alwaystrust = b;
01416 }
01417
01418 void GpgOp::setKeyrings(const QString &pubfile, const QString &secfile)
01419 {
01420 d->opt_pubfile = pubfile;
01421 d->opt_secfile = secfile;
01422 }
01423
01424 void GpgOp::doCheck()
01425 {
01426 d->make_act(Check);
01427 d->act->start();
01428 }
01429
01430 void GpgOp::doSecretKeyringFile()
01431 {
01432 d->make_act(SecretKeyringFile);
01433 d->act->start();
01434 }
01435
01436 void GpgOp::doPublicKeyringFile()
01437 {
01438 d->make_act(PublicKeyringFile);
01439 d->act->start();
01440 }
01441
01442 void GpgOp::doSecretKeys()
01443 {
01444 d->make_act(SecretKeys);
01445 d->act->start();
01446 }
01447
01448 void GpgOp::doPublicKeys()
01449 {
01450 d->make_act(PublicKeys);
01451 d->act->start();
01452 }
01453
01454 void GpgOp::doEncrypt(const QStringList &recip_ids)
01455 {
01456 #ifdef GPG_PROFILE
01457 d->timer.start();
01458 printf("<< doEncrypt >>\n");
01459 #endif
01460
01461 d->make_act(Encrypt);
01462 d->act->input.recip_ids = recip_ids;
01463 d->act->start();
01464 }
01465
01466 void GpgOp::doDecrypt()
01467 {
01468 d->make_act(Decrypt);
01469 d->act->start();
01470 }
01471
01472 void GpgOp::doSign(const QString &signer_id)
01473 {
01474 d->make_act(Sign);
01475 d->act->input.signer_id = signer_id;
01476 d->act->start();
01477 }
01478
01479 void GpgOp::doSignAndEncrypt(const QString &signer_id, const QStringList &recip_ids)
01480 {
01481 d->make_act(SignAndEncrypt);
01482 d->act->input.signer_id = signer_id;
01483 d->act->input.recip_ids = recip_ids;
01484 d->act->start();
01485 }
01486
01487 void GpgOp::doSignClearsign(const QString &signer_id)
01488 {
01489 d->make_act(SignClearsign);
01490 d->act->input.signer_id = signer_id;
01491 d->act->start();
01492 }
01493
01494 void GpgOp::doSignDetached(const QString &signer_id)
01495 {
01496 d->make_act(SignDetached);
01497 d->act->input.signer_id = signer_id;
01498 d->act->start();
01499 }
01500
01501 void GpgOp::doVerify()
01502 {
01503 d->make_act(Verify);
01504 d->act->start();
01505 }
01506
01507 void GpgOp::doVerifyDetached(const QByteArray &sig)
01508 {
01509 d->make_act(VerifyDetached);
01510 d->act->input.sig = sig;
01511 d->act->start();
01512 }
01513
01514 void GpgOp::doImport(const QByteArray &in)
01515 {
01516 d->make_act(Import);
01517 d->act->input.inkey = in;
01518 d->act->start();
01519 }
01520
01521 void GpgOp::doExport(const QString &key_id)
01522 {
01523 d->make_act(Export);
01524 d->act->input.export_key_id = key_id;
01525 d->act->start();
01526 }
01527
01528 void GpgOp::doDeleteKey(const QString &key_fingerprint)
01529 {
01530 d->make_act(DeleteKey);
01531 d->act->input.delete_key_fingerprint = key_fingerprint;
01532 d->act->start();
01533 }
01534
01535 #ifdef QPIPE_SECURE
01536 void GpgOp::submitPassphrase(const QCA::SecureArray &a)
01537 #else
01538 void GpgOp::submitPassphrase(const QByteArray &a)
01539 #endif
01540 {
01541 d->act->submitPassphrase(a);
01542 }
01543
01544 void GpgOp::cardOkay()
01545 {
01546 d->act->cardOkay();
01547 }
01548
01549 QByteArray GpgOp::read()
01550 {
01551 if(d->act)
01552 {
01553 return d->act->read();
01554 }
01555 else
01556 {
01557 QByteArray a = d->result;
01558 d->result.clear();
01559 return a;
01560 }
01561 }
01562
01563 void GpgOp::write(const QByteArray &in)
01564 {
01565 d->act->write(in);
01566 }
01567
01568 void GpgOp::endWrite()
01569 {
01570 d->act->endWrite();
01571 }
01572
01573 QString GpgOp::readDiagnosticText()
01574 {
01575 QString s = d->diagnosticText;
01576 d->diagnosticText = QString();
01577 return s;
01578 }
01579
01580 GpgOp::Event GpgOp::waitForEvent(int msecs)
01581 {
01582 if(!d->eventList.isEmpty())
01583 return d->eventList.takeFirst();
01584
01585 if(!d->act)
01586 return GpgOp::Event();
01587
01588 d->waiting = true;
01589 d->sync.waitForCondition(msecs);
01590 d->waiting = false;
01591 return d->eventList.takeFirst();
01592 }
01593
01594 bool GpgOp::success() const
01595 {
01596 return d->output.success;
01597 }
01598
01599 GpgOp::Error GpgOp::errorCode() const
01600 {
01601 return d->output.errorCode;
01602 }
01603
01604 GpgOp::KeyList GpgOp::keys() const
01605 {
01606 return d->output.keys;
01607 }
01608
01609 QString GpgOp::keyringFile() const
01610 {
01611 return d->output.keyringFile;
01612 }
01613
01614 QString GpgOp::encryptedToId() const
01615 {
01616 return d->output.encryptedToId;
01617 }
01618
01619 bool GpgOp::wasSigned() const
01620 {
01621 return d->output.wasSigned;
01622 }
01623
01624 QString GpgOp::signerId() const
01625 {
01626 return d->output.signerId;
01627 }
01628
01629 QDateTime GpgOp::timestamp() const
01630 {
01631 return d->output.timestamp;
01632 }
01633
01634 GpgOp::VerifyResult GpgOp::verifyResult() const
01635 {
01636 return d->output.verifyResult;
01637 }
01638
01639 }
01640
01641 #include "gpgop.moc"