LCOV - code coverage report
Current view: top level - lang/cpp/src - context.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 187 801 23.3 %
Date: 2016-09-12 13:07:23 Functions: 47 155 30.3 %

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

Generated by: LCOV version 1.11