diff options
Diffstat (limited to 'kgpg')
61 files changed, 10071 insertions, 0 deletions
diff --git a/kgpg/core/KGpgExpandableNode.cpp b/kgpg/core/KGpgExpandableNode.cpp new file mode 100644 index 0000000..4cf9607 --- /dev/null +++ b/kgpg/core/KGpgExpandableNode.cpp @@ -0,0 +1,88 @@ +/* Copyright 2008,2009,2012 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KGpgExpandableNode.h" + +//#include "kgpgsettings.h" +#include "convert.h" +//#include "model/kgpgitemmodel.h" + +//#include <KLocale> + +KGpgExpandableNode::KGpgExpandableNode(KGpgExpandableNode *parent) + : KGpgNode(parent) +{ + if (parent != NULL) + parent->children.append(this); +} + +KGpgExpandableNode::~KGpgExpandableNode() +{ + for (int i = children.count() - 1; i >= 0; i--) + delete children[i]; +} + +KGpgNode * +KGpgExpandableNode::getChild(const int index) const +{ + if ((index < 0) || (index > children.count())) + return NULL; + return children.at(index); +} + +int +KGpgExpandableNode::getChildCount() +{ + if (children.count() == 0) + readChildren(); + + return children.count(); +} + +bool +KGpgExpandableNode::hasChildren() const +{ + return (children.count() != 0); +} + +bool +KGpgExpandableNode::wasExpanded() const +{ + return (children.count() != 0); +} + +const +KGpgNode::List & +KGpgExpandableNode::getChildren() const +{ + return children; +} + +int +KGpgExpandableNode::getChildIndex(KGpgNode *node) const +{ + return children.indexOf(node); +} + +void +KGpgExpandableNode::deleteChild(KGpgNode *child) +{ + children.removeAll(child); +} + +//#include "KGpgExpandableNode.moc" diff --git a/kgpg/core/KGpgExpandableNode.h b/kgpg/core/KGpgExpandableNode.h new file mode 100644 index 0000000..39f351d --- /dev/null +++ b/kgpg/core/KGpgExpandableNode.h @@ -0,0 +1,85 @@ +/* Copyright 2008,2009,2012 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef KGPGEXPANDABLENODE_H +#define KGPGEXPANDABLENODE_H + +#include "KGpgNode.h" + +class KGpgSubkeyNode; +class KGpgRefNode; + +/** + * @brief The abstract base class for all classes that may have child objects + * + * Every class that represents something in the keyring that may have + * child objects inherits from this class. That does not mean that every + * child object always has children, but every child \em may have children. + */ +class KGpgExpandableNode : public KGpgNode +{ + Q_OBJECT + + friend class KGpgRefNode; + friend class KGpgSubkeyNode; +protected: + KGpgNode::List children; + + /** + * reimplemented in every base class to read in the child data + * + * This allows the child objects to delay the loading of the + * child objects until they are really needed to avoid time + * consuming operations for data never used. + */ + virtual void readChildren() = 0; + + explicit KGpgExpandableNode(KGpgExpandableNode *parent = NULL); +public: + virtual ~KGpgExpandableNode(); + + /** + * check if there are any child nodes + * + * The default implementation returns true if any child nodes were loaded. + * This may be reimplemented by child classes so they can indicate that + * there are child nodes before actually loading them. + * + * This method indicates if there are children if this node is expanded. + * In contrast wasExpanded() will only return true if the child nodes + * are actually present in memory. + */ + virtual bool hasChildren() const; + /** + * check if there are any child nodes present in memory + * + * Returns true if any child nodes were loaded. + * + * This method indicates if the children of this node are already loaded + * into memory. In contrast hasChildren() may return true even if the child + * objects are not present in memory. + */ + virtual bool wasExpanded() const; + virtual int getChildCount(); + virtual const KGpgNode::List &getChildren() const; + virtual KGpgNode *getChild(const int index) const; + virtual int getChildIndex(KGpgNode *node) const; + virtual void deleteChild(KGpgNode *child); +}; + +#endif /* KGPGEXPANDABLENODE_H */ diff --git a/kgpg/core/KGpgGroupMemberNode.cpp b/kgpg/core/KGpgGroupMemberNode.cpp new file mode 100644 index 0000000..e7a9f97 --- /dev/null +++ b/kgpg/core/KGpgGroupMemberNode.cpp @@ -0,0 +1,100 @@ +/* Copyright 2008,2009 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KGpgGroupMemberNode.h" + +#include <QDateTime> + +#include "KGpgGroupNode.h" +#include "KGpgKeyNode.h" + +KGpgGroupMemberNode::KGpgGroupMemberNode(KGpgGroupNode *parent, const QString &k) + : KGpgRefNode(parent, k) +{ +} + +KGpgGroupMemberNode::KGpgGroupMemberNode(KGpgGroupNode *parent, KGpgKeyNode *k) + : KGpgRefNode(parent, k) +{ +} + +KGpgGroupMemberNode::~KGpgGroupMemberNode() +{ +} + +KgpgKeyTrust +KGpgGroupMemberNode::getTrust() const +{ + if (m_keynode != NULL) + return m_keynode->getTrust(); + return KgpgCore::TRUST_NOKEY; +} + +KgpgItemType +KGpgGroupMemberNode::getType() const +{ + if (m_keynode != NULL) + return m_keynode->getType() | KgpgCore::ITYPE_GROUP; + return KgpgCore::ITYPE_PUBLIC | KgpgCore::ITYPE_GROUP; +} + +QString +KGpgGroupMemberNode::getSize() const +{ + if (m_keynode != NULL) + return m_keynode->getSize(); + return QString(); +} + +QDateTime +KGpgGroupMemberNode::getExpiration() const +{ + if (m_keynode != NULL) + return m_keynode->getExpiration(); + return QDateTime(); +} + +QDateTime +KGpgGroupMemberNode::getCreation() const +{ + if (m_keynode != NULL) + return m_keynode->getCreation(); + return QDateTime(); +} + +unsigned int +KGpgGroupMemberNode::getSignKeySize() const +{ + if (m_keynode != NULL) + return m_keynode->getSignKeySize(); + return 0; +} + +unsigned int +KGpgGroupMemberNode::getEncryptionKeySize() const +{ + if (m_keynode != NULL) + return m_keynode->getEncryptionKeySize(); + return 0; +} + +KGpgGroupNode * +KGpgGroupMemberNode::getParentKeyNode() const +{ + return m_parent->toGroupNode(); +} diff --git a/kgpg/core/KGpgGroupMemberNode.h b/kgpg/core/KGpgGroupMemberNode.h new file mode 100644 index 0000000..2a456ef --- /dev/null +++ b/kgpg/core/KGpgGroupMemberNode.h @@ -0,0 +1,61 @@ +/* Copyright 2008,2009 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef KGPGGROUPMEMBERNODE_H +#define KGPGGROUPMEMBERNODE_H + +#include "KGpgRefNode.h" + +#include <QPixmap> +#include "kgpgkey.h" + +using namespace KgpgCore; + +class KGpgKeyNode; +class KGpgGroupNode; + +/** + * @brief A member of a GnuPG group + */ +class KGpgGroupMemberNode : public KGpgRefNode +{ +public: + explicit KGpgGroupMemberNode(KGpgGroupNode *parent, const QString &k); + explicit KGpgGroupMemberNode(KGpgGroupNode *parent, KGpgKeyNode *k); + virtual ~KGpgGroupMemberNode(); + + virtual KgpgCore::KgpgKeyTrust getTrust() const; + virtual KgpgCore::KgpgItemType getType() const; + virtual QString getSize() const; + virtual QDateTime getExpiration() const; + virtual QDateTime getCreation() const; + virtual KGpgGroupNode *getParentKeyNode() const; + + /** + * Returns the size of the signing key. + * @return signing key size in bits + */ + virtual unsigned int getSignKeySize() const; + /** + * Returns the size of the first encryption subkey. + * @return encryption key size in bits + */ + virtual unsigned int getEncryptionKeySize() const; +}; + +#endif /* KGPGGROUPMEMBERNODE_H */ diff --git a/kgpg/core/KGpgGroupNode.cpp b/kgpg/core/KGpgGroupNode.cpp new file mode 100644 index 0000000..3475303 --- /dev/null +++ b/kgpg/core/KGpgGroupNode.cpp @@ -0,0 +1,279 @@ +/* Copyright 2008,2009,2010,2012 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KGpgGroupNode.h" + +#include "KGpgGroupMemberNode.h" +#include "KGpgRootNode.h" +//#include "kgpgsettings.h" + +#include <QDebug> +//#include <KLocale> +#include <QFile> +#include <QStringList> +#include <QTextStream> + +class KGpgGroupNodePrivate { +public: + KGpgGroupNodePrivate(const QString &name); + + QString m_name; + + /** + * @brief find the line that defines this group in the configuration + * @param conffile file object (will be initialized) + * @param stream text stream (will be initialized and connected to conffile) + * @param lines the lines found in conffile (will be filled) + * @return the index in lines of the entry defining this group + * @retval -1 no entry defining this group was found + * + * stream will be positioned at the beginning. + */ + int findGroupEntry(QFile &conffile, QTextStream &stream, QStringList &lines); + + static const QRegExp &groupPattern(); + static const QString &groupTag(); +}; + +KGpgGroupNodePrivate::KGpgGroupNodePrivate(const QString &name) + : m_name(name) +{ +} + +int +KGpgGroupNodePrivate::findGroupEntry(QFile &conffile, QTextStream &stream, QStringList &lines) +{ + //conffile.setFileName(KGpgSettings::gpgConfigPath()); + conffile.setFileName(""); + + if (!conffile.exists()) + return -1; + + if (!conffile.open(QIODevice::ReadWrite)) + return -1; + + stream.setDevice(&conffile); + int index = -1; + int i = -1; + + while (!stream.atEnd()) { + const QString rawLine = stream.readLine(); + i++; + QString parsedLine = rawLine.simplified().section(QLatin1Char('#'), 0, 0); + + if (groupPattern().exactMatch(parsedLine)) { + // remove "group " + parsedLine = parsedLine.remove(0, 6); + if (parsedLine.startsWith(m_name)) { + if (parsedLine.mid(m_name.length()).simplified().startsWith(QLatin1Char('='))) { + if (index >= 0) { + // multiple definitions of the same group, drop the second one + continue; + } else { + index = i; + } + } + } + } + + lines << rawLine; + } + + stream.seek(0); + + return index; +} + +const QRegExp & +KGpgGroupNodePrivate::groupPattern() +{ + static const QRegExp groupre(QLatin1String("^group [^ ]+ ?= ?([0-9a-fA-F]{8,} ?)*$")); + + return groupre; +} + +const QString & +KGpgGroupNodePrivate::groupTag() +{ + static const QString grouptag(QLatin1String("group ")); + + return grouptag; +} + +KGpgGroupNode::KGpgGroupNode(KGpgRootNode *parent, const QString &name, const QStringList &members) + : KGpgExpandableNode(parent), + d_ptr(new KGpgGroupNodePrivate(name)) +{ + foreach (const QString &id, members) + new KGpgGroupMemberNode(this, id); + + parent->m_groups++; +} + +KGpgGroupNode::KGpgGroupNode(KGpgRootNode *parent, const QString &name, const KGpgKeyNode::List &members) + : KGpgExpandableNode(parent), + d_ptr(new KGpgGroupNodePrivate(name)) +{ + Q_ASSERT(members.count() > 0); + + foreach (KGpgKeyNode *nd, members) + new KGpgGroupMemberNode(this, nd); + + parent->m_groups++; +} + +KGpgGroupNode::~KGpgGroupNode() +{ + KGpgRootNode *root = m_parent->toRootNode(); + + if (root != NULL) + root->m_groups--; +} + +KgpgCore::KgpgItemType +KGpgGroupNode::getType() const +{ + return ITYPE_GROUP; +} + +QString +KGpgGroupNode::getName() const +{ + const Q_D(KGpgGroupNode); + + return d->m_name; +} + +QString +KGpgGroupNode::getSize() const +{ + return tr("1 key", "%1 keys").arg(children.count()); +} + +void +KGpgGroupNode::readChildren() +{ +} + +void +KGpgGroupNode::rename(const QString &newName) +{ + Q_D(KGpgGroupNode); + + QFile conffile; + QTextStream t; + QStringList lines; + int index = d->findGroupEntry(conffile, t, lines); + + // check if file opening failed + if (!t.device()) + return; + + if (index < 0) { + qDebug() << "Group " << d->m_name << " not renamed, group does not exist"; + return; + } + + // 6 = groupTag().length() + const QString values = lines[index].simplified().mid(6 + d->m_name.length()); + lines[index] = d->groupTag() + newName + QLatin1Char(' ') + values; + + conffile.resize(0); + t << lines.join(QLatin1String("\n")) + QLatin1Char('\n'); + + d->m_name = newName; +} + +void +KGpgGroupNode::saveMembers() +{ + Q_D(KGpgGroupNode); + + QFile conffile; + QTextStream t; + QStringList lines; + int index = d->findGroupEntry(conffile, t, lines); + + // check if file opening failed + if (!t.device()) + return; + + QStringList memberIds; + + for (int j = getChildCount() - 1; j >= 0; j--) + memberIds << getChild(j)->toGroupMemberNode()->getId(); + + const QString groupEntry = d->groupTag() + d->m_name + QLatin1String(" = ") + + memberIds.join(QLatin1String(" ")); + + if (index >= 0) + lines[index] = groupEntry; + else + lines << groupEntry; + + conffile.resize(0); + t << lines.join(QLatin1String("\n")) + QLatin1Char('\n'); +} + +void +KGpgGroupNode::remove() +{ + Q_D(KGpgGroupNode); + + QFile conffile; + QTextStream t; + QStringList lines; + int index = d->findGroupEntry(conffile, t, lines); + + // check if file opening failed + if (!t.device()) + return; + + if (index < 0) + return; + + lines.removeAt(index); + conffile.resize(0); + t << lines.join(QLatin1String("\n")) + QLatin1Char('\n'); +} + +QStringList +KGpgGroupNode::readGroups() +{ + QStringList groups; + //QFile qfile(KGpgSettings::gpgConfigPath()); + QFile qfile(""); + + if (!qfile.exists() || !qfile.open(QIODevice::ReadOnly)) + return groups; + + QTextStream t(&qfile); + + while (!t.atEnd()) { + QString line = t.readLine().simplified().section(QLatin1Char('#'), 0, 0); + if (!KGpgGroupNodePrivate::groupPattern().exactMatch(line)) + continue; + + // remove the "group " at the start + line.remove(0, 6); + // transform it in a simple space separated list + groups.append(line.replace(QLatin1Char('='), QLatin1Char(' ')).simplified()); + } + + return groups; +} diff --git a/kgpg/core/KGpgGroupNode.h b/kgpg/core/KGpgGroupNode.h new file mode 100644 index 0000000..5aca837 --- /dev/null +++ b/kgpg/core/KGpgGroupNode.h @@ -0,0 +1,84 @@ +/* Copyright 2008,2009,2010,2012 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef KGPGGROUPNODE_H +#define KGPGGROUPNODE_H + +#include "KGpgExpandableNode.h" +#include "KGpgKeyNode.h" + +class QString; +class QStringList; + +class KGpgGroupNodePrivate; + +/** + * @brief A GnuPG group of public keys + */ +class KGpgGroupNode : public KGpgExpandableNode +{ +private: + KGpgGroupNodePrivate * const d_ptr; + Q_DECLARE_PRIVATE(KGpgGroupNode) + Q_DISABLE_COPY(KGpgGroupNode) + +protected: + virtual void readChildren(); + +public: + KGpgGroupNode(KGpgRootNode *parent, const QString &name, const QStringList &members); + KGpgGroupNode(KGpgRootNode *parent, const QString &name, const KGpgKeyNode::List &members); + virtual ~KGpgGroupNode(); + + virtual KgpgCore::KgpgItemType getType() const; + /** + * Return size of group + * + * @return the number of keys in this group + */ + virtual QString getSize() const; + virtual QString getName() const; + + /** + * Rename this group node + * + * @param newName new name of the group + */ + void rename(const QString &newName); + + /** + * Write the current members to GnuPG config file + */ + void saveMembers(); + + /** + * Remove this group from the GnuPG config file + */ + void remove(); + + /** + * @brief get all groups from GnuPG config file + * @return list of groups names and their keys + * + * The strings are themself space separated list. The first entry is the + * group name, the others are the keys inside + */ + static QStringList readGroups(); +}; + +#endif /* KGPGGROUPNODE_H */ diff --git a/kgpg/core/KGpgKeyNode.cpp b/kgpg/core/KGpgKeyNode.cpp new file mode 100644 index 0000000..4e5fb55 --- /dev/null +++ b/kgpg/core/KGpgKeyNode.cpp @@ -0,0 +1,358 @@ +/* Copyright 2008,2009,2010,2012 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KGpgKeyNode.h" + +#include "KGpgGroupMemberNode.h" +#include "KGpgRootNode.h" +#include "KGpgSubkeyNode.h" +#include "KGpgUatNode.h" +#include "KGpgUidNode.h" +#include "convert.h" +#include "../kgpginterface.h" +//#include "kgpgsettings.h" +//#include "model/kgpgitemmodel.h" + +//#include <KLocale> + +KGpgKeyNode::KGpgKeyNode(KGpgRootNode *parent, const KgpgCore::KgpgKey &k) + : KGpgSignableNode(parent), + m_key(new KgpgCore::KgpgKey(k)), + m_signs(0) +{ +} + +KGpgKeyNode::~KGpgKeyNode() +{ + foreach (KGpgRefNode *nd, m_refs) { + nd->unRef(m_parent->toRootNode()); + } +} + +KgpgCore::KgpgItemType +KGpgKeyNode::getType() const +{ + return getType(m_key); +} + +bool +KGpgKeyNode::hasChildren() const +{ + return true; +} + +KgpgCore::KgpgItemType +KGpgKeyNode::getType(const KgpgCore::KgpgKey *k) +{ + if (k->secret()) + return KgpgCore::ITYPE_PAIR; + + return KgpgCore::ITYPE_PUBLIC; +} + +KgpgCore::KgpgKeyTrust +KGpgKeyNode::getTrust() const +{ + return m_key->trust(); +} + +const QString & +KGpgKeyNode::getFingerprint() const +{ + return m_key->fingerprint(); +} + +QString +KGpgKeyNode::getSize() const +{ + return "size of signing key / size of encryption key", + "%1 / %2", QString::number(getSignKeySize()), + QString::number(getEncryptionKeySize()); +} + +QString +KGpgKeyNode::getName() const +{ + return m_key->name(); +} + +QString +KGpgKeyNode::getEmail() const +{ + return m_key->email(); +} + +QDateTime +KGpgKeyNode::getExpiration() const +{ + return m_key->expirationDate(); +} + +QDateTime +KGpgKeyNode::getCreation() const +{ + return m_key->creationDate(); +} + +QString +KGpgKeyNode::getId() const +{ + return m_key->fullId(); +} + +KGpgKeyNode * +KGpgKeyNode::getKeyNode(void) +{ + return this; +} + +bool +KGpgKeyNode::isSecret() const +{ + return m_key->secret(); +} + +const KGpgKeyNode * +KGpgKeyNode::getKeyNode(void) const +{ + return this; +} + +QString +KGpgKeyNode::getBeautifiedFingerprint() const +{ + return m_key->fingerprintBeautified(); +} + +QString +KGpgKeyNode::getComment() const +{ + return m_key->comment(); +} + +void +KGpgKeyNode::readChildren() +{ + KgpgInterface::readSignatures(this); + + m_signs = 0; + foreach(KGpgNode *n, children) + if (n->getType() == ITYPE_SIGN) + m_signs++; +} + +QString +KGpgKeyNode::getSignCount() const +{ + if (!wasExpanded()) + return QString(); + //return i18np("1 signature", "%1 signatures", m_signs); + return "TODO"; +} + +KgpgKey * +KGpgKeyNode::copyKey() const +{ + return new KgpgKey(*m_key); +} + +void +KGpgKeyNode::setKey(const KgpgKey &key) +{ + Q_ASSERT(m_key->fingerprint() == key.fingerprint()); + delete m_key; + + for (int i = 0; i < children.count(); i++) + delete children.at(i); + children.clear(); + + m_key = new KgpgKey(key); +} + +const KgpgKey * +KGpgKeyNode::getKey() const +{ + return m_key; +} + +unsigned int +KGpgKeyNode::getSignKeySize() const +{ + return m_key->size(); +} + +unsigned int +KGpgKeyNode::getEncryptionKeySize() const +{ + return m_key->encryptionSize(); +} + +void +KGpgKeyNode::addRef(KGpgRefNode *node) +{ + Q_ASSERT(m_refs.indexOf(node) == -1); + m_refs.append(node); +} + +void +KGpgKeyNode::delRef(KGpgRefNode *node) +{ + Q_ASSERT(m_refs.indexOf(node) != -1); + m_refs.removeOne(node); + Q_ASSERT(m_refs.indexOf(node) == -1); +} + +QList<KGpgGroupNode *> +KGpgKeyNode::getGroups(void) const +{ + QList<KGpgGroupNode *> ret; + + foreach (KGpgGroupMemberNode *gnd, getGroupRefs()) + ret.append(gnd->getParentKeyNode()); + + return ret; +} + +QList<KGpgRefNode *> +KGpgKeyNode::getRefsOfType(const KgpgItemType &type) const +{ + QList<KGpgRefNode *> ret; + + foreach (KGpgRefNode *nd, m_refs) { + if (nd->getType() & type) + ret.append(nd); + } + + return ret; +} + +QList<KGpgGroupMemberNode *> +KGpgKeyNode::getGroupRefs(void) const +{ + QList<KGpgGroupMemberNode *> ret; + + foreach (KGpgRefNode *rn, getRefsOfType(KgpgCore::ITYPE_GROUP)) + ret.append(rn->toGroupMemberNode()); + + return ret; +} + +KGpgSignNode::List +KGpgKeyNode::getSignRefs(void) const +{ + KGpgSignNode::List ret; + + QList<KGpgRefNode *> refs = getRefsOfType(KgpgCore::ITYPE_SIGN); + + foreach (KGpgRefNode *rn, refs) + ret.append(rn->toSignNode()); + + return ret; +} + +KGpgSignNode::List +KGpgKeyNode::getSignatures(const bool subkeys) const +{ + KGpgSignNode::List ret = KGpgSignableNode::getSignatures(); + + if (!subkeys) + return ret; + + foreach (KGpgNode *child, children) { + KGpgSignNode::List tmp; + + switch (child->getType()) { + case KgpgCore::ITYPE_UID: + case KgpgCore::ITYPE_UAT: + tmp = child->toSignableNode()->getSignatures(); + break; + default: + continue; + } + + foreach (KGpgSignNode *sn, tmp) { + bool found = false; + const QString snid(sn->getId()); + + foreach (const KGpgSignNode *retsn, ret) { + found = (retsn->getId() == snid); + if (found) + break; + } + + if (!found) + ret << sn; + } + } + + return ret; +} + +const KGpgSignableNode * +KGpgKeyNode::getUid(const unsigned int index) const +{ + Q_ASSERT(index > 0); + + if (index == 1) + return this; + + const QString idxstr(QString::number(index)); + + foreach (const KGpgNode *child, children) { + KGpgSignNode::List tmp; + + switch (child->getType()) { + case KgpgCore::ITYPE_UID: + case KgpgCore::ITYPE_UAT: + if (child->getId() == idxstr) + return child->toSignableNode(); + break; + default: + continue; + } + } + + return NULL; +} + +bool +KGpgKeyNode::compareId(const QString &other) const +{ + if (other.length() == m_key->fullId().length()) + return (other.compare(m_key->fullId(), Qt::CaseInsensitive) == 0); + + if (other.length() == m_key->fingerprint().length()) + return (other.compare(m_key->fingerprint(), Qt::CaseInsensitive) == 0); + + const QString comId = m_key->fullId().isEmpty() ? m_key->fingerprint() : m_key->fullId(); + + return (other.right(comId.length()).compare( + comId.right(other.length()), + Qt::CaseInsensitive) == 0); +} + +void +KGpgKeyNode::expand() +{ + if (!wasExpanded()) + readChildren(); + + emit expanded(); +} + +//#include "KGpgKeyNode.moc" diff --git a/kgpg/core/KGpgKeyNode.h b/kgpg/core/KGpgKeyNode.h new file mode 100644 index 0000000..caf0ba4 --- /dev/null +++ b/kgpg/core/KGpgKeyNode.h @@ -0,0 +1,191 @@ +/* Copyright 2008,2009,2010,2012 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef KGPGKEYNODE_H +#define KGPGKEYNODE_H + +#include "KGpgSignableNode.h" +#include "KGpgSignNode.h" + +#include "kgpgkey.h" + +class KGpgExpandableNode; +class KGpgRefNode; + +/** + * @brief A public key with or without corresponding secret key + */ +class KGpgKeyNode : public KGpgSignableNode +{ + Q_OBJECT + + friend class KGpgGroupMemberNode; + +private: + KgpgCore::KgpgKey *m_key; + int m_signs; + +protected: + virtual void readChildren(); + + QList<KGpgRefNode *> m_refs; + QList<KGpgRefNode *> getRefsOfType(const KgpgCore::KgpgItemType &type) const; + +public: + typedef QList<KGpgKeyNode *> List; + typedef QList<const KGpgKeyNode *> ConstList; + + explicit KGpgKeyNode(KGpgRootNode *parent, const KgpgCore::KgpgKey &k); + virtual ~KGpgKeyNode(); + + virtual bool hasChildren() const; + + static KgpgCore::KgpgItemType getType(const KgpgCore::KgpgKey *k); + + virtual KgpgCore::KgpgItemType getType() const; + virtual KgpgCore::KgpgKeyTrust getTrust() const; + const QString &getFingerprint() const; + virtual QString getSize() const; + virtual QString getName() const; + virtual QString getEmail() const; + virtual QDateTime getExpiration() const; + virtual QDateTime getCreation() const; + virtual QString getId() const; + virtual KGpgKeyNode *getKeyNode(void); + virtual const KGpgKeyNode *getKeyNode(void) const; + /** + * @brief Return if this key has a private key + */ + bool isSecret() const; + /** + * @brief Print the full key fingerprint with spaces inserted + * + * For display purposes you normally don't want to print the full + * fingerprint as is because it's too many hex characters at once. + * This function returns the fingerprint in the format usually used + * for printing this out, i.e. with a space after each fourth hex + * character. + * + * @return the full fingerprint with spaces inserted + */ + QString getBeautifiedFingerprint() const; + virtual QString getComment() const; + /** + * @brief Return the number of signatures of the primary user id + * + * This is different from the number of children of this node as there + * is usually at least one subkey and there may also be additional + * user ids or attributes. This does not count the signatures to those + * slave objects, only the ones that are direct children of this node. + * + * @return the number of signatures to the primary user id + */ + virtual QString getSignCount() const; + /** + * @brief Creates a copy of the KgpgKey that belongs to this class + */ + virtual KgpgCore::KgpgKey *copyKey() const; + /** + * @brief Replaces the current key information with the new one. + * All sub-items (i.e. signatures, user ids ...) will be deleted. This must + * only be used when the id of both new and old key is the same. + */ + void setKey(const KgpgCore::KgpgKey &key); + /** + * @brief Returns a reference to the key used in this object. + * This allows direct access to the values of the key e.g. for KgpgKeyInfo. + */ + const KgpgCore::KgpgKey *getKey() const; + + /** + * @brief Returns the size of the signing key. + * @return signing key size in bits + */ + virtual unsigned int getSignKeySize() const; + /** + * @brief Returns the size of the first encryption subkey. + * @return encryption key size in bits + */ + virtual unsigned int getEncryptionKeySize() const; + /** + * @brief Notify this key that a KGpgRefNode now references this key. + * @param node object that takes the reference + */ + void addRef(KGpgRefNode *node); + /** + * @brief Remove a reference to this object + * @param node node that no longer has the reference + * + * Note that this must not be called as reply when this object + * emits updated(NULL) + */ + void delRef(KGpgRefNode *node); + /** + * @brief returns a list of all groups this key is member of + */ + QList<KGpgGroupNode *> getGroups(void) const; + /** + * @brief returns a list of all group member nodes that reference this key + */ + QList<KGpgGroupMemberNode *> getGroupRefs(void) const; + /** + * @brief returns a list of all sign nodes that reference this key + */ + KGpgSignNode::List getSignRefs(void) const; + /** + * @brief returns a list of signatures to this key + * @param subkeys if signatures on subkeys should be included + */ + KGpgSignNode::List getSignatures(const bool subkeys) const; + /** + * @brief get the user id or user attribute with the given number + * @param index the index of the user id to return + * @return the requested subitem or NULL if that is not present + * + * User ids indexes are 1-based, so 0 is not a valid index. Passing + * 1 as index will return the object itself, representing the primary + * user id. + */ + const KGpgSignableNode *getUid(const unsigned int index) const; + + /** + * @brief compare the id of this node to the given other node + * @param other key id to compare to + * @return if ids are identical + * + * This handles different length of the id string. + */ + bool compareId(const QString &other) const; +Q_SIGNALS: + void expanded(); + +public slots: + /** + * @brief read all subitems + * + * This will read in all subitems (e.g. subkeys, signatures). When + * this is done the expanded() signal is emitted. The signal is emitted + * immediately if the key has been expanded before. + * + * This will not update the child items in case they are already present. + * Use KGpgItemModel::refreshKey() instead. + */ + void expand(); +}; + +#endif /* KGPGKEYNODE_H */ diff --git a/kgpg/core/KGpgNode.cpp b/kgpg/core/KGpgNode.cpp new file mode 100644 index 0000000..18645f8 --- /dev/null +++ b/kgpg/core/KGpgNode.cpp @@ -0,0 +1,337 @@ +/* Copyright 2008,2009,2012 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KGpgNode.h" + +#include "KGpgGroupMemberNode.h" +#include "KGpgGroupNode.h" +#include "KGpgOrphanNode.h" +#include "KGpgRootNode.h" +#include "KGpgSubkeyNode.h" +#include "KGpgUatNode.h" +#include "KGpgUidNode.h" +//#include "model/kgpgitemmodel.h" + +//#include <KLocale> + +KGpgNode::KGpgNode(KGpgExpandableNode *parent) + : QObject(), m_parent(parent) +{ +/* if (parent == NULL) + m_model = NULL; + else + m_model = parent->m_model; +*/ +} + +KGpgNode::~KGpgNode() +{ +/* Q_ASSERT(m_model); + m_model->invalidateIndexes(this); +*/ + if (m_parent != NULL) + m_parent->deleteChild(this); +} + +QString +KGpgNode::getNameComment() const +{ + if (getComment().isEmpty()) + return getName(); + else + return tr("Name of uid (comment) %1 (%2)").arg(getName()).arg(getComment()); + //return QString("Name of uid (comment)", "%1 (%2)", getName(), getComment()); +} + +KGpgExpandableNode * +KGpgNode::toExpandableNode() +{ + Q_ASSERT(((getType() & KgpgCore::ITYPE_GROUP) && !(getType() & KgpgCore::ITYPE_PAIR)) || + (getType() & (KgpgCore::ITYPE_PAIR | KgpgCore::ITYPE_SUB | KgpgCore::ITYPE_UID | KgpgCore::ITYPE_UAT))); + + return qobject_cast<KGpgExpandableNode *>(this); +} + +const KGpgExpandableNode * +KGpgNode::toExpandableNode() const +{ + Q_ASSERT(((getType() & KgpgCore::ITYPE_GROUP) && !(getType() & KgpgCore::ITYPE_PAIR)) || + (getType() & (KgpgCore::ITYPE_PAIR | KgpgCore::ITYPE_SUB | KgpgCore::ITYPE_UID | KgpgCore::ITYPE_UAT))); + + return qobject_cast<const KGpgExpandableNode *>(this); +} + +KGpgSignableNode * +KGpgNode::toSignableNode() +{ + Q_ASSERT(getType() & (KgpgCore::ITYPE_PAIR | KgpgCore::ITYPE_SUB | KgpgCore::ITYPE_UID | KgpgCore::ITYPE_UAT)); + + return qobject_cast<KGpgSignableNode *>(this); +} + +const KGpgSignableNode * +KGpgNode::toSignableNode() const +{ + Q_ASSERT(getType() & (KgpgCore::ITYPE_PAIR | KgpgCore::ITYPE_SUB | KgpgCore::ITYPE_UID | KgpgCore::ITYPE_UAT)); + + return qobject_cast<const KGpgSignableNode *>(this); +} + +KGpgKeyNode * +KGpgNode::toKeyNode() +{ + Q_ASSERT(getType() & KgpgCore::ITYPE_PAIR); + Q_ASSERT(!(getType() & KgpgCore::ITYPE_GROUP)); + + return qobject_cast<KGpgKeyNode *>(this); +} + +const KGpgKeyNode * +KGpgNode::toKeyNode() const +{ + Q_ASSERT(getType() & KgpgCore::ITYPE_PAIR); + Q_ASSERT(!(getType() & KgpgCore::ITYPE_GROUP)); + + return qobject_cast<const KGpgKeyNode *>(this); +} + +KGpgRootNode * +KGpgNode::toRootNode() +{ + Q_ASSERT((m_parent == NULL) && (getType() == 0)); + + return static_cast<KGpgRootNode *>(this)->asRootNode(); +} + +const KGpgRootNode * +KGpgNode::toRootNode() const +{ + Q_ASSERT((m_parent == NULL) && (getType() == 0)); + + return static_cast<const KGpgRootNode *>(this)->asRootNode(); +} + +KGpgUidNode * +KGpgNode::toUidNode() +{ + Q_ASSERT(getType() == KgpgCore::ITYPE_UID); + + return static_cast<KGpgUidNode *>(this); +} + +const KGpgUidNode * +KGpgNode::toUidNode() const +{ + Q_ASSERT(getType() == KgpgCore::ITYPE_UID); + + return static_cast<const KGpgUidNode *>(this); +} + +KGpgSubkeyNode * +KGpgNode::toSubkeyNode() +{ + Q_ASSERT(getType() == KgpgCore::ITYPE_SUB); + + return static_cast<KGpgSubkeyNode *>(this); +} + +const KGpgSubkeyNode * +KGpgNode::toSubkeyNode() const +{ + Q_ASSERT(getType() == KgpgCore::ITYPE_SUB); + + return static_cast<const KGpgSubkeyNode *>(this); +} + +KGpgUatNode * +KGpgNode::toUatNode() +{ + Q_ASSERT(getType() == KgpgCore::ITYPE_UAT); + + return static_cast<KGpgUatNode *>(this); +} + +const KGpgUatNode * +KGpgNode::toUatNode() const +{ + Q_ASSERT(getType() == KgpgCore::ITYPE_UAT); + + return static_cast<const KGpgUatNode *>(this); +} + +KGpgGroupNode * +KGpgNode::toGroupNode() +{ + Q_ASSERT(getType() == KgpgCore::ITYPE_GROUP); + + return static_cast<KGpgGroupNode *>(this); +} + +const KGpgGroupNode * +KGpgNode::toGroupNode() const +{ + Q_ASSERT(getType() == KgpgCore::ITYPE_GROUP); + + return static_cast<const KGpgGroupNode *>(this); +} + +KGpgRefNode * +KGpgNode::toRefNode() +{ + Q_ASSERT(((getType() & KgpgCore::ITYPE_GROUP) && (getType() & KgpgCore::ITYPE_PAIR)) || (getType() & KgpgCore::ITYPE_SIGN)); + + return qobject_cast<KGpgRefNode *>(this); +} + +const KGpgRefNode * +KGpgNode::toRefNode() const +{ + Q_ASSERT(((getType() & KgpgCore::ITYPE_GROUP) && (getType() & KgpgCore::ITYPE_PAIR)) || (getType() & KgpgCore::ITYPE_SIGN)); + + return qobject_cast<const KGpgRefNode *>(this); +} + +KGpgGroupMemberNode * +KGpgNode::toGroupMemberNode() +{ + Q_ASSERT((getType() & KgpgCore::ITYPE_GROUP) && (getType() & KgpgCore::ITYPE_PAIR)); + + return static_cast<KGpgGroupMemberNode *>(this); +} + +const KGpgGroupMemberNode * +KGpgNode::toGroupMemberNode() const +{ + Q_ASSERT((getType() & KgpgCore::ITYPE_GROUP) && (getType() & KgpgCore::ITYPE_PAIR)); + + return static_cast<const KGpgGroupMemberNode *>(this); +} + +KGpgSignNode * +KGpgNode::toSignNode() +{ + Q_ASSERT(getType() == KgpgCore::ITYPE_SIGN); + + return static_cast<KGpgSignNode *>(this); +} + +const KGpgSignNode * +KGpgNode::toSignNode() const +{ + Q_ASSERT(getType() == KgpgCore::ITYPE_SIGN); + + return static_cast<const KGpgSignNode *>(this); +} + +KGpgOrphanNode * +KGpgNode::toOrphanNode() +{ + Q_ASSERT(getType() == KgpgCore::ITYPE_SECRET); + + return static_cast<KGpgOrphanNode *>(this); +} + +const KGpgOrphanNode * +KGpgNode::toOrphanNode() const +{ + Q_ASSERT(getType() == KgpgCore::ITYPE_SECRET); + + return static_cast<const KGpgOrphanNode *>(this); +} + +bool +KGpgNode::hasChildren() const +{ + return false; +} + +int +KGpgNode::getChildCount() +{ + return 0; +} + +KGpgNode * +KGpgNode::getChild(const int index) const +{ + Q_UNUSED(index); + return NULL; +} + +int +KGpgNode::getChildIndex(KGpgNode *node) const +{ + Q_UNUSED(node); + return 0; +} + +KgpgCore::KgpgKeyTrust +KGpgNode::getTrust() const +{ + return TRUST_NOKEY; +} + +QString +KGpgNode::getSize() const +{ + return QString(); +} + +QString +KGpgNode::getName() const +{ + return QString(); +} + +QString +KGpgNode::getEmail() const +{ + return QString(); +} + +QDateTime +KGpgNode::getExpiration() const +{ + return QDateTime(); +} + +QDateTime +KGpgNode::getCreation() const +{ + return QDateTime(); +} + +QString +KGpgNode::getId() const +{ + return QString(); +} + +QString +KGpgNode::getComment() const +{ + return QString(); +} + +KGpgExpandableNode * +KGpgNode::getParentKeyNode() const +{ + return m_parent; +} + +//#include "KGpgNode.moc" diff --git a/kgpg/core/KGpgNode.h b/kgpg/core/KGpgNode.h new file mode 100644 index 0000000..1d89875 --- /dev/null +++ b/kgpg/core/KGpgNode.h @@ -0,0 +1,156 @@ +/* Copyright 2008,2009 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef KGPGNODE_H +#define KGPGNODE_H + +#include <QPixmap> +#include "kgpgkey.h" + +class KGpgExpandableNode; +class KGpgKeyNode; +class KGpgRootNode; +class KGpgUidNode; +class KGpgSignableNode; +class KGpgSubkeyNode; +class KGpgUatNode; +class KGpgGroupNode; +class KGpgRefNode; +class KGpgGroupMemberNode; +class KGpgSignNode; +class KGpgOrphanNode; +class KGpgItemModel; + +/** + * @brief The abstract base class for all classes representing keyring data + */ +class KGpgNode : public QObject +{ + Q_OBJECT + + friend class KGpgItemModel; + + KGpgNode(); // = delete C++0x +protected: + KGpgExpandableNode *m_parent; + KGpgItemModel *m_model; + + /** + * constructor + * @param parent the parent node in item hierarchy + */ + explicit KGpgNode(KGpgExpandableNode *parent); + +public: + typedef QList<KGpgNode *> List; + + /** + * destructor + */ + virtual ~KGpgNode(); + + /** + * Returns if this node has child nodes + * + * This may be reimplemented by child classes so they can indicate that + * there are child nodes before actually loading them. + */ + virtual bool hasChildren() const; + /** + * Return how many child nodes exist + * + * When the child nodes do not already exist this will create them. + * This is the reason why this method is not const. + */ + virtual int getChildCount(); + /** + * Returns the child node at the given index + * @param index child index + * + * index may be in range 0 to getChildCount() - 1. + */ + virtual KGpgNode *getChild(const int index) const; + /** + * Returns the index for a given child node + * @return -1 if the given node is not a child of this object + */ + virtual int getChildIndex(KGpgNode *node) const; + + /** + * Returns the item type of this object + * + * Since every subclass returns a distinct value you can use the + * result of this function to decide which cast to take. Note that + * there are subclasses (KGpgKeyNode, KGpgGroupMemberNode) that + * can return two different values. + */ + virtual KgpgCore::KgpgItemType getType() const = 0; + virtual KgpgCore::KgpgKeyTrust getTrust() const; + /** + * Returns a string describing the size of this object + * + * Subclasses may return a value that makes sense for whatever + * object they represent. + * + * The default implementation returns an empty string. + */ + virtual QString getSize() const; + virtual QString getName() const; + virtual QString getEmail() const; + virtual QDateTime getExpiration() const; + virtual QDateTime getCreation() const; + virtual QString getId() const; + virtual QString getComment() const; + virtual QString getNameComment() const; + /** + * Returns the parent node in the key hierarchy + * + * For all "primary" items like keys and key groups this will + * return the (invisible) root node. Calling this function for + * the root node will return %NULL. No other node but the root + * node has a %NULL parent. + */ + KGpgExpandableNode *getParentKeyNode() const; + + KGpgExpandableNode *toExpandableNode(); + const KGpgExpandableNode *toExpandableNode() const; + KGpgSignableNode *toSignableNode(); + const KGpgSignableNode *toSignableNode() const; + KGpgKeyNode *toKeyNode(); + const KGpgKeyNode *toKeyNode() const; + KGpgRootNode *toRootNode(); + const KGpgRootNode *toRootNode() const; + KGpgUidNode *toUidNode(); + const KGpgUidNode *toUidNode() const; + KGpgSubkeyNode *toSubkeyNode(); + const KGpgSubkeyNode *toSubkeyNode() const; + KGpgUatNode *toUatNode(); + const KGpgUatNode *toUatNode() const; + KGpgGroupNode *toGroupNode(); + const KGpgGroupNode *toGroupNode() const; + KGpgRefNode *toRefNode(); + const KGpgRefNode *toRefNode() const; + KGpgGroupMemberNode *toGroupMemberNode(); + const KGpgGroupMemberNode *toGroupMemberNode() const; + KGpgSignNode *toSignNode(); + const KGpgSignNode *toSignNode() const; + KGpgOrphanNode *toOrphanNode(); + const KGpgOrphanNode *toOrphanNode() const; +}; + +#endif /* KGPGNODE_H */ diff --git a/kgpg/core/KGpgOrphanNode.cpp b/kgpg/core/KGpgOrphanNode.cpp new file mode 100644 index 0000000..f245121 --- /dev/null +++ b/kgpg/core/KGpgOrphanNode.cpp @@ -0,0 +1,84 @@ +/* Copyright 2008,2009,2010,2012 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KGpgOrphanNode.h" + +KGpgOrphanNode::KGpgOrphanNode(KGpgExpandableNode *parent, const KgpgKey &k) + : KGpgNode(parent), + m_key(new KgpgKey(k)) +{ +} + +KGpgOrphanNode::~KGpgOrphanNode() +{ + delete m_key; +} + +KgpgItemType +KGpgOrphanNode::getType() const +{ + return ITYPE_SECRET; +} + +QString +KGpgOrphanNode::getName() const +{ + return m_key->name(); +} + +QString +KGpgOrphanNode::getEmail() const +{ + return m_key->email(); +} + +QString +KGpgOrphanNode::getSize() const +{ + return QString::number(m_key->size()); +} + +QDateTime +KGpgOrphanNode::getExpiration() const +{ + return m_key->expirationDate(); +} + +QDateTime +KGpgOrphanNode::getCreation() const +{ + return m_key->creationDate(); +} + +QString +KGpgOrphanNode::getId() const +{ + return m_key->fullId(); +} + +KgpgCore::KgpgKeyTrust +KGpgOrphanNode::getTrust() const +{ + return m_key->trust(); +} + +const QString & +KGpgOrphanNode::getFingerprint() const +{ + return m_key->fingerprint(); +} diff --git a/kgpg/core/KGpgOrphanNode.h b/kgpg/core/KGpgOrphanNode.h new file mode 100644 index 0000000..e3b6132 --- /dev/null +++ b/kgpg/core/KGpgOrphanNode.h @@ -0,0 +1,53 @@ +/* Copyright 2008,2009,2010,2012 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef KGPGORPHANNODE_H +#define KGPGORPHANNODE_H + +#include "KGpgNode.h" + +#include "kgpgkey.h" + +using namespace KgpgCore; + +class KGpgExpandableNode; + +/** + * @brief A lone secret key without public key + */ +class KGpgOrphanNode : public KGpgNode +{ +private: + KgpgCore::KgpgKey *m_key; + +public: + explicit KGpgOrphanNode(KGpgExpandableNode *parent, const KgpgKey &k); + virtual ~KGpgOrphanNode(); + + virtual KgpgCore::KgpgItemType getType() const; + virtual KgpgCore::KgpgKeyTrust getTrust() const; + const QString &getFingerprint() const; + virtual QString getSize() const; + virtual QString getName() const; + virtual QString getEmail() const; + virtual QDateTime getExpiration() const; + virtual QDateTime getCreation() const; + virtual QString getId() const; +}; + +#endif /* KGPGORPHANNODE_H */ diff --git a/kgpg/core/KGpgRefNode.cpp b/kgpg/core/KGpgRefNode.cpp new file mode 100644 index 0000000..a67d6b5 --- /dev/null +++ b/kgpg/core/KGpgRefNode.cpp @@ -0,0 +1,151 @@ +/* Copyright 2008,2009 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KGpgRefNode.h" + +//#include <KLocale> + +#include "KGpgExpandableNode.h" +#include "KGpgRootNode.h" + +KGpgRefNode::KGpgRefNode(KGpgExpandableNode *parent, const QString &keyid) + : KGpgNode(parent), + m_id(keyid) +{ + Q_ASSERT(!keyid.isEmpty()); + + KGpgRootNode *root = getRootNode(); + KGpgExpandableNode *pnd = parent; + + do { + m_selfsig = (pnd->getId().right(keyid.length()) == keyid); + if (m_selfsig) + m_keynode = pnd->toKeyNode(); + else + pnd = pnd->getParentKeyNode(); + } while (!m_selfsig && (pnd != root)); + + // Self signatures do net need to get notified by their key: if the key is changed + // the key node is deleted, then those refnode would be deleted anyway. This avoids + // crashes when they would try to find the root node by iterating over their parent + // when the parents destructor is already called (see bug 208659). + if (!m_selfsig) { + m_keynode = root->findKey(keyid); + + if (m_keynode != NULL) { + m_keynode->addRef(this); + } else { + connect(root, SIGNAL(newKeyNode(KGpgKeyNode*)), this, SLOT(keyUpdated(KGpgKeyNode*))); + } + } + + parent->children.append(this); +} + +KGpgRefNode::KGpgRefNode(KGpgExpandableNode *parent, KGpgKeyNode *key) + : KGpgNode(parent), + m_id(key->getId()), + m_keynode(key) +{ + Q_ASSERT(key != NULL); + Q_ASSERT(parent != NULL); + m_keynode->addRef(this); + + parent->children.append(this); +} + +KGpgRefNode::~KGpgRefNode() +{ + if (m_keynode && !m_selfsig) + m_keynode->delRef(this); +} + +KGpgRootNode * +KGpgRefNode::getRootNode() const +{ + KGpgExpandableNode *root; + KGpgExpandableNode *pt = m_parent; + + do { + root = pt; + pt = pt->getParentKeyNode(); + } while (pt != NULL); + + return root->toRootNode(); +} + +void +KGpgRefNode::keyUpdated(KGpgKeyNode *nkey) +{ + Q_ASSERT(m_keynode == NULL); + Q_ASSERT(nkey != NULL); + + if (nkey->getId().right(m_id.length()) == m_id) { + disconnect(sender(), NULL, this, SLOT(keyUpdated(KGpgKeyNode*))); + m_keynode = nkey; + m_keynode->addRef(this); + } +} + +void +KGpgRefNode::unRef(KGpgRootNode *root) +{ + if (root != NULL) + connect(root, SIGNAL(newKeyNode(KGpgKeyNode*)), this, SLOT(keyUpdated(KGpgKeyNode*))); + + m_keynode = NULL; +} + +QString +KGpgRefNode::getId() const +{ + if (m_keynode != NULL) + return m_keynode->getId(); + else + return m_id; +} + +QString +KGpgRefNode::getName() const +{ + if (m_keynode != NULL) + return m_keynode->getName(); + return tr("[No user id found]"); +} + +QString +KGpgRefNode::getEmail() const +{ + if (m_keynode != NULL) + return m_keynode->getEmail(); + return QString(); +} + +bool +KGpgRefNode::isUnknown() const +{ + return (m_keynode == NULL); +} + +KGpgKeyNode * +KGpgRefNode::getRefNode() const +{ + return m_keynode; +} + +//#include "KGpgRefNode.moc" diff --git a/kgpg/core/KGpgRefNode.h b/kgpg/core/KGpgRefNode.h new file mode 100644 index 0000000..f977567 --- /dev/null +++ b/kgpg/core/KGpgRefNode.h @@ -0,0 +1,98 @@ +/* Copyright 2008,2009 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef KGPGREFNODE_H +#define KGPGREFNODE_H + +#include "KGpgNode.h" + +class KGpgKeyNode; +class KGpgRootNode; + +/** + * @brief Class for child objects that are only a reference to a primary key + * + * This is the base class for all type of objects that match these criteria: + * -they can not have child objects + * -they are only a reference to a primary key (which needs not to be in the + * key ring) + * + * Do not create instances from this class. Use KGpgGroupMemberNode and + * KGpgSignNode as those represent the existing objects. This class exists + * only to get the hierarchy right. + */ +class KGpgRefNode : public KGpgNode +{ + Q_OBJECT + +private: + const QString m_id; + bool m_selfsig; ///< if this is a reference to it's own parent + +protected: + KGpgKeyNode *m_keynode; + + explicit KGpgRefNode(KGpgExpandableNode *parent, KGpgKeyNode *key); + explicit KGpgRefNode(KGpgExpandableNode *parent, const QString &keyid); + + KGpgRootNode *getRootNode() const; + +public: + virtual ~KGpgRefNode(); + + virtual QString getId() const; + virtual QString getName() const; + virtual QString getEmail() const; + /** + * Get the node of the primary key this node references to + * + * This will return the key node of the primary key this node + * references. This may be %NULL if the primary key is not in the key + * ring, e.g. if this is a signature of an unknown key. + * + * @return the node of the primary key or %NULL + */ + virtual KGpgKeyNode *getRefNode() const; + + /** + * Check if the referenced key exists + * + * @return if getRefNode() will return %NULL or not + */ + bool isUnknown() const; + + /** + * Break the current reference + * @param root root node + * + * This is called when the referenced node is going away. + * + * The root node is passed for two reasons: + * @li it doesn't need to be searched again for every ref node which + * can be many in case of an important key node get's deleted + * @li the ref node may be a child of the deleted node, then we can + * not call the parents functions to find the root anymore. This helps + * simplifying the code + */ + void unRef(KGpgRootNode *root); + +private Q_SLOTS: + void keyUpdated(KGpgKeyNode *); +}; + +#endif /* KGPGREFNODE_H */ diff --git a/kgpg/core/KGpgRootNode.cpp b/kgpg/core/KGpgRootNode.cpp new file mode 100644 index 0000000..9ceb571 --- /dev/null +++ b/kgpg/core/KGpgRootNode.cpp @@ -0,0 +1,189 @@ +/* Copyright 2008,2009,2010,2012 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KGpgRootNode.h" + +#include "KGpgGroupNode.h" +#include "../kgpginterface.h" +#include "KGpgOrphanNode.h" +//#include "kgpgsettings.h" + +#include <QString> +#include <QStringList> + +KGpgRootNode::KGpgRootNode(KGpgItemModel *model) + : KGpgExpandableNode(NULL), + m_groups(0), + m_deleting(false) +{ + m_model = model; +} + +KGpgRootNode::~KGpgRootNode() +{ + m_deleting = true; +} + +void +KGpgRootNode::readChildren() +{ +} + +KgpgCore::KgpgItemType +KGpgRootNode::getType() const +{ + return 0; +} + +void +KGpgRootNode::addGroups(const QStringList &groups) +{ + foreach (const QString &group, groups) { + QStringList members = group.split(QLatin1Char(' ')); + const QString groupName = members.takeFirst(); + new KGpgGroupNode(this, groupName, members); + } +} + +void +KGpgRootNode::addKeys(const QStringList &ids) +{ + KgpgCore::KgpgKeyList publiclist = KgpgInterface::readPublicKeys(ids); + KgpgCore::KgpgKeyList secretlist = KgpgInterface::readSecretKeys(); + + QStringList issec = secretlist; + + for (int i = 0; i < publiclist.size(); ++i) { + KgpgCore::KgpgKey key = publiclist.at(i); + + int index = issec.indexOf(key.fullId()); + if (index != -1) { + key.setSecret(true); + issec.removeAt(index); + secretlist.removeAt(index); + } + + KGpgKeyNode *nd = new KGpgKeyNode(this, key); + emit newKeyNode(nd); + } + + for (int i = 0; i < secretlist.count(); ++i) { + KgpgCore::KgpgKey key = secretlist.at(i); + + new KGpgOrphanNode(this, key); + } +} + +void +KGpgRootNode::refreshKeys(KGpgKeyNode::List nodes) +{ + QStringList ids; + + foreach (const KGpgNode *nd, nodes) + ids << nd->getId(); + + KgpgCore::KgpgKeyList publiclist = KgpgInterface::readPublicKeys(ids); + QStringList issec = KgpgInterface::readSecretKeys(ids); + + for (int i = 0; i < publiclist.size(); ++i) { + KgpgCore::KgpgKey key = publiclist.at(i); + + int index = issec.indexOf(key.fullId()); + if (index != -1) { + key.setSecret(true); + issec.removeAt(index); + } + + for (int j = 0; j < nodes.count(); j++) { + KGpgKeyNode *nd = nodes.at(j); + + if (nd->getId() == key.fingerprint()) { + nodes.removeAt(j); + nd->setKey(key); + break; + } + } + } +} + +KGpgKeyNode * +KGpgRootNode::findKey(const QString &keyId) +{ + int i = findKeyRow(keyId); + if (i >= 0) { + return children[i]->toKeyNode(); + } + + return NULL; +} + +int +KGpgRootNode::findKeyRow(const QString &keyId) +{ + int i = 0; + + foreach (const KGpgNode *node, children) { + if ((node->getType() & ITYPE_PAIR) == 0) { + ++i; + continue; + } + + const KGpgKeyNode *key = node->toKeyNode(); + + if (key->compareId(keyId)) + return i; + ++i; + } + return -1; +} + +int +KGpgRootNode::groupChildren() const +{ + return m_groups; +} + +int +KGpgRootNode::findKeyRow(const KGpgKeyNode *key) +{ + for (int i = 0; i < children.count(); i++) { + if (children[i] == key) + return i; + } + return -1; +} + +KGpgRootNode * +KGpgRootNode::asRootNode() +{ + if (m_deleting) + return NULL; + + return this; +} + +const KGpgRootNode * +KGpgRootNode::asRootNode() const +{ + if (m_deleting) + return NULL; + + return this; +} + +//#include "KGpgRootNode.moc" diff --git a/kgpg/core/KGpgRootNode.h b/kgpg/core/KGpgRootNode.h new file mode 100644 index 0000000..97c597c --- /dev/null +++ b/kgpg/core/KGpgRootNode.h @@ -0,0 +1,129 @@ +/* Copyright 2008,2009 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef KGPGROOTNODE_H +#define KGPGROOTNODE_H + +#include "KGpgExpandableNode.h" +#include "KGpgKeyNode.h" + +class KGpgGroupNode; +class QString; +class QStringList; + +/** + * @brief The parent of all key data objects + * + * This object is invisible to the user but acts as the internal base object for + * everything in the keyring. It is anchestor of all other KGpgNode objects and + * the only one that will ever return NULL when calling getParentKeyNode() on it. + * + * There is only one object of this type around at any time. + */ +class KGpgRootNode : public KGpgExpandableNode +{ + Q_OBJECT + + friend class KGpgGroupNode; + +private: + int m_groups; + int m_deleting; + +protected: + virtual void readChildren(); + +public: + explicit KGpgRootNode(KGpgItemModel *model); + virtual ~KGpgRootNode(); + + virtual KgpgCore::KgpgItemType getType() const; + + /** + * Create new group nodes + * @param groups list of group names to create + */ + void addGroups(const QStringList &groups); + void addKeys(const QStringList &ids = QStringList()); + void refreshKeys(KGpgKeyNode::List nodes); + /** + * Find a key node with the given id + * + * This scans the list of primary keys for a key with the given id + * and returns the corresponding key node. + * + * The key id will be matched against the characters given in keyId. + * If you give only 8 or 16 byte you will still find the key if it + * exists. To be really sure to find the correct node you should pass + * the complete fingerprint whenever possible. + * + * @param keyId the key id to find, any length is permitted + * @return pointer to key node or %NULL if no such key + */ + KGpgKeyNode *findKey(const QString &keyId); + /** + * Return the child number of the key with the given id + * + * This scans the list of direct children for a key with the given + * key id. It returns the number in the internal list of children + * which is identical to the row number in the item model. Since + * proxy models may sort the items you should only call this function + * from the primary model (i.e. KGpgItemModel). + * + * The key id will be matched against the characters given in keyId. + * If you give only 8 or 16 byte you will still find the key if it + * exists. To be really sure to find the correct node you should pass + * the complete fingerprint whenever possible. + * + * @param keyId the key id to find, any length is permitted + * @return the child number or -1 if there is no such key + */ + int findKeyRow(const QString &keyId); + + /** + * Return the child number of the given key + * @param key the key to search for + * + * @overload + */ + int findKeyRow(const KGpgKeyNode *key); + + /** + * Return the group count + * @return the number of group nodes + */ + int groupChildren() const; + + /** + * Return a pointer to this object or NULL + * + * This returns a pointer to this object if the object will persist, + * i.e. is not currently in destruction. If the object is already + * cleaning up NULL is returned. + */ + KGpgRootNode *asRootNode(); + /** + * @overload + */ + const KGpgRootNode *asRootNode() const; + +Q_SIGNALS: + void newKeyNode(KGpgKeyNode *); +}; + +#endif /* KGPGROOTNODE_H */ diff --git a/kgpg/core/KGpgSignNode.cpp b/kgpg/core/KGpgSignNode.cpp new file mode 100644 index 0000000..f35bd9a --- /dev/null +++ b/kgpg/core/KGpgSignNode.cpp @@ -0,0 +1,95 @@ +/* Copyright 2008,2009,2010 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KGpgSignNode.h" + +#include "KGpgSignableNode.h" + +//#include <KLocale> +#include <QLocale> + +class KGpgSignNodePrivate { +public: + KGpgSignNodePrivate(const QStringList &sl); + + QDateTime m_creation; + QDateTime m_expiration; + bool m_local; + bool m_revocation; +}; + +KGpgSignNodePrivate::KGpgSignNodePrivate(const QStringList &sl) +{ + m_revocation = (sl.at(0) == QLatin1String("rev")); + if (sl.count() < 6) + return; + m_creation = QDateTime::fromTime_t(sl.at(5).toUInt()); + if (sl.count() < 7) + return; + if (!sl.at(6).isEmpty()) + m_expiration = QDateTime::fromTime_t(sl.at(6).toUInt()); + if (sl.count() < 11) + return; + m_local = sl.at(10).endsWith(QLatin1Char( 'l' )); +} + +KGpgSignNode::KGpgSignNode(KGpgSignableNode *parent, const QStringList &s) + : KGpgRefNode(parent, s.at(4)), + d_ptr(new KGpgSignNodePrivate(s)) +{ +} + +KGpgSignNode::~KGpgSignNode() +{ + delete d_ptr; +} + +QDateTime +KGpgSignNode::getExpiration() const +{ + const Q_D(KGpgSignNode); + + return d->m_expiration; +} + +QDateTime +KGpgSignNode::getCreation() const +{ + const Q_D(KGpgSignNode); + + return d->m_creation; +} + +QString +KGpgSignNode::getName() const +{ + const Q_D(KGpgSignNode); + const QString name = KGpgRefNode::getName(); + + if (!d->m_local) + return name; + + //return tr("%1 [local signature]", &name.constData()->toAscii()); + return "fixme"; +} + +KgpgCore::KgpgItemType +KGpgSignNode::getType() const +{ + return KgpgCore::ITYPE_SIGN; +} diff --git a/kgpg/core/KGpgSignNode.h b/kgpg/core/KGpgSignNode.h new file mode 100644 index 0000000..398ee57 --- /dev/null +++ b/kgpg/core/KGpgSignNode.h @@ -0,0 +1,54 @@ +/* Copyright 2008,2009,2010 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef KGPGSIGNNODE_H +#define KGPGSIGNNODE_H + +#include "KGpgRefNode.h" + +class KGpgSignableNode; + +class KGpgSignNodePrivate; + +/** + * @brief A signature to another key object + */ +class KGpgSignNode : public KGpgRefNode +{ +private: + KGpgSignNodePrivate * const d_ptr; + Q_DECLARE_PRIVATE(KGpgSignNode) + +public: + typedef QList<KGpgSignNode *> List; + + /** + * @brief constructor for KGpgSignNode + * @param parent the signed node + * @param s GnuPG line describing this signature + */ + explicit KGpgSignNode(KGpgSignableNode *parent, const QStringList &s); + virtual ~KGpgSignNode(); + + virtual KgpgCore::KgpgItemType getType() const; + virtual QDateTime getExpiration() const; + virtual QString getName() const; + virtual QDateTime getCreation() const; +}; + +#endif /* KGPGSIGNNODE_H */ diff --git a/kgpg/core/KGpgSignableNode.cpp b/kgpg/core/KGpgSignableNode.cpp new file mode 100644 index 0000000..e3782c1 --- /dev/null +++ b/kgpg/core/KGpgSignableNode.cpp @@ -0,0 +1,99 @@ +/* Copyright 2008,2009 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KGpgSignableNode.h" + +//#include <KLocale> + +KGpgSignableNode::KGpgSignableNode(KGpgExpandableNode *parent) + : KGpgExpandableNode(parent) +{ +} + +KGpgSignableNode::~KGpgSignableNode() +{ +} + +KGpgSignNode::List +KGpgSignableNode::getSignatures(void) const +{ + KGpgSignNode::List ret; + + foreach (KGpgNode *kn, children) { + if (kn->getType() == KgpgCore::ITYPE_SIGN) + ret << kn->toSignNode(); + } + + return ret; +} + +QString +KGpgSignableNode::getSignCount() const +{ + //return i18np("1 signature", "%1 signatures", children.count()); + return tr("1 signature", "%1 signatures", children.count()); +} + +bool +KGpgSignableNode::operator<(const KGpgSignableNode &other) const +{ + return operator<(&other); +} + +bool +KGpgSignableNode::operator<(const KGpgSignableNode *other) const +{ + switch (getType()) { + case KgpgCore::ITYPE_PUBLIC: + case KgpgCore::ITYPE_PAIR: { + const QString myid(getId()); + + switch (other->getType()) { + case KgpgCore::ITYPE_PUBLIC: + case KgpgCore::ITYPE_PAIR: + return (myid < other->getId()); + default: { + const QString otherid(other->getParentKeyNode()->getId()); + + if (myid == otherid) + return true; + return (myid < otherid); + } + } + } + default: { + const QString myp(getParentKeyNode()->getId()); + + switch (other->getType()) { + case KgpgCore::ITYPE_PAIR: + case KgpgCore::ITYPE_PUBLIC: + return (myp < other->getId()); + default: { + const QString otherp(other->getParentKeyNode()->getId()); + + if (otherp == myp) + return (getId().toInt() < other->getId().toInt()); + + return (myp < otherp); + } + } + } + } +} + +//#include "KGpgSignableNode.moc" diff --git a/kgpg/core/KGpgSignableNode.h b/kgpg/core/KGpgSignableNode.h new file mode 100644 index 0000000..fddae25 --- /dev/null +++ b/kgpg/core/KGpgSignableNode.h @@ -0,0 +1,62 @@ +/* Copyright 2008,2009,2012 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef KGPGSIGNABLENODE_H +#define KGPGSIGNABLENODE_H + +#include "KGpgExpandableNode.h" +#include "KGpgSignNode.h" + +/** + * @brief An object that may have KGpgSignNode children + * + * This class represents an object that may be signed, i.e. key nodes, + * user ids, user attributes, and subkeys. + */ +class KGpgSignableNode : public KGpgExpandableNode +{ + Q_OBJECT + +public: + typedef QList<KGpgSignableNode *> List; + typedef QList<const KGpgSignableNode *> const_List; + + KGpgSignableNode(KGpgExpandableNode *parent = NULL); + virtual ~KGpgSignableNode(); + + KGpgSignNode::List getSignatures(void) const; + /** + * @brief count signatures + * @return the number of signatures to this object + * + * This does not include the number of signatures to child objects. + */ + virtual QString getSignCount() const; + + bool operator<(const KGpgSignableNode &other) const; + bool operator<(const KGpgSignableNode *other) const; + + /** + * @brief returns the key node this node belongs to + * @returns this node if the node itself is a key or it's parent otherwise + */ + virtual KGpgKeyNode *getKeyNode(void) = 0; + virtual const KGpgKeyNode *getKeyNode(void) const = 0; +}; + +#endif /* KGPGSIGNABLENODE_H */ diff --git a/kgpg/core/KGpgSubkeyNode.cpp b/kgpg/core/KGpgSubkeyNode.cpp new file mode 100644 index 0000000..571ca35 --- /dev/null +++ b/kgpg/core/KGpgSubkeyNode.cpp @@ -0,0 +1,100 @@ +/* Copyright 2008,2009 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KGpgSubkeyNode.h" + +//#include <KLocale> + +#include "convert.h" +#include "KGpgKeyNode.h" + +KGpgSubkeyNode::KGpgSubkeyNode(KGpgKeyNode *parent, const KgpgKeySub &k) + : KGpgSignableNode(parent), + m_skey(k) +{ + Q_ASSERT(parent != NULL); +} +KGpgSubkeyNode::~KGpgSubkeyNode() +{ +} + +void +KGpgSubkeyNode::readChildren() +{ +} + +KgpgCore::KgpgItemType +KGpgSubkeyNode::getType() const +{ + return ITYPE_SUB; +} + +KgpgCore::KgpgKeyTrust +KGpgSubkeyNode::getTrust() const +{ + return m_skey.trust(); +} + +QDateTime +KGpgSubkeyNode::getExpiration() const +{ + return m_skey.expirationDate(); +} + +QDateTime +KGpgSubkeyNode::getCreation() const +{ + return m_skey.creationDate(); +} + +QString +KGpgSubkeyNode::getId() const +{ + return m_skey.id(); +} + +KGpgKeyNode * +KGpgSubkeyNode::getKeyNode(void) +{ + return getParentKeyNode()->toKeyNode(); +} + +const KGpgKeyNode * +KGpgSubkeyNode::getKeyNode(void) const +{ + return getParentKeyNode()->toKeyNode(); +} + +QString +KGpgSubkeyNode::getName() const +{ + //return i18n("%1 subkey", Convert::toString(m_skey.algorithm())); + return "TODO"; +} + +QString +KGpgSubkeyNode::getSize() const +{ + return QString::number(m_skey.size()); +} + +KGpgKeyNode * +KGpgSubkeyNode::getParentKeyNode() const +{ + return m_parent->toKeyNode(); +} diff --git a/kgpg/core/KGpgSubkeyNode.h b/kgpg/core/KGpgSubkeyNode.h new file mode 100644 index 0000000..bbe5ab8 --- /dev/null +++ b/kgpg/core/KGpgSubkeyNode.h @@ -0,0 +1,55 @@ +/* Copyright 2008,2009 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef KGPGSUBKEYNODE_H +#define KGPGSUBKEYNODE_H + +#include "KGpgSignableNode.h" + +#include "kgpgkey.h" + +using namespace KgpgCore; + +/** + * @brief a subkey of a public key or key pair + */ +class KGpgSubkeyNode : public KGpgSignableNode +{ +private: + KgpgCore::KgpgKeySub m_skey; + +protected: + virtual void readChildren(); + +public: + explicit KGpgSubkeyNode(KGpgKeyNode *parent, const KgpgCore::KgpgKeySub &k); + virtual ~KGpgSubkeyNode(); + + virtual KgpgCore::KgpgItemType getType() const; + virtual KgpgCore::KgpgKeyTrust getTrust() const; + virtual QString getSize() const; + virtual QString getName() const; + virtual QDateTime getExpiration() const; + virtual QDateTime getCreation() const; + virtual QString getId() const; + virtual KGpgKeyNode *getKeyNode(void); + virtual const KGpgKeyNode *getKeyNode(void) const; + virtual KGpgKeyNode *getParentKeyNode() const; +}; + +#endif /* KGPGSUBKEYNODE_H */ diff --git a/kgpg/core/KGpgUatNode.cpp b/kgpg/core/KGpgUatNode.cpp new file mode 100644 index 0000000..174db66 --- /dev/null +++ b/kgpg/core/KGpgUatNode.cpp @@ -0,0 +1,174 @@ +/* Copyright 2008,2009,2010,2012 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KGpgUatNode.h" + +#include "../gpgproc.h" +#include "KGpgKeyNode.h" + +//#include <KLocale> +//#include <KUrl> + +#include <QUrl> +#include <QDir> +#include <QFile> +#include <QPixmap> +#include <QDateTime> + +class KGpgUatNodePrivate { +public: + KGpgUatNodePrivate(const KGpgKeyNode *parent, const unsigned int index, const QStringList &sl); + + const QString m_idx; + const QPixmap m_pixmap; + QDateTime m_creation; + +private: + static QPixmap loadImage(const KGpgKeyNode *parent, const QString &index); +}; + +KGpgUatNodePrivate::KGpgUatNodePrivate(const KGpgKeyNode *parent, const unsigned int index, const QStringList &sl) + : m_idx(QString::number(index)), + m_pixmap(loadImage(parent, m_idx)) +{ + if (sl.count() < 6) + return; + m_creation = QDateTime::fromTime_t(sl.at(5).toUInt()); +} + +QPixmap +KGpgUatNodePrivate::loadImage(const KGpgKeyNode *parent, const QString &index) +{ + QPixmap pixmap; +#ifdef Q_OS_WIN32 //krazy:exclude=cpp + const QString pgpgoutput = QLatin1String("cmd /C \"echo %I\""); +#else + const QString pgpgoutput = QLatin1String("echo %I"); +#endif + + GPGProc workProcess; + workProcess << + QLatin1String("--no-greeting") << + QLatin1String("--status-fd=2") << + QLatin1String("--photo-viewer") << pgpgoutput << + QLatin1String("--edit-key") << parent->getFingerprint() << + QLatin1String( "uid" ) << index << + QLatin1String( "showphoto" ) << + QLatin1String( "quit" ); + + workProcess.start(); + workProcess.waitForFinished(); + if (workProcess.exitCode() != 0) + return pixmap; + + QString tmpfile; + if (workProcess.readln(tmpfile) < 0) + return pixmap; + + QUrl url(tmpfile); + pixmap.load(url.path()); + QFile::remove(url.path()); + QDir dir; + //dir.rmdir(url.directory()); + + return pixmap; +} + +KGpgUatNode::KGpgUatNode(KGpgKeyNode *parent, const unsigned int index, const QStringList &sl) + : KGpgSignableNode(parent), + d_ptr(new KGpgUatNodePrivate(parent, index, sl)) +{ +} + +KGpgUatNode::~KGpgUatNode() +{ + delete d_ptr; +} + +QString +KGpgUatNode::getName() const +{ + return tr("Photo id"); +} + +QString +KGpgUatNode::getSize() const +{ + const Q_D(KGpgUatNode); + + return QString::number(d->m_pixmap.width()) + QLatin1Char( 'x' ) + QString::number(d->m_pixmap.height()); +} + +QDateTime +KGpgUatNode::getCreation() const +{ + const Q_D(KGpgUatNode); + + return d->m_creation; +} + +KGpgKeyNode * +KGpgUatNode::getParentKeyNode() const +{ + return m_parent->toKeyNode(); +} + +void +KGpgUatNode::readChildren() +{ +} + +KgpgCore::KgpgItemType +KGpgUatNode::getType() const +{ + return KgpgCore::ITYPE_UAT; +} + +KgpgCore::KgpgKeyTrust +KGpgUatNode::getTrust() const +{ + return KgpgCore::TRUST_NOKEY; +} + +const QPixmap & +KGpgUatNode::getPixmap() const +{ + const Q_D(KGpgUatNode); + + return d->m_pixmap; +} + +QString +KGpgUatNode::getId() const +{ + const Q_D(KGpgUatNode); + + return d->m_idx; +} + +KGpgKeyNode * +KGpgUatNode::getKeyNode(void) +{ + return getParentKeyNode()->toKeyNode(); +} + +const KGpgKeyNode * +KGpgUatNode::getKeyNode(void) const +{ + return getParentKeyNode()->toKeyNode(); +} diff --git a/kgpg/core/KGpgUatNode.h b/kgpg/core/KGpgUatNode.h new file mode 100644 index 0000000..b4c6775 --- /dev/null +++ b/kgpg/core/KGpgUatNode.h @@ -0,0 +1,61 @@ +/* Copyright 2008,2009,2010 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef KGPGUATNODE_H +#define KGPGUATNODE_H + +#include "KGpgSignableNode.h" + +#include <QDateTime> +#include <QPixmap> + +class KGpgExpandableNode; +class KGpgKeyNode; +class QPixmap; + +class KGpgUatNodePrivate; + +/** + * @brief A user attribute (i.e. photo id) of a public key or key pair + */ +class KGpgUatNode : public KGpgSignableNode +{ +private: + KGpgUatNodePrivate * const d_ptr; + Q_DECLARE_PRIVATE(KGpgUatNode) + +protected: + virtual void readChildren(); + +public: + explicit KGpgUatNode(KGpgKeyNode *parent, const unsigned int index, const QStringList &sl); + virtual ~KGpgUatNode(); + + virtual KgpgCore::KgpgItemType getType() const; + virtual KgpgCore::KgpgKeyTrust getTrust() const; + const QPixmap &getPixmap() const; + virtual QString getId() const; + virtual QString getSize() const; + virtual QString getName() const; + virtual QDateTime getCreation() const; + virtual KGpgKeyNode *getParentKeyNode() const; + virtual KGpgKeyNode *getKeyNode(void); + virtual const KGpgKeyNode *getKeyNode(void) const; +}; + +#endif /* KGPGUATNODE_H */ diff --git a/kgpg/core/KGpgUidNode.cpp b/kgpg/core/KGpgUidNode.cpp new file mode 100644 index 0000000..0be6c10 --- /dev/null +++ b/kgpg/core/KGpgUidNode.cpp @@ -0,0 +1,146 @@ +/* Copyright 2008,2009,2010 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KGpgUidNode.h" + +#include "KGpgKeyNode.h" +#include "convert.h" + +class KGpgUidNodePrivate { +public: + KGpgUidNodePrivate(const unsigned int index, const QStringList &sl); + + const QString m_index; + QString m_email; + QString m_name; + QString m_comment; + KgpgCore::KgpgKeyTrust m_trust; + bool m_valid; +}; + +KGpgUidNodePrivate::KGpgUidNodePrivate(const unsigned int index, const QStringList &sl) + : m_index(QString::number(index)) +{ + QString fullname(sl.at(9)); + if (fullname.contains(QLatin1Char( '<' )) ) { + m_email = fullname; + + if (fullname.contains(QLatin1Char( ')' )) ) + m_email = m_email.section(QLatin1Char( ')' ), 1); + + m_email = m_email.section(QLatin1Char( '<' ), 1); + m_email.truncate(m_email.length() - 1); + + if (m_email.contains(QLatin1Char( '<' ))) { + // several email addresses in the same key + m_email = m_email.replace(QLatin1Char( '>' ), QLatin1Char( ';' )); + m_email.remove(QLatin1Char( '<' )); + } + } + + m_name = fullname.section(QLatin1String( " <" ), 0, 0); + if (fullname.contains(QLatin1Char( '(' )) ) { + m_name = m_name.section(QLatin1String( " (" ), 0, 0); + m_comment = fullname.section(QLatin1Char( '(' ), 1, 1); + m_comment = m_comment.section(QLatin1Char( ')' ), 0, 0); + } + + m_trust = KgpgCore::Convert::toTrust(sl.at(1)); + m_valid = ((sl.count() <= 11) || !sl.at(11).contains(QLatin1Char( 'D' ))); +} + + +KGpgUidNode::KGpgUidNode(KGpgKeyNode *parent, const unsigned int index, const QStringList &sl) + : KGpgSignableNode(parent), + d_ptr(new KGpgUidNodePrivate(index, sl)) +{ +} + +KGpgUidNode::~KGpgUidNode() +{ + delete d_ptr; +} + +QString +KGpgUidNode::getName() const +{ + const Q_D(KGpgUidNode); + + return d->m_name; +} + +QString +KGpgUidNode::getEmail() const +{ + const Q_D(KGpgUidNode); + + return d->m_email; +} + +QString +KGpgUidNode::getId() const +{ + const Q_D(KGpgUidNode); + + return d->m_index; +} + +KGpgKeyNode * +KGpgUidNode::getKeyNode(void) +{ + return getParentKeyNode()->toKeyNode(); +} + +const KGpgKeyNode * +KGpgUidNode::getKeyNode(void) const +{ + return getParentKeyNode()->toKeyNode(); +} + +KGpgKeyNode * +KGpgUidNode::getParentKeyNode() const +{ + return m_parent->toKeyNode(); +} + +void +KGpgUidNode::readChildren() +{ +} + +KgpgCore::KgpgItemType +KGpgUidNode::getType() const +{ + return KgpgCore::ITYPE_UID; +} + +KgpgCore::KgpgKeyTrust +KGpgUidNode::getTrust() const +{ + const Q_D(KGpgUidNode); + + return d->m_trust; +} + +QString +KGpgUidNode::getComment() const +{ + const Q_D(KGpgUidNode); + + return d->m_comment; +} diff --git a/kgpg/core/KGpgUidNode.h b/kgpg/core/KGpgUidNode.h new file mode 100644 index 0000000..cd1b563 --- /dev/null +++ b/kgpg/core/KGpgUidNode.h @@ -0,0 +1,57 @@ +/* Copyright 2008,2009,2010 Rolf Eike Beer <[email protected]> + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef KGPGUIDNODE_H +#define KGPGUIDNODE_H + +#include "KGpgSignableNode.h" + +#include "kgpgkey.h" + +class KGpgKeyNode; + +class KGpgUidNodePrivate; + +/** + * @brief A user id of a public key or key pair + */ +class KGpgUidNode : public KGpgSignableNode +{ +private: + KGpgUidNodePrivate * const d_ptr; + Q_DECLARE_PRIVATE(KGpgUidNode) + +protected: + virtual void readChildren(); + +public: + explicit KGpgUidNode(KGpgKeyNode *parent, const unsigned int index, const QStringList &sl); + virtual ~KGpgUidNode(); + + virtual KgpgCore::KgpgItemType getType() const; + virtual KgpgCore::KgpgKeyTrust getTrust() const; + virtual QString getName() const; + virtual QString getEmail() const; + virtual QString getId() const; + virtual KGpgKeyNode *getKeyNode(void); + virtual const KGpgKeyNode *getKeyNode(void) const; + virtual KGpgKeyNode *getParentKeyNode() const; + virtual QString getComment() const; +}; + +#endif /* KGPGUIDNODE_H */ diff --git a/kgpg/core/convert.cpp b/kgpg/core/convert.cpp new file mode 100644 index 0000000..934ec02 --- /dev/null +++ b/kgpg/core/convert.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2006 Jimmy Gilles <[email protected]> + * Copyright (C) 2010 Rolf Eike Beer <[email protected]> + */ +/*************************************************************************** + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "convert.h" + +//#include <KGlobal> +//#include <KLocale> +#include <QTranslator> +//#include "kgpgsettings.h" +#include "images.h" + +namespace KgpgCore +{ + +QString Convert::toString(const KgpgKeyAlgo algorithm) +{ + switch (algorithm) + { + case ALGO_RSA: return QObject::tr("Encryption algorithm", "RSA"); + case ALGO_DSA: return QObject::tr("Encryption algorithm", "DSA"); + case ALGO_ELGAMAL: return QObject::tr("Encryption algorithm", "ElGamal"); + case ALGO_DSA_ELGAMAL: return QObject::tr("Encryption algorithm", "DSA & ElGamal"); + case ALGO_RSA_RSA: return QObject::tr("Encryption algorithm RSA, Signing algorithm RSA", "RSA & RSA"); + case ALGO_UNKNOWN: + default: return QObject::tr("Unknown algorithm", "Unknown"); + } +} + +QString Convert::toString(const KgpgKeyOwnerTrust ownertrust) +{ + switch (ownertrust) + { + case OWTRUST_UNDEFINED: return QObject::tr("Do not Know"); + case OWTRUST_NONE: return QObject::tr("Do NOT Trust"); + case OWTRUST_MARGINAL: return QObject::tr("Marginally"); + case OWTRUST_FULL: return QObject::tr("Fully"); + case OWTRUST_ULTIMATE: return QObject::tr("Ultimately"); + case OWTRUST_UNKNOWN: + default: return QObject::tr("Unknown trust in key owner", "Unknown"); + } +} + +QString Convert::toString(const KgpgKeyTrust trust) +{ + switch (trust) + { + case TRUST_INVALID: return QObject::tr("Invalid key", "Invalid"); + case TRUST_DISABLED: return QObject::tr("Disabled key", "Disabled"); + case TRUST_REVOKED: return QObject::tr("Revoked"); + case TRUST_EXPIRED: return QObject::tr("Expired key", "Expired"); + case TRUST_UNDEFINED: return QObject::tr("Undefined key trust", "Undefined"); + case TRUST_NONE: return QObject::tr("No trust in key", "None"); + case TRUST_MARGINAL: return QObject::tr("Marginal trust in key", "Marginal"); + case TRUST_FULL: return QObject::tr("Full trust in key", "Full"); + case TRUST_ULTIMATE: return QObject::tr("Ultimate trust in key", "Ultimate"); + case TRUST_UNKNOWN: + default: return QObject::tr("Unknown trust in key", "Unknown"); + } +} + +QColor Convert::toColor(const KgpgKeyTrust trust) +{ + switch (trust) + { + case TRUST_INVALID: + /*case TRUST_DISABLED: return KGpgSettings::colorBad(); + case TRUST_EXPIRED: return KGpgSettings::colorExpired(); + case TRUST_MARGINAL: return KGpgSettings::colorMarginal(); + case TRUST_REVOKED: return KGpgSettings::colorRev(); + case TRUST_UNDEFINED: + case TRUST_NONE: return KGpgSettings::colorUnknown(); + case TRUST_FULL: return KGpgSettings::colorGood(); + case TRUST_ULTIMATE: return KGpgSettings::colorUltimate();*/ + case TRUST_UNKNOWN: + default: return QColor(0,0,0); + //return KGpgSettings::colorUnknown(); + } +} + +QString Convert::toString(const QDate &date) +{ + //return KGlobal::locale()->formatDate(date, KLocale::ShortDate); +} + +KgpgKeyAlgo Convert::toAlgo(const uint v) +{ + switch (v) + { + case 1: return ALGO_RSA; + case 16: + case 20: return ALGO_ELGAMAL; + case 17: return ALGO_DSA; + default: return ALGO_UNKNOWN; + } +} + +KgpgKeyAlgo Convert::toAlgo(const QString &s) +{ + bool b; + unsigned int u = s.toUInt(&b); + return b ? toAlgo(u) : ALGO_UNKNOWN; +} + +KgpgKeyTrust Convert::toTrust(const QChar &c) +{ + switch (c.toAscii()) + { + case 'o': return TRUST_UNKNOWN; + case 'i': return TRUST_INVALID; + case 'd': return TRUST_DISABLED; + case 'r': return TRUST_REVOKED; + case 'e': return TRUST_EXPIRED; + case 'q': return TRUST_UNDEFINED; + case 'n': return TRUST_NONE; + case 'm': return TRUST_MARGINAL; + case 'f': return TRUST_FULL; + case 'u': return TRUST_ULTIMATE; + default: return TRUST_UNKNOWN; + } +} + +KgpgKeyTrust Convert::toTrust(const QString &s) +{ + return s.isEmpty() ? TRUST_UNKNOWN : toTrust(s[0]); +} + +KgpgKeyOwnerTrust Convert::toOwnerTrust(const QChar &c) +{ + switch (c.toAscii()) + { + case 'n': return OWTRUST_NONE; + case 'm': return OWTRUST_MARGINAL; + case 'u': return OWTRUST_ULTIMATE; + case 'f': return OWTRUST_FULL; + default: return OWTRUST_UNDEFINED; + } +} + +KgpgKeyOwnerTrust Convert::toOwnerTrust(const QString &s) +{ + return s.isEmpty() ? OWTRUST_UNDEFINED : toOwnerTrust(s[0]); +} + +QPixmap Convert::toPixmap(const KgpgItemType t) +{ + switch (t) + { + case ITYPE_GROUP: return Images::group(); + case ITYPE_GSECRET: + case ITYPE_SECRET: return Images::orphan(); + case ITYPE_GPUBLIC: + case ITYPE_SUB: + case ITYPE_PUBLIC: return Images::single(); + case ITYPE_GPAIR: + case ITYPE_PAIR: return Images::pair(); + case ITYPE_UID: return Images::userId(); + case ITYPE_UAT: return Images::photo(); + case ITYPE_REVSIGN: return Images::revoke(); + case ITYPE_SIGN: return Images::signature(); + default: Q_ASSERT(1); + return NULL; + } +} + +} // namespace KgpgCore diff --git a/kgpg/core/convert.h b/kgpg/core/convert.h new file mode 100644 index 0000000..96043a8 --- /dev/null +++ b/kgpg/core/convert.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2006 Jimmy Gilles <[email protected]> + * Copyright (C) 2010 Rolf Eike Beer <[email protected]> + */ +/*************************************************************************** + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef CONVERT_H +#define CONVERT_H + +#include "kgpgkey.h" + +class QColor; +class QString; +class QPixmap; + +namespace KgpgCore +{ + +class Convert +{ +public: + static QString toString(const KgpgCore::KgpgKeyAlgo algorithm); + static QString toString(const KgpgCore::KgpgKeyOwnerTrust ownertrust); + static QString toString(const KgpgCore::KgpgKeyTrust trust); + static QString toString(const QDate &date); + static QColor toColor(const KgpgCore::KgpgKeyTrust trust); + static KgpgKeyAlgo toAlgo(const uint v); + static KgpgKeyAlgo toAlgo(const QString &s); + static KgpgKeyTrust toTrust(const QChar &c); + static KgpgKeyTrust toTrust(const QString &s); + static KgpgKeyOwnerTrust toOwnerTrust(const QChar &c); + static KgpgKeyOwnerTrust toOwnerTrust(const QString &s); + static QPixmap toPixmap(const KgpgCore::KgpgItemType t); +}; + +} // namespace KgpgCore + +#endif // CONVERT_H diff --git a/kgpg/core/images.cpp b/kgpg/core/images.cpp new file mode 100644 index 0000000..c63dceb --- /dev/null +++ b/kgpg/core/images.cpp @@ -0,0 +1,100 @@ +/*************************************************************************** + * Copyright (C) 2006 by Jimmy Gilles * + * [email protected] * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "images.h" + +//#include <KIconLoader> + +namespace KgpgCore +{ + +QPixmap Images::single() +{ + static QPixmap single; +// if (single.isNull()) +// single = KIconLoader::global()->loadIcon(QLatin1String( "key-single" ), KIconLoader::Small, 20); + return single; +} + +QPixmap Images::pair() +{ + static QPixmap pair; +// if (pair.isNull()) +// pair = KIconLoader::global()->loadIcon(QLatin1String( "key-pair" ), KIconLoader::Small, 20); + return pair; +} + +QPixmap Images::group() +{ + static QPixmap group; +// if (group.isNull()) +// group = KIconLoader::global()->loadIcon(QLatin1String( "key-group" ), KIconLoader::Small, 20); + return group; +} + +QPixmap Images::orphan() +{ + static QPixmap oprpan; +// if (oprpan.isNull()) +// oprpan = KIconLoader::global()->loadIcon(QLatin1String( "key-orphan" ), KIconLoader::Small, 20); + return oprpan; +} + +QPixmap Images::signature() +{ + static QPixmap signature; +// if (signature.isNull()) +// signature = KIconLoader::global()->loadIcon(QLatin1String( "application-pgp-signature" ), KIconLoader::Small, 20); + return signature; +} + +QPixmap Images::userId() +{ + static QPixmap userid; +// if (userid.isNull()) +// userid = KIconLoader::global()->loadIcon(QLatin1String( "x-office-contact" ), KIconLoader::Small, 20); + return userid; +} + +QPixmap Images::photo() +{ + static QPixmap photo; +// if (photo.isNull()) +// photo = KIconLoader::global()->loadIcon(QLatin1String( "image-x-generic" ), KIconLoader::Small, 20); + return photo; +} + +QPixmap Images::revoke() +{ + static QPixmap revoke; +// if (revoke.isNull()) +// revoke = KIconLoader::global()->loadIcon(QLatin1String( "dialog-error" ), KIconLoader::Small, 20); + return revoke; +} + +QPixmap Images::kgpg() +{ + static QPixmap kgpg; +// if (kgpg.isNull()) +// kgpg = KIconLoader::global()->loadIcon(QLatin1String( "kgpg" ), KIconLoader::Desktop); + return kgpg; +} + +} // namespace KgpgCore diff --git a/kgpg/core/images.h b/kgpg/core/images.h new file mode 100644 index 0000000..739a618 --- /dev/null +++ b/kgpg/core/images.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2006 by Jimmy Gilles * + * [email protected] * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef IMAGES_H +#define IMAGES_H + +#include <QPixmap> + +namespace KgpgCore +{ + +class Images +{ +public: + static QPixmap single(); + static QPixmap pair(); + static QPixmap group(); + static QPixmap orphan(); + static QPixmap signature(); + static QPixmap userId(); + static QPixmap photo(); + static QPixmap revoke(); + + /* Desktop image */ + static QPixmap kgpg(); +}; + +} // namespace KgpgCore + +#endif // IMAGES_H diff --git a/kgpg/core/kgpgkey.cpp b/kgpg/core/kgpgkey.cpp new file mode 100644 index 0000000..57ed820 --- /dev/null +++ b/kgpg/core/kgpgkey.cpp @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2006,2007 Jimmy Gilles <[email protected]> + * Copyright (C) 2007,2008,2009,2010,2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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 "kgpgkey.h" + +#include "convert.h" + +//#include <KLocale> + +#include <QStringList> + +namespace KgpgCore +{ + +//BEGIN KeySub +KgpgKeySubPrivate::KgpgKeySubPrivate(const QString &id, const uint size, const KgpgKeyTrust trust, const KgpgKeyAlgo algo, + const KgpgSubKeyType type, const QDateTime &date) + : gpgsubid(id), + gpgsubsize(size), + gpgsubcreation(date), + gpgsubtrust(trust), + gpgsubalgo(algo), + gpgsubtype(type) +{ +} + +bool KgpgKeySubPrivate::operator==(const KgpgKeySubPrivate &other) const +{ + if (gpgsubvalid != other.gpgsubvalid) return false; + if (gpgsubalgo != other.gpgsubalgo) return false; + if (gpgsubid != other.gpgsubid) return false; + if (gpgsubsize != other.gpgsubsize) return false; + if (gpgsubexpiration != other.gpgsubexpiration) return false; + if (gpgsubcreation != other.gpgsubcreation) return false; + if (gpgsubtrust != other.gpgsubtrust) return false; + if (gpgsubtype != other.gpgsubtype) return false; + return true; +} + +KgpgKeySub::KgpgKeySub(const QString &id, const uint size, const KgpgKeyTrust trust, const KgpgKeyAlgo algo, const KgpgSubKeyType type, + const QDateTime &date) + : d(new KgpgKeySubPrivate(id, size, trust, algo, type, date)) +{ + d->gpgsubvalid = false; +} + +KgpgKeySub::KgpgKeySub(const KgpgKeySub &other) +{ + d = other.d; +} + +void KgpgKeySub::setExpiration(const QDateTime &date) +{ + d->gpgsubexpiration = date; +} + +void KgpgKeySub::setValid(const bool valid) +{ + d->gpgsubvalid = valid; +} + +QString KgpgKeySub::id() const +{ + return d->gpgsubid; +} + +uint KgpgKeySub::size() const +{ + return d->gpgsubsize; +} + +bool KgpgKeySub::unlimited() const +{ + return d->gpgsubexpiration.isNull(); +} + +QDateTime KgpgKeySub::expirationDate() const +{ + return d->gpgsubexpiration; +} + +QDateTime KgpgKeySub::creationDate() const +{ + return d->gpgsubcreation; +} + +KgpgKeyTrust KgpgKeySub::trust() const +{ + return d->gpgsubtrust; +} + +KgpgKeyAlgo KgpgKeySub::algorithm() const +{ + return d->gpgsubalgo; +} + +bool KgpgKeySub::valid() const +{ + return d->gpgsubvalid; +} + +KgpgSubKeyType KgpgKeySub::type() const +{ + return d->gpgsubtype; +} + +bool KgpgKeySub::operator==(const KgpgKeySub &other) const +{ + if (d == other.d) return true; + if ((*d) == (*(other.d))) return true; + return false; +} + +KgpgKeySub& KgpgKeySub::operator=(const KgpgKeySub &other) +{ + d = other.d; + return *this; +} + +//END KeySub + + +//BEGIN Key + +KgpgKeyPrivate::KgpgKeyPrivate(const QString &id, const uint size, const KgpgKeyTrust trust, const KgpgKeyAlgo algo, const QDateTime &date) + : gpgkeysecret(false), + gpgkeyvalid(false), + gpgkeyid(id), + gpgkeysize(size), + gpgkeytrust(trust), + gpgkeycreation(date), + gpgkeyalgo(algo), + gpgsublist(new KgpgKeySubList()) +{ +} + +bool KgpgKeyPrivate::operator==(const KgpgKeyPrivate &other) const +{ + if (gpgkeysecret != other.gpgkeysecret) return false; + if (gpgkeyvalid != other.gpgkeyvalid) return false; + if (gpgkeymail != other.gpgkeymail) return false; + if (gpgkeyname != other.gpgkeyname) return false; + if (gpgkeycomment != other.gpgkeycomment) return false; + if (gpgkeyfingerprint != other.gpgkeyfingerprint) return false; + if (gpgkeyid != other.gpgkeyid) return false; + if (gpgkeysize != other.gpgkeysize) return false; + if (gpgkeyownertrust != other.gpgkeyownertrust) return false; + if (gpgkeytrust != other.gpgkeytrust) return false; + if (gpgkeycreation != other.gpgkeycreation) return false; + if (gpgkeyexpiration != other.gpgkeyexpiration) return false; + if (gpgkeyalgo != other.gpgkeyalgo) return false; + if (gpgsublist != other.gpgsublist) return false; + return true; +} + +KgpgKey::KgpgKey(const QString &id, const uint size, const KgpgKeyTrust trust, const KgpgKeyAlgo algo, const QDateTime &date) + : d(new KgpgKeyPrivate(id, size, trust, algo, date)) +{ +} + +KgpgKey::KgpgKey(const KgpgKey &other) +{ + d = other.d; +} + +void KgpgKey::setSecret(const bool secret) +{ + d->gpgkeysecret = secret; +} + +void KgpgKey::setValid(const bool valid) +{ + d->gpgkeyvalid = valid; +} + +void KgpgKey::setName(const QString &name) +{ + d->gpgkeyname = name; +} + +void KgpgKey::setEmail(const QString &email) +{ + d->gpgkeymail = email; +} + +void KgpgKey::setComment(const QString &comment) +{ + d->gpgkeycomment = comment; +} + +void KgpgKey::setFingerprint(const QString &fingerprint) +{ + d->gpgkeyfingerprint = fingerprint; +} + +void KgpgKey::setOwnerTrust(const KgpgKeyOwnerTrust &owtrust) +{ + d->gpgkeyownertrust = owtrust; +} + +void KgpgKey::setExpiration(const QDateTime &date) +{ + d->gpgkeyexpiration = date; +} + +bool KgpgKey::secret() const +{ + return d->gpgkeysecret; +} + +bool KgpgKey::valid() const +{ + return d->gpgkeyvalid; +} + +QString KgpgKey::id() const +{ + return d->gpgkeyid.right(8); +} + +QString KgpgKey::fullId() const +{ + return d->gpgkeyid; +} + +QString KgpgKey::name() const +{ + return d->gpgkeyname; +} + +QString KgpgKey::email() const +{ + return d->gpgkeymail; +} + +QString KgpgKey::comment() const +{ + return d->gpgkeycomment; +} + +const QString &KgpgKey::fingerprint() const +{ + return d->gpgkeyfingerprint; +} + +QString KgpgKey::fingerprintBeautified() const +{ + QString fingervalue =d->gpgkeyfingerprint; + uint len = fingervalue.length(); + if ((len > 0) && (len % 4 == 0)) + for (uint n = 0; 4 * (n + 1) < len; ++n) + fingervalue.insert(5 * n + 4, QLatin1Char( ' ' )); + return fingervalue; +} + +uint KgpgKey::size() const +{ + return d->gpgkeysize; +} + +uint KgpgKey::encryptionSize() const +{ + // Get the first encryption subkey + for (int i = 0; i < d->gpgsublist->count(); ++i) { + KgpgKeySub temp = d->gpgsublist->at(i); + if (temp.type() & SKT_ENCRYPTION) { + return temp.size(); + } + } + return 0; +} + +KgpgKeyOwnerTrust KgpgKey::ownerTrust() const +{ + return d->gpgkeyownertrust; +} + +KgpgKeyTrust KgpgKey::trust() const +{ + return d->gpgkeytrust; +} + +QDateTime KgpgKey::creationDate() const +{ + return d->gpgkeycreation; +} + +QDateTime KgpgKey::expirationDate() const +{ + return d->gpgkeyexpiration; +} + +bool KgpgKey::unlimited() const +{ + return d->gpgkeyexpiration.isNull(); +} + +KgpgKeyAlgo KgpgKey::algorithm() const +{ + return d->gpgkeyalgo; +} + +KgpgKeyAlgo KgpgKey::encryptionAlgorithm() const +{ + // Get the first encryption subkey + for (int i = 0; i < d->gpgsublist->count(); ++i) { + KgpgKeySub temp = d->gpgsublist->at(i); + if (temp.type() & SKT_ENCRYPTION) { + return temp.algorithm(); + } + } + return ALGO_UNKNOWN; +} + +KgpgKeySubListPtr KgpgKey::subList() const +{ + return d->gpgsublist; +} + +bool KgpgKey::operator==(const KgpgKey &other) const +{ + if (d == other.d) return true; + if ((*d) == (*(other.d))) return true; + return false; +} + +KgpgKey& KgpgKey::operator=(const KgpgKey &other) +{ + d = other.d; + return *this; +} + +KgpgKeyList::operator QStringList() const +{ + QStringList res; + foreach(const KgpgKey &key, *this) + res << key.fullId(); + return res; +} + +//END Key + +} // namespace KgpgCore diff --git a/kgpg/core/kgpgkey.h b/kgpg/core/kgpgkey.h new file mode 100644 index 0000000..f16907c --- /dev/null +++ b/kgpg/core/kgpgkey.h @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2006,2007 Jimmy Gilles <[email protected]> + * Copyright (C) 2007,2008,2009,2010,2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KGPGKEY_H +#define KGPGKEY_H + +#include <QSharedDataPointer> +#include <QSharedData> +#include <QPointer> +#include <QObject> +#include <QList> +#include <QDateTime> + +class QStringList; + +namespace KgpgCore +{ + +//BEGIN Enums + +enum KgpgKeyAlgoFlag +{ + ALGO_UNKNOWN = 0, + ALGO_RSA = 1, + ALGO_DSA = 2, + ALGO_ELGAMAL = 4, + ALGO_DSA_ELGAMAL = ALGO_DSA | ALGO_ELGAMAL, + ALGO_RSA_RSA = 0x10001 +}; +Q_DECLARE_FLAGS(KgpgKeyAlgo, KgpgKeyAlgoFlag) +Q_DECLARE_OPERATORS_FOR_FLAGS(KgpgKeyAlgo) + +/*! \brief trust levels of keys, uids and uats + * + * These values represent the trust that you have in a public key or obe if it's + * user ids or attributes (i.e. photo ids). They are more or less ordered by + * the level of trust. Every value but the first and the last matches one trust + * value that is + */ +enum KgpgKeyTrustFlag +{ + TRUST_MINIMUM = 0, //!< internal value for use in filters + TRUST_INVALID = 1, //!< key is invalid + TRUST_DISABLED = 2, //!< key is disabled by user (not owner) + TRUST_REVOKED = 3, //!< key is revoked by owner + TRUST_EXPIRED = 4, //!< key is beyond it's expiry date + TRUST_UNDEFINED = 5, //!< trust value undefined (i.e. you did not set a trust level) + TRUST_UNKNOWN = 6, //!< trust value unknown (i.e. no entry in gpg's trust database) + TRUST_NONE = 7, //!< there is no trusted path to this key + TRUST_MARGINAL = 8, //!< there is a minimal level of trust + TRUST_FULL = 9, //!< you can fully trust this key + TRUST_ULTIMATE = 10, //!< this key has highest possible level of trust (e.g. your own secret keys) + TRUST_NOKEY = 11 //!< internal value, e.g. for key groups +}; +Q_DECLARE_FLAGS(KgpgKeyTrust, KgpgKeyTrustFlag) +Q_DECLARE_OPERATORS_FOR_FLAGS(KgpgKeyTrust) + +/*! \brief trust levels for trust in other key owners + * + * These values represent the trust that you have in other people when they + * sign keys. Once you have signed someones keys you can benefit from the + * keys they have signed if you trust them to carefully check which keys they + * sign. + */ +enum KgpgKeyOwnerTrustFlag +{ + OWTRUST_UNKNOWN = 0, //!< Trust value is unknown (e.g. no entry in trust database). + OWTRUST_UNDEFINED = 1, //!< Trust value undefined (e.g. not trust level set). + OWTRUST_NONE = 2, //!< You do not trust the key owner, keys signed by him are untrusted. + OWTRUST_MARGINAL = 3, //!< You have a minimum level of trust in the key owner. + OWTRUST_FULL = 4, //!< You believe the key owner does good checking. Keys signed by him are trusted by you, too. + OWTRUST_ULTIMATE = 5 //!< There is no doubt in this key owner. This level is used for your own secret keys. +}; +Q_DECLARE_FLAGS(KgpgKeyOwnerTrust, KgpgKeyOwnerTrustFlag) +Q_DECLARE_OPERATORS_FOR_FLAGS(KgpgKeyOwnerTrust) + +enum KgpgSubKeyTypeFlag +{ + SKT_ENCRYPTION = 0x1, + SKT_SIGNATURE = 0x2, + SKT_AUTHENTICATION = 0x4, + SKT_CERTIFICATION = 0x8 +}; +Q_DECLARE_FLAGS(KgpgSubKeyType, KgpgSubKeyTypeFlag) +Q_DECLARE_OPERATORS_FOR_FLAGS(KgpgSubKeyType) + +/*! \brief types of items in the item models + * + * Every item in the item models is of one of the following types. Some of the + * items can have properties of more than one basic type, e.g. a key pair can + * act both as a secret and a public key. Because of this the value for key + * pairs is a composite of the two "elementary" types for secret and public + * keys. Other compositions than the ones defined here must not be used to set + * an item type, but may of course be used as a mask for comparison. + */ +enum KgpgItemTypeFlag +{ + ITYPE_GROUP = 1, //!< the element is a GnuPG key group + ITYPE_SECRET = 2, //!< secret key + ITYPE_PUBLIC = 4, //!< public key + ITYPE_PAIR = ITYPE_SECRET | ITYPE_PUBLIC, //!< key pair + ITYPE_GSECRET = ITYPE_GROUP | ITYPE_SECRET, //!< secret key as member of a key group + ITYPE_GPUBLIC = ITYPE_GROUP | ITYPE_PUBLIC, //!< public key as member of a key group + ITYPE_GPAIR = ITYPE_GROUP | ITYPE_PAIR, //!< key pair as member of a key group + ITYPE_SUB = 8, //!< subkey of a public or secret key + ITYPE_UID = 16, //!< additional user id + ITYPE_UAT = 32, //!< user attribute to a key (i.e. photo id) + ITYPE_REVSIGN = 64, //!< revokation signature + ITYPE_SIGN = 128 //!< signature (to a key, uid or uat) +}; +Q_DECLARE_FLAGS(KgpgItemType, KgpgItemTypeFlag) +Q_DECLARE_OPERATORS_FOR_FLAGS(KgpgItemType) + +//END Enums + +//BEGIN KeySub + +class KgpgKeySubPrivate : public QSharedData +{ + KgpgKeySubPrivate(); +public: + KgpgKeySubPrivate(const QString &id, const uint size, const KgpgKeyTrust trust, const KgpgKeyAlgo algo, const KgpgSubKeyType type, + const QDateTime &date); + + bool gpgsubvalid; + const QString gpgsubid; + const uint gpgsubsize; + QDateTime gpgsubexpiration; + const QDateTime gpgsubcreation; + const KgpgKeyTrust gpgsubtrust; + const KgpgKeyAlgo gpgsubalgo; + const KgpgSubKeyType gpgsubtype; + + bool operator==(const KgpgKeySubPrivate &other) const; + inline bool operator!=(const KgpgKeySubPrivate &other) const + { return !operator==(other); } +}; + +class KgpgKeySub +{ + KgpgKeySub(); +public: + KgpgKeySub(const QString &id, const uint size, const KgpgKeyTrust trust, const KgpgKeyAlgo algo, const KgpgSubKeyType type, + const QDateTime &date); + KgpgKeySub(const KgpgKeySub &other); + + void setExpiration(const QDateTime &date); + void setValid(const bool valid); // FIXME : is it possible to have a subkey that is not valid (disabled)? Please give an example. Thx. If not, this method should be removed. + + QString id() const; + uint size() const; + bool unlimited() const; + QDateTime expirationDate() const; + QDateTime creationDate() const; + KgpgKeyTrust trust() const; + KgpgKeyAlgo algorithm() const; + bool valid() const; + KgpgSubKeyType type() const; + + bool operator==(const KgpgKeySub &other) const; + inline bool operator!=(const KgpgKeySub &other) const + { return !operator==(other); } + KgpgKeySub& operator=(const KgpgKeySub &other); + +private: + QSharedDataPointer<KgpgKeySubPrivate> d; +}; + +class KgpgKeySubList : public QList<KgpgKeySub>, public QObject +{ +public: + inline KgpgKeySubList() { } + inline explicit KgpgKeySubList(const KgpgKeySub &sub) { append(sub); } + inline KgpgKeySubList(const KgpgKeySubList &other) : QList<KgpgKeySub>(other), QObject() { } + inline KgpgKeySubList(const QList<KgpgKeySub> &other) : QList<KgpgKeySub>(other), QObject() { } + + inline KgpgKeySubList operator+(const KgpgKeySubList &other) const + { + KgpgKeySubList n = *this; + n += other; + return n; + } + + inline KgpgKeySubList &operator<<(KgpgKeySub sub) + { + append(sub); + return *this; + } + + inline KgpgKeySubList &operator<<(const KgpgKeySubList &l) + { + *this += l; + return *this; + } +}; +typedef QPointer<KgpgKeySubList> KgpgKeySubListPtr; + +//END KeySub + + +//BEGIN Key + +class KgpgKeyPrivate : public QSharedData +{ + KgpgKeyPrivate(); +public: + KgpgKeyPrivate(const QString &id, const uint size, const KgpgKeyTrust trust, const KgpgKeyAlgo algo, const QDateTime &date); + + bool gpgkeysecret; + bool gpgkeyvalid; + QString gpgkeymail; + QString gpgkeyname; + QString gpgkeycomment; + QString gpgkeyfingerprint; + const QString gpgkeyid; + const uint gpgkeysize; + KgpgKeyOwnerTrust gpgkeyownertrust; + const KgpgKeyTrust gpgkeytrust; + const QDateTime gpgkeycreation; + QDateTime gpgkeyexpiration; + const KgpgKeyAlgo gpgkeyalgo; + + KgpgKeySubListPtr gpgsublist; + + bool operator==(const KgpgKeyPrivate &other) const; + inline bool operator!=(const KgpgKeyPrivate &other) const + { return !operator==(other); } +}; + +class KgpgKey +{ + KgpgKey(); +public: + KgpgKey(const QString &id, const uint size, const KgpgKeyTrust trust, const KgpgKeyAlgo algo, const QDateTime &date); + KgpgKey(const KgpgKey &other); + + void setSecret(const bool secret); + void setValid(const bool valid); + void setName(const QString &name); + void setEmail(const QString &email); + void setComment(const QString &comment); + void setFingerprint(const QString &fingerprint); + void setOwnerTrust(const KgpgKeyOwnerTrust &owtrust); + void setExpiration(const QDateTime &date); + + bool secret() const; + bool valid() const; + QString id() const; + QString fullId() const; + QString name() const; + QString email() const; + QString comment() const; + const QString &fingerprint() const; + QString fingerprintBeautified() const; + uint size() const; + uint encryptionSize() const; + KgpgKeyOwnerTrust ownerTrust() const; + KgpgKeyTrust trust() const; + QDateTime creationDate() const; + QDateTime expirationDate() const; + bool unlimited() const; + KgpgKeyAlgo algorithm() const; + KgpgKeyAlgo encryptionAlgorithm() const; + + KgpgKeySubListPtr subList() const; + + bool operator==(const KgpgKey &other) const; + inline bool operator!=(const KgpgKey &other) const + { return !operator==(other); } + KgpgKey& operator=(const KgpgKey &other); + +private: + QSharedDataPointer<KgpgKeyPrivate> d; +}; + +class KgpgKeyList : public QList<KgpgKey>, public QObject +{ +public: + inline KgpgKeyList() { } + inline explicit KgpgKeyList(const KgpgKey &key) { append(key); } + inline KgpgKeyList(const KgpgKeyList &other) : QList<KgpgKey>(other), QObject() { } + inline KgpgKeyList(const QList<KgpgKey> &other) : QList<KgpgKey>(other), QObject() { } + + inline KgpgKeyList& operator=(const KgpgKeyList &other) + { + QList<KgpgKey>::operator=(static_cast<const QList<KgpgKey> >(other)); + return *this; + } + + inline KgpgKeyList operator+(const KgpgKeyList &other) const + { + KgpgKeyList n = *this; + n += other; + return n; + } + + inline KgpgKeyList &operator<<(KgpgKey key) + { + append(key); + return *this; + } + + inline KgpgKeyList &operator<<(const KgpgKeyList &l) + { + *this += l; + return *this; + } + + operator QStringList() const; +}; + +//END Key + +} // namespace + +#endif // KGPGKEY_H diff --git a/kgpg/gpgproc.cpp b/kgpg/gpgproc.cpp new file mode 100644 index 0000000..10f2845 --- /dev/null +++ b/kgpg/gpgproc.cpp @@ -0,0 +1,370 @@ +/* + * Copyright (C) 2007,2008,2009,2010,2011,2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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 "gpgproc.h" + +//#include "kgpgsettings.h" + +//#include <KDebug> +#include <QDebug> +//#include <KProcess> +#include "kprocess.h" +//#include <KStandardDirs> +#include <QDir> +#include <QTextCodec> + +class GnupgBinary { +public: + GnupgBinary(); + + const QString &binary() const; + void setBinary(const QString &executable); + const QStringList &standardArguments() const; + unsigned int version() const; + bool supportsDebugLevel() const; + //static GnupgBinary* instance(); + +private: + QString m_binary; + QStringList m_standardArguments; + unsigned int m_version; + bool m_useDebugLevel; +}; + +GnupgBinary::GnupgBinary() + : m_useDebugLevel(false) +{ +} + +const QString &GnupgBinary::binary() const +{ + return m_binary; +} + +/** + * @brief check if GnuPG returns an error for this arguments + * @param executable the GnuPG executable to call + * @param arguments the arguments to pass to executable + * + * The arguments will be used together with "--version", so they should not + * be any commands. + */ +static bool checkGnupgArguments(const QString &executable, const QStringList &arguments) +{ + KProcess gpg; + + // We ignore the output anyway, just make sure it doesn't clutter the output of + // the parent process. Simplify the handling by putting all trash in one can. + gpg.setOutputChannelMode(KProcess::MergedChannels); + + QStringList allArguments = arguments; + allArguments << QLatin1String("--version"); + gpg.setProgram(executable, allArguments); + + return (gpg.execute() == 0); +} + +static QString getGpgProcessHome(const QString &binary) +{ + GPGProc process(0, binary); + process << QLatin1String( "--version" ); + process.start(); + process.waitForFinished(-1); + + if (process.exitCode() == 255) { + return QString(); + } + + QString line; + while (process.readln(line) != -1) { + if (line.startsWith(QLatin1String("Home: "))) { + line.remove(0, 6); + return line; + } + } + + return QString(); +} + + +void GnupgBinary::setBinary(const QString &executable) +{ + qDebug() << "checking version of GnuPG executable" << executable; + // must be set first as gpgVersionString() uses GPGProc to parse the output + m_binary = executable; + const QString verstr = GPGProc::gpgVersionString(executable); + m_version = GPGProc::gpgVersion(verstr); + qDebug() << "version is" << verstr << m_version; + + m_useDebugLevel = (m_version > 0x20000); + + const QString gpgConfigFile = "";//KGpgSettings::gpgConfigPath(); + + m_standardArguments.clear(); + m_standardArguments << QLatin1String( "--no-secmem-warning" ) + << QLatin1String( "--no-tty" ) + << QLatin1String("--no-greeting") + << QLatin1String("--homedir") << GPGProc::getGpgHome(""); + + if (!gpgConfigFile.isEmpty()) + m_standardArguments << QLatin1String("--options") + << gpgConfigFile; + + QStringList debugLevelArguments(QLatin1String("--debug-level")); + debugLevelArguments << QLatin1String("none"); + if (checkGnupgArguments(executable, debugLevelArguments)) + m_standardArguments << debugLevelArguments; +} + +const QStringList& GnupgBinary::standardArguments() const +{ + return m_standardArguments; +} + +unsigned int GnupgBinary::version() const +{ + return m_version; +} + +bool GnupgBinary::supportsDebugLevel() const +{ + return m_useDebugLevel; +} + +Q_GLOBAL_STATIC(GnupgBinary, lastBinary) + +GPGProc::GPGProc(QObject *parent, const QString &binary) + : KLineBufferedProcess(parent) +{ + resetProcess(binary); +} + +GPGProc::~GPGProc() +{ +} + +void +GPGProc::resetProcess(const QString &binary) +{ + GnupgBinary *bin = lastBinary(); + QString executable; + + //qDebug() << "bin:" << binary; + + if (binary.isEmpty()) { + //executable = KGpgSettings::gpgBinaryPath(); + QString appPath = qApp->applicationDirPath(); + QString gpgBin; + #ifdef Q_WS_WIN + gpgBin = appPath + "/bin/gpg.exe"; + #endif + #ifdef Q_WS_MAC + gpgBin = appPath + "/gpg-mac"; + #endif + #ifdef Q_WS_X11 + gpgBin = appPath + "/bin/gpg"; + #endif + executable = gpgBin; + } else + executable = binary; + + if (bin->binary() != executable) + bin->setBinary(executable); + //qDebug() << "ex: " << executable; + setProgram(executable, bin->standardArguments()); + + setOutputChannelMode(OnlyStdoutChannel); + + disconnect(SIGNAL(finished(int,QProcess::ExitStatus))); + disconnect(SIGNAL(lineReadyStandardOutput())); +} + +void GPGProc::start() +{ + // make sure there is exactly one connection from us to that signal + connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished()), Qt::UniqueConnection); + connect(this, SIGNAL(lineReadyStandardOutput()), this, SLOT(received()), Qt::UniqueConnection); + KProcess::start(); +} + +void GPGProc::received() +{ + emit readReady(); +} + +void GPGProc::finished() +{ + emit processExited(); +} + +int GPGProc::readln(QString &line, const bool colons) +{ + QByteArray a; + if (!readLineStandardOutput(&a)) + return -1; + + line = recode(a, colons); + + return line.length(); +} + +int GPGProc::readln(QStringList &l) +{ + QString s; + + int len = readln(s); + if (len < 0) + return len; + + l = s.split(QLatin1Char( ':' )); + + for (int i = 0; i < l.count(); ++i) + { + int j = 0; + while ((j = l[i].indexOf(QLatin1String( "\\x3a" ), j, Qt::CaseInsensitive)) >= 0) + { + l[i].replace(j, 4, QLatin1Char( ':' )); + j++; + } + } + + return l.count(); +} + +QString +GPGProc::recode(QByteArray a, const bool colons) +{ + int pos = 0; + + while ((pos = a.indexOf("\\x", pos)) >= 0) { + if (pos > a.length() - 4) + break; + + const QByteArray pattern(a.mid(pos, 4)); + const QByteArray hexnum(pattern.right(2)); + bool ok; + char n[2]; + n[0] = hexnum.toUShort(&ok, 16); + n[1] = '\0'; // to use n as a 0-terminated string + if (!ok) + continue; + + // QLatin1Char( ':' ) must be skipped, it is used as column delimiter + // since it is pure ascii it can be replaced in QString. + if (!colons && (n[0] == ':' )) { + pos += 3; + continue; + } + + // it is likely to find the same byte sequence more than once + int npos = pos; + do { + a.replace(npos, 4, n); + } while ((npos = a.indexOf(pattern, npos)) >= 0); + } + + return QTextCodec::codecForName("utf8")->toUnicode(a); +} + +int GPGProc::gpgVersion(const QString &vstr) +{ + if (vstr.isEmpty()) + return -1; + + QStringList values(vstr.split(QLatin1Char( '.' ))); + if (values.count() < 3) + return -2; + + return (0x10000 * values[0].toInt() + 0x100 * values[1].toInt() + values[2].toInt()); +} + +QString GPGProc::gpgVersionString(const QString &binary) +{ + GPGProc process(0, binary); + process << QLatin1String( "--version" ); + process.start(); + process.waitForFinished(-1); + + if (process.exitCode() == 255) { + qDebug() << "exit255"; + return QString(); + } + + QString line; + if (process.readln(line) != -1) { + qDebug() << line; + return line.simplified().section(QLatin1Char( ' ' ), -1); + } else { + qDebug() << "no readln"; + return QString(); + } +} + +QString GPGProc::getGpgStartupError(const QString &binary) +{ + GPGProc process(0, binary); + process << QLatin1String( "--version" ); + process.start(); + process.waitForFinished(-1); + + QString result; + + while (process.hasLineStandardError()) { + QByteArray tmp; + process.readLineStandardError(&tmp); + tmp += '\n'; + result += QString::fromUtf8(tmp); + } + + return result; +} + +QString GPGProc::getGpgHome(const QString &binary) +{ + // First try: if environment is set GnuPG will use that directory + // We can use this directly without starting a new process +/* QByteArray env(qgetenv("GNUPGHOME")); + QString gpgHome; + if (!env.isEmpty()) { + gpgHome = QLatin1String( env ); + } else if (!binary.isEmpty()) { + // Second try: start GnuPG and ask what it is + gpgHome = getGpgProcessHome(binary); + } + + // Third try: guess what it is. + if (gpgHome.isEmpty()) { +#ifdef Q_OS_WIN32 //krazy:exclude=cpp + gpgHome = qgetenv("APPDATA") + QLatin1String( "/gnupg/" ); + gpgHome.replace(QLatin1Char( '\\' ), QLatin1Char( '/' )); +#else + gpgHome = QDir::homePath() + QLatin1String( "/.gnupg/" ); +#endif + } + + gpgHome.replace(QLatin1String( "//" ), QLatin1String( "/" )); + + if (!gpgHome.endsWith(QLatin1Char( '/' ))) + gpgHome.append(QLatin1Char( '/' )); + + if (gpgHome.startsWith(QLatin1Char( '~' ))) + gpgHome.replace(0, 1, QDir::homePath()); + + //KStandardDirs::makeDir(gpgHome, 0700);*/ + QString appPath = qApp->applicationDirPath(); + QString gpgHome = appPath + "/keydb"; + + return gpgHome; +} + +//#include "gpgproc.moc" diff --git a/kgpg/gpgproc.h b/kgpg/gpgproc.h new file mode 100644 index 0000000..7f9ae9b --- /dev/null +++ b/kgpg/gpgproc.h @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2007 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef GPGPROC_H +#define GPGPROC_H + +#include <QString> +#include <QStringList> +#include <QApplication> + +#include "klinebufferedprocess.h" + +/** + * @brief A interface to GnuPG handling UTF8 recoding correctly + * + * This class handles the GnuPG formatted UTF8 output correctly. + * GnuPG recodes some characters as \\xnn where nn is the hex representation + * of the character. This can't be fixed up simply when using QString as + * QString already did it's own UTF8 conversion. Therefore we replace this + * sequences by their corresponding character so QString will work just fine. + * + * As we know that GnuPG limits it's columns by QLatin1Char( ':' ) we skip \\x3a. Since this + * is an ascii character (single byte) the replacement can be done later without + * problems after the line has been split into pieces. + * + * @author Rolf Eike Beer + */ +class GPGProc : public KLineBufferedProcess +{ + Q_OBJECT + +public: + /** + * Constructor + * @param parent parent object + * @param binary path to GnuPG binary or QString() to use the configured + */ + explicit GPGProc(QObject *parent = 0, const QString &binary = QString()); + + /** + * Destructor + */ + ~GPGProc(); + + /** + * Starts the process + */ + void start(); + + /** + * Reads a line of text (excluding '\\n'). + * + * Use readln() in response to a readReady() signal. + * You may use it multiple times if more than one line of data is + * available. + * + * readln() never blocks. + * + * @param line is used to store the line that was read. + * @param colons recode also colons + * @return the number of characters read, or -1 if no data is available. + */ + int readln(QString &line, const bool colons = false); + + /** + * Reads a line of text and splits it into parts. + * + * Use readln() in response to a readReady() signal. + * You may use it multiple times if more than one line of data is + * available. + * + * readln() never blocks. + * + * @param l is used to store the parts of the line that was read. + * @return the number of characters read, or -1 if no data is available. + */ + int readln(QStringList &l); + + /** + * Recode a line from GnuPG encoding to UTF8 + * + * @param a data to recode + * @param colons recode also colons + * @return recoded string + */ + static QString recode(QByteArray a, const bool colons = true); + + /** + * Reset the class to the state it had right after creation + * @param binary path to GnuPG binary or empty string to use the configured one + */ + void resetProcess(const QString &binary = QString()); + + /** + * @brief parse GnuPG version string and return version as number + * @param vstr version string + * @return -1 if vstr is empty, -2 on parse error, parsed number on success + * + * The version string must be in format A.B.C with A, B, and C numbers. The + * returned number is A * 65536 + B * 256 + C. + */ + static int gpgVersion(const QString &vstr); + /** + * @brief get the GnuPG version string of the given binary + * @param binary name or path to GnuPG binary + * @return version string or empty string on error + * + * This starts a GnuPG process and asks the binary for version information. + * The returned string is the version information without any leading text. + */ + static QString gpgVersionString(const QString &binary); + /** + * @brief find users GnuPG directory + * @param binary name or path to GnuPG binary + * @return path to directory + * + * Use this function to find out where GnuPG would store it's configuration + * and data files. The returned path always ends with a '/'. + */ + static QString getGpgHome(const QString &binary); + + /** + * @brief run GnuPG and check if it complains about anything + * @param binary the GnuPG binary to run + * @return the error message GnuPG gave out (if any) + */ + static QString getGpgStartupError(const QString &binary); + +signals: + /** + * Emitted when the process is ready for reading. + * The signal is only emitted if at least one complete line of data is ready. + * @param p the process that emitted the signal + */ + void readReady(); + + /** + * Emitted when the process has finished + * @param p the process that emitted the signal + */ + void processExited(); + +protected slots: + void finished(); + void received(); +}; + +#endif // GPGPROC_H diff --git a/kgpg/kgpginterface.cpp b/kgpg/kgpginterface.cpp new file mode 100644 index 0000000..8632897 --- /dev/null +++ b/kgpg/kgpginterface.cpp @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2002 Jean-Baptiste Mardelle <[email protected]> + * Copyright (C) 2007,2008,2009,2010,2011,2012 + * Rolf Eike Beer <[email protected]> + */ +/*************************************************************************** + * * + * 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 <KConfig> +#include <KDebug> +#include <KGlobal> +#include <KLocale> +#include <KMessageBox> +#include <KPasswordDialog> +#include <KProcess> +#include <KPushButton>*/ +#include <QFile> +#include <QPointer> +#include <QString> +#include <QTextStream> +#include <QDebug> +#include <QInputDialog> + +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(); + } + } +} + +int KgpgInterface::sendPassphrase(const QString &text, KProcess *process, QWidget *widget) +{ + qDebug() << "KgpgInterface::sendPassphrase called"; + + QPointer<KProcess> gpgprocess = process; + QByteArray passphrase; + //int code; + bool ok; + + /*QPointer<KPasswordDialog> dlg = new KPasswordDialog(widget); + QObject::connect(process, SIGNAL(processExited()), dlg->button(KDialog::Cancel), SLOT(click())); + dlg->setPrompt(text); + code = dlg->exec(); + + if (!dlg.isNull()) + passphrase = dlg->password().toUtf8(); + delete dlg; + + if (code != KPasswordDialog::Accepted) + return 1; +*/ + + QString password = QInputDialog::getText(QApplication::activeWindow(), QObject::tr("Enter Password"), + text, QLineEdit::Password, + "", &ok); + + if(!ok) return 1; + + passphrase = password.toAscii(); + + if (!gpgprocess.isNull()) { + gpgprocess->write(passphrase + '\n'); + } + + return 0; +} + +/** + * @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)) { + publiclistkeys << KgpgKey(lsp.at(4), lsp.at(2).toUInt(), Convert::toTrust(lsp.at(1)), + Convert::toAlgo(lsp.at(3).toInt()), QDateTime::fromTime_t(lsp.at(5).toUInt())); + + publickey = &publiclistkeys.last(); + + publickey->setOwnerTrust(Convert::toOwnerTrust(lsp.at(8))); + + if (lsp.at(6).isEmpty()) + publickey->setExpiration(QDateTime()); + else + publickey->setExpiration(QDateTime::fromTime_t(lsp.at(6).toUInt())); + + publickey->setValid((items <= 11) || !lsp.at(11).contains(QLatin1Char( 'D' ), Qt::CaseSensitive)); // disabled key + + idIndex = 0; + } else if ((lsp.at(0) == QLatin1String( "fpr" )) && (items >= 10)) { + const QString fingervalue(lsp.at(9)); + + publickey->setFingerprint(fingervalue); + } else if ((lsp.at(0) == QLatin1String( "sub" )) && (items >= 7)) { + KgpgSubKeyType subtype; + + if (items > 11) { + if (lsp.at(11).contains(QLatin1Char( 's' ))) + subtype |= SKT_SIGNATURE; + if (lsp.at(11).contains(QLatin1Char( 'e' ))) + subtype |= SKT_ENCRYPTION; + if (lsp.at(11).contains(QLatin1Char( 'e' ))) + subtype |= SKT_AUTHENTICATION; + if (lsp.at(11).contains(QLatin1Char( 'e' ))) + subtype |= SKT_CERTIFICATION; + } + + 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 (lsp.at(0) == QLatin1String( "uat" )) { + idIndex++; + if (readNode != NULL) { + currentSNode = new KGpgUatNode(readNode, idIndex, lsp); + } + } else if ((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 (((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); + qDebug() << "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("--homedir") << GPGProc::getGpgHome("") << + 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 = true; + KgpgCore::KgpgKeyList result; + KgpgCore::KgpgKey *secretkey = NULL; + + while ( (items = p.readln(lsp)) >= 0 ) { + if ((lsp.at(0) == QLatin1String( "sec" )) && (items >= 10)) { + result << KgpgKey(lsp.at(4), lsp.at(2).toUInt(), Convert::toTrust(lsp.at(1)), + Convert::toAlgo(lsp.at(3).toInt()), 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 "kgpginterface.moc" diff --git a/kgpg/kgpginterface.h b/kgpg/kgpginterface.h new file mode 100644 index 0000000..1ed0e53 --- /dev/null +++ b/kgpg/kgpginterface.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2002 Jean-Baptiste Mardelle <[email protected]> + * Copyright (C) 2007,2008,2009,2010,2011,2012 + * Rolf Eike Beer <[email protected]> + */ +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KGPGINTERFACE_H +#define KGPGINTERFACE_H + +#include "core/kgpgkey.h" +#include <QStringList> + +class KGpgKeyNode; +class KProcess; +class QString; +class QApplication; + +/** + * GnuPG interface functions + */ +namespace KgpgInterface { + QString getGpgSetting(const QString &name, const QString &configfile); + void setGpgSetting(const QString &name, const QString &value, const QString &url); + + bool getGpgBoolSetting(const QString &name, const QString &configfile); + void setGpgBoolSetting(const QString &name, const bool enable, const QString &url); + + /** + * @brief ask the user for a passphrase and send it to the given gpg process + * @param text text is the message that must be displayed in the MessageBox + * @param process GnuPG process + * @param isnew if the password is a \e new password that must be confirmed. Default is true + * @param widget parent widget of this dialog or NULL + * @return 0 if there is no error + * @return 1 if there is an error + */ + int sendPassphrase(const QString &text, KProcess *process, QWidget *widget = NULL); + + KgpgCore::KgpgKeyList readPublicKeys(const QStringList &ids = QStringList()); + void readSignatures(KGpgKeyNode *node); + KgpgCore::KgpgKeyList readSecretKeys(const QStringList &ids = QStringList()); +}; + +#endif // KGPGINTERFACE_H diff --git a/kgpg/klinebufferedprocess.cpp b/kgpg/klinebufferedprocess.cpp new file mode 100644 index 0000000..00099af --- /dev/null +++ b/kgpg/klinebufferedprocess.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2008 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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 "klinebufferedprocess.h" + + +KLineBufferedProcessPrivate::KLineBufferedProcessPrivate(KLineBufferedProcess *parent) + : m_newlineInStdout(-1), + m_newlineInStderr(-1), + m_parent(parent), +#ifdef Q_OS_WIN32 //krazy:exclude=cpp + m_lineEnd("\r\n") +#else + m_lineEnd("\n") +#endif +{ +} + +KLineBufferedProcess::KLineBufferedProcess(QObject *parent) + : KProcess(parent), + d(new KLineBufferedProcessPrivate(this)) +{ + connect(this, SIGNAL(readyReadStandardOutput()), this, SLOT(_k_receivedStdout())); + connect(this, SIGNAL(readyReadStandardError()), this, SLOT(_k_receivedStderr())); +} + +KLineBufferedProcess::~KLineBufferedProcess() +{ + delete d; +} + +void KLineBufferedProcessPrivate::_k_receivedStdout() +{ + QByteArray ndata = m_parent->readAllStandardOutput(); + int oldBufferSize = m_stdoutBuffer.size(); + m_stdoutBuffer.append(ndata); + + if (m_newlineInStdout < 0) { + m_newlineInStdout = ndata.indexOf(m_lineEnd); + if (m_newlineInStdout >= 0) { + m_newlineInStdout += oldBufferSize; + emit m_parent->lineReadyStandardOutput(); + } + } +} + +void KLineBufferedProcessPrivate::_k_receivedStderr() +{ + QByteArray ndata = m_parent->readAllStandardError(); + int oldBufferSize = m_stderrBuffer.size(); + m_stderrBuffer.append(ndata); + + if (m_newlineInStderr < 0) { + m_newlineInStderr = ndata.indexOf(m_lineEnd); + if (m_newlineInStderr >= 0) { + m_newlineInStderr += oldBufferSize; + emit m_parent->lineReadyStandardError(); + } + } +} + +bool KLineBufferedProcess::readLineStandardOutput(QByteArray *line) +{ + if (d->m_newlineInStdout < 0) { + return false; + } + + // don't copy '\n' + *line = d->m_stdoutBuffer.left(d->m_newlineInStdout); + d->m_stdoutBuffer.remove(0, d->m_newlineInStdout + d->m_lineEnd.length()); + + d->m_newlineInStdout = d->m_stdoutBuffer.indexOf(d->m_lineEnd); + + return true; +} + +bool KLineBufferedProcess::readLineStandardError(QByteArray *line) +{ + if (d->m_newlineInStderr < 0) { + return false; + } + + // don't copy '\n' + *line = d->m_stderrBuffer.left(d->m_newlineInStderr); + d->m_stderrBuffer.remove(0, d->m_newlineInStderr + d->m_lineEnd.length()); + + d->m_newlineInStderr = d->m_stderrBuffer.indexOf(d->m_lineEnd); + + return true; +} + +bool KLineBufferedProcess::hasLineStandardOutput() const +{ + return d->m_newlineInStdout >= 0; +} + +bool KLineBufferedProcess::hasLineStandardError() const +{ + return d->m_newlineInStderr >= 0; +} + +//#include "moc_klinebufferedprocess.cpp" diff --git a/kgpg/klinebufferedprocess.h b/kgpg/klinebufferedprocess.h new file mode 100644 index 0000000..eab360b --- /dev/null +++ b/kgpg/klinebufferedprocess.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2008 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KLINEBUFFEREDPROCESS_H +#define KLINEBUFFEREDPROCESS_H + +#include "kprocess.h" + +class QByteArray; +//class KLineBufferedProcessPrivate; +class KLineBufferedProcess; +class KLineBufferedProcessPrivate +{ +public: + KLineBufferedProcessPrivate(KLineBufferedProcess *parent); + +//private slot implementations + void _k_receivedStdout(); + void _k_receivedStderr(); + + QByteArray m_stdoutBuffer; + QByteArray m_stderrBuffer; + int m_newlineInStdout; + int m_newlineInStderr; + KLineBufferedProcess * const m_parent; + const QByteArray m_lineEnd; +}; + +/** + * Read output of a process split into lines + * + * This class reads the output of a process and splits it up into lines. This + * is especially useful if you try to parse the output of a command line tool. + * + * \b Usage \n + * + * The class is created and set up like a KProcess. After this you can do + * something like this: + * + * \code + * connect(m_linebufprocess, SIGNAL(lineReadyStandardOutput()), SLOT(dataStdout())); + * ... + * void myobj::dataStdout() + * { + * while (m_linebufprocess->hasLineStandardOutput()) { + * QByteArray line; + * m_linebufprocess->readLineStandardOutput(line); + * ... + * } + * } + * \endcode + * + * Never use the read functionality of KProcess with this class. This class + * needs to read all data from the process into an internal buffer first. If + * you try to use the read functions of the parent classes you would normally + * get no output at all. + * + * The write functions of the parent classes are not effected. You can use + * them exactly the same way as in KProcess. + * + * @author Rolf Eike Beer + */ +class KLineBufferedProcess : public KProcess +{ + Q_OBJECT + friend class KLineBufferedProcessPrivate; + +public: + /** + * Constructor + */ + explicit KLineBufferedProcess(QObject *parent = 0); + + /** + * Destructor + */ + ~KLineBufferedProcess(); + + /** + * Reads a line of text (excluding '\\n') from stdout. + * + * Use readLineStdout() in response to a lineReadyStdout() signal or + * when hasLineStdout() returns true. You may use it multiple times if + * more than one line of data is available. If no complete line is + * available the content of line is undefined and the function returns + * false. + * + * @param line is used to store the line that was read. + * @return if data was read or not + */ + bool readLineStandardOutput(QByteArray *line); + + /** + * Reads a line of text (excluding '\\n') from stderr. + * + * Use readLineStderr() in response to a lineReadyStderr() signal or + * when hasLineStderr() returns true. You may use it multiple times if + * more than one line of data is available. If no complete line is + * available the content of line is undefined and the function returns + * false. + * + * @param line is used to store the line that was read. + * @return if data was read or not + */ + bool readLineStandardError(QByteArray *line); + + /** + * Checks if a line is ready on stdout + * + * @return true if a complete line can be read + */ + bool hasLineStandardOutput() const; + + /** + * Checks if a line is ready on stdout + * + * @return true if a complete line can be read + */ + bool hasLineStandardError() const; + +signals: + /** + * Emitted when there is a line of data available from stdout when there was + * previously none. + * There may or may not be more than one line available for reading when this + * signal is emitted. + */ + void lineReadyStandardOutput(); + + /** + * Emitted when there is a line of data available from stderr when there was + * previously none. + * There may or may not be more than one line available for reading when this + * signal is emitted. + */ + void lineReadyStandardError(); + +private: + KLineBufferedProcessPrivate* const d; + + Q_PRIVATE_SLOT(d, void _k_receivedStdout()) + Q_PRIVATE_SLOT(d, void _k_receivedStderr()) +}; + +#endif // KLINEBUFFEREDPROCESS_H diff --git a/kgpg/kprocess.cpp b/kgpg/kprocess.cpp new file mode 100644 index 0000000..907c75c --- /dev/null +++ b/kgpg/kprocess.cpp @@ -0,0 +1,411 @@ +/* + This file is part of the KDE libraries + + Copyright (C) 2007 Oswald Buddenhagen <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kprocess_p.h" + +//#include <kstandarddirs.h> +//#include <kshell.h> +//#ifdef Q_OS_WIN +//# include <kshell_p.h> +//#endif + +#include <qfile.h> +#include <QDebug> + +#ifdef Q_OS_WIN +# include <windows.h> +#else +# include <unistd.h> +# include <errno.h> +#endif + +#ifndef Q_OS_WIN +# define STD_OUTPUT_HANDLE 1 +# define STD_ERROR_HANDLE 2 +#endif + +#ifdef _WIN32_WCE +#include <stdio.h> +#endif + +void KProcessPrivate::writeAll(const QByteArray &buf, int fd) +{ +#ifdef Q_OS_WIN +#ifndef _WIN32_WCE + HANDLE h = GetStdHandle(fd); + if (h) { + DWORD wr; + WriteFile(h, buf.data(), buf.size(), &wr, 0); + } +#else + fwrite(buf.data(), 1, buf.size(), (FILE*)fd); +#endif +#else + int off = 0; + do { + int ret = ::write(fd, buf.data() + off, buf.size() - off); + if (ret < 0) { + if (errno != EINTR) + return; + } else { + off += ret; + } + } while (off < buf.size()); +#endif +} + +void KProcessPrivate::forwardStd(KProcess::ProcessChannel good, int fd) +{ + Q_Q(KProcess); + + QProcess::ProcessChannel oc = q->readChannel(); + q->setReadChannel(good); + writeAll(q->readAll(), fd); + q->setReadChannel(oc); +} + +void KProcessPrivate::_k_forwardStdout() +{ +#ifndef _WIN32_WCE + forwardStd(KProcess::StandardOutput, STD_OUTPUT_HANDLE); +#else + forwardStd(KProcess::StandardOutput, (int)stdout); +#endif +} + +void KProcessPrivate::_k_forwardStderr() +{ +#ifndef _WIN32_WCE + forwardStd(KProcess::StandardError, STD_ERROR_HANDLE); +#else + forwardStd(KProcess::StandardError, (int)stderr); +#endif +} + +///////////////////////////// +// public member functions // +///////////////////////////// + +KProcess::KProcess(QObject *parent) : + QProcess(parent), + d_ptr(new KProcessPrivate) +{ + d_ptr->q_ptr = this; + setOutputChannelMode(ForwardedChannels); +} + +KProcess::KProcess(KProcessPrivate *d, QObject *parent) : + QProcess(parent), + d_ptr(d) +{ + d_ptr->q_ptr = this; + setOutputChannelMode(ForwardedChannels); +} + +KProcess::~KProcess() +{ + delete d_ptr; +} + +void KProcess::setOutputChannelMode(OutputChannelMode mode) +{ + Q_D(KProcess); + + d->outputChannelMode = mode; + disconnect(this, SIGNAL(readyReadStandardOutput())); + disconnect(this, SIGNAL(readyReadStandardError())); + switch (mode) { + case OnlyStdoutChannel: + connect(this, SIGNAL(readyReadStandardError()), SLOT(_k_forwardStderr())); + break; + case OnlyStderrChannel: + connect(this, SIGNAL(readyReadStandardOutput()), SLOT(_k_forwardStdout())); + break; + default: + QProcess::setProcessChannelMode((ProcessChannelMode)mode); + return; + } + QProcess::setProcessChannelMode(QProcess::SeparateChannels); +} + +KProcess::OutputChannelMode KProcess::outputChannelMode() const +{ + Q_D(const KProcess); + + return d->outputChannelMode; +} + +void KProcess::setNextOpenMode(QIODevice::OpenMode mode) +{ + Q_D(KProcess); + + d->openMode = mode; +} + +#define DUMMYENV "_KPROCESS_DUMMY_=" + +void KProcess::clearEnvironment() +{ + setEnvironment(QStringList() << QString::fromLatin1(DUMMYENV)); +} + +void KProcess::setEnv(const QString &name, const QString &value, bool overwrite) +{ + QStringList env = environment(); + if (env.isEmpty()) { + env = systemEnvironment(); + env.removeAll(QString::fromLatin1(DUMMYENV)); + } + QString fname(name); + fname.append(QLatin1Char('=')); + for (QStringList::Iterator it = env.begin(); it != env.end(); ++it) + if ((*it).startsWith(fname)) { + if (overwrite) { + *it = fname.append(value); + setEnvironment(env); + } + return; + } + env.append(fname.append(value)); + setEnvironment(env); +} + +void KProcess::unsetEnv(const QString &name) +{ + QStringList env = environment(); + if (env.isEmpty()) { + env = systemEnvironment(); + env.removeAll(QString::fromLatin1(DUMMYENV)); + } + QString fname(name); + fname.append(QLatin1Char('=')); + for (QStringList::Iterator it = env.begin(); it != env.end(); ++it) + if ((*it).startsWith(fname)) { + env.erase(it); + if (env.isEmpty()) + env.append(QString::fromLatin1(DUMMYENV)); + setEnvironment(env); + return; + } +} + +void KProcess::setProgram(const QString &exe, const QStringList &args) +{ + Q_D(KProcess); + + d->prog = exe; + d->args = args; +#ifdef Q_OS_WIN + setNativeArguments(QString()); +#endif +} + +void KProcess::setProgram(const QStringList &argv) +{ + Q_D(KProcess); + + Q_ASSERT( !argv.isEmpty() ); + d->args = argv; + d->prog = d->args.takeFirst(); +#ifdef Q_OS_WIN + setNativeArguments(QString()); +#endif +} + +KProcess &KProcess::operator<<(const QString &arg) +{ + Q_D(KProcess); + + if (d->prog.isEmpty()) + d->prog = arg; + else + d->args << arg; + return *this; +} + +KProcess &KProcess::operator<<(const QStringList &args) +{ + Q_D(KProcess); + + if (d->prog.isEmpty()) + setProgram(args); + else + d->args << args; + return *this; +} + +void KProcess::clearProgram() +{ + Q_D(KProcess); + + d->prog.clear(); + d->args.clear(); +#ifdef Q_OS_WIN + setNativeArguments(QString()); +#endif +} + +/*void KProcess::setShellCommand(const QString &cmd) +{ + Q_D(KProcess); + + KShell::Errors err; + d->args = KShell::splitArgs( + cmd, KShell::AbortOnMeta | KShell::TildeExpand, &err); + if (err == KShell::NoError && !d->args.isEmpty()) { + d->prog = KStandardDirs::findExe(d->args[0]); + if (!d->prog.isEmpty()) { + d->args.removeFirst(); +#ifdef Q_OS_WIN + setNativeArguments(QString()); +#endif + return; + } + } + + d->args.clear(); + +#ifdef Q_OS_UNIX +// #ifdef NON_FREE // ... as they ship non-POSIX /bin/sh +# if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__GNU__) + // If /bin/sh is a symlink, we can be pretty sure that it points to a + // POSIX shell - the original bourne shell is about the only non-POSIX + // shell still in use and it is always installed natively as /bin/sh. + d->prog = QFile::symLinkTarget(QString::fromLatin1("/bin/sh")); + if (d->prog.isEmpty()) { + // Try some known POSIX shells. + d->prog = KStandardDirs::findExe(QString::fromLatin1("ksh")); + if (d->prog.isEmpty()) { + d->prog = KStandardDirs::findExe(QString::fromLatin1("ash")); + if (d->prog.isEmpty()) { + d->prog = KStandardDirs::findExe(QString::fromLatin1("bash")); + if (d->prog.isEmpty()) { + d->prog = KStandardDirs::findExe(QString::fromLatin1("zsh")); + if (d->prog.isEmpty()) + // We're pretty much screwed, to be honest ... + d->prog = QString::fromLatin1("/bin/sh"); + } + } + } + } +# else + d->prog = QString::fromLatin1("/bin/sh"); +# endif + + d->args << QString::fromLatin1("-c") << cmd; +#else // Q_OS_UNIX + // KMacroExpander::expandMacrosShellQuote(), KShell::quoteArg() and + // KShell::joinArgs() may generate these for security reasons. + setEnv(PERCENT_VARIABLE, QLatin1String("%")); + +#ifndef _WIN32_WCE + WCHAR sysdir[MAX_PATH + 1]; + UINT size = GetSystemDirectoryW(sysdir, MAX_PATH + 1); + d->prog = QString::fromUtf16((const ushort *) sysdir, size); + d->prog += QLatin1String("\\cmd.exe"); + setNativeArguments(QLatin1String("/V:OFF /S /C \"") + cmd + QLatin1Char('"')); +#else + d->prog = QLatin1String("\\windows\\cmd.exe"); + setNativeArguments(QLatin1String("/S /C \"") + cmd + QLatin1Char('"')); +#endif +#endif +}*/ + +QStringList KProcess::program() const +{ + Q_D(const KProcess); + + QStringList argv = d->args; + argv.prepend(d->prog); + return argv; +} + +void KProcess::start() +{ + Q_D(KProcess); + qDebug() << "prog: " << d->prog << " | args: " << d->args; + QProcess::start(d->prog, d->args, d->openMode); +} + +int KProcess::execute(int msecs) +{ + start(); + if (!waitForFinished(msecs)) { + kill(); + waitForFinished(-1); + return -2; + } + return (exitStatus() == QProcess::NormalExit) ? exitCode() : -1; +} + +// static +int KProcess::execute(const QString &exe, const QStringList &args, int msecs) +{ + KProcess p; + p.setProgram(exe, args); + return p.execute(msecs); +} + +// static +int KProcess::execute(const QStringList &argv, int msecs) +{ + KProcess p; + p.setProgram(argv); + return p.execute(msecs); +} + +int KProcess::startDetached() +{ + Q_D(KProcess); + + qint64 pid; + if (!QProcess::startDetached(d->prog, d->args, workingDirectory(), &pid)) + return 0; + return (int) pid; +} + +// static +int KProcess::startDetached(const QString &exe, const QStringList &args) +{ + qint64 pid; + if (!QProcess::startDetached(exe, args, QString(), &pid)) + return 0; + return (int) pid; +} + +// static +int KProcess::startDetached(const QStringList &argv) +{ + QStringList args = argv; + QString prog = args.takeFirst(); + return startDetached(prog, args); +} + +int KProcess::pid() const +{ +#ifdef Q_OS_UNIX + return (int) QProcess::pid(); +#else + return QProcess::pid() ? QProcess::pid()->dwProcessId : 0; +#endif +} + +#include "moc_kprocess.cpp" diff --git a/kgpg/kprocess.h b/kgpg/kprocess.h new file mode 100644 index 0000000..6f28e24 --- /dev/null +++ b/kgpg/kprocess.h @@ -0,0 +1,341 @@ +/* + This file is part of the KDE libraries + + Copyright (C) 2007 Oswald Buddenhagen <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KPROCESS_H +#define KPROCESS_H + +//#include <kdecore_export.h> + +#include <QtCore/QProcess> + +class KProcessPrivate; +//#include "kprocess_p.h" +/** + * \class KProcess kprocess.h <KProcess> + * + * Child process invocation, monitoring and control. + * + * This class extends QProcess by some useful functionality, overrides + * some defaults with saner values and wraps parts of the API into a more + * accessible one. + * This is the preferred way of spawning child processes in KDE; don't + * use QProcess directly. + * + * @author Oswald Buddenhagen <[email protected]> + **/ +class KProcess : public QProcess +{ + Q_OBJECT + Q_DECLARE_PRIVATE(KProcess) + +public: + + /** + * Modes in which the output channels can be opened. + */ + enum OutputChannelMode { + SeparateChannels = QProcess::SeparateChannels, + /**< Standard output and standard error are handled by KProcess + as separate channels */ + MergedChannels = QProcess::MergedChannels, + /**< Standard output and standard error are handled by KProcess + as one channel */ + ForwardedChannels = QProcess::ForwardedChannels, + /**< Both standard output and standard error are forwarded + to the parent process' respective channel */ + OnlyStdoutChannel, + /**< Only standard output is handled; standard error is forwarded */ + OnlyStderrChannel /**< Only standard error is handled; standard output is forwarded */ + }; + + /** + * Constructor + */ + explicit KProcess(QObject *parent = 0); + + /** + * Destructor + */ + virtual ~KProcess(); + + /** + * Set how to handle the output channels of the child process. + * + * The default is ForwardedChannels, which is unlike in QProcess. + * Do not request more than you actually handle, as this output is + * simply lost otherwise. + * + * This function must be called before starting the process. + * + * @param mode the output channel handling mode + */ + void setOutputChannelMode(OutputChannelMode mode); + + /** + * Query how the output channels of the child process are handled. + * + * @return the output channel handling mode + */ + OutputChannelMode outputChannelMode() const; + + /** + * Set the QIODevice open mode the process will be opened in. + * + * This function must be called before starting the process, obviously. + * + * @param mode the open mode. Note that this mode is automatically + * "reduced" according to the channel modes and redirections. + * The default is QIODevice::ReadWrite. + */ + void setNextOpenMode(QIODevice::OpenMode mode); + + /** + * Adds the variable @p name to the process' environment. + * + * This function must be called before starting the process. + * + * @param name the name of the environment variable + * @param value the new value for the environment variable + * @param overwrite if @c false and the environment variable is already + * set, the old value will be preserved + */ + void setEnv(const QString &name, const QString &value, bool overwrite = true); + + /** + * Removes the variable @p name from the process' environment. + * + * This function must be called before starting the process. + * + * @param name the name of the environment variable + */ + void unsetEnv(const QString &name); + + /** + * Empties the process' environment. + * + * Note that LD_LIBRARY_PATH/DYLD_LIBRARY_PATH is automatically added + * on *NIX. + * + * This function must be called before starting the process. + */ + void clearEnvironment(); + + /** + * Set the program and the command line arguments. + * + * This function must be called before starting the process, obviously. + * + * @param exe the program to execute + * @param args the command line arguments for the program, + * one per list element + */ + void setProgram(const QString &exe, const QStringList &args = QStringList()); + + /** + * @overload + * + * @param argv the program to execute and the command line arguments + * for the program, one per list element + */ + void setProgram(const QStringList &argv); + + /** + * Append an element to the command line argument list for this process. + * + * If no executable is set yet, it will be set instead. + * + * For example, doing an "ls -l /usr/local/bin" can be achieved by: + * \code + * KProcess p; + * p << "ls" << "-l" << "/usr/local/bin"; + * ... + * \endcode + * + * This function must be called before starting the process, obviously. + * + * @param arg the argument to add + * @return a reference to this KProcess + */ + KProcess &operator<<(const QString& arg); + + /** + * @overload + * + * @param args the arguments to add + * @return a reference to this KProcess + */ + KProcess &operator<<(const QStringList& args); + + /** + * Clear the program and command line argument list. + */ + void clearProgram(); + + /** + * Set a command to execute through a shell (a POSIX sh on *NIX + * and cmd.exe on Windows). + * + * Using this for anything but user-supplied commands is usually a bad + * idea, as the command's syntax depends on the platform. + * Redirections including pipes, etc. are better handled by the + * respective functions provided by QProcess. + * + * If KProcess determines that the command does not really need a + * shell, it will trasparently execute it without one for performance + * reasons. + * + * This function must be called before starting the process, obviously. + * + * @param cmd the command to execute through a shell. + * The caller must make sure that all filenames etc. are properly + * quoted when passed as argument. Failure to do so often results in + * serious security holes. See KShell::quoteArg(). + */ + void setShellCommand(const QString &cmd); + + /** + * Obtain the currently set program and arguments. + * + * @return a list, the first element being the program, the remaining ones + * being command line arguments to the program. + */ + QStringList program() const; + + /** + * Start the process. + * + * @see QProcess::start(const QString &, const QStringList &, OpenMode) + */ + void start(); + + /** + * Start the process, wait for it to finish, and return the exit code. + * + * This method is roughly equivalent to the sequence: + * <code> + * start(); + * waitForFinished(msecs); + * return exitCode(); + * </code> + * + * Unlike the other execute() variants this method is not static, + * so the process can be parametrized properly and talked to. + * + * @param msecs time to wait for process to exit before killing it + * @return -2 if the process could not be started, -1 if it crashed, + * otherwise its exit code + */ + int execute(int msecs = -1); + + /** + * @overload + * + * @param exe the program to execute + * @param args the command line arguments for the program, + * one per list element + * @param msecs time to wait for process to exit before killing it + * @return -2 if the process could not be started, -1 if it crashed, + * otherwise its exit code + */ + static int execute(const QString &exe, const QStringList &args = QStringList(), int msecs = -1); + + /** + * @overload + * + * @param argv the program to execute and the command line arguments + * for the program, one per list element + * @param msecs time to wait for process to exit before killing it + * @return -2 if the process could not be started, -1 if it crashed, + * otherwise its exit code + */ + static int execute(const QStringList &argv, int msecs = -1); + + /** + * Start the process and detach from it. See QProcess::startDetached() + * for details. + * + * Unlike the other startDetached() variants this method is not static, + * so the process can be parametrized properly. + * @note Currently, only the setProgram()/setShellCommand() and + * setWorkingDirectory() parametrizations are supported. + * + * The KProcess object may be re-used immediately after calling this + * function. + * + * @return the PID of the started process or 0 on error + */ + int startDetached(); + + /** + * @overload + * + * @param exe the program to start + * @param args the command line arguments for the program, + * one per list element + * @return the PID of the started process or 0 on error + */ + static int startDetached(const QString &exe, const QStringList &args = QStringList()); + + /** + * @overload + * + * @param argv the program to start and the command line arguments + * for the program, one per list element + * @return the PID of the started process or 0 on error + */ + static int startDetached(const QStringList &argv); + + /** + * Obtain the process' ID as known to the system. + * + * Unlike with QProcess::pid(), this is a real PID also on Windows. + * + * This function can be called only while the process is running. + * It cannot be applied to detached processes. + * + * @return the process ID + */ + int pid() const; + +protected: + /** + * @internal + */ + KProcess(KProcessPrivate *d, QObject *parent); + + /** + * @internal + */ + KProcessPrivate * const d_ptr; + +private: + // hide those + using QProcess::setReadChannelMode; + using QProcess::readChannelMode; + using QProcess::setProcessChannelMode; + using QProcess::processChannelMode; + + Q_PRIVATE_SLOT(d_func(), void _k_forwardStdout()) + Q_PRIVATE_SLOT(d_func(), void _k_forwardStderr()) +}; + +#endif + diff --git a/kgpg/kprocess_p.h b/kgpg/kprocess_p.h new file mode 100644 index 0000000..11d3356 --- /dev/null +++ b/kgpg/kprocess_p.h @@ -0,0 +1,50 @@ +/* + This file is part of the KDE libraries + + Copyright (C) 2007 Oswald Buddenhagen <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KPROCESS_P_H +#define KPROCESS_P_H + +#include "kprocess.h" + +//class KProcess; + +class KProcessPrivate { + Q_DECLARE_PUBLIC(KProcess) +protected: + KProcessPrivate() : + openMode(QIODevice::ReadWrite) + { + } + void writeAll(const QByteArray &buf, int fd); + void forwardStd(KProcess::ProcessChannel good, int fd); + void _k_forwardStdout(); + void _k_forwardStderr(); + + QString prog; + QStringList args; + KProcess::OutputChannelMode outputChannelMode; + QIODevice::OpenMode openMode; + + KProcess *q_ptr; +}; + + +#endif diff --git a/kgpg/transactions/kgpgdecrypt.cpp b/kgpg/transactions/kgpgdecrypt.cpp new file mode 100644 index 0000000..20f0c50 --- /dev/null +++ b/kgpg/transactions/kgpgdecrypt.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2010,2011,2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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 "kgpgdecrypt.h" + +#include "../gpgproc.h" +//#include "kgpgsettings.h" + +//#include <KLocale> + +KGpgDecrypt::KGpgDecrypt(QObject *parent, const QString &text) + : KGpgTextOrFileTransaction(parent, text), + m_fileIndex(-1), + m_plainLength(-1) +{ +} + +KGpgDecrypt::KGpgDecrypt(QObject *parent, const QList<QUrl> &files) + : KGpgTextOrFileTransaction(parent, files), + m_fileIndex(0), + m_plainLength(-1) +{ +} + +KGpgDecrypt::KGpgDecrypt(QObject* parent, const QUrl& infile, const QUrl& outfile) + : KGpgTextOrFileTransaction(parent, QList<QUrl>() << infile ), + m_fileIndex(0), + m_plainLength(-1), + m_outFilename(outfile.toLocalFile()) +{ +} + +KGpgDecrypt::~KGpgDecrypt() +{ +} + +QStringList +KGpgDecrypt::command() const +{ + QStringList ret; + + ret << QLatin1String("--decrypt") << QLatin1String("--command-fd=0"); + + if (!m_outFilename.isEmpty()) + ret << QLatin1String("-o") << m_outFilename; + + //ret << KGpgSettings::customDecrypt().simplified().split(QLatin1Char(' '), QString::SkipEmptyParts); + + return ret; +} + +QStringList +KGpgDecrypt::decryptedText() const +{ + QStringList result; + int txtlength = 0; + + foreach (const QString &line, getMessages()) + if (!line.startsWith(QLatin1String("[GNUPG:] "))) { + result.append(line); + txtlength += line.length() + 1; + } + + if (result.isEmpty()) + return result; + + QString last = result.last(); + // this may happen when the original text did not end with a newline + if (last.endsWith(QLatin1String("[GNUPG:] DECRYPTION_OKAY"))) { + // if GnuPG doesn't tell us the length assume that this happend + // if it told us the length then check if it _really_ happend + if (((m_plainLength != -1) && (txtlength != m_plainLength)) || + (m_plainLength == -1)) { + last.chop(24); + result[result.count() - 1] = last; + } + } + + return result; +} + +bool +KGpgDecrypt::isEncryptedText(const QString &text, int *startPos, int *endPos) +{ + int posStart = text.indexOf(QLatin1String("-----BEGIN PGP MESSAGE-----")); + if (posStart == -1) + return false; + + int posEnd = text.indexOf(QLatin1String("-----END PGP MESSAGE-----"), posStart); + if (posEnd == -1) + return false; + + if (startPos != NULL) + *startPos = posStart; + if (endPos != NULL) + *endPos = posEnd; + + return true; +} + +bool +KGpgDecrypt::nextLine(const QString& line) +{ + const QList<QUrl> &inputFiles = getInputFiles(); + + if (!inputFiles.isEmpty()) { + if (line == QLatin1String("[GNUPG:] BEGIN_DECRYPTION")) { + emit statusMessage(tr("Status message 'Decrypting <filename>' (operation starts)", "Decrypting %1").arg(inputFiles.at(m_fileIndex).toLocalFile())); + emit infoProgress(2 * m_fileIndex + 1, inputFiles.count() * 2); + } else if (line == QLatin1String("[GNUPG:] END_DECRYPTION")) { + emit statusMessage(tr("Status message 'Decrypted <filename>' (operation was completed)", "Decrypted %1").arg(inputFiles.at(m_fileIndex).toLocalFile())); + m_fileIndex++; + emit infoProgress(2 * m_fileIndex, inputFiles.count() * 2); + } + } else { + if (line.startsWith(QLatin1String("[GNUPG:] PLAINTEXT_LENGTH "))) { + bool ok; + m_plainLength = line.mid(26).toInt(&ok); + if (!ok) + m_plainLength = -1; + } else if (line == QLatin1String("[GNUPG:] BEGIN_DECRYPTION")) { + // close the command channel (if any) to signal GnuPG that it + // can start sending the output. + getProcess()->closeWriteChannel(); + } + } + + return KGpgTextOrFileTransaction::nextLine(line); +} + +//#include "kgpgdecrypt.moc" diff --git a/kgpg/transactions/kgpgdecrypt.h b/kgpg/transactions/kgpgdecrypt.h new file mode 100644 index 0000000..aa28c19 --- /dev/null +++ b/kgpg/transactions/kgpgdecrypt.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2010,2011 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KGPGDECRYPT_H +#define KGPGDECRYPT_H + +#include <QObject> + +#include <QUrl> + +#include "kgpgtextorfiletransaction.h" + +class QProcess; +class QStringList; + +/** + * @brief decrypt the given text or files + */ +class KGpgDecrypt: public KGpgTextOrFileTransaction { + Q_OBJECT + + Q_DISABLE_COPY(KGpgDecrypt) + KGpgDecrypt(); // = delete C++0x +public: + /** + * @brief decrypt given text + * @param parent parent object + * @param text text to decrypt + */ + explicit KGpgDecrypt(QObject *parent, const QString &text = QString()); + + /** + * @brief decrypt file(s) + * @param parent parent object + * @param files list of file locations to decrypt + */ + KGpgDecrypt(QObject *parent, const QList<QUrl> &files); + + /** + * @brief decrypt file to given output filename + * @param parent parent object + * @param infile name of file to decrypt + * @param outfile name of file to write output to (will be overwritten) + */ + KGpgDecrypt(QObject *parent, const QUrl &infile, const QUrl &outfile); + + /** + * @brief destructor + */ + virtual ~KGpgDecrypt(); + + /** + * @brief get decryption result + * @return decrypted text + */ + QStringList decryptedText() const; + + /** + * @brief check if the given text contains an encoded message + * @param text text to check + * @param startPos if not NULL start offset of encoded text will be returned here + * @param endPos if not NULL end offset of encoded text will be returned here + */ + static bool isEncryptedText(const QString &text, int *startPos = NULL, int *endPos = NULL); + +protected: + virtual QStringList command() const; + virtual bool nextLine(const QString &line); + +private: + int m_fileIndex; + int m_plainLength; ///< length of decrypted plain text if given by GnuPG + const QString m_outFilename; ///< name of file to write output to +}; + +#endif // KGPGDECRYPT_H diff --git a/kgpg/transactions/kgpgdelkey.cpp b/kgpg/transactions/kgpgdelkey.cpp new file mode 100644 index 0000000..ac09610 --- /dev/null +++ b/kgpg/transactions/kgpgdelkey.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2008,2009,2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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 "kgpgdelkey.h" + +#include "../gpgproc.h" + +#include <QString> +#include <QStringList> + +/*KGpgDelKey::KGpgDelKey(QObject *parent, KGpgKeyNode *key) + : KGpgTransaction(parent) +{ + m_keys << key; + setCmdLine(); +}*/ + +KGpgDelKey::KGpgDelKey(QObject *parent, const QStringList &uids) + : KGpgTransaction(parent), + m_uids(uids) +{ + setCmdLine(); +} + +KGpgDelKey::~KGpgDelKey() +{ +} + +QStringList +KGpgDelKey::keys() const +{ + return m_uids; +} + +bool +KGpgDelKey::nextLine(const QString &line) +{ + if (!line.startsWith(QLatin1String("[GNUPG:] GOT_IT"))) + setSuccess(KGpgTransaction::TS_MSG_SEQUENCE); + + return false; +} + +KGpgTransaction::ts_boolanswer +KGpgDelKey::boolQuestion(const QString &line) +{ + if (line.startsWith(QLatin1String("delete_key.okay"))) + return KGpgTransaction::BA_YES; + + if (line.startsWith(QLatin1String("delete_key.secret.okay"))) + return KGpgTransaction::BA_YES; + + return KGpgTransaction::boolQuestion(line); +} + +bool +KGpgDelKey::preStart() +{ + GPGProc *proc = getProcess(); + QStringList args = proc->program(); + + /*foreach (const KGpgKeyNode *key, m_keys) + args << key->getFingerprint();*/ + foreach (const QString uid, m_uids) + args << uid; + + proc->setProgram(args); + + setSuccess(KGpgTransaction::TS_OK); + + return true; +} + +void +KGpgDelKey::setCmdLine() +{ + addArgument(QLatin1String( "--status-fd=1" )); + addArgument(QLatin1String( "--command-fd=0" )); + addArgument(QLatin1String( "--delete-secret-and-public-key" )); + + m_argscount = getProcess()->program().count(); +} + +//#include "kgpgdelkey.moc" diff --git a/kgpg/transactions/kgpgdelkey.h b/kgpg/transactions/kgpgdelkey.h new file mode 100644 index 0000000..c7a35ae --- /dev/null +++ b/kgpg/transactions/kgpgdelkey.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008,2009 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KGPGDELKEY_H +#define KGPGDELKEY_H + +#include "kgpgtransaction.h" + +#include "../core/KGpgKeyNode.h" + +#include <QObject> + +/** + * @brief delete a public key + */ +class KGpgDelKey: public KGpgTransaction { + Q_OBJECT + + Q_DISABLE_COPY(KGpgDelKey) + KGpgDelKey(); // = delete C++0x +public: + //KGpgDelKey(QObject *parent, KGpgKeyNode *key); + KGpgDelKey(QObject *parent, const QStringList &uids); + virtual ~KGpgDelKey(); + + /** + * @brief the keys that were requested to be removed + * @return the list of key nodes + */ + QStringList keys() const; + +protected: + virtual bool nextLine(const QString &line); + virtual ts_boolanswer boolQuestion(const QString &line); + virtual bool preStart(); + +private: + //KGpgKeyNode::List m_keys; + QStringList m_uids; + int m_argscount; + + void setCmdLine(); +}; + +#endif // KGPGDELKEY_H diff --git a/kgpg/transactions/kgpgencrypt.cpp b/kgpg/transactions/kgpgencrypt.cpp new file mode 100644 index 0000000..4891bf0 --- /dev/null +++ b/kgpg/transactions/kgpgencrypt.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2011,2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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 "kgpgencrypt.h" + +//#include "kgpgsettings.h" +#include "../gpgproc.h" + +//#include <kio/renamedialog.h> +//#include <KLocale> +#include <QPointer> + +static QStringList trustOptions(const QString &binary) +{ + const int gpgver = GPGProc::gpgVersion(GPGProc::gpgVersionString(binary)); + QStringList args; + if (gpgver >= 0x10302) + args << QLatin1String("--trust-model") + << QLatin1String("always"); + else + args << QLatin1String("--always-trust"); + + return args; +} + +KGpgEncrypt::KGpgEncrypt(QObject *parent, const QStringList &userIds, const QString &text, const EncryptOptions &options, const QStringList &extraOptions) + : KGpgTextOrFileTransaction(parent, text), + m_fileIndex(-1), + m_options(options), + m_userIds(userIds), + m_extraOptions(extraOptions) +{ + if ((m_options & AllowUntrustedEncryption) && !m_userIds.isEmpty()) + m_extraOptions << trustOptions(getProcess()->program().at(0)); +} + +KGpgEncrypt::KGpgEncrypt(QObject *parent, const QStringList &userIds, const QList<QUrl> &files, const EncryptOptions &options, const QStringList &extraOptions) + : KGpgTextOrFileTransaction(parent, files), + m_fileIndex(0), + m_options(options), + m_userIds(userIds), + m_extraOptions(extraOptions) +{ + if ((m_options & AllowUntrustedEncryption) && !m_userIds.isEmpty()) + m_extraOptions << trustOptions(getProcess()->program().at(0)); +} + +KGpgEncrypt::~KGpgEncrypt() +{ +} + +QStringList +KGpgEncrypt::command() const +{ + QStringList ret = m_extraOptions; + + if (m_options.testFlag(AsciiArmored)) + ret << QLatin1String("--armor"); + + if (m_userIds.isEmpty()) { + ret << QLatin1String( "--symmetric" ); + } else { + if (m_options.testFlag(HideKeyId)) + ret << QLatin1String("--throw-keyid"); + + foreach (const QString &uid, m_userIds) + ret << QLatin1String( "--recipient" ) << uid; + ret << QLatin1String( "--encrypt" ); + } + + return ret; +} + +QStringList +KGpgEncrypt::encryptedText() const +{ + QStringList result; + int txtlength = 0; + + foreach (const QString &line, getMessages()) + if (!line.startsWith(QLatin1String("[GNUPG:] "))) { + result.append(line); + txtlength += line.length() + 1; + } + + return result; +} + +bool +KGpgEncrypt::nextLine(const QString &line) +{ + const QList<QUrl> &inputFiles = getInputFiles(); + + if (line.startsWith(QLatin1String("[GNUPG:] MISSING_PASSPHRASE"))) { + setSuccess(KGpgTransaction::TS_BAD_PASSPHRASE); + return true; + } + + if (!inputFiles.isEmpty()) { + static const QString encStart = QLatin1String("[GNUPG:] FILE_START 2 "); + static const QString encDone = QLatin1String("[GNUPG:] FILE_DONE"); + static const QString askName = QLatin1String("[GNUPG:] GET_LINE openfile.askoutname"); + + if (line.startsWith(encStart)) { + m_currentFile = line.mid(encStart.length()); + emit statusMessage(tr("Status message 'Encrypting <filename>' (operation starts)", "Encrypting %1").arg(m_currentFile)); + emit infoProgress(2 * m_fileIndex + 1, inputFiles.count() * 2); + } else if (line == encDone) { + emit statusMessage(tr("Status message 'Encrypted <filename>' (operation was completed)", "Encrypted %1").arg(m_currentFile)); + m_fileIndex++; + emit infoProgress(2 * m_fileIndex, inputFiles.count() * 2); +// TODO +/* } else if (line == askName) { + QPointer<KIO::RenameDialog> over = new KIO::RenameDialog(qobject_cast<QWidget *>(parent()), + i18n("File Already Exists"), KUrl(), + KUrl::fromPath(m_currentFile + encryptExtension(m_options.testFlag(AsciiArmored))), + KIO::M_OVERWRITE); + + if (over->exec() != QDialog::Accepted) { + delete over; + setSuccess(KGpgTransaction::TS_USER_ABORTED); + return true; + } + write(over->newDestUrl().path().toUtf8()); + delete over;*/ + } + } + + return KGpgTextOrFileTransaction::nextLine(line); +} + +QString +KGpgEncrypt::encryptExtension(const bool ascii) +{ + if (ascii) + return QLatin1String( ".asc" ); + /*else if (KGpgSettings::pgpExtension()) + return QLatin1String( ".pgp" );*/ + else + return QLatin1String( ".gpg" ); +} + +//#include "kgpgencrypt.moc" diff --git a/kgpg/transactions/kgpgencrypt.h b/kgpg/transactions/kgpgencrypt.h new file mode 100644 index 0000000..ad9d89c --- /dev/null +++ b/kgpg/transactions/kgpgencrypt.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2011 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KGPGENCRYPT_H +#define KGPGENCRYPT_H + +#include <QObject> +#include <QString> +#include <QStringList> + +#include <QUrl> + +#include "kgpgtextorfiletransaction.h" + +class QProcess; + +/** + * @brief encrypt the given text or files + */ +class KGpgEncrypt: public KGpgTextOrFileTransaction { + Q_OBJECT + + Q_DISABLE_COPY(KGpgEncrypt) + KGpgEncrypt(); // = delete C++0x +public: + enum EncryptOption { + DefaultEncryption = 0, ///< use whatever GnuPGs defaults are + AsciiArmored = 0x1, ///< output the data as printable ASCII as opposed to binary data + AllowUntrustedEncryption = 0x2, ///< allow encryption with untrusted keys, ignored for symmetric encryption + HideKeyId = 0x4 ///< remove anything that shows which key ids this data is encrypted to, ignored for symmetric encryption + }; + Q_DECLARE_FLAGS(EncryptOptions, EncryptOption); + + /** + * @brief encrypt given text + * @param parent parent object + * @param userIds ids to encrypt to or empty list to use symmetric encryption with passphrase + * @param text text to encrypt + * @param options encryption options + */ + explicit KGpgEncrypt(QObject *parent, const QStringList &userIds = QStringList(), const QString &text = QString(), const EncryptOptions &options = DefaultEncryption, const QStringList &extraOptions = QStringList()); + + /** + * @brief encrypt file(s) + * @param parent parent object + * @param userIds ids to encrypt to or empty list to use symmetric encryption with passphrase + * @param files list of file locations to encrypt + * @param options encryption options + */ + KGpgEncrypt(QObject *parent, const QStringList &userIds, const QList<QUrl> &files, const EncryptOptions &options = DefaultEncryption, const QStringList &extraOptions = QStringList()); + + /** + * @brief destructor + */ + virtual ~KGpgEncrypt(); + + /** + * @brief get decryption result + * @return decrypted text + */ + QStringList encryptedText() const; + + /** + * @brief return the preferred extension for encrypted files + * @param ascii if the file is encrypted with ASCII armor + * @return the file extension with leading dot + */ + static QString encryptExtension(const bool ascii); + +protected: + virtual QStringList command() const; + virtual bool nextLine(const QString &line); + +private: + int m_fileIndex; + const EncryptOptions m_options; + const QStringList m_userIds; + QStringList m_extraOptions; + QString m_currentFile; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(KGpgEncrypt::EncryptOptions); + +#endif // KGPGENCRYPT_H diff --git a/kgpg/transactions/kgpgexport.cpp b/kgpg/transactions/kgpgexport.cpp new file mode 100644 index 0000000..79f6afe --- /dev/null +++ b/kgpg/transactions/kgpgexport.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2009,2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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 "kgpgexport.h" + +#include "../gpgproc.h" + +#include <QFile> +#include <QProcess> + +KGpgExport::KGpgExport(QObject *parent, const QStringList &ids, QProcess *outp, const QStringList &options, const bool secret) + : KGpgTransaction(parent), + m_keyids(ids), + m_outp(outp), + m_outputmode(ModeProcess) +{ + procSetup(options, secret); +} + +KGpgExport::KGpgExport(QObject *parent, const QStringList &ids, const QString &file, const QStringList &options, const bool secret) + : KGpgTransaction(parent), + m_keyids(ids), + m_outp(NULL), + m_outf(file), + m_outputmode(ModeFile) +{ + procSetup(options, secret); +} + +KGpgExport::KGpgExport(QObject *parent, const QStringList &ids, const QStringList &options, const bool secret) + : KGpgTransaction(parent), + m_keyids(ids), + m_outp(NULL), + m_outputmode(ModeStdout) +{ + procSetup(options, secret); +} + +KGpgExport::KGpgExport(QObject *parent, const QStringList &ids, KGpgTransaction *outt, const QStringList &options, const bool secret) + : KGpgTransaction(parent), + m_keyids(ids), + m_outp(NULL), + m_outputmode(ModeTransaction) +{ + procSetup(options, secret); + outt->setInputTransaction(this); +} + +KGpgExport::~KGpgExport() +{ +} + +void +KGpgExport::setKeyId(const QString &id) +{ + m_keyids.clear(); + m_keyids.append(id); +} + +void +KGpgExport::setKeyIds(const QStringList &ids) +{ + m_keyids = ids; +} + +const QStringList & +KGpgExport::getKeyIds() const +{ + return m_keyids; +} + +void +KGpgExport::setOutputProcess(QProcess *outp) +{ + m_outf.clear(); + m_outp = outp; + m_outputmode = ModeProcess; +} + +void +KGpgExport::setOutputFile(const QString &filename) +{ + m_outp = NULL; + m_outf = filename; + if (filename.isEmpty()) + m_outputmode = ModeStdout; + else + m_outputmode = ModeFile; +} + +void +KGpgExport::setOutputTransaction(KGpgTransaction *outt) +{ + m_outp = NULL; + m_outf.clear(); + m_outputmode = ModeTransaction; + outt->setInputTransaction(this); +} + +const QString & +KGpgExport::getOutputFile() const +{ + return m_outf; +} + +const QByteArray & +KGpgExport::getOutputData() const +{ + return m_data; +} + +bool +KGpgExport::preStart() +{ + setSuccess(TS_OK); + + switch (m_outputmode) { + case ModeFile: + { + Q_ASSERT(!m_outf.isEmpty()); + Q_ASSERT(m_outp == NULL); + + addArgument(QLatin1String( "--output" )); + addArgument(m_outf); + + QFile ofile(m_outf); + if (ofile.exists()) + ofile.remove(); + + break; + } + case ModeProcess: + Q_ASSERT(m_outf.isEmpty()); + Q_ASSERT(m_outp != NULL); + + getProcess()->setStandardOutputProcess(m_outp); + + break; + case ModeStdout: + Q_ASSERT(m_outf.isEmpty()); + Q_ASSERT(m_outp == NULL); + break; + case ModeTransaction: + Q_ASSERT(m_outf.isEmpty()); + Q_ASSERT(m_outp == NULL); + break; + default: + Q_ASSERT(0); + } + + addArguments(m_keyids); + + m_data.clear(); + + return true; +} + +bool +KGpgExport::nextLine(const QString &line) +{ + // key exporting does not send any messages + + m_data.append(line.toAscii() + '\n'); + + if (m_outputmode != 2) + setSuccess(TS_MSG_SEQUENCE); + + return false; +} + +void +KGpgExport::procSetup(const QStringList &options, const bool secret) +{ + getProcess()->resetProcess(); + + if (secret) + addArgument(QLatin1String( "--export-secret-key" )); + else + addArgument(QLatin1String( "--export" )); + + if ((m_outputmode == 2) && !options.contains(QLatin1String( "--armor" ))) + addArgument(QLatin1String( "--armor" )); + + addArguments(options); +} + +//#include "kgpgexport.moc" diff --git a/kgpg/transactions/kgpgexport.h b/kgpg/transactions/kgpgexport.h new file mode 100644 index 0000000..63aeaac --- /dev/null +++ b/kgpg/transactions/kgpgexport.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2009 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KGPGEXPORT_H +#define KGPGEXPORT_H + +#include <QObject> +#include <QStringList> + +#include <QUrl> + +#include "kgpgtransaction.h" + +class QProcess; + +/** + * @brief export one or more keys from keyring + * + * The exported keys can be written to a file or sent to standard input of another + * QProcess. + */ +class KGpgExport: public KGpgTransaction { + Q_OBJECT + + KGpgExport(); // = delete C++0x + Q_DISABLE_COPY(KGpgExport) +public: + /** + * @brief export keys to QProcess + * @param parent parent object + * @param ids ids to export + * @param outp process to write into + * @param options additional options to pass to GnuPG (e.g. export ascii armored) + * @param secret if secret key exporting is allowed + */ + KGpgExport(QObject *parent, const QStringList &ids, QProcess *outp, const QStringList &options = QStringList(), const bool secret = false); + + /** + * @brief export keys to KGpgTransaction + * @param parent parent object + * @param ids ids to export + * @param outt transaction to write into + * @param options additional options to pass to GnuPG (e.g. export ascii armored) + * @param secret if secret key exporting is allowed + */ + KGpgExport(QObject *parent, const QStringList &ids, KGpgTransaction *outt, const QStringList &options = QStringList(), const bool secret = false); + + /** + * @brief export keys to file + * @param parent parent object + * @param ids ids to export + * @param file filename to write into + * @param options additional options to pass to GnuPG (e.g. export ascii armored) + * @param secret if secret key exporting is allowed + */ + KGpgExport(QObject *parent, const QStringList &ids, const QString &file, const QStringList &options = QStringList(), const bool secret = false); + + /** + * @brief export keys to standard output + * @param parent parent object + * @param ids ids to export + * @param options additional options to pass to GnuPG (e.g. export ascii armored) + * @param secret if secret key exporting is allowed + * + * Only ascii-armored export is supported in standard output mode. If it is not + * already set in the given option it will be added automatically. + */ + KGpgExport(QObject *parent, const QStringList &ids, const QStringList &options = QStringList(), const bool secret = false); + + /** + * @brief destructor + */ + virtual ~KGpgExport(); + + /** + * @brief set key id to export + * @param id key fingerprint + */ + void setKeyId(const QString &id); + /** + * @brief set key ids to export + * @param ids key fingerprints + */ + void setKeyIds(const QStringList &ids); + /** + * @brief return the key ids to export + * @return list of key fingerprints + */ + const QStringList &getKeyIds() const; + /** + * @brief set the process the output is sent to + * @param outp process to send output to + */ + void setOutputProcess(QProcess *outp); + /** + * @brief set the transaction the output is sent to + * @param outd transaction to send output to + */ + void setOutputTransaction(KGpgTransaction *outt); + /** + * @brief set filename to send output to + * @param filename file to send output to + */ + void setOutputFile(const QString &filename); + /** + * @brief return the output filename currently set + * @return filename key will get written to + */ + const QString &getOutputFile() const; + /** + * @brief return the data read from standard output + * @return standard output data + */ + const QByteArray &getOutputData() const; + +protected: + virtual bool preStart(); + virtual bool nextLine(const QString &line); + +private: + QStringList m_keyids; + QProcess *m_outp; + QString m_outf; + QByteArray m_data; + + enum OutputMode { + ModeFile = 0, + ModeProcess = 1, + ModeStdout = 2, + ModeTransaction = 3 + }; + enum OutputMode m_outputmode; + + void procSetup(const QStringList &options, const bool secret); +}; + +#endif // KGPGEXPORT_H diff --git a/kgpg/transactions/kgpggeneratekey.cpp b/kgpg/transactions/kgpggeneratekey.cpp new file mode 100644 index 0000000..d95f1e0 --- /dev/null +++ b/kgpg/transactions/kgpggeneratekey.cpp @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2008,2009,2010,2011,2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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 "kgpggeneratekey.h" + +#include "../gpgproc.h" + +//#include <KLocale> +//#include <KMessageBox> +//#include <kpimutils/email.h> +#include <QApplication> + +KGpgGenerateKey::KGpgGenerateKey(QObject *parent, const QString &name, const QString &email, const QString &comment, + const KgpgCore::KgpgKeyAlgo &algorithm, const uint size, const unsigned int expire, + const char expireunit) + : KGpgTransaction(parent) +{ + addArgument(QLatin1String( "--status-fd=1" )); + addArgument(QLatin1String( "--command-fd=0" )); + addArgument(QLatin1String( "--no-verbose" )); + addArgument(QLatin1String( "--gen-key" )); + addArgument(QLatin1String( "--batch" )); + + setName(name); + setEmail(email); + setComment(comment); + setAlgorithm(algorithm); + setSize(size); + setExpire(expire, expireunit); + + getProcess()->setOutputChannelMode(KProcess::SeparateChannels); +} + +KGpgGenerateKey::~KGpgGenerateKey() +{ +} + +bool +KGpgGenerateKey::preStart() +{ + /*if (!m_email.isEmpty() && !KPIMUtils::isValidSimpleAddress(m_email)) { + setSuccess(TS_INVALID_EMAIL); + return false; + }*/ + + m_fingerprint.clear(); + m_namesent = false; + + setSuccess(TS_MSG_SEQUENCE); + + setDescription(QObject::tr("Generating New Key for %1").arg(m_name)); + + return true; +} + +void +KGpgGenerateKey::postStart() +{ + QByteArray keymessage("Key-Type: "); + switch (m_algorithm) { + case KgpgCore::ALGO_RSA: + keymessage.append("RSA"); + break; + case KgpgCore::ALGO_RSA_RSA: + keymessage.append("RSA\nSubkey-Type: RSA"); + break; + case KgpgCore::ALGO_DSA_ELGAMAL: + keymessage.append("DSA\nSubkey-Type: ELG-E"); + break; + default: + Q_ASSERT(m_algorithm == KgpgCore::ALGO_RSA); + return; + } + + const QByteArray keylen = QByteArray::number(m_size); + + keymessage.append("\nKey-Length: "); + keymessage.append(keylen); + keymessage.append("\nSubkey-Length: "); + keymessage.append(keylen); + keymessage.append("\nName-Real: "); + keymessage.append(m_name.toUtf8()); + if (!m_email.isEmpty()) { + keymessage.append("\nName-Email: "); + keymessage.append(m_email.toAscii()); + } + if (!m_comment.isEmpty()) { + keymessage.append("\nName-Comment: "); + keymessage.append(m_comment.toUtf8()); + } + if (m_expire != 0) { + keymessage.append("\nExpire-Date: "); + keymessage.append(QByteArray::number(m_expire)); + keymessage.append(m_expireunit); + } + keymessage.append("\nPassphrase: "); + write(keymessage, false); + + QString passdlgmessage; + if (!m_email.isEmpty()) { + passdlgmessage = QObject::tr("<p><b>Enter passphrase for %1 <%2></b>:<br />Passphrase should include non alphanumeric characters and random sequences.</p>").arg(m_name).arg(m_email); + } else { + passdlgmessage = QObject::tr("<p><b>Enter passphrase for %1</b>:<br />Passphrase should include non alphanumeric characters and random sequences.</p>").arg(m_name); + } + + QApplication::restoreOverrideCursor(); + askNewPassphrase(passdlgmessage); +} + +bool +KGpgGenerateKey::nextLine(const QString &line) +{ + QString msg(QObject::tr("Generating Key")); + + if (!line.startsWith(QLatin1String("[GNUPG:] "))) + return false; + + int result = false; + + if (line.contains(QLatin1String( "PROGRESS" ))) { + QStringList parts(line.mid(18).split(QLatin1Char( ' ' ))); + if (parts.count() >= 4) { + const QString p0(parts.at(0)); + if (p0 == QLatin1String( "primegen" )) { + msg = tr("Generating prime numbers"); + } else if (p0 == QLatin1String( "pk_dsa" )) { + msg = tr("Generating DSA key"); + } else if (p0 == QLatin1String( "pk_elg" )) { + msg = tr("Generating ElGamal key"); + } else if (p0 == QLatin1String( "need_entropy" )) { + msg = tr("Waiting for entropy"); + + // This message is currenlty not displayed. Nevertheless it's + // included here so string freeze is not broken if it will be + // displayed later on. + QString msglong = tr("The entropy pool ran empty. The key generation process is stalled until enough entropy is present. You can generate entropy e.g. by moving the mouse or typing at the keyboard. The easiest way is by using another application until the key generation continues."); + } + if (parts.at(3) != QLatin1String( "0" )) + emit infoProgress(parts.at(2).toUInt(), parts.at(3).toUInt()); + } + } else if (line.contains(QLatin1String( "GOOD_PASSPHRASE" ))) { + setSuccess(TS_MSG_SEQUENCE); + } else if (line.contains(QLatin1String( "KEY_CREATED" ))) { + m_fingerprint = line.right(40); + setSuccess(TS_OK); + result = true; + } else if (line.contains(QLatin1String( "NEED_PASSPHRASE" ))) { + setSuccess(TS_USER_ABORTED); + } else if (line.contains(QLatin1String( "GET_" ))) { + setSuccess(TS_MSG_SEQUENCE); + result = true; + } else if (line.contains(QLatin1String("KEY_NOT_CREATED"))) { + result = true; + } + + emit statusMessage(msg); + + return result; +} + +void +KGpgGenerateKey::finish() +{ + switch (getSuccess()) { + case TS_BAD_PASSPHRASE: + emit statusMessage(tr("Bad passphrase. Cannot generate a new key pair.")); + break; + case TS_USER_ABORTED: + emit statusMessage(tr("Aborted by the user. Cannot generate a new key pair.")); + break; + case TS_INVALID_EMAIL: + emit statusMessage(tr("The email address is not valid. Cannot generate a new key pair.")); + break; + case TS_INVALID_NAME: + emit statusMessage(tr("The name is not accepted by gpg. Cannot generate a new key pair.")); + break; + case TS_OK: + emit statusMessage(tr("Key %1 generated").arg(getFingerprint())); + break; + default: + { + QStringList errorLines; + + while (getProcess()->hasLineStandardError()) { + QByteArray b; + getProcess()->readLineStandardError(&b); + errorLines << QString::fromUtf8(b); + } + + m_errorOutput = errorLines.join(QLatin1String("\n")); + emit statusMessage(tr("gpg process did not finish. Cannot generate a new key pair.")); + } + } +} + +void +KGpgGenerateKey::newPasswordEntered() +{ + QApplication::setOverrideCursor(Qt::BusyCursor); + write("%commit"); +} + +void +KGpgGenerateKey::setName(const QString &name) +{ + m_name = name; +} + +QString +KGpgGenerateKey::getName() const +{ + return m_name; +} + +void +KGpgGenerateKey::setEmail(const QString &email) +{ + m_email = email; +} + +QString +KGpgGenerateKey::getEmail() const +{ + return m_email; +} + +void +KGpgGenerateKey::setComment(const QString &comment) +{ + m_comment = comment; +} + +void +KGpgGenerateKey::setAlgorithm(const KgpgCore::KgpgKeyAlgo &algorithm) +{ + m_algorithm = algorithm; +} + +void +KGpgGenerateKey::setSize(const unsigned int size) +{ + m_size = size; +} + +void +KGpgGenerateKey::setExpire(const unsigned int expire, const char expireunit) +{ + Q_ASSERT((expireunit == 'd') || (expireunit == 'w') || + (expireunit == 'm') || (expireunit == 'y')); + m_expire = expire; + m_expireunit = expireunit; +} + +QString +KGpgGenerateKey::getFingerprint() const +{ + return m_fingerprint; +} + +QString +KGpgGenerateKey::gpgErrorMessage() const +{ + return m_errorOutput; +} + +//#include "kgpggeneratekey.moc" diff --git a/kgpg/transactions/kgpggeneratekey.h b/kgpg/transactions/kgpggeneratekey.h new file mode 100644 index 0000000..3649d8f --- /dev/null +++ b/kgpg/transactions/kgpggeneratekey.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2008,2009,2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KGPGGENERATEKEY_H +#define KGPGGENERATEKEY_H + +#include "kgpgtransaction.h" + +#include "../core/kgpgkey.h" + +#include <QObject> + +class QString; + +/** + * @brief generate a new key pair + */ +class KGpgGenerateKey: public KGpgTransaction { + Q_OBJECT + + Q_DISABLE_COPY(KGpgGenerateKey) + KGpgGenerateKey(); // = delete C++0x +public: + enum ts_generatekey { + TS_INVALID_NAME = TS_COMMON_END + 1 ///< the owners name is not accepted by GnuPG + }; + /** + * @brief KGpgGenerateKey's constructor + * @param parent parent object + * @param name the name of the key, it is also the user's name. + * @param email email MUST be a valid email address or an empty string. + * @param comment is a comment, it can be an empty string + * @param algorithm this is the type of the key, RSA or DSA & ELGAMAL (\see Kgpg::KeyAlgo ). + * @param size this is the length of the key (1024, 2048, ...) + * @param expire defines the key expiry time together with \em expireunit, 0 for unlimited key lifetime + * @param expireunit is the unit of the number given as \em expire. \see setExpire + */ + KGpgGenerateKey(QObject *parent, const QString &name, const QString &email, const QString &comment, + const KgpgCore::KgpgKeyAlgo &algorithm, const uint size, const unsigned int expire = 0, + const char expireunit = 'd'); + virtual ~KGpgGenerateKey(); + + void setName(const QString &name); + QString getName() const; + void setEmail(const QString &email); + QString getEmail() const; + void setComment(const QString &comment); + void setAlgorithm(const KgpgCore::KgpgKeyAlgo &algorithm); + void setSize(const unsigned int size); + /** + * @brief set expire date for key + * @param expire defines the key expiry time together with \em expireunit, 0 for unlimited key lifetime + * @param expireunit is the unit of the number given as \em expire. + * + * Valid units are 'd', 'w', 'm' and 'y'. The unit is ignored if expire is 0. + */ + void setExpire(const unsigned int expire, const char expireunit); + + QString getFingerprint() const; + + /** + * @brief get error output of GnuPG + * @return the messages GnuPG printed to standard error + * + * This will only return data after the done() signal has been emitted. + */ + QString gpgErrorMessage() const; + +protected: + virtual bool preStart(); + virtual void postStart(); + virtual bool nextLine(const QString &line); + virtual void finish(); + virtual void newPasswordEntered(); + +private: + QString m_name; + QString m_email; + QString m_comment; + KgpgCore::KgpgKeyAlgo m_algorithm; + unsigned int m_size; + unsigned int m_expire; + unsigned int m_expireunit; + QString m_fingerprint; + bool m_namesent; + QString m_errorOutput; +}; + +#endif // KGPGGENERATEKEY_H diff --git a/kgpg/transactions/kgpgimport.cpp b/kgpg/transactions/kgpgimport.cpp new file mode 100644 index 0000000..4a3041c --- /dev/null +++ b/kgpg/transactions/kgpgimport.cpp @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2008,2009,2010,2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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 "kgpgimport.h" + +//#include "model/kgpgitemmodel.h" +#include "../core/KGpgKeyNode.h" + +#include <QDebug> +//#include <KLocale> + +KGpgImport::KGpgImport(QObject *parent, const QString &text) + : KGpgTextOrFileTransaction(parent, text, true) +{ +} + +KGpgImport::KGpgImport(QObject *parent, const QList<QUrl> &files) + : KGpgTextOrFileTransaction(parent, files, true) +{ +} + +KGpgImport::~KGpgImport() +{ +} + +QStringList +KGpgImport::command() const +{ + QStringList ret; + + ret << QLatin1String( "--import" ) << QLatin1String( "--allow-secret-key-import" ); + + return ret; +} + +QStringList +KGpgImport::getImportedKeys() const +{ + QStringList res; + + foreach (const QString &str, getMessages()) + if (str.startsWith(QLatin1String("[GNUPG:] IMPORTED "))) + res << str.mid(18); + + return res; +} + +QStringList +KGpgImport::getImportedIds(const QStringList &log, const int reason) +{ + QStringList res; + + foreach (const QString &str, log) { + if (!str.startsWith(QLatin1String("[GNUPG:] IMPORT_OK "))) + continue; + + QString tmpstr(str.mid(19).simplified()); + + int space = tmpstr.indexOf(QLatin1Char( ' ' )); + if (space <= 0) { + qDebug() << __LINE__ << "invalid format:" << str; + continue; + } + + bool ok; + unsigned char code = tmpstr.left(space).toUInt(&ok); + if (!ok) { + qDebug() << __LINE__ << "invalid format:" << str << space << tmpstr.left(space - 1); + continue; + } + + if ((reason == -1) || ((reason == 0) && (code == 0)) || ((reason & code) != 0)) + res << tmpstr.mid(space + 1); + } + + return res; +} + +QStringList +KGpgImport::getImportedIds(const int reason) const +{ + return getImportedIds(getMessages(), reason); +} + +QString +KGpgImport::getImportMessage() const +{ + return getImportMessage(getMessages()); +} + +QString +KGpgImport::getImportMessage(const QStringList &log) +{ +#define RESULT_PARTS 14 + unsigned long rcode[RESULT_PARTS]; + unsigned int i = 0; + int line = 0; + bool fine; + + memset(rcode, 0, sizeof(rcode)); + + foreach (const QString &str, log) { + line++; + if (!str.startsWith(QLatin1String("[GNUPG:] IMPORT_RES "))) + continue; + + const QStringList rstr(str.mid(20).simplified().split(QLatin1Char( ' ' ))); + + fine = (rstr.count() == RESULT_PARTS); + + i = 0; + while (fine && (i < RESULT_PARTS)) { + rcode[i] += rstr.at(i).toULong(&fine); + i++; + } + + if (!fine) + return tr("The import result string has an unsupported format in line %1.<br />Please see the detailed log for more information.").arg(line); + } + + fine = false; + i = 0; + while (!fine && (i < RESULT_PARTS)) { + fine = (rcode[i] != 0); + i++; + } + + if (!fine) + return tr("No key imported.<br />Please see the detailed log for more information."); + + QString resultMessage(tr("<qt>%1 key processed.</qt>", "<qt>%1 keys processed.</qt>", rcode[0])); + + if (rcode[1]) + resultMessage += tr("<qt><br />One key without ID.</qt>", "<qt><br />%1 keys without ID.</qt>", rcode[1]); + if (rcode[2]) + resultMessage += tr("<qt><br /><b>One key imported:</b></qt>", "<qt><br /><b>%1 keys imported:</b></qt>", rcode[2]); + if (rcode[3]) + resultMessage += tr("<qt><br />One RSA key imported.</qt>", "<qt><br />%1 RSA keys imported.</qt>", rcode[3]); + if (rcode[4]) + resultMessage += tr("<qt><br />One key unchanged.</qt>", "<qt><br />%1 keys unchanged.</qt>", rcode[4]); + if (rcode[5]) + resultMessage += tr("<qt><br />One user ID imported.</qt>", "<qt><br />%1 user IDs imported.</qt>", rcode[5]); + if (rcode[6]) + resultMessage += tr("<qt><br />One subkey imported.</qt>", "<qt><br />%1 subkeys imported.</qt>", rcode[6]); + if (rcode[7]) + resultMessage += tr("<qt><br />One signature imported.</qt>", "<qt><br />%1 signatures imported.</qt>", rcode[7]); + if (rcode[8]) + resultMessage += tr("<qt><br />One revocation certificate imported.</qt>", "<qt><br />%1 revocation certificates imported.</qt>", rcode[8]); + if (rcode[9]) + resultMessage += tr("<qt><br />One secret key processed.</qt>", "<qt><br />%1 secret keys processed.</qt>", rcode[9]); + if (rcode[10]) + resultMessage += tr("<qt><br /><b>One secret key imported.</b></qt>", "<qt><br /><b>%1 secret keys imported.</b></qt>", rcode[10]); + if (rcode[11]) + resultMessage += tr("<qt><br />One secret key unchanged.</qt>", "<qt><br />%1 secret keys unchanged.</qt>", rcode[11]); + if (rcode[12]) + resultMessage += tr("<qt><br />One secret key not imported.</qt>", "<qt><br />%1 secret keys not imported.</qt>", rcode[12]); + + if (rcode[9]) + resultMessage += tr("<qt><br /><b>You have imported a secret key.</b> <br />" + "Please note that imported secret keys are not trusted by default.<br />" + "To fully use this secret key for signing and encryption, you must edit the key (double click on it) and set its trust to Full or Ultimate.</qt>"); + + return resultMessage; +} + +/*static QString +beautifyKeyList(const QStringList &keyIds, const KGpgItemModel *model) +{ + QString result; + + result.append(QLatin1String("\n")); + if (model == NULL) { + result.append(QLatin1String(" ") + keyIds.join(QLatin1String("\n "))); + } else { + foreach (const QString &changed, keyIds) { + const KGpgKeyNode *node = model->findKeyNode(changed); + QString line; + + if (node == NULL) { + line = changed; + } else { + if (node->getEmail().isEmpty()) + line = trc("ID: Name", "%1: %2", node->getFingerprint(), node->getName()); + else + line = trc("ID: Name <Email>", "%1: %2 <%3>", node->getFingerprint(), node->getName(), node->getEmail()); + } + + result.append(QLatin1String(" ") + line + QLatin1String("\n")); + } + } + + return result; +}*/ + +QString +KGpgImport::getDetailedImportMessage(const QStringList &log, const KGpgItemModel *model) +{ + QString result; + QMap<QString, unsigned int> resultcodes; + + foreach (const QString &keyresult, log) { + if (!keyresult.startsWith(QLatin1String("[GNUPG:] IMPORT_OK "))) + continue; + + QStringList rc(keyresult.mid(19).split(QLatin1Char( ' ' ))); + if (rc.count() < 2) { + qDebug() << "unexpected syntax:" << keyresult; + continue; + } + + resultcodes[rc.at(1)] = rc.at(0).toUInt(); + } + + QMap<QString, unsigned int>::const_iterator iterend = resultcodes.constEnd(); + + for (unsigned int flag = 1; flag <= 16; flag <<= 1) { + QStringList thischanged; + + for (QMap<QString, unsigned int>::const_iterator iter = resultcodes.constBegin(); iter != iterend; ++iter) { + if (iter.value() & flag) + thischanged << iter.key(); + } + + if (thischanged.isEmpty()) + continue; + + switch (flag) { + case 1: + result.append(tr("New Key", "New Keys", thischanged.count())); + break; + case 2: + result.append(tr("Key with new User Id", "Keys with new User Ids", thischanged.count())); + break; + case 4: + result.append(tr("Key with new Signatures", "Keys with new Signatures", thischanged.count())); + break; + case 8: + result.append(tr("Key with new Subkeys", "Keys with new Subkeys", thischanged.count())); + break; + case 16: + result.append(tr("New Private Key", "New Private Keys", thischanged.count())); + break; + default: + Q_ASSERT(flag == 1); + } + +// result.append(beautifyKeyList(thischanged, model)); + result.append(QLatin1String("\n\n")); + } + + QStringList unchanged(resultcodes.keys(0)); + + if (unchanged.isEmpty()) { + // remove empty line at end + result.chop(1); + } else { + result.append(tr("Unchanged Key", "Unchanged Keys", unchanged.count())); +// result.append(beautifyKeyList(unchanged, model)); + result.append(QLatin1String("\n")); + } + + return result; +} + +int +KGpgImport::isKey(const QString &text, const bool incomplete) +{ + int markpos = text.indexOf(QLatin1String("-----BEGIN PGP PUBLIC KEY BLOCK-----")); + if (markpos >= 0) { + markpos = text.indexOf(QLatin1String("-----END PGP PUBLIC KEY BLOCK-----"), markpos); + return ((markpos > 0) || incomplete) ? 1 : 0; + } + + markpos = text.indexOf(QLatin1String("-----BEGIN PGP PRIVATE KEY BLOCK-----")); + if (markpos < 0) + return 0; + + markpos = text.indexOf(QLatin1String("-----END PGP PRIVATE KEY BLOCK-----"), markpos); + if ((markpos < 0) && !incomplete) + return 0; + + return 2; +} + +//#include "kgpgimport.moc" diff --git a/kgpg/transactions/kgpgimport.h b/kgpg/transactions/kgpgimport.h new file mode 100644 index 0000000..7fe6deb --- /dev/null +++ b/kgpg/transactions/kgpgimport.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2008,2009,2010 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KGPGIMPORT_H +#define KGPGIMPORT_H + +#include <QObject> +#include <QList> +#include <QString> +#include <QStringList> + +#include <QUrl> + +#include "kgpgtextorfiletransaction.h" + +class KGpgItemModel; + +/** + * @brief import one or more keys into the keyring + */ +class KGpgImport: public KGpgTextOrFileTransaction { + Q_OBJECT + + Q_DISABLE_COPY(KGpgImport) +public: + /** + * @brief import given text + * @param parent parent object + * @param text key text to import + */ + explicit KGpgImport(QObject *parent, const QString &text = QString()); + + /** + * @brief import key(s) from file(s) + * @param parent parent object + * @param files list of file locations to import from + */ + KGpgImport(QObject *parent, const QList<QUrl> &files); + + /** + * @brief destructor + */ + virtual ~KGpgImport(); + + /** + * @brief get the names and short fingerprints of the imported keys + * @return list of keys that were imported + */ + QStringList getImportedKeys() const; + + /** + * @brief get the full fingerprints of the imported keys + * @param log transaction log to scan + * @param reason key import reason + * @return list of ids that were imported + * + * You can filter the list of keys returned by the status of that key + * as reported by GnuPG. See doc/DETAILS of GnuPG for the meaning of + * the different flags. + * + * If reason is -1 (the default) all processed key ids are returned. + * If reason is 0 only keys of status 0 (unchanged) are returned. For + * any other value a key is returned if one of his status bits matched + * one of the bits in reason (i.e. (reason & status) != 0). + */ + static QStringList getImportedIds(const QStringList &log, const int reason = -1); + /** + * @brief get the full fingerprints of the imported keys + * + * This is an overloaded member. It calls the static function with the + * result log from this transaction object. + */ + QStringList getImportedIds(const int reason = -1) const; + + /** + * @brief get textual summary of the import events + * @return messages describing what was imported + * + * This is an overloaded member. It calls the static function with the + * result log from this transaction object. + */ + QString getImportMessage() const; + + /** + * @brief get textual summary of the import events + * @param log import log + * @return messages describing what was imported + * + * The log must contain a "IMPORT_RES" line. If this is not present + * the result string will contain an error message. + */ + static QString getImportMessage(const QStringList &log); + + /** + * @brief get detailed summary of import + * @param log import log + * @return message describing which keys changed and how + * + * The log must contain a "IMPORT_RES" line. If this is not present + * the result string will contain an error message. + */ + static QString getDetailedImportMessage(const QStringList &log, const KGpgItemModel *model = NULL); + + /** + * @brief check if the given text contains a private or public key + * @param text text to check + * @param incomplete assume text is only the beginning of the data + * @return if text contains a key or not + * @retval 0 no key found + * @retval 1 public key found + * @retval 2 private key found + */ + static int isKey(const QString &text, const bool incomplete = false); + +protected: + virtual QStringList command() const; +}; + +#endif // KGPGIMPORT_H diff --git a/kgpg/transactions/kgpgsigntext.cpp b/kgpg/transactions/kgpgsigntext.cpp new file mode 100644 index 0000000..c971214 --- /dev/null +++ b/kgpg/transactions/kgpgsigntext.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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 "kgpgsigntext.h" +#include <QDebug> +#include "../gpgproc.h" + +//#include "kgpgsettings.h" + +KGpgSignText::KGpgSignText(QObject *parent, const QString &signId, const QString &text, const SignOptions &options, const QStringList &extraOptions) + : KGpgTextOrFileTransaction(parent, text), + m_fileIndex(-1), + m_options(options), + m_signId(signId), + m_extraOptions(extraOptions), + m_text(text) +{ +} + +KGpgSignText::KGpgSignText(QObject *parent, const QString &signId, const QList<QUrl> &files, const SignOptions &options, const QStringList &extraOptions) + : KGpgTextOrFileTransaction(parent, files), + m_fileIndex(0), + m_options(options), + m_signId(signId), + m_extraOptions(extraOptions) +{ + /* GnuPG can only handle one file at a time when signing */ + Q_ASSERT(files.count() == 1); +} + +KGpgSignText::~KGpgSignText() +{ +} + +QStringList +KGpgSignText::command() const +{ + QStringList ret = m_extraOptions; + + const QList<QUrl> &files = getInputFiles(); + QString fileName; + + if (!files.isEmpty()) + fileName = files.first().path(); + + ret << QLatin1String("-u") << m_signId; + + if (m_options & AsciiArmored) { + if (fileName.isEmpty()) + ret << QLatin1String("--clearsign"); + else + ret << QLatin1String("--armor"); + } + /*if (KGpgSettings::pgpCompatibility()) + ret << QLatin1String("--pgp6");*/ + + if (!fileName.isEmpty()) { + if (m_options & DetachedSignature) + ret << QLatin1String("--detach-sign") << + QLatin1String("--output") << fileName + QLatin1String(".sig"); + + ret << fileName; + } + + // command-fd for pass? + ret << QLatin1String("--command-fd=0"); + + return ret; +} + +QStringList +KGpgSignText::signedText() const +{ + QStringList result; + + foreach (const QString &line, getMessages()) + if (!line.startsWith(QLatin1String("[GNUPG:] "))) { + result.append(line); + } + + return result; +} + +void +KGpgSignText::postStart() +{ + // do nothing, its to early +} + +bool KGpgSignText::nextLine(const QString &line) { + + if (line.startsWith(QLatin1String("[GNUPG:] BEGIN_SIGNING")) &! m_text.isEmpty()) { + GPGProc *proc = getProcess(); + proc->write(m_text.toUtf8()); + proc->closeWriteChannel(); + } else if (!line.startsWith(QLatin1String("[GNUPG:] SIGEXPIRED")) && !line.startsWith(QLatin1String("[GNUPG:] KEYEXPIRED "))) + m_messages.append(line); + + return false; +} + +const QStringList & +KGpgSignText::getMessages() const +{ + return m_messages; +} + +//#include "kgpgsigntext.moc" diff --git a/kgpg/transactions/kgpgsigntext.h b/kgpg/transactions/kgpgsigntext.h new file mode 100644 index 0000000..14459af --- /dev/null +++ b/kgpg/transactions/kgpgsigntext.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KGPGSIGNTEXT_H +#define KGPGSIGNTEXT_H + +#include "kgpgtextorfiletransaction.h" + +#include <QUrl> +#include <QObject> +#include <QString> +#include <QStringList> + +class QProcess; + +/** + * @brief sign the given text or files + */ +class KGpgSignText: public KGpgTextOrFileTransaction { + Q_OBJECT + + Q_DISABLE_COPY(KGpgSignText) + KGpgSignText(); // = delete C++0x +public: + enum SignOption { + DefaultSignature = 0, ///< use whatever GnuPGs defaults are + AsciiArmored = 0x1, ///< output the data as printable ASCII as opposed to binary data + DetachedSignature = 0x2, ///< save the signature in a separate file + }; + Q_DECLARE_FLAGS(SignOptions, SignOption); + + /** + * @brief sign given text + * @param parent parent object + * @param signId the key to use for signing + * @param text text to sign + * @param options signing options + */ + KGpgSignText(QObject *parent, const QString &signId, const QString &text = QString(), const SignOptions &options = AsciiArmored, const QStringList &extraOptions = QStringList()); + + /** + * @brief sign file + * @param parent parent object + * @param signId the key to use for signing + * @param files list of file locations to sign (must only be 1 file) + * @param options signing options + * + * @warning GnuPG can currently handle only one file per invocation for + * signing, so files may only contain one single file. + */ + KGpgSignText(QObject *parent, const QString &signId, const QList<QUrl> &files, const SignOptions &options = DefaultSignature, const QStringList &extraOptions = QStringList()); + + /** + * @brief destructor + */ + virtual ~KGpgSignText(); + + /** + * @brief get signing result + * @return signed text + */ + QStringList signedText() const; + + /** + * @brief get gpg info message + * @return the raw messages from gpg during the operation + */ + const QStringList &getMessages() const; + +protected: + virtual QStringList command() const; + virtual bool nextLine(const QString &line); + +private: + int m_fileIndex; + const SignOptions m_options; + const QString m_signId; + QStringList m_extraOptions; + const QString m_text; + QStringList m_messages; + +private slots: + void postStart(); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(KGpgSignText::SignOptions); + +#endif // KGPGSIGNTEXT_H diff --git a/kgpg/transactions/kgpgtextorfiletransaction.cpp b/kgpg/transactions/kgpgtextorfiletransaction.cpp new file mode 100644 index 0000000..036d911 --- /dev/null +++ b/kgpg/transactions/kgpgtextorfiletransaction.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2008,2009,2010,2011,2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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 "kgpgtextorfiletransaction.h" + +#include "../gpgproc.h" + +//#include <KIO/NetAccess> +//#include <KLocale> +#include <QDebug> + +KGpgTextOrFileTransaction::KGpgTextOrFileTransaction(QObject *parent, const QString &text, const bool allowChaining) + : KGpgTransaction(parent, allowChaining), + m_text(text) +{ +} + +KGpgTextOrFileTransaction::KGpgTextOrFileTransaction(QObject *parent, const QList<QUrl> &files, const bool allowChaining) + : KGpgTransaction(parent, allowChaining) +{ + setUrls(files); +} + +KGpgTextOrFileTransaction::~KGpgTextOrFileTransaction() +{ + cleanUrls(); +} + +void +KGpgTextOrFileTransaction::setText(const QString &text) +{ + m_text = text; + cleanUrls(); +} + +void +KGpgTextOrFileTransaction::setUrls(const QList<QUrl> &files) +{ + m_text.clear(); + m_inpfiles = files; + qDebug() << "files set:"; + foreach(QUrl file, m_inpfiles) { + qDebug() << file.toString(); + } +} + +bool +KGpgTextOrFileTransaction::preStart() +{ + QStringList locfiles; + + foreach (const QUrl &url, m_inpfiles) { + // qt 4.8 ! todo mac + qDebug() << "what the loc:" << url.isLocalFile(); + + if (url.isLocalFile()) { + locfiles.append(url.toLocalFile()); + } else { + /* QString tmpfile; + //TODO: QIODevice ...? + if (KIO::NetAccess::download(url, tmpfile, 0)) { + m_tempfiles.append(tmpfile); + } else { + m_messages.append(KIO::NetAccess::lastErrorString()); + cleanUrls(); + setSuccess(TS_KIO_FAILED); + return false; + }*/ + } + } + + qDebug() << "m_text: " << m_text; + qDebug() << "hasInputTransaction: " << hasInputTransaction(); + + if (locfiles.isEmpty() && m_tempfiles.isEmpty() && m_text.isEmpty() && !hasInputTransaction()) { + setSuccess(TS_MSG_SEQUENCE); + return false; + } + + QStringList args(QLatin1String("--status-fd=1")); + + args << command(); + // if the input is not stdin set command-fd so GnuPG + // can ask if e.g. the file already exists + if (!locfiles.isEmpty() && !m_tempfiles.isEmpty()) { + args << QLatin1String("--command-fd=0"); + m_closeInput = false; + qDebug() << "if"; + } else { + m_closeInput = !args.contains(QLatin1String("--command-fd=0")); + qDebug() << "else"; + } + if (locfiles.count() + m_tempfiles.count() > 1) + args << QLatin1String("--multifile"); + args << locfiles << m_tempfiles; + addArguments(args); + + return true; +} + +void +KGpgTextOrFileTransaction::postStart() +{ + qDebug() << "post-start! " << m_text; + if (!m_text.isEmpty()){ + GPGProc *proc = getProcess(); + proc->write(m_text.toUtf8()); + if (m_closeInput) + proc->closeWriteChannel(); + } +} + +bool +KGpgTextOrFileTransaction::nextLine(const QString &line) +{ + qDebug() << "nextline called: " << line; + if (!line.startsWith(QLatin1String("[GNUPG:] SIGEXPIRED")) && !line.startsWith(QLatin1String("[GNUPG:] KEYEXPIRED "))) + m_messages.append(line); + + return false; +} + +void +KGpgTextOrFileTransaction::finish() +{ + if (getProcess()->exitCode() != 0) { + setSuccess(TS_MSG_SEQUENCE); + } +} + +const QStringList & +KGpgTextOrFileTransaction::getMessages() const +{ + return m_messages; +} + +void +KGpgTextOrFileTransaction::cleanUrls() +{ +// TODO +/* foreach (const QString &u, m_tempfiles) + KIO::NetAccess::removeTempFile(u); +*/ + m_tempfiles.clear(); + m_locfiles.clear(); + m_inpfiles.clear(); +} + +const QList<QUrl> & +KGpgTextOrFileTransaction::getInputFiles() const +{ + return m_inpfiles; +} + +//#include "kgpgtextorfiletransaction.moc" diff --git a/kgpg/transactions/kgpgtextorfiletransaction.h b/kgpg/transactions/kgpgtextorfiletransaction.h new file mode 100644 index 0000000..46bf190 --- /dev/null +++ b/kgpg/transactions/kgpgtextorfiletransaction.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2008,2009,2010 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KGPGTEXTORFILETRANSACTION_H +#define KGPGTEXTORFILETRANSACTION_H + +#include <QObject> +#include <QList> +#include <QString> +#include <QStringList> + +#include <QUrl> + +#include "kgpgtransaction.h" + +/** + * @brief feed a text or file through gpg + */ +class KGpgTextOrFileTransaction: public KGpgTransaction { + Q_OBJECT + + Q_DISABLE_COPY(KGpgTextOrFileTransaction) + +public: + /** + * @brief additional status codes for KGpgImport + */ + enum ts_import { + TS_KIO_FAILED = TS_COMMON_END + 1 ///< download of remote file failed + }; + +protected: + /** + * @brief work with given text + * @param parent parent object + * @param text text to work with + */ + explicit KGpgTextOrFileTransaction(QObject *parent = 0, const QString &text = QString(), const bool allowChaining = false); + + /** + * @brief work with given file(s) + * @param parent parent object + * @param keys list of file locations to work with + */ + KGpgTextOrFileTransaction(QObject *parent, const QList<QUrl> &files, const bool allowChaining = false); + +public: + /** + * @brief destructor + */ + virtual ~KGpgTextOrFileTransaction(); + + /** + * @brief set text to work with + * @param text text to work with + */ + void setText(const QString &text); + /** + * @brief set file locations to work with + * @param keys list of file locations to work with + */ + void setUrls(const QList<QUrl> &files); + + /** + * @brief get gpg info message + * @return the raw messages from gpg during the operation + */ + const QStringList &getMessages() const; + +protected: + /** + * @brief construct the command line of the process + */ + virtual bool preStart(); + virtual bool nextLine(const QString &line); + /** + * @brief implement special handling for GnuPG return codes + */ + virtual void finish(); + + virtual QStringList command() const = 0; + + const QList<QUrl> &getInputFiles() const; + +private: + QStringList m_tempfiles; + QStringList m_locfiles; + QList<QUrl> m_inpfiles; + QString m_text; + QStringList m_messages; + bool m_closeInput; ///< if input channel of GnuPG should be closed after m_text is written + + void cleanUrls(); + +private slots: + void postStart(); +}; + +#endif // KGPGTEXTORFILETRANSACTION_H diff --git a/kgpg/transactions/kgpgtransaction.cpp b/kgpg/transactions/kgpgtransaction.cpp new file mode 100644 index 0000000..241252c --- /dev/null +++ b/kgpg/transactions/kgpgtransaction.cpp @@ -0,0 +1,558 @@ +/* + * Copyright (C) 2008,2009,2010,2011,2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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 "kgpgtransaction.h" + +#include "../gpgproc.h" +#include "../kgpginterface.h" + +//#include <KDebug> +#include <QDebug> +//#include <knewpassworddialog.h> +//#include <KLocale> +//#include <KPushButton> +#include <QByteArray> +#include <QStringList> +#include <QWeakPointer> +#include <QWidget> + + + +KGpgTransactionPrivate::KGpgTransactionPrivate(KGpgTransaction *parent, bool allowChaining) + : QObject(parent), + m_parent(parent), + m_process(new GPGProc()), + m_inputTransaction(NULL), + //m_passwordDialog(NULL), + m_success(KGpgTransaction::TS_OK), + m_tries(3), + m_chainingAllowed(allowChaining), + m_passphraseAction(KGpgTransaction::PA_NONE), + m_inputProcessDone(false), + m_inputProcessResult(KGpgTransaction::TS_OK), + m_ownProcessFinished(false), + m_quitTries(0) +{ +} + +KGpgTransactionPrivate::~KGpgTransactionPrivate() +{ + /*if (m_passwordDialog) { + m_passwordDialog->close(); + m_passwordDialog->deleteLater(); + }*/ + if (m_process->state() == QProcess::Running) { + m_process->closeWriteChannel(); + m_process->terminate(); + } + delete m_inputTransaction; + delete m_process; +} + +KGpgTransaction::KGpgTransaction(QObject *parent, const bool allowChaining) + : QObject(parent), + d(new KGpgTransactionPrivate(this, allowChaining)) +{ + connect(d->m_process, SIGNAL(readReady()), SLOT(slotReadReady())); + connect(d->m_process, SIGNAL(processExited()), SLOT(slotProcessExited())); + connect(d->m_process, SIGNAL(started()), SLOT(slotProcessStarted())); +} + +KGpgTransaction::~KGpgTransaction() +{ + delete d; +} + +void +KGpgTransactionPrivate::slotReadReady() +{ + QString line; + + QWeakPointer<GPGProc> process(m_process); + QWeakPointer<KGpgTransaction> par(m_parent); + + while (!process.isNull() && (m_process->readln(line, true) >= 0)) { + if (m_quitTries) + m_quitLines << line; +#ifdef KGPG_DEBUG_TRANSACTIONS + qDebug() << m_parent << line; +#endif /* KGPG_DEBUG_TRANSACTIONS */ + //qDebug() << "trans-read: " << m_parent << line; + + + if (line.startsWith(QLatin1String("[GNUPG:] USERID_HINT "))) { + m_parent->addIdHint(line); + } else if (line.startsWith(QLatin1String("[GNUPG:] BAD_PASSPHRASE "))) { + m_success = KGpgTransaction::TS_BAD_PASSPHRASE; + } else if (line.startsWith(QLatin1String("[GNUPG:] GET_HIDDEN passphrase.enter"))) { + // Do not directly assign to the member here, the object could + // get deleted while waiting for the result + const KGpgTransaction::ts_passphrase_actions action = m_parent->passphraseRequested(); + + if (par.isNull()) + return; + + m_passphraseAction = action; + + switch (action) { + case KGpgTransaction::PA_USER_ABORTED: + m_parent->setSuccess(KGpgTransaction::TS_USER_ABORTED); + // sending "quit" here is useless as it would be interpreted as the passphrase + m_process->closeWriteChannel(); + break; + default: + break; + } + } else if ((m_passphraseAction == KGpgTransaction::PA_CLOSE_GOOD) && + line.startsWith(QLatin1String("[GNUPG:] GOOD_PASSPHRASE"))) { + // signal GnuPG that there will be no further input and it can + // begin sending output. + + // except when signing text... + if(QString::fromAscii(m_parent->metaObject()->className()) != "KGpgSignText"){ + m_process->closeWriteChannel(); + } + } else if (line.startsWith(QLatin1String("[GNUPG:] GET_BOOL "))) { + switch (m_parent->boolQuestion(line.mid(18))) { + case KGpgTransaction::BA_YES: + write("YES\n"); + break; + case KGpgTransaction::BA_NO: + write("NO\n"); + break; + case KGpgTransaction::BA_UNKNOWN: + m_parent->setSuccess(KGpgTransaction::TS_MSG_SEQUENCE); + m_parent->unexpectedLine(line); + sendQuit(); + } + } else if (line.startsWith(QLatin1String("[GNUPG:] CARDCTRL "))) { + // just ignore them, pinentry should handle that + } else if (m_parent->nextLine(line)) { + sendQuit(); + } + } +} + +void +KGpgTransactionPrivate::slotProcessExited() +{ + Q_ASSERT(m_parent->sender() == m_process); + m_ownProcessFinished = true; + + if (m_inputProcessDone) + processDone(); +} + +void +KGpgTransactionPrivate::slotProcessStarted() +{ + m_parent->postStart(); +} + +void +KGpgTransactionPrivate::sendQuit(void) +{ + write("quit\n"); + +#ifdef KGPG_DEBUG_TRANSACTIONS + if (m_quitTries == 0) + qDebug() << "sending quit"; +#endif /* KGPG_DEBUG_TRANSACTIONS */ + + if (m_quitTries++ >= 3) { + qDebug() << "tried" << m_quitTries << "times to quit the GnuPG session"; + qDebug() << "last input was" << m_quitLines; + qDebug() << "please file a bug report at https://bugs.kde.org"; + m_process->closeWriteChannel(); + m_success = KGpgTransaction::TS_MSG_SEQUENCE; + } +} + +void +KGpgTransactionPrivate::slotInputTransactionDone(int result) +{ + Q_ASSERT(m_parent->sender() == m_inputTransaction); + + m_inputProcessDone = true; + m_inputProcessResult = result; + + if (m_ownProcessFinished) + processDone(); +} + +void +KGpgTransactionPrivate::slotPasswordEntered(const QString &password) +{ + sender()->deleteLater(); + //m_passwordDialog = NULL; + m_process->write(password.toUtf8() + '\n'); + m_parent->newPasswordEntered(); +} + +void +KGpgTransactionPrivate::slotPasswordAborted() +{ + sender()->deleteLater(); + //m_passwordDialog = NULL; + m_process->closeWriteChannel(); + m_success = KGpgTransaction::TS_USER_ABORTED; +} + +void +KGpgTransactionPrivate::write(const QByteArray &a) +{ + m_process->write(a); +#ifdef KGPG_DEBUG_TRANSACTIONS + qDebug() << m_parent << a; +#endif /* KGPG_DEBUG_TRANSACTIONS */ + qDebug() << "trans-write: " << m_parent << a; +} + +void +KGpgTransactionPrivate::processDone() +{ + m_parent->finish(); + emit m_parent->infoProgress(100, 100); + emit m_parent->done(m_success); +} + +void +KGpgTransaction::start() +{ + d->m_inputProcessResult = false; + d->m_inputProcessDone = (d->m_inputTransaction == NULL); + + setSuccess(TS_OK); + d->m_idhints.clear(); + d->m_tries = 3; + if (preStart()) { + d->m_ownProcessFinished = false; + if (d->m_inputTransaction != NULL) + d->m_inputTransaction->start(); +#ifdef KGPG_DEBUG_TRANSACTIONS + kDebug(2100) << this << d->m_process->program(); +#endif /* KGPG_DEBUG_TRANSACTIONS */ + d->m_process->start(); + emit infoProgress(0, 1); + } else { + emit done(d->m_success); + } +} + +void +KGpgTransaction::write(const QByteArray &a, const bool lf) +{ + if (lf) + d->write(a + '\n'); + else + d->write(a); +} + +void +KGpgTransaction::write(const int i) +{ + write(QByteArray::number(i)); +} + +void +KGpgTransaction::askNewPassphrase(const QString& text) +{ + qDebug() << "KGpgTransaction::askNewPassphrase called"; + + emit statusMessage(tr("Requesting Passphrase")); + + /*d->m_passwordDialog = new KNewPasswordDialog(qobject_cast<QWidget *>(parent())); + d->m_passwordDialog->setPrompt(text); + d->m_passwordDialog->setAllowEmptyPasswords(false); + connect(d->m_passwordDialog, SIGNAL(newPassword(QString)), SLOT(slotPasswordEntered(QString))); + connect(d->m_passwordDialog, SIGNAL(rejected()), SLOT(slotPasswordAborted())); + connect(d->m_process, SIGNAL(processExited()), d->m_passwordDialog->button(KDialog::Cancel), SLOT(clicked())); + d->m_passwordDialog->show();*/ + + +} + +int +KGpgTransaction::getSuccess() const +{ + return d->m_success; +} + +void +KGpgTransaction::setSuccess(const int v) +{ +#ifdef KGPG_DEBUG_TRANSACTIONS + qDebug() << d->m_success << v; +#endif /* KGPG_DEBUG_TRANSACTIONS */ + d->m_success = v; +} + +KGpgTransaction::ts_boolanswer +KGpgTransaction::boolQuestion(const QString& line) +{ + Q_UNUSED(line); + + return BA_UNKNOWN; +} + +void +KGpgTransaction::finish() +{ +} + +void +KGpgTransaction::setDescription(const QString &description) +{ + d->m_description = description; +} + +void +KGpgTransaction::waitForInputTransaction() +{ + Q_ASSERT(d->m_inputTransaction != NULL); + + if (d->m_inputProcessDone) + return; + + d->m_inputTransaction->waitForFinished(); +} + +void +KGpgTransaction::unexpectedLine(const QString &line) +{ + qDebug() << this << "unexpected input line" << line << "for command" << d->m_process->program(); +} + +KGpgTransaction::ts_passphrase_actions +KGpgTransaction::passphraseRequested() +{ + qDebug() << "KGpgTransaction::passphraseRequested called"; + if (!askPassphrase()) + return PA_USER_ABORTED; + else + return PA_CLOSE_GOOD; +} + +bool +KGpgTransaction::preStart() +{ + return true; +} + +void +KGpgTransaction::postStart() +{ +} + +void +KGpgTransaction::addIdHint(QString txt) +{ + int cut = txt.indexOf(QLatin1Char( ' ' ), 22, Qt::CaseInsensitive); + txt.remove(0, cut); + + if (txt.contains(QLatin1Char( '(' ), Qt::CaseInsensitive)) + txt = txt.section(QLatin1Char( '(' ), 0, 0) + txt.section(QLatin1Char( ')' ), -1); + + txt.replace(QLatin1Char( '<' ), QLatin1String( "<" )); + + if (!d->m_idhints.contains(txt)) + d->m_idhints << txt; +} + +QString +KGpgTransaction::getIdHints() const +{ + return d->m_idhints.join( tr(" or " )); +} + +GPGProc * +KGpgTransaction::getProcess() +{ + return d->m_process; +} + +int +KGpgTransaction::addArgument(const QString &arg) +{ + int r = d->m_process->program().count(); + + *d->m_process << arg; + + return r; +} + +int +KGpgTransaction::addArguments(const QStringList &args) +{ + int r = d->m_process->program().count(); + + *d->m_process << args; + + return r; +} + +void +KGpgTransaction::replaceArgument(const int pos, const QString &arg) +{ + QStringList args(d->m_process->program()); + d->m_process->clearProgram(); + + args.replace(pos, arg); + + d->m_process->setProgram(args); +} + +void +KGpgTransaction::insertArgument(const int pos, const QString &arg) +{ + insertArguments(pos, QStringList(arg)); +} + +void +KGpgTransaction::insertArguments(const int pos, const QStringList &args) +{ + QStringList tmp(d->m_process->program()); + + int tmppos = pos; + foreach (const QString &s, args) { + tmp.insert(tmppos++, s); + } + d->m_process->setProgram(tmp); + + int move = args.count(); + foreach (int *ref, d->m_argRefs) { + if (*ref >= pos) + *ref += move; + } +} + +void +KGpgTransaction::addArgumentRef(int *ref) +{ + d->m_argRefs.append(ref); +} + +bool +KGpgTransaction::askPassphrase(const QString &message) +{ + qDebug() << "KGpgTransaction::askPassphrase called"; + + if (d->m_passphraseAction == PA_USER_ABORTED) + return false; + + QString passdlgmessage; + QString userIDs(getIdHints()); + if (userIDs.isEmpty()) + userIDs = tr("[No user id found]"); + else + userIDs.replace(QLatin1Char( '<' ), QLatin1String( "<" )); + + if (d->m_tries < 3) + passdlgmessage = tr("<p><b>Bad passphrase</b>. You have 1 try left.</p>", "<p><b>Bad passphrase</b>. You have %1 tries left.</p>", d->m_tries); + if (message.isEmpty()) { + passdlgmessage += tr("Enter passphrase for <b>%1</b>").arg(userIDs); + } else { + passdlgmessage += message; + } + + --d->m_tries; + + emit statusMessage(tr("Requesting Passphrase")); + return (KgpgInterface::sendPassphrase(passdlgmessage, d->m_process, qobject_cast<QWidget *>(parent())) == 0); +} + +void +KGpgTransaction::setGnuPGHome(const QString &home) +{ + QStringList tmp(d->m_process->program()); + + Q_ASSERT(tmp.count() > 3); + int homepos = tmp.indexOf(QLatin1String("--options"), 1); + if (homepos == -1) + homepos = tmp.indexOf(QLatin1String("--homedir"), 1); + Q_ASSERT(homepos != -1); + Q_ASSERT(homepos + 1 < tmp.count()); + + tmp[homepos] = QLatin1String("--homedir"); + tmp[homepos + 1] = home; + + d->m_process->setProgram(tmp); +} + +int +KGpgTransaction::waitForFinished(const int msecs) +{ + int ret = TS_OK; + + if (d->m_inputTransaction != NULL) { + int ret = d->m_inputTransaction->waitForFinished(msecs); + if ((ret != TS_OK) && (msecs != -1)) + return ret; + } + + bool b = d->m_process->waitForFinished(msecs); + + if (ret != TS_OK) + return ret; + + if (!b) + return TS_USER_ABORTED; + else + return getSuccess(); +} + +const QString & +KGpgTransaction::getDescription() const +{ + return d->m_description; +} + +void +KGpgTransaction::setInputTransaction(KGpgTransaction *ta) +{ + Q_ASSERT(d->m_chainingAllowed); + + if (d->m_inputTransaction != NULL) + clearInputTransaction(); + d->m_inputTransaction = ta; + + GPGProc *proc = ta->getProcess(); + proc->setStandardOutputProcess(d->m_process); + connect(ta, SIGNAL(done(int)), SLOT(slotInputTransactionDone(int))); +} + +void +KGpgTransaction::clearInputTransaction() +{ + disconnect(d->m_inputTransaction, SIGNAL(done(int)), this, SLOT(slotInputTransactionDone(int))); + d->m_inputTransaction = NULL; +} + +bool +KGpgTransaction::hasInputTransaction() const +{ + return (d->m_inputTransaction != NULL); +} + +void +KGpgTransaction::kill() +{ + d->m_process->kill(); +} + +void +KGpgTransaction::newPasswordEntered() +{ +} + +//#include "moc_kgpgtransaction.cpp" diff --git a/kgpg/transactions/kgpgtransaction.h b/kgpg/transactions/kgpgtransaction.h new file mode 100644 index 0000000..8fc76a5 --- /dev/null +++ b/kgpg/transactions/kgpgtransaction.h @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2008,2009 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KGPGTRANSACTION_H +#define KGPGTRANSACTION_H + +#include <QObject> +#include <QString> +#include <QStringList> + +class GPGProc; +class KGpgSignTransactionHelper; +class KGpgTransactionPrivate; +class QByteArray; +class QProcess; + +/** + * @brief Process one GnuPG operation + * + * This class encapsulates one GnuPG operation. It will care for all + * interaction with the gpg process. Everything you have to care about + * is to set up the object properly, call start() and catch the done signal. + * + * This is an abstract base class for specific operations that implements + * the basic I/O loop, the process setup and interaction and some convenience + * members to set extra arguments for the process. + * + * If you want to add a new operation create a child class that implements + * nextLine(). Ususally you also need a constructor that takes some information + * like the id of the key to modify. + * + * @author Rolf Eike Beer + */ +class KGpgTransaction: public QObject { + Q_OBJECT + + friend class KGpgTransactionPrivate; + friend class KGpgSignTransactionHelper; + + Q_DISABLE_COPY(KGpgTransaction) + +public: + /** + * @brief return codes common to many transactions + * + * Every transaction may define additional return codes, which + * should start at TS_COMMON_END + 1. + */ + enum ts_transaction { + TS_OK = 0, ///< everything went fine + TS_BAD_PASSPHRASE = 1, ///< the passphrase was not correct + TS_MSG_SEQUENCE = 2, ///< unexpected sequence of GnuPG messages + TS_USER_ABORTED = 3, ///< the user aborted the transaction + TS_INVALID_EMAIL = 4, ///< the given email address is invalid + TS_INPUT_PROCESS_ERROR = 5, ///< the connected input process returned an error + TS_COMMON_END = 100 ///< placeholder for return values of derived classes + }; + /** + * @brief result codes for GnuPG boolean questions + * + * These are the possible answers to a boolean question of a GnuPG process. + */ + enum ts_boolanswer { + BA_UNKNOWN = 0, ///< the question is not supported (this is an error) + BA_YES = 1, ///< answer "YES" + BA_NO = 2 ///< answer "NO" + }; + /** + * @brief actions to do after a passphrase was sent to GnuPG + */ + enum ts_passphrase_actions { + PA_NONE = 0, ///< do nothing special + PA_CLOSE_GOOD = 1, ///< close command channel if passphrase was accepted + PA_USER_ABORTED = 2 ///< the user has cancelled the dialog, abort the transaction + }; + + /** + * @brief KGpgTransaction constructor + */ + explicit KGpgTransaction(QObject *parent = 0, const bool allowChaining = false); + /** + * @brief KGpgTransaction destructor + */ + virtual ~KGpgTransaction(); + + /** + * @brief Start the operation. + */ + void start(); + + /** + * @brief sets the home directory of GnuPG called for this transaction + */ + void setGnuPGHome(const QString &home); + + /** + * @brief blocks until the transaction is complete + * @return the result of the transaction like done() would + * @retval TS_USER_ABORTED the timeout expired + * + * If this transaction has another transaction set as input then + * it would wait for those transaction to finish first. The msecs + * argument is used as limit for both transactions then so you + * can end up waiting twice the given time (or longer if you have + * more transactions chained). + */ + int waitForFinished(const int msecs = -1); + + /** + * @brief return description of this transaction + * @return string used to describe what's going on + * + * This is especially useful when using this transaction from a KJob. + */ + const QString &getDescription() const; + + /** + * @brief connect the standard input of this transaction to another process + * @param proc process to read data from + * + * Once the input process is connected this transaction will not emit + * the done signal until the input process sends the done signal. + * + * The basic idea is that when an input transaction is set you only need + * to care about this transaction. The other transaction is automatically + * started when this one is started and is destroyed when this one is. + */ + void setInputTransaction(KGpgTransaction *ta); + + /** + * @brief tell the process the standard input is no longer connected + * + * If you had connected an input process you need to tell the transaction + * once this input process is gone. Otherwise you will not get a done + * signal from this transaction as it will wait for the finished signal + * from the process that will never come. + */ + void clearInputTransaction(); + + /** + * @brief check if another transaction will sent input to this + */ + bool hasInputTransaction() const; + + /** + * @brief abort this operation as soon as possible + */ + void kill(); + +signals: + /** + * @brief Emitted when the operation was completed. + * @param result return status of the transaction + * + * @see ts_transaction for the common status codes. Each transaction + * may define additional status codes. + */ + void done(int result); + + /** + * @brief emits textual status information + * @param msg the status message + */ + void statusMessage(const QString &msg); + + /** + * @brief emits procentual status information + * @param processedAmount how much of the job is done + * @param totalAmount how much needs to be done to complete this job + */ + void infoProgress(qulonglong processedAmount, qulonglong totalAmount); + +protected: + /** + * @brief Called before the gpg process is started. + * @return true if the process should be started + * + * You may reimplement this member if you need to do some special + * operations before the process is started. The command line of the + * process may be modified for the last time here. + * + * When you notice that some values passed are invalid or the + * transaction does not need to be run for some other reason you should + * call setSuccess() to set the return value and return false. In this + * case the process is not started but the value is immediately + * returned. + */ + virtual bool preStart(); + /** + * @brief Called when the gpg process is up and running. + * + * This functions is connected to the started() signal of the gpg process. + */ + virtual void postStart(); + /** + * @brief Called for every line the gpg process writes. + * @param line the input from the process + * @return true if "quit" should be sent to process + * + * You need to implement this member to get a usable subclass. + * + * When this function returns true "quit" is written to the process. + */ + virtual bool nextLine(const QString &line) = 0; + /** + * @brief Called for every boolean question GnuPG answers + * @param line the question GnuPG asked + * @return what to answer GnuPG + * + * This is called instead of nextLine() if the line contains a boolean + * question. Returning BA_UNKNOWN will cancel the current transaction + * and will set the transaction result to TS_MSG_SEQUENCE. + * + * The default implementation will answer BA_UNKNOWN to every question. + */ + virtual ts_boolanswer boolQuestion(const QString &line); + /** + * @brief Called when the gpg process finishes. + * + * You may reimplement this member if you need to do some special + * operations after process completion. The provided one simply + * does nothing which should be enough for most cases. + */ + virtual void finish(); + /** + * @brief called when the user entered a new password + * + * This is called after askNewPassphrase() was called, the user has + * entered a new password and it was sent to the GnuPG process. + * + * The default implementation does nothing. + */ + virtual void newPasswordEntered(); + /** + * @brief set the description returned in getDescription() + * @param description the new description of this transaction + */ + void setDescription(const QString &description); + + /** + * @brief wait until the input transaction has finished + */ + void waitForInputTransaction(); + + /** + * @brief notify of an unexpected line + * + * This will print out the line to the console to ease debugging. + */ + void unexpectedLine(const QString &line); + + /** + * @brief called when GnuPG asks for a passphrase + * @return true if "quit" should be sent to process + * + * This allows a transaction to implement special handling for + * passphrases, e.g. when both old and new passphrase must be + * requested when changing it. The default implementation will just + * call askPassphrase(). + */ + virtual ts_passphrase_actions passphraseRequested(); + +private: + KGpgTransactionPrivate* const d; + + Q_PRIVATE_SLOT(d, void slotReadReady()) + Q_PRIVATE_SLOT(d, void slotProcessExited()) + Q_PRIVATE_SLOT(d, void slotProcessStarted()) + Q_PRIVATE_SLOT(d, void slotInputTransactionDone(int)) + Q_PRIVATE_SLOT(d, void slotPasswordEntered(const QString &)) + Q_PRIVATE_SLOT(d, void slotPasswordAborted()) + +protected: + /** + * @brief Ask user for passphrase and send it to gpg process. + * + * If the gpg process asks for a new passphrase this function will do + * all necessary steps for you: ask the user for the password and write + * it to the gpg process. If the password is wrong the user is prompted + * again for the correct password. If the user aborts the password + * entry the gpg process will be killed and the transaction result will + * be set to TS_USER_ABORTED. + * + * In contrast to sendPassphrase() this function will not block, but + * handle everything using signals and slots. + * + * @see KgpgInterface::sendPassphrase + * @see askPassphrase + */ + void askNewPassphrase(const QString &text); + + /** + * @brief get the success value that will be returned with the done signal + */ + int getSuccess() const; + /** + * @brief set the success value that will be returned with the done signal + * @param v the new success value + * + * You should use 0 as success value. Other values can be defined as needed. + */ + void setSuccess(const int v); + + /** + * @brief add a userid hint + * @param txt userid description + * + * Before GnuPG asks for a passphrase it usually sends out a hint message + * for which key the passphrase will be needed. There may be several hint + * messages, e.g. if a text was encrypted with multiple keys. + */ + void addIdHint(QString txt); + /** + * @brief get string of all userid hints + * @returns concatenation of all ids previously added with addIdHint(). + */ + QString getIdHints() const; + + /** + * @brief get a reference to the gpg process object + * @returns gpg process object + * + * This returns a reference to the gpg process object used internally. + * In case you need to do some special things (e.g. changing the output + * mode) you can modify this object. + * + * Usually you will not need this. + * + * @warning Never free this object! + */ + GPGProc *getProcess(); + /** + * @brief add a command line argument to gpg process + * @param arg new argument + * @returns the position of the new argument + * + * This is a convenience function that allows adding one additional + * argument to the command line of the process. This must be called + * before start() is called. Usually you will call this from your + * constructor. + */ + int addArgument(const QString &arg); + /** + * @brief add command line arguments to gpg process + * @param args new arguments + * @returns the position of the first argument added + * + * This is a convenience function that allows adding additional + * arguments to the command line of the process. This must be called + * before start() is called. + */ + int addArguments(const QStringList &args); + /** + * @brief replace the argument at the given position + * @param pos position of old argument + * @param arg new argument + */ + void replaceArgument(const int pos, const QString &arg); + /** + * @brief insert an argument at the given position + * @param pos position to insert at + * @param arg new argument + */ + void insertArgument(const int pos, const QString &arg); + /** + * @brief insert arguments at the given position + * @param pos position to insert at + * @param args new arguments + */ + void insertArguments(const int pos, const QStringList &args); + /** + * @brief make sure the reference to a specific argument is kept up to date + * @param ref the value where the position is stored + * + * You might want to keep the position of a specific argument to + * later be able to repace it easily. In that case put it into + * this function too so every time someone mofifies the argument + * list (especially by insertArgument() and insertArguments()) + * this reference will be kept up to date. + */ + void addArgumentRef(int *ref); + /** + * @brief write data to standard input of gpg process + * @param a data to write + * @param lf if line feed should be appended to message + * + * Use this function to interact with the gpg process. A carriage + * return is appended to the data automatically. Usually you will + * call this function from nextLine(). + */ + void write(const QByteArray &a, const bool lf = true); + /** + * @brief write data to standard input of gpg process + * @param i data to write + * + * @overload + */ + void write(const int i); + /** + * @brief ask user for password + * @param message message to display to the user. If message is empty + * "Enter password for [UID]" will be used. + * @return true if the authorization was successful + * + * This function handles user authorization for key changes. It will + * take care to display the message asking the user for the password + * and the number of tries left. + */ + bool askPassphrase(const QString &message = QString()); +}; + +class KGpgTransactionPrivate: QObject { +public: + KGpgTransactionPrivate(KGpgTransaction *parent, bool allowChaining); + ~KGpgTransactionPrivate(); + + KGpgTransaction *m_parent; + GPGProc *m_process; + KGpgTransaction *m_inputTransaction; + //KNewPasswordDialog *m_passwordDialog; + int m_success; + int m_tries; + QString m_description; + bool m_chainingAllowed; + KGpgTransaction::ts_passphrase_actions m_passphraseAction; ///< ignore further request for passphrase + + QStringList m_idhints; + + void slotReadReady(); + void slotProcessExited(); + void slotProcessStarted(); + void slotInputTransactionDone(int result); + void slotPasswordEntered(const QString &password); + void slotPasswordAborted(); + + QList<int *> m_argRefs; + bool m_inputProcessDone; + int m_inputProcessResult; + bool m_ownProcessFinished; + + /** + * terminate GnuPG session + */ + void sendQuit(void); + + void write(const QByteArray &a); + +private: + void processDone(); + + unsigned int m_quitTries; ///< how many times we tried to quit + QStringList m_quitLines; ///< what we received after we tried to quit +}; + +#endif // KGPGTRANSACTION_H diff --git a/kgpg/transactions/kgpgverify.cpp b/kgpg/transactions/kgpgverify.cpp new file mode 100644 index 0000000..e9dbb36 --- /dev/null +++ b/kgpg/transactions/kgpgverify.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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 "kgpgverify.h" + +#include "../gpgproc.h" +#include "../core/KGpgKeyNode.h" +//#include "../model/kgpgitemmodel.h" + +//#include <KGlobal> +//#include <KLocale> + +KGpgVerify::KGpgVerify(QObject *parent, const QString &text) + : KGpgTextOrFileTransaction(parent, text), + m_fileIndex(-1) +{ +} + +KGpgVerify::KGpgVerify(QObject *parent, const QList<QUrl> &files) + : KGpgTextOrFileTransaction(parent, files), + m_fileIndex(0) +{ +} + +KGpgVerify::~KGpgVerify() +{ +} + +QStringList +KGpgVerify::command() const +{ + QStringList ret(QLatin1String("--verify")); + + return ret; +} + +bool +KGpgVerify::nextLine(const QString &line) +{ + if (line.startsWith(QLatin1String("[GNUPG:] NO_PUBKEY "))) { + setSuccess(TS_MISSING_KEY); + m_missingId = line.mid(19).simplified(); + return false; + } + + if (line.startsWith(QLatin1String("[GNUPG:] ")) && + line.contains(QLatin1String("SIG"))) { + if (line.startsWith(QLatin1String("[GNUPG:] BADSIG"))) + setSuccess(KGpgVerify::TS_BAD_SIGNATURE); + else + setSuccess(KGpgTransaction::TS_OK); + } + + return KGpgTextOrFileTransaction::nextLine(line); +} + +void +KGpgVerify::finish() +{ + // GnuPG will return error code 2 if it wasn't able to verify the file. + // If it complained about a missing signature before that is fine. + if (((getProcess()->exitCode() == 2) && (getSuccess() == TS_MISSING_KEY)) || + ((getProcess()->exitCode() == 1) && (getSuccess() == TS_BAD_SIGNATURE))) + return; + + KGpgTextOrFileTransaction::finish(); +} + +static QString +sigTimeMessage(const QString &sigtime) +{ + QDateTime stamp; + if (sigtime.contains(QLatin1Char('T'))) { + stamp = QDateTime::fromString(sigtime, Qt::ISODate); + } else { + bool ok; + qint64 secs = sigtime.toLongLong(&ok); + if (ok) + stamp = QDateTime::fromMSecsSinceEpoch(secs * 1000); + } + + if (!stamp.isValid()) + return QString(); + +/* return tr("first argument is formatted date, second argument is formatted time", + "The signature was created at %1 %2", + KGlobal::locale()->formatDate(stamp.date(), KLocale::LongDate), + KGlobal::locale()->formatTime(stamp.time(), KLocale::LongDate)) + + QLatin1String("<br/>");*/ + return "todo"; +} + +/* +QString +KGpgVerify::getReport(const QStringList &log, const KGpgItemModel *model) +{ + QString result; + // newer versions of GnuPG emit both VALIDSIG and GOODSIG + // for a good signature. Since VALIDSIG has more information + // we use that. + const QRegExp validsig(QLatin1String("^\\[GNUPG:\\] VALIDSIG([ ]+[^ ]+){10,}.*$")); + const bool useGoodSig = (model != NULL) && (log.indexOf(validsig) == -1); + QString sigtime; // timestamp of signature creation + + foreach (const QString &line, log) { + if (!line.startsWith(QLatin1String("[GNUPG:] "))) + continue; + + const QString msg = line.mid(9); + + if (msg.startsWith(QLatin1String("VALIDSIG ")) && !useGoodSig) { + // from GnuPG source, doc/DETAILS: + // VALIDSIG <fingerprint in hex> <sig_creation_date> <sig-timestamp> + // <expire-timestamp> <sig-version> <reserved> <pubkey-algo> + // <hash-algo> <sig-class> <primary-key-fpr> + const QStringList vsig = msg.mid(9).split(QLatin1Char(' '), QString::SkipEmptyParts); + Q_ASSERT(vsig.count() >= 10); + + const KGpgKeyNode *node = model->findKeyNode(vsig[9]); + + if (node != NULL) { + // ignore for now if this is signed with the primary id (vsig[0] == vsig[9]) or not + if (node->getEmail().isEmpty()) + result += tr("<qt>Good signature from:<br /><b>%1</b><br />Key ID: %2<br /></qt>") + .arg(node->getName()).arg(vsig[9]); + else + result += tr("Good signature from: NAME <EMAIL>, Key ID: HEXID", + "<qt>Good signature from:<br /><b>%1 <%2></b><br />Key ID: %3<br /></qt>") + .arg(node->getName()).arg(node->getEmail()).arg(vsig[9]); + + result += sigTimeMessage(vsig[2]); + } else { + // this should normally never happen, but one could delete + // the key just after the verification. Brute force solution: + // do the whole report generation again, but this time make + // sure GOODSIG is used. + return getReport(log, NULL); + } + } else if (msg.startsWith(QLatin1String("UNEXPECTED")) || + msg.startsWith(QLatin1String("NODATA"))) { + result += tr("No signature found.") + QLatin1Char('\n'); + } else if (useGoodSig && msg.startsWith(QLatin1String("GOODSIG "))) { + int sigpos = msg.indexOf( ' ' , 8); + const QString keyid = msg.mid(8, sigpos - 8); + + // split the name/email pair to give translators more power to handle this + QString email; + QString name = msg.mid(sigpos + 1); + + int oPos = name.indexOf(QLatin1Char('<')); + int cPos = name.indexOf(QLatin1Char('>')); + if ((oPos >= 0) && (cPos >= 0)) { + email = name.mid(oPos + 1, cPos - oPos - 1); + name = name.left(oPos).simplified(); + } + + if (email.isEmpty()) + result += tr("<qt>Good signature from:<br /><b>%1</b><br />Key ID: %2<br /></qt>") + .arg(name).arg(keyid); + else + result += tr("Good signature from: NAME <EMAIL>, Key ID: HEXID", + "<qt>Good signature from:<br /><b>%1 <%2></b><br />Key ID: %3<br /></qt>") + .arg(name).arg(email).arg(keyid); + if (!sigtime.isEmpty()) { + result += sigTimeMessage(sigtime); + sigtime.clear(); + } + } else if (msg.startsWith(QLatin1String("SIG_ID "))) { + const QStringList parts = msg.simplified().split(QLatin1Char(' ')); + if (parts.count() > 2) + sigtime = parts[2]; + } else if (msg.startsWith(QLatin1String("BADSIG"))) { + int sigpos = msg.indexOf( ' ', 7); + result += tr("<qt><b>BAD signature</b> from:<br /> %1<br />Key id: %2<br /><br /><b>The file is corrupted</b><br /></qt>") + .arg(msg.mid(sigpos + 1).replace(QLatin1Char('<'), QLatin1String("<"))) + .arg(msg.mid(7, sigpos - 7)); + } else if (msg.startsWith(QLatin1String("TRUST_UNDEFINED"))) { + result += tr("<qt>The signature is valid, but the key is untrusted<br /></qt>"); + } else if (msg.startsWith(QLatin1String("TRUST_ULTIMATE"))) { + result += tr("<qt>The signature is valid, and the key is ultimately trusted<br /></qt>"); + } + } + + return result; +} +*/ + +QString +KGpgVerify::missingId() const +{ + return m_missingId; +} + +//#include "kgpgverify.moc" diff --git a/kgpg/transactions/kgpgverify.h b/kgpg/transactions/kgpgverify.h new file mode 100644 index 0000000..beba12f --- /dev/null +++ b/kgpg/transactions/kgpgverify.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2012 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KGPGVERIFY_H +#define KGPGVERIFY_H + +#include "kgpgtextorfiletransaction.h" + +#include <QObject> +#include <QString> +#include <QStringList> + +#include <QUrl> + +//class KGpgItemModel; +class QProcess; + +/** + * @brief verify the signature of the given text or files + */ +class KGpgVerify: public KGpgTextOrFileTransaction { + Q_OBJECT + + Q_DISABLE_COPY(KGpgVerify) + KGpgVerify(); // = delete C++0x +public: + enum ts_verify { + TS_MISSING_KEY = KGpgTransaction::TS_COMMON_END + 1, ///< signing key not in keyring + TS_BAD_SIGNATURE = TS_MISSING_KEY + 1 ///< the file is signed, but the signature is invalid + }; + + /** + * @brief verify signature of given text + * @param parent parent object + * @param text text to verify + */ + explicit KGpgVerify(QObject *parent, const QString &text = QString()); + + /** + * @brief verify signatures of file(s) + * @param parent parent object + * @param files list of file locations to verify + */ + KGpgVerify(QObject *parent, const QList<QUrl> &files); + + /** + * @brief destructor + */ + virtual ~KGpgVerify(); + + /** + * @brief get verification report + * @param log the log lines to scan + * @param model key model to use for key lookups + * @return verification report of GnuPG + */ + //static QString getReport(const QStringList &log, const KGpgItemModel *model = NULL); + + /** + * @brief get the missing key id + * @return key id that signed the message + * + * This is only valid if the transaction returned with result + * TS_MISSING_KEY. + */ + QString missingId() const; + +protected: + virtual QStringList command() const; + virtual bool nextLine(const QString &line); + virtual void finish(); + +private: + int m_fileIndex; + QString m_currentFile; + QStringList m_report; + QString m_missingId; +}; + +#endif // KGPGVERIFY_H |