kde-extraapps/kgpg/kgpginterface.cpp
2015-02-27 11:02:43 +00:00

417 lines
11 KiB
C++

/*
* Copyright (C) 2002 Jean-Baptiste Mardelle <bj@altern.org>
* Copyright (C) 2007,2008,2009,2010,2011,2012,2013
* Rolf Eike Beer <kde@opensource.sf-tec.de>
*/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "kgpginterface.h"
#include "gpgproc.h"
#include "core/convert.h"
#include "core/KGpgKeyNode.h"
#include "core/KGpgSignNode.h"
#include "core/KGpgSubkeyNode.h"
#include "core/KGpgUatNode.h"
#include "core/KGpgUidNode.h"
#include <gpgme.h>
#include <KConfig>
#include <KDebug>
#include <KGlobal>
#include <KLocale>
#include <KMessageBox>
#include <KProcess>
#include <QFile>
#include <QString>
#include <QTextStream>
using namespace KgpgCore;
QString KgpgInterface::getGpgSetting(const QString &name, const QString &configfile)
{
const QString tmp(name.simplified() + QLatin1Char( ' ' ));
QFile qfile(configfile);
if (qfile.open(QIODevice::ReadOnly) && (qfile.exists())) {
QTextStream t(&qfile);
while (!t.atEnd()) {
QString result(t.readLine().simplified());
if (result.startsWith(tmp)) {
result = result.mid(tmp.length()).simplified();
return result.section(QLatin1Char( ' ' ), 0, 0);
}
}
qfile.close();
}
return QString();
}
void KgpgInterface::setGpgSetting(const QString &name, const QString &value, const QString &url)
{
QFile qfile(url);
if (qfile.open(QIODevice::ReadOnly) && (qfile.exists())) {
const QString temp(name + QLatin1Char( ' ' ));
QString texttowrite;
bool found = false;
QTextStream t(&qfile);
while (!t.atEnd()) {
QString result = t.readLine();
if (result.simplified().startsWith(temp)) {
if (!value.isEmpty())
result = temp + QLatin1Char( ' ' ) + value;
else
result.clear();
found = true;
}
texttowrite += result + QLatin1Char( '\n' );
}
qfile.close();
if ((!found) && (!value.isEmpty()))
texttowrite += QLatin1Char( '\n' ) + temp + QLatin1Char( ' ' ) + value;
if (qfile.open(QIODevice::WriteOnly)) {
QTextStream t(&qfile);
t << texttowrite;
qfile.close();
}
}
}
bool KgpgInterface::getGpgBoolSetting(const QString &name, const QString &configfile)
{
QFile qfile(configfile);
if (qfile.open(QIODevice::ReadOnly) && (qfile.exists())) {
QTextStream t(&qfile);
while (!t.atEnd()) {
if (t.readLine().simplified().startsWith(name))
return true;
}
qfile.close();
}
return false;
}
void KgpgInterface::setGpgBoolSetting(const QString &name, const bool enable, const QString &url)
{
QFile qfile(url);
if (qfile.open(QIODevice::ReadOnly) && (qfile.exists())) {
QString texttowrite;
bool found = false;
QTextStream t(&qfile);
while (!t.atEnd()) {
QString result(t.readLine());
if (result.simplified().startsWith(name)) {
if (enable)
result = name;
else
result.clear();
found = true;
}
texttowrite += result + QLatin1Char( '\n' );
}
qfile.close();
if ((!found) && (enable))
texttowrite += name;
if (qfile.open(QIODevice::WriteOnly)) {
QTextStream t(&qfile);
t << texttowrite;
qfile.close();
}
}
}
/**
* @param p the process that reads the GnuPG data
* @param readNode the node where the signatures are read for
*/
static KgpgCore::KgpgKeyList
readPublicKeysProcess(GPGProc &p, KGpgKeyNode *readNode)
{
QStringList lsp;
int items;
KgpgCore::KgpgKeyList publiclistkeys;
KgpgCore::KgpgKey *publickey = NULL;
unsigned int idIndex = 0;
QString log;
KGpgSignableNode *currentSNode = NULL; ///< the current (sub)node signatures are read for
while ((items = p.readln(lsp)) >= 0) {
if ((lsp.at(0) == QLatin1String( "pub" )) && (items >= 10)) {
KgpgSubKeyType subtype;
KgpgSubKeyType keytype;
bool enabled = true;
if (items > 11) {
const QString &caps = lsp.at(11);
enabled = !caps.contains(QLatin1Char('D'), Qt::CaseSensitive);
subtype = Convert::toSubType(caps, false);
keytype = Convert::toSubType(caps, true);
}
publiclistkeys << KgpgKey(lsp.at(4), lsp.at(2).toUInt(), Convert::toTrust(lsp.at(1)),
Convert::toAlgo(lsp.at(3).toInt()), subtype, keytype,
QDateTime::fromTime_t(lsp.at(5).toUInt()));
publickey = &publiclistkeys.last();
const QString &owTrust = lsp.at(8);
if (owTrust.isEmpty())
publickey->setOwnerTrust(GPGME_VALIDITY_UNDEFINED);
else
publickey->setOwnerTrust(Convert::toOwnerTrust(owTrust[0]));
const QString &endDate = lsp.at(6);
if (endDate.isEmpty())
publickey->setExpiration(QDateTime());
else
publickey->setExpiration(QDateTime::fromTime_t(endDate.toUInt()));
publickey->setValid(enabled); // disabled key
idIndex = 0;
} else if (publickey && (lsp.at(0) == QLatin1String( "fpr" )) && (items >= 10)) {
const QString fingervalue(lsp.at(9));
publickey->setFingerprint(fingervalue);
} else if (publickey && (lsp.at(0) == QLatin1String( "sub" )) && (items >= 7)) {
KgpgSubKeyType subtype;
if (items > 11)
subtype = Convert::toSubType(lsp.at(11), false);
KgpgKeySub sub(lsp.at(4), lsp.at(2).toUInt(), Convert::toTrust(lsp.at(1)),
Convert::toAlgo(lsp.at(3).toInt()), subtype, QDateTime::fromTime_t(lsp.at(5).toUInt()));
// FIXME: Please see kgpgkey.h, KgpgSubKey class
if (items <= 11)
sub.setValid(true);
else
sub.setValid(!lsp.at(11).contains(QLatin1Char( 'D' )));
if (lsp.at(6).isEmpty())
sub.setExpiration(QDateTime());
else
sub.setExpiration(QDateTime::fromTime_t(lsp.at(6).toUInt()));
publickey->subList()->append(sub);
if (readNode == NULL)
currentSNode = NULL;
else
currentSNode = new KGpgSubkeyNode(readNode, sub);
} else if (publickey && (lsp.at(0) == QLatin1String( "uat" ))) {
idIndex++;
if (readNode != NULL) {
currentSNode = new KGpgUatNode(readNode, idIndex, lsp);
}
} else if (publickey && (lsp.at(0) == QLatin1String( "uid" )) && (items >= 10)) {
if (idIndex == 0) {
QString fullname(lsp.at(9));
QString kmail;
if (fullname.contains(QLatin1Char( '<' )) ) {
kmail = fullname;
if (fullname.contains(QLatin1Char( ')' )) )
kmail = kmail.section(QLatin1Char( ')' ), 1);
kmail = kmail.section(QLatin1Char( '<' ), 1);
kmail.truncate(kmail.length() - 1);
if (kmail.contains(QLatin1Char( '<' ))) {
// several email addresses in the same key
kmail = kmail.replace(QLatin1Char( '>' ), QLatin1Char( ';' ));
kmail.remove(QLatin1Char( '<' ));
}
}
QString kname(fullname.section( QLatin1String( " <" ), 0, 0));
QString comment;
if (fullname.contains(QLatin1Char( '(' )) ) {
kname = kname.section( QLatin1String( " (" ), 0, 0);
comment = fullname.section(QLatin1Char( '(' ), 1, 1);
comment = comment.section(QLatin1Char( ')' ), 0, 0);
}
idIndex++;
publickey->setEmail(kmail);
publickey->setComment(comment);
publickey->setName(kname);
currentSNode = readNode;
} else {
idIndex++;
if (readNode != NULL) {
currentSNode = new KGpgUidNode(readNode, idIndex, lsp);
}
}
} else if (publickey && ((lsp.at(0) == QLatin1String( "sig" )) || (lsp.at(0) == QLatin1String( "rev" ))) && (items >= 11)) {
// there are no strings here that could have a recoded QLatin1Char( ':' ) in them
const QString signature = lsp.join(QLatin1String(":"));
if (currentSNode != NULL)
(void) new KGpgSignNode(currentSNode, lsp);
} else {
log += lsp.join(QString(QLatin1Char( ':' ))) + QLatin1Char( '\n' );
}
}
if (p.exitCode() != 0) {
KMessageBox::detailedError(NULL, i18n("An error occurred while scanning your keyring"), log);
log.clear();
}
return publiclistkeys;
}
KgpgKeyList KgpgInterface::readPublicKeys(const QStringList &ids)
{
GPGProc process;
process <<
QLatin1String("--with-colons") <<
QLatin1String("--with-fingerprint") <<
QLatin1String("--fixed-list-mode") <<
QLatin1String("--list-keys") <<
ids;
process.setOutputChannelMode(KProcess::MergedChannels);
process.start();
process.waitForFinished(-1);
return readPublicKeysProcess(process, NULL);
}
void KgpgInterface::readSignatures(KGpgKeyNode *node)
{
GPGProc process;
process <<
QLatin1String("--with-colons") <<
QLatin1String("--with-fingerprint") <<
QLatin1String("--fixed-list-mode") <<
QLatin1String("--list-sigs") <<
node->getId();
process.setOutputChannelMode(KProcess::MergedChannels);
process.start();
process.waitForFinished(-1);
readPublicKeysProcess(process, node);
}
static KgpgCore::KgpgKeyList
readSecretKeysProcess(GPGProc &p)
{
QStringList lsp;
int items;
bool hasuid = false;
KgpgCore::KgpgKeyList result;
KgpgCore::KgpgKey *secretkey = NULL;
while ( (items = p.readln(lsp)) >= 0 ) {
if ((lsp.at(0) == QLatin1String( "sec" )) && (items >= 10)) {
KgpgSubKeyType subtype;
KgpgSubKeyType keytype;
if (items >= 11) {
const QString &caps = lsp.at(11);
subtype = Convert::toSubType(caps, false);
keytype = Convert::toSubType(caps, true);
}
result << KgpgKey(lsp.at(4), lsp.at(2).toUInt(), Convert::toTrust(lsp.at(1)),
Convert::toAlgo(lsp.at(3).toInt()), subtype, keytype,
QDateTime::fromTime_t(lsp.at(5).toUInt()));
secretkey = &result.last();
secretkey->setSecret(true);
if (lsp.at(6).isEmpty())
secretkey->setExpiration(QDateTime());
else
secretkey->setExpiration(QDateTime::fromTime_t(lsp.at(6).toUInt()));
hasuid = true;
} else if ((lsp.at(0) == QLatin1String( "uid" )) && (items >= 10)) {
if (hasuid)
continue;
hasuid = true;
const QString fullname(lsp.at(9));
if (fullname.contains(QLatin1Char( '<' ) )) {
QString kmail(fullname);
if (fullname.contains(QLatin1Char( ')' ) ))
kmail = kmail.section(QLatin1Char( ')' ), 1);
kmail = kmail.section(QLatin1Char( '<' ), 1);
kmail.truncate(kmail.length() - 1);
if (kmail.contains(QLatin1Char( '<' ) )) { // several email addresses in the same key
kmail = kmail.replace(QLatin1Char( '>' ), QLatin1Char( ';' ));
kmail.remove(QLatin1Char( '<' ));
}
secretkey->setEmail(kmail);
} else {
secretkey->setEmail(QString());
}
QString kname(fullname.section( QLatin1String( " <" ), 0, 0));
if (fullname.contains(QLatin1Char( '(' ) )) {
kname = kname.section( QLatin1String( " (" ), 0, 0);
QString comment = fullname.section(QLatin1Char( '(' ), 1, 1);
comment = comment.section(QLatin1Char( ')' ), 0, 0);
secretkey->setComment(comment);
} else {
secretkey->setComment(QString());
}
secretkey->setName(kname);
} else if ((lsp.at(0) == QLatin1String( "fpr" )) && (items >= 10)) {
secretkey->setFingerprint(lsp.at(9));
}
}
return result;
}
KgpgKeyList KgpgInterface::readSecretKeys(const QStringList &ids)
{
GPGProc process;
process <<
QLatin1String("--with-colons") <<
QLatin1String("--list-secret-keys") <<
QLatin1String("--with-fingerprint") <<
QLatin1String("--fixed-list-mode") <<
ids;
process.start();
process.waitForFinished(-1);
KgpgCore::KgpgKeyList result = readSecretKeysProcess(process);
return result;
}
#include "moc_kgpginterface.cpp"