3
#include<qstringlist.h>
7
#include"gpgproc/gpgproc.h"
9
static QByteArray stringToArray(const QString &str)
11
QCString cs = str.utf8();
12
QByteArray a(cs.length());
13
memcpy(a.data(), cs.data(), a.size());
27
QByteArray outbuf, errbuf;
33
OpenPGP::KeyList keys;
41
GpgOp::GpgOp(const QString &bin, QObject *parent)
60
d->proc->disconnect(this);
61
d->proc->deleteLater();
66
d->sigTS = QDateTime();
67
d->didPassphrase = false;
72
d->verType = OpenPGP::VerifyError;
83
bool GpgOp::isActive() const
85
return (d->proc ? true: false);
93
const OpenPGP::KeyList & GpgOp::keys() const
98
const QString & GpgOp::keyringFile() const
103
const QString & GpgOp::keyID() const
108
const QDateTime & GpgOp::timestamp() const
113
int GpgOp::verifyResult() const
118
bool GpgOp::badPassphrase() const
123
const QString & GpgOp::encrypted() const
128
const QByteArray & GpgOp::decrypted() const
133
const QString & GpgOp::signature() const
138
void GpgOp::setTryAgent(bool b)
143
void GpgOp::doCheck()
150
if(!launchGPG(args, false)) {
151
QTimer::singleShot(0, this, SLOT(doFail()));
156
void GpgOp::doSecretKeyringFile()
160
d->op = SecretKeyringFile;
162
args += "--list-secret-keys";
163
if(!launchGPG(args, false)) {
164
QTimer::singleShot(0, this, SLOT(doFail()));
169
void GpgOp::doPublicKeyringFile()
173
d->op = PublicKeyringFile;
175
args += "--list-public-keys";
176
if(!launchGPG(args, false)) {
177
QTimer::singleShot(0, this, SLOT(doFail()));
182
void GpgOp::doSecretKeys()
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()));
197
void GpgOp::doPublicKeys()
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()));
212
void GpgOp::doEncrypt(const QByteArray &in, const QStringList &keys)
219
args += "--always-trust";
223
for(QStringList::ConstIterator it = keys.begin(); it != keys.end(); ++it) {
224
args += "--recipient";
225
args += QString("0x") + *it;
228
if(!launchGPG(args)) {
229
QTimer::singleShot(0, this, SLOT(doFail()));
234
d->proc->writeToStdin(in);
236
d->proc->closeStdin();
239
void GpgOp::doDecrypt(const QString &in)
246
args += "--no-use-agent";
249
if(!launchGPG(args)) {
250
QTimer::singleShot(0, this, SLOT(doFail()));
255
d->proc->writeToStdin(stringToArray(fixOutgoingLines(in)));
257
d->proc->closeStdin();
260
void GpgOp::doSign(const QByteArray &in, const QString &keyID)
267
args += "--no-use-agent";
269
args += "--default-key";
270
args += QString("0x") + keyID;
271
args += "--detach-sign";
272
if(!launchGPG(args)) {
273
QTimer::singleShot(0, this, SLOT(doFail()));
278
d->proc->writeToStdin(in);
280
d->proc->closeStdin();
283
void GpgOp::doVerify(const QByteArray &in, const QString &sig)
288
d->verType = OpenPGP::VerifyError;
295
if(!launchGPG(args)) {
296
QTimer::singleShot(0, this, SLOT(doFail()));
300
// sig goes into stdin
302
d->proc->writeToStdin(stringToArray(fixOutgoingLines(sig)));
304
d->proc->closeStdin();
306
// data goes into aux
307
d->proc->writeToAux(in);
311
void GpgOp::submitPassphrase(const QString &pp)
313
QCString cs = pp.local8Bit() + '\n';
314
QByteArray a(cs.length());
315
memcpy(a.data(), cs.data(), a.size());
316
d->proc->writeToCommand(a);
324
bool GpgOp::launchGPG(const QStringList &args, bool useExtra)
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 &)));
333
if(!d->proc->start(d->bin, args, useExtra)) {
334
d->proc->disconnect(this);
335
d->proc->deleteLater();
343
void GpgOp::proc_readyReadStdout()
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());
351
void GpgOp::proc_readyReadStderr()
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());
359
void GpgOp::proc_wroteToStdin()
361
d->proc->closeStdin();
364
void GpgOp::proc_statusLine(const QString &str)
367
printf("{%s}\n", str.latin1());
370
int n = str.find(' ');
380
if(s == "NEED_PASSPHRASE") {
381
if(!(d->tryAgent && getenv("GPG_AGENT_INFO"))) {
382
if(!d->didPassphrase) {
383
d->didPassphrase = true;
389
d->proc->writeToCommand(a);
393
else if(s == "BAD_PASSPHRASE") {
396
else if(s == "GOOD_PASSPHRASE") {
399
else if(s == "GOODSIG") {
401
int n = rest.find(' ');
405
keyID = rest.mid(0, n);
407
d->verType = OpenPGP::VerifyGood;
409
else if(s == "BADSIG") {
411
int n = rest.find(' ');
415
keyID = rest.mid(0, n);
417
d->verType = OpenPGP::VerifyBad;
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;
425
else if(s == "VALIDSIG") {
426
QStringList list = QStringList::split(' ', rest, false);
427
d->sigTS.setTime_t(list[2].toInt());
431
void GpgOp::proc_processExited()
437
printf("GPG Finished: ");
442
if(!d->proc->normalExit()) {
445
printf("bad exit.. crash?\n");
449
exitStatus = d->proc->exitStatus();
451
printf("exitStatus=%d\n", exitStatus);
455
d->proc->disconnect(this);
456
d->proc->deleteLater();
459
processResult(clean, exitStatus, d->outbuf, d->errbuf);
462
void GpgOp::processResult(bool clean, int code, const QByteArray &out, const QByteArray &err)
464
// put stdout and stderr into QStrings
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);
474
printf("stdout: [%s]\n", outstr.latin1());
475
printf("stderr: [%s]\n", errstr.latin1());
479
if(!clean || code != 0) {
485
else if(d->op == SecretKeyringFile || d->op == PublicKeyringFile) {
486
if(!clean || code != 0) {
490
if(!findKeyringFilename(fixIncomingLines(outstr), &d->keyring)) {
496
else if(d->op == SecretKeys || d->op == PublicKeys) {
497
if(!clean || code != 0) {
501
if(!stringToKeyList(fixIncomingLines(outstr), &d->keys, &d->keyring)) {
507
else if(d->op == Encrypt) {
508
if(!clean || code != 0) {
512
d->enc = fixIncomingLines(outstr);
515
else if(d->op == Decrypt) {
516
if(!clean || code != 0) {
523
else if(d->op == Sign) {
524
if(!clean || code != 0) {
528
d->enc = fixIncomingLines(outstr);
531
else if(d->op == Verify) {
532
if(!clean || code != 0) {
540
QString GpgOp::fixIncomingLines(const QString &str)
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') {
558
QString GpgOp::fixOutgoingLines(const QString &str)
562
for(int n = 0; n < (int)str.length(); ++n) {
563
if(str.at(n) == '\n' && (n == 0 || str.at(n-1) != '\r'))
574
bool GpgOp::stringToKeyList(const QString &outstr, OpenPGP::KeyList *_keylist, QString *_keyring)
576
OpenPGP::KeyList keyList;
577
QStringList lines = QStringList::split('\n', outstr, true);
579
if(lines.count() < 1)
582
QStringList::ConstIterator it = lines.begin();
584
// first line is keyring file
585
QString keyring = *(it++);
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...
593
// ...so read the first line again
597
// this was the divider line - skip it
602
for(; it != lines.end(); ++it) {
603
QStringList f = QStringList::split(':', *it, true);
612
k = new OpenPGP::Key;
616
else if(type == "sec") {
622
k = new OpenPGP::Key;
626
else if(type == "uid") {
629
// ignore a uid if we already have one
630
if(!k->userID().isEmpty())
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()) {
638
unsigned char c = (unsigned char)s.at(n).latin1();
641
else if(c == 'x' && n + 2 < (int)s.length()) {
643
QString hex = s.mid(n, 2);
645
uint val = hex.toInt(&ok, 16);
646
uid += (unsigned char)val;
647
++n; // only skip one, the for-loop will skip the next
651
uid += (unsigned char)s.at(n).latin1();
654
k->setUserID(QString::fromUtf8(uid));
671
bool GpgOp::findKeyringFilename(const QString &outstr, QString *_keyring)
673
QStringList lines = QStringList::split('\n', outstr, true);
674
if(lines.count() < 1)
677
*_keyring = lines[0];