aboutsummaryrefslogtreecommitdiffstats
path: root/kgpg/transactions
diff options
context:
space:
mode:
Diffstat (limited to 'kgpg/transactions')
-rw-r--r--kgpg/transactions/kgpgdecrypt.cpp141
-rw-r--r--kgpg/transactions/kgpgdecrypt.h86
-rw-r--r--kgpg/transactions/kgpgdelkey.cpp94
-rw-r--r--kgpg/transactions/kgpgdelkey.h55
-rw-r--r--kgpg/transactions/kgpgencrypt.cpp154
-rw-r--r--kgpg/transactions/kgpgencrypt.h94
-rw-r--r--kgpg/transactions/kgpgexport.cpp197
-rw-r--r--kgpg/transactions/kgpgexport.h147
-rw-r--r--kgpg/transactions/kgpggeneratekey.cpp276
-rw-r--r--kgpg/transactions/kgpggeneratekey.h99
-rw-r--r--kgpg/transactions/kgpgimport.cpp295
-rw-r--r--kgpg/transactions/kgpgimport.h129
-rw-r--r--kgpg/transactions/kgpgsigntext.cpp118
-rw-r--r--kgpg/transactions/kgpgsigntext.h98
-rw-r--r--kgpg/transactions/kgpgtextorfiletransaction.cpp165
-rw-r--r--kgpg/transactions/kgpgtextorfiletransaction.h109
-rw-r--r--kgpg/transactions/kgpgtransaction.cpp558
-rw-r--r--kgpg/transactions/kgpgtransaction.h465
-rw-r--r--kgpg/transactions/kgpgverify.cpp204
-rw-r--r--kgpg/transactions/kgpgverify.h90
20 files changed, 3574 insertions, 0 deletions
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 &lt;%2&gt;</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 &lt;%3&gt;", 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( "&lt;" ));
+
+ 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( "&lt;" ));
+
+ 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 &lt;%2&gt;</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 &lt;%2&gt;</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("&lt;")))
+ .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