diff options
author | ubbo <ubbo@34ebc366-c3a9-4b3c-9f84-69acf7962910> | 2012-08-03 20:38:27 +0000 |
---|---|---|
committer | ubbo <ubbo@34ebc366-c3a9-4b3c-9f84-69acf7962910> | 2012-08-03 20:38:27 +0000 |
commit | a274da36798b7aa7a7cbc9e85ec30748fa66047e (patch) | |
tree | b5f4e5403ecae4a86a28f8e58925c2a2f1e01db0 | |
parent | reorganize kgpg source tree (diff) | |
download | gpg4usb-a274da36798b7aa7a7cbc9e85ec30748fa66047e.tar.gz gpg4usb-a274da36798b7aa7a7cbc9e85ec30748fa66047e.zip |
start porting encrypt from kgpg, not yet working
git-svn-id: http://cpunk.de/svn/src/gpg4usb/branches/0.3.2-mac@932 34ebc366-c3a9-4b3c-9f84-69acf7962910
-rw-r--r-- | gpg4usb.pro | 11 | ||||
-rw-r--r-- | gpgcontext.cpp | 17 | ||||
-rw-r--r-- | kgpg/kgpginterface.cpp | 20 | ||||
-rw-r--r-- | kgpg/kprocess.cpp | 2 | ||||
-rw-r--r-- | kgpg/transactions/kgpgencrypt.cpp | 154 | ||||
-rw-r--r-- | kgpg/transactions/kgpgencrypt.h | 94 | ||||
-rw-r--r-- | kgpg/transactions/kgpgtextorfiletransaction.cpp | 150 | ||||
-rw-r--r-- | kgpg/transactions/kgpgtextorfiletransaction.h | 109 | ||||
-rw-r--r-- | kgpg/transactions/kgpgtransaction.cpp | 543 | ||||
-rw-r--r-- | kgpg/transactions/kgpgtransaction.h | 465 | ||||
-rw-r--r-- | mainwindow.cpp | 27 | ||||
-rw-r--r-- | mainwindow.h | 2 |
12 files changed, 1581 insertions, 13 deletions
diff --git a/gpg4usb.pro b/gpg4usb.pro index 84bc18c..5d90051 100644 --- a/gpg4usb.pro +++ b/gpg4usb.pro @@ -46,6 +46,7 @@ HEADERS += attachments.h \ kgpg/kprocess.h \ kgpg/kprocess_p.h \ kgpg/kgpginterface.h \ + gpgconstants.h \ kgpg/core/kgpgkey.h \ kgpg/core/KGpgSignableNode.h \ kgpg/core/KGpgExpandableNode.h \ @@ -62,7 +63,10 @@ HEADERS += attachments.h \ kgpg/core/KGpgOrphanNode.h \ kgpg/core/convert.h \ kgpg/core/images.h \ - gpgconstants.h + kgpg/transactions/kgpgtransaction.h \ + kgpg/transactions/kgpgtextorfiletransaction.h \ + kgpg/transactions/kgpgencrypt.h + SOURCES += attachments.cpp \ gpgcontext.cpp \ @@ -87,6 +91,7 @@ SOURCES += attachments.cpp \ verifykeydetailbox.cpp \ wizard.cpp \ helppage.cpp \ + gpgconstants.cpp \ kgpg/gpgproc.cpp \ kgpg/klinebufferedprocess.cpp \ kgpg/kprocess.cpp \ @@ -107,7 +112,9 @@ SOURCES += attachments.cpp \ kgpg/core/KGpgOrphanNode.cpp \ kgpg/core/convert.cpp \ kgpg/core/images.cpp \ - gpgconstants.cpp + kgpg/transactions/kgpgtransaction.cpp \ + kgpg/transactions/kgpgtextorfiletransaction.cpp \ + kgpg/transactions/kgpgencrypt.cpp RC_FILE = gpg4usb.rc diff --git a/gpgcontext.cpp b/gpgcontext.cpp index f87ed11..a6dec21 100644 --- a/gpgcontext.cpp +++ b/gpgcontext.cpp @@ -24,6 +24,7 @@ #include "kgpg/kgpginterface.h" #include "kgpg/klinebufferedprocess.h" #include "kgpg/core/kgpgkey.h" +#include "kgpg/transactions/kgpgencrypt.h" #ifdef _WIN32 #include <windows.h> #include <unistd.h> /* contains read/write */ @@ -274,7 +275,7 @@ void GpgContext::deleteKeys(QStringList *uidList) bool GpgContext::encrypt(QStringList *uidList, const QByteArray &inBuffer, QByteArray *outBuffer) { - gpgme_data_t in = 0, out = 0; + /*gpgme_data_t in = 0, out = 0; outBuffer->resize(0); if (uidList->count() == 0) { @@ -285,7 +286,7 @@ bool GpgContext::encrypt(QStringList *uidList, const QByteArray &inBuffer, QByte //gpgme_encrypt_result_t e_result; gpgme_key_t recipients[uidList->count()+1]; - /* get key for user */ + // get key for user for (int i = 0; i < uidList->count(); i++) { // the last 0 is for public keys, 1 would return private keys gpgme_op_keylist_start(mCtx, uidList->at(i).toAscii().constData(), 0); @@ -312,7 +313,7 @@ bool GpgContext::encrypt(QStringList *uidList, const QByteArray &inBuffer, QByte } } } - /* unref all keys */ + // unref all keys for (int i = 0; i <= uidList->count(); i++) { gpgme_key_unref(recipients[i]); } @@ -322,9 +323,17 @@ bool GpgContext::encrypt(QStringList *uidList, const QByteArray &inBuffer, QByte if (out) { gpgme_data_release(out); } - return (err == GPG_ERR_NO_ERROR); + return (err == GPG_ERR_NO_ERROR);*/ + QStringList options; + KGpgEncrypt::EncryptOptions opts = KGpgEncrypt::DefaultEncryption; + + //KGpgEncrypt *encr = new KGpgEncrypt(this, uidList, toPlainText(), opts, options); + //encr->start(); + //connect(encr, SIGNAL(done(int)), SLOT(slotEncodeUpdate(int))); } + + /** Decrypt QByteAarray, return QByteArray * mainly from http://basket.kde.org/ (kgpgme.cpp) */ diff --git a/kgpg/kgpginterface.cpp b/kgpg/kgpginterface.cpp index 0c14b33..a907fe3 100644 --- a/kgpg/kgpginterface.cpp +++ b/kgpg/kgpginterface.cpp @@ -35,6 +35,7 @@ #include <QString> #include <QTextStream> #include <QDebug> +#include <QInputDialog> using namespace KgpgCore; @@ -143,28 +144,37 @@ void KgpgInterface::setGpgBoolSetting(const QString &name, const bool enable, co } } -/*int KgpgInterface::sendPassphrase(const QString &text, KProcess *process, QWidget *widget) +int KgpgInterface::sendPassphrase(const QString &text, KProcess *process, QWidget *widget) { QPointer<KProcess> gpgprocess = process; QByteArray passphrase; - int code; + //int code; + bool result; - QPointer<KPasswordDialog> dlg = new KPasswordDialog(widget); + /*QPointer<KPasswordDialog> dlg = new KPasswordDialog(widget); QObject::connect(process, SIGNAL(processExited()), dlg->button(KDialog::Cancel), SLOT(click())); dlg->setPrompt(text); - code = dlg->exec(); + code = dlg->exec(); + if (!dlg.isNull()) passphrase = dlg->password().toUtf8(); delete dlg; if (code != KPasswordDialog::Accepted) return 1; +*/ + + QString password = QInputDialog::getText(QApplication::activeWindow(), QObject::tr("Enter Password"), + text, QLineEdit::Password, + "", &result); + + passphrase = password.toAscii(); if (!gpgprocess.isNull()) gpgprocess->write(passphrase + '\n'); return 0; -}*/ +} /** * @param p the process that reads the GnuPG data diff --git a/kgpg/kprocess.cpp b/kgpg/kprocess.cpp index ba71ebd..907c75c 100644 --- a/kgpg/kprocess.cpp +++ b/kgpg/kprocess.cpp @@ -341,7 +341,7 @@ QStringList KProcess::program() const void KProcess::start() { Q_D(KProcess); - //qDebug() << "prog: " << d->prog << " | args: " << d->args; + qDebug() << "prog: " << d->prog << " | args: " << d->args; QProcess::start(d->prog, d->args, d->openMode); } 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/kgpgtextorfiletransaction.cpp b/kgpg/transactions/kgpgtextorfiletransaction.cpp new file mode 100644 index 0000000..6989353 --- /dev/null +++ b/kgpg/transactions/kgpgtextorfiletransaction.cpp @@ -0,0 +1,150 @@ +/* + * 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> + +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; +} + +bool +KGpgTextOrFileTransaction::preStart() +{ + QStringList locfiles; + + foreach (const QUrl &url, m_inpfiles) { + 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; + }*/ + } + } + + 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; + } else { + m_closeInput = !args.contains(QLatin1String("--command-fd=0")); + } + if (locfiles.count() + m_tempfiles.count() > 1) + args << QLatin1String("--multifile"); + args << locfiles << m_tempfiles; + addArguments(args); + + return true; +} + +void +KGpgTextOrFileTransaction::postStart() +{ + if (!m_text.isEmpty()){ + GPGProc *proc = getProcess(); + proc->write(m_text.toUtf8()); + if (m_closeInput) + proc->closeWriteChannel(); + } +} + +bool +KGpgTextOrFileTransaction::nextLine(const QString &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..84783aa --- /dev/null +++ b/kgpg/transactions/kgpgtransaction.cpp @@ -0,0 +1,543 @@ +/* + * 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 + kDebug(2100) << m_parent << line; +#endif /* KGPG_DEBUG_TRANSACTIONS */ + + 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. + 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 + kDebug(2100) << m_parent << a; +#endif /* KGPG_DEBUG_TRANSACTIONS */ +} + +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) +{ + 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() +{ + if (!askPassphrase()) + return PA_USER_ABORTED; + else + return PA_CLOSE_GOOD; +} + +bool +KGpgTransaction::preStart() +{ + return true; +} + +void +KGpgTransaction::postStart() +{ +} + +void +KGpgTransaction::addIdHint(QString txt) +{ + int cut = txt.indexOf(QLatin1Char( ' ' ), 22, Qt::CaseInsensitive); + txt.remove(0, cut); + + if (txt.contains(QLatin1Char( '(' ), Qt::CaseInsensitive)) + txt = txt.section(QLatin1Char( '(' ), 0, 0) + txt.section(QLatin1Char( ')' ), -1); + + txt.replace(QLatin1Char( '<' ), QLatin1String( "<" )); + + if (!d->m_idhints.contains(txt)) + d->m_idhints << txt; +} + +QString +KGpgTransaction::getIdHints() const +{ + return d->m_idhints.join( tr(" or " )); +} + +GPGProc * +KGpgTransaction::getProcess() +{ + return d->m_process; +} + +int +KGpgTransaction::addArgument(const QString &arg) +{ + int r = d->m_process->program().count(); + + *d->m_process << arg; + + return r; +} + +int +KGpgTransaction::addArguments(const QStringList &args) +{ + int r = d->m_process->program().count(); + + *d->m_process << args; + + return r; +} + +void +KGpgTransaction::replaceArgument(const int pos, const QString &arg) +{ + QStringList args(d->m_process->program()); + d->m_process->clearProgram(); + + args.replace(pos, arg); + + d->m_process->setProgram(args); +} + +void +KGpgTransaction::insertArgument(const int pos, const QString &arg) +{ + insertArguments(pos, QStringList(arg)); +} + +void +KGpgTransaction::insertArguments(const int pos, const QStringList &args) +{ + QStringList tmp(d->m_process->program()); + + int tmppos = pos; + foreach (const QString &s, args) { + tmp.insert(tmppos++, s); + } + d->m_process->setProgram(tmp); + + int move = args.count(); + foreach (int *ref, d->m_argRefs) { + if (*ref >= pos) + *ref += move; + } +} + +void +KGpgTransaction::addArgumentRef(int *ref) +{ + d->m_argRefs.append(ref); +} + +bool +KGpgTransaction::askPassphrase(const QString &message) +{ + if (d->m_passphraseAction == PA_USER_ABORTED) + return false; + + QString passdlgmessage; + QString userIDs(getIdHints()); + if (userIDs.isEmpty()) + userIDs = tr("[No user id found]"); + else + userIDs.replace(QLatin1Char( '<' ), QLatin1String( "<" )); + + if (d->m_tries < 3) + passdlgmessage = tr("<p><b>Bad passphrase</b>. You have 1 try left.</p>", "<p><b>Bad passphrase</b>. You have %1 tries left.</p>", d->m_tries); + if (message.isEmpty()) { + passdlgmessage += tr("Enter passphrase for <b>%1</b>").arg(userIDs); + } else { + passdlgmessage += message; + } + + --d->m_tries; + + emit statusMessage(tr("Requesting Passphrase")); + return (KgpgInterface::sendPassphrase(passdlgmessage, d->m_process, qobject_cast<QWidget *>(parent())) == 0); +} + +void +KGpgTransaction::setGnuPGHome(const QString &home) +{ + QStringList tmp(d->m_process->program()); + + Q_ASSERT(tmp.count() > 3); + int homepos = tmp.indexOf(QLatin1String("--options"), 1); + if (homepos == -1) + homepos = tmp.indexOf(QLatin1String("--homedir"), 1); + Q_ASSERT(homepos != -1); + Q_ASSERT(homepos + 1 < tmp.count()); + + tmp[homepos] = QLatin1String("--homedir"); + tmp[homepos + 1] = home; + + d->m_process->setProgram(tmp); +} + +int +KGpgTransaction::waitForFinished(const int msecs) +{ + int ret = TS_OK; + + if (d->m_inputTransaction != NULL) { + int ret = d->m_inputTransaction->waitForFinished(msecs); + if ((ret != TS_OK) && (msecs != -1)) + return ret; + } + + bool b = d->m_process->waitForFinished(msecs); + + if (ret != TS_OK) + return ret; + + if (!b) + return TS_USER_ABORTED; + else + return getSuccess(); +} + +const QString & +KGpgTransaction::getDescription() const +{ + return d->m_description; +} + +void +KGpgTransaction::setInputTransaction(KGpgTransaction *ta) +{ + Q_ASSERT(d->m_chainingAllowed); + + if (d->m_inputTransaction != NULL) + clearInputTransaction(); + d->m_inputTransaction = ta; + + GPGProc *proc = ta->getProcess(); + proc->setStandardOutputProcess(d->m_process); + connect(ta, SIGNAL(done(int)), SLOT(slotInputTransactionDone(int))); +} + +void +KGpgTransaction::clearInputTransaction() +{ + disconnect(d->m_inputTransaction, SIGNAL(done(int)), this, SLOT(slotInputTransactionDone(int))); + d->m_inputTransaction = NULL; +} + +bool +KGpgTransaction::hasInputTransaction() const +{ + return (d->m_inputTransaction != NULL); +} + +void +KGpgTransaction::kill() +{ + d->m_process->kill(); +} + +void +KGpgTransaction::newPasswordEntered() +{ +} + +//#include "moc_kgpgtransaction.cpp" diff --git a/kgpg/transactions/kgpgtransaction.h b/kgpg/transactions/kgpgtransaction.h new file mode 100644 index 0000000..8fc76a5 --- /dev/null +++ b/kgpg/transactions/kgpgtransaction.h @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2008,2009 Rolf Eike Beer <[email protected]> + */ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef KGPGTRANSACTION_H +#define KGPGTRANSACTION_H + +#include <QObject> +#include <QString> +#include <QStringList> + +class GPGProc; +class KGpgSignTransactionHelper; +class KGpgTransactionPrivate; +class QByteArray; +class QProcess; + +/** + * @brief Process one GnuPG operation + * + * This class encapsulates one GnuPG operation. It will care for all + * interaction with the gpg process. Everything you have to care about + * is to set up the object properly, call start() and catch the done signal. + * + * This is an abstract base class for specific operations that implements + * the basic I/O loop, the process setup and interaction and some convenience + * members to set extra arguments for the process. + * + * If you want to add a new operation create a child class that implements + * nextLine(). Ususally you also need a constructor that takes some information + * like the id of the key to modify. + * + * @author Rolf Eike Beer + */ +class KGpgTransaction: public QObject { + Q_OBJECT + + friend class KGpgTransactionPrivate; + friend class KGpgSignTransactionHelper; + + Q_DISABLE_COPY(KGpgTransaction) + +public: + /** + * @brief return codes common to many transactions + * + * Every transaction may define additional return codes, which + * should start at TS_COMMON_END + 1. + */ + enum ts_transaction { + TS_OK = 0, ///< everything went fine + TS_BAD_PASSPHRASE = 1, ///< the passphrase was not correct + TS_MSG_SEQUENCE = 2, ///< unexpected sequence of GnuPG messages + TS_USER_ABORTED = 3, ///< the user aborted the transaction + TS_INVALID_EMAIL = 4, ///< the given email address is invalid + TS_INPUT_PROCESS_ERROR = 5, ///< the connected input process returned an error + TS_COMMON_END = 100 ///< placeholder for return values of derived classes + }; + /** + * @brief result codes for GnuPG boolean questions + * + * These are the possible answers to a boolean question of a GnuPG process. + */ + enum ts_boolanswer { + BA_UNKNOWN = 0, ///< the question is not supported (this is an error) + BA_YES = 1, ///< answer "YES" + BA_NO = 2 ///< answer "NO" + }; + /** + * @brief actions to do after a passphrase was sent to GnuPG + */ + enum ts_passphrase_actions { + PA_NONE = 0, ///< do nothing special + PA_CLOSE_GOOD = 1, ///< close command channel if passphrase was accepted + PA_USER_ABORTED = 2 ///< the user has cancelled the dialog, abort the transaction + }; + + /** + * @brief KGpgTransaction constructor + */ + explicit KGpgTransaction(QObject *parent = 0, const bool allowChaining = false); + /** + * @brief KGpgTransaction destructor + */ + virtual ~KGpgTransaction(); + + /** + * @brief Start the operation. + */ + void start(); + + /** + * @brief sets the home directory of GnuPG called for this transaction + */ + void setGnuPGHome(const QString &home); + + /** + * @brief blocks until the transaction is complete + * @return the result of the transaction like done() would + * @retval TS_USER_ABORTED the timeout expired + * + * If this transaction has another transaction set as input then + * it would wait for those transaction to finish first. The msecs + * argument is used as limit for both transactions then so you + * can end up waiting twice the given time (or longer if you have + * more transactions chained). + */ + int waitForFinished(const int msecs = -1); + + /** + * @brief return description of this transaction + * @return string used to describe what's going on + * + * This is especially useful when using this transaction from a KJob. + */ + const QString &getDescription() const; + + /** + * @brief connect the standard input of this transaction to another process + * @param proc process to read data from + * + * Once the input process is connected this transaction will not emit + * the done signal until the input process sends the done signal. + * + * The basic idea is that when an input transaction is set you only need + * to care about this transaction. The other transaction is automatically + * started when this one is started and is destroyed when this one is. + */ + void setInputTransaction(KGpgTransaction *ta); + + /** + * @brief tell the process the standard input is no longer connected + * + * If you had connected an input process you need to tell the transaction + * once this input process is gone. Otherwise you will not get a done + * signal from this transaction as it will wait for the finished signal + * from the process that will never come. + */ + void clearInputTransaction(); + + /** + * @brief check if another transaction will sent input to this + */ + bool hasInputTransaction() const; + + /** + * @brief abort this operation as soon as possible + */ + void kill(); + +signals: + /** + * @brief Emitted when the operation was completed. + * @param result return status of the transaction + * + * @see ts_transaction for the common status codes. Each transaction + * may define additional status codes. + */ + void done(int result); + + /** + * @brief emits textual status information + * @param msg the status message + */ + void statusMessage(const QString &msg); + + /** + * @brief emits procentual status information + * @param processedAmount how much of the job is done + * @param totalAmount how much needs to be done to complete this job + */ + void infoProgress(qulonglong processedAmount, qulonglong totalAmount); + +protected: + /** + * @brief Called before the gpg process is started. + * @return true if the process should be started + * + * You may reimplement this member if you need to do some special + * operations before the process is started. The command line of the + * process may be modified for the last time here. + * + * When you notice that some values passed are invalid or the + * transaction does not need to be run for some other reason you should + * call setSuccess() to set the return value and return false. In this + * case the process is not started but the value is immediately + * returned. + */ + virtual bool preStart(); + /** + * @brief Called when the gpg process is up and running. + * + * This functions is connected to the started() signal of the gpg process. + */ + virtual void postStart(); + /** + * @brief Called for every line the gpg process writes. + * @param line the input from the process + * @return true if "quit" should be sent to process + * + * You need to implement this member to get a usable subclass. + * + * When this function returns true "quit" is written to the process. + */ + virtual bool nextLine(const QString &line) = 0; + /** + * @brief Called for every boolean question GnuPG answers + * @param line the question GnuPG asked + * @return what to answer GnuPG + * + * This is called instead of nextLine() if the line contains a boolean + * question. Returning BA_UNKNOWN will cancel the current transaction + * and will set the transaction result to TS_MSG_SEQUENCE. + * + * The default implementation will answer BA_UNKNOWN to every question. + */ + virtual ts_boolanswer boolQuestion(const QString &line); + /** + * @brief Called when the gpg process finishes. + * + * You may reimplement this member if you need to do some special + * operations after process completion. The provided one simply + * does nothing which should be enough for most cases. + */ + virtual void finish(); + /** + * @brief called when the user entered a new password + * + * This is called after askNewPassphrase() was called, the user has + * entered a new password and it was sent to the GnuPG process. + * + * The default implementation does nothing. + */ + virtual void newPasswordEntered(); + /** + * @brief set the description returned in getDescription() + * @param description the new description of this transaction + */ + void setDescription(const QString &description); + + /** + * @brief wait until the input transaction has finished + */ + void waitForInputTransaction(); + + /** + * @brief notify of an unexpected line + * + * This will print out the line to the console to ease debugging. + */ + void unexpectedLine(const QString &line); + + /** + * @brief called when GnuPG asks for a passphrase + * @return true if "quit" should be sent to process + * + * This allows a transaction to implement special handling for + * passphrases, e.g. when both old and new passphrase must be + * requested when changing it. The default implementation will just + * call askPassphrase(). + */ + virtual ts_passphrase_actions passphraseRequested(); + +private: + KGpgTransactionPrivate* const d; + + Q_PRIVATE_SLOT(d, void slotReadReady()) + Q_PRIVATE_SLOT(d, void slotProcessExited()) + Q_PRIVATE_SLOT(d, void slotProcessStarted()) + Q_PRIVATE_SLOT(d, void slotInputTransactionDone(int)) + Q_PRIVATE_SLOT(d, void slotPasswordEntered(const QString &)) + Q_PRIVATE_SLOT(d, void slotPasswordAborted()) + +protected: + /** + * @brief Ask user for passphrase and send it to gpg process. + * + * If the gpg process asks for a new passphrase this function will do + * all necessary steps for you: ask the user for the password and write + * it to the gpg process. If the password is wrong the user is prompted + * again for the correct password. If the user aborts the password + * entry the gpg process will be killed and the transaction result will + * be set to TS_USER_ABORTED. + * + * In contrast to sendPassphrase() this function will not block, but + * handle everything using signals and slots. + * + * @see KgpgInterface::sendPassphrase + * @see askPassphrase + */ + void askNewPassphrase(const QString &text); + + /** + * @brief get the success value that will be returned with the done signal + */ + int getSuccess() const; + /** + * @brief set the success value that will be returned with the done signal + * @param v the new success value + * + * You should use 0 as success value. Other values can be defined as needed. + */ + void setSuccess(const int v); + + /** + * @brief add a userid hint + * @param txt userid description + * + * Before GnuPG asks for a passphrase it usually sends out a hint message + * for which key the passphrase will be needed. There may be several hint + * messages, e.g. if a text was encrypted with multiple keys. + */ + void addIdHint(QString txt); + /** + * @brief get string of all userid hints + * @returns concatenation of all ids previously added with addIdHint(). + */ + QString getIdHints() const; + + /** + * @brief get a reference to the gpg process object + * @returns gpg process object + * + * This returns a reference to the gpg process object used internally. + * In case you need to do some special things (e.g. changing the output + * mode) you can modify this object. + * + * Usually you will not need this. + * + * @warning Never free this object! + */ + GPGProc *getProcess(); + /** + * @brief add a command line argument to gpg process + * @param arg new argument + * @returns the position of the new argument + * + * This is a convenience function that allows adding one additional + * argument to the command line of the process. This must be called + * before start() is called. Usually you will call this from your + * constructor. + */ + int addArgument(const QString &arg); + /** + * @brief add command line arguments to gpg process + * @param args new arguments + * @returns the position of the first argument added + * + * This is a convenience function that allows adding additional + * arguments to the command line of the process. This must be called + * before start() is called. + */ + int addArguments(const QStringList &args); + /** + * @brief replace the argument at the given position + * @param pos position of old argument + * @param arg new argument + */ + void replaceArgument(const int pos, const QString &arg); + /** + * @brief insert an argument at the given position + * @param pos position to insert at + * @param arg new argument + */ + void insertArgument(const int pos, const QString &arg); + /** + * @brief insert arguments at the given position + * @param pos position to insert at + * @param args new arguments + */ + void insertArguments(const int pos, const QStringList &args); + /** + * @brief make sure the reference to a specific argument is kept up to date + * @param ref the value where the position is stored + * + * You might want to keep the position of a specific argument to + * later be able to repace it easily. In that case put it into + * this function too so every time someone mofifies the argument + * list (especially by insertArgument() and insertArguments()) + * this reference will be kept up to date. + */ + void addArgumentRef(int *ref); + /** + * @brief write data to standard input of gpg process + * @param a data to write + * @param lf if line feed should be appended to message + * + * Use this function to interact with the gpg process. A carriage + * return is appended to the data automatically. Usually you will + * call this function from nextLine(). + */ + void write(const QByteArray &a, const bool lf = true); + /** + * @brief write data to standard input of gpg process + * @param i data to write + * + * @overload + */ + void write(const int i); + /** + * @brief ask user for password + * @param message message to display to the user. If message is empty + * "Enter password for [UID]" will be used. + * @return true if the authorization was successful + * + * This function handles user authorization for key changes. It will + * take care to display the message asking the user for the password + * and the number of tries left. + */ + bool askPassphrase(const QString &message = QString()); +}; + +class KGpgTransactionPrivate: QObject { +public: + KGpgTransactionPrivate(KGpgTransaction *parent, bool allowChaining); + ~KGpgTransactionPrivate(); + + KGpgTransaction *m_parent; + GPGProc *m_process; + KGpgTransaction *m_inputTransaction; + //KNewPasswordDialog *m_passwordDialog; + int m_success; + int m_tries; + QString m_description; + bool m_chainingAllowed; + KGpgTransaction::ts_passphrase_actions m_passphraseAction; ///< ignore further request for passphrase + + QStringList m_idhints; + + void slotReadReady(); + void slotProcessExited(); + void slotProcessStarted(); + void slotInputTransactionDone(int result); + void slotPasswordEntered(const QString &password); + void slotPasswordAborted(); + + QList<int *> m_argRefs; + bool m_inputProcessDone; + int m_inputProcessResult; + bool m_ownProcessFinished; + + /** + * terminate GnuPG session + */ + void sendQuit(void); + + void write(const QByteArray &a); + +private: + void processDone(); + + unsigned int m_quitTries; ///< how many times we tried to quit + QStringList m_quitLines; ///< what we received after we tried to quit +}; + +#endif // KGPGTRANSACTION_H diff --git a/mainwindow.cpp b/mainwindow.cpp index 024fb35..6f9efc2 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -775,10 +775,35 @@ void MainWindow::encrypt() QStringList *uidList = mKeyList->getChecked(); QByteArray *tmp = new QByteArray(); - if (mCtx->encrypt(uidList, edit->curTextPage()->toPlainText().toUtf8(), tmp)) { + /*if (mCtx->encrypt(uidList, edit->curTextPage()->toPlainText().toUtf8(), tmp)) { QString *tmp2 = new QString(*tmp); edit->fillTextEditWithText(*tmp2); + }*/ + + QStringList options; + KGpgEncrypt::EncryptOptions opts = KGpgEncrypt::DefaultEncryption; + + KGpgEncrypt *encr = new KGpgEncrypt(this, *uidList, edit->curTextPage()->toPlainText(), opts, options); + encr->start(); + connect(encr, SIGNAL(done(int)), SLOT(slotEncryptDone(int))); +} + +void MainWindow::slotEncryptDone(int result) +{ + KGpgEncrypt *enc = qobject_cast<KGpgEncrypt *>(sender()); + Q_ASSERT(enc != NULL); + + if (result == KGpgTransaction::TS_OK) { + const QString lf = QLatin1String("\n"); + //setPlainText(enc->encryptedText().join(lf) + lf); + edit->fillTextEditWithText(enc->encryptedText().join(lf) + lf); + } else { + /*KMessageBox::sorry(this, i18n("The encryption failed with error code %1", result), + i18n("Encryption failed."));*/ + qDebug() << "The encryption failed with error code " << result; } + + sender()->deleteLater(); } void MainWindow::sign() diff --git a/mainwindow.h b/mainwindow.h index 6df5ab4..bbf940b 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -31,6 +31,7 @@ #include "verifynotification.h" #include "wizard.h" #include "kgpg/core/kgpgkey.h" +#include "kgpg/transactions/kgpgencrypt.h" QT_BEGIN_NAMESPACE class QMainWindow; @@ -87,6 +88,7 @@ private slots: * with the currently checked keys */ void encrypt(); + void slotEncryptDone(int result); /** * @details Show a passphrase dialog and decrypt the text of currently active tab. |