814e5a82520bc6e56cd5e422bb44766455bb220c
[gpgme.git] / lang / cpp / src / context.cpp
1 /*
2   context.cpp - wraps a gpgme key context
3   Copyright (C) 2003, 2007 Klarälvdalens Datakonsult AB
4
5   This file is part of GPGME++.
6
7   GPGME++ is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Library General Public
9   License as published by the Free Software Foundation; either
10   version 2 of the License, or (at your option) any later version.
11
12   GPGME++ is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU Library General Public License for more details.
16
17   You should have received a copy of the GNU Library General Public License
18   along with GPGME++; see the file COPYING.LIB.  If not, write to the
19   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20   Boston, MA 02110-1301, USA.
21 */
22
23 #include <context.h>
24 #include <eventloopinteractor.h>
25 #include <trustitem.h>
26 #include <assuanresult.h>
27 #include <keylistresult.h>
28 #include <keygenerationresult.h>
29 #include <importresult.h>
30 #include <decryptionresult.h>
31 #include <verificationresult.h>
32 #include <signingresult.h>
33 #include <encryptionresult.h>
34 #include <engineinfo.h>
35 #include <editinteractor.h>
36 #include <vfsmountresult.h>
37
38 #include <interfaces/assuantransaction.h>
39 #include <defaultassuantransaction.h>
40
41 #include "callbacks.h"
42 #include "data_p.h"
43 #include "context_p.h"
44 #include "util.h"
45
46 #include <gpgme.h>
47
48 #include <istream>
49 #ifndef NDEBUG
50 #include <iostream>
51 using std::cerr;
52 using std::endl;
53 #endif
54
55 #include <cassert>
56
57 namespace GpgME
58 {
59
60 static inline unsigned int xtoi_1(const char *str)
61 {
62     const unsigned int ch = *str;
63     const unsigned int result =
64         ch <= '9' ? ch - '0' :
65         ch <= 'F' ? ch - 'A' + 10 :
66         /* else */  ch - 'a' + 10 ;
67     return result < 16 ? result : 0 ;
68 }
69 static inline int xtoi_2(const char *str)
70 {
71     return xtoi_1(str) * 16U + xtoi_1(str + 1);
72 }
73
74 static void percent_unescape(std::string &s, bool plus2space)
75 {
76     std::string::iterator src = s.begin(), dest = s.begin(), end = s.end();
77     while (src != end) {
78         if (*src == '%' && end - src > 2) {
79             *dest++ = xtoi_2(&*++src);
80             src += 2;
81         } else if (*src == '+' && plus2space) {
82             *dest++ = ' ';
83             ++src;
84         } else {
85             *dest++ = *src++;
86         }
87     }
88     s.erase(dest, end);
89 }
90
91 void initializeLibrary()
92 {
93     gpgme_check_version(0);
94 }
95
96 Error initializeLibrary(int)
97 {
98     if (gpgme_check_version(GPGME_VERSION)) {
99         return Error();
100     } else {
101         return Error::fromCode(GPG_ERR_USER_1);
102     }
103 }
104
105 static void format_error(gpgme_error_t err, std::string &str)
106 {
107     char buffer[ 1024 ];
108     gpgme_strerror_r(err, buffer, sizeof buffer);
109     buffer[ sizeof buffer - 1 ] = '\0';
110     str = buffer;
111 }
112
113 const char *Error::source() const
114 {
115     return gpgme_strsource((gpgme_error_t)mErr);
116 }
117
118 const char *Error::asString() const
119 {
120     if (mMessage.empty()) {
121         format_error(static_cast<gpgme_error_t>(mErr), mMessage);
122     }
123     return mMessage.c_str();
124 }
125
126 int Error::code() const
127 {
128     return gpgme_err_code(mErr);
129 }
130
131 int Error::sourceID() const
132 {
133     return gpgme_err_source(mErr);
134 }
135
136 bool Error::isCanceled() const
137 {
138     return code() == GPG_ERR_CANCELED;
139 }
140
141 int Error::toErrno() const
142 {
143 //#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
144     return gpgme_err_code_to_errno(static_cast<gpgme_err_code_t>(code()));
145 //#else
146 //    return gpg_err_code_to_errno( static_cast<gpg_err_code_t>( code() ) );
147 //#endif
148 }
149
150 // static
151 bool Error::hasSystemError()
152 {
153     return gpgme_err_code_from_syserror() == GPG_ERR_MISSING_ERRNO ;
154 }
155
156 // static
157 void Error::setSystemError(gpg_err_code_t err)
158 {
159     setErrno(gpgme_err_code_to_errno(err));
160 }
161
162 // static
163 void Error::setErrno(int err)
164 {
165     gpgme_err_set_errno(err);
166 }
167
168 // static
169 Error Error::fromSystemError(unsigned int src)
170 {
171     return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), gpgme_err_code_from_syserror()));
172 }
173
174 // static
175 Error Error::fromErrno(int err, unsigned int src)
176 {
177     return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), gpgme_err_code_from_errno(err)));
178 }
179
180 // static
181 Error Error::fromCode(unsigned int err, unsigned int src)
182 {
183     return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), static_cast<gpgme_err_code_t>(err)));
184 }
185
186 std::ostream &operator<<(std::ostream &os, const Error &err)
187 {
188     return os << "GpgME::Error(" << err.encodedError() << " (" << err.asString() << "))";
189 }
190
191 Context::Context(gpgme_ctx_t ctx) : d(new Private(ctx))
192 {
193 }
194
195 Context::~Context()
196 {
197     delete d;
198 }
199
200 Context *Context::createForProtocol(Protocol proto)
201 {
202     gpgme_ctx_t ctx = 0;
203     if (gpgme_new(&ctx) != 0) {
204         return 0;
205     }
206
207     switch (proto) {
208     case OpenPGP:
209         if (gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP) != 0) {
210             gpgme_release(ctx);
211             return 0;
212         }
213         break;
214     case CMS:
215         if (gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS) != 0) {
216             gpgme_release(ctx);
217             return 0;
218         }
219         break;
220     default:
221         return 0;
222     }
223
224     return new Context(ctx);
225 }
226
227 std::unique_ptr<Context> Context::createForEngine(Engine eng, Error *error)
228 {
229     gpgme_ctx_t ctx = 0;
230     if (const gpgme_error_t err = gpgme_new(&ctx)) {
231         if (error) {
232             *error = Error(err);
233         }
234         return std::unique_ptr<Context>();
235     }
236
237     switch (eng) {
238     case AssuanEngine:
239         if (const gpgme_error_t err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_ASSUAN)) {
240             gpgme_release(ctx);
241             if (error) {
242                 *error = Error(err);
243             }
244             return std::unique_ptr<Context>();
245         }
246         break;
247     case G13Engine:
248         if (const gpgme_error_t err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_G13)) {
249             gpgme_release(ctx);
250             if (error) {
251                 *error = Error(err);
252             }
253             return std::unique_ptr<Context>();
254         }
255         break;
256     default:
257         if (error) {
258             *error = Error::fromCode(GPG_ERR_INV_ARG);
259         }
260         return std::unique_ptr<Context>();
261     }
262
263     if (error) {
264         *error = Error();
265     }
266
267     return std::unique_ptr<Context>(new Context(ctx));
268 }
269
270 //
271 //
272 // Context::Private
273 //
274 //
275
276 Context::Private::Private(gpgme_ctx_t c)
277     : ctx(c),
278       iocbs(0),
279       lastop(None),
280       lasterr(GPG_ERR_NO_ERROR),
281       lastAssuanInquireData(Data::null),
282       lastAssuanTransaction(),
283       lastEditInteractor(),
284       lastCardEditInteractor()
285 {
286
287 }
288
289 Context::Private::~Private()
290 {
291     if (ctx) {
292         gpgme_release(ctx);
293     }
294     ctx = 0;
295     delete iocbs;
296 }
297
298 //
299 //
300 // Context attributes:
301 //
302 //
303
304 Protocol Context::protocol() const
305 {
306     gpgme_protocol_t p = gpgme_get_protocol(d->ctx);
307     switch (p) {
308     case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
309     case GPGME_PROTOCOL_CMS:     return CMS;
310     default:                     return UnknownProtocol;
311     }
312 }
313
314 void Context::setArmor(bool useArmor)
315 {
316     gpgme_set_armor(d->ctx, int(useArmor));
317 }
318 bool Context::armor() const
319 {
320     return gpgme_get_armor(d->ctx);
321 }
322
323 void Context::setTextMode(bool useTextMode)
324 {
325     gpgme_set_textmode(d->ctx, int(useTextMode));
326 }
327 bool Context::textMode() const
328 {
329     return gpgme_get_textmode(d->ctx);
330 }
331
332 void Context::setOffline(bool useOfflineMode)
333 {
334     gpgme_set_offline(d->ctx, int(useOfflineMode));
335 }
336 bool Context::offline() const
337 {
338     return gpgme_get_offline(d->ctx);
339 }
340
341 void Context::setIncludeCertificates(int which)
342 {
343     if (which == DefaultCertificates) {
344         which = GPGME_INCLUDE_CERTS_DEFAULT;
345     }
346     gpgme_set_include_certs(d->ctx, which);
347 }
348
349 int Context::includeCertificates() const
350 {
351     return gpgme_get_include_certs(d->ctx);
352 }
353
354 void Context::setKeyListMode(unsigned int mode)
355 {
356     gpgme_set_keylist_mode(d->ctx, add_to_gpgme_keylist_mode_t(0, mode));
357 }
358
359 void Context::addKeyListMode(unsigned int mode)
360 {
361     const unsigned int cur = gpgme_get_keylist_mode(d->ctx);
362     gpgme_set_keylist_mode(d->ctx, add_to_gpgme_keylist_mode_t(cur, mode));
363 }
364
365 unsigned int Context::keyListMode() const
366 {
367     return convert_from_gpgme_keylist_mode_t(gpgme_get_keylist_mode(d->ctx));
368 }
369
370 void Context::setProgressProvider(ProgressProvider *provider)
371 {
372     gpgme_set_progress_cb(d->ctx, provider ? &progress_callback : 0, provider);
373 }
374 ProgressProvider *Context::progressProvider() const
375 {
376     void *pp = 0;
377     gpgme_progress_cb_t pcb = &progress_callback;
378     gpgme_get_progress_cb(d->ctx, &pcb, &pp);
379     return static_cast<ProgressProvider *>(pp);
380 }
381
382 void Context::setPassphraseProvider(PassphraseProvider *provider)
383 {
384     gpgme_set_passphrase_cb(d->ctx, provider ? &passphrase_callback : 0, provider);
385 }
386
387 PassphraseProvider *Context::passphraseProvider() const
388 {
389     void *pp = 0;
390     gpgme_passphrase_cb_t pcb = &passphrase_callback;
391     gpgme_get_passphrase_cb(d->ctx, &pcb, &pp);
392     return static_cast<PassphraseProvider *>(pp);
393 }
394
395 void Context::setManagedByEventLoopInteractor(bool manage)
396 {
397     if (!EventLoopInteractor::instance()) {
398 #ifndef NDEBUG
399         cerr << "Context::setManagedByEventLoopInteractor(): "
400              "You must create an instance of EventLoopInteractor "
401              "before using anything that needs one." << endl;
402 #endif
403         return;
404     }
405     if (manage) {
406         EventLoopInteractor::instance()->manage(this);
407     } else {
408         EventLoopInteractor::instance()->unmanage(this);
409     }
410 }
411 bool Context::managedByEventLoopInteractor() const
412 {
413     return d->iocbs != 0;
414 }
415
416 void Context::installIOCallbacks(gpgme_io_cbs *iocbs)
417 {
418     if (!iocbs) {
419         uninstallIOCallbacks();
420         return;
421     }
422     gpgme_set_io_cbs(d->ctx, iocbs);
423     delete d->iocbs; d->iocbs = iocbs;
424 }
425
426 void Context::uninstallIOCallbacks()
427 {
428     static gpgme_io_cbs noiocbs = { 0, 0, 0, 0, 0 };
429     // io.add == 0 means disable io callbacks:
430     gpgme_set_io_cbs(d->ctx, &noiocbs);
431     delete d->iocbs; d->iocbs = 0;
432 }
433
434 Error Context::setLocale(int cat, const char *val)
435 {
436     return Error(d->lasterr = gpgme_set_locale(d->ctx, cat, val));
437 }
438
439 EngineInfo Context::engineInfo() const
440 {
441     return EngineInfo(gpgme_ctx_get_engine_info(d->ctx));
442 }
443
444 Error Context::setEngineFileName(const char *filename)
445 {
446     const char *const home_dir = engineInfo().homeDirectory();
447     return Error(gpgme_ctx_set_engine_info(d->ctx, gpgme_get_protocol(d->ctx), filename, home_dir));
448 }
449
450 Error Context::setEngineHomeDirectory(const char *home_dir)
451 {
452     const char *const filename = engineInfo().fileName();
453     return Error(gpgme_ctx_set_engine_info(d->ctx, gpgme_get_protocol(d->ctx), filename, home_dir));
454 }
455
456 //
457 //
458 // Key Management
459 //
460 //
461
462 Error Context::startKeyListing(const char *pattern, bool secretOnly)
463 {
464     d->lastop = Private::KeyList;
465     return Error(d->lasterr = gpgme_op_keylist_start(d->ctx, pattern, int(secretOnly)));
466 }
467
468 Error Context::startKeyListing(const char *patterns[], bool secretOnly)
469 {
470     d->lastop = Private::KeyList;
471 #ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
472     if (!patterns || !patterns[0] || !patterns[1]) {
473         // max. one pattern -> use the non-ext version
474         return startKeyListing(patterns ? patterns[0] : 0, secretOnly);
475     }
476 #endif
477     return Error(d->lasterr = gpgme_op_keylist_ext_start(d->ctx, patterns, int(secretOnly), 0));
478 }
479
480 Key Context::nextKey(GpgME::Error &e)
481 {
482     d->lastop = Private::KeyList;
483     gpgme_key_t key;
484     e = Error(d->lasterr = gpgme_op_keylist_next(d->ctx, &key));
485     return Key(key, false);
486 }
487
488 KeyListResult Context::endKeyListing()
489 {
490     d->lasterr = gpgme_op_keylist_end(d->ctx);
491     return keyListResult();
492 }
493
494 KeyListResult Context::keyListResult() const
495 {
496     return KeyListResult(d->ctx, Error(d->lasterr));
497 }
498
499 Key Context::key(const char *fingerprint, GpgME::Error &e , bool secret /*, bool forceUpdate*/)
500 {
501     d->lastop = Private::KeyList;
502     gpgme_key_t key;
503     e = Error(d->lasterr = gpgme_get_key(d->ctx, fingerprint, &key, int(secret)/*, int( forceUpdate )*/));
504     return Key(key, false);
505 }
506
507 KeyGenerationResult Context::generateKey(const char *parameters, Data &pubKey)
508 {
509     d->lastop = Private::KeyGen;
510     Data::Private *const dp = pubKey.impl();
511     d->lasterr = gpgme_op_genkey(d->ctx, parameters, dp ? dp->data : 0, 0);
512     return KeyGenerationResult(d->ctx, Error(d->lasterr));
513 }
514
515 Error Context::startKeyGeneration(const char *parameters, Data &pubKey)
516 {
517     d->lastop = Private::KeyGen;
518     Data::Private *const dp = pubKey.impl();
519     return Error(d->lasterr = gpgme_op_genkey_start(d->ctx, parameters, dp ? dp->data : 0, 0));
520 }
521
522 KeyGenerationResult Context::keyGenerationResult() const
523 {
524     if (d->lastop & Private::KeyGen) {
525         return KeyGenerationResult(d->ctx, Error(d->lasterr));
526     } else {
527         return KeyGenerationResult();
528     }
529 }
530
531 Error Context::exportPublicKeys(const char *pattern, Data &keyData)
532 {
533     d->lastop = Private::Export;
534     Data::Private *const dp = keyData.impl();
535     return Error(d->lasterr = gpgme_op_export(d->ctx, pattern, 0, dp ? dp->data : 0));
536 }
537
538 Error Context::exportPublicKeys(const char *patterns[], Data &keyData)
539 {
540     d->lastop = Private::Export;
541 #ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
542     if (!patterns || !patterns[0] || !patterns[1]) {
543         // max. one pattern -> use the non-ext version
544         return exportPublicKeys(patterns ? patterns[0] : 0, keyData);
545     }
546 #endif
547     Data::Private *const dp = keyData.impl();
548     return Error(d->lasterr = gpgme_op_export_ext(d->ctx, patterns, 0, dp ? dp->data : 0));
549 }
550
551 Error Context::startPublicKeyExport(const char *pattern, Data &keyData)
552 {
553     d->lastop = Private::Export;
554     Data::Private *const dp = keyData.impl();
555     return Error(d->lasterr = gpgme_op_export_start(d->ctx, pattern, 0, dp ? dp->data : 0));
556 }
557
558 Error Context::startPublicKeyExport(const char *patterns[], Data &keyData)
559 {
560     d->lastop = Private::Export;
561 #ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
562     if (!patterns || !patterns[0] || !patterns[1]) {
563         // max. one pattern -> use the non-ext version
564         return startPublicKeyExport(patterns ? patterns[0] : 0, keyData);
565     }
566 #endif
567     Data::Private *const dp = keyData.impl();
568     return Error(d->lasterr = gpgme_op_export_ext_start(d->ctx, patterns, 0, dp ? dp->data : 0));
569 }
570
571 ImportResult Context::importKeys(const Data &data)
572 {
573     d->lastop = Private::Import;
574     const Data::Private *const dp = data.impl();
575     d->lasterr = gpgme_op_import(d->ctx, dp ? dp->data : 0);
576     return ImportResult(d->ctx, Error(d->lasterr));
577 }
578
579 ImportResult Context::importKeys(const std::vector<Key> &kk)
580 {
581     d->lastop = Private::Import;
582     d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED);
583
584     bool shouldHaveResult = false;
585     gpgme_key_t * const keys = new gpgme_key_t[ kk.size() + 1 ];
586     gpgme_key_t *keys_it = &keys[0];
587     for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
588         if (it->impl()) {
589             *keys_it++ = it->impl();
590         }
591     }
592     *keys_it++ = 0;
593     d->lasterr = gpgme_op_import_keys(d->ctx, keys);
594     shouldHaveResult = true;
595     if ((gpgme_err_code(d->lasterr) == GPG_ERR_NOT_IMPLEMENTED ||
596             gpgme_err_code(d->lasterr) == GPG_ERR_NOT_SUPPORTED) &&
597             protocol() == CMS) {
598         // ok, try the workaround (export+import):
599         std::vector<const char *> fprs;
600         for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
601             if (const char *fpr = it->primaryFingerprint()) {
602                 if (*fpr) {
603                     fprs.push_back(fpr);
604                 }
605             } else if (const char *keyid = it->keyID()) {
606                 if (*keyid) {
607                     fprs.push_back(keyid);
608                 }
609             }
610         }
611         fprs.push_back(0);
612         Data data;
613         Data::Private *const dp = data.impl();
614         const gpgme_keylist_mode_t oldMode = gpgme_get_keylist_mode(d->ctx);
615         gpgme_set_keylist_mode(d->ctx, GPGME_KEYLIST_MODE_EXTERN);
616         d->lasterr = gpgme_op_export_ext(d->ctx, &fprs[0], 0, dp ? dp->data : 0);
617         gpgme_set_keylist_mode(d->ctx, oldMode);
618         if (!d->lasterr) {
619             data.seek(0, SEEK_SET);
620             d->lasterr = gpgme_op_import(d->ctx, dp ? dp->data : 0);
621             shouldHaveResult = true;
622         }
623     }
624     delete[] keys;
625     if (shouldHaveResult) {
626         return ImportResult(d->ctx, Error(d->lasterr));
627     } else {
628         return ImportResult(Error(d->lasterr));
629     }
630 }
631
632 Error Context::startKeyImport(const Data &data)
633 {
634     d->lastop = Private::Import;
635     const Data::Private *const dp = data.impl();
636     return Error(d->lasterr = gpgme_op_import_start(d->ctx, dp ? dp->data : 0));
637 }
638
639 Error Context::startKeyImport(const std::vector<Key> &kk)
640 {
641     d->lastop = Private::Import;
642     gpgme_key_t * const keys = new gpgme_key_t[ kk.size() + 1 ];
643     gpgme_key_t *keys_it = &keys[0];
644     for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
645         if (it->impl()) {
646             *keys_it++ = it->impl();
647         }
648     }
649     *keys_it++ = 0;
650     Error err = Error(d->lasterr = gpgme_op_import_keys_start(d->ctx, keys));
651     delete[] keys;
652     return err;
653 }
654
655 ImportResult Context::importResult() const
656 {
657     if (d->lastop & Private::Import) {
658         return ImportResult(d->ctx, Error(d->lasterr));
659     } else {
660         return ImportResult();
661     }
662 }
663
664 Error Context::deleteKey(const Key &key, bool allowSecretKeyDeletion)
665 {
666     d->lastop = Private::Delete;
667     return Error(d->lasterr = gpgme_op_delete(d->ctx, key.impl(), int(allowSecretKeyDeletion)));
668 }
669
670 Error Context::startKeyDeletion(const Key &key, bool allowSecretKeyDeletion)
671 {
672     d->lastop = Private::Delete;
673     return Error(d->lasterr = gpgme_op_delete_start(d->ctx, key.impl(), int(allowSecretKeyDeletion)));
674 }
675
676 Error Context::passwd(const Key &key)
677 {
678     d->lastop = Private::Passwd;
679     return Error(d->lasterr = gpgme_op_passwd(d->ctx, key.impl(), 0U));
680 }
681
682 Error Context::startPasswd(const Key &key)
683 {
684     d->lastop = Private::Passwd;
685     return Error(d->lasterr = gpgme_op_passwd_start(d->ctx, key.impl(), 0U));
686 }
687
688 Error Context::edit(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
689 {
690     d->lastop = Private::Edit;
691     d->lastEditInteractor = std::move(func);
692     Data::Private *const dp = data.impl();
693     return Error(d->lasterr = gpgme_op_edit(d->ctx, key.impl(),
694                                             d->lastEditInteractor.get() ? edit_interactor_callback : 0,
695                                             d->lastEditInteractor.get() ? d->lastEditInteractor->d : 0,
696                                             dp ? dp->data : 0));
697 }
698
699 Error Context::startEditing(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
700 {
701     d->lastop = Private::Edit;
702     d->lastEditInteractor = std::move(func);
703     Data::Private *const dp = data.impl();
704     return Error(d->lasterr = gpgme_op_edit_start(d->ctx, key.impl(),
705                               d->lastEditInteractor.get() ? edit_interactor_callback : 0,
706                               d->lastEditInteractor.get() ? d->lastEditInteractor->d : 0,
707                               dp ? dp->data : 0));
708 }
709
710 EditInteractor *Context::lastEditInteractor() const
711 {
712     return d->lastEditInteractor.get();
713 }
714
715 std::unique_ptr<EditInteractor> Context::takeLastEditInteractor()
716 {
717     return std::move(d->lastEditInteractor);
718 }
719
720 Error Context::cardEdit(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
721 {
722     d->lastop = Private::CardEdit;
723     d->lastCardEditInteractor = std::move(func);
724     Data::Private *const dp = data.impl();
725     return Error(d->lasterr = gpgme_op_card_edit(d->ctx, key.impl(),
726                               d->lastCardEditInteractor.get() ? edit_interactor_callback : 0,
727                               d->lastCardEditInteractor.get() ? d->lastCardEditInteractor->d : 0,
728                               dp ? dp->data : 0));
729 }
730
731 Error Context::startCardEditing(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
732 {
733     d->lastop = Private::CardEdit;
734     d->lastCardEditInteractor = std::move(func);
735     Data::Private *const dp = data.impl();
736     return Error(d->lasterr = gpgme_op_card_edit_start(d->ctx, key.impl(),
737                               d->lastCardEditInteractor.get() ? edit_interactor_callback : 0,
738                               d->lastCardEditInteractor.get() ? d->lastCardEditInteractor->d : 0,
739                               dp ? dp->data : 0));
740 }
741
742 EditInteractor *Context::lastCardEditInteractor() const
743 {
744     return d->lastCardEditInteractor.get();
745 }
746
747 std::unique_ptr<EditInteractor> Context::takeLastCardEditInteractor()
748 {
749     return std::move(d->lastCardEditInteractor);
750 }
751
752 Error Context::startTrustItemListing(const char *pattern, int maxLevel)
753 {
754     d->lastop = Private::TrustList;
755     return Error(d->lasterr = gpgme_op_trustlist_start(d->ctx, pattern, maxLevel));
756 }
757
758 TrustItem Context::nextTrustItem(Error &e)
759 {
760     gpgme_trust_item_t ti = 0;
761     e = Error(d->lasterr = gpgme_op_trustlist_next(d->ctx, &ti));
762     return TrustItem(ti);
763 }
764
765 Error Context::endTrustItemListing()
766 {
767     return Error(d->lasterr = gpgme_op_trustlist_end(d->ctx));
768 }
769
770 static gpgme_error_t assuan_transaction_data_callback(void *opaque, const void *data, size_t datalen)
771 {
772     assert(opaque);
773     AssuanTransaction *t = static_cast<AssuanTransaction *>(opaque);
774     return t->data(static_cast<const char *>(data), datalen).encodedError();
775 }
776
777 static gpgme_error_t assuan_transaction_inquire_callback(void *opaque, const char *name, const char *args, gpgme_data_t *r_data)
778 {
779     assert(opaque);
780     Context::Private *p = static_cast<Context::Private *>(opaque);
781     AssuanTransaction *t = p->lastAssuanTransaction.get();
782     assert(t);
783     Error err;
784     if (name) {
785         p->lastAssuanInquireData = t->inquire(name, args, err);
786     } else {
787         p->lastAssuanInquireData = Data::null;
788     }
789     if (!p->lastAssuanInquireData.isNull()) {
790         *r_data = p->lastAssuanInquireData.impl()->data;
791     }
792     return err.encodedError();
793 }
794
795 static gpgme_error_t assuan_transaction_status_callback(void *opaque, const char *status, const char *args)
796 {
797     assert(opaque);
798     AssuanTransaction *t = static_cast<AssuanTransaction *>(opaque);
799     std::string a = args;
800     percent_unescape(a, true);   // ### why doesn't gpgme do this??
801     return t->status(status, a.c_str()).encodedError();
802 }
803
804 AssuanResult Context::assuanTransact(const char *command)
805 {
806     return assuanTransact(command, std::unique_ptr<AssuanTransaction>(new DefaultAssuanTransaction));
807 }
808
809 AssuanResult Context::assuanTransact(const char *command, std::unique_ptr<AssuanTransaction> transaction)
810 {
811     d->lastop = Private::AssuanTransact;
812     d->lastAssuanTransaction = std::move(transaction);
813     if (!d->lastAssuanTransaction.get()) {
814         return AssuanResult(Error(d->lasterr = make_error(GPG_ERR_INV_ARG)));
815     }
816     d->lasterr = gpgme_op_assuan_transact(d->ctx, command,
817                                           assuan_transaction_data_callback,
818                                           d->lastAssuanTransaction.get(),
819                                           assuan_transaction_inquire_callback,
820                                           d, // sic!
821                                           assuan_transaction_status_callback,
822                                           d->lastAssuanTransaction.get());
823     return AssuanResult(d->ctx, d->lasterr);
824 }
825
826 Error Context::startAssuanTransaction(const char *command)
827 {
828     return startAssuanTransaction(command, std::unique_ptr<AssuanTransaction>(new DefaultAssuanTransaction));
829 }
830
831 Error Context::startAssuanTransaction(const char *command, std::unique_ptr<AssuanTransaction> transaction)
832 {
833     d->lastop = Private::AssuanTransact;
834     d->lastAssuanTransaction = std::move(transaction);
835     if (!d->lastAssuanTransaction.get()) {
836         return Error(d->lasterr = make_error(GPG_ERR_INV_ARG));
837     }
838     return Error(d->lasterr = gpgme_op_assuan_transact_start(d->ctx, command,
839                               assuan_transaction_data_callback,
840                               d->lastAssuanTransaction.get(),
841                               assuan_transaction_inquire_callback,
842                               d, // sic!
843                               assuan_transaction_status_callback,
844                               d->lastAssuanTransaction.get()));
845 }
846
847 AssuanResult Context::assuanResult() const
848 {
849     if (d->lastop & Private::AssuanTransact) {
850         return AssuanResult(d->ctx, d->lasterr);
851     } else {
852         return AssuanResult();
853     }
854 }
855
856 AssuanTransaction *Context::lastAssuanTransaction() const
857 {
858     return d->lastAssuanTransaction.get();
859 }
860
861 std::unique_ptr<AssuanTransaction> Context::takeLastAssuanTransaction()
862 {
863     return std::move(d->lastAssuanTransaction);
864 }
865
866 DecryptionResult Context::decrypt(const Data &cipherText, Data &plainText)
867 {
868     d->lastop = Private::Decrypt;
869     const Data::Private *const cdp = cipherText.impl();
870     Data::Private *const pdp = plainText.impl();
871     d->lasterr = gpgme_op_decrypt(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0);
872     return DecryptionResult(d->ctx, Error(d->lasterr));
873 }
874
875 Error Context::startDecryption(const Data &cipherText, Data &plainText)
876 {
877     d->lastop = Private::Decrypt;
878     const Data::Private *const cdp = cipherText.impl();
879     Data::Private *const pdp = plainText.impl();
880     return Error(d->lasterr = gpgme_op_decrypt_start(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0));
881 }
882
883 DecryptionResult Context::decryptionResult() const
884 {
885     if (d->lastop & Private::Decrypt) {
886         return DecryptionResult(d->ctx, Error(d->lasterr));
887     } else {
888         return DecryptionResult();
889     }
890 }
891
892 VerificationResult Context::verifyDetachedSignature(const Data &signature, const Data &signedText)
893 {
894     d->lastop = Private::Verify;
895     const Data::Private *const sdp = signature.impl();
896     const Data::Private *const tdp = signedText.impl();
897     d->lasterr = gpgme_op_verify(d->ctx, sdp ? sdp->data : 0, tdp ? tdp->data : 0, 0);
898     return VerificationResult(d->ctx, Error(d->lasterr));
899 }
900
901 VerificationResult Context::verifyOpaqueSignature(const Data &signedData, Data &plainText)
902 {
903     d->lastop = Private::Verify;
904     const Data::Private *const sdp = signedData.impl();
905     Data::Private *const pdp = plainText.impl();
906     d->lasterr = gpgme_op_verify(d->ctx, sdp ? sdp->data : 0, 0, pdp ? pdp->data : 0);
907     return VerificationResult(d->ctx, Error(d->lasterr));
908 }
909
910 Error Context::startDetachedSignatureVerification(const Data &signature, const Data &signedText)
911 {
912     d->lastop = Private::Verify;
913     const Data::Private *const sdp = signature.impl();
914     const Data::Private *const tdp = signedText.impl();
915     return Error(d->lasterr = gpgme_op_verify_start(d->ctx, sdp ? sdp->data : 0, tdp ? tdp->data : 0, 0));
916 }
917
918 Error Context::startOpaqueSignatureVerification(const Data &signedData, Data &plainText)
919 {
920     d->lastop = Private::Verify;
921     const Data::Private *const sdp = signedData.impl();
922     Data::Private *const pdp = plainText.impl();
923     return Error(d->lasterr = gpgme_op_verify_start(d->ctx, sdp ? sdp->data : 0, 0, pdp ? pdp->data : 0));
924 }
925
926 VerificationResult Context::verificationResult() const
927 {
928     if (d->lastop & Private::Verify) {
929         return VerificationResult(d->ctx, Error(d->lasterr));
930     } else {
931         return VerificationResult();
932     }
933 }
934
935 std::pair<DecryptionResult, VerificationResult> Context::decryptAndVerify(const Data &cipherText, Data &plainText)
936 {
937     d->lastop = Private::DecryptAndVerify;
938     const Data::Private *const cdp = cipherText.impl();
939     Data::Private *const pdp = plainText.impl();
940     d->lasterr = gpgme_op_decrypt_verify(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0);
941     return std::make_pair(DecryptionResult(d->ctx, Error(d->lasterr)),
942                           VerificationResult(d->ctx, Error(d->lasterr)));
943 }
944
945 Error Context::startCombinedDecryptionAndVerification(const Data &cipherText, Data &plainText)
946 {
947     d->lastop = Private::DecryptAndVerify;
948     const Data::Private *const cdp = cipherText.impl();
949     Data::Private *const pdp = plainText.impl();
950     return Error(d->lasterr = gpgme_op_decrypt_verify_start(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0));
951 }
952
953 unsigned int to_auditlog_flags(unsigned int flags)
954 {
955     unsigned int result = 0;
956     if (flags & Context::HtmlAuditLog) {
957         result |= GPGME_AUDITLOG_HTML;
958     }
959     if (flags & Context::AuditLogWithHelp) {
960         result |= GPGME_AUDITLOG_WITH_HELP;
961     }
962     return result;
963 }
964
965 Error Context::startGetAuditLog(Data &output, unsigned int flags)
966 {
967     d->lastop = Private::GetAuditLog;
968     Data::Private *const odp = output.impl();
969     return Error(d->lasterr = gpgme_op_getauditlog_start(d->ctx, odp ? odp->data : 0, to_auditlog_flags(flags)));
970 }
971
972 Error Context::getAuditLog(Data &output, unsigned int flags)
973 {
974     d->lastop = Private::GetAuditLog;
975     Data::Private *const odp = output.impl();
976     return Error(d->lasterr = gpgme_op_getauditlog(d->ctx, odp ? odp->data : 0, to_auditlog_flags(flags)));
977 }
978
979 void Context::clearSigningKeys()
980 {
981     gpgme_signers_clear(d->ctx);
982 }
983
984 Error Context::addSigningKey(const Key &key)
985 {
986     return Error(d->lasterr = gpgme_signers_add(d->ctx, key.impl()));
987 }
988
989 Key Context::signingKey(unsigned int idx) const
990 {
991     gpgme_key_t key = gpgme_signers_enum(d->ctx, idx);
992     return Key(key, false);
993 }
994
995 std::vector<Key> Context::signingKeys() const
996 {
997     std::vector<Key> result;
998     gpgme_key_t key;
999     for (unsigned int i = 0 ; (key = gpgme_signers_enum(d->ctx, i)) ; ++i) {
1000         result.push_back(Key(key, false));
1001     }
1002     return result;
1003 }
1004
1005 void Context::clearSignatureNotations()
1006 {
1007     gpgme_sig_notation_clear(d->ctx);
1008 }
1009
1010 GpgME::Error Context::addSignatureNotation(const char *name, const char *value, unsigned int flags)
1011 {
1012     return Error(gpgme_sig_notation_add(d->ctx, name, value, add_to_gpgme_sig_notation_flags_t(0, flags)));
1013 }
1014
1015 GpgME::Error Context::addSignaturePolicyURL(const char *url, bool critical)
1016 {
1017     return Error(gpgme_sig_notation_add(d->ctx, 0, url, critical ? GPGME_SIG_NOTATION_CRITICAL : 0));
1018 }
1019
1020 const char *Context::signaturePolicyURL() const
1021 {
1022     for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
1023         if (!n->name) {
1024             return n->value;
1025         }
1026     }
1027 }
1028
1029 Notation Context::signatureNotation(unsigned int idx) const
1030 {
1031     for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
1032         if (n->name) {
1033             if (idx-- == 0) {
1034                 return Notation(n);
1035             }
1036         }
1037     }
1038     return Notation();
1039 }
1040
1041 std::vector<Notation> Context::signatureNotations() const
1042 {
1043     std::vector<Notation> result;
1044     for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
1045         if (n->name) {
1046             result.push_back(Notation(n));
1047         }
1048     }
1049     return result;
1050 }
1051
1052 static gpgme_sig_mode_t sigmode2sigmode(SignatureMode mode)
1053 {
1054     switch (mode) {
1055     default:
1056     case NormalSignatureMode: return GPGME_SIG_MODE_NORMAL;
1057     case Detached:            return GPGME_SIG_MODE_DETACH;
1058     case Clearsigned:         return GPGME_SIG_MODE_CLEAR;
1059     }
1060 }
1061
1062 SigningResult Context::sign(const Data &plainText, Data &signature, SignatureMode mode)
1063 {
1064     d->lastop = Private::Sign;
1065     const Data::Private *const pdp = plainText.impl();
1066     Data::Private *const sdp = signature.impl();
1067     d->lasterr = gpgme_op_sign(d->ctx, pdp ? pdp->data : 0, sdp ? sdp->data : 0, sigmode2sigmode(mode));
1068     return SigningResult(d->ctx, Error(d->lasterr));
1069 }
1070
1071 Error Context::startSigning(const Data &plainText, Data &signature, SignatureMode mode)
1072 {
1073     d->lastop = Private::Sign;
1074     const Data::Private *const pdp = plainText.impl();
1075     Data::Private *const sdp = signature.impl();
1076     return Error(d->lasterr = gpgme_op_sign_start(d->ctx, pdp ? pdp->data : 0, sdp ? sdp->data : 0, sigmode2sigmode(mode)));
1077 }
1078
1079 SigningResult Context::signingResult() const
1080 {
1081     if (d->lastop & Private::Sign) {
1082         return SigningResult(d->ctx, Error(d->lasterr));
1083     } else {
1084         return SigningResult();
1085     }
1086 }
1087
1088 static gpgme_encrypt_flags_t encryptflags2encryptflags(Context::EncryptionFlags flags)
1089 {
1090     unsigned int result = 0;
1091     if (flags & Context::AlwaysTrust) {
1092         result |= GPGME_ENCRYPT_ALWAYS_TRUST;
1093     }
1094     if (flags & Context::NoEncryptTo) {
1095         result |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
1096     }
1097     return static_cast<gpgme_encrypt_flags_t>(result);
1098 }
1099
1100 EncryptionResult Context::encrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
1101 {
1102     d->lastop = Private::Encrypt;
1103     if (flags & NoEncryptTo) {
1104         return EncryptionResult(Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED)));
1105     }
1106     const Data::Private *const pdp = plainText.impl();
1107     Data::Private *const cdp = cipherText.impl();
1108     gpgme_key_t *const keys = new gpgme_key_t[ recipients.size() + 1 ];
1109     gpgme_key_t *keys_it = keys;
1110     for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
1111         if (it->impl()) {
1112             *keys_it++ = it->impl();
1113         }
1114     }
1115     *keys_it++ = 0;
1116     d->lasterr = gpgme_op_encrypt(d->ctx, recipients.empty() ? nullptr : keys,
1117                                   encryptflags2encryptflags(flags),
1118                                   pdp ? pdp->data : 0, cdp ? cdp->data : 0);
1119     delete[] keys;
1120     return EncryptionResult(d->ctx, Error(d->lasterr));
1121 }
1122
1123 Error Context::encryptSymmetrically(const Data &plainText, Data &cipherText)
1124 {
1125     d->lastop = Private::Encrypt;
1126     const Data::Private *const pdp = plainText.impl();
1127     Data::Private *const cdp = cipherText.impl();
1128     return Error(d->lasterr = gpgme_op_encrypt(d->ctx, 0, (gpgme_encrypt_flags_t)0,
1129                               pdp ? pdp->data : 0, cdp ? cdp->data : 0));
1130 }
1131
1132 Error Context::startEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
1133 {
1134     d->lastop = Private::Encrypt;
1135     if (flags & NoEncryptTo) {
1136         return Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED));
1137     }
1138     const Data::Private *const pdp = plainText.impl();
1139     Data::Private *const cdp = cipherText.impl();
1140     gpgme_key_t *const keys = new gpgme_key_t[ recipients.size() + 1 ];
1141     gpgme_key_t *keys_it = keys;
1142     for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
1143         if (it->impl()) {
1144             *keys_it++ = it->impl();
1145         }
1146     }
1147     *keys_it++ = 0;
1148     d->lasterr = gpgme_op_encrypt_start(d->ctx, keys, encryptflags2encryptflags(flags),
1149                                         pdp ? pdp->data : 0, cdp ? cdp->data : 0);
1150     delete[] keys;
1151     return Error(d->lasterr);
1152 }
1153
1154 EncryptionResult Context::encryptionResult() const
1155 {
1156     if (d->lastop & Private::Encrypt) {
1157         return EncryptionResult(d->ctx, Error(d->lasterr));
1158     } else {
1159         return EncryptionResult();
1160     }
1161 }
1162
1163 std::pair<SigningResult, EncryptionResult> Context::signAndEncrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
1164 {
1165     d->lastop = Private::SignAndEncrypt;
1166     const Data::Private *const pdp = plainText.impl();
1167     Data::Private *const cdp = cipherText.impl();
1168     gpgme_key_t *const keys = new gpgme_key_t[ recipients.size() + 1 ];
1169     gpgme_key_t *keys_it = keys;
1170     for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
1171         if (it->impl()) {
1172             *keys_it++ = it->impl();
1173         }
1174     }
1175     *keys_it++ = 0;
1176     d->lasterr = gpgme_op_encrypt_sign(d->ctx, keys, encryptflags2encryptflags(flags),
1177                                        pdp ? pdp->data : 0, cdp ? cdp->data : 0);
1178     delete[] keys;
1179     return std::make_pair(SigningResult(d->ctx, Error(d->lasterr)),
1180                           EncryptionResult(d->ctx, Error(d->lasterr)));
1181 }
1182
1183 Error Context::startCombinedSigningAndEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
1184 {
1185     d->lastop = Private::SignAndEncrypt;
1186     const Data::Private *const pdp = plainText.impl();
1187     Data::Private *const cdp = cipherText.impl();
1188     gpgme_key_t *const keys = new gpgme_key_t[ recipients.size() + 1 ];
1189     gpgme_key_t *keys_it = keys;
1190     for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
1191         if (it->impl()) {
1192             *keys_it++ = it->impl();
1193         }
1194     }
1195     *keys_it++ = 0;
1196     d->lasterr = gpgme_op_encrypt_sign_start(d->ctx, keys, encryptflags2encryptflags(flags),
1197                  pdp ? pdp->data : 0, cdp ? cdp->data : 0);
1198     delete[] keys;
1199     return Error(d->lasterr);
1200 }
1201
1202 Error Context::createVFS(const char *containerFile, const std::vector< Key > &recipients)
1203 {
1204     d->lastop = Private::CreateVFS;
1205     gpgme_key_t *const keys = new gpgme_key_t[ recipients.size() + 1 ];
1206     gpgme_key_t *keys_it = keys;
1207     for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
1208         if (it->impl()) {
1209             *keys_it++ = it->impl();
1210         }
1211     }
1212     *keys_it++ = 0;
1213
1214     gpgme_error_t op_err;
1215     d->lasterr = gpgme_op_vfs_create(d->ctx, keys, containerFile, 0, &op_err);
1216     delete[] keys;
1217     Error error(d->lasterr);
1218     if (error) {
1219         return error;
1220     }
1221     return Error(d->lasterr = op_err);
1222 }
1223
1224 VfsMountResult Context::mountVFS(const char *containerFile, const char *mountDir)
1225 {
1226     d->lastop = Private::MountVFS;
1227     gpgme_error_t op_err;
1228     d->lasterr = gpgme_op_vfs_mount(d->ctx, containerFile, mountDir, 0, &op_err);
1229     return VfsMountResult(d->ctx, Error(d->lasterr), Error(op_err));
1230 }
1231
1232 Error Context::cancelPendingOperation()
1233 {
1234     return Error(gpgme_cancel_async(d->ctx));
1235 }
1236
1237 bool Context::poll()
1238 {
1239     gpgme_error_t e = GPG_ERR_NO_ERROR;
1240     const bool finished = gpgme_wait(d->ctx, &e, 0);
1241     if (finished) {
1242         d->lasterr = e;
1243     }
1244     return finished;
1245 }
1246
1247 Error Context::wait()
1248 {
1249     gpgme_error_t e = GPG_ERR_NO_ERROR;
1250     gpgme_wait(d->ctx, &e, 1);
1251     return Error(d->lasterr = e);
1252 }
1253
1254 Error Context::lastError() const
1255 {
1256     return Error(d->lasterr);
1257 }
1258
1259 Context::PinentryMode Context::pinentryMode() const
1260 {
1261     switch (gpgme_get_pinentry_mode (d->ctx)) {
1262         case GPGME_PINENTRY_MODE_ASK:
1263             return PinentryAsk;
1264         case GPGME_PINENTRY_MODE_CANCEL:
1265             return PinentryCancel;
1266         case GPGME_PINENTRY_MODE_ERROR:
1267             return PinentryError;
1268         case GPGME_PINENTRY_MODE_LOOPBACK:
1269             return PinentryLoopback;
1270         case GPGME_PINENTRY_MODE_DEFAULT:
1271         default:
1272             return PinentryDefault;
1273     }
1274 }
1275
1276 Error Context::setPinentryMode(PinentryMode which)
1277 {
1278     gpgme_pinentry_mode_t mode;
1279     switch (which) {
1280         case PinentryAsk:
1281             mode = GPGME_PINENTRY_MODE_ASK;
1282             break;
1283         case PinentryCancel:
1284             mode = GPGME_PINENTRY_MODE_CANCEL;
1285             break;
1286         case PinentryError:
1287             mode = GPGME_PINENTRY_MODE_ERROR;
1288             break;
1289         case PinentryLoopback:
1290             mode = GPGME_PINENTRY_MODE_LOOPBACK;
1291             break;
1292         case PinentryDefault:
1293         default:
1294             mode = GPGME_PINENTRY_MODE_DEFAULT;
1295     }
1296     return Error(d->lasterr = gpgme_set_pinentry_mode(d->ctx, mode));
1297 }
1298
1299 std::ostream &operator<<(std::ostream &os, Protocol proto)
1300 {
1301     os << "GpgME::Protocol(";
1302     switch (proto) {
1303     case OpenPGP:
1304         os << "OpenPGP";
1305         break;
1306     case CMS:
1307         os << "CMS";
1308         break;
1309     default:
1310     case UnknownProtocol:
1311         os << "UnknownProtocol";
1312         break;
1313     }
1314     return os << ')';
1315 }
1316
1317 std::ostream &operator<<(std::ostream &os, Engine eng)
1318 {
1319     os << "GpgME::Engine(";
1320     switch (eng) {
1321     case GpgEngine:
1322         os << "GpgEngine";
1323         break;
1324     case GpgSMEngine:
1325         os << "GpgSMEngine";
1326         break;
1327     case GpgConfEngine:
1328         os << "GpgConfEngine";
1329         break;
1330     case AssuanEngine:
1331         os << "AssuanEngine";
1332         break;
1333     default:
1334     case UnknownEngine:
1335         os << "UnknownEngine";
1336         break;
1337     }
1338     return os << ')';
1339 }
1340
1341 std::ostream &operator<<(std::ostream &os, Context::CertificateInclusion incl)
1342 {
1343     os << "GpgME::Context::CertificateInclusion(" << static_cast<int>(incl);
1344     switch (incl) {
1345     case Context::DefaultCertificates:
1346         os << "(DefaultCertificates)";
1347         break;
1348     case Context::AllCertificatesExceptRoot:
1349         os << "(AllCertificatesExceptRoot)";
1350         break;
1351     case Context::AllCertificates:
1352         os << "(AllCertificates)";
1353         break;
1354     case Context::NoCertificates:
1355         os << "(NoCertificates)";
1356         break;
1357     case Context::OnlySenderCertificate:
1358         os << "(OnlySenderCertificate)";
1359         break;
1360     }
1361     return os << ')';
1362 }
1363
1364 std::ostream &operator<<(std::ostream &os, KeyListMode mode)
1365 {
1366     os << "GpgME::KeyListMode(";
1367 #define CHECK( x ) if ( !(mode & (x)) ) {} else do { os << #x " "; } while (0)
1368     CHECK(Local);
1369     CHECK(Extern);
1370     CHECK(Signatures);
1371     CHECK(Validate);
1372     CHECK(Ephemeral);
1373 #undef CHECK
1374     return os << ')';
1375 }
1376
1377 std::ostream &operator<<(std::ostream &os, SignatureMode mode)
1378 {
1379     os << "GpgME::SignatureMode(";
1380     switch (mode) {
1381 #define CHECK( x ) case x: os << #x; break
1382         CHECK(NormalSignatureMode);
1383         CHECK(Detached);
1384         CHECK(Clearsigned);
1385 #undef CHECK
1386     default:
1387         os << "???" "(" << static_cast<int>(mode) << ')';
1388         break;
1389     }
1390     return os << ')';
1391 }
1392
1393 std::ostream &operator<<(std::ostream &os, Context::EncryptionFlags flags)
1394 {
1395     os << "GpgME::Context::EncryptionFlags(";
1396 #define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
1397     CHECK(AlwaysTrust);
1398 #undef CHECK
1399     return os << ')';
1400 }
1401
1402 std::ostream &operator<<(std::ostream &os, Context::AuditLogFlags flags)
1403 {
1404     os << "GpgME::Context::AuditLogFlags(";
1405 #define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
1406     CHECK(HtmlAuditLog);
1407     CHECK(AuditLogWithHelp);
1408 #undef CHECK
1409     return os << ')';
1410 }
1411
1412 } // namespace GpgME
1413
1414 GpgME::Error GpgME::setDefaultLocale(int cat, const char *val)
1415 {
1416     return Error(gpgme_set_locale(0, cat, val));
1417 }
1418
1419 GpgME::EngineInfo GpgME::engineInfo(GpgME::Protocol proto)
1420 {
1421     gpgme_engine_info_t ei = 0;
1422     if (gpgme_get_engine_info(&ei)) {
1423         return EngineInfo();
1424     }
1425
1426     const gpgme_protocol_t p = proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP ;
1427
1428     for (gpgme_engine_info_t i = ei ; i ; i = i->next) {
1429         if (i->protocol == p) {
1430             return EngineInfo(i);
1431         }
1432     }
1433
1434     return EngineInfo();
1435 }
1436
1437 GpgME::Error GpgME::checkEngine(GpgME::Protocol proto)
1438 {
1439     const gpgme_protocol_t p = proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP ;
1440
1441     return Error(gpgme_engine_check_version(p));
1442 }
1443
1444 static const gpgme_protocol_t UNKNOWN_PROTOCOL = static_cast<gpgme_protocol_t>(255);
1445
1446 static gpgme_protocol_t engine2protocol(const GpgME::Engine engine)
1447 {
1448     switch (engine) {
1449     case GpgME::GpgEngine:   return GPGME_PROTOCOL_OpenPGP;
1450     case GpgME::GpgSMEngine: return GPGME_PROTOCOL_CMS;
1451     case GpgME::GpgConfEngine:
1452         return GPGME_PROTOCOL_GPGCONF;
1453     case GpgME::AssuanEngine:
1454         return GPGME_PROTOCOL_ASSUAN;
1455     case GpgME::G13Engine:
1456         return GPGME_PROTOCOL_G13;
1457     case GpgME::UnknownEngine:
1458         ;
1459     }
1460     return UNKNOWN_PROTOCOL;
1461 }
1462
1463 GpgME::EngineInfo GpgME::engineInfo(GpgME::Engine engine)
1464 {
1465     gpgme_engine_info_t ei = 0;
1466     if (gpgme_get_engine_info(&ei)) {
1467         return EngineInfo();
1468     }
1469
1470     const gpgme_protocol_t p = engine2protocol(engine);
1471
1472     for (gpgme_engine_info_t i = ei ; i ; i = i->next) {
1473         if (i->protocol == p) {
1474             return EngineInfo(i);
1475         }
1476     }
1477
1478     return EngineInfo();
1479 }
1480
1481 GpgME::Error GpgME::checkEngine(GpgME::Engine engine)
1482 {
1483     const gpgme_protocol_t p = engine2protocol(engine);
1484
1485     return Error(gpgme_engine_check_version(p));
1486 }
1487
1488 static const unsigned long supported_features = 0
1489         | GpgME::ValidatingKeylistModeFeature
1490         | GpgME::CancelOperationFeature
1491         | GpgME::WrongKeyUsageFeature
1492         | GpgME::DefaultCertificateInclusionFeature
1493         | GpgME::GetSetEngineInfoFeature
1494         | GpgME::ClearAddGetSignatureNotationsFeature
1495         | GpgME::SetDataFileNameFeeature
1496         | GpgME::SignatureNotationsKeylistModeFeature
1497         | GpgME::KeySignatureNotationsFeature
1498         | GpgME::KeyIsQualifiedFeature
1499         | GpgME::SignatureNotationsCriticalFlagFeature
1500         | GpgME::SignatureNotationsFlagsFeature
1501         | GpgME::SignatureNotationsHumanReadableFlagFeature
1502         | GpgME::SubkeyIsQualifiedFeature
1503         | GpgME::EngineInfoHomeDirFeature
1504         | GpgME::DecryptionResultFileNameFeature
1505         | GpgME::DecryptionResultRecipientsFeature
1506         | GpgME::VerificationResultFileNameFeature
1507         | GpgME::SignaturePkaFieldsFeature
1508         | GpgME::SignatureAlgorithmFieldsFeature
1509         | GpgME::FdPointerFeature
1510         | GpgME::AuditLogFeature
1511         | GpgME::GpgConfEngineFeature
1512         | GpgME::CancelOperationAsyncFeature
1513         | GpgME::NoEncryptToEncryptionFlagFeature
1514         | GpgME::CardKeyFeature
1515         | GpgME::AssuanEngineFeature
1516         | GpgME::EphemeralKeylistModeFeature
1517         | GpgME::ImportFromKeyserverFeature
1518         | GpgME::G13VFSFeature
1519         | GpgME::PasswdFeature
1520         ;
1521
1522 static const unsigned long supported_features2 = 0
1523         | GpgME::BinaryAndFineGrainedIdentify
1524         ;
1525
1526 bool GpgME::hasFeature(unsigned long features)
1527 {
1528     return features == (features & supported_features);
1529 }
1530
1531 bool GpgME::hasFeature(unsigned long features, unsigned long features2)
1532 {
1533     return features  == (features  & supported_features)
1534            && features2 == (features2 & supported_features2)
1535            ;
1536 }