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