diff options
Diffstat (limited to 'lang/cpp/src/configuration.cpp')
-rw-r--r-- | lang/cpp/src/configuration.cpp | 934 |
1 files changed, 934 insertions, 0 deletions
diff --git a/lang/cpp/src/configuration.cpp b/lang/cpp/src/configuration.cpp new file mode 100644 index 0000000..7ef2883 --- /dev/null +++ b/lang/cpp/src/configuration.cpp @@ -0,0 +1,934 @@ +/* + configuration.cpp - wraps gpgme configuration components + Copyright (C) 2010 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 "configuration.h" +#include "error.h" +#include "util.h" + +#include <gpgme.h> + +#include <iterator> +#include <algorithm> +#include <ostream> +#include <cstring> +#include <assert.h> + +using namespace GpgME; +using namespace GpgME::Configuration; + +typedef std::shared_ptr< std::remove_pointer<gpgme_conf_opt_t>::type > shared_gpgme_conf_opt_t; +typedef std::weak_ptr< std::remove_pointer<gpgme_conf_opt_t>::type > weak_gpgme_conf_opt_t; + +typedef std::shared_ptr< std::remove_pointer<gpgme_conf_arg_t>::type > shared_gpgme_conf_arg_t; +typedef std::weak_ptr< std::remove_pointer<gpgme_conf_arg_t>::type > weak_gpgme_conf_arg_t; + +typedef std::shared_ptr< std::remove_pointer<gpgme_ctx_t>::type > shared_gpgme_ctx_t; +typedef std::weak_ptr< std::remove_pointer<gpgme_ctx_t>::type > weak_gpgme_ctx_t; + +namespace +{ +struct nodelete { + template <typename T> void operator()(T *) {} +}; +} + +// static +std::vector<Component> Component::load(Error &returnedError) +{ + + // + // 1. get a context: + // + gpgme_ctx_t ctx_native = 0; + if (const gpgme_error_t err = gpgme_new(&ctx_native)) { + returnedError = Error(err); + return std::vector<Component>(); + } + const shared_gpgme_ctx_t ctx(ctx_native, &gpgme_release); + + // + // 2. load the config: + // + gpgme_conf_comp_t conf_list_native = 0; + if (const gpgme_error_t err = gpgme_op_conf_load(ctx_native, &conf_list_native)) { + returnedError = Error(err); + return std::vector<Component>(); + } + shared_gpgme_conf_comp_t head(conf_list_native, &gpgme_conf_release); + + // + // 3. convert to vector<Component>: + // + std::vector<Component> result; + + while (head) { + // secure 'head->next' (if any) against memleaks: + shared_gpgme_conf_comp_t next; + if (head->next) { + next.reset(head->next, &gpgme_conf_release); + } + + // now prevent double-free of next.get() and following: + head->next = 0; + + // now add a new Component to 'result' (may throw): + result.resize(result.size() + 1); + result.back().comp.swap(head); // .comp = std::move( head ); + head.swap(next); // head = std::move( next ); + } + + return result; +} + +Error Component::save() const +{ + + if (isNull()) { + return Error(make_error(GPG_ERR_INV_ARG)); + } + + // + // 1. get a context: + // + gpgme_ctx_t ctx_native = 0; + if (const gpgme_error_t err = gpgme_new(&ctx_native)) { + return Error(err); + } + const shared_gpgme_ctx_t ctx(ctx_native, &gpgme_release); + + // + // 2. save the config: + // + return Error(gpgme_op_conf_save(ctx.get(), comp.get())); +} + +const char *Component::name() const +{ + return comp ? comp->name : 0 ; +} + +const char *Component::description() const +{ + return comp ? comp->description : 0 ; +} + +const char *Component::programName() const +{ + return comp ? comp->program_name : 0 ; +} + +Option Component::option(unsigned int idx) const +{ + gpgme_conf_opt_t opt = 0; + if (comp) { + opt = comp->options; + } + while (opt && idx) { + opt = opt->next; + --idx; + } + if (opt) { + return Option(comp, opt); + } + return Option(); +} + +Option Component::option(const char *name) const +{ + gpgme_conf_opt_t opt = 0; + if (comp) { + opt = comp->options; + } + using namespace std; // for strcmp + while (opt && strcmp(name, opt->name) != 0) { + opt = opt->next; + } + if (opt) { + return Option(comp, opt); + } + return Option(); +} + +unsigned int Component::numOptions() const +{ + unsigned int result = 0; + for (gpgme_conf_opt_t opt = comp ? comp->options : 0 ; opt ; opt = opt->next) { + ++result; + } + return result; +} + +std::vector<Option> Component::options() const +{ + std::vector<Option> result; + for (gpgme_conf_opt_t opt = comp ? comp->options : 0 ; opt ; opt = opt->next) { + result.push_back(Option(comp, opt)); + } + return result; +} + +static gpgme_conf_arg_t mygpgme_conf_arg_copy(gpgme_conf_arg_t other, gpgme_conf_type_t type) +{ + gpgme_conf_arg_t result = 0, last = 0; + for (gpgme_conf_arg_t a = other ; a ; a = a->next) { + gpgme_conf_arg_t arg = 0; + const gpgme_error_t err + = gpgme_conf_arg_new(&arg, type, + a->no_arg ? 0 : + type == GPGME_CONF_STRING ? a->value.string : + /* else */ static_cast<void *>(&a->value)); + if (err) { + gpgme_conf_arg_release(result, type); + return 0; + } + assert(arg); + if (result) { + last->next = arg; + } else { + result = arg; + } + last = arg; + } + return result; +} + +Component Option::parent() const +{ + return Component(comp.lock()); +} + +unsigned int Option::flags() const +{ + return isNull() ? 0 : opt->flags; +} + +Level Option::level() const +{ + return isNull() ? Internal : static_cast<Level>(opt->level) ; +} + +const char *Option::name() const +{ + return isNull() ? 0 : opt->name ; +} + +const char *Option::description() const +{ + return isNull() ? 0 : opt->description ; +} + +const char *Option::argumentName() const +{ + return isNull() ? 0 : opt->argname ; +} + +Type Option::type() const +{ + return isNull() ? NoType : static_cast<Type>(opt->type) ; +} + +Type Option::alternateType() const +{ + return isNull() ? NoType : static_cast<Type>(opt->alt_type) ; +} + +#if 0 +static Option::Variant argument_to_variant(gpgme_conf_type_t type, bool list, gpgme_conf_arg_t arg) +{ + assert(arg); + switch (type) { + case GPGME_CONF_NONE: + if (list) { + // return the count (number of times set): + return arg->value.count; + } else { + return none; + } + case GPGME_CONF_INT32: + if (list) { + std::vector<int> result; + for (gpgme_conf_arg_t a = arg ; a ; a = a->next) { + result.push_back(a->value.int32); + } + return result; + } else { + return arg->value.int32; + } + case GPGME_CONF_UINT32: + if (list) { + std::vector<unsigned int> result; + for (gpgme_conf_arg_t a = arg ; a ; a = a->next) { + result.push_back(a->value.uint32); + } + return result; + } else { + return arg->value.uint32; + } + case GPGME_CONF_FILENAME: + case GPGME_CONF_LDAP_SERVER: + case GPGME_CONF_KEY_FPR: + case GPGME_CONF_PUB_KEY: + case GPGME_CONF_SEC_KEY: + case GPGME_CONF_ALIAS_LIST: + // these should not happen in alt_type, but fall through + case GPGME_CONF_STRING: + if (list) { + std::vector<const char *> result; + for (gpgme_conf_arg_t a = arg ; a ; a = a->next) { + result.push_back(a->value.string); + } + return result; + } else { + return arg->value.string; + } + } + assert(!"Option: unknown alt_type!"); + return Option::Variant(); +} + +namespace +{ +inline const void *to_void_star(const char *s) +{ + return s; +} +inline const void *to_void_star(const std::string &s) +{ + return s.c_str(); +} +inline const void *to_void_star(const int &i) +{ + return &i; // const-&: sic! +} +inline const void *to_void_star(const unsigned int &i) +{ + return &i; // const-&: sic! +} + +struct VariantToArgumentVisitor : boost::static_visitor<gpgme_conf_arg_t> { + static gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const void *value) + { + gpgme_conf_arg_t arg = 0; +#ifdef HAVE_GPGME_CONF_ARG_NEW_WITH_CONST_VALUE + if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, value)) { + return 0; + } +#else + if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, const_cast<void *>(value))) { + return 0; + } +#endif + else { + return arg; + } + } + + gpgme_conf_arg_t operator()(bool v) const + { + return v ? make_argument(0) : 0 ; + } + + gpgme_conf_arg_t operator()(const char *s) const + { + return make_argument(s ? s : ""); + } + + gpgme_conf_arg_t operator()(const std::string &s) const + { + return operator()(s.c_str()); + } + + gpgme_conf_arg_t operator()(int i) const + { + return make_argument(&i); + } + + gpgme_conf_arg_t operator()(unsigned int i) const + { + return make_argument(&i); + } + + template <typename T> + gpgme_conf_arg_t operator()(const std::vector<T> &value) const + { + gpgme_conf_arg_t result = 0; + gpgme_conf_arg_t last = 0; + for (typename std::vector<T>::const_iterator it = value.begin(), end = value.end() ; it != end ; ++it) { + if (gpgme_conf_arg_t arg = make_argument(to_void_star(*it))) { + if (last) { + last = last->next = arg; + } else { + result = last = arg; + } + } + } + return result; + } + +}; +} + +static gpgme_conf_arg_t variant_to_argument(const Option::Variant &value) +{ + VariantToArgumentVisitor v; + return apply_visitor(v, value); +} + +optional<Option::Variant> Option::defaultValue() const +{ + if (isNull()) { + return optional<Variant>(); + } else { + return argument_to_variant(opt->alt_type, opt->flags & GPGME_CONF_LIST, opt->default_value); + } +} +#endif + +Argument Option::defaultValue() const +{ + if (isNull()) { + return Argument(); + } else { + return Argument(comp.lock(), opt, opt->default_value, false); + } +} + +const char *Option::defaultDescription() const +{ + return isNull() ? 0 : opt->default_description ; +} + +Argument Option::noArgumentValue() const +{ + if (isNull()) { + return Argument(); + } else { + return Argument(comp.lock(), opt, opt->no_arg_value, false); + } +} + +const char *Option::noArgumentDescription() const +{ + return isNull() ? 0 : opt->no_arg_description ; +} + +Argument Option::activeValue() const +{ + if (isNull()) { + return Argument(); + } else { + return Argument(comp.lock(), opt, opt->value, false); + } +} + +Argument Option::currentValue() const +{ + if (isNull()) { + return Argument(); + } + const gpgme_conf_arg_t arg = + opt->change_value ? opt->new_value ? opt->new_value : opt->default_value : + opt->value ? opt->value : + /* else */ opt->default_value ; + return Argument(comp.lock(), opt, arg, false); +} + +Argument Option::newValue() const +{ + if (isNull()) { + return Argument(); + } else { + return Argument(comp.lock(), opt, opt->new_value, false); + } +} + +bool Option::set() const +{ + if (isNull()) { + return false; + } else if (opt->change_value) { + return opt->new_value; + } else { + return opt->value; + } +} + +bool Option::dirty() const +{ + return !isNull() && opt->change_value ; +} + +Error Option::setNewValue(const Argument &argument) +{ + if (isNull()) { + return Error(make_error(GPG_ERR_INV_ARG)); + } else if (argument.isNull()) { + return resetToDefaultValue(); + } else if (const gpgme_conf_arg_t arg = mygpgme_conf_arg_copy(argument.arg, opt->alt_type)) { + return Error(gpgme_conf_opt_change(opt, 0, arg)); + } else { + return Error(make_error(GPG_ERR_ENOMEM)); + } +} + +Error Option::resetToActiveValue() +{ + if (isNull()) { + return Error(make_error(GPG_ERR_INV_ARG)); + } else { + return Error(gpgme_conf_opt_change(opt, 1, 0)); + } +} + +Error Option::resetToDefaultValue() +{ + if (isNull()) { + return Error(make_error(GPG_ERR_INV_ARG)); + } else { + return Error(gpgme_conf_opt_change(opt, 0, 0)); + } +} + +static gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const void *value) +{ + gpgme_conf_arg_t arg = 0; + if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, value)) { + return 0; + } else { + return arg; + } +} + +Argument Option::createNoneArgument(bool set) const +{ + if (isNull() || alternateType() != NoType) { + return Argument(); + } else { + if (set) { + return createNoneListArgument(1); + } + } + return Argument(); +} + +Argument Option::createStringArgument(const char *value) const +{ + if (isNull() || alternateType() != StringType) { + return Argument(); + } else { + return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true); + } +} + +Argument Option::createStringArgument(const std::string &value) const +{ + if (isNull() || alternateType() != StringType) { + return Argument(); + } else { + return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value.c_str()), true); + } +} + +Argument Option::createIntArgument(int value) const +{ + if (isNull() || alternateType() != IntegerType) { + return Argument(); + } else { + return Argument(comp.lock(), opt, make_argument(GPGME_CONF_INT32, &value), true); + } +} + +Argument Option::createUIntArgument(unsigned int value) const +{ + if (isNull() || alternateType() != UnsignedIntegerType) { + return Argument(); + } else { + return Argument(comp.lock(), opt, make_argument(GPGME_CONF_UINT32, &value), true); + } +} + +namespace +{ +const void *to_void_star(const char *s) +{ + return s; +} +const void *to_void_star(const std::string &s) +{ + return s.c_str(); +} +const void *to_void_star(const int &i) +{ + return &i; // const-&: sic! +} +const void *to_void_star(const unsigned int &i) +{ + return &i; // const-&: sic! +} + +template <typename T> +gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const std::vector<T> &value) +{ + gpgme_conf_arg_t result = 0; + gpgme_conf_arg_t last = 0; + for (typename std::vector<T>::const_iterator it = value.begin(), end = value.end() ; it != end ; ++it) { + if (gpgme_conf_arg_t arg = make_argument(type, to_void_star(*it))) { + if (last) { + last = last->next = arg; + } else { + result = last = arg; + } + } + } + return result; +} +} + +Argument Option::createNoneListArgument(unsigned int value) const +{ + if (value) { + return Argument(comp.lock(), opt, make_argument(GPGME_CONF_NONE, &value), true); + } + return Argument(); +} + +Argument Option::createStringListArgument(const std::vector<const char *> &value) const +{ + return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true); +} + +Argument Option::createStringListArgument(const std::vector<std::string> &value) const +{ + return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true); +} + +Argument Option::createIntListArgument(const std::vector<int> &value) const +{ + return Argument(comp.lock(), opt, make_argument(GPGME_CONF_INT32, value), true); +} + +Argument Option::createUIntListArgument(const std::vector<unsigned int> &value) const +{ + return Argument(comp.lock(), opt, make_argument(GPGME_CONF_UINT32, value), true); +} + +Argument::Argument(const shared_gpgme_conf_comp_t &comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg, bool owns) + : comp(comp), + opt(opt), + arg(owns ? arg : mygpgme_conf_arg_copy(arg, opt ? opt->alt_type : GPGME_CONF_NONE)) +{ + +} + +#if 0 +Argument::Argument(const shared_gpgme_conf_comp_t &comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg) + : comp(comp), + opt(opt), + arg(mygpgme_conf_arg_copy(arg, opt ? opt->alt_type : GPGME_CONF_NONE)) +{ + +} +#endif + +Argument::Argument(const Argument &other) + : comp(other.comp), + opt(other.opt), + arg(mygpgme_conf_arg_copy(other.arg, opt ? opt->alt_type : GPGME_CONF_NONE)) +{ + +} + +Argument::~Argument() +{ + gpgme_conf_arg_release(arg, opt ? opt->alt_type : GPGME_CONF_NONE); +} + +Option Argument::parent() const +{ + return Option(comp.lock(), opt); +} + +bool Argument::boolValue() const +{ + return numberOfTimesSet(); +} + +unsigned int Argument::numElements() const +{ + if (isNull()) { + return 0; + } + unsigned int result = 0; + for (gpgme_conf_arg_t a = arg ; a ; a = a->next) { + ++result; + } + return result; +} + +const char *Argument::stringValue(unsigned int idx) const +{ + if (isNull() || opt->alt_type != GPGME_CONF_STRING) { + return 0; + } + gpgme_conf_arg_t a = arg; + while (a && idx) { + a = a->next; + --idx; + } + return a ? a->value.string : 0 ; +} + +int Argument::intValue(unsigned int idx) const +{ + if (isNull() || opt->alt_type != GPGME_CONF_INT32) { + return 0; + } + gpgme_conf_arg_t a = arg; + while (a && idx) { + a = a->next; + --idx; + } + return a ? a->value.int32 : 0 ; +} + +unsigned int Argument::uintValue(unsigned int idx) const +{ + if (isNull() || opt->alt_type != GPGME_CONF_UINT32) { + return 0; + } + gpgme_conf_arg_t a = arg; + while (a && idx) { + a = a->next; + --idx; + } + return a ? a->value.uint32 : 0 ; +} + +unsigned int Argument::numberOfTimesSet() const +{ + if (isNull() || opt->alt_type != GPGME_CONF_NONE) { + return 0; + } + return arg->value.count; +} + +std::vector<const char *> Argument::stringValues() const +{ + if (isNull() || opt->alt_type != GPGME_CONF_STRING) { + return std::vector<const char *>(); + } + std::vector<const char *> result; + for (gpgme_conf_arg_t a = arg ; a ; a = a->next) { + result.push_back(a->value.string); + } + return result; +} + +std::vector<int> Argument::intValues() const +{ + if (isNull() || opt->alt_type != GPGME_CONF_INT32) { + return std::vector<int>(); + } + std::vector<int> result; + for (gpgme_conf_arg_t a = arg ; a ; a = a->next) { + result.push_back(a->value.int32); + } + return result; +} + +std::vector<unsigned int> Argument::uintValues() const +{ + if (isNull() || opt->alt_type != GPGME_CONF_UINT32) { + return std::vector<unsigned int>(); + } + std::vector<unsigned int> result; + for (gpgme_conf_arg_t a = arg ; a ; a = a->next) { + result.push_back(a->value.uint32); + } + return result; +} + +std::ostream &Configuration::operator<<(std::ostream &os, Level level) +{ + switch (level) { + case Basic: return os << "Basic"; + case Advanced: return os << "Advanced"; + case Expert: return os << "Expert"; + case Invisible: return os << "Invisible"; + case Internal: return os << "Internal"; + case NumLevels: ; + } + return os << "<unknown>"; +} + +std::ostream &Configuration::operator<<(std::ostream &os, Type type) +{ + switch (type) { + case NoType: return os << "None"; + case StringType: return os << "String"; + case IntegerType: return os << "Integer"; + case UnsignedIntegerType: return os << "UnsignedInteger"; + case FilenameType: return os << "Filename"; + case LdapServerType: return os << "LdapServer"; + case KeyFingerprintType: return os << "KeyFingerprint"; + case PublicKeyType: return os << "PublicKey"; + case SecretKeyType: return os << "SecretKey"; + case AliasListType: return os << "AliasList"; + case MaxType: ; + } + return os << "<unknown>"; +} + +std::ostream &Configuration::operator<<(std::ostream &os, Flag f) +{ + unsigned int flags = f; + std::vector<const char *> s; + if (flags & Group) { + s.push_back("Group"); + } + if (flags & Optional) { + s.push_back("Optional"); + } + if (flags & List) { + s.push_back("List"); + } + if (flags & Runtime) { + s.push_back("Runtime"); + } + if (flags & Default) { + s.push_back("Default"); + } + if (flags & DefaultDescription) { + s.push_back("DefaultDescription"); + } + if (flags & NoArgumentDescription) { + s.push_back("NoArgumentDescription"); + } + if (flags & NoChange) { + s.push_back("NoChange"); + } + flags &= ~(Group | Optional | List | Runtime | Default | DefaultDescription | NoArgumentDescription | NoChange); + if (flags) { + s.push_back("other flags("); + } + std::copy(s.begin(), s.end(), + std::ostream_iterator<const char *>(os, "|")); + if (flags) { + os << flags << ')'; + } + return os; +} + +std::ostream &Configuration::operator<<(std::ostream &os, const Component &c) +{ + os << "Component[" + << "\n name : " << protect(c.name()) + << "\n description: " << protect(c.description()) + << "\n programName: " << protect(c.programName()) + << "\n options : \n"; + const std::vector<Option> options = c.options(); + std::copy(options.begin(), options.end(), + std::ostream_iterator<Option>(os, "\n")); + os << "\n]"; + return os; +} + +std::ostream &Configuration::operator<<(std::ostream &os, const Option &o) +{ + return os << "Option[" + << "\n name: : " << protect(o.name()) + << "\n description : " << protect(o.description()) + << "\n argName : " << protect(o.argumentName()) + << "\n flags : " << static_cast<Flag>(o.flags()) + << "\n level : " << o.level() + << "\n type : " << o.type() + << "\n alt_type : " << o.alternateType() + << "\n default_val : " << o.defaultValue() + << "\n default_desc: " << protect(o.defaultDescription()) + << "\n no_arg_value: " << o.noArgumentValue() + << "\n no_arg_desc : " << protect(o.noArgumentDescription()) + << "\n active_value: " << o.activeValue() + << "\n new_value : " << o.newValue() + << "\n --> cur_val : " << o.currentValue() + << "\n set : " << o.set() + << "\n dirty : " << o.dirty() + << "\n]" + ; +} + +std::ostream &Configuration::operator<<(std::ostream &os, const Argument &a) +{ + const Option o = a.parent(); + const bool list = o.flags() & List; + os << "Argument["; + if (a) { + switch (o.alternateType()) { + case NoType: + if (list) { + os << a.numberOfTimesSet() << 'x'; + } else { + os << a.boolValue(); + } + break; + default: + case StringType: + if (list) { + const std::vector<const char *> v = a.stringValues(); + os << v.size() << ':'; + // can't use std::copy + ostream_iterator here, since we need the protect() call + bool first = true; + std::for_each(v.begin(), v.end(), [&first, &os](const char *s) { + if (first) { + first = false; + } else { + os << ','; + } + os << protect(s); + }); + } else { + os << protect(a.stringValue()); + } + break; + case IntegerType: + if (list) { + const std::vector<int> v = a.intValues(); + os << v.size() << ':'; + std::copy(v.begin(), v.end(), + std::ostream_iterator<int>(os, ",")); + } else { + os << a.intValue(); + } + break; + case UnsignedIntegerType: + if (list) { + const std::vector<unsigned int> v = a.uintValues(); + os << v.size() << ':'; + std::copy(v.begin(), v.end(), + std::ostream_iterator<unsigned int>(os, ",")); + } else { + os << a.intValue(); + } + break; + } + } + return os << ']'; +} |