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