Imported Upstream version 1.14.0
[platform/upstream/gpgme.git] / lang / qt / src / qgpgmerefreshkeysjob.cpp
1 /*
2     qgpgmerefreshkeysjob.cpp
3
4     This file is part of qgpgme, the Qt API binding for gpgme
5     Copyright (c) 2004 Klarävdalens Datakonsult AB
6     Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik
7     Software engineering by Intevation GmbH
8
9     QGpgME is free software; you can redistribute it and/or
10     modify it under the terms of the GNU General Public License as
11     published by the Free Software Foundation; either version 2 of the
12     License, or (at your option) any later version.
13
14     QGpgME is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17     General Public License for more details.
18
19     You should have received a copy of the GNU General Public License along
20     with this program; if not, write to the Free Software Foundation, Inc.,
21     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
23     In addition, as a special exception, the copyright holders give
24     permission to link the code of this program with any edition of
25     the Qt library by Trolltech AS, Norway (or with modified versions
26     of Qt that use the same license as Qt), and distribute linked
27     combinations including the two.  You must obey the GNU General
28     Public License in all respects for all of the code used other than
29     Qt.  If you modify this file, you may extend this exception to
30     your version of the file, but you are not obligated to do so.  If
31     you do not wish to do so, delete this exception statement from
32     your version.
33 */
34
35 #define MAX_CMD_LENGTH 32768
36
37 #ifdef HAVE_CONFIG_H
38  #include "config.h"
39 #endif
40
41 #include "qgpgmerefreshkeysjob.h"
42
43 #include <QDebug>
44 #include "qgpgme_debug.h"
45
46 #include "context.h"
47
48 #include <QByteArray>
49 #include <QStringList>
50
51 #include <gpg-error.h>
52
53 #include <assert.h>
54
55 QGpgME::QGpgMERefreshKeysJob::QGpgMERefreshKeysJob()
56     : RefreshKeysJob(nullptr),
57       mProcess(nullptr),
58       mError(0)
59 {
60
61 }
62
63 QGpgME::QGpgMERefreshKeysJob::~QGpgMERefreshKeysJob()
64 {
65
66 }
67
68 GpgME::Error QGpgME::QGpgMERefreshKeysJob::start(const QStringList &patterns)
69 {
70     assert(mPatternsToDo.empty());
71
72     mPatternsToDo = patterns;
73     if (mPatternsToDo.empty()) {
74         mPatternsToDo.push_back(QStringLiteral(" "));    // empty list means all -> mae
75     }
76     // sure to fail the first
77     // startAProcess() guard clause
78
79     return startAProcess();
80 }
81
82 #if MAX_CMD_LENGTH < 65 + 128
83 #error MAX_CMD_LENGTH is too low
84 #endif
85
86 GpgME::Error QGpgME::QGpgMERefreshKeysJob::startAProcess()
87 {
88     if (mPatternsToDo.empty()) {
89         return GpgME::Error();
90     }
91     // create and start gpgsm process:
92     mProcess = new QProcess(this);
93     mProcess->setObjectName(QStringLiteral("gpgsm -k --with-validation --force-crl-refresh --enable-crl-checks"));
94
95     // FIXME: obbtain the path to gpgsm from gpgme, so we use the same instance.
96     mProcess->setProgram(QStringLiteral("gpgsm"));
97     QStringList arguments;
98     arguments << QStringLiteral("-k")
99               << QStringLiteral("--with-validation")
100               << QStringLiteral("--force-crl-refresh")
101               << QStringLiteral("--enable-crl-checks");
102     unsigned int commandLineLength = MAX_CMD_LENGTH;
103     commandLineLength -=
104         strlen("gpgsm") + 1 + strlen("-k") + 1 +
105         strlen("--with-validation") + 1 + strlen("--force-crl-refresh") + 1 +
106         strlen("--enable-crl-checks") + 1;
107     while (!mPatternsToDo.empty()) {
108         const QByteArray pat = mPatternsToDo.front().toUtf8().trimmed();
109         const unsigned int patLength = pat.length();
110         if (patLength >= commandLineLength) {
111             break;
112         }
113         mPatternsToDo.pop_front();
114         if (pat.isEmpty()) {
115             continue;
116         }
117         arguments << QLatin1String(pat);
118         commandLineLength -= patLength + 1;
119     }
120
121     mProcess->setArguments(arguments);
122
123     connect(mProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
124             SLOT(slotProcessExited(int,QProcess::ExitStatus)));
125     connect(mProcess, SIGNAL(readyReadStandardOutput()),
126             SLOT(slotStdout()));
127     connect(mProcess, &QProcess::readyReadStandardError,
128             this, &QGpgMERefreshKeysJob::slotStderr);
129
130     mProcess->start();
131     if (!mProcess->waitForStarted()) {
132         mError = GpgME::Error::fromCode(GPG_ERR_ENOENT, GPG_ERR_SOURCE_GPGSM);   // what else?
133         deleteLater();
134         return mError;
135     } else {
136         return GpgME::Error();
137     }
138 }
139
140 void QGpgME::QGpgMERefreshKeysJob::slotCancel()
141 {
142     if (mProcess) {
143         mProcess->kill();
144     }
145     mProcess = nullptr;
146     mError = GpgME::Error::fromCode(GPG_ERR_CANCELED, GPG_ERR_SOURCE_GPGSM);
147 }
148
149 void QGpgME::QGpgMERefreshKeysJob::slotStatus(QProcess *proc, const QString &type, const QStringList &args)
150 {
151     if (proc != mProcess) {
152         return;
153     }
154     QStringList::const_iterator it = args.begin();
155     bool ok = false;
156
157     if (type == QLatin1String("ERROR")) {
158
159         if (args.size() < 2) {
160             qCDebug(QGPGME_LOG) << "not recognising ERROR with < 2 args!";
161             return;
162         }
163         const int source = (*++it).toInt(&ok);
164         if (!ok) {
165             qCDebug(QGPGME_LOG) << "expected number for first ERROR arg, got something else";
166             return;
167         }
168         ok = false;
169         const int code = (*++it).toInt(&ok);
170         if (!ok) {
171             qCDebug(QGPGME_LOG) << "expected number for second ERROR arg, got something else";
172             return;
173         }
174         mError = GpgME::Error::fromCode(code, source);
175
176     } else if (type == QLatin1String("PROGRESS")) {
177
178         if (args.size() < 4) {
179             qCDebug(QGPGME_LOG) << "not recognising PROGRESS with < 4 args!";
180             return;
181         }
182         const QString what = *++it;
183         ok = false;
184         (*++it).toInt(&ok);
185         if (!ok) {
186             qCDebug(QGPGME_LOG) << "expected number for \"type\", got something else";
187             return;
188         }
189         ok = false;
190         const int cur = (*++it).toInt(&ok);
191         if (!ok) {
192             qCDebug(QGPGME_LOG) << "expected number for \"cur\", got something else";
193             return;
194         }
195         ok = false;
196         const int total = (*++it).toInt(&ok);
197         if (!ok) {
198             qCDebug(QGPGME_LOG) << "expected number for \"total\", got something else";
199             return;
200         }
201         // TODO port
202         Q_EMIT progress(QString(), cur, total);
203
204     }
205 }
206
207 void QGpgME::QGpgMERefreshKeysJob::slotStderr()
208 {
209     // implement? or not?
210 }
211
212 void QGpgME::QGpgMERefreshKeysJob::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus)
213 {
214     if (!mError && !mPatternsToDo.empty()) {
215         if (const GpgME::Error err = startAProcess()) {
216             mError = err;
217         } else {
218             return;
219         }
220     }
221
222     Q_EMIT done();
223     if (!mError &&
224             (exitStatus != QProcess::NormalExit || exitCode != 0)) {
225         mError = GpgME::Error::fromCode(GPG_ERR_GENERAL, GPG_ERR_SOURCE_GPGSM);
226     }
227     Q_EMIT result(mError);
228     deleteLater();
229 }
230 #include "qgpgmerefreshkeysjob.moc"