diff options
| -rw-r--r-- | lang/python/gpgme.i | 78 | ||||
| -rw-r--r-- | lang/python/helpers.c | 32 | ||||
| -rw-r--r-- | lang/python/helpers.h | 2 | ||||
| -rw-r--r-- | lang/python/pyme/results.py | 116 | 
4 files changed, 224 insertions, 4 deletions
| diff --git a/lang/python/gpgme.i b/lang/python/gpgme.i index 9cc2022c..c6ddbb40 100644 --- a/lang/python/gpgme.i +++ b/lang/python/gpgme.i @@ -283,10 +283,11 @@  // Make types containing 'next' field to be lists  %ignore next; -%typemap(out) gpgme_sig_notation_t, gpgme_engine_info_t, gpgme_subkey_t, gpgme_key_sig_t, -	gpgme_user_id_t, gpgme_invalid_key_t, gpgme_recipient_t, gpgme_new_signature_t, -	gpgme_signature_t, gpgme_import_status_t, gpgme_conf_arg_t, gpgme_conf_opt_t, -	gpgme_conf_comp_t { +%typemap(out) gpgme_sig_notation_t, gpgme_engine_info_t, gpgme_subkey_t, +   gpgme_key_sig_t, gpgme_user_id_t, gpgme_invalid_key_t, +   gpgme_recipient_t, gpgme_new_signature_t, gpgme_signature_t, +   gpgme_import_status_t, gpgme_conf_arg_t, gpgme_conf_opt_t, +   gpgme_conf_comp_t, gpgme_tofu_info_t {    int i;    int size = 0;    $1_ltype curr; @@ -300,6 +301,75 @@    }  } + + +/* Wrap the fragile result objects into robust Python ones.  */ +%typemap(out) gpgme_encrypt_result_t { +  PyObject *fragile; +  fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, +                               %newpointer_flags); +  $result = pygpgme_wrap_fragile_result(fragile, "EncryptResult"); +  Py_DECREF(fragile); +} + +%typemap(out) gpgme_decrypt_result_t { +  PyObject *fragile; +  fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, +                               %newpointer_flags); +  $result = pygpgme_wrap_fragile_result(fragile, "DecryptResult"); +  Py_DECREF(fragile); +} + +%typemap(out) gpgme_sign_result_t { +  PyObject *fragile; +  fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, +                               %newpointer_flags); +  $result = pygpgme_wrap_fragile_result(fragile, "SignResult"); +  Py_DECREF(fragile); +} + +%typemap(out) gpgme_verify_result_t { +  PyObject *fragile; +  fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, +                               %newpointer_flags); +  $result = pygpgme_wrap_fragile_result(fragile, "VerifyResult"); +  Py_DECREF(fragile); +} + +%typemap(out) gpgme_import_result_t { +  PyObject *fragile; +  fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, +                               %newpointer_flags); +  $result = pygpgme_wrap_fragile_result(fragile, "ImportResult"); +  Py_DECREF(fragile); +} + +%typemap(out) gpgme_genkey_result_t { +  PyObject *fragile; +  fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, +                               %newpointer_flags); +  $result = pygpgme_wrap_fragile_result(fragile, "GenkeyResult"); +  Py_DECREF(fragile); +} + +%typemap(out) gpgme_keylist_result_t { +  PyObject *fragile; +  fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, +                               %newpointer_flags); +  $result = pygpgme_wrap_fragile_result(fragile, "KeylistResult"); +  Py_DECREF(fragile); +} + +%typemap(out) gpgme_vfs_mount_result_t { +  PyObject *fragile; +  fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, +                               %newpointer_flags); +  $result = pygpgme_wrap_fragile_result(fragile, "VFSMountResult"); +  Py_DECREF(fragile); +} + + +  // Include mapper for edit callbacks  %typemap(in) (gpgme_edit_cb_t fnc, void *fnc_value) {    if (! PyTuple_Check($input)) diff --git a/lang/python/helpers.c b/lang/python/helpers.c index 6de2b8de..1b661466 100644 --- a/lang/python/helpers.c +++ b/lang/python/helpers.c @@ -272,6 +272,38 @@ object_to_gpgme_data_t(PyObject *input, int argnum, gpgme_data_t *wrapper, +PyObject * +pygpgme_wrap_fragile_result(PyObject *fragile, const char *classname) +{ +  static PyObject *results; +  PyObject *class; +  PyObject *replacement; + +  if (results == NULL) +    { +      PyObject *from_list = PyList_New(0); +      if (from_list == NULL) +        return NULL; + +      results = PyImport_ImportModuleLevel("results", PyEval_GetGlobals(), +                                           PyEval_GetLocals(), from_list, 1); +      Py_DECREF(from_list); + +      if (results == NULL) +        return NULL; +    } + +  class = PyMapping_GetItemString(PyModule_GetDict(results), classname); +  if (class == NULL) +    return NULL; + +  replacement = PyObject_CallFunctionObjArgs(class, fragile, NULL); +  Py_DECREF(class); +  return replacement; +} + + +  /* Callback support.  */  static gpgme_error_t pyPassphraseCb(void *hook,  				    const char *uid_hint, diff --git a/lang/python/helpers.h b/lang/python/helpers.h index 15642903..beb2682f 100644 --- a/lang/python/helpers.h +++ b/lang/python/helpers.h @@ -34,6 +34,8 @@ PyObject *object_to_gpgme_data_t(PyObject *input, int argnum,  				 gpgme_data_t *wrapper,  				 PyObject **bytesio, Py_buffer *view); +PyObject *pygpgme_wrap_fragile_result(PyObject *fragile, const char *classname); +  PyObject *pygpgme_raise_callback_exception(PyObject *self);  PyObject *pygpgme_set_passphrase_cb(PyObject *self, PyObject *cb); diff --git a/lang/python/pyme/results.py b/lang/python/pyme/results.py new file mode 100644 index 00000000..e6e89689 --- /dev/null +++ b/lang/python/pyme/results.py @@ -0,0 +1,116 @@ +# Robust result objects +# +# Copyright (C) 2016 g10 Code 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 Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 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 Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +"""Robust result objects + +Results returned by the underlying library are fragile, i.e. they are +only valid until the next operation is performed in the context. + +We cannot arbitrarily constrain the lifetime of Python objects, we +therefore create deep copies of the results. + +""" + +class Result(object): +    """Result object + +    Describes the result of an operation. + +    """ + +    """Convert to types""" +    _type = {} + +    """Map functions over list attributes""" +    _map = {} + +    """Automatically copy unless blacklisted""" +    _blacklist = { +        'acquire', 'append', 'disown', 'next', 'own', 'this', 'thisown', +    } +    def __init__(self, fragile): +        for key, func in self._type.items(): +            setattr(self, key, func(getattr(fragile, key))) + +        for key, func in self._map.items(): +            setattr(self, key, list(map(func, getattr(fragile, key)))) + +        for key, func in self._map.items(): +            setattr(self, key, list(map(func, getattr(fragile, key)))) + +        for key in dir(fragile): +            if key.startswith('_') or key in self._blacklist: +                continue +            if hasattr(self, key): +                continue + +            setattr(self, key, getattr(fragile, key)) + +    def __str__(self): +        return '<{} {}>'.format( +            self.__class__.__name__, +            ', '.join('{}: {}'.format(k, getattr(self, k)) +                      for k in dir(self) if not k.startswith('_'))) + +class InvalidKey(Result): +    pass + +class EncryptResult(Result): +    _map = dict(invalid_recipients=InvalidKey) + +class Recipient(Result): +    pass + +class DecryptResult(Result): +    _type = dict(wrong_key_usage=bool) +    _map = dict(recipients=Recipient) + +class NewSignature(Result): +    pass + +class SignResult(Result): +    _map = dict(invalid_signers=InvalidKey, signatures=NewSignature) + +class Notation(Result): +    pass + +class TofuInfo(Result): +    pass + +class Signature(Result): +    _type = dict(wrong_key_usage=bool, chain_model=bool) +    _map = dict(notations=Notation, tofu=TofuInfo) + +class VerifyResult(Result): +    _map = dict(signatures=Signature) + +class ImportStatus(Result): +    pass + +class ImportResult(Result): +    _map = dict(imports=ImportStatus) + +class GenkeyResult(Result): +    _type = dict(primary=bool, sub=bool) + +class KeylistResult(Result): +    _type = dict(truncated=bool) + +class VFSMountResult(Result): +    pass | 
