aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lang/python/gpgme.i78
-rw-r--r--lang/python/helpers.c32
-rw-r--r--lang/python/helpers.h2
-rw-r--r--lang/python/pyme/results.py116
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