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