Mailcommon

filteractionwithcrypto.cpp
1/*
2 * SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.org>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 *
6 */
7
8#include "filteractionwithcrypto.h"
9
10#include <QProcess>
11#include <QStandardPaths>
12
13using namespace MailCommon;
14
15QStringList FilterActionWithCrypto::getEncryptionKeysFromContent(const KMime::Message::Ptr &msg, GpgME::Protocol protocol) const
16{
17 if (protocol == GpgME::CMS && mGpgSmPath.isNull()) {
18 const auto path = QStandardPaths::findExecutable(QStringLiteral("gpgsm"));
19 mGpgSmPath = path.isEmpty() ? QString() : path;
20 } else if (protocol == GpgME::OpenPGP && mGpgPath.isNull()) {
21 auto path = QStandardPaths::findExecutable(QStringLiteral("gpg2"));
22 if (path.isEmpty()) {
23 path = QStandardPaths::findExecutable(QStringLiteral("gpg"));
24 mGpgPath = path.isEmpty() ? QString() : path;
25 } else {
26 mGpgPath = path;
27 }
28 }
29
30 if ((protocol == GpgME::CMS && mGpgSmPath.isEmpty()) || (protocol == GpgME::OpenPGP && mGpgPath.isEmpty())) {
31 return {};
32 }
33
34 QProcess gpg;
35 QStringList keyIds;
36 // TODO: contribute an API for this into gpgme
37 if (protocol == GpgME::OpenPGP) {
38 gpg.setProgram(mGpgPath);
39 // --list-packets will give us list of keys used to encrypt the message
40 // --batch will prevent gpg from asking for decryption password (we don't need it yet)
41 gpg.setArguments({QStringLiteral("--list-packets"), QStringLiteral("--batch")});
43 gpg.waitForStarted();
44 gpg.write(msg->encodedContent());
46 gpg.waitForFinished();
47 while (!gpg.atEnd()) {
48 const auto l = gpg.readLine();
49 if (l.startsWith(":pubkey")) {
50 const int pos = l.indexOf("keyid ");
51 if (pos < 0) {
52 continue;
53 }
54 const int start = pos + 6; // strlen("keyid ")
55 const int len = l.size() - start - 1; // -1 to skip trailing \n
56 keyIds << QString::fromUtf8(l.mid(start, len));
57 }
58 }
59 } else if (protocol == GpgME::CMS) {
60 gpg.setProgram(mGpgSmPath);
61 // --decrypt - the only way how to get the keys from gpgsm, sadly, is to decrypt the email
62 // --status-fd 2 - make sure the status output is not mangled with the decrypted content
63 // --assume-base64 - so that we don't have to decode it ourselves
64 gpg.setArguments({QStringLiteral("--decrypt"),
65 QStringLiteral("--status-fd"),
66 QStringLiteral("2"),
67 QStringLiteral("--debug-level"),
68 QStringLiteral("basic"),
69 QStringLiteral("--assume-base64")});
71 gpg.waitForStarted();
72 gpg.write(msg->encodedBody()); // just the body!
74 gpg.waitForFinished();
76 while (!gpg.atEnd()) {
77 const auto l = gpg.readLine();
78 if (l.startsWith("gpgsm: DBG: recp ")) {
79 const int pos = l.indexOf("serial: ");
80 if (pos < 0) {
81 continue;
82 }
83 const int start = pos + 8; // strlen("serial: ")
84 const int len = l.size() - start - 1; // -1 to skip trailing \n
85 keyIds << QString::fromUtf8(l.mid(start, len));
86 }
87 }
88 }
89
90 return keyIds;
91}
92
93#include "moc_filteractionwithcrypto.cpp"
Q_SCRIPTABLE Q_NOREPLY void start()
QString path(const QString &relativePath)
The filter dialog.
qsizetype indexOf(QByteArrayView bv, qsizetype from) const const
virtual bool atEnd() const const
QByteArray readLine(qint64 maxSize)
qint64 write(const QByteArray &data)
void closeWriteChannel()
void setArguments(const QStringList &arguments)
void setProgram(const QString &program)
void setReadChannel(ProcessChannel channel)
void start(OpenMode mode)
bool waitForFinished(int msecs)
bool waitForStarted(int msecs)
QString findExecutable(const QString &executableName, const QStringList &paths)
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
bool isNull() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:00 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.