Add QGpgME code from libkleo
[gpgme.git] / lang / qt / src / qgpgmebackend.cpp
1 /*
2     qgpgmebackend.cpp
3
4     This file is part of qgpgme, the Qt API binding for gpgme
5     Copyright (c) 2004,2005 Klarälvdalens Datakonsult AB
6     Copyright (c) 2016 Intevation GmbH
7
8     Libkleopatra 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     Libkleopatra 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
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 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 #include "qgpgmebackend.h"
35
36 #include "qgpgmecryptoconfig.h"
37 #include "qgpgmenewcryptoconfig.h"
38
39 #include "qgpgmekeygenerationjob.h"
40 #include "qgpgmekeylistjob.h"
41 #include "qgpgmelistallkeysjob.h"
42 #include "qgpgmedecryptjob.h"
43 #include "qgpgmedecryptverifyjob.h"
44 #include "qgpgmerefreshkeysjob.h"
45 #include "qgpgmedeletejob.h"
46 #include "qgpgmesecretkeyexportjob.h"
47 #include "qgpgmedownloadjob.h"
48 #include "qgpgmesignencryptjob.h"
49 #include "qgpgmeencryptjob.h"
50 #include "qgpgmesignjob.h"
51 #include "qgpgmesignkeyjob.h"
52 #include "qgpgmeexportjob.h"
53 #include "qgpgmeverifydetachedjob.h"
54 #include "qgpgmeimportjob.h"
55 #include "qgpgmeimportfromkeyserverjob.h"
56 #include "qgpgmeverifyopaquejob.h"
57 #include "qgpgmechangeexpiryjob.h"
58 #include "qgpgmechangeownertrustjob.h"
59 #include "qgpgmechangepasswdjob.h"
60 #include "qgpgmeadduseridjob.h"
61
62 #include "error.h"
63 #include "engineinfo.h"
64
65 #include <QFile>
66 #include <QString>
67
68 const char QGpgME::QGpgMEBackend::OpenPGP[] = "OpenPGP";
69 const char QGpgME::QGpgMEBackend::SMIME[] = "SMIME";
70
71 namespace
72 {
73
74 class Protocol : public QGpgME::Protocol
75 {
76     GpgME::Protocol mProtocol;
77 public:
78     explicit Protocol(GpgME::Protocol proto) : mProtocol(proto) {}
79
80     QString name() const Q_DECL_OVERRIDE
81     {
82         switch (mProtocol) {
83         case GpgME::OpenPGP: return QStringLiteral("OpenPGP");
84         case GpgME::CMS:     return QStringLiteral("SMIME");
85         default:             return QString();
86         }
87     }
88
89     QString displayName() const Q_DECL_OVERRIDE
90     {
91         // ah (2.4.16): Where is this used and isn't this inverted
92         // with name
93         switch (mProtocol) {
94         case GpgME::OpenPGP: return QStringLiteral("gpg");
95         case GpgME::CMS:     return QStringLiteral("gpgsm");
96         default:             return QStringLiteral("unknown");
97         }
98     }
99
100     QGpgME::SpecialJob *specialJob(const char *, const QMap<QString, QVariant> &) const Q_DECL_OVERRIDE
101     {
102         return 0;
103     }
104
105     QGpgME::KeyListJob *keyListJob(bool remote, bool includeSigs, bool validate) const Q_DECL_OVERRIDE
106     {
107         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
108         if (!context) {
109             return 0;
110         }
111
112         unsigned int mode = context->keyListMode();
113         if (remote) {
114             mode |= GpgME::Extern;
115             mode &= ~GpgME::Local;
116         } else {
117             mode |= GpgME::Local;
118             mode &= ~GpgME::Extern;
119         }
120         if (includeSigs) {
121             mode |= GpgME::Signatures;
122         }
123         if (validate) {
124             mode |= GpgME::Validate;
125         }
126         context->setKeyListMode(mode);
127         return new QGpgME::QGpgMEKeyListJob(context);
128     }
129
130     QGpgME::ListAllKeysJob *listAllKeysJob(bool includeSigs, bool validate) const Q_DECL_OVERRIDE
131     {
132         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
133         if (!context) {
134             return 0;
135         }
136
137         unsigned int mode = context->keyListMode();
138         mode |= GpgME::Local;
139         mode &= ~GpgME::Extern;
140         if (includeSigs) {
141             mode |= GpgME::Signatures;
142         }
143         if (validate) {
144             mode |= GpgME::Validate;
145             /* Setting the context to offline mode disables CRL / OCSP checks in
146                this Job. Otherwise we would try to fetch the CRL's for all CMS
147                keys in the users keyring because GpgME::Validate includes remote
148                resources by default in the validity check.
149                This setting only has any effect if gpgsm >= 2.1.6 is used.
150                */
151             context->setOffline(true);
152         }
153         context->setKeyListMode(mode);
154         return new QGpgME::QGpgMEListAllKeysJob(context);
155     }
156
157     QGpgME::EncryptJob *encryptJob(bool armor, bool textmode) const Q_DECL_OVERRIDE
158     {
159         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
160         if (!context) {
161             return 0;
162         }
163
164         context->setArmor(armor);
165         context->setTextMode(textmode);
166         return new QGpgME::QGpgMEEncryptJob(context);
167     }
168
169     QGpgME::DecryptJob *decryptJob() const Q_DECL_OVERRIDE
170     {
171         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
172         if (!context) {
173             return 0;
174         }
175         return new QGpgME::QGpgMEDecryptJob(context);
176     }
177
178     QGpgME::SignJob *signJob(bool armor, bool textMode) const Q_DECL_OVERRIDE
179     {
180         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
181         if (!context) {
182             return 0;
183         }
184
185         context->setArmor(armor);
186         context->setTextMode(textMode);
187         return new QGpgME::QGpgMESignJob(context);
188     }
189
190     QGpgME::VerifyDetachedJob *verifyDetachedJob(bool textMode) const Q_DECL_OVERRIDE
191     {
192         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
193         if (!context) {
194             return 0;
195         }
196
197         context->setTextMode(textMode);
198         return new QGpgME::QGpgMEVerifyDetachedJob(context);
199     }
200
201     QGpgME::VerifyOpaqueJob *verifyOpaqueJob(bool textMode) const Q_DECL_OVERRIDE
202     {
203         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
204         if (!context) {
205             return 0;
206         }
207
208         context->setTextMode(textMode);
209         return new QGpgME::QGpgMEVerifyOpaqueJob(context);
210     }
211
212     QGpgME::KeyGenerationJob *keyGenerationJob() const Q_DECL_OVERRIDE
213     {
214         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
215         if (!context) {
216             return 0;
217         }
218         return new QGpgME::QGpgMEKeyGenerationJob(context);
219     }
220
221     QGpgME::ImportJob *importJob() const Q_DECL_OVERRIDE
222     {
223         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
224         if (!context) {
225             return 0;
226         }
227         return new QGpgME::QGpgMEImportJob(context);
228     }
229
230     QGpgME::ImportFromKeyserverJob *importFromKeyserverJob() const Q_DECL_OVERRIDE
231     {
232         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
233         if (!context) {
234             return 0;
235         }
236         return new QGpgME::QGpgMEImportFromKeyserverJob(context);
237     }
238
239     QGpgME::ExportJob *publicKeyExportJob(bool armor) const Q_DECL_OVERRIDE
240     {
241         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
242         if (!context) {
243             return 0;
244         }
245
246         context->setArmor(armor);
247         return new QGpgME::QGpgMEExportJob(context);
248     }
249
250     QGpgME::ExportJob *secretKeyExportJob(bool armor, const QString &charset) const Q_DECL_OVERRIDE
251     {
252         if (mProtocol != GpgME::CMS) { // fixme: add support for gpg, too
253             return 0;
254         }
255
256         // this operation is not supported by gpgme, so we have to call gpgsm ourselves:
257         return new QGpgME::QGpgMESecretKeyExportJob(armor, charset);
258     }
259
260     QGpgME::RefreshKeysJob *refreshKeysJob() const Q_DECL_OVERRIDE
261     {
262         if (mProtocol != GpgME::CMS) { // fixme: add support for gpg, too
263             return 0;
264         }
265
266         // this operation is not supported by gpgme, so we have to call gpgsm ourselves:
267         return new QGpgME::QGpgMERefreshKeysJob();
268     }
269
270     QGpgME::DownloadJob *downloadJob(bool armor) const Q_DECL_OVERRIDE
271     {
272         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
273         if (!context) {
274             return 0;
275         }
276
277         context->setArmor(armor);
278         // this is the hackish interface for downloading from keyserers currently:
279         context->setKeyListMode(GpgME::Extern);
280         return new QGpgME::QGpgMEDownloadJob(context);
281     }
282
283     QGpgME::DeleteJob *deleteJob() const Q_DECL_OVERRIDE
284     {
285         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
286         if (!context) {
287             return 0;
288         }
289         return new QGpgME::QGpgMEDeleteJob(context);
290     }
291
292     QGpgME::SignEncryptJob *signEncryptJob(bool armor, bool textMode) const Q_DECL_OVERRIDE
293     {
294         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
295         if (!context) {
296             return 0;
297         }
298
299         context->setArmor(armor);
300         context->setTextMode(textMode);
301         return new QGpgME::QGpgMESignEncryptJob(context);
302     }
303
304     QGpgME::DecryptVerifyJob *decryptVerifyJob(bool textMode) const Q_DECL_OVERRIDE
305     {
306         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
307         if (!context) {
308             return 0;
309         }
310
311         context->setTextMode(textMode);
312         return new QGpgME::QGpgMEDecryptVerifyJob(context);
313     }
314
315     QGpgME::ChangeExpiryJob *changeExpiryJob() const Q_DECL_OVERRIDE
316     {
317         if (mProtocol != GpgME::OpenPGP) {
318             return 0;    // only supported by gpg
319         }
320
321         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
322         if (!context) {
323             return 0;
324         }
325         return new QGpgME::QGpgMEChangeExpiryJob(context);
326     }
327
328     QGpgME::ChangePasswdJob *changePasswdJob() const Q_DECL_OVERRIDE
329     {
330         if (!GpgME::hasFeature(GpgME::PasswdFeature, 0)) {
331             return 0;
332         }
333         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
334         if (!context) {
335             return 0;
336         }
337         return new QGpgME::QGpgMEChangePasswdJob(context);
338     }
339
340     QGpgME::SignKeyJob *signKeyJob() const Q_DECL_OVERRIDE
341     {
342         if (mProtocol != GpgME::OpenPGP) {
343             return 0;    // only supported by gpg
344         }
345
346         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
347         if (!context) {
348             return 0;
349         }
350         return new QGpgME::QGpgMESignKeyJob(context);
351     }
352
353     QGpgME::ChangeOwnerTrustJob *changeOwnerTrustJob() const Q_DECL_OVERRIDE
354     {
355         if (mProtocol != GpgME::OpenPGP) {
356             return 0;    // only supported by gpg
357         }
358
359         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
360         if (!context) {
361             return 0;
362         }
363         return new QGpgME::QGpgMEChangeOwnerTrustJob(context);
364     }
365
366     QGpgME::AddUserIDJob *addUserIDJob() const Q_DECL_OVERRIDE
367     {
368         if (mProtocol != GpgME::OpenPGP) {
369             return 0;    // only supported by gpg
370         }
371
372         GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
373         if (!context) {
374             return 0;
375         }
376         return new QGpgME::QGpgMEAddUserIDJob(context);
377     }
378
379 };
380
381 }
382
383 QGpgME::QGpgMEBackend::QGpgMEBackend()
384     : mCryptoConfig(0),
385       mOpenPGPProtocol(0),
386       mSMIMEProtocol(0)
387 {
388     GpgME::initializeLibrary();
389 }
390
391 QGpgME::QGpgMEBackend::~QGpgMEBackend()
392 {
393     delete mCryptoConfig; mCryptoConfig = 0;
394     delete mOpenPGPProtocol; mOpenPGPProtocol = 0;
395     delete mSMIMEProtocol; mSMIMEProtocol = 0;
396 }
397
398 QString QGpgME::QGpgMEBackend::name() const
399 {
400     return QStringLiteral("gpgme");
401 }
402
403 QString QGpgME::QGpgMEBackend::displayName() const
404 {
405     return QStringLiteral("GpgME");
406 }
407
408 QGpgME::CryptoConfig *QGpgME::QGpgMEBackend::config() const
409 {
410     if (!mCryptoConfig) {
411 #ifdef _WIN32_WCE // for now...
412         if (GpgME::hasFeature(GpgME::GpgConfEngineFeature, 0)) {
413             mCryptoConfig = new QGpgMENewCryptoConfig;
414         } else
415 #endif
416             if (!QGpgMECryptoConfig::gpgConfPath().isEmpty()) {
417                 mCryptoConfig = new QGpgMECryptoConfig();
418             }
419     }
420     return mCryptoConfig;
421 }
422
423 static bool check(GpgME::Protocol proto, QString *reason)
424 {
425     if (!GpgME::checkEngine(proto)) {
426         return true;
427     }
428     if (!reason) {
429         return false;
430     }
431     // error, check why:
432 #if 0
433 Port away from localised string or delete.
434     const GpgME::EngineInfo ei = GpgME::engineInfo(proto);
435     if (ei.isNull()) {
436         *reason = i18n("GPGME was compiled without support for %1.", proto == GpgME::CMS ? QLatin1String("S/MIME") : QLatin1String("OpenPGP"));
437     } else if (ei.fileName() && !ei.version()) {
438         *reason = i18n("Engine %1 is not installed properly.", QFile::decodeName(ei.fileName()));
439     } else if (ei.fileName() && ei.version() && ei.requiredVersion())
440         *reason = i18n("Engine %1 version %2 installed, "
441                        "but at least version %3 is required.",
442                        QFile::decodeName(ei.fileName()), QLatin1String(ei.version()), QLatin1String(ei.requiredVersion()));
443     else {
444         *reason = i18n("Unknown problem with engine for protocol %1.", proto == GpgME::CMS ? QLatin1String("S/MIME") : QLatin1String("OpenPGP"));
445     }
446 #endif
447     return false;
448 }
449
450 bool QGpgME::QGpgMEBackend::checkForOpenPGP(QString *reason) const
451 {
452     return check(GpgME::OpenPGP, reason);
453 }
454
455 bool QGpgME::QGpgMEBackend::checkForSMIME(QString *reason) const
456 {
457     return check(GpgME::CMS, reason);
458 }
459
460 bool QGpgME::QGpgMEBackend::checkForProtocol(const char *name, QString *reason) const
461 {
462     if (qstricmp(name, OpenPGP) == 0) {
463         return check(GpgME::OpenPGP, reason);
464     }
465     if (qstricmp(name, SMIME) == 0) {
466         return check(GpgME::CMS, reason);
467     }
468     if (reason) {
469         *reason = QStringLiteral("Unsupported protocol \"%1\"").arg(QLatin1String(name));
470     }
471     return false;
472 }
473
474 QGpgME::Protocol *QGpgME::QGpgMEBackend::openpgp() const
475 {
476     if (!mOpenPGPProtocol)
477         if (checkForOpenPGP()) {
478             mOpenPGPProtocol = new ::Protocol(GpgME::OpenPGP);
479         }
480     return mOpenPGPProtocol;
481 }
482
483 QGpgME::Protocol *QGpgME::QGpgMEBackend::smime() const
484 {
485     if (!mSMIMEProtocol)
486         if (checkForSMIME()) {
487             mSMIMEProtocol = new ::Protocol(GpgME::CMS);
488         }
489     return mSMIMEProtocol;
490 }
491
492 QGpgME::Protocol *QGpgME::QGpgMEBackend::protocol(const char *name) const
493 {
494     if (qstricmp(name, OpenPGP) == 0) {
495         return openpgp();
496     }
497     if (qstricmp(name, SMIME) == 0) {
498         return smime();
499     }
500     return 0;
501 }
502
503 bool QGpgME::QGpgMEBackend::supportsProtocol(const char *name) const
504 {
505     return qstricmp(name, OpenPGP) == 0 || qstricmp(name, SMIME) == 0;
506 }
507
508 const char *QGpgME::QGpgMEBackend::enumerateProtocols(int i) const
509 {
510     switch (i) {
511     case 0: return OpenPGP;
512     case 1: return SMIME;
513     default: return 0;
514     }
515 }