File indexing completed on 2025-01-12 04:19:45
0001 /* 0002 * Copyright (C) 2003-2005 Justin Karneges <justin@affinix.com> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Lesser General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2.1 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Lesser General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Lesser General Public 0015 * License along with this library; if not, write to the Free Software 0016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 0017 * 0018 */ 0019 0020 // #define GPGOP_DEBUG 0021 0022 #include "gpgaction.h" 0023 0024 #ifdef GPGOP_DEBUG 0025 #include "stdio.h" 0026 #endif 0027 0028 namespace gpgQCAPlugin { 0029 0030 static QDateTime getTimestamp(const QString &s) 0031 { 0032 if (s.isEmpty()) 0033 return QDateTime(); 0034 0035 if (s.contains(QLatin1Char('T'))) { 0036 return QDateTime::fromString(s, Qt::ISODate); 0037 } else { 0038 return QDateTime::fromSecsSinceEpoch(s.toInt()); 0039 } 0040 } 0041 0042 static QByteArray getCString(const QByteArray &a) 0043 { 0044 QByteArray out; 0045 0046 // convert the "backslash" C-string syntax 0047 for (int n = 0; n < a.size(); ++n) { 0048 if (a[n] == '\\' && n + 1 < a.size()) { 0049 ++n; 0050 unsigned char c = (unsigned char)a[n]; 0051 if (c == '\\') { 0052 out += '\\'; 0053 } else if (c == 'x' && n + 2 < a.size()) { 0054 ++n; 0055 const QByteArray hex = a.mid(n, 2); 0056 ++n; // only skip one, loop will skip the next 0057 0058 bool ok; 0059 uint val = hex.toInt(&ok, 16); 0060 if (ok) { 0061 out += (unsigned char)val; 0062 } else { 0063 out += "\\x"; 0064 out += hex; 0065 } 0066 } 0067 } else { 0068 out += a[n]; 0069 } 0070 } 0071 0072 return out; 0073 } 0074 0075 static bool stringToKeyList(const QString &outstr, GpgOp::KeyList *_keylist, QString *_keyring) 0076 { 0077 GpgOp::KeyList keyList; 0078 const QStringList lines = outstr.split(QLatin1Char('\n')); 0079 0080 if (lines.count() < 1) 0081 return false; 0082 0083 QStringList::ConstIterator it = lines.constBegin(); 0084 0085 // first line is keyring file 0086 QString keyring = *(it++); 0087 0088 // if the second line isn't a divider, we are dealing 0089 // with a new version of gnupg that doesn't give us 0090 // the keyring file on gpg --list-keys --with-colons 0091 if (it == lines.constEnd() || (*it).isEmpty() || (*it).at(0) != QLatin1Char('-')) { 0092 // first line wasn't the keyring name... 0093 keyring.clear(); 0094 // ...so read the first line again 0095 it--; 0096 } else { 0097 // this was the divider line - skip it 0098 it++; 0099 } 0100 0101 for (; it != lines.constEnd(); ++it) { 0102 const QStringList f = (*it).split(QLatin1Char(':')); 0103 if (f.count() < 1) 0104 continue; 0105 const QString &type = f[0]; 0106 0107 bool key = false; // key or not 0108 bool primary = false; // primary key or sub key 0109 // bool sec = false; // private key or not 0110 0111 if (type == QLatin1String("pub")) { 0112 key = true; 0113 primary = true; 0114 } else if (type == QLatin1String("sec")) { 0115 key = true; 0116 primary = true; 0117 // sec = true; 0118 } else if (type == QLatin1String("sub")) { 0119 key = true; 0120 } else if (type == QLatin1String("ssb")) { 0121 key = true; 0122 // sec = true; 0123 } 0124 0125 if (key) { 0126 if (primary) { 0127 keyList += GpgOp::Key(); 0128 0129 const QString &trust = f[1]; 0130 if (trust == QLatin1String("f") || trust == QLatin1String("u")) 0131 keyList.last().isTrusted = true; 0132 } 0133 0134 const int key_type = f[3].toInt(); 0135 const QString &caps = f[11]; 0136 0137 GpgOp::KeyItem item; 0138 item.bits = f[2].toInt(); 0139 if (key_type == 1) 0140 item.type = GpgOp::KeyItem::RSA; 0141 else if (key_type == 16) 0142 item.type = GpgOp::KeyItem::ElGamal; 0143 else if (key_type == 17) 0144 item.type = GpgOp::KeyItem::DSA; 0145 else 0146 item.type = GpgOp::KeyItem::Unknown; 0147 item.id = f[4]; 0148 item.creationDate = getTimestamp(f[5]); 0149 item.expirationDate = getTimestamp(f[6]); 0150 if (caps.contains(QLatin1Char('e'))) 0151 item.caps |= GpgOp::KeyItem::Encrypt; 0152 if (caps.contains(QLatin1Char('s'))) 0153 item.caps |= GpgOp::KeyItem::Sign; 0154 if (caps.contains(QLatin1Char('c'))) 0155 item.caps |= GpgOp::KeyItem::Certify; 0156 if (caps.contains(QLatin1Char('a'))) 0157 item.caps |= GpgOp::KeyItem::Auth; 0158 0159 keyList.last().keyItems += item; 0160 } else if (type == QLatin1String("uid")) { 0161 const QByteArray uid = getCString(f[9].toUtf8()); 0162 keyList.last().userIds.append(QString::fromUtf8(uid)); 0163 } else if (type == QLatin1String("fpr")) { 0164 const QString &s = f[9]; 0165 keyList.last().keyItems.last().fingerprint = s; 0166 } 0167 } 0168 0169 if (_keylist) 0170 *_keylist = keyList; 0171 if (_keyring) 0172 *_keyring = keyring; 0173 0174 return true; 0175 } 0176 0177 static bool findKeyringFilename(const QString &outstr, QString *_keyring) 0178 { 0179 const QStringList lines = outstr.split(QLatin1Char('\n')); 0180 if (lines.count() < 1) 0181 return false; 0182 0183 *_keyring = lines[0]; 0184 return true; 0185 } 0186 0187 GpgAction::GpgAction(QObject *parent) 0188 : QObject(parent) 0189 , proc(this) 0190 , dtextTimer(this) 0191 , utf8Output(false) 0192 { 0193 dtextTimer.setSingleShot(true); 0194 0195 connect(&proc, &GPGProc::error, this, &GpgAction::proc_error); 0196 connect(&proc, &GPGProc::finished, this, &GpgAction::proc_finished); 0197 connect(&proc, &GPGProc::readyReadStdout, this, &GpgAction::proc_readyReadStdout); 0198 connect(&proc, &GPGProc::readyReadStderr, this, &GpgAction::proc_readyReadStderr); 0199 connect(&proc, &GPGProc::readyReadStatusLines, this, &GpgAction::proc_readyReadStatusLines); 0200 connect(&proc, &GPGProc::bytesWrittenStdin, this, &GpgAction::proc_bytesWrittenStdin); 0201 connect(&proc, &GPGProc::bytesWrittenAux, this, &GpgAction::proc_bytesWrittenAux); 0202 connect(&proc, &GPGProc::bytesWrittenCommand, this, &GpgAction::proc_bytesWrittenCommand); 0203 connect(&proc, &GPGProc::debug, this, &GpgAction::proc_debug); 0204 connect(&dtextTimer, &QCA::SafeTimer::timeout, this, &GpgAction::t_dtext); 0205 0206 reset(); 0207 } 0208 0209 GpgAction::~GpgAction() 0210 { 0211 reset(); 0212 } 0213 0214 void GpgAction::reset() 0215 { 0216 collectOutput = true; 0217 allowInput = false; 0218 readConv.setup(LineConverter::Read); 0219 writeConv.setup(LineConverter::Write); 0220 readText = false; 0221 writeText = false; 0222 useAux = false; 0223 passphraseKeyId = QString(); 0224 signing = false; 0225 decryptGood = false; 0226 signGood = false; 0227 curError = GpgOp::ErrorUnknown; 0228 badPassphrase = false; 0229 need_submitPassphrase = false; 0230 need_cardOkay = false; 0231 diagnosticText = QString(); 0232 dtextTimer.stop(); 0233 0234 output = Output(); 0235 0236 proc.reset(); 0237 } 0238 0239 void GpgAction::start() 0240 { 0241 reset(); 0242 0243 QStringList args; 0244 bool extra = false; 0245 0246 if (input.opt_ascii) 0247 args += QStringLiteral("--armor"); 0248 0249 if (input.opt_noagent) 0250 args += QStringLiteral("--no-use-agent"); 0251 0252 if (input.opt_alwaystrust) 0253 args += QStringLiteral("--always-trust"); 0254 0255 if (!input.opt_pubfile.isEmpty() && !input.opt_secfile.isEmpty()) { 0256 args += QStringLiteral("--no-default-keyring"); 0257 args += QStringLiteral("--keyring"); 0258 args += input.opt_pubfile; 0259 args += QStringLiteral("--secret-keyring"); 0260 args += input.opt_secfile; 0261 } 0262 0263 switch (input.op) { 0264 case GpgOp::Check: 0265 { 0266 args += QStringLiteral("--version"); 0267 readText = true; 0268 break; 0269 } 0270 case GpgOp::SecretKeyringFile: 0271 { 0272 #ifndef Q_OS_WIN 0273 args += QStringLiteral("--display-charset=utf-8"); 0274 #endif 0275 args += QStringLiteral("--list-secret-keys"); 0276 readText = true; 0277 break; 0278 } 0279 case GpgOp::PublicKeyringFile: 0280 { 0281 #ifndef Q_OS_WIN 0282 args += QStringLiteral("--display-charset=utf-8"); 0283 #endif 0284 args += QStringLiteral("--list-public-keys"); 0285 readText = true; 0286 break; 0287 } 0288 case GpgOp::SecretKeys: 0289 { 0290 args += QStringLiteral("--fixed-list-mode"); 0291 args += QStringLiteral("--with-colons"); 0292 args += QStringLiteral("--with-fingerprint"); 0293 args += QStringLiteral("--with-fingerprint"); 0294 args += QStringLiteral("--list-secret-keys"); 0295 utf8Output = true; 0296 readText = true; 0297 break; 0298 } 0299 case GpgOp::PublicKeys: 0300 { 0301 args += QStringLiteral("--fixed-list-mode"); 0302 args += QStringLiteral("--with-colons"); 0303 args += QStringLiteral("--with-fingerprint"); 0304 args += QStringLiteral("--with-fingerprint"); 0305 args += QStringLiteral("--list-public-keys"); 0306 utf8Output = true; 0307 readText = true; 0308 break; 0309 } 0310 case GpgOp::Encrypt: 0311 { 0312 args += QStringLiteral("--encrypt"); 0313 0314 // recipients 0315 for (QStringList::ConstIterator it = input.recip_ids.constBegin(); it != input.recip_ids.constEnd(); ++it) { 0316 args += QStringLiteral("--recipient"); 0317 args += QStringLiteral("0x") + *it; 0318 } 0319 extra = true; 0320 collectOutput = false; 0321 allowInput = true; 0322 if (input.opt_ascii) 0323 readText = true; 0324 break; 0325 } 0326 case GpgOp::Decrypt: 0327 { 0328 args += QStringLiteral("--decrypt"); 0329 extra = true; 0330 collectOutput = false; 0331 allowInput = true; 0332 if (input.opt_ascii) 0333 writeText = true; 0334 break; 0335 } 0336 case GpgOp::Sign: 0337 { 0338 args += QStringLiteral("--default-key"); 0339 args += QStringLiteral("0x") + input.signer_id; 0340 args += QStringLiteral("--sign"); 0341 extra = true; 0342 collectOutput = false; 0343 allowInput = true; 0344 if (input.opt_ascii) 0345 readText = true; 0346 signing = true; 0347 break; 0348 } 0349 case GpgOp::SignAndEncrypt: 0350 { 0351 args += QStringLiteral("--default-key"); 0352 args += QStringLiteral("0x") + input.signer_id; 0353 args += QStringLiteral("--sign"); 0354 args += QStringLiteral("--encrypt"); 0355 0356 // recipients 0357 for (QStringList::ConstIterator it = input.recip_ids.constBegin(); it != input.recip_ids.constEnd(); ++it) { 0358 args += QStringLiteral("--recipient"); 0359 args += QStringLiteral("0x") + *it; 0360 } 0361 extra = true; 0362 collectOutput = false; 0363 allowInput = true; 0364 if (input.opt_ascii) 0365 readText = true; 0366 signing = true; 0367 break; 0368 } 0369 case GpgOp::SignClearsign: 0370 { 0371 args += QStringLiteral("--default-key"); 0372 args += QStringLiteral("0x") + input.signer_id; 0373 args += QStringLiteral("--clearsign"); 0374 extra = true; 0375 collectOutput = false; 0376 allowInput = true; 0377 if (input.opt_ascii) 0378 readText = true; 0379 signing = true; 0380 break; 0381 } 0382 case GpgOp::SignDetached: 0383 { 0384 args += QStringLiteral("--default-key"); 0385 args += QStringLiteral("0x") + input.signer_id; 0386 args += QStringLiteral("--detach-sign"); 0387 extra = true; 0388 collectOutput = false; 0389 allowInput = true; 0390 if (input.opt_ascii) 0391 readText = true; 0392 signing = true; 0393 break; 0394 } 0395 case GpgOp::Verify: 0396 { 0397 args += QStringLiteral("--verify"); 0398 args += QStringLiteral("-"); // krazy:exclude=doublequote_chars 0399 extra = true; 0400 allowInput = true; 0401 if (input.opt_ascii) 0402 writeText = true; 0403 break; 0404 } 0405 case GpgOp::VerifyDetached: 0406 { 0407 args += QStringLiteral("--verify"); 0408 args += QStringLiteral("-"); // krazy:exclude=doublequote_chars 0409 args += QStringLiteral("-&?"); 0410 extra = true; 0411 allowInput = true; 0412 useAux = true; 0413 break; 0414 } 0415 case GpgOp::Import: 0416 { 0417 args += QStringLiteral("--import"); 0418 readText = true; 0419 if (input.opt_ascii) 0420 writeText = true; 0421 break; 0422 } 0423 case GpgOp::Export: 0424 { 0425 args += QStringLiteral("--export"); 0426 args += QStringLiteral("0x") + input.export_key_id; 0427 collectOutput = false; 0428 if (input.opt_ascii) 0429 readText = true; 0430 break; 0431 } 0432 case GpgOp::DeleteKey: 0433 { 0434 args += QStringLiteral("--batch"); 0435 args += QStringLiteral("--delete-key"); 0436 args += QStringLiteral("0x") + input.delete_key_fingerprint; 0437 break; 0438 } 0439 } 0440 0441 #ifdef GPG_PROFILE 0442 timer.start(); 0443 printf("<< launch >>\n"); 0444 #endif 0445 proc.start(input.bin, args, extra ? GPGProc::ExtendedMode : GPGProc::NormalMode); 0446 0447 // detached sig 0448 if (input.op == GpgOp::VerifyDetached) { 0449 QByteArray a = input.sig; 0450 if (input.opt_ascii) { 0451 LineConverter conv; 0452 conv.setup(LineConverter::Write); 0453 a = conv.process(a); 0454 } 0455 proc.writeStdin(a); 0456 proc.closeStdin(); 0457 } 0458 0459 // import 0460 if (input.op == GpgOp::Import) { 0461 QByteArray a = input.inkey; 0462 if (writeText) { 0463 LineConverter conv; 0464 conv.setup(LineConverter::Write); 0465 a = conv.process(a); 0466 } 0467 proc.writeStdin(a); 0468 proc.closeStdin(); 0469 } 0470 } 0471 0472 #ifdef QPIPE_SECURE 0473 void GpgAction::submitPassphrase(const QCA::SecureArray &a) 0474 #else 0475 void GpgAction::submitPassphrase(const QByteArray &a) 0476 #endif 0477 { 0478 if (!need_submitPassphrase) 0479 return; 0480 0481 need_submitPassphrase = false; 0482 0483 #ifdef QPIPE_SECURE 0484 QCA::SecureArray b; 0485 #else 0486 QByteArray b; 0487 #endif 0488 // filter out newlines, since that's the delimiter used 0489 // to indicate a submitted passphrase 0490 b.resize(a.size()); 0491 int at = 0; 0492 for (int n = 0; n < a.size(); ++n) { 0493 if (a[n] != '\n') 0494 b[at++] = a[n]; 0495 } 0496 b.resize(at); 0497 0498 // append newline 0499 b.resize(b.size() + 1); 0500 b[b.size() - 1] = '\n'; 0501 proc.writeCommand(b); 0502 } 0503 0504 QByteArray GpgAction::read() 0505 { 0506 if (collectOutput) 0507 return QByteArray(); 0508 0509 QByteArray a = proc.readStdout(); 0510 if (readText) 0511 a = readConv.update(a); 0512 if (!proc.isActive()) 0513 a += readConv.final(); 0514 return a; 0515 } 0516 0517 void GpgAction::write(const QByteArray &in) 0518 { 0519 if (!allowInput) 0520 return; 0521 0522 QByteArray a = in; 0523 if (writeText) 0524 a = writeConv.update(in); 0525 0526 if (useAux) 0527 proc.writeAux(a); 0528 else 0529 proc.writeStdin(a); 0530 } 0531 0532 void GpgAction::endWrite() 0533 { 0534 if (!allowInput) 0535 return; 0536 0537 if (useAux) 0538 proc.closeAux(); 0539 else 0540 proc.closeStdin(); 0541 } 0542 0543 void GpgAction::cardOkay() 0544 { 0545 if (need_cardOkay) { 0546 need_cardOkay = false; 0547 submitCommand("\n"); 0548 } 0549 } 0550 0551 QString GpgAction::readDiagnosticText() 0552 { 0553 QString s = diagnosticText; 0554 diagnosticText = QString(); 0555 return s; 0556 } 0557 0558 void GpgAction::submitCommand(const QByteArray &a) 0559 { 0560 proc.writeCommand(a); 0561 } 0562 0563 // since str is taken as a value, it is ok to use the same variable for 'rest' 0564 QString GpgAction::nextArg(QString str, QString *rest) 0565 { 0566 int n = str.indexOf(QLatin1Char(' ')); 0567 if (n == -1) { 0568 if (rest) 0569 *rest = QString(); 0570 return str; 0571 } else { 0572 if (rest) 0573 *rest = str.mid(n + 1); 0574 return str.mid(0, n); 0575 } 0576 } 0577 0578 void GpgAction::processStatusLine(const QString &line) 0579 { 0580 appendDiagnosticText(QStringLiteral("{") + line + QStringLiteral("}")); 0581 ensureDTextEmit(); 0582 0583 if (!proc.isActive()) 0584 return; 0585 0586 QString s, rest; 0587 s = nextArg(line, &rest); 0588 0589 if (s == QLatin1String("NODATA")) { 0590 // only set this if it'll make it better 0591 if (curError == GpgOp::ErrorUnknown) 0592 curError = GpgOp::ErrorFormat; 0593 } else if (s == QLatin1String("UNEXPECTED")) { 0594 if (curError == GpgOp::ErrorUnknown) 0595 curError = GpgOp::ErrorFormat; 0596 } else if (s == QLatin1String("EXPKEYSIG")) { 0597 curError = GpgOp::ErrorSignerExpired; 0598 } else if (s == QLatin1String("REVKEYSIG")) { 0599 curError = GpgOp::ErrorSignerRevoked; 0600 } else if (s == QLatin1String("EXPSIG")) { 0601 curError = GpgOp::ErrorSignatureExpired; 0602 } else if (s == QLatin1String("INV_RECP")) { 0603 const int r = nextArg(rest).toInt(); 0604 0605 if (curError == GpgOp::ErrorUnknown) { 0606 if (r == 10) 0607 curError = GpgOp::ErrorEncryptUntrusted; 0608 else if (r == 4) 0609 curError = GpgOp::ErrorEncryptRevoked; 0610 else if (r == 5) 0611 curError = GpgOp::ErrorEncryptExpired; 0612 else 0613 // due to GnuPG bug #1650 0614 // <https://bugs.g10code.com/gnupg/issue1650> 0615 // encrypting to expired and revoked keys will 0616 // not specify any reason for failing, 0617 // defaulting to this 0618 curError = GpgOp::ErrorEncryptInvalid; 0619 } 0620 } else if (s == QLatin1String("NO_SECKEY")) { 0621 output.encryptedToId = nextArg(rest); 0622 0623 if (curError == GpgOp::ErrorUnknown) 0624 curError = GpgOp::ErrorDecryptNoKey; 0625 } else if (s == QLatin1String("DECRYPTION_OKAY")) { 0626 decryptGood = true; 0627 0628 // message could be encrypted with several keys 0629 if (curError == GpgOp::ErrorDecryptNoKey) 0630 curError = GpgOp::ErrorUnknown; 0631 } else if (s == QLatin1String("SIG_CREATED")) { 0632 signGood = true; 0633 } else if (s == QLatin1String("USERID_HINT")) { 0634 passphraseKeyId = nextArg(rest); 0635 } else if (s == QLatin1String("GET_HIDDEN")) { 0636 QString arg = nextArg(rest); 0637 if (arg == QLatin1String("passphrase.enter") || arg == QLatin1String("passphrase.pin.ask")) { 0638 need_submitPassphrase = true; 0639 0640 // for signal-safety, emit later 0641 QMetaObject::invokeMethod(this, "needPassphrase", Qt::QueuedConnection, Q_ARG(QString, passphraseKeyId)); 0642 } 0643 } else if (s == QLatin1String("GET_LINE")) { 0644 QString arg = nextArg(rest); 0645 if (arg == QLatin1String("cardctrl.insert_card.okay")) { 0646 need_cardOkay = true; 0647 0648 QMetaObject::invokeMethod(this, "needCard", Qt::QueuedConnection); 0649 } 0650 } else if (s == QLatin1String("GET_BOOL")) { 0651 QString arg = nextArg(rest); 0652 if (arg == QLatin1String("untrusted_key.override")) 0653 submitCommand("no\n"); 0654 } else if (s == QLatin1String("GOOD_PASSPHRASE")) { 0655 badPassphrase = false; 0656 } else if (s == QLatin1String("BAD_PASSPHRASE")) { 0657 badPassphrase = true; 0658 } else if (s == QLatin1String("GOODSIG")) { 0659 output.wasSigned = true; 0660 output.signerId = nextArg(rest); 0661 output.verifyResult = GpgOp::VerifyGood; 0662 } else if (s == QLatin1String("BADSIG")) { 0663 output.wasSigned = true; 0664 output.signerId = nextArg(rest); 0665 output.verifyResult = GpgOp::VerifyBad; 0666 } else if (s == QLatin1String("ERRSIG")) { 0667 output.wasSigned = true; 0668 const QStringList list = rest.split(QLatin1Char(' '), Qt::SkipEmptyParts); 0669 output.signerId = list[0]; 0670 output.timestamp = getTimestamp(list[4]); 0671 output.verifyResult = GpgOp::VerifyNoKey; 0672 } else if (s == QLatin1String("VALIDSIG")) { 0673 const QStringList list = rest.split(QLatin1Char(' '), Qt::SkipEmptyParts); 0674 output.timestamp = getTimestamp(list[2]); 0675 } 0676 } 0677 0678 void GpgAction::processResult(int code) 0679 { 0680 #ifdef GPG_PROFILE 0681 printf("<< launch: %d >>\n", timer.elapsed()); 0682 #endif 0683 0684 // put stdout and stderr into QStrings 0685 0686 QString outstr; 0687 QString errstr; 0688 0689 #ifdef Q_OS_WIN 0690 if (!utf8Output) { 0691 outstr = QString::fromLocal8Bit(buf_stdout); 0692 errstr = QString::fromLocal8Bit(buf_stderr); 0693 } else { 0694 #endif 0695 outstr = QString::fromUtf8(buf_stdout); 0696 errstr = QString::fromUtf8(buf_stderr); 0697 #ifdef Q_OS_WIN 0698 } 0699 #endif 0700 0701 if (collectOutput) 0702 appendDiagnosticText(QStringLiteral("stdout: [%1]").arg(outstr)); 0703 appendDiagnosticText(QStringLiteral("stderr: [%1]").arg(errstr)); 0704 ensureDTextEmit(); 0705 0706 if (badPassphrase) { 0707 output.errorCode = GpgOp::ErrorPassphrase; 0708 } else if (curError != GpgOp::ErrorUnknown) { 0709 output.errorCode = curError; 0710 } else if (code == 0) { 0711 if (input.op == GpgOp::Check) { 0712 const QStringList strList = outstr.split(QStringLiteral("\n")); 0713 foreach (const QString &str, strList) { 0714 if (!str.startsWith(QLatin1String("Home: "))) 0715 continue; 0716 0717 output.homeDir = str.section(QLatin1Char(' '), 1); 0718 break; 0719 } 0720 output.success = true; 0721 } else if (input.op == GpgOp::SecretKeyringFile || input.op == GpgOp::PublicKeyringFile) { 0722 if (findKeyringFilename(outstr, &output.keyringFile)) 0723 output.success = true; 0724 } else if (input.op == GpgOp::SecretKeys || input.op == GpgOp::PublicKeys) { 0725 if (stringToKeyList(outstr, &output.keys, &output.keyringFile)) 0726 output.success = true; 0727 } else 0728 output.success = true; 0729 } else { 0730 // decrypt and sign success based on status only. 0731 // this is mainly because gpg uses fatal return 0732 // values if there is trouble with gpg-agent, even 0733 // though the operation otherwise works. 0734 0735 if (input.op == GpgOp::Decrypt && decryptGood) 0736 output.success = true; 0737 if (signing && signGood) 0738 output.success = true; 0739 0740 // gpg will indicate failure for bad sigs, but we don't 0741 // consider this to be operation failure. 0742 0743 bool signedMakesItGood = false; 0744 if (input.op == GpgOp::Verify || input.op == GpgOp::VerifyDetached) 0745 signedMakesItGood = true; 0746 0747 if (signedMakesItGood && output.wasSigned) 0748 output.success = true; 0749 } 0750 0751 emit finished(); 0752 } 0753 0754 void GpgAction::ensureDTextEmit() 0755 { 0756 if (!dtextTimer.isActive()) 0757 dtextTimer.start(); 0758 } 0759 0760 void GpgAction::t_dtext() 0761 { 0762 emit readyReadDiagnosticText(); 0763 } 0764 0765 void GpgAction::proc_error(gpgQCAPlugin::GPGProc::Error e) 0766 { 0767 QString str; 0768 if (e == GPGProc::FailedToStart) 0769 str = QStringLiteral("FailedToStart"); 0770 else if (e == GPGProc::UnexpectedExit) 0771 str = QStringLiteral("UnexpectedExit"); 0772 else if (e == GPGProc::ErrorWrite) 0773 str = QStringLiteral("ErrorWrite"); 0774 0775 appendDiagnosticText(QStringLiteral("GPG Process Error: %1").arg(str)); 0776 ensureDTextEmit(); 0777 0778 output.errorCode = GpgOp::ErrorProcess; 0779 emit finished(); 0780 } 0781 0782 void GpgAction::proc_finished(int exitCode) 0783 { 0784 appendDiagnosticText(QStringLiteral("GPG Process Finished: exitStatus=%1").arg(exitCode)); 0785 ensureDTextEmit(); 0786 0787 processResult(exitCode); 0788 } 0789 0790 void GpgAction::proc_readyReadStdout() 0791 { 0792 if (collectOutput) { 0793 QByteArray a = proc.readStdout(); 0794 if (readText) 0795 a = readConv.update(a); 0796 buf_stdout.append(a); 0797 } else 0798 emit readyRead(); 0799 } 0800 0801 void GpgAction::proc_readyReadStderr() 0802 { 0803 buf_stderr.append(proc.readStderr()); 0804 } 0805 0806 void GpgAction::proc_readyReadStatusLines() 0807 { 0808 const QStringList lines = proc.readStatusLines(); 0809 for (int n = 0; n < lines.count(); ++n) 0810 processStatusLine(lines[n]); 0811 } 0812 0813 void GpgAction::proc_bytesWrittenStdin(int bytes) 0814 { 0815 if (!useAux) { 0816 int actual = writeConv.writtenToActual(bytes); 0817 emit bytesWritten(actual); 0818 } 0819 } 0820 0821 void GpgAction::proc_bytesWrittenAux(int bytes) 0822 { 0823 if (useAux) { 0824 int actual = writeConv.writtenToActual(bytes); 0825 emit bytesWritten(actual); 0826 } 0827 } 0828 0829 void GpgAction::proc_bytesWrittenCommand(int) 0830 { 0831 // don't care about this 0832 } 0833 0834 void GpgAction::proc_debug(const QString &str) 0835 { 0836 appendDiagnosticText(QStringLiteral("GPGProc: ") + str); 0837 ensureDTextEmit(); 0838 } 0839 0840 void GpgAction::appendDiagnosticText(const QString &line) 0841 { 0842 #ifdef GPGOP_DEBUG 0843 printf("%s\n", qPrintable(line)); 0844 #endif 0845 diagnosticText += line; 0846 } 0847 0848 } // end namespace gpgQCAPlugin