LCOV - code coverage report
Current view: top level - lang/cpp/src - context.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 185 817 22.6 %
Date: 2016-11-29 15:07:43 Functions: 48 160 30.0 %

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

Generated by: LCOV version 1.11