8f97cb5708c4f5901abf85d7c7acf564aeae825d
[gpgme.git] / lang / qt / src / qgpgmewkspublishjob.cpp
1 /* wkspublishjob.cpp
2
3     Copyright (c) 2016 Intevation GmbH
4
5     QGpgME is free software; you can redistribute it and/or
6     modify it under the terms of the GNU General Public License as
7     published by the Free Software Foundation; either version 2 of the
8     License, or (at your option) any later version.
9
10     QGpgME is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18
19     In addition, as a special exception, the copyright holders give
20     permission to link the code of this program with any edition of
21     the Qt library by Trolltech AS, Norway (or with modified versions
22     of Qt that use the same license as Qt), and distribute linked
23     combinations including the two.  You must obey the GNU General
24     Public License in all respects for all of the code used other than
25     Qt.  If you modify this file, you may extend this exception to
26     your version of the file, but you are not obligated to do so.  If
27     you do not wish to do so, delete this exception statement from
28     your version.
29 */
30
31 #include "qgpgmewkspublishjob.h"
32
33 #include "context.h"
34 #include "key.h"
35 #include "util.h"
36
37 #include <QFileInfo>
38 #include <QDir>
39 #include <QProcess>
40
41 /* Timeout for the WKS Processes will be 5 Minutes as
42  * they can involve pinentry questions. */
43 #define TIMEOUT_VALUE (5*60*1000)
44
45 using namespace QGpgME;
46 using namespace GpgME;
47
48 QGpgMEWKSPublishJob::QGpgMEWKSPublishJob(Context *context)
49     : mixin_type(context)
50 {
51     lateInitialization();
52 }
53
54 QGpgMEWKSPublishJob::~QGpgMEWKSPublishJob() {}
55
56 static QString getWKSClient()
57 {
58     auto libexecdir = QString::fromLocal8Bit(dirInfo("libexecdir"));
59     if (libexecdir.isEmpty()) {
60         return QString();
61     }
62
63     const QFileInfo fi(QDir(libexecdir).absoluteFilePath(QStringLiteral("gpg-wks-client")));
64     if (fi.exists() && fi.isExecutable()) {
65         return fi.absoluteFilePath();
66     }
67     return QString();
68 }
69
70 static QGpgMEWKSPublishJob::result_type check_worker(const QString &mail)
71 {
72     if (mail.isEmpty()) {
73         return std::make_tuple (Error(make_error(GPG_ERR_INV_ARG)),
74                                 QByteArray(), QByteArray(), QString(), Error());
75     }
76
77     const auto wksPath = getWKSClient();
78     if (wksPath.isEmpty()) {
79         return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
80                                 QByteArray(), QByteArray(), QString(), Error());
81     }
82
83     /* QProcess instead of engine_spawn because engine_spawn does not communicate
84      * the return value of the process and we are in qt anyway. */
85     QProcess proc;
86     proc.setProgram(wksPath);
87     proc.setArguments(QStringList() << QStringLiteral("--supported") << mail);
88     proc.start();
89     if (!proc.waitForStarted()) {
90         return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
91                                 QByteArray(), QByteArray(), QString(), Error());
92     }
93     if (!proc.waitForFinished(TIMEOUT_VALUE)) {
94         return std::make_tuple (Error(make_error(GPG_ERR_TIMEOUT)),
95                                 QByteArray(), QByteArray(), QString(), Error());
96     }
97     if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0) {
98         return std::make_tuple (Error(), QByteArray(), QByteArray(), QString(), Error());
99     }
100     return std::make_tuple (Error(make_error(GPG_ERR_NOT_ENABLED)),
101                             QByteArray(), QByteArray(), QString(), Error());
102 }
103
104 static QGpgMEWKSPublishJob::result_type create_worker(const char *fpr, const QString &mail)
105 {
106     if (mail.isEmpty() || !fpr) {
107         return std::make_tuple (Error(make_error(GPG_ERR_INV_ARG)),
108                                 QByteArray(), QByteArray(), QString(), Error());
109     }
110
111     const auto wksPath = getWKSClient();
112     if (wksPath.isEmpty()) {
113         return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
114                                 QByteArray(), QByteArray(), QString(), Error());
115     }
116
117     QProcess proc;
118     proc.setProgram(wksPath);
119     proc.setArguments(QStringList() << QStringLiteral("--create")
120                                     << QLatin1String(fpr)
121                                     << mail);
122     proc.start();
123     if (!proc.waitForStarted()) {
124         return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
125                                 QByteArray(), QByteArray(), QString(), Error());
126     }
127
128     if (!proc.waitForFinished(TIMEOUT_VALUE)) {
129         return std::make_tuple (Error(make_error(GPG_ERR_TIMEOUT)),
130                                 QByteArray(), QByteArray(), QString(), Error());
131     }
132     if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0) {
133         return std::make_tuple (Error(), proc.readAllStandardOutput(),
134                                 proc.readAllStandardError(), QString(), Error());
135     }
136     return std::make_tuple (Error(make_error(GPG_ERR_GENERAL)),
137                             proc.readAllStandardOutput(), proc.readAllStandardError(), QString(), Error());
138 }
139
140 static QGpgMEWKSPublishJob::result_type recieve_worker(const QByteArray &response)
141 {
142     if (response.isEmpty()) {
143         return std::make_tuple (Error(make_error(GPG_ERR_INV_ARG)),
144                                 QByteArray(), QByteArray(), QString(), Error());
145     }
146
147     const auto wksPath = getWKSClient();
148     if (wksPath.isEmpty()) {
149         return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
150                                 QByteArray(), QByteArray(), QString(), Error());
151     }
152
153     QProcess proc;
154     proc.setProgram(wksPath);
155     proc.setArguments(QStringList() << QStringLiteral("--receive"));
156     proc.start();
157     if (!proc.waitForStarted()) {
158         return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
159                                 QByteArray(), QByteArray(), QString(), Error());
160     }
161     proc.write(response);
162     proc.closeWriteChannel();
163     if (!proc.waitForFinished(TIMEOUT_VALUE)) {
164         return std::make_tuple (Error(make_error(GPG_ERR_TIMEOUT)),
165                                 QByteArray(), QByteArray(), QString(), Error());
166     }
167     if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0) {
168         return std::make_tuple (Error(), proc.readAllStandardOutput(),
169                                 proc.readAllStandardError(), QString(), Error());
170     }
171     return std::make_tuple (Error(make_error(GPG_ERR_GENERAL)),
172                             proc.readAllStandardOutput(), proc.readAllStandardError(), QString(), Error());
173 }
174
175 void QGpgMEWKSPublishJob::startCheck(const QString &mailbox)
176 {
177     run(std::bind(&check_worker, mailbox));
178 }
179
180 void QGpgMEWKSPublishJob::startCreate(const char *fpr, const QString &mailbox) {
181     run(std::bind(&create_worker, fpr, mailbox));
182 }
183
184 void QGpgMEWKSPublishJob::startRecieve(const QByteArray &response)
185 {
186     run(std::bind(&recieve_worker, response));
187 }
188
189 #include "qgpgmewkspublishjob.moc"