Mailcommon

filteractionwithcrypto.cpp
1 /*
2  * SPDX-FileCopyrightText: 2017 Daniel Vr├ítil <[email protected]>
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 
13 using namespace MailCommon;
14 
15 QStringList 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());
45  gpg.closeWriteChannel();
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!
73  gpg.closeWriteChannel();
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 }
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode)
QString fromUtf8(const char *str, int size)
bool waitForFinished(int msecs)
void setProgram(const QString &program)
Q_SCRIPTABLE Q_NOREPLY void start()
QString findExecutable(const QString &executableName, const QStringList &paths)
void setArguments(const QStringList &arguments)
bool waitForStarted(int msecs)
qint64 readLine(char *data, qint64 maxSize)
void setReadChannel(QProcess::ProcessChannel channel)
void closeWriteChannel()
virtual bool atEnd() const const override
qint64 write(const char *data, qint64 maxSize)
The filter dialog.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Sep 24 2022 03:58:15 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.