1 /*
2 SPDX-FileCopyrightText: 2010, 2011, 2012 Rolf Eike Beer <kde@opensource.sf-tec.de>
3 SPDX-License-Identifier: GPL-2.0-or-later
4 */
5
6 #include "kgpgdecrypt.h"
7
8 #include "gpgproc.h"
9 #include "kgpgsettings.h"
10
11 #include <KLocalizedString>
12
KGpgDecrypt(QObject * parent,const QString & text)13 KGpgDecrypt::KGpgDecrypt(QObject *parent, const QString &text)
14 : KGpgTextOrFileTransaction(parent, text),
15 m_fileIndex(-1),
16 m_plainLength(-1)
17 {
18 }
19
KGpgDecrypt(QObject * parent,const QList<QUrl> & files)20 KGpgDecrypt::KGpgDecrypt(QObject *parent, const QList<QUrl> &files)
21 : KGpgTextOrFileTransaction(parent, files),
22 m_fileIndex(0),
23 m_plainLength(-1)
24 {
25 }
26
KGpgDecrypt(QObject * parent,const QUrl & infile,const QUrl & outfile)27 KGpgDecrypt::KGpgDecrypt(QObject* parent, const QUrl& infile, const QUrl& outfile)
28 : KGpgTextOrFileTransaction(parent, QList<QUrl>({infile})),
29 m_fileIndex(0),
30 m_plainLength(-1),
31 m_outFilename(outfile.toLocalFile())
32 {
33 }
34
~KGpgDecrypt()35 KGpgDecrypt::~KGpgDecrypt()
36 {
37 }
38
39 QStringList
command() const40 KGpgDecrypt::command() const
41 {
42 QStringList ret;
43
44 ret << QLatin1String("--decrypt") << QLatin1String("--command-fd=0");
45
46 if (!m_outFilename.isEmpty())
47 ret << QLatin1String("-o") << m_outFilename;
48
49 ret << KGpgSettings::customDecrypt().simplified().split(QLatin1Char(' '), Qt::SkipEmptyParts);
50
51 return ret;
52 }
53
54 QStringList
decryptedText() const55 KGpgDecrypt::decryptedText() const
56 {
57 QStringList result;
58 int txtlength = 0;
59
60 for (const QString &line : getMessages())
61 if (!line.startsWith(QLatin1String("[GNUPG:] "))) {
62 result.append(line);
63 txtlength += line.length() + 1;
64 }
65
66 if (result.isEmpty())
67 return result;
68
69 QString last = result.last();
70 // this may happen when the original text did not end with a newline
71 if (last.endsWith(QLatin1String("[GNUPG:] DECRYPTION_OKAY"))) {
72 // if GnuPG doesn't tell us the length assume that this happend
73 // if it told us the length then check if it _really_ happend
74 if (((m_plainLength != -1) && (txtlength != m_plainLength)) ||
75 (m_plainLength == -1)) {
76 last.chop(24);
77 result[result.count() - 1] = last;
78 }
79 }
80
81 return result;
82 }
83
84 bool
isEncryptedText(const QString & text,int * startPos,int * endPos)85 KGpgDecrypt::isEncryptedText(const QString &text, int *startPos, int *endPos)
86 {
87 int posStart = text.indexOf(QLatin1String("-----BEGIN PGP MESSAGE-----"));
88 if (posStart == -1)
89 return false;
90
91 int posEnd = text.indexOf(QLatin1String("-----END PGP MESSAGE-----"), posStart);
92 if (posEnd == -1)
93 return false;
94
95 if (startPos != nullptr)
96 *startPos = posStart;
97 if (endPos != nullptr)
98 *endPos = posEnd;
99
100 return true;
101 }
102
103 bool
nextLine(const QString & line)104 KGpgDecrypt::nextLine(const QString& line)
105 {
106 const QList<QUrl> &inputFiles = getInputFiles();
107
108 if (line == QLatin1String("[GNUPG:] DECRYPTION_OKAY")) {
109 // Assume Gpg decryption was successful even if gpg returns
110 // an error code.
111 decryptSuccess = true;
112 } else if (!inputFiles.isEmpty()) {
113 if (line == QLatin1String("[GNUPG:] BEGIN_DECRYPTION")) {
114 Q_EMIT statusMessage(i18nc("Status message 'Decrypting <filename>' (operation starts)", "Decrypting %1", inputFiles.at(m_fileIndex).fileName()));
115 Q_EMIT infoProgress(2 * m_fileIndex + 1, inputFiles.count() * 2);
116 } else if (line == QLatin1String("[GNUPG:] END_DECRYPTION")) {
117 Q_EMIT statusMessage(i18nc("Status message 'Decrypted <filename>' (operation was completed)", "Decrypted %1", inputFiles.at(m_fileIndex).fileName()));
118 m_fileIndex++;
119 Q_EMIT infoProgress(2 * m_fileIndex, inputFiles.count() * 2);
120 }
121 } else {
122 if (line.startsWith(QLatin1String("[GNUPG:] PLAINTEXT_LENGTH "))) {
123 bool ok;
124 m_plainLength = line.midRef(26).toInt(&ok);
125 if (!ok)
126 m_plainLength = -1;
127 } else if (line == QLatin1String("[GNUPG:] BEGIN_DECRYPTION")) {
128 // close the command channel (if any) to signal GnuPG that it
129 // can start sending the output.
130 getProcess()->closeWriteChannel();
131 }
132 }
133
134 return KGpgTextOrFileTransaction::nextLine(line);
135 }
136
137 void
finish()138 KGpgDecrypt::finish()
139 {
140 if (decryptSuccess) {
141 // Gpg error code is ignored.
142 // https://bugs.kde.org/show_bug.cgi?id=357462
143 setSuccess(TS_OK);
144 } else {
145 KGpgTextOrFileTransaction::finish();
146 }
147 }
148
closeInputAfterText() const149 bool KGpgDecrypt::closeInputAfterText() const
150 {
151 // otherwise decryption does never start in GnuPG 2.3,
152 // but doesn't hurt on older versions as well
153 return true;
154 }
155