Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F26446700
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
73 KB
Subscribers
None
View Options
diff --git a/src/context.cpp b/src/context.cpp
index 00f397b4..43a73b1f 100644
--- a/src/context.cpp
+++ b/src/context.cpp
@@ -1,1639 +1,1641 @@
/*
context.cpp - wraps a gpgme key context
Copyright (C) 2003, 2007 Klarälvdalens Datakonsult AB
This file is part of GPGME++.
GPGME++ is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
GPGME++ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with GPGME++; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <context.h>
#include <eventloopinteractor.h>
#include <trustitem.h>
#include <keylistresult.h>
#include <keygenerationresult.h>
#include <importresult.h>
#include <decryptionresult.h>
#include <verificationresult.h>
#include <signingresult.h>
#include <encryptionresult.h>
#include <engineinfo.h>
#include <editinteractor.h>
#include <vfsmountresult.h>
#include <interfaces/assuantransaction.h>
#include <defaultassuantransaction.h>
#include "callbacks.h"
#include "data_p.h"
#include "context_p.h"
#include "util.h"
#include "tofuinfo.h"
#include <gpgme.h>
#include <istream>
#ifndef NDEBUG
#include <iostream>
using std::cerr;
using std::endl;
#endif
#include <cassert>
namespace GpgME
{
static inline unsigned int xtoi_1(const char *str)
{
const unsigned int ch = *str;
const unsigned int result =
ch <= '9' ? ch - '0' :
ch <= 'F' ? ch - 'A' + 10 :
/* else */ ch - 'a' + 10 ;
return result < 16 ? result : 0 ;
}
static inline int xtoi_2(const char *str)
{
return xtoi_1(str) * 16U + xtoi_1(str + 1);
}
static void percent_unescape(std::string &s, bool plus2space)
{
std::string::iterator src = s.begin(), dest = s.begin(), end = s.end();
while (src != end) {
if (*src == '%' && end - src > 2) {
*dest++ = xtoi_2(&*++src);
src += 2;
} else if (*src == '+' && plus2space) {
*dest++ = ' ';
++src;
} else {
*dest++ = *src++;
}
}
s.erase(dest, end);
}
void initializeLibrary()
{
gpgme_check_version(0);
}
Error initializeLibrary(int)
{
if (gpgme_check_version(GPGME_VERSION)) {
return Error();
} else {
return Error::fromCode(GPG_ERR_USER_1);
}
}
static void format_error(gpgme_error_t err, std::string &str)
{
char buffer[ 1024 ];
gpgme_strerror_r(err, buffer, sizeof buffer);
buffer[ sizeof buffer - 1 ] = '\0';
str = buffer;
}
const char *Error::source() const
{
return gpgme_strsource((gpgme_error_t)mErr);
}
const char *Error::asString() const
{
if (mMessage.empty()) {
format_error(static_cast<gpgme_error_t>(mErr), mMessage);
}
return mMessage.c_str();
}
int Error::code() const
{
return gpgme_err_code(mErr);
}
int Error::sourceID() const
{
return gpgme_err_source(mErr);
}
bool Error::isCanceled() const
{
return code() == GPG_ERR_CANCELED;
}
int Error::toErrno() const
{
//#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
return gpgme_err_code_to_errno(static_cast<gpgme_err_code_t>(code()));
//#else
// return gpg_err_code_to_errno( static_cast<gpg_err_code_t>( code() ) );
//#endif
}
// static
bool Error::hasSystemError()
{
return gpgme_err_code_from_syserror() == GPG_ERR_MISSING_ERRNO ;
}
// static
void Error::setSystemError(gpg_err_code_t err)
{
setErrno(gpgme_err_code_to_errno(err));
}
// static
void Error::setErrno(int err)
{
gpgme_err_set_errno(err);
}
// static
Error Error::fromSystemError(unsigned int src)
{
return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), gpgme_err_code_from_syserror()));
}
// static
Error Error::fromErrno(int err, unsigned int src)
{
return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), gpgme_err_code_from_errno(err)));
}
// static
Error Error::fromCode(unsigned int err, unsigned int src)
{
return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), static_cast<gpgme_err_code_t>(err)));
}
std::ostream &operator<<(std::ostream &os, const Error &err)
{
return os << "GpgME::Error(" << err.encodedError() << " (" << err.asString() << "))";
}
Context::Context(gpgme_ctx_t ctx) : d(new Private(ctx))
{
}
Context::~Context()
{
delete d;
}
Context *Context::createForProtocol(Protocol proto)
{
gpgme_ctx_t ctx = 0;
if (gpgme_new(&ctx) != 0) {
return 0;
}
switch (proto) {
case OpenPGP:
if (gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP) != 0) {
gpgme_release(ctx);
return 0;
}
break;
case CMS:
if (gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS) != 0) {
gpgme_release(ctx);
return 0;
}
break;
default:
return 0;
}
return new Context(ctx);
}
std::unique_ptr<Context> Context::createForEngine(Engine eng, Error *error)
{
gpgme_ctx_t ctx = 0;
if (const gpgme_error_t err = gpgme_new(&ctx)) {
if (error) {
*error = Error(err);
}
return std::unique_ptr<Context>();
}
switch (eng) {
case AssuanEngine:
if (const gpgme_error_t err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_ASSUAN)) {
gpgme_release(ctx);
if (error) {
*error = Error(err);
}
return std::unique_ptr<Context>();
}
break;
case G13Engine:
if (const gpgme_error_t err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_G13)) {
gpgme_release(ctx);
if (error) {
*error = Error(err);
}
return std::unique_ptr<Context>();
}
break;
case SpawnEngine:
if (const gpgme_error_t err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_SPAWN)) {
gpgme_release(ctx);
if (error) {
*error = Error(err);
}
return std::unique_ptr<Context>();
}
break;
default:
if (error) {
*error = Error::fromCode(GPG_ERR_INV_ARG);
}
return std::unique_ptr<Context>();
}
if (error) {
*error = Error();
}
return std::unique_ptr<Context>(new Context(ctx));
}
//
//
// Context::Private
//
//
Context::Private::Private(gpgme_ctx_t c)
: ctx(c),
iocbs(0),
lastop(None),
lasterr(GPG_ERR_NO_ERROR),
lastAssuanInquireData(Data::null),
lastAssuanTransaction(),
lastEditInteractor(),
lastCardEditInteractor()
{
}
Context::Private::~Private()
{
if (ctx) {
gpgme_release(ctx);
}
ctx = 0;
delete iocbs;
}
//
//
// Context attributes:
//
//
Protocol Context::protocol() const
{
gpgme_protocol_t p = gpgme_get_protocol(d->ctx);
switch (p) {
case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
case GPGME_PROTOCOL_CMS: return CMS;
default: return UnknownProtocol;
}
}
void Context::setArmor(bool useArmor)
{
gpgme_set_armor(d->ctx, int(useArmor));
}
bool Context::armor() const
{
return gpgme_get_armor(d->ctx);
}
void Context::setTextMode(bool useTextMode)
{
gpgme_set_textmode(d->ctx, int(useTextMode));
}
bool Context::textMode() const
{
return gpgme_get_textmode(d->ctx);
}
void Context::setOffline(bool useOfflineMode)
{
gpgme_set_offline(d->ctx, int(useOfflineMode));
}
bool Context::offline() const
{
return gpgme_get_offline(d->ctx);
}
void Context::setIncludeCertificates(int which)
{
if (which == DefaultCertificates) {
which = GPGME_INCLUDE_CERTS_DEFAULT;
}
gpgme_set_include_certs(d->ctx, which);
}
int Context::includeCertificates() const
{
return gpgme_get_include_certs(d->ctx);
}
void Context::setKeyListMode(unsigned int mode)
{
gpgme_set_keylist_mode(d->ctx, add_to_gpgme_keylist_mode_t(0, mode));
}
void Context::addKeyListMode(unsigned int mode)
{
const unsigned int cur = gpgme_get_keylist_mode(d->ctx);
gpgme_set_keylist_mode(d->ctx, add_to_gpgme_keylist_mode_t(cur, mode));
}
unsigned int Context::keyListMode() const
{
return convert_from_gpgme_keylist_mode_t(gpgme_get_keylist_mode(d->ctx));
}
void Context::setProgressProvider(ProgressProvider *provider)
{
gpgme_set_progress_cb(d->ctx, provider ? &progress_callback : 0, provider);
}
ProgressProvider *Context::progressProvider() const
{
void *pp = 0;
gpgme_progress_cb_t pcb = &progress_callback;
gpgme_get_progress_cb(d->ctx, &pcb, &pp);
return static_cast<ProgressProvider *>(pp);
}
void Context::setPassphraseProvider(PassphraseProvider *provider)
{
gpgme_set_passphrase_cb(d->ctx, provider ? &passphrase_callback : 0, provider);
}
PassphraseProvider *Context::passphraseProvider() const
{
void *pp = 0;
gpgme_passphrase_cb_t pcb = &passphrase_callback;
gpgme_get_passphrase_cb(d->ctx, &pcb, &pp);
return static_cast<PassphraseProvider *>(pp);
}
void Context::setManagedByEventLoopInteractor(bool manage)
{
if (!EventLoopInteractor::instance()) {
#ifndef NDEBUG
cerr << "Context::setManagedByEventLoopInteractor(): "
"You must create an instance of EventLoopInteractor "
"before using anything that needs one." << endl;
#endif
return;
}
if (manage) {
EventLoopInteractor::instance()->manage(this);
} else {
EventLoopInteractor::instance()->unmanage(this);
}
}
bool Context::managedByEventLoopInteractor() const
{
return d->iocbs != 0;
}
void Context::installIOCallbacks(gpgme_io_cbs *iocbs)
{
if (!iocbs) {
uninstallIOCallbacks();
return;
}
gpgme_set_io_cbs(d->ctx, iocbs);
delete d->iocbs; d->iocbs = iocbs;
}
void Context::uninstallIOCallbacks()
{
static gpgme_io_cbs noiocbs = { 0, 0, 0, 0, 0 };
// io.add == 0 means disable io callbacks:
gpgme_set_io_cbs(d->ctx, &noiocbs);
delete d->iocbs; d->iocbs = 0;
}
Error Context::setLocale(int cat, const char *val)
{
return Error(d->lasterr = gpgme_set_locale(d->ctx, cat, val));
}
EngineInfo Context::engineInfo() const
{
return EngineInfo(gpgme_ctx_get_engine_info(d->ctx));
}
Error Context::setEngineFileName(const char *filename)
{
const char *const home_dir = engineInfo().homeDirectory();
return Error(gpgme_ctx_set_engine_info(d->ctx, gpgme_get_protocol(d->ctx), filename, home_dir));
}
Error Context::setEngineHomeDirectory(const char *home_dir)
{
const char *const filename = engineInfo().fileName();
return Error(gpgme_ctx_set_engine_info(d->ctx, gpgme_get_protocol(d->ctx), filename, home_dir));
}
//
//
// Key Management
//
//
Error Context::startKeyListing(const char *pattern, bool secretOnly)
{
d->lastop = Private::KeyList;
return Error(d->lasterr = gpgme_op_keylist_start(d->ctx, pattern, int(secretOnly)));
}
Error Context::startKeyListing(const char *patterns[], bool secretOnly)
{
d->lastop = Private::KeyList;
#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
if (!patterns || !patterns[0] || !patterns[1]) {
// max. one pattern -> use the non-ext version
return startKeyListing(patterns ? patterns[0] : 0, secretOnly);
}
#endif
return Error(d->lasterr = gpgme_op_keylist_ext_start(d->ctx, patterns, int(secretOnly), 0));
}
Key Context::nextKey(GpgME::Error &e)
{
d->lastop = Private::KeyList;
gpgme_key_t key;
e = Error(d->lasterr = gpgme_op_keylist_next(d->ctx, &key));
return Key(key, false);
}
KeyListResult Context::endKeyListing()
{
d->lasterr = gpgme_op_keylist_end(d->ctx);
return keyListResult();
}
KeyListResult Context::keyListResult() const
{
return KeyListResult(d->ctx, Error(d->lasterr));
}
Key Context::key(const char *fingerprint, GpgME::Error &e , bool secret /*, bool forceUpdate*/)
{
d->lastop = Private::KeyList;
gpgme_key_t key;
e = Error(d->lasterr = gpgme_get_key(d->ctx, fingerprint, &key, int(secret)/*, int( forceUpdate )*/));
return Key(key, false);
}
KeyGenerationResult Context::generateKey(const char *parameters, Data &pubKey)
{
d->lastop = Private::KeyGen;
Data::Private *const dp = pubKey.impl();
d->lasterr = gpgme_op_genkey(d->ctx, parameters, dp ? dp->data : 0, 0);
return KeyGenerationResult(d->ctx, Error(d->lasterr));
}
Error Context::startKeyGeneration(const char *parameters, Data &pubKey)
{
d->lastop = Private::KeyGen;
Data::Private *const dp = pubKey.impl();
return Error(d->lasterr = gpgme_op_genkey_start(d->ctx, parameters, dp ? dp->data : 0, 0));
}
KeyGenerationResult Context::keyGenerationResult() const
{
if (d->lastop & Private::KeyGen) {
return KeyGenerationResult(d->ctx, Error(d->lasterr));
} else {
return KeyGenerationResult();
}
}
Error Context::exportPublicKeys(const char *pattern, Data &keyData)
{
d->lastop = Private::Export;
Data::Private *const dp = keyData.impl();
return Error(d->lasterr = gpgme_op_export(d->ctx, pattern, 0, dp ? dp->data : 0));
}
Error Context::exportPublicKeys(const char *patterns[], Data &keyData)
{
d->lastop = Private::Export;
#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
if (!patterns || !patterns[0] || !patterns[1]) {
// max. one pattern -> use the non-ext version
return exportPublicKeys(patterns ? patterns[0] : 0, keyData);
}
#endif
Data::Private *const dp = keyData.impl();
return Error(d->lasterr = gpgme_op_export_ext(d->ctx, patterns, 0, dp ? dp->data : 0));
}
Error Context::startPublicKeyExport(const char *pattern, Data &keyData)
{
d->lastop = Private::Export;
Data::Private *const dp = keyData.impl();
return Error(d->lasterr = gpgme_op_export_start(d->ctx, pattern, 0, dp ? dp->data : 0));
}
Error Context::startPublicKeyExport(const char *patterns[], Data &keyData)
{
d->lastop = Private::Export;
#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
if (!patterns || !patterns[0] || !patterns[1]) {
// max. one pattern -> use the non-ext version
return startPublicKeyExport(patterns ? patterns[0] : 0, keyData);
}
#endif
Data::Private *const dp = keyData.impl();
return Error(d->lasterr = gpgme_op_export_ext_start(d->ctx, patterns, 0, dp ? dp->data : 0));
}
ImportResult Context::importKeys(const Data &data)
{
d->lastop = Private::Import;
const Data::Private *const dp = data.impl();
d->lasterr = gpgme_op_import(d->ctx, dp ? dp->data : 0);
return ImportResult(d->ctx, Error(d->lasterr));
}
ImportResult Context::importKeys(const std::vector<Key> &kk)
{
d->lastop = Private::Import;
d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED);
bool shouldHaveResult = false;
gpgme_key_t * const keys = new gpgme_key_t[ kk.size() + 1 ];
gpgme_key_t *keys_it = &keys[0];
for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
if (it->impl()) {
*keys_it++ = it->impl();
}
}
*keys_it++ = 0;
d->lasterr = gpgme_op_import_keys(d->ctx, keys);
shouldHaveResult = true;
if ((gpgme_err_code(d->lasterr) == GPG_ERR_NOT_IMPLEMENTED ||
gpgme_err_code(d->lasterr) == GPG_ERR_NOT_SUPPORTED) &&
protocol() == CMS) {
// ok, try the workaround (export+import):
std::vector<const char *> fprs;
for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
if (const char *fpr = it->primaryFingerprint()) {
if (*fpr) {
fprs.push_back(fpr);
}
} else if (const char *keyid = it->keyID()) {
if (*keyid) {
fprs.push_back(keyid);
}
}
}
fprs.push_back(0);
Data data;
Data::Private *const dp = data.impl();
const gpgme_keylist_mode_t oldMode = gpgme_get_keylist_mode(d->ctx);
gpgme_set_keylist_mode(d->ctx, GPGME_KEYLIST_MODE_EXTERN);
d->lasterr = gpgme_op_export_ext(d->ctx, &fprs[0], 0, dp ? dp->data : 0);
gpgme_set_keylist_mode(d->ctx, oldMode);
if (!d->lasterr) {
data.seek(0, SEEK_SET);
d->lasterr = gpgme_op_import(d->ctx, dp ? dp->data : 0);
shouldHaveResult = true;
}
}
delete[] keys;
if (shouldHaveResult) {
return ImportResult(d->ctx, Error(d->lasterr));
} else {
return ImportResult(Error(d->lasterr));
}
}
Error Context::startKeyImport(const Data &data)
{
d->lastop = Private::Import;
const Data::Private *const dp = data.impl();
return Error(d->lasterr = gpgme_op_import_start(d->ctx, dp ? dp->data : 0));
}
Error Context::startKeyImport(const std::vector<Key> &kk)
{
d->lastop = Private::Import;
gpgme_key_t * const keys = new gpgme_key_t[ kk.size() + 1 ];
gpgme_key_t *keys_it = &keys[0];
for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
if (it->impl()) {
*keys_it++ = it->impl();
}
}
*keys_it++ = 0;
Error err = Error(d->lasterr = gpgme_op_import_keys_start(d->ctx, keys));
delete[] keys;
return err;
}
ImportResult Context::importResult() const
{
if (d->lastop & Private::Import) {
return ImportResult(d->ctx, Error(d->lasterr));
} else {
return ImportResult();
}
}
Error Context::deleteKey(const Key &key, bool allowSecretKeyDeletion)
{
d->lastop = Private::Delete;
return Error(d->lasterr = gpgme_op_delete(d->ctx, key.impl(), int(allowSecretKeyDeletion)));
}
Error Context::startKeyDeletion(const Key &key, bool allowSecretKeyDeletion)
{
d->lastop = Private::Delete;
return Error(d->lasterr = gpgme_op_delete_start(d->ctx, key.impl(), int(allowSecretKeyDeletion)));
}
Error Context::passwd(const Key &key)
{
d->lastop = Private::Passwd;
return Error(d->lasterr = gpgme_op_passwd(d->ctx, key.impl(), 0U));
}
Error Context::startPasswd(const Key &key)
{
d->lastop = Private::Passwd;
return Error(d->lasterr = gpgme_op_passwd_start(d->ctx, key.impl(), 0U));
}
#pragma GCC push_diagnostics
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
Error Context::edit(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
{
d->lastop = Private::Edit;
d->lastEditInteractor = std::move(func);
Data::Private *const dp = data.impl();
return Error(d->lasterr = gpgme_op_edit(d->ctx, key.impl(),
d->lastEditInteractor.get() ? edit_interactor_callback : 0,
d->lastEditInteractor.get() ? d->lastEditInteractor->d : 0,
dp ? dp->data : 0));
}
Error Context::startEditing(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
{
d->lastop = Private::Edit;
d->lastEditInteractor = std::move(func);
Data::Private *const dp = data.impl();
return Error(d->lasterr = gpgme_op_edit_start(d->ctx, key.impl(),
d->lastEditInteractor.get() ? edit_interactor_callback : 0,
d->lastEditInteractor.get() ? d->lastEditInteractor->d : 0,
dp ? dp->data : 0));
}
EditInteractor *Context::lastEditInteractor() const
{
return d->lastEditInteractor.get();
}
std::unique_ptr<EditInteractor> Context::takeLastEditInteractor()
{
return std::move(d->lastEditInteractor);
}
Error Context::cardEdit(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
{
d->lastop = Private::CardEdit;
d->lastCardEditInteractor = std::move(func);
Data::Private *const dp = data.impl();
return Error(d->lasterr = gpgme_op_card_edit(d->ctx, key.impl(),
d->lastCardEditInteractor.get() ? edit_interactor_callback : 0,
d->lastCardEditInteractor.get() ? d->lastCardEditInteractor->d : 0,
dp ? dp->data : 0));
}
Error Context::startCardEditing(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
{
d->lastop = Private::CardEdit;
d->lastCardEditInteractor = std::move(func);
Data::Private *const dp = data.impl();
return Error(d->lasterr = gpgme_op_card_edit_start(d->ctx, key.impl(),
d->lastCardEditInteractor.get() ? edit_interactor_callback : 0,
d->lastCardEditInteractor.get() ? d->lastCardEditInteractor->d : 0,
dp ? dp->data : 0));
}
#pragma GCC pop_diagnostics
EditInteractor *Context::lastCardEditInteractor() const
{
return d->lastCardEditInteractor.get();
}
std::unique_ptr<EditInteractor> Context::takeLastCardEditInteractor()
{
return std::move(d->lastCardEditInteractor);
}
Error Context::startTrustItemListing(const char *pattern, int maxLevel)
{
d->lastop = Private::TrustList;
return Error(d->lasterr = gpgme_op_trustlist_start(d->ctx, pattern, maxLevel));
}
TrustItem Context::nextTrustItem(Error &e)
{
gpgme_trust_item_t ti = 0;
e = Error(d->lasterr = gpgme_op_trustlist_next(d->ctx, &ti));
return TrustItem(ti);
}
Error Context::endTrustItemListing()
{
return Error(d->lasterr = gpgme_op_trustlist_end(d->ctx));
}
static gpgme_error_t assuan_transaction_data_callback(void *opaque, const void *data, size_t datalen)
{
assert(opaque);
AssuanTransaction *t = static_cast<AssuanTransaction *>(opaque);
return t->data(static_cast<const char *>(data), datalen).encodedError();
}
static gpgme_error_t assuan_transaction_inquire_callback(void *opaque, const char *name, const char *args, gpgme_data_t *r_data)
{
assert(opaque);
Context::Private *p = static_cast<Context::Private *>(opaque);
AssuanTransaction *t = p->lastAssuanTransaction.get();
assert(t);
Error err;
if (name) {
p->lastAssuanInquireData = t->inquire(name, args, err);
} else {
p->lastAssuanInquireData = Data::null;
}
if (!p->lastAssuanInquireData.isNull()) {
*r_data = p->lastAssuanInquireData.impl()->data;
}
return err.encodedError();
}
static gpgme_error_t assuan_transaction_status_callback(void *opaque, const char *status, const char *args)
{
assert(opaque);
AssuanTransaction *t = static_cast<AssuanTransaction *>(opaque);
std::string a = args;
percent_unescape(a, true); // ### why doesn't gpgme do this??
return t->status(status, a.c_str()).encodedError();
}
Error Context::assuanTransact(const char *command)
{
return assuanTransact(command, std::unique_ptr<AssuanTransaction>(new DefaultAssuanTransaction));
}
Error Context::assuanTransact(const char *command, std::unique_ptr<AssuanTransaction> transaction)
{
gpgme_error_t err, operr;
d->lastop = Private::AssuanTransact;
d->lastAssuanTransaction = std::move(transaction);
if (!d->lastAssuanTransaction.get()) {
return Error(d->lasterr = make_error(GPG_ERR_INV_ARG));
}
err = gpgme_op_assuan_transact_ext
(d->ctx,
command,
assuan_transaction_data_callback,
d->lastAssuanTransaction.get(),
assuan_transaction_inquire_callback,
d,
assuan_transaction_status_callback,
d->lastAssuanTransaction.get(),
&operr);
if (!err)
err = operr;
d->lasterr = err;
return Error(d->lasterr);
}
Error Context::startAssuanTransaction(const char *command)
{
return startAssuanTransaction(command, std::unique_ptr<AssuanTransaction>(new DefaultAssuanTransaction));
}
Error Context::startAssuanTransaction(const char *command, std::unique_ptr<AssuanTransaction> transaction)
{
gpgme_error_t err;
d->lastop = Private::AssuanTransact;
d->lastAssuanTransaction = std::move(transaction);
if (!d->lastAssuanTransaction.get()) {
return Error(d->lasterr = make_error(GPG_ERR_INV_ARG));
}
err = gpgme_op_assuan_transact_start
(d->ctx,
command,
assuan_transaction_data_callback,
d->lastAssuanTransaction.get(),
assuan_transaction_inquire_callback,
d,
assuan_transaction_status_callback,
d->lastAssuanTransaction.get());
d->lasterr = err;
return Error(d->lasterr);
}
AssuanTransaction *Context::lastAssuanTransaction() const
{
return d->lastAssuanTransaction.get();
}
std::unique_ptr<AssuanTransaction> Context::takeLastAssuanTransaction()
{
return std::move(d->lastAssuanTransaction);
}
DecryptionResult Context::decrypt(const Data &cipherText, Data &plainText)
{
d->lastop = Private::Decrypt;
const Data::Private *const cdp = cipherText.impl();
Data::Private *const pdp = plainText.impl();
d->lasterr = gpgme_op_decrypt(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0);
return DecryptionResult(d->ctx, Error(d->lasterr));
}
Error Context::startDecryption(const Data &cipherText, Data &plainText)
{
d->lastop = Private::Decrypt;
const Data::Private *const cdp = cipherText.impl();
Data::Private *const pdp = plainText.impl();
return Error(d->lasterr = gpgme_op_decrypt_start(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0));
}
DecryptionResult Context::decryptionResult() const
{
if (d->lastop & Private::Decrypt) {
return DecryptionResult(d->ctx, Error(d->lasterr));
} else {
return DecryptionResult();
}
}
VerificationResult Context::verifyDetachedSignature(const Data &signature, const Data &signedText)
{
d->lastop = Private::Verify;
const Data::Private *const sdp = signature.impl();
const Data::Private *const tdp = signedText.impl();
d->lasterr = gpgme_op_verify(d->ctx, sdp ? sdp->data : 0, tdp ? tdp->data : 0, 0);
return VerificationResult(d->ctx, Error(d->lasterr));
}
VerificationResult Context::verifyOpaqueSignature(const Data &signedData, Data &plainText)
{
d->lastop = Private::Verify;
const Data::Private *const sdp = signedData.impl();
Data::Private *const pdp = plainText.impl();
d->lasterr = gpgme_op_verify(d->ctx, sdp ? sdp->data : 0, 0, pdp ? pdp->data : 0);
return VerificationResult(d->ctx, Error(d->lasterr));
}
Error Context::startDetachedSignatureVerification(const Data &signature, const Data &signedText)
{
d->lastop = Private::Verify;
const Data::Private *const sdp = signature.impl();
const Data::Private *const tdp = signedText.impl();
return Error(d->lasterr = gpgme_op_verify_start(d->ctx, sdp ? sdp->data : 0, tdp ? tdp->data : 0, 0));
}
Error Context::startOpaqueSignatureVerification(const Data &signedData, Data &plainText)
{
d->lastop = Private::Verify;
const Data::Private *const sdp = signedData.impl();
Data::Private *const pdp = plainText.impl();
return Error(d->lasterr = gpgme_op_verify_start(d->ctx, sdp ? sdp->data : 0, 0, pdp ? pdp->data : 0));
}
VerificationResult Context::verificationResult() const
{
if (d->lastop & Private::Verify) {
return VerificationResult(d->ctx, Error(d->lasterr));
} else {
return VerificationResult();
}
}
std::pair<DecryptionResult, VerificationResult> Context::decryptAndVerify(const Data &cipherText, Data &plainText)
{
d->lastop = Private::DecryptAndVerify;
const Data::Private *const cdp = cipherText.impl();
Data::Private *const pdp = plainText.impl();
d->lasterr = gpgme_op_decrypt_verify(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0);
return std::make_pair(DecryptionResult(d->ctx, Error(d->lasterr)),
VerificationResult(d->ctx, Error(d->lasterr)));
}
Error Context::startCombinedDecryptionAndVerification(const Data &cipherText, Data &plainText)
{
d->lastop = Private::DecryptAndVerify;
const Data::Private *const cdp = cipherText.impl();
Data::Private *const pdp = plainText.impl();
return Error(d->lasterr = gpgme_op_decrypt_verify_start(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0));
}
unsigned int to_auditlog_flags(unsigned int flags)
{
unsigned int result = 0;
if (flags & Context::HtmlAuditLog) {
result |= GPGME_AUDITLOG_HTML;
}
if (flags & Context::AuditLogWithHelp) {
result |= GPGME_AUDITLOG_WITH_HELP;
}
return result;
}
Error Context::startGetAuditLog(Data &output, unsigned int flags)
{
d->lastop = Private::GetAuditLog;
Data::Private *const odp = output.impl();
return Error(d->lasterr = gpgme_op_getauditlog_start(d->ctx, odp ? odp->data : 0, to_auditlog_flags(flags)));
}
Error Context::getAuditLog(Data &output, unsigned int flags)
{
d->lastop = Private::GetAuditLog;
Data::Private *const odp = output.impl();
return Error(d->lasterr = gpgme_op_getauditlog(d->ctx, odp ? odp->data : 0, to_auditlog_flags(flags)));
}
void Context::clearSigningKeys()
{
gpgme_signers_clear(d->ctx);
}
Error Context::addSigningKey(const Key &key)
{
return Error(d->lasterr = gpgme_signers_add(d->ctx, key.impl()));
}
Key Context::signingKey(unsigned int idx) const
{
gpgme_key_t key = gpgme_signers_enum(d->ctx, idx);
return Key(key, false);
}
std::vector<Key> Context::signingKeys() const
{
std::vector<Key> result;
gpgme_key_t key;
for (unsigned int i = 0 ; (key = gpgme_signers_enum(d->ctx, i)) ; ++i) {
result.push_back(Key(key, false));
}
return result;
}
void Context::clearSignatureNotations()
{
gpgme_sig_notation_clear(d->ctx);
}
GpgME::Error Context::addSignatureNotation(const char *name, const char *value, unsigned int flags)
{
return Error(gpgme_sig_notation_add(d->ctx, name, value, add_to_gpgme_sig_notation_flags_t(0, flags)));
}
GpgME::Error Context::addSignaturePolicyURL(const char *url, bool critical)
{
return Error(gpgme_sig_notation_add(d->ctx, 0, url, critical ? GPGME_SIG_NOTATION_CRITICAL : 0));
}
const char *Context::signaturePolicyURL() const
{
for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
if (!n->name) {
return n->value;
}
}
+ return nullptr;
}
Notation Context::signatureNotation(unsigned int idx) const
{
for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
if (n->name) {
if (idx-- == 0) {
return Notation(n);
}
}
}
return Notation();
}
std::vector<Notation> Context::signatureNotations() const
{
std::vector<Notation> result;
for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
if (n->name) {
result.push_back(Notation(n));
}
}
return result;
}
static gpgme_sig_mode_t sigmode2sigmode(SignatureMode mode)
{
switch (mode) {
default:
case NormalSignatureMode: return GPGME_SIG_MODE_NORMAL;
case Detached: return GPGME_SIG_MODE_DETACH;
case Clearsigned: return GPGME_SIG_MODE_CLEAR;
}
}
SigningResult Context::sign(const Data &plainText, Data &signature, SignatureMode mode)
{
d->lastop = Private::Sign;
const Data::Private *const pdp = plainText.impl();
Data::Private *const sdp = signature.impl();
d->lasterr = gpgme_op_sign(d->ctx, pdp ? pdp->data : 0, sdp ? sdp->data : 0, sigmode2sigmode(mode));
return SigningResult(d->ctx, Error(d->lasterr));
}
Error Context::startSigning(const Data &plainText, Data &signature, SignatureMode mode)
{
d->lastop = Private::Sign;
const Data::Private *const pdp = plainText.impl();
Data::Private *const sdp = signature.impl();
return Error(d->lasterr = gpgme_op_sign_start(d->ctx, pdp ? pdp->data : 0, sdp ? sdp->data : 0, sigmode2sigmode(mode)));
}
SigningResult Context::signingResult() const
{
if (d->lastop & Private::Sign) {
return SigningResult(d->ctx, Error(d->lasterr));
} else {
return SigningResult();
}
}
static gpgme_encrypt_flags_t encryptflags2encryptflags(Context::EncryptionFlags flags)
{
unsigned int result = 0;
if (flags & Context::AlwaysTrust) {
result |= GPGME_ENCRYPT_ALWAYS_TRUST;
}
if (flags & Context::NoEncryptTo) {
result |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
}
if (flags & Context::Prepare) {
result |= GPGME_ENCRYPT_PREPARE;
}
if (flags & Context::ExpectSign) {
result |= GPGME_ENCRYPT_EXPECT_SIGN;
}
if (flags & Context::NoCompress) {
result |= GPGME_ENCRYPT_NO_COMPRESS;
}
if (flags & Context::Symmetric) {
result |= GPGME_ENCRYPT_SYMMETRIC;
}
return static_cast<gpgme_encrypt_flags_t>(result);
}
gpgme_key_t *Context::getKeysFromRecipients(const std::vector<Key> &recipients)
{
if (recipients.empty()) {
return nullptr;
}
gpgme_key_t *ret = new gpgme_key_t[ recipients.size() + 1 ];
gpgme_key_t *keys_it = ret;
for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
if (it->impl()) {
*keys_it++ = it->impl();
}
}
*keys_it++ = 0;
return ret;
}
EncryptionResult Context::encrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
{
d->lastop = Private::Encrypt;
if (flags & NoEncryptTo) {
return EncryptionResult(Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED)));
}
const Data::Private *const pdp = plainText.impl();
Data::Private *const cdp = cipherText.impl();
gpgme_key_t *const keys = getKeysFromRecipients(recipients);
d->lasterr = gpgme_op_encrypt(d->ctx, keys, encryptflags2encryptflags(flags),
pdp ? pdp->data : 0, cdp ? cdp->data : 0);
if (keys) {
delete[] keys;
}
return EncryptionResult(d->ctx, Error(d->lasterr));
}
Error Context::encryptSymmetrically(const Data &plainText, Data &cipherText)
{
d->lastop = Private::Encrypt;
const Data::Private *const pdp = plainText.impl();
Data::Private *const cdp = cipherText.impl();
return Error(d->lasterr = gpgme_op_encrypt(d->ctx, 0, (gpgme_encrypt_flags_t)0,
pdp ? pdp->data : 0, cdp ? cdp->data : 0));
}
Error Context::startEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
{
d->lastop = Private::Encrypt;
if (flags & NoEncryptTo) {
return Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED));
}
const Data::Private *const pdp = plainText.impl();
Data::Private *const cdp = cipherText.impl();
gpgme_key_t *const keys = getKeysFromRecipients(recipients);
d->lasterr = gpgme_op_encrypt_start(d->ctx, keys, encryptflags2encryptflags(flags),
pdp ? pdp->data : 0, cdp ? cdp->data : 0);
if (keys) {
delete[] keys;
}
return Error(d->lasterr);
}
EncryptionResult Context::encryptionResult() const
{
if (d->lastop & Private::Encrypt) {
return EncryptionResult(d->ctx, Error(d->lasterr));
} else {
return EncryptionResult();
}
}
std::pair<SigningResult, EncryptionResult> Context::signAndEncrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
{
d->lastop = Private::SignAndEncrypt;
const Data::Private *const pdp = plainText.impl();
Data::Private *const cdp = cipherText.impl();
gpgme_key_t *const keys = getKeysFromRecipients(recipients);
d->lasterr = gpgme_op_encrypt_sign(d->ctx, keys, encryptflags2encryptflags(flags),
pdp ? pdp->data : 0, cdp ? cdp->data : 0);
if (keys) {
delete[] keys;
}
return std::make_pair(SigningResult(d->ctx, Error(d->lasterr)),
EncryptionResult(d->ctx, Error(d->lasterr)));
}
Error Context::startCombinedSigningAndEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
{
d->lastop = Private::SignAndEncrypt;
const Data::Private *const pdp = plainText.impl();
Data::Private *const cdp = cipherText.impl();
gpgme_key_t *const keys = getKeysFromRecipients(recipients);
d->lasterr = gpgme_op_encrypt_sign_start(d->ctx, keys, encryptflags2encryptflags(flags),
pdp ? pdp->data : 0, cdp ? cdp->data : 0);
if (keys) {
delete[] keys;
}
return Error(d->lasterr);
}
Error Context::createVFS(const char *containerFile, const std::vector< Key > &recipients)
{
d->lastop = Private::CreateVFS;
gpgme_key_t *const keys = new gpgme_key_t[ recipients.size() + 1 ];
gpgme_key_t *keys_it = keys;
for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
if (it->impl()) {
*keys_it++ = it->impl();
}
}
*keys_it++ = 0;
gpgme_error_t op_err;
d->lasterr = gpgme_op_vfs_create(d->ctx, keys, containerFile, 0, &op_err);
delete[] keys;
Error error(d->lasterr);
if (error) {
return error;
}
return Error(d->lasterr = op_err);
}
VfsMountResult Context::mountVFS(const char *containerFile, const char *mountDir)
{
d->lastop = Private::MountVFS;
gpgme_error_t op_err;
d->lasterr = gpgme_op_vfs_mount(d->ctx, containerFile, mountDir, 0, &op_err);
return VfsMountResult(d->ctx, Error(d->lasterr), Error(op_err));
}
Error Context::cancelPendingOperation()
{
return Error(gpgme_cancel_async(d->ctx));
}
bool Context::poll()
{
gpgme_error_t e = GPG_ERR_NO_ERROR;
const bool finished = gpgme_wait(d->ctx, &e, 0);
if (finished) {
d->lasterr = e;
}
return finished;
}
Error Context::wait()
{
gpgme_error_t e = GPG_ERR_NO_ERROR;
gpgme_wait(d->ctx, &e, 1);
return Error(d->lasterr = e);
}
Error Context::lastError() const
{
return Error(d->lasterr);
}
Context::PinentryMode Context::pinentryMode() const
{
switch (gpgme_get_pinentry_mode (d->ctx)) {
case GPGME_PINENTRY_MODE_ASK:
return PinentryAsk;
case GPGME_PINENTRY_MODE_CANCEL:
return PinentryCancel;
case GPGME_PINENTRY_MODE_ERROR:
return PinentryError;
case GPGME_PINENTRY_MODE_LOOPBACK:
return PinentryLoopback;
case GPGME_PINENTRY_MODE_DEFAULT:
default:
return PinentryDefault;
}
}
Error Context::setPinentryMode(PinentryMode which)
{
gpgme_pinentry_mode_t mode;
switch (which) {
case PinentryAsk:
mode = GPGME_PINENTRY_MODE_ASK;
break;
case PinentryCancel:
mode = GPGME_PINENTRY_MODE_CANCEL;
break;
case PinentryError:
mode = GPGME_PINENTRY_MODE_ERROR;
break;
case PinentryLoopback:
mode = GPGME_PINENTRY_MODE_LOOPBACK;
break;
case PinentryDefault:
default:
mode = GPGME_PINENTRY_MODE_DEFAULT;
}
return Error(d->lasterr = gpgme_set_pinentry_mode(d->ctx, mode));
}
static gpgme_tofu_policy_t to_tofu_policy_t(unsigned int policy)
{
switch (policy) {
case TofuInfo::PolicyNone:
return GPGME_TOFU_POLICY_NONE;
case TofuInfo::PolicyAuto:
return GPGME_TOFU_POLICY_AUTO;
case TofuInfo::PolicyGood:
return GPGME_TOFU_POLICY_GOOD;
case TofuInfo::PolicyBad:
return GPGME_TOFU_POLICY_BAD;
case TofuInfo::PolicyAsk:
return GPGME_TOFU_POLICY_ASK;
case TofuInfo::PolicyUnknown:
+ default:
return GPGME_TOFU_POLICY_UNKNOWN;
}
}
Error Context::setTofuPolicy(const Key &k, unsigned int policy)
{
return Error(d->lasterr = gpgme_op_tofu_policy(d->ctx,
k.impl(), to_tofu_policy_t(policy)));
}
Error Context::setTofuPolicyStart(const Key &k, unsigned int policy)
{
return Error(d->lasterr = gpgme_op_tofu_policy_start(d->ctx,
k.impl(), to_tofu_policy_t(policy)));
}
// Engine Spawn stuff
Error Context::spawn(const char *file, const char *argv[],
Data &input, Data &output, Data &err,
SpawnFlags flags)
{
return Error(d->lasterr = gpgme_op_spawn (d->ctx, file, argv,
input.impl() ? input.impl()->data : nullptr,
output.impl() ? output.impl()->data : nullptr,
err.impl() ? err.impl()->data : nullptr,
static_cast<int>(flags)));
}
Error Context::spawnAsync(const char *file, const char *argv[],
Data &input, Data &output, Data &err,
SpawnFlags flags)
{
return Error(d->lasterr = gpgme_op_spawn_start (d->ctx, file, argv,
input.impl() ? input.impl()->data : nullptr,
output.impl() ? output.impl()->data : nullptr,
err.impl() ? err.impl()->data : nullptr,
static_cast<int>(flags)));
}
std::ostream &operator<<(std::ostream &os, Protocol proto)
{
os << "GpgME::Protocol(";
switch (proto) {
case OpenPGP:
os << "OpenPGP";
break;
case CMS:
os << "CMS";
break;
default:
case UnknownProtocol:
os << "UnknownProtocol";
break;
}
return os << ')';
}
std::ostream &operator<<(std::ostream &os, Engine eng)
{
os << "GpgME::Engine(";
switch (eng) {
case GpgEngine:
os << "GpgEngine";
break;
case GpgSMEngine:
os << "GpgSMEngine";
break;
case GpgConfEngine:
os << "GpgConfEngine";
break;
case AssuanEngine:
os << "AssuanEngine";
break;
case SpawnEngine:
os << "SpawnEngine";
break;
default:
case UnknownEngine:
os << "UnknownEngine";
break;
}
return os << ')';
}
std::ostream &operator<<(std::ostream &os, Context::CertificateInclusion incl)
{
os << "GpgME::Context::CertificateInclusion(" << static_cast<int>(incl);
switch (incl) {
case Context::DefaultCertificates:
os << "(DefaultCertificates)";
break;
case Context::AllCertificatesExceptRoot:
os << "(AllCertificatesExceptRoot)";
break;
case Context::AllCertificates:
os << "(AllCertificates)";
break;
case Context::NoCertificates:
os << "(NoCertificates)";
break;
case Context::OnlySenderCertificate:
os << "(OnlySenderCertificate)";
break;
}
return os << ')';
}
std::ostream &operator<<(std::ostream &os, KeyListMode mode)
{
os << "GpgME::KeyListMode(";
#define CHECK( x ) if ( !(mode & (x)) ) {} else do { os << #x " "; } while (0)
CHECK(Local);
CHECK(Extern);
CHECK(Signatures);
CHECK(Validate);
CHECK(Ephemeral);
CHECK(WithTofu);
#undef CHECK
return os << ')';
}
std::ostream &operator<<(std::ostream &os, SignatureMode mode)
{
os << "GpgME::SignatureMode(";
switch (mode) {
#define CHECK( x ) case x: os << #x; break
CHECK(NormalSignatureMode);
CHECK(Detached);
CHECK(Clearsigned);
#undef CHECK
default:
os << "???" "(" << static_cast<int>(mode) << ')';
break;
}
return os << ')';
}
std::ostream &operator<<(std::ostream &os, Context::EncryptionFlags flags)
{
os << "GpgME::Context::EncryptionFlags(";
#define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
CHECK(AlwaysTrust);
CHECK(NoEncryptTo);
CHECK(Prepare);
CHECK(ExpectSign);
CHECK(NoCompress);
CHECK(Symmetric);
#undef CHECK
return os << ')';
}
std::ostream &operator<<(std::ostream &os, Context::AuditLogFlags flags)
{
os << "GpgME::Context::AuditLogFlags(";
#define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
CHECK(HtmlAuditLog);
CHECK(AuditLogWithHelp);
#undef CHECK
return os << ')';
}
} // namespace GpgME
GpgME::Error GpgME::setDefaultLocale(int cat, const char *val)
{
return Error(gpgme_set_locale(0, cat, val));
}
GpgME::EngineInfo GpgME::engineInfo(GpgME::Protocol proto)
{
gpgme_engine_info_t ei = 0;
if (gpgme_get_engine_info(&ei)) {
return EngineInfo();
}
const gpgme_protocol_t p = proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP ;
for (gpgme_engine_info_t i = ei ; i ; i = i->next) {
if (i->protocol == p) {
return EngineInfo(i);
}
}
return EngineInfo();
}
const char *GpgME::dirInfo(const char *what)
{
return gpgme_get_dirinfo(what);
}
GpgME::Error GpgME::checkEngine(GpgME::Protocol proto)
{
const gpgme_protocol_t p = proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP ;
return Error(gpgme_engine_check_version(p));
}
static const gpgme_protocol_t UNKNOWN_PROTOCOL = static_cast<gpgme_protocol_t>(255);
static gpgme_protocol_t engine2protocol(const GpgME::Engine engine)
{
switch (engine) {
case GpgME::GpgEngine: return GPGME_PROTOCOL_OpenPGP;
case GpgME::GpgSMEngine: return GPGME_PROTOCOL_CMS;
case GpgME::GpgConfEngine:
return GPGME_PROTOCOL_GPGCONF;
case GpgME::AssuanEngine:
return GPGME_PROTOCOL_ASSUAN;
case GpgME::G13Engine:
return GPGME_PROTOCOL_G13;
case GpgME::SpawnEngine:
return GPGME_PROTOCOL_SPAWN;
case GpgME::UnknownEngine:
;
}
return UNKNOWN_PROTOCOL;
}
GpgME::EngineInfo GpgME::engineInfo(GpgME::Engine engine)
{
gpgme_engine_info_t ei = 0;
if (gpgme_get_engine_info(&ei)) {
return EngineInfo();
}
const gpgme_protocol_t p = engine2protocol(engine);
for (gpgme_engine_info_t i = ei ; i ; i = i->next) {
if (i->protocol == p) {
return EngineInfo(i);
}
}
return EngineInfo();
}
GpgME::Error GpgME::checkEngine(GpgME::Engine engine)
{
const gpgme_protocol_t p = engine2protocol(engine);
return Error(gpgme_engine_check_version(p));
}
static const unsigned long supported_features = 0
| GpgME::ValidatingKeylistModeFeature
| GpgME::CancelOperationFeature
| GpgME::WrongKeyUsageFeature
| GpgME::DefaultCertificateInclusionFeature
| GpgME::GetSetEngineInfoFeature
| GpgME::ClearAddGetSignatureNotationsFeature
| GpgME::SetDataFileNameFeeature
| GpgME::SignatureNotationsKeylistModeFeature
| GpgME::KeySignatureNotationsFeature
| GpgME::KeyIsQualifiedFeature
| GpgME::SignatureNotationsCriticalFlagFeature
| GpgME::SignatureNotationsFlagsFeature
| GpgME::SignatureNotationsHumanReadableFlagFeature
| GpgME::SubkeyIsQualifiedFeature
| GpgME::EngineInfoHomeDirFeature
| GpgME::DecryptionResultFileNameFeature
| GpgME::DecryptionResultRecipientsFeature
| GpgME::VerificationResultFileNameFeature
| GpgME::SignaturePkaFieldsFeature
| GpgME::SignatureAlgorithmFieldsFeature
| GpgME::FdPointerFeature
| GpgME::AuditLogFeature
| GpgME::GpgConfEngineFeature
| GpgME::CancelOperationAsyncFeature
| GpgME::NoEncryptToEncryptionFlagFeature
| GpgME::CardKeyFeature
| GpgME::AssuanEngineFeature
| GpgME::EphemeralKeylistModeFeature
| GpgME::ImportFromKeyserverFeature
| GpgME::G13VFSFeature
| GpgME::PasswdFeature
;
static const unsigned long supported_features2 = 0
| GpgME::BinaryAndFineGrainedIdentify
;
bool GpgME::hasFeature(unsigned long features)
{
return features == (features & supported_features);
}
bool GpgME::hasFeature(unsigned long features, unsigned long features2)
{
return features == (features & supported_features)
&& features2 == (features2 & supported_features2)
;
}
diff --git a/src/key.cpp b/src/key.cpp
index cfa1ba31..a56f77ca 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -1,912 +1,913 @@
/*
key.cpp - wraps a gpgme key
Copyright (C) 2003, 2005 Klarälvdalens Datakonsult AB
This file is part of GPGME++.
GPGME++ is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
GPGME++ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with GPGME++; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <key.h>
#include "util.h"
#include "tofuinfo.h"
#include "context.h"
#include <gpgme.h>
#include <string.h>
#include <istream>
#include <iterator>
const GpgME::Key::Null GpgME::Key::null;
namespace GpgME
{
Key::Key() : key() {}
Key::Key(const Null &) : key() {}
Key::Key(const shared_gpgme_key_t &k) : key(k) {}
Key::Key(gpgme_key_t k, bool ref)
: key(k
? shared_gpgme_key_t(k, &gpgme_key_unref)
: shared_gpgme_key_t())
{
if (ref && impl()) {
gpgme_key_ref(impl());
}
}
UserID Key::userID(unsigned int index) const
{
return UserID(key, index);
}
Subkey Key::subkey(unsigned int index) const
{
return Subkey(key, index);
}
unsigned int Key::numUserIDs() const
{
if (!key) {
return 0;
}
unsigned int count = 0;
for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
++count;
}
return count;
}
unsigned int Key::numSubkeys() const
{
if (!key) {
return 0;
}
unsigned int count = 0;
for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
++count;
}
return count;
}
std::vector<UserID> Key::userIDs() const
{
if (!key) {
return std::vector<UserID>();
}
std::vector<UserID> v;
v.reserve(numUserIDs());
for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
v.push_back(UserID(key, uid));
}
return v;
}
std::vector<Subkey> Key::subkeys() const
{
if (!key) {
return std::vector<Subkey>();
}
std::vector<Subkey> v;
v.reserve(numSubkeys());
for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
v.push_back(Subkey(key, subkey));
}
return v;
}
Key::OwnerTrust Key::ownerTrust() const
{
if (!key) {
return Unknown;
}
switch (key->owner_trust) {
default:
case GPGME_VALIDITY_UNKNOWN: return Unknown;
case GPGME_VALIDITY_UNDEFINED: return Undefined;
case GPGME_VALIDITY_NEVER: return Never;
case GPGME_VALIDITY_MARGINAL: return Marginal;
case GPGME_VALIDITY_FULL: return Full;
case GPGME_VALIDITY_ULTIMATE: return Ultimate;
}
}
char Key::ownerTrustAsString() const
{
if (!key) {
return '?';
}
switch (key->owner_trust) {
default:
case GPGME_VALIDITY_UNKNOWN: return '?';
case GPGME_VALIDITY_UNDEFINED: return 'q';
case GPGME_VALIDITY_NEVER: return 'n';
case GPGME_VALIDITY_MARGINAL: return 'm';
case GPGME_VALIDITY_FULL: return 'f';
case GPGME_VALIDITY_ULTIMATE: return 'u';
}
}
Protocol Key::protocol() const
{
if (!key) {
return UnknownProtocol;
}
switch (key->protocol) {
case GPGME_PROTOCOL_CMS: return CMS;
case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
default: return UnknownProtocol;
}
}
const char *Key::protocolAsString() const
{
return key ? gpgme_get_protocol_name(key->protocol) : 0 ;
}
bool Key::isRevoked() const
{
return key && key->revoked;
}
bool Key::isExpired() const
{
return key && key->expired;
}
bool Key::isDisabled() const
{
return key && key->disabled;
}
bool Key::isInvalid() const
{
return key && key->invalid;
}
bool Key::hasSecret() const
{
return key && key->secret;
}
bool Key::isRoot() const
{
return key && key->subkeys && key->subkeys->fpr && key->chain_id &&
strcasecmp(key->subkeys->fpr, key->chain_id) == 0;
}
bool Key::canEncrypt() const
{
return key && key->can_encrypt;
}
bool Key::canSign() const
{
#ifndef GPGME_CAN_SIGN_ON_SECRET_OPENPGP_KEYLISTING_NOT_BROKEN
if (key && key->protocol == GPGME_PROTOCOL_OpenPGP) {
return true;
}
#endif
return canReallySign();
}
bool Key::canReallySign() const
{
return key && key->can_sign;
}
bool Key::canCertify() const
{
return key && key->can_certify;
}
bool Key::canAuthenticate() const
{
return key && key->can_authenticate;
}
bool Key::isQualified() const
{
return key && key->is_qualified;
}
const char *Key::issuerSerial() const
{
return key ? key->issuer_serial : 0 ;
}
const char *Key::issuerName() const
{
return key ? key->issuer_name : 0 ;
}
const char *Key::chainID() const
{
return key ? key->chain_id : 0 ;
}
const char *Key::keyID() const
{
return key && key->subkeys ? key->subkeys->keyid : 0 ;
}
const char *Key::shortKeyID() const
{
if (!key || !key->subkeys || !key->subkeys->keyid) {
return 0;
}
const int len = strlen(key->subkeys->keyid);
if (len > 8) {
return key->subkeys->keyid + len - 8; // return the last 8 bytes (in hex notation)
} else {
return key->subkeys->keyid;
}
}
const char *Key::primaryFingerprint() const
{
if (!key) {
return nullptr;
}
if (key->fpr) {
/* Return what gpgme thinks is the primary fingerprint */
return key->fpr;
}
if (key->subkeys) {
/* Return the first subkeys fingerprint */
return key->subkeys->fpr;
}
+ return nullptr;
}
unsigned int Key::keyListMode() const
{
return key ? convert_from_gpgme_keylist_mode_t(key->keylist_mode) : 0 ;
}
const Key &Key::mergeWith(const Key &other)
{
// ### incomplete. Just merges has* and can*, nothing else atm
// ### detach also missing
if (!this->primaryFingerprint() ||
!other.primaryFingerprint() ||
strcasecmp(this->primaryFingerprint(), other.primaryFingerprint()) != 0) {
return *this; // only merge the Key object which describe the same key
}
const gpgme_key_t me = impl();
const gpgme_key_t him = other.impl();
if (!me || !him) {
return *this;
}
me->revoked |= him->revoked;
me->expired |= him->expired;
me->disabled |= him->disabled;
me->invalid |= him->invalid;
me->can_encrypt |= him->can_encrypt;
me->can_sign |= him->can_sign;
me->can_certify |= him->can_certify;
me->secret |= him->secret;
me->can_authenticate |= him->can_authenticate;
me->is_qualified |= him->is_qualified;
me->keylist_mode |= him->keylist_mode;
// make sure the gpgme_sub_key_t::is_cardkey flag isn't lost:
for (gpgme_sub_key_t mysk = me->subkeys ; mysk ; mysk = mysk->next) {
for (gpgme_sub_key_t hissk = him->subkeys ; hissk ; hissk = hissk->next) {
if (strcmp(mysk->fpr, hissk->fpr) == 0) {
mysk->is_cardkey |= hissk->is_cardkey;
break;
}
}
}
return *this;
}
void Key::update()
{
auto ctx = Context::createForProtocol(protocol());
if (!ctx) {
return;
}
ctx->setKeyListMode(KeyListMode::Local |
KeyListMode::Signatures |
KeyListMode::SignatureNotations |
KeyListMode::Validate |
KeyListMode::WithTofu);
Error err;
auto newKey = ctx->key(primaryFingerprint(), err, hasSecret());
delete ctx;
if (err) {
return;
}
swap(newKey);
return;
}
//
//
// class Subkey
//
//
gpgme_sub_key_t find_subkey(const shared_gpgme_key_t &key, unsigned int idx)
{
if (key) {
for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next, --idx) {
if (idx == 0) {
return s;
}
}
}
return 0;
}
gpgme_sub_key_t verify_subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey)
{
if (key) {
for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next) {
if (s == subkey) {
return subkey;
}
}
}
return 0;
}
Subkey::Subkey() : key(), subkey(0) {}
Subkey::Subkey(const shared_gpgme_key_t &k, unsigned int idx)
: key(k), subkey(find_subkey(k, idx))
{
}
Subkey::Subkey(const shared_gpgme_key_t &k, gpgme_sub_key_t sk)
: key(k), subkey(verify_subkey(k, sk))
{
}
Key Subkey::parent() const
{
return Key(key);
}
const char *Subkey::keyID() const
{
return subkey ? subkey->keyid : 0 ;
}
const char *Subkey::fingerprint() const
{
return subkey ? subkey->fpr : 0 ;
}
Subkey::PubkeyAlgo Subkey::publicKeyAlgorithm() const
{
return subkey ? static_cast<PubkeyAlgo>(subkey->pubkey_algo) : AlgoUnknown;
}
const char *Subkey::publicKeyAlgorithmAsString() const
{
return gpgme_pubkey_algo_name(subkey ? subkey->pubkey_algo : (gpgme_pubkey_algo_t)0);
}
/* static */
const char *Subkey::publicKeyAlgorithmAsString(PubkeyAlgo algo)
{
if (algo == AlgoUnknown) {
return NULL;
}
return gpgme_pubkey_algo_name(static_cast<gpgme_pubkey_algo_t>(algo));
}
std::string Subkey::algoName() const
{
char *gpgmeStr;
if (subkey && (gpgmeStr = gpgme_pubkey_algo_string(subkey))) {
std::string ret = std::string(gpgmeStr);
gpgme_free(gpgmeStr);
return ret;
}
return std::string();
}
bool Subkey::canEncrypt() const
{
return subkey && subkey->can_encrypt;
}
bool Subkey::canSign() const
{
return subkey && subkey->can_sign;
}
bool Subkey::canCertify() const
{
return subkey && subkey->can_certify;
}
bool Subkey::canAuthenticate() const
{
return subkey && subkey->can_authenticate;
}
bool Subkey::isQualified() const
{
return subkey && subkey->is_qualified;
}
bool Subkey::isCardKey() const
{
return subkey && subkey->is_cardkey;
}
const char *Subkey::cardSerialNumber() const
{
return subkey ? subkey->card_number : 0 ;
}
bool Subkey::isSecret() const
{
return subkey && subkey->secret;
}
unsigned int Subkey::length() const
{
return subkey ? subkey->length : 0 ;
}
time_t Subkey::creationTime() const
{
return static_cast<time_t>(subkey ? subkey->timestamp : 0);
}
time_t Subkey::expirationTime() const
{
return static_cast<time_t>(subkey ? subkey->expires : 0);
}
bool Subkey::neverExpires() const
{
return expirationTime() == time_t(0);
}
bool Subkey::isRevoked() const
{
return subkey && subkey->revoked;
}
bool Subkey::isInvalid() const
{
return subkey && subkey->invalid;
}
bool Subkey::isExpired() const
{
return subkey && subkey->expired;
}
bool Subkey::isDisabled() const
{
return subkey && subkey->disabled;
}
//
//
// class UserID
//
//
gpgme_user_id_t find_uid(const shared_gpgme_key_t &key, unsigned int idx)
{
if (key) {
for (gpgme_user_id_t u = key->uids ; u ; u = u->next, --idx) {
if (idx == 0) {
return u;
}
}
}
return 0;
}
gpgme_user_id_t verify_uid(const shared_gpgme_key_t &key, gpgme_user_id_t uid)
{
if (key) {
for (gpgme_user_id_t u = key->uids ; u ; u = u->next) {
if (u == uid) {
return uid;
}
}
}
return 0;
}
UserID::UserID() : key(), uid(0) {}
UserID::UserID(const shared_gpgme_key_t &k, gpgme_user_id_t u)
: key(k), uid(verify_uid(k, u))
{
}
UserID::UserID(const shared_gpgme_key_t &k, unsigned int idx)
: key(k), uid(find_uid(k, idx))
{
}
Key UserID::parent() const
{
return Key(key);
}
UserID::Signature UserID::signature(unsigned int index) const
{
return Signature(key, uid, index);
}
unsigned int UserID::numSignatures() const
{
if (!uid) {
return 0;
}
unsigned int count = 0;
for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
++count;
}
return count;
}
std::vector<UserID::Signature> UserID::signatures() const
{
if (!uid) {
return std::vector<Signature>();
}
std::vector<Signature> v;
v.reserve(numSignatures());
for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
v.push_back(Signature(key, uid, sig));
}
return v;
}
const char *UserID::id() const
{
return uid ? uid->uid : 0 ;
}
const char *UserID::name() const
{
return uid ? uid->name : 0 ;
}
const char *UserID::email() const
{
return uid ? uid->email : 0 ;
}
const char *UserID::comment() const
{
return uid ? uid->comment : 0 ;
}
UserID::Validity UserID::validity() const
{
if (!uid) {
return Unknown;
}
switch (uid->validity) {
default:
case GPGME_VALIDITY_UNKNOWN: return Unknown;
case GPGME_VALIDITY_UNDEFINED: return Undefined;
case GPGME_VALIDITY_NEVER: return Never;
case GPGME_VALIDITY_MARGINAL: return Marginal;
case GPGME_VALIDITY_FULL: return Full;
case GPGME_VALIDITY_ULTIMATE: return Ultimate;
}
}
char UserID::validityAsString() const
{
if (!uid) {
return '?';
}
switch (uid->validity) {
default:
case GPGME_VALIDITY_UNKNOWN: return '?';
case GPGME_VALIDITY_UNDEFINED: return 'q';
case GPGME_VALIDITY_NEVER: return 'n';
case GPGME_VALIDITY_MARGINAL: return 'm';
case GPGME_VALIDITY_FULL: return 'f';
case GPGME_VALIDITY_ULTIMATE: return 'u';
}
}
bool UserID::isRevoked() const
{
return uid && uid->revoked;
}
bool UserID::isInvalid() const
{
return uid && uid->invalid;
}
TofuInfo UserID::tofuInfo() const
{
if (!uid) {
return TofuInfo();
}
return TofuInfo(uid->tofu);
}
//
//
// class Signature
//
//
gpgme_key_sig_t find_signature(gpgme_user_id_t uid, unsigned int idx)
{
if (uid) {
for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, --idx) {
if (idx == 0) {
return s;
}
}
}
return 0;
}
gpgme_key_sig_t verify_signature(gpgme_user_id_t uid, gpgme_key_sig_t sig)
{
if (uid) {
for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
if (s == sig) {
return sig;
}
}
}
return 0;
}
UserID::Signature::Signature() : key(), uid(0), sig(0) {}
UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, unsigned int idx)
: key(k), uid(verify_uid(k, u)), sig(find_signature(uid, idx))
{
}
UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, gpgme_key_sig_t s)
: key(k), uid(verify_uid(k, u)), sig(verify_signature(uid, s))
{
}
UserID UserID::Signature::parent() const
{
return UserID(key, uid);
}
const char *UserID::Signature::signerKeyID() const
{
return sig ? sig->keyid : 0 ;
}
const char *UserID::Signature::algorithmAsString() const
{
return gpgme_pubkey_algo_name(sig ? sig->pubkey_algo : (gpgme_pubkey_algo_t)0);
}
unsigned int UserID::Signature::algorithm() const
{
return sig ? sig->pubkey_algo : 0 ;
}
time_t UserID::Signature::creationTime() const
{
return static_cast<time_t>(sig ? sig->timestamp : 0);
}
time_t UserID::Signature::expirationTime() const
{
return static_cast<time_t>(sig ? sig->expires : 0);
}
bool UserID::Signature::neverExpires() const
{
return expirationTime() == time_t(0);
}
bool UserID::Signature::isRevokation() const
{
return sig && sig->revoked;
}
bool UserID::Signature::isInvalid() const
{
return sig && sig->invalid;
}
bool UserID::Signature::isExpired() const
{
return sig && sig->expired;
}
bool UserID::Signature::isExportable() const
{
return sig && sig->exportable;
}
const char *UserID::Signature::signerUserID() const
{
return sig ? sig->uid : 0 ;
}
const char *UserID::Signature::signerName() const
{
return sig ? sig->name : 0 ;
}
const char *UserID::Signature::signerEmail() const
{
return sig ? sig->email : 0 ;
}
const char *UserID::Signature::signerComment() const
{
return sig ? sig->comment : 0 ;
}
unsigned int UserID::Signature::certClass() const
{
return sig ? sig->sig_class : 0 ;
}
UserID::Signature::Status UserID::Signature::status() const
{
if (!sig) {
return GeneralError;
}
switch (gpgme_err_code(sig->status)) {
case GPG_ERR_NO_ERROR: return NoError;
case GPG_ERR_SIG_EXPIRED: return SigExpired;
case GPG_ERR_KEY_EXPIRED: return KeyExpired;
case GPG_ERR_BAD_SIGNATURE: return BadSignature;
case GPG_ERR_NO_PUBKEY: return NoPublicKey;
default:
case GPG_ERR_GENERAL: return GeneralError;
}
}
std::string UserID::Signature::statusAsString() const
{
if (!sig) {
return std::string();
}
char buf[ 1024 ];
gpgme_strerror_r(sig->status, buf, sizeof buf);
buf[ sizeof buf - 1 ] = '\0';
return std::string(buf);
}
GpgME::Notation UserID::Signature::notation(unsigned int idx) const
{
if (!sig) {
return GpgME::Notation();
}
for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
if (nota->name) {
if (idx-- == 0) {
return GpgME::Notation(nota);
}
}
}
return GpgME::Notation();
}
unsigned int UserID::Signature::numNotations() const
{
if (!sig) {
return 0;
}
unsigned int count = 0;
for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
if (nota->name) {
++count; // others are policy URLs...
}
}
return count;
}
std::vector<Notation> UserID::Signature::notations() const
{
if (!sig) {
return std::vector<GpgME::Notation>();
}
std::vector<GpgME::Notation> v;
v.reserve(numNotations());
for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
if (nota->name) {
v.push_back(GpgME::Notation(nota));
}
}
return v;
}
const char *UserID::Signature::policyURL() const
{
if (!sig) {
return 0;
}
for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
if (!nota->name) {
return nota->value;
}
}
return 0;
}
std::ostream &operator<<(std::ostream &os, const UserID &uid)
{
os << "GpgME::UserID(";
if (!uid.isNull()) {
os << "\n name: " << protect(uid.name())
<< "\n email: " << protect(uid.email())
<< "\n comment: " << protect(uid.comment())
<< "\n validity: " << uid.validityAsString()
<< "\n revoked: " << uid.isRevoked()
<< "\n invalid: " << uid.isInvalid()
<< "\n numsigs: " << uid.numSignatures()
<< "\n tofuinfo:\n" << uid.tofuInfo();
}
return os << ')';
}
std::ostream &operator<<(std::ostream &os, const Key &key)
{
os << "GpgME::Key(";
if (!key.isNull()) {
os << "\n protocol: " << protect(key.protocolAsString())
<< "\n ownertrust: " << key.ownerTrustAsString()
<< "\n issuer: " << protect(key.issuerName())
<< "\n fingerprint:" << protect(key.primaryFingerprint())
<< "\n listmode: " << key.keyListMode()
<< "\n canSign: " << key.canReallySign()
<< "\n canEncrypt: " << key.canEncrypt()
<< "\n canCertify: " << key.canCertify()
<< "\n canAuth: " << key.canAuthenticate()
<< "\n uids:\n";
const std::vector<UserID> uids = key.userIDs();
std::copy(uids.begin(), uids.end(),
std::ostream_iterator<UserID>(os, "\n"));
}
return os << ')';
}
} // namespace GpgME
diff --git a/src/tofuinfo.cpp b/src/tofuinfo.cpp
index bb67fc8c..e661b3b1 100644
--- a/src/tofuinfo.cpp
+++ b/src/tofuinfo.cpp
@@ -1,167 +1,168 @@
/* tofuinfo.cpp - wraps gpgme tofu info
Copyright (C) 2016 Intevation GmbH
This file is part of GPGME++.
GPGME++ is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
GPGME++ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with GPGME++; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "tofuinfo.h"
#include <istream>
#include "util.h"
class GpgME::TofuInfo::Private
{
public:
Private() {}
Private(gpgme_tofu_info_t info)
: mInfo(info ? new _gpgme_tofu_info(*info) : nullptr)
{
if (mInfo && mInfo->description) {
mInfo->description = strdup(mInfo->description);
}
}
Private(const Private &other)
: mInfo(other.mInfo)
{
if (mInfo && mInfo->description) {
mInfo->description = strdup(mInfo->description);
}
}
~Private()
{
if (mInfo) {
std::free(mInfo->description);
mInfo->description = nullptr;
delete mInfo;
}
}
gpgme_tofu_info_t mInfo;
};
GpgME::TofuInfo::TofuInfo(gpgme_tofu_info_t info)
: d(new Private(info))
{
}
GpgME::TofuInfo::TofuInfo() : d()
{
}
bool GpgME::TofuInfo::isNull() const
{
return !d || !d->mInfo;
}
GpgME::TofuInfo::Validity GpgME::TofuInfo::validity() const
{
if (isNull()) {
return ValidityUnknown;
}
switch (d->mInfo->validity) {
case 0:
return Conflict;
case 1:
return NoHistory;
case 2:
return LittleHistory;
case 3:
return BasicHistory;
case 4:
return LargeHistory;
default:
return ValidityUnknown;
}
}
GpgME::TofuInfo::Policy GpgME::TofuInfo::policy() const
{
if (isNull()) {
return PolicyUnknown;
}
switch (d->mInfo->policy) {
case GPGME_TOFU_POLICY_NONE:
return PolicyNone;
case GPGME_TOFU_POLICY_AUTO:
return PolicyAuto;
case GPGME_TOFU_POLICY_GOOD:
return PolicyGood;
case GPGME_TOFU_POLICY_BAD:
return PolicyBad;
case GPGME_TOFU_POLICY_ASK:
return PolicyAsk;
case GPGME_TOFU_POLICY_UNKNOWN:
+ default:
return PolicyUnknown;
}
}
const char *GpgME::TofuInfo::description() const
{
return isNull() ? nullptr : d->mInfo->description;
}
unsigned short GpgME::TofuInfo::signCount() const
{
return isNull() ? 0 : d->mInfo->signcount;
}
unsigned short GpgME::TofuInfo::encrCount() const
{
return isNull() ? 0 : d->mInfo->encrcount;
}
unsigned long GpgME::TofuInfo::signFirst() const
{
return isNull() ? 0 : d->mInfo->signfirst;
}
unsigned long GpgME::TofuInfo::signLast() const
{
return isNull() ? 0 : d->mInfo->signlast;
}
unsigned long GpgME::TofuInfo::encrFirst() const
{
return isNull() ? 0 : d->mInfo->encrfirst;
}
unsigned long GpgME::TofuInfo::encrLast() const
{
return isNull() ? 0 : d->mInfo->encrlast;
}
std::ostream &GpgME::operator<<(std::ostream &os, const GpgME::TofuInfo &info)
{
os << "GpgME::Signature::TofuInfo(";
if (!info.isNull()) {
os << "\n desc: " << protect(info.description())
<< "\n validity: " << info.validity()
<< "\n policy: " << info.policy()
<< "\n signcount: "<< info.signCount()
<< "\n signfirst: "<< info.signFirst()
<< "\n signlast: " << info.signLast()
<< "\n encrcount: "<< info.encrCount()
<< "\n encrfirst: "<< info.encrFirst()
<< "\n encrlast: " << info.encrLast()
<< '\n';
}
return os << ")";
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jul 17, 1:41 AM (2 h, 55 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
be/68/bb53699ca4c860011aaeb9dfe419
Attached To
rGPGMEPP Gpgme plus plus
Event Timeline
Log In to Comment