1 /*
2   context.cpp - wraps a gpgme key context
3   Copyright (C) 2003, 2007 Klarälvdalens Datakonsult AB
4                 2017, 2018 Intevation GmbH
5 
6   This file is part of GPGME++.
7 
8   GPGME++ is free software; you can redistribute it and/or
9   modify it under the terms of the GNU Library General Public
10   License as published by the Free Software Foundation; either
11   version 2 of the License, or (at your option) any later version.
12 
13   GPGME++ 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
16   GNU Library General Public License for more details.
17 
18   You should have received a copy of the GNU Library General Public License
19   along with GPGME++; see the file COPYING.LIB.  If not, write to the
20   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21   Boston, MA 02110-1301, USA.
22 */
23 
24 #ifdef HAVE_CONFIG_H
25  #include "config.h"
26 #endif
27 
28 #include <context.h>
29 #include <eventloopinteractor.h>
30 #include <trustitem.h>
31 #include <keylistresult.h>
32 #include <keygenerationresult.h>
33 #include <importresult.h>
34 #include <decryptionresult.h>
35 #include <verificationresult.h>
36 #include <signingresult.h>
37 #include <encryptionresult.h>
38 #include <engineinfo.h>
39 #include <editinteractor.h>
40 #include <vfsmountresult.h>
41 
42 #include <interfaces/assuantransaction.h>
43 #include <defaultassuantransaction.h>
44 
45 #include "callbacks.h"
46 #include "data_p.h"
47 #include "context_p.h"
48 #include "util.h"
49 #include "tofuinfo.h"
50 
51 #include <gpgme.h>
52 
53 #include <istream>
54 #include <numeric>
55 #ifndef NDEBUG
56 #include <iostream>
57 using std::cerr;
58 using std::endl;
59 #endif
60 
61 #include <cassert>
62 
63 namespace GpgME
64 {
65 
xtoi_1(const char * str)66 static inline unsigned int xtoi_1(const char *str)
67 {
68     const unsigned int ch = *str;
69     const unsigned int result =
70         ch <= '9' ? ch - '0' :
71         ch <= 'F' ? ch - 'A' + 10 :
72         /* else */  ch - 'a' + 10 ;
73     return result < 16 ? result : 0 ;
74 }
xtoi_2(const char * str)75 static inline int xtoi_2(const char *str)
76 {
77     return xtoi_1(str) * 16U + xtoi_1(str + 1);
78 }
79 
percent_unescape(std::string & s,bool plus2space)80 static void percent_unescape(std::string &s, bool plus2space)
81 {
82     std::string::iterator src = s.begin(), dest = s.begin(), end = s.end();
83     while (src != end) {
84         if (*src == '%' && end - src > 2) {
85             *dest++ = xtoi_2(&*++src);
86             src += 2;
87         } else if (*src == '+' && plus2space) {
88             *dest++ = ' ';
89             ++src;
90         } else {
91             *dest++ = *src++;
92         }
93     }
94     s.erase(dest, end);
95 }
96 
initializeLibrary()97 void initializeLibrary()
98 {
99     gpgme_check_version(nullptr);
100 }
101 
initializeLibrary(int)102 Error initializeLibrary(int)
103 {
104     if (gpgme_check_version(GPGME_VERSION)) {
105         return Error();
106     } else {
107         return Error::fromCode(GPG_ERR_USER_1);
108     }
109 }
110 
format_error(gpgme_error_t err,std::string & str)111 static void format_error(gpgme_error_t err, std::string &str)
112 {
113     char buffer[ 1024 ];
114     gpgme_strerror_r(err, buffer, sizeof buffer);
115     buffer[ sizeof buffer - 1 ] = '\0';
116     str = buffer;
117 }
118 
source() const119 const char *Error::source() const
120 {
121     return gpgme_strsource((gpgme_error_t)mErr);
122 }
123 
asString() const124 const char *Error::asString() const
125 {
126     if (mMessage.empty()) {
127         format_error(static_cast<gpgme_error_t>(mErr), mMessage);
128     }
129     return mMessage.c_str();
130 }
131 
code() const132 int Error::code() const
133 {
134     return gpgme_err_code(mErr);
135 }
136 
sourceID() const137 int Error::sourceID() const
138 {
139     return gpgme_err_source(mErr);
140 }
141 
isCanceled() const142 bool Error::isCanceled() const
143 {
144     return code() == GPG_ERR_CANCELED;
145 }
146 
toErrno() const147 int Error::toErrno() const
148 {
149 //#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
150     return gpgme_err_code_to_errno(static_cast<gpgme_err_code_t>(code()));
151 //#else
152 //    return gpg_err_code_to_errno( static_cast<gpg_err_code_t>( code() ) );
153 //#endif
154 }
155 
156 // static
hasSystemError()157 bool Error::hasSystemError()
158 {
159     return gpgme_err_code_from_syserror() != GPG_ERR_MISSING_ERRNO ;
160 }
161 
162 // static
setSystemError(gpg_err_code_t err)163 void Error::setSystemError(gpg_err_code_t err)
164 {
165     setErrno(gpgme_err_code_to_errno(err));
166 }
167 
168 // static
setErrno(int err)169 void Error::setErrno(int err)
170 {
171     gpgme_err_set_errno(err);
172 }
173 
174 // static
fromSystemError(unsigned int src)175 Error Error::fromSystemError(unsigned int src)
176 {
177     return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), gpgme_err_code_from_syserror()));
178 }
179 
180 // static
fromErrno(int err,unsigned int src)181 Error Error::fromErrno(int err, unsigned int src)
182 {
183     return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), gpgme_err_code_from_errno(err)));
184 }
185 
186 // static
fromCode(unsigned int err,unsigned int src)187 Error Error::fromCode(unsigned int err, unsigned int src)
188 {
189     return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), static_cast<gpgme_err_code_t>(err)));
190 }
191 
operator <<(std::ostream & os,const Error & err)192 std::ostream &operator<<(std::ostream &os, const Error &err)
193 {
194     return os << "GpgME::Error(" << err.encodedError() << " (" << err.asString() << "))";
195 }
196 
Context(gpgme_ctx_t ctx)197 Context::Context(gpgme_ctx_t ctx) : d(new Private(ctx))
198 {
199 }
200 
~Context()201 Context::~Context()
202 {
203     delete d;
204 }
205 
createForProtocol(Protocol proto)206 Context *Context::createForProtocol(Protocol proto)
207 {
208     gpgme_ctx_t ctx = nullptr;
209     if (gpgme_new(&ctx) != 0) {
210         return nullptr;
211     }
212 
213     switch (proto) {
214     case OpenPGP:
215         if (gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP) != 0) {
216             gpgme_release(ctx);
217             return nullptr;
218         }
219         break;
220     case CMS:
221         if (gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS) != 0) {
222             gpgme_release(ctx);
223             return nullptr;
224         }
225         break;
226     default:
227         return nullptr;
228     }
229 
230     return new Context(ctx);
231 }
232 
create(Protocol proto)233 std::unique_ptr<Context> Context::create(Protocol proto)
234 {
235   return std::unique_ptr <Context> (createForProtocol(proto));
236 }
237 
createForEngine(Engine eng,Error * error)238 std::unique_ptr<Context> Context::createForEngine(Engine eng, Error *error)
239 {
240     gpgme_ctx_t ctx = nullptr;
241     if (const gpgme_error_t err = gpgme_new(&ctx)) {
242         if (error) {
243             *error = Error(err);
244         }
245         return std::unique_ptr<Context>();
246     }
247 
248     switch (eng) {
249     case AssuanEngine:
250         if (const gpgme_error_t err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_ASSUAN)) {
251             gpgme_release(ctx);
252             if (error) {
253                 *error = Error(err);
254             }
255             return std::unique_ptr<Context>();
256         }
257         break;
258     case G13Engine:
259         if (const gpgme_error_t err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_G13)) {
260             gpgme_release(ctx);
261             if (error) {
262                 *error = Error(err);
263             }
264             return std::unique_ptr<Context>();
265         }
266         break;
267     case SpawnEngine:
268         if (const gpgme_error_t err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_SPAWN)) {
269             gpgme_release(ctx);
270             if (error) {
271                 *error = Error(err);
272             }
273             return std::unique_ptr<Context>();
274         }
275         break;
276     default:
277         if (error) {
278             *error = Error::fromCode(GPG_ERR_INV_ARG);
279         }
280         return std::unique_ptr<Context>();
281     }
282 
283     if (error) {
284         *error = Error();
285     }
286 
287     return std::unique_ptr<Context>(new Context(ctx));
288 }
289 
setDecryptionFlags(DecryptionFlags flags)290 void Context::setDecryptionFlags(DecryptionFlags flags)
291 {
292     d->decryptFlags = flags;
293 }
294 
295 //
296 //
297 // Context::Private
298 //
299 //
300 
Private(gpgme_ctx_t c)301 Context::Private::Private(gpgme_ctx_t c)
302     : ctx(c),
303       iocbs(nullptr),
304       lastop(None),
305       lasterr(GPG_ERR_NO_ERROR),
306       lastAssuanInquireData(Data::null),
307       lastAssuanTransaction(),
308       lastEditInteractor(),
309       lastCardEditInteractor(),
310       decryptFlags(DecryptNone)
311 {
312 
313 }
314 
~Private()315 Context::Private::~Private()
316 {
317     if (ctx) {
318         gpgme_release(ctx);
319     }
320     ctx = nullptr;
321     delete iocbs;
322 }
323 
324 //
325 //
326 // Context attributes:
327 //
328 //
329 
protocol() const330 Protocol Context::protocol() const
331 {
332     gpgme_protocol_t p = gpgme_get_protocol(d->ctx);
333     switch (p) {
334     case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
335     case GPGME_PROTOCOL_CMS:     return CMS;
336     default:                     return UnknownProtocol;
337     }
338 }
339 
setArmor(bool useArmor)340 void Context::setArmor(bool useArmor)
341 {
342     gpgme_set_armor(d->ctx, int(useArmor));
343 }
armor() const344 bool Context::armor() const
345 {
346     return gpgme_get_armor(d->ctx);
347 }
348 
setTextMode(bool useTextMode)349 void Context::setTextMode(bool useTextMode)
350 {
351     gpgme_set_textmode(d->ctx, int(useTextMode));
352 }
textMode() const353 bool Context::textMode() const
354 {
355     return gpgme_get_textmode(d->ctx);
356 }
357 
setOffline(bool useOfflineMode)358 void Context::setOffline(bool useOfflineMode)
359 {
360     gpgme_set_offline(d->ctx, int(useOfflineMode));
361 }
offline() const362 bool Context::offline() const
363 {
364     return gpgme_get_offline(d->ctx);
365 }
366 
setIncludeCertificates(int which)367 void Context::setIncludeCertificates(int which)
368 {
369     if (which == DefaultCertificates) {
370         which = GPGME_INCLUDE_CERTS_DEFAULT;
371     }
372     gpgme_set_include_certs(d->ctx, which);
373 }
374 
includeCertificates() const375 int Context::includeCertificates() const
376 {
377     return gpgme_get_include_certs(d->ctx);
378 }
379 
setKeyListMode(unsigned int mode)380 void Context::setKeyListMode(unsigned int mode)
381 {
382     gpgme_set_keylist_mode(d->ctx, add_to_gpgme_keylist_mode_t(0, mode));
383 }
384 
addKeyListMode(unsigned int mode)385 void Context::addKeyListMode(unsigned int mode)
386 {
387     const unsigned int cur = gpgme_get_keylist_mode(d->ctx);
388     gpgme_set_keylist_mode(d->ctx, add_to_gpgme_keylist_mode_t(cur, mode));
389 }
390 
keyListMode() const391 unsigned int Context::keyListMode() const
392 {
393     return convert_from_gpgme_keylist_mode_t(gpgme_get_keylist_mode(d->ctx));
394 }
395 
setProgressProvider(ProgressProvider * provider)396 void Context::setProgressProvider(ProgressProvider *provider)
397 {
398     gpgme_set_progress_cb(d->ctx, provider ? &progress_callback : nullptr, provider);
399 }
progressProvider() const400 ProgressProvider *Context::progressProvider() const
401 {
402     void *pp = nullptr;
403     gpgme_progress_cb_t pcb = &progress_callback;
404     gpgme_get_progress_cb(d->ctx, &pcb, &pp);
405     return static_cast<ProgressProvider *>(pp);
406 }
407 
setPassphraseProvider(PassphraseProvider * provider)408 void Context::setPassphraseProvider(PassphraseProvider *provider)
409 {
410     gpgme_set_passphrase_cb(d->ctx, provider ? &passphrase_callback : nullptr, provider);
411 }
412 
passphraseProvider() const413 PassphraseProvider *Context::passphraseProvider() const
414 {
415     void *pp = nullptr;
416     gpgme_passphrase_cb_t pcb = &passphrase_callback;
417     gpgme_get_passphrase_cb(d->ctx, &pcb, &pp);
418     return static_cast<PassphraseProvider *>(pp);
419 }
420 
setManagedByEventLoopInteractor(bool manage)421 void Context::setManagedByEventLoopInteractor(bool manage)
422 {
423     if (!EventLoopInteractor::instance()) {
424 #ifndef NDEBUG
425         cerr << "Context::setManagedByEventLoopInteractor(): "
426              "You must create an instance of EventLoopInteractor "
427              "before using anything that needs one." << endl;
428 #endif
429         return;
430     }
431     if (manage) {
432         EventLoopInteractor::instance()->manage(this);
433     } else {
434         EventLoopInteractor::instance()->unmanage(this);
435     }
436 }
managedByEventLoopInteractor() const437 bool Context::managedByEventLoopInteractor() const
438 {
439     return d->iocbs != nullptr;
440 }
441 
installIOCallbacks(gpgme_io_cbs * iocbs)442 void Context::installIOCallbacks(gpgme_io_cbs *iocbs)
443 {
444     if (!iocbs) {
445         uninstallIOCallbacks();
446         return;
447     }
448     gpgme_set_io_cbs(d->ctx, iocbs);
449     delete d->iocbs; d->iocbs = iocbs;
450 }
451 
uninstallIOCallbacks()452 void Context::uninstallIOCallbacks()
453 {
454     static gpgme_io_cbs noiocbs = { nullptr, nullptr, nullptr, nullptr, nullptr };
455     // io.add == 0 means disable io callbacks:
456     gpgme_set_io_cbs(d->ctx, &noiocbs);
457     delete d->iocbs; d->iocbs = nullptr;
458 }
459 
setLocale(int cat,const char * val)460 Error Context::setLocale(int cat, const char *val)
461 {
462     return Error(d->lasterr = gpgme_set_locale(d->ctx, cat, val));
463 }
464 
engineInfo() const465 EngineInfo Context::engineInfo() const
466 {
467     return EngineInfo(gpgme_ctx_get_engine_info(d->ctx));
468 }
469 
setEngineFileName(const char * filename)470 Error Context::setEngineFileName(const char *filename)
471 {
472     const char *const home_dir = engineInfo().homeDirectory();
473     return Error(gpgme_ctx_set_engine_info(d->ctx, gpgme_get_protocol(d->ctx), filename, home_dir));
474 }
475 
setEngineHomeDirectory(const char * home_dir)476 Error Context::setEngineHomeDirectory(const char *home_dir)
477 {
478     const char *const filename = engineInfo().fileName();
479     return Error(gpgme_ctx_set_engine_info(d->ctx, gpgme_get_protocol(d->ctx), filename, home_dir));
480 }
481 
setSender(const char * sender)482 Error Context::setSender (const char *sender)
483 {
484     return Error(gpgme_set_sender(d->ctx, sender));
485 }
486 
getSender()487 const char *Context::getSender ()
488 {
489     return gpgme_get_sender(d->ctx);
490 }
491 
492 //
493 //
494 // Key Management
495 //
496 //
497 
startKeyListing(const char * pattern,bool secretOnly)498 Error Context::startKeyListing(const char *pattern, bool secretOnly)
499 {
500     d->lastop = Private::KeyList;
501     return Error(d->lasterr = gpgme_op_keylist_start(d->ctx, pattern, int(secretOnly)));
502 }
503 
startKeyListing(const char * patterns[],bool secretOnly)504 Error Context::startKeyListing(const char *patterns[], bool secretOnly)
505 {
506     d->lastop = Private::KeyList;
507 #ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
508     if (!patterns || !patterns[0] || !patterns[1]) {
509         // max. one pattern -> use the non-ext version
510         return startKeyListing(patterns ? patterns[0] : nullptr, secretOnly);
511     }
512 #endif
513     return Error(d->lasterr = gpgme_op_keylist_ext_start(d->ctx, patterns, int(secretOnly), 0));
514 }
515 
nextKey(GpgME::Error & e)516 Key Context::nextKey(GpgME::Error &e)
517 {
518     d->lastop = Private::KeyList;
519     gpgme_key_t key = nullptr;
520     e = Error(d->lasterr = gpgme_op_keylist_next(d->ctx, &key));
521     return Key(key, false);
522 }
523 
endKeyListing()524 KeyListResult Context::endKeyListing()
525 {
526     d->lasterr = gpgme_op_keylist_end(d->ctx);
527     return keyListResult();
528 }
529 
keyListResult() const530 KeyListResult Context::keyListResult() const
531 {
532     return KeyListResult(d->ctx, Error(d->lasterr));
533 }
534 
key(const char * fingerprint,GpgME::Error & e,bool secret)535 Key Context::key(const char *fingerprint, GpgME::Error &e , bool secret /*, bool forceUpdate*/)
536 {
537     d->lastop = Private::KeyList;
538     gpgme_key_t key = nullptr;
539     e = Error(d->lasterr = gpgme_get_key(d->ctx, fingerprint, &key, int(secret)/*, int( forceUpdate )*/));
540     return Key(key, false);
541 }
542 
generateKey(const char * parameters,Data & pubKey)543 KeyGenerationResult Context::generateKey(const char *parameters, Data &pubKey)
544 {
545     d->lastop = Private::KeyGen;
546     Data::Private *const dp = pubKey.impl();
547     d->lasterr = gpgme_op_genkey(d->ctx, parameters, dp ? dp->data : nullptr, nullptr);
548     return KeyGenerationResult(d->ctx, Error(d->lasterr));
549 }
550 
startKeyGeneration(const char * parameters,Data & pubKey)551 Error Context::startKeyGeneration(const char *parameters, Data &pubKey)
552 {
553     d->lastop = Private::KeyGen;
554     Data::Private *const dp = pubKey.impl();
555     return Error(d->lasterr = gpgme_op_genkey_start(d->ctx, parameters, dp ? dp->data : nullptr, nullptr));
556 }
557 
keyGenerationResult() const558 KeyGenerationResult Context::keyGenerationResult() const
559 {
560     if (d->lastop & Private::KeyGen) {
561         return KeyGenerationResult(d->ctx, Error(d->lasterr));
562     } else {
563         return KeyGenerationResult();
564     }
565 }
566 
exportPublicKeys(const char * pattern,Data & keyData,unsigned int flags)567 Error Context::exportPublicKeys(const char *pattern, Data &keyData, unsigned int flags)
568 {
569     d->lastop = Private::Export;
570     Data::Private *const dp = keyData.impl();
571     return Error(d->lasterr = gpgme_op_export(d->ctx, pattern, flags, dp ? dp->data : nullptr));
572 }
573 
exportPublicKeys(const char * patterns[],Data & keyData,unsigned int flags)574 Error Context::exportPublicKeys(const char *patterns[], Data &keyData, unsigned int flags)
575 {
576     d->lastop = Private::Export;
577 #ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
578     if (!patterns || !patterns[0] || !patterns[1]) {
579         // max. one pattern -> use the non-ext version
580         return exportPublicKeys(patterns ? patterns[0] : nullptr, keyData, flags);
581     }
582 #endif
583     Data::Private *const dp = keyData.impl();
584     return Error(d->lasterr = gpgme_op_export_ext(d->ctx, patterns, flags, dp ? dp->data : nullptr));
585 }
586 
startPublicKeyExport(const char * pattern,Data & keyData,unsigned int flags)587 Error Context::startPublicKeyExport(const char *pattern, Data &keyData, unsigned int flags)
588 {
589     d->lastop = Private::Export;
590     Data::Private *const dp = keyData.impl();
591     return Error(d->lasterr = gpgme_op_export_start(d->ctx, pattern, flags, dp ? dp->data : nullptr));
592 }
593 
startPublicKeyExport(const char * patterns[],Data & keyData,unsigned int flags)594 Error Context::startPublicKeyExport(const char *patterns[], Data &keyData, unsigned int flags)
595 {
596     d->lastop = Private::Export;
597 #ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
598     if (!patterns || !patterns[0] || !patterns[1]) {
599         // max. one pattern -> use the non-ext version
600         return startPublicKeyExport(patterns ? patterns[0] : nullptr, keyData, flags);
601     }
602 #endif
603     Data::Private *const dp = keyData.impl();
604     return Error(d->lasterr = gpgme_op_export_ext_start(d->ctx, patterns, flags, dp ? dp->data : nullptr));
605 }
606 
607 
608 /* Same as above but without flags  */
exportPublicKeys(const char * pattern,Data & keyData)609 Error Context::exportPublicKeys(const char *pattern, Data &keyData)
610 {
611     return exportPublicKeys(pattern, keyData, 0);
612 }
613 
exportPublicKeys(const char * patterns[],Data & keyData)614 Error Context::exportPublicKeys(const char *patterns[], Data &keyData)
615 {
616     return exportPublicKeys(patterns, keyData, 0);
617 }
618 
startPublicKeyExport(const char * pattern,Data & keyData)619 Error Context::startPublicKeyExport(const char *pattern, Data &keyData)
620 {
621     return startPublicKeyExport(pattern, keyData, 0);
622 }
623 
startPublicKeyExport(const char * patterns[],Data & keyData)624 Error Context::startPublicKeyExport(const char *patterns[], Data &keyData)
625 {
626     return startPublicKeyExport(patterns, keyData, 0);
627 }
628 
importKeys(const Data & data)629 ImportResult Context::importKeys(const Data &data)
630 {
631     d->lastop = Private::Import;
632     const Data::Private *const dp = data.impl();
633     d->lasterr = gpgme_op_import(d->ctx, dp ? dp->data : nullptr);
634     return ImportResult(d->ctx, Error(d->lasterr));
635 }
636 
importKeys(const std::vector<Key> & kk)637 ImportResult Context::importKeys(const std::vector<Key> &kk)
638 {
639     d->lastop = Private::Import;
640     d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED);
641 
642     bool shouldHaveResult = false;
643     gpgme_key_t * const keys = new gpgme_key_t[ kk.size() + 1 ];
644     gpgme_key_t *keys_it = &keys[0];
645     for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
646         if (it->impl()) {
647             *keys_it++ = it->impl();
648         }
649     }
650     *keys_it++ = nullptr;
651     d->lasterr = gpgme_op_import_keys(d->ctx, keys);
652     shouldHaveResult = true;
653     if ((gpgme_err_code(d->lasterr) == GPG_ERR_NOT_IMPLEMENTED ||
654             gpgme_err_code(d->lasterr) == GPG_ERR_NOT_SUPPORTED) &&
655             protocol() == CMS) {
656         // ok, try the workaround (export+import):
657         std::vector<const char *> fprs;
658         for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
659             if (const char *fpr = it->primaryFingerprint()) {
660                 if (*fpr) {
661                     fprs.push_back(fpr);
662                 }
663             } else if (const char *keyid = it->keyID()) {
664                 if (*keyid) {
665                     fprs.push_back(keyid);
666                 }
667             }
668         }
669         fprs.push_back(nullptr);
670         Data data;
671         Data::Private *const dp = data.impl();
672         const gpgme_keylist_mode_t oldMode = gpgme_get_keylist_mode(d->ctx);
673         gpgme_set_keylist_mode(d->ctx, GPGME_KEYLIST_MODE_EXTERN);
674         d->lasterr = gpgme_op_export_ext(d->ctx, &fprs[0], 0, dp ? dp->data : nullptr);
675         gpgme_set_keylist_mode(d->ctx, oldMode);
676         if (!d->lasterr) {
677             data.seek(0, SEEK_SET);
678             d->lasterr = gpgme_op_import(d->ctx, dp ? dp->data : nullptr);
679             shouldHaveResult = true;
680         }
681     }
682     delete[] keys;
683     if (shouldHaveResult) {
684         return ImportResult(d->ctx, Error(d->lasterr));
685     } else {
686         return ImportResult(Error(d->lasterr));
687     }
688 }
689 
startKeyImport(const Data & data)690 Error Context::startKeyImport(const Data &data)
691 {
692     d->lastop = Private::Import;
693     const Data::Private *const dp = data.impl();
694     return Error(d->lasterr = gpgme_op_import_start(d->ctx, dp ? dp->data : nullptr));
695 }
696 
startKeyImport(const std::vector<Key> & kk)697 Error Context::startKeyImport(const std::vector<Key> &kk)
698 {
699     d->lastop = Private::Import;
700     gpgme_key_t * const keys = new gpgme_key_t[ kk.size() + 1 ];
701     gpgme_key_t *keys_it = &keys[0];
702     for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
703         if (it->impl()) {
704             *keys_it++ = it->impl();
705         }
706     }
707     *keys_it++ = nullptr;
708     Error err = Error(d->lasterr = gpgme_op_import_keys_start(d->ctx, keys));
709     delete[] keys;
710     return err;
711 }
712 
importResult() const713 ImportResult Context::importResult() const
714 {
715     if (d->lastop & Private::Import) {
716         return ImportResult(d->ctx, Error(d->lasterr));
717     } else {
718         return ImportResult();
719     }
720 }
721 
deleteKey(const Key & key,bool allowSecretKeyDeletion)722 Error Context::deleteKey(const Key &key, bool allowSecretKeyDeletion)
723 {
724     d->lastop = Private::Delete;
725     return Error(d->lasterr = gpgme_op_delete(d->ctx, key.impl(), int(allowSecretKeyDeletion)));
726 }
727 
startKeyDeletion(const Key & key,bool allowSecretKeyDeletion)728 Error Context::startKeyDeletion(const Key &key, bool allowSecretKeyDeletion)
729 {
730     d->lastop = Private::Delete;
731     return Error(d->lasterr = gpgme_op_delete_start(d->ctx, key.impl(), int(allowSecretKeyDeletion)));
732 }
733 
passwd(const Key & key)734 Error Context::passwd(const Key &key)
735 {
736     d->lastop = Private::Passwd;
737     return Error(d->lasterr = gpgme_op_passwd(d->ctx, key.impl(), 0U));
738 }
739 
startPasswd(const Key & key)740 Error Context::startPasswd(const Key &key)
741 {
742     d->lastop = Private::Passwd;
743     return Error(d->lasterr = gpgme_op_passwd_start(d->ctx, key.impl(), 0U));
744 }
745 
746 
747 #pragma GCC diagnostic push
748 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
749 
edit(const Key & key,std::unique_ptr<EditInteractor> func,Data & data)750 Error Context::edit(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
751 {
752     d->lastop = Private::Edit;
753     d->lastEditInteractor = std::move(func);
754     Data::Private *const dp = data.impl();
755     return Error(d->lasterr = gpgme_op_edit(d->ctx, key.impl(),
756                                             d->lastEditInteractor.get() ? edit_interactor_callback : nullptr,
757                                             d->lastEditInteractor.get() ? d->lastEditInteractor->d : nullptr,
758                                             dp ? dp->data : nullptr));
759 }
760 
761 
startEditing(const Key & key,std::unique_ptr<EditInteractor> func,Data & data)762 Error Context::startEditing(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
763 {
764     d->lastop = Private::Edit;
765     d->lastEditInteractor = std::move(func);
766     Data::Private *const dp = data.impl();
767     return Error(d->lasterr = gpgme_op_edit_start(d->ctx, key.impl(),
768                               d->lastEditInteractor.get() ? edit_interactor_callback : nullptr,
769                               d->lastEditInteractor.get() ? d->lastEditInteractor->d : nullptr,
770                               dp ? dp->data : nullptr));
771 }
772 
773 
lastEditInteractor() const774 EditInteractor *Context::lastEditInteractor() const
775 {
776     return d->lastEditInteractor.get();
777 }
778 
takeLastEditInteractor()779 std::unique_ptr<EditInteractor> Context::takeLastEditInteractor()
780 {
781     return std::move(d->lastEditInteractor);
782 }
783 
784 
cardEdit(const Key & key,std::unique_ptr<EditInteractor> func,Data & data)785 Error Context::cardEdit(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
786 {
787     d->lastop = Private::CardEdit;
788     d->lastCardEditInteractor = std::move(func);
789     Data::Private *const dp = data.impl();
790     return Error(d->lasterr = gpgme_op_card_edit(d->ctx, key.impl(),
791                               d->lastCardEditInteractor.get() ? edit_interactor_callback : nullptr,
792                               d->lastCardEditInteractor.get() ? d->lastCardEditInteractor->d : nullptr,
793                               dp ? dp->data : nullptr));
794 }
795 
startCardEditing(const Key & key,std::unique_ptr<EditInteractor> func,Data & data)796 Error Context::startCardEditing(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
797 {
798     d->lastop = Private::CardEdit;
799     d->lastCardEditInteractor = std::move(func);
800     Data::Private *const dp = data.impl();
801     return Error(d->lasterr = gpgme_op_card_edit_start(d->ctx, key.impl(),
802                               d->lastCardEditInteractor.get() ? edit_interactor_callback : nullptr,
803                               d->lastCardEditInteractor.get() ? d->lastCardEditInteractor->d : nullptr,
804                               dp ? dp->data : nullptr));
805 }
806 
807 #pragma GCC diagnostic pop
808 
lastCardEditInteractor() const809 EditInteractor *Context::lastCardEditInteractor() const
810 {
811     return d->lastCardEditInteractor.get();
812 }
813 
takeLastCardEditInteractor()814 std::unique_ptr<EditInteractor> Context::takeLastCardEditInteractor()
815 {
816     return std::move(d->lastCardEditInteractor);
817 }
818 
startTrustItemListing(const char * pattern,int maxLevel)819 Error Context::startTrustItemListing(const char *pattern, int maxLevel)
820 {
821     d->lastop = Private::TrustList;
822     return Error(d->lasterr = gpgme_op_trustlist_start(d->ctx, pattern, maxLevel));
823 }
824 
nextTrustItem(Error & e)825 TrustItem Context::nextTrustItem(Error &e)
826 {
827     gpgme_trust_item_t ti = nullptr;
828     e = Error(d->lasterr = gpgme_op_trustlist_next(d->ctx, &ti));
829     return TrustItem(ti);
830 }
831 
endTrustItemListing()832 Error Context::endTrustItemListing()
833 {
834     return Error(d->lasterr = gpgme_op_trustlist_end(d->ctx));
835 }
836 
assuan_transaction_data_callback(void * opaque,const void * data,size_t datalen)837 static gpgme_error_t assuan_transaction_data_callback(void *opaque, const void *data, size_t datalen)
838 {
839     assert(opaque);
840     AssuanTransaction *t = static_cast<AssuanTransaction *>(opaque);
841     return t->data(static_cast<const char *>(data), datalen).encodedError();
842 }
843 
assuan_transaction_inquire_callback(void * opaque,const char * name,const char * args,gpgme_data_t * r_data)844 static gpgme_error_t assuan_transaction_inquire_callback(void *opaque, const char *name, const char *args, gpgme_data_t *r_data)
845 {
846     assert(opaque);
847     Context::Private *p = static_cast<Context::Private *>(opaque);
848     AssuanTransaction *t = p->lastAssuanTransaction.get();
849     assert(t);
850     Error err;
851     if (name) {
852         p->lastAssuanInquireData = t->inquire(name, args, err);
853     } else {
854         p->lastAssuanInquireData = Data::null;
855     }
856     if (!p->lastAssuanInquireData.isNull()) {
857         *r_data = p->lastAssuanInquireData.impl()->data;
858     }
859     return err.encodedError();
860 }
861 
assuan_transaction_status_callback(void * opaque,const char * status,const char * args)862 static gpgme_error_t assuan_transaction_status_callback(void *opaque, const char *status, const char *args)
863 {
864     assert(opaque);
865     AssuanTransaction *t = static_cast<AssuanTransaction *>(opaque);
866     std::string a = args;
867     percent_unescape(a, true);   // ### why doesn't gpgme do this??
868     return t->status(status, a.c_str()).encodedError();
869 }
870 
assuanTransact(const char * command)871 Error Context::assuanTransact(const char *command)
872 {
873     return assuanTransact(command, std::unique_ptr<AssuanTransaction>(new DefaultAssuanTransaction));
874 }
875 
assuanTransact(const char * command,std::unique_ptr<AssuanTransaction> transaction)876 Error Context::assuanTransact(const char *command, std::unique_ptr<AssuanTransaction> transaction)
877 {
878     gpgme_error_t err, operr;
879 
880     d->lastop = Private::AssuanTransact;
881     d->lastAssuanTransaction = std::move(transaction);
882     if (!d->lastAssuanTransaction.get()) {
883         return Error(d->lasterr = make_error(GPG_ERR_INV_ARG));
884     }
885     err = gpgme_op_assuan_transact_ext
886       (d->ctx,
887        command,
888        assuan_transaction_data_callback,
889        d->lastAssuanTransaction.get(),
890        assuan_transaction_inquire_callback,
891        d,
892        assuan_transaction_status_callback,
893        d->lastAssuanTransaction.get(),
894        &operr);
895 
896     if (!err)
897       err = operr;
898     d->lasterr = err;
899 
900     return Error(d->lasterr);
901 }
902 
startAssuanTransaction(const char * command)903 Error Context::startAssuanTransaction(const char *command)
904 {
905     return startAssuanTransaction(command, std::unique_ptr<AssuanTransaction>(new DefaultAssuanTransaction));
906 }
907 
startAssuanTransaction(const char * command,std::unique_ptr<AssuanTransaction> transaction)908 Error Context::startAssuanTransaction(const char *command, std::unique_ptr<AssuanTransaction> transaction)
909 {
910     gpgme_error_t err;
911 
912     d->lastop = Private::AssuanTransact;
913     d->lastAssuanTransaction = std::move(transaction);
914     if (!d->lastAssuanTransaction.get()) {
915         return Error(d->lasterr = make_error(GPG_ERR_INV_ARG));
916     }
917     err = gpgme_op_assuan_transact_start
918       (d->ctx,
919        command,
920        assuan_transaction_data_callback,
921        d->lastAssuanTransaction.get(),
922        assuan_transaction_inquire_callback,
923        d,
924        assuan_transaction_status_callback,
925        d->lastAssuanTransaction.get());
926 
927     d->lasterr = err;
928 
929     return Error(d->lasterr);
930 }
931 
lastAssuanTransaction() const932 AssuanTransaction *Context::lastAssuanTransaction() const
933 {
934     return d->lastAssuanTransaction.get();
935 }
936 
takeLastAssuanTransaction()937 std::unique_ptr<AssuanTransaction> Context::takeLastAssuanTransaction()
938 {
939     return std::move(d->lastAssuanTransaction);
940 }
941 
decrypt(const Data & cipherText,Data & plainText,const DecryptionFlags flags)942 DecryptionResult Context::decrypt(const Data &cipherText, Data &plainText, const DecryptionFlags flags)
943 {
944     d->lastop = Private::Decrypt;
945     const Data::Private *const cdp = cipherText.impl();
946     Data::Private *const pdp = plainText.impl();
947     d->lasterr = gpgme_op_decrypt_ext(d->ctx, static_cast<gpgme_decrypt_flags_t> (d->decryptFlags | flags), cdp ? cdp->data : nullptr, pdp ? pdp->data : nullptr);
948     return DecryptionResult(d->ctx, Error(d->lasterr));
949 }
950 
decrypt(const Data & cipherText,Data & plainText)951 DecryptionResult Context::decrypt(const Data &cipherText, Data &plainText)
952 {
953     return decrypt(cipherText, plainText, DecryptNone);
954 }
955 
startDecryption(const Data & cipherText,Data & plainText,const DecryptionFlags flags)956 Error Context::startDecryption(const Data &cipherText, Data &plainText, const DecryptionFlags flags)
957 {
958     d->lastop = Private::Decrypt;
959     const Data::Private *const cdp = cipherText.impl();
960     Data::Private *const pdp = plainText.impl();
961     return Error(d->lasterr = gpgme_op_decrypt_ext_start(d->ctx, static_cast<gpgme_decrypt_flags_t> (d->decryptFlags | flags),
962                  cdp ? cdp->data : nullptr, pdp ? pdp->data : nullptr));
963 }
964 
startDecryption(const Data & cipherText,Data & plainText)965 Error Context::startDecryption(const Data &cipherText, Data &plainText)
966 {
967     return startDecryption(cipherText, plainText, DecryptNone);
968 }
969 
decryptionResult() const970 DecryptionResult Context::decryptionResult() const
971 {
972     if (d->lastop & Private::Decrypt) {
973         return DecryptionResult(d->ctx, Error(d->lasterr));
974     } else {
975         return DecryptionResult();
976     }
977 }
978 
verifyDetachedSignature(const Data & signature,const Data & signedText)979 VerificationResult Context::verifyDetachedSignature(const Data &signature, const Data &signedText)
980 {
981     d->lastop = Private::Verify;
982     const Data::Private *const sdp = signature.impl();
983     const Data::Private *const tdp = signedText.impl();
984     d->lasterr = gpgme_op_verify(d->ctx, sdp ? sdp->data : nullptr, tdp ? tdp->data : nullptr, nullptr);
985     return VerificationResult(d->ctx, Error(d->lasterr));
986 }
987 
verifyOpaqueSignature(const Data & signedData,Data & plainText)988 VerificationResult Context::verifyOpaqueSignature(const Data &signedData, Data &plainText)
989 {
990     d->lastop = Private::Verify;
991     const Data::Private *const sdp = signedData.impl();
992     Data::Private *const pdp = plainText.impl();
993     d->lasterr = gpgme_op_verify(d->ctx, sdp ? sdp->data : nullptr, nullptr, pdp ? pdp->data : nullptr);
994     return VerificationResult(d->ctx, Error(d->lasterr));
995 }
996 
startDetachedSignatureVerification(const Data & signature,const Data & signedText)997 Error Context::startDetachedSignatureVerification(const Data &signature, const Data &signedText)
998 {
999     d->lastop = Private::Verify;
1000     const Data::Private *const sdp = signature.impl();
1001     const Data::Private *const tdp = signedText.impl();
1002     return Error(d->lasterr = gpgme_op_verify_start(d->ctx, sdp ? sdp->data : nullptr, tdp ? tdp->data : nullptr, nullptr));
1003 }
1004 
startOpaqueSignatureVerification(const Data & signedData,Data & plainText)1005 Error Context::startOpaqueSignatureVerification(const Data &signedData, Data &plainText)
1006 {
1007     d->lastop = Private::Verify;
1008     const Data::Private *const sdp = signedData.impl();
1009     Data::Private *const pdp = plainText.impl();
1010     return Error(d->lasterr = gpgme_op_verify_start(d->ctx, sdp ? sdp->data : nullptr, nullptr, pdp ? pdp->data : nullptr));
1011 }
1012 
verificationResult() const1013 VerificationResult Context::verificationResult() const
1014 {
1015     if (d->lastop & Private::Verify) {
1016         return VerificationResult(d->ctx, Error(d->lasterr));
1017     } else {
1018         return VerificationResult();
1019     }
1020 }
1021 
decryptAndVerify(const Data & cipherText,Data & plainText,DecryptionFlags flags)1022 std::pair<DecryptionResult, VerificationResult> Context::decryptAndVerify(const Data &cipherText, Data &plainText, DecryptionFlags flags)
1023 {
1024     d->lastop = Private::DecryptAndVerify;
1025     const Data::Private *const cdp = cipherText.impl();
1026     Data::Private *const pdp = plainText.impl();
1027     d->lasterr = gpgme_op_decrypt_ext(d->ctx, static_cast<gpgme_decrypt_flags_t> (d->decryptFlags | flags | DecryptVerify),
1028                                       cdp ? cdp->data : nullptr, pdp ? pdp->data : nullptr);
1029     return std::make_pair(DecryptionResult(d->ctx, Error(d->lasterr)),
1030                           VerificationResult(d->ctx, Error(d->lasterr)));
1031 }
1032 
decryptAndVerify(const Data & cipherText,Data & plainText)1033 std::pair<DecryptionResult, VerificationResult> Context::decryptAndVerify(const Data &cipherText, Data &plainText)
1034 {
1035     return decryptAndVerify(cipherText, plainText, DecryptNone);
1036 }
1037 
startCombinedDecryptionAndVerification(const Data & cipherText,Data & plainText,DecryptionFlags flags)1038 Error Context::startCombinedDecryptionAndVerification(const Data &cipherText, Data &plainText, DecryptionFlags flags)
1039 {
1040     d->lastop = Private::DecryptAndVerify;
1041     const Data::Private *const cdp = cipherText.impl();
1042     Data::Private *const pdp = plainText.impl();
1043     return Error(d->lasterr = gpgme_op_decrypt_ext_start(d->ctx, static_cast<gpgme_decrypt_flags_t> (d->decryptFlags | flags | DecryptVerify), cdp ? cdp->data : nullptr, pdp ? pdp->data : nullptr));
1044 }
1045 
startCombinedDecryptionAndVerification(const Data & cipherText,Data & plainText)1046 Error Context::startCombinedDecryptionAndVerification(const Data &cipherText, Data &plainText)
1047 {
1048     return startCombinedDecryptionAndVerification(cipherText, plainText, DecryptNone);
1049 }
1050 
to_auditlog_flags(unsigned int flags)1051 unsigned int to_auditlog_flags(unsigned int flags)
1052 {
1053     unsigned int result = 0;
1054     if (flags & Context::HtmlAuditLog) {
1055         result |= GPGME_AUDITLOG_HTML;
1056     }
1057     if (flags & Context::AuditLogWithHelp) {
1058         result |= GPGME_AUDITLOG_WITH_HELP;
1059     }
1060     if (flags & Context::DiagnosticAuditLog) {
1061         result |= GPGME_AUDITLOG_DIAG;
1062     }
1063     return result;
1064 }
1065 
startGetAuditLog(Data & output,unsigned int flags)1066 Error Context::startGetAuditLog(Data &output, unsigned int flags)
1067 {
1068     d->lastop = Private::GetAuditLog;
1069     Data::Private *const odp = output.impl();
1070     return Error(d->lasterr = gpgme_op_getauditlog_start(d->ctx, odp ? odp->data : nullptr, to_auditlog_flags(flags)));
1071 }
1072 
getAuditLog(Data & output,unsigned int flags)1073 Error Context::getAuditLog(Data &output, unsigned int flags)
1074 {
1075     d->lastop = Private::GetAuditLog;
1076     Data::Private *const odp = output.impl();
1077     return Error(d->lasterr = gpgme_op_getauditlog(d->ctx, odp ? odp->data : nullptr, to_auditlog_flags(flags)));
1078 }
1079 
clearSigningKeys()1080 void Context::clearSigningKeys()
1081 {
1082     gpgme_signers_clear(d->ctx);
1083 }
1084 
addSigningKey(const Key & key)1085 Error Context::addSigningKey(const Key &key)
1086 {
1087     return Error(d->lasterr = gpgme_signers_add(d->ctx, key.impl()));
1088 }
1089 
signingKey(unsigned int idx) const1090 Key Context::signingKey(unsigned int idx) const
1091 {
1092     gpgme_key_t key = gpgme_signers_enum(d->ctx, idx);
1093     return Key(key, false);
1094 }
1095 
signingKeys() const1096 std::vector<Key> Context::signingKeys() const
1097 {
1098     std::vector<Key> result;
1099     gpgme_key_t key = nullptr;
1100     for (unsigned int i = 0 ; (key = gpgme_signers_enum(d->ctx, i)) ; ++i) {
1101         result.push_back(Key(key, false));
1102     }
1103     return result;
1104 }
1105 
clearSignatureNotations()1106 void Context::clearSignatureNotations()
1107 {
1108     gpgme_sig_notation_clear(d->ctx);
1109 }
1110 
addSignatureNotation(const char * name,const char * value,unsigned int flags)1111 GpgME::Error Context::addSignatureNotation(const char *name, const char *value, unsigned int flags)
1112 {
1113     return Error(gpgme_sig_notation_add(d->ctx, name, value, add_to_gpgme_sig_notation_flags_t(0, flags)));
1114 }
1115 
addSignaturePolicyURL(const char * url,bool critical)1116 GpgME::Error Context::addSignaturePolicyURL(const char *url, bool critical)
1117 {
1118     return Error(gpgme_sig_notation_add(d->ctx, nullptr, url, critical ? GPGME_SIG_NOTATION_CRITICAL : 0));
1119 }
1120 
signaturePolicyURL() const1121 const char *Context::signaturePolicyURL() const
1122 {
1123     for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
1124         if (!n->name) {
1125             return n->value;
1126         }
1127     }
1128     return nullptr;
1129 }
1130 
signatureNotation(unsigned int idx) const1131 Notation Context::signatureNotation(unsigned int idx) const
1132 {
1133     for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
1134         if (n->name) {
1135             if (idx-- == 0) {
1136                 return Notation(n);
1137             }
1138         }
1139     }
1140     return Notation();
1141 }
1142 
signatureNotations() const1143 std::vector<Notation> Context::signatureNotations() const
1144 {
1145     std::vector<Notation> result;
1146     for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
1147         if (n->name) {
1148             result.push_back(Notation(n));
1149         }
1150     }
1151     return result;
1152 }
1153 
sigmode2sigmode(SignatureMode mode)1154 static gpgme_sig_mode_t sigmode2sigmode(SignatureMode mode)
1155 {
1156     switch (mode) {
1157     default:
1158     case NormalSignatureMode: return GPGME_SIG_MODE_NORMAL;
1159     case Detached:            return GPGME_SIG_MODE_DETACH;
1160     case Clearsigned:         return GPGME_SIG_MODE_CLEAR;
1161     }
1162 }
1163 
sign(const Data & plainText,Data & signature,SignatureMode mode)1164 SigningResult Context::sign(const Data &plainText, Data &signature, SignatureMode mode)
1165 {
1166     d->lastop = Private::Sign;
1167     const Data::Private *const pdp = plainText.impl();
1168     Data::Private *const sdp = signature.impl();
1169     d->lasterr = gpgme_op_sign(d->ctx, pdp ? pdp->data : nullptr, sdp ? sdp->data : nullptr, sigmode2sigmode(mode));
1170     return SigningResult(d->ctx, Error(d->lasterr));
1171 }
1172 
startSigning(const Data & plainText,Data & signature,SignatureMode mode)1173 Error Context::startSigning(const Data &plainText, Data &signature, SignatureMode mode)
1174 {
1175     d->lastop = Private::Sign;
1176     const Data::Private *const pdp = plainText.impl();
1177     Data::Private *const sdp = signature.impl();
1178     return Error(d->lasterr = gpgme_op_sign_start(d->ctx, pdp ? pdp->data : nullptr, sdp ? sdp->data : nullptr, sigmode2sigmode(mode)));
1179 }
1180 
signingResult() const1181 SigningResult Context::signingResult() const
1182 {
1183     if (d->lastop & Private::Sign) {
1184         return SigningResult(d->ctx, Error(d->lasterr));
1185     } else {
1186         return SigningResult();
1187     }
1188 }
1189 
encryptflags2encryptflags(Context::EncryptionFlags flags)1190 static gpgme_encrypt_flags_t encryptflags2encryptflags(Context::EncryptionFlags flags)
1191 {
1192     unsigned int result = 0;
1193     if (flags & Context::AlwaysTrust) {
1194         result |= GPGME_ENCRYPT_ALWAYS_TRUST;
1195     }
1196     if (flags & Context::NoEncryptTo) {
1197         result |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
1198     }
1199     if (flags & Context::Prepare) {
1200         result |= GPGME_ENCRYPT_PREPARE;
1201     }
1202     if (flags & Context::ExpectSign) {
1203         result |= GPGME_ENCRYPT_EXPECT_SIGN;
1204     }
1205     if (flags & Context::NoCompress) {
1206         result |= GPGME_ENCRYPT_NO_COMPRESS;
1207     }
1208     if (flags & Context::Symmetric) {
1209         result |= GPGME_ENCRYPT_SYMMETRIC;
1210     }
1211     return static_cast<gpgme_encrypt_flags_t>(result);
1212 }
1213 
getKeysFromRecipients(const std::vector<Key> & recipients)1214 gpgme_key_t *Context::getKeysFromRecipients(const std::vector<Key> &recipients)
1215 {
1216     if (recipients.empty()) {
1217         return nullptr;
1218     }
1219     gpgme_key_t *ret = new gpgme_key_t[ recipients.size() + 1 ];
1220     gpgme_key_t *keys_it = ret;
1221     for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
1222         if (it->impl()) {
1223             *keys_it++ = it->impl();
1224         }
1225     }
1226     *keys_it++ = nullptr;
1227     return ret;
1228 }
1229 
encrypt(const std::vector<Key> & recipients,const Data & plainText,Data & cipherText,EncryptionFlags flags)1230 EncryptionResult Context::encrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
1231 {
1232     d->lastop = Private::Encrypt;
1233     if (flags & NoEncryptTo) {
1234         return EncryptionResult(Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED)));
1235     }
1236     const Data::Private *const pdp = plainText.impl();
1237     Data::Private *const cdp = cipherText.impl();
1238     gpgme_key_t *const keys = getKeysFromRecipients(recipients);
1239     d->lasterr = gpgme_op_encrypt(d->ctx, keys, encryptflags2encryptflags(flags),
1240                                   pdp ? pdp->data : nullptr, cdp ? cdp->data : nullptr);
1241     if (keys) {
1242         delete[] keys;
1243     }
1244     return EncryptionResult(d->ctx, Error(d->lasterr));
1245 }
1246 
encryptSymmetrically(const Data & plainText,Data & cipherText)1247 Error Context::encryptSymmetrically(const Data &plainText, Data &cipherText)
1248 {
1249     d->lastop = Private::Encrypt;
1250     const Data::Private *const pdp = plainText.impl();
1251     Data::Private *const cdp = cipherText.impl();
1252     return Error(d->lasterr = gpgme_op_encrypt(d->ctx, nullptr, (gpgme_encrypt_flags_t)0,
1253                               pdp ? pdp->data : nullptr, cdp ? cdp->data : nullptr));
1254 }
1255 
startEncryption(const std::vector<Key> & recipients,const Data & plainText,Data & cipherText,EncryptionFlags flags)1256 Error Context::startEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
1257 {
1258     d->lastop = Private::Encrypt;
1259     if (flags & NoEncryptTo) {
1260         return Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED));
1261     }
1262     const Data::Private *const pdp = plainText.impl();
1263     Data::Private *const cdp = cipherText.impl();
1264     gpgme_key_t *const keys = getKeysFromRecipients(recipients);
1265     d->lasterr = gpgme_op_encrypt_start(d->ctx, keys, encryptflags2encryptflags(flags),
1266                                         pdp ? pdp->data : nullptr, cdp ? cdp->data : nullptr);
1267     if (keys) {
1268         delete[] keys;
1269     }
1270     return Error(d->lasterr);
1271 }
1272 
encryptionResult() const1273 EncryptionResult Context::encryptionResult() const
1274 {
1275     if (d->lastop & Private::Encrypt) {
1276         return EncryptionResult(d->ctx, Error(d->lasterr));
1277     } else {
1278         return EncryptionResult();
1279     }
1280 }
1281 
signAndEncrypt(const std::vector<Key> & recipients,const Data & plainText,Data & cipherText,EncryptionFlags flags)1282 std::pair<SigningResult, EncryptionResult> Context::signAndEncrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
1283 {
1284     d->lastop = Private::SignAndEncrypt;
1285     const Data::Private *const pdp = plainText.impl();
1286     Data::Private *const cdp = cipherText.impl();
1287     gpgme_key_t *const keys = getKeysFromRecipients(recipients);
1288     d->lasterr = gpgme_op_encrypt_sign(d->ctx, keys, encryptflags2encryptflags(flags),
1289                                        pdp ? pdp->data : nullptr, cdp ? cdp->data : nullptr);
1290     if (keys) {
1291         delete[] keys;
1292     }
1293     return std::make_pair(SigningResult(d->ctx, Error(d->lasterr)),
1294                           EncryptionResult(d->ctx, Error(d->lasterr)));
1295 }
1296 
startCombinedSigningAndEncryption(const std::vector<Key> & recipients,const Data & plainText,Data & cipherText,EncryptionFlags flags)1297 Error Context::startCombinedSigningAndEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
1298 {
1299     d->lastop = Private::SignAndEncrypt;
1300     const Data::Private *const pdp = plainText.impl();
1301     Data::Private *const cdp = cipherText.impl();
1302     gpgme_key_t *const keys = getKeysFromRecipients(recipients);
1303     d->lasterr = gpgme_op_encrypt_sign_start(d->ctx, keys, encryptflags2encryptflags(flags),
1304                  pdp ? pdp->data : nullptr, cdp ? cdp->data : nullptr);
1305     if (keys) {
1306         delete[] keys;
1307     }
1308     return Error(d->lasterr);
1309 }
1310 
createVFS(const char * containerFile,const std::vector<Key> & recipients)1311 Error Context::createVFS(const char *containerFile, const std::vector< Key > &recipients)
1312 {
1313     d->lastop = Private::CreateVFS;
1314     gpgme_key_t *const keys = new gpgme_key_t[ recipients.size() + 1 ];
1315     gpgme_key_t *keys_it = keys;
1316     for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
1317         if (it->impl()) {
1318             *keys_it++ = it->impl();
1319         }
1320     }
1321     *keys_it++ = nullptr;
1322 
1323     gpgme_error_t op_err;
1324     d->lasterr = gpgme_op_vfs_create(d->ctx, keys, containerFile, 0, &op_err);
1325     delete[] keys;
1326     Error error(d->lasterr);
1327     if (error) {
1328         return error;
1329     }
1330     return Error(d->lasterr = op_err);
1331 }
1332 
mountVFS(const char * containerFile,const char * mountDir)1333 VfsMountResult Context::mountVFS(const char *containerFile, const char *mountDir)
1334 {
1335     d->lastop = Private::MountVFS;
1336     gpgme_error_t op_err;
1337     d->lasterr = gpgme_op_vfs_mount(d->ctx, containerFile, mountDir, 0, &op_err);
1338     return VfsMountResult(d->ctx, Error(d->lasterr), Error(op_err));
1339 }
1340 
cancelPendingOperation()1341 Error Context::cancelPendingOperation()
1342 {
1343     return Error(gpgme_cancel_async(d->ctx));
1344 }
1345 
cancelPendingOperationImmediately()1346 Error Context::cancelPendingOperationImmediately()
1347 {
1348     return Error(gpgme_cancel(d->ctx));
1349 }
1350 
poll()1351 bool Context::poll()
1352 {
1353     gpgme_error_t e = GPG_ERR_NO_ERROR;
1354     const bool finished = gpgme_wait(d->ctx, &e, 0);
1355     if (finished) {
1356         d->lasterr = e;
1357     }
1358     return finished;
1359 }
1360 
wait()1361 Error Context::wait()
1362 {
1363     gpgme_error_t e = GPG_ERR_NO_ERROR;
1364     gpgme_wait(d->ctx, &e, 1);
1365     return Error(d->lasterr = e);
1366 }
1367 
lastError() const1368 Error Context::lastError() const
1369 {
1370     return Error(d->lasterr);
1371 }
1372 
pinentryMode() const1373 Context::PinentryMode Context::pinentryMode() const
1374 {
1375     switch (gpgme_get_pinentry_mode (d->ctx)) {
1376         case GPGME_PINENTRY_MODE_ASK:
1377             return PinentryAsk;
1378         case GPGME_PINENTRY_MODE_CANCEL:
1379             return PinentryCancel;
1380         case GPGME_PINENTRY_MODE_ERROR:
1381             return PinentryError;
1382         case GPGME_PINENTRY_MODE_LOOPBACK:
1383             return PinentryLoopback;
1384         case GPGME_PINENTRY_MODE_DEFAULT:
1385         default:
1386             return PinentryDefault;
1387     }
1388 }
1389 
setPinentryMode(PinentryMode which)1390 Error Context::setPinentryMode(PinentryMode which)
1391 {
1392     gpgme_pinentry_mode_t mode;
1393     switch (which) {
1394         case PinentryAsk:
1395             mode = GPGME_PINENTRY_MODE_ASK;
1396             break;
1397         case PinentryCancel:
1398             mode = GPGME_PINENTRY_MODE_CANCEL;
1399             break;
1400         case PinentryError:
1401             mode = GPGME_PINENTRY_MODE_ERROR;
1402             break;
1403         case PinentryLoopback:
1404             mode = GPGME_PINENTRY_MODE_LOOPBACK;
1405             break;
1406         case PinentryDefault:
1407         default:
1408             mode = GPGME_PINENTRY_MODE_DEFAULT;
1409     }
1410     return Error(d->lasterr = gpgme_set_pinentry_mode(d->ctx, mode));
1411 }
1412 
to_tofu_policy_t(unsigned int policy)1413 static gpgme_tofu_policy_t to_tofu_policy_t(unsigned int policy)
1414 {
1415     switch (policy) {
1416         case TofuInfo::PolicyNone:
1417             return GPGME_TOFU_POLICY_NONE;
1418         case TofuInfo::PolicyAuto:
1419             return GPGME_TOFU_POLICY_AUTO;
1420         case TofuInfo::PolicyGood:
1421             return GPGME_TOFU_POLICY_GOOD;
1422         case TofuInfo::PolicyBad:
1423             return GPGME_TOFU_POLICY_BAD;
1424         case TofuInfo::PolicyAsk:
1425             return GPGME_TOFU_POLICY_ASK;
1426         case TofuInfo::PolicyUnknown:
1427         default:
1428             return GPGME_TOFU_POLICY_UNKNOWN;
1429     }
1430 }
1431 
setTofuPolicy(const Key & k,unsigned int policy)1432 Error Context::setTofuPolicy(const Key &k, unsigned int policy)
1433 {
1434     return Error(d->lasterr = gpgme_op_tofu_policy(d->ctx,
1435                  k.impl(), to_tofu_policy_t(policy)));
1436 }
1437 
setTofuPolicyStart(const Key & k,unsigned int policy)1438 Error Context::setTofuPolicyStart(const Key &k, unsigned int policy)
1439 {
1440     return Error(d->lasterr = gpgme_op_tofu_policy_start(d->ctx,
1441                  k.impl(), to_tofu_policy_t(policy)));
1442 }
1443 
startCreateKey(const char * userid,const char * algo,unsigned long reserved,unsigned long expires,const Key & certkey,unsigned int flags)1444 Error Context::startCreateKey (const char *userid,
1445                                const char *algo,
1446                                unsigned long reserved,
1447                                unsigned long expires,
1448                                const Key &certkey,
1449                                unsigned int flags)
1450 {
1451     return Error(d->lasterr = gpgme_op_createkey_start(d->ctx,
1452                  userid,
1453                  algo,
1454                  reserved,
1455                  expires,
1456                  certkey.impl(),
1457                  flags));
1458 }
1459 
createKey(const char * userid,const char * algo,unsigned long reserved,unsigned long expires,const Key & certkey,unsigned int flags)1460 Error Context::createKey (const char *userid,
1461                           const char *algo,
1462                           unsigned long reserved,
1463                           unsigned long expires,
1464                           const Key &certkey,
1465                           unsigned int flags)
1466 {
1467     return Error(d->lasterr = gpgme_op_createkey(d->ctx,
1468                  userid,
1469                  algo,
1470                  reserved,
1471                  expires,
1472                  certkey.impl(),
1473                  flags));
1474 }
1475 
createKeyEx(const char * userid,const char * algo,unsigned long reserved,unsigned long expires,const Key & certkey,unsigned int flags)1476 KeyGenerationResult Context::createKeyEx (const char *userid,
1477                                           const char *algo,
1478                                           unsigned long reserved,
1479                                           unsigned long expires,
1480                                           const Key &certkey,
1481                                           unsigned int flags)
1482 {
1483     d->lasterr = gpgme_op_createkey(d->ctx,
1484                  userid,
1485                  algo,
1486                  reserved,
1487                  expires,
1488                  certkey.impl(),
1489                  flags);
1490     return KeyGenerationResult(d->ctx, Error(d->lasterr));
1491 }
1492 
addUid(const Key & k,const char * userid)1493 Error Context::addUid(const Key &k, const char *userid)
1494 {
1495     return Error(d->lasterr = gpgme_op_adduid(d->ctx,
1496                  k.impl(), userid, 0));
1497 }
1498 
startAddUid(const Key & k,const char * userid)1499 Error Context::startAddUid(const Key &k, const char *userid)
1500 {
1501     return Error(d->lasterr = gpgme_op_adduid_start(d->ctx,
1502                  k.impl(), userid, 0));
1503 }
1504 
revUid(const Key & k,const char * userid)1505 Error Context::revUid(const Key &k, const char *userid)
1506 {
1507     return Error(d->lasterr = gpgme_op_revuid(d->ctx,
1508                  k.impl(), userid, 0));
1509 }
1510 
startRevUid(const Key & k,const char * userid)1511 Error Context::startRevUid(const Key &k, const char *userid)
1512 {
1513     return Error(d->lasterr = gpgme_op_revuid_start(d->ctx,
1514                  k.impl(), userid, 0));
1515 }
1516 
createSubkey(const Key & k,const char * algo,unsigned long reserved,unsigned long expires,unsigned int flags)1517 Error Context::createSubkey(const Key &k, const char *algo,
1518                             unsigned long reserved,
1519                             unsigned long expires,
1520                             unsigned int flags)
1521 {
1522     return Error(d->lasterr = gpgme_op_createsubkey(d->ctx,
1523                  k.impl(), algo, reserved, expires, flags));
1524 }
1525 
startCreateSubkey(const Key & k,const char * algo,unsigned long reserved,unsigned long expires,unsigned int flags)1526 Error Context::startCreateSubkey(const Key &k, const char *algo,
1527                                  unsigned long reserved,
1528                                  unsigned long expires,
1529                                  unsigned int flags)
1530 {
1531     return Error(d->lasterr = gpgme_op_createsubkey_start(d->ctx,
1532                  k.impl(), algo, reserved, expires, flags));
1533 }
1534 
getLFSeparatedListOfStrings(const std::vector<std::string> & strings)1535 static std::string getLFSeparatedListOfStrings(const std::vector<std::string> &strings)
1536 {
1537     if (strings.empty()) {
1538         return std::string();
1539     }
1540 
1541     return std::accumulate(
1542         std::next(strings.begin()),
1543         strings.end(),
1544         strings[0],
1545         [](const std::string &a, const std::string &b) {
1546             return a + '\n' + b;
1547         }
1548     );
1549 }
1550 
getLFSeparatedListOfFingerprintsFromSubkeys(const std::vector<Subkey> & subkeys)1551 static std::string getLFSeparatedListOfFingerprintsFromSubkeys(const std::vector<Subkey> &subkeys)
1552 {
1553     if (subkeys.empty()) {
1554         return std::string();
1555     }
1556 
1557     std::vector<std::string> fprs;
1558     fprs.reserve(subkeys.size());
1559     for (auto &it : subkeys) {
1560         if (it.fingerprint()) {
1561             fprs.push_back(std::string(it.fingerprint()));
1562         }
1563     }
1564 
1565     return getLFSeparatedListOfStrings(fprs);
1566 }
1567 
setExpire(const Key & k,unsigned long expires,const std::vector<Subkey> & subkeys,const Context::SetExpireFlags flags)1568 Error Context::setExpire(const Key &k, unsigned long expires,
1569                          const std::vector<Subkey> &subkeys,
1570                          const Context::SetExpireFlags flags)
1571 {
1572     std::string subfprs;
1573     if (flags & Context::SetExpireAllSubkeys) {
1574         subfprs = "*";
1575     } else {
1576         subfprs = getLFSeparatedListOfFingerprintsFromSubkeys(subkeys);
1577     }
1578     return Error(d->lasterr = gpgme_op_setexpire(d->ctx,
1579                  k.impl(), expires, subfprs.c_str(), 0));
1580 }
1581 
startSetExpire(const Key & k,unsigned long expires,const std::vector<Subkey> & subkeys,const Context::SetExpireFlags flags)1582 Error Context::startSetExpire(const Key &k, unsigned long expires,
1583                               const std::vector<Subkey> &subkeys,
1584                               const Context::SetExpireFlags flags)
1585 {
1586     std::string subfprs;
1587     if (flags & Context::SetExpireAllSubkeys) {
1588         subfprs = "*";
1589     } else {
1590         subfprs = getLFSeparatedListOfFingerprintsFromSubkeys(subkeys);
1591     }
1592     return Error(d->lasterr = gpgme_op_setexpire_start(d->ctx,
1593                  k.impl(), expires, subfprs.c_str(), 0));
1594 }
1595 
getLFSeparatedListOfUserIds(const std::vector<UserID> & userIds)1596 static std::string getLFSeparatedListOfUserIds(const std::vector<UserID> &userIds)
1597 {
1598     if (userIds.empty()) {
1599         return std::string();
1600     }
1601 
1602     std::vector<std::string> uids;
1603     uids.reserve(userIds.size());
1604     for (auto &userId : userIds) {
1605         if (userId.id()) {
1606             uids.push_back(std::string(userId.id()));
1607         }
1608     }
1609 
1610     return getLFSeparatedListOfStrings(uids);
1611 }
1612 
revokeSignature(const Key & key,const Key & signingKey,const std::vector<UserID> & userIds)1613 Error Context::revokeSignature(const Key &key, const Key &signingKey,
1614                                const std::vector<UserID> &userIds)
1615 {
1616     const unsigned int flags = userIds.size() > 1 ? GPGME_REVSIG_LFSEP : 0;
1617     const std::string uids = getLFSeparatedListOfUserIds(userIds);
1618     return Error(d->lasterr = gpgme_op_revsig(d->ctx,
1619                  key.impl(), signingKey.impl(), uids.c_str(), flags));
1620 }
1621 
startRevokeSignature(const Key & key,const Key & signingKey,const std::vector<UserID> & userIds)1622 Error Context::startRevokeSignature(const Key &key, const Key &signingKey,
1623                                     const std::vector<UserID> &userIds)
1624 {
1625     const unsigned int flags = userIds.size() > 1 ? GPGME_REVSIG_LFSEP : 0;
1626     const std::string uids = getLFSeparatedListOfUserIds(userIds);
1627     return Error(d->lasterr = gpgme_op_revsig_start(d->ctx,
1628                  key.impl(), signingKey.impl(), uids.c_str(), flags));
1629 }
1630 
setFlag(const char * name,const char * value)1631 Error Context::setFlag(const char *name, const char *value)
1632 {
1633   return Error(d->lasterr = gpgme_set_ctx_flag(d->ctx, name, value));
1634 }
1635 
getFlag(const char * name) const1636 const char *Context::getFlag(const char *name) const
1637 {
1638   return gpgme_get_ctx_flag(d->ctx, name);
1639 }
1640 
1641 // Engine Spawn stuff
spawn(const char * file,const char * argv[],Data & input,Data & output,Data & err,SpawnFlags flags)1642 Error Context::spawn(const char *file, const char *argv[],
1643                      Data &input, Data &output, Data &err,
1644                      SpawnFlags flags)
1645 {
1646     return Error(d->lasterr = gpgme_op_spawn (d->ctx, file, argv,
1647         input.impl() ? input.impl()->data : nullptr,
1648         output.impl() ? output.impl()->data : nullptr,
1649         err.impl() ? err.impl()->data : nullptr,
1650         static_cast<int>(flags)));
1651 }
1652 
spawnAsync(const char * file,const char * argv[],Data & input,Data & output,Data & err,SpawnFlags flags)1653 Error Context::spawnAsync(const char *file, const char *argv[],
1654                           Data &input, Data &output, Data &err,
1655                           SpawnFlags flags)
1656 {
1657     return Error(d->lasterr = gpgme_op_spawn_start (d->ctx, file, argv,
1658         input.impl() ? input.impl()->data : nullptr,
1659         output.impl() ? output.impl()->data : nullptr,
1660         err.impl() ? err.impl()->data : nullptr,
1661         static_cast<int>(flags)));
1662 }
1663 
operator <<(std::ostream & os,Protocol proto)1664 std::ostream &operator<<(std::ostream &os, Protocol proto)
1665 {
1666     os << "GpgME::Protocol(";
1667     switch (proto) {
1668     case OpenPGP:
1669         os << "OpenPGP";
1670         break;
1671     case CMS:
1672         os << "CMS";
1673         break;
1674     default:
1675     case UnknownProtocol:
1676         os << "UnknownProtocol";
1677         break;
1678     }
1679     return os << ')';
1680 }
1681 
operator <<(std::ostream & os,Engine eng)1682 std::ostream &operator<<(std::ostream &os, Engine eng)
1683 {
1684     os << "GpgME::Engine(";
1685     switch (eng) {
1686     case GpgEngine:
1687         os << "GpgEngine";
1688         break;
1689     case GpgSMEngine:
1690         os << "GpgSMEngine";
1691         break;
1692     case GpgConfEngine:
1693         os << "GpgConfEngine";
1694         break;
1695     case AssuanEngine:
1696         os << "AssuanEngine";
1697         break;
1698     case SpawnEngine:
1699         os << "SpawnEngine";
1700         break;
1701     default:
1702     case UnknownEngine:
1703         os << "UnknownEngine";
1704         break;
1705     }
1706     return os << ')';
1707 }
1708 
operator <<(std::ostream & os,Context::CertificateInclusion incl)1709 std::ostream &operator<<(std::ostream &os, Context::CertificateInclusion incl)
1710 {
1711     os << "GpgME::Context::CertificateInclusion(" << static_cast<int>(incl);
1712     switch (incl) {
1713     case Context::DefaultCertificates:
1714         os << "(DefaultCertificates)";
1715         break;
1716     case Context::AllCertificatesExceptRoot:
1717         os << "(AllCertificatesExceptRoot)";
1718         break;
1719     case Context::AllCertificates:
1720         os << "(AllCertificates)";
1721         break;
1722     case Context::NoCertificates:
1723         os << "(NoCertificates)";
1724         break;
1725     case Context::OnlySenderCertificate:
1726         os << "(OnlySenderCertificate)";
1727         break;
1728     }
1729     return os << ')';
1730 }
1731 
operator <<(std::ostream & os,KeyListMode mode)1732 std::ostream &operator<<(std::ostream &os, KeyListMode mode)
1733 {
1734     os << "GpgME::KeyListMode(";
1735 #define CHECK( x ) if ( !(mode & (x)) ) {} else do { os << #x " "; } while (0)
1736     CHECK(Local);
1737     CHECK(Extern);
1738     CHECK(Signatures);
1739     CHECK(Validate);
1740     CHECK(Ephemeral);
1741     CHECK(WithTofu);
1742     CHECK(WithKeygrip);
1743     CHECK(WithSecret);
1744 #undef CHECK
1745     return os << ')';
1746 }
1747 
operator <<(std::ostream & os,SignatureMode mode)1748 std::ostream &operator<<(std::ostream &os, SignatureMode mode)
1749 {
1750     os << "GpgME::SignatureMode(";
1751     switch (mode) {
1752 #define CHECK( x ) case x: os << #x; break
1753         CHECK(NormalSignatureMode);
1754         CHECK(Detached);
1755         CHECK(Clearsigned);
1756 #undef CHECK
1757     default:
1758         os << "???" "(" << static_cast<int>(mode) << ')';
1759         break;
1760     }
1761     return os << ')';
1762 }
1763 
operator <<(std::ostream & os,Context::EncryptionFlags flags)1764 std::ostream &operator<<(std::ostream &os, Context::EncryptionFlags flags)
1765 {
1766     os << "GpgME::Context::EncryptionFlags(";
1767 #define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
1768     CHECK(AlwaysTrust);
1769     CHECK(NoEncryptTo);
1770     CHECK(Prepare);
1771     CHECK(ExpectSign);
1772     CHECK(NoCompress);
1773     CHECK(Symmetric);
1774 #undef CHECK
1775     return os << ')';
1776 }
1777 
operator <<(std::ostream & os,Context::AuditLogFlags flags)1778 std::ostream &operator<<(std::ostream &os, Context::AuditLogFlags flags)
1779 {
1780     os << "GpgME::Context::AuditLogFlags(";
1781 #define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
1782     CHECK(HtmlAuditLog);
1783     CHECK(AuditLogWithHelp);
1784 #undef CHECK
1785     return os << ')';
1786 }
1787 
1788 } // namespace GpgME
1789 
setDefaultLocale(int cat,const char * val)1790 GpgME::Error GpgME::setDefaultLocale(int cat, const char *val)
1791 {
1792     return Error(gpgme_set_locale(nullptr, cat, val));
1793 }
1794 
engineInfo(GpgME::Protocol proto)1795 GpgME::EngineInfo GpgME::engineInfo(GpgME::Protocol proto)
1796 {
1797     gpgme_engine_info_t ei = nullptr;
1798     if (gpgme_get_engine_info(&ei)) {
1799         return EngineInfo();
1800     }
1801 
1802     const gpgme_protocol_t p = proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP ;
1803 
1804     for (gpgme_engine_info_t i = ei ; i ; i = i->next) {
1805         if (i->protocol == p) {
1806             return EngineInfo(i);
1807         }
1808     }
1809 
1810     return EngineInfo();
1811 }
1812 
dirInfo(const char * what)1813 const char *GpgME::dirInfo(const char *what)
1814 {
1815     return gpgme_get_dirinfo(what);
1816 }
1817 
checkEngine(GpgME::Protocol proto)1818 GpgME::Error GpgME::checkEngine(GpgME::Protocol proto)
1819 {
1820     const gpgme_protocol_t p = proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP ;
1821 
1822     return Error(gpgme_engine_check_version(p));
1823 }
1824 
1825 static const gpgme_protocol_t UNKNOWN_PROTOCOL = static_cast<gpgme_protocol_t>(255);
1826 
engine2protocol(const GpgME::Engine engine)1827 static gpgme_protocol_t engine2protocol(const GpgME::Engine engine)
1828 {
1829     switch (engine) {
1830     case GpgME::GpgEngine:   return GPGME_PROTOCOL_OpenPGP;
1831     case GpgME::GpgSMEngine: return GPGME_PROTOCOL_CMS;
1832     case GpgME::GpgConfEngine:
1833         return GPGME_PROTOCOL_GPGCONF;
1834     case GpgME::AssuanEngine:
1835         return GPGME_PROTOCOL_ASSUAN;
1836     case GpgME::G13Engine:
1837         return GPGME_PROTOCOL_G13;
1838     case GpgME::SpawnEngine:
1839         return GPGME_PROTOCOL_SPAWN;
1840     case GpgME::UnknownEngine:
1841         ;
1842     }
1843     return UNKNOWN_PROTOCOL;
1844 }
1845 
engineInfo(GpgME::Engine engine)1846 GpgME::EngineInfo GpgME::engineInfo(GpgME::Engine engine)
1847 {
1848     gpgme_engine_info_t ei = nullptr;
1849     if (gpgme_get_engine_info(&ei)) {
1850         return EngineInfo();
1851     }
1852 
1853     const gpgme_protocol_t p = engine2protocol(engine);
1854 
1855     for (gpgme_engine_info_t i = ei ; i ; i = i->next) {
1856         if (i->protocol == p) {
1857             return EngineInfo(i);
1858         }
1859     }
1860 
1861     return EngineInfo();
1862 }
1863 
checkEngine(GpgME::Engine engine)1864 GpgME::Error GpgME::checkEngine(GpgME::Engine engine)
1865 {
1866     const gpgme_protocol_t p = engine2protocol(engine);
1867 
1868     return Error(gpgme_engine_check_version(p));
1869 }
1870 
1871 static const unsigned long supported_features = 0
1872         | GpgME::ValidatingKeylistModeFeature
1873         | GpgME::CancelOperationFeature
1874         | GpgME::WrongKeyUsageFeature
1875         | GpgME::DefaultCertificateInclusionFeature
1876         | GpgME::GetSetEngineInfoFeature
1877         | GpgME::ClearAddGetSignatureNotationsFeature
1878         | GpgME::SetDataFileNameFeeature
1879         | GpgME::SignatureNotationsKeylistModeFeature
1880         | GpgME::KeySignatureNotationsFeature
1881         | GpgME::KeyIsQualifiedFeature
1882         | GpgME::SignatureNotationsCriticalFlagFeature
1883         | GpgME::SignatureNotationsFlagsFeature
1884         | GpgME::SignatureNotationsHumanReadableFlagFeature
1885         | GpgME::SubkeyIsQualifiedFeature
1886         | GpgME::EngineInfoHomeDirFeature
1887         | GpgME::DecryptionResultFileNameFeature
1888         | GpgME::DecryptionResultRecipientsFeature
1889         | GpgME::VerificationResultFileNameFeature
1890         | GpgME::SignaturePkaFieldsFeature
1891         | GpgME::SignatureAlgorithmFieldsFeature
1892         | GpgME::FdPointerFeature
1893         | GpgME::AuditLogFeature
1894         | GpgME::GpgConfEngineFeature
1895         | GpgME::CancelOperationAsyncFeature
1896         | GpgME::NoEncryptToEncryptionFlagFeature
1897         | GpgME::CardKeyFeature
1898         | GpgME::AssuanEngineFeature
1899         | GpgME::EphemeralKeylistModeFeature
1900         | GpgME::ImportFromKeyserverFeature
1901         | GpgME::G13VFSFeature
1902         | GpgME::PasswdFeature
1903         ;
1904 
1905 static const unsigned long supported_features2 = 0
1906         | GpgME::BinaryAndFineGrainedIdentify
1907         ;
1908 
hasFeature(unsigned long features)1909 bool GpgME::hasFeature(unsigned long features)
1910 {
1911     return features == (features & supported_features);
1912 }
1913 
hasFeature(unsigned long features,unsigned long features2)1914 bool GpgME::hasFeature(unsigned long features, unsigned long features2)
1915 {
1916     return features  == (features  & supported_features)
1917            && features2 == (features2 & supported_features2)
1918            ;
1919 }
1920 
setGlobalFlag(const char * name,const char * value)1921 int GpgME::setGlobalFlag(const char *name, const char *value)
1922 {
1923     return gpgme_set_global_flag(name, value);
1924 }
1925