diff --git a/lang/python/gpgme.i b/lang/python/gpgme.i index 1e4c9ff6..65cd2352 100644 --- a/lang/python/gpgme.i +++ b/lang/python/gpgme.i @@ -302,11 +302,14 @@ // Include mapper for edit callbacks %typemap(in) (gpgme_edit_cb_t fnc, void *fnc_value) { + if (! PyTuple_Check($input)) + return PyErr_Format(PyExc_TypeError, "edit callback must be a tuple"); + if (PyTuple_Size($input) != 2 && PyTuple_Size($input) != 3) + return PyErr_Format(PyExc_TypeError, + "edit callback must be a tuple of size 2 or 3"); + $1 = (gpgme_edit_cb_t) pyEditCb; - if ($input == Py_None) - $2 = NULL; - else - $2 = $input; + $2 = $input; } /* Include the unmodified for cc, and the cleaned-up local @@ -355,8 +358,6 @@ struct _gpgme_sig_notation %pointer_functions(gpgme_error_t, gpgme_error_t_p); %pointer_functions(gpgme_trust_item_t, gpgme_trust_item_t_p); %pointer_functions(gpgme_engine_info_t, gpgme_engine_info_t_p); -%pointer_functions(PyObject *, PyObject_p_p); -%pointer_functions(void *, void_p_p); // Helper functions. @@ -374,6 +375,18 @@ pygpgme_wrap_gpgme_data_t(gpgme_data_t data) { return SWIG_NewPointerObj(data, SWIGTYPE_p_gpgme_data, 0); } + +gpgme_ctx_t +pygpgme_unwrap_gpgme_ctx_t(PyObject *wrapped) +{ + gpgme_ctx_t result; + if (SWIG_ConvertPtr(wrapped, + (void **) &result, + SWIGTYPE_p_gpgme_context, + SWIG_POINTER_EXCEPTION) == -1) + return NULL; + return result; +} %} %include "helpers.h" diff --git a/lang/python/helpers.c b/lang/python/helpers.c index ad33d07b..5380ff26 100644 --- a/lang/python/helpers.c +++ b/lang/python/helpers.c @@ -76,10 +76,6 @@ gpgme_error_t pygpgme_exception2code(void) { return err_status; } -void pygpgme_clear_generic_cb(PyObject **cb) { - Py_DECREF(*cb); -} - /* Exception support for callbacks. */ #define EXCINFO "_callback_excinfo" @@ -293,6 +289,7 @@ static gpgme_error_t pyPassphraseCb(void *hook, pygpgme_exception_init(); assert (PyTuple_Check(pyhook)); + assert (PyTuple_Size(pyhook) == 2 || PyTuple_Size(pyhook) == 3); self = PyTuple_GetItem(pyhook, 0); func = PyTuple_GetItem(pyhook, 1); if (PyTuple_Size(pyhook) == 3) { @@ -374,15 +371,47 @@ static gpgme_error_t pyPassphraseCb(void *hook, return err_status; } -void pygpgme_set_passphrase_cb(gpgme_ctx_t ctx, PyObject *cb, - PyObject **freelater) { +PyObject * +pygpgme_set_passphrase_cb(PyObject *self, PyObject *cb) { + PyObject *wrapped; + gpgme_ctx_t ctx; + + wrapped = PyObject_GetAttrString(self, "wrapped"); + if (wrapped == NULL) + { + assert (PyErr_Occurred ()); + return NULL; + } + + ctx = pygpgme_unwrap_gpgme_ctx_t(wrapped); + Py_DECREF(wrapped); + if (ctx == NULL) + { + if (cb == Py_None) + goto out; + else + return PyErr_Format(PyExc_RuntimeError, "wrapped is NULL"); + } + if (cb == Py_None) { gpgme_set_passphrase_cb(ctx, NULL, NULL); - return; + PyObject_SetAttrString(self, "_passphrase_cb", Py_None); + goto out; } - Py_INCREF(cb); - *freelater = cb; - gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t)pyPassphraseCb, (void *) cb); + + if (! PyTuple_Check(cb)) + return PyErr_Format(PyExc_TypeError, "cb must be a tuple"); + if (PyTuple_Size(cb) != 2 && PyTuple_Size(cb) != 3) + return PyErr_Format(PyExc_TypeError, + "cb must be a tuple of size 2 or 3"); + + gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t) pyPassphraseCb, + (void *) cb); + PyObject_SetAttrString(self, "_passphrase_cb", cb); + + out: + Py_INCREF(Py_None); + return Py_None; } static void pyProgressCb(void *hook, const char *what, int type, int current, @@ -392,6 +421,7 @@ static void pyProgressCb(void *hook, const char *what, int type, int current, PyObject *self = NULL; assert (PyTuple_Check(pyhook)); + assert (PyTuple_Size(pyhook) == 2 || PyTuple_Size(pyhook) == 3); self = PyTuple_GetItem(pyhook, 0); func = PyTuple_GetItem(pyhook, 1); if (PyTuple_Size(pyhook) == 3) { @@ -423,14 +453,46 @@ static void pyProgressCb(void *hook, const char *what, int type, int current, Py_XDECREF(retval); } -void pygpgme_set_progress_cb(gpgme_ctx_t ctx, PyObject *cb, PyObject **freelater){ +PyObject * +pygpgme_set_progress_cb(PyObject *self, PyObject *cb) { + PyObject *wrapped; + gpgme_ctx_t ctx; + + wrapped = PyObject_GetAttrString(self, "wrapped"); + if (wrapped == NULL) + { + assert (PyErr_Occurred ()); + return NULL; + } + + ctx = pygpgme_unwrap_gpgme_ctx_t(wrapped); + Py_DECREF(wrapped); + if (ctx == NULL) + { + if (cb == Py_None) + goto out; + else + return PyErr_Format(PyExc_RuntimeError, "wrapped is NULL"); + } + if (cb == Py_None) { gpgme_set_progress_cb(ctx, NULL, NULL); - return; + PyObject_SetAttrString(self, "_progress_cb", Py_None); + goto out; } - Py_INCREF(cb); - *freelater = cb; + + if (! PyTuple_Check(cb)) + return PyErr_Format(PyExc_TypeError, "cb must be a tuple"); + if (PyTuple_Size(cb) != 2 && PyTuple_Size(cb) != 3) + return PyErr_Format(PyExc_TypeError, + "cb must be a tuple of size 2 or 3"); + gpgme_set_progress_cb(ctx, (gpgme_progress_cb_t) pyProgressCb, (void *) cb); + PyObject_SetAttrString(self, "_progress_cb", cb); + + out: + Py_INCREF(Py_None); + return Py_None; } /* Status callbacks. */ @@ -488,15 +550,46 @@ static gpgme_error_t pyStatusCb(void *hook, const char *keyword, return err; } -void pygpgme_set_status_cb(gpgme_ctx_t ctx, PyObject *cb, - PyObject **freelater) { +PyObject * +pygpgme_set_status_cb(PyObject *self, PyObject *cb) { + PyObject *wrapped; + gpgme_ctx_t ctx; + + wrapped = PyObject_GetAttrString(self, "wrapped"); + if (wrapped == NULL) + { + assert (PyErr_Occurred ()); + return NULL; + } + + ctx = pygpgme_unwrap_gpgme_ctx_t(wrapped); + Py_DECREF(wrapped); + if (ctx == NULL) + { + if (cb == Py_None) + goto out; + else + return PyErr_Format(PyExc_RuntimeError, "wrapped is NULL"); + } + if (cb == Py_None) { gpgme_set_status_cb(ctx, NULL, NULL); - return; + PyObject_SetAttrString(self, "_status_cb", Py_None); + goto out; } - Py_INCREF(cb); - *freelater = cb; + + if (! PyTuple_Check(cb)) + return PyErr_Format(PyExc_TypeError, "cb must be a tuple"); + if (PyTuple_Size(cb) != 2 && PyTuple_Size(cb) != 3) + return PyErr_Format(PyExc_TypeError, + "cb must be a tuple of size 2 or 3"); + gpgme_set_status_cb(ctx, (gpgme_status_cb_t) pyStatusCb, (void *) cb); + PyObject_SetAttrString(self, "_status_cb", cb); + + out: + Py_INCREF(Py_None); + return Py_None; } /* Edit callbacks. */ @@ -775,9 +868,10 @@ static void pyDataReleaseCb(void *hook) pygpgme_stash_callback_exception(self); } -gpgme_error_t pygpgme_data_new_from_cbs(gpgme_data_t *r_data, - PyObject *pycbs, - PyObject **freelater) +PyObject * +pygpgme_data_new_from_cbs(PyObject *self, + PyObject *pycbs, + gpgme_data_t *r_data) { static struct gpgme_data_cbs cbs = { pyDataReadCb, @@ -785,12 +879,20 @@ gpgme_error_t pygpgme_data_new_from_cbs(gpgme_data_t *r_data, pyDataSeekCb, pyDataReleaseCb, }; + gpgme_error_t err; - assert (PyTuple_Check(pycbs)); - assert (PyTuple_Size(pycbs) == 5 || PyTuple_Size(pycbs) == 6); + if (! PyTuple_Check(pycbs)) + return PyErr_Format(PyExc_TypeError, "pycbs must be a tuple"); + if (PyTuple_Size(pycbs) != 5 && PyTuple_Size(pycbs) != 6) + return PyErr_Format(PyExc_TypeError, + "pycbs must be a tuple of size 5 or 6"); - Py_INCREF(pycbs); - *freelater = pycbs; + err = gpgme_data_new_from_cbs(r_data, &cbs, (void *) pycbs); + if (err) + return pygpgme_raise_exception(err); - return gpgme_data_new_from_cbs(r_data, &cbs, (void *) pycbs); + PyObject_SetAttrString(self, "_data_cbs", pycbs); + + Py_INCREF(Py_None); + return Py_None; } diff --git a/lang/python/helpers.h b/lang/python/helpers.h index 37362aee..15642903 100644 --- a/lang/python/helpers.h +++ b/lang/python/helpers.h @@ -34,21 +34,18 @@ PyObject *object_to_gpgme_data_t(PyObject *input, int argnum, gpgme_data_t *wrapper, PyObject **bytesio, Py_buffer *view); -void pygpgme_clear_generic_cb(PyObject **cb); PyObject *pygpgme_raise_callback_exception(PyObject *self); -void pygpgme_set_passphrase_cb(gpgme_ctx_t ctx, PyObject *cb, - PyObject **freelater); -void pygpgme_set_progress_cb(gpgme_ctx_t ctx, PyObject *cb, PyObject **freelater); -void pygpgme_set_status_cb(gpgme_ctx_t ctx, PyObject *cb, - PyObject **freelater); +PyObject *pygpgme_set_passphrase_cb(PyObject *self, PyObject *cb); +PyObject *pygpgme_set_progress_cb(PyObject *self, PyObject *cb); +PyObject *pygpgme_set_status_cb(PyObject *self, PyObject *cb); gpgme_error_t pyEditCb(void *opaque, gpgme_status_code_t status, const char *args, int fd); -gpgme_error_t pygpgme_data_new_from_cbs(gpgme_data_t *r_data, - PyObject *pycbs, - PyObject **freelater); +PyObject *pygpgme_data_new_from_cbs(PyObject *self, PyObject *pycbs, + gpgme_data_t *r_data); /* SWIG support for helpers.c */ PyObject *pygpgme_wrap_gpgme_data_t(gpgme_data_t data); +gpgme_ctx_t pygpgme_unwrap_gpgme_ctx_t(PyObject *wrapped); diff --git a/lang/python/pyme/core.py b/lang/python/pyme/core.py index 64dc7878..e5a50617 100644 --- a/lang/python/pyme/core.py +++ b/lang/python/pyme/core.py @@ -220,9 +220,6 @@ class Context(GpgmeWrapper): pygpgme.delete_gpgme_ctx_t_p(tmp) self.own = True super().__init__(wrapped) - self.last_passcb = None - self.last_progresscb = None - self.last_statuscb = None self.armor = armor self.textmode = textmode self.offline = offline @@ -247,30 +244,6 @@ class Context(GpgmeWrapper): def __exit__(self, type, value, tb): self.__del__() - def _free_passcb(self): - if self.last_passcb != None: - if pygpgme.pygpgme_clear_generic_cb: - pygpgme.pygpgme_clear_generic_cb(self.last_passcb) - if pygpgme.delete_PyObject_p_p: - pygpgme.delete_PyObject_p_p(self.last_passcb) - self.last_passcb = None - - def _free_progresscb(self): - if self.last_progresscb != None: - if pygpgme.pygpgme_clear_generic_cb: - pygpgme.pygpgme_clear_generic_cb(self.last_progresscb) - if pygpgme.delete_PyObject_p_p: - pygpgme.delete_PyObject_p_p(self.last_progresscb) - self.last_progresscb = None - - def _free_statuscb(self): - if self.last_statuscb != None: - if pygpgme.pygpgme_clear_generic_cb: - pygpgme.pygpgme_clear_generic_cb(self.last_statuscb) - if pygpgme.delete_PyObject_p_p: - pygpgme.delete_PyObject_p_p(self.last_statuscb) - self.last_statuscb = None - def op_keylist_all(self, *args, **kwargs): self.op_keylist_start(*args, **kwargs) key = self.op_keylist_next() @@ -341,16 +314,18 @@ class Context(GpgmeWrapper): Please see the GPGME manual for more information. """ - self._free_passcb() if func == None: hookdata = None else: - self.last_passcb = pygpgme.new_PyObject_p_p() if hook == None: hookdata = (weakref.ref(self), func) else: hookdata = (weakref.ref(self), func, hook) - pygpgme.pygpgme_set_passphrase_cb(self.wrapped, hookdata, self.last_passcb) + pygpgme.pygpgme_set_passphrase_cb(self, hookdata) + + def _free_passcb(self): + if pygpgme.pygpgme_set_passphrase_cb: + self.set_passphrase_cb(None) def set_progress_cb(self, func, hook=None): """Sets the progress meter callback to the function specified by FUNC. @@ -364,16 +339,18 @@ class Context(GpgmeWrapper): Please see the GPGME manual for more information. """ - self._free_progresscb() if func == None: hookdata = None else: - self.last_progresscb = pygpgme.new_PyObject_p_p() if hook == None: hookdata = (weakref.ref(self), func) else: hookdata = (weakref.ref(self), func, hook) - pygpgme.pygpgme_set_progress_cb(self.wrapped, hookdata, self.last_progresscb) + pygpgme.pygpgme_set_progress_cb(self, hookdata) + + def _free_progresscb(self): + if pygpgme.pygpgme_set_progress_cb: + self.set_progress_cb(None) def set_status_cb(self, func, hook=None): """Sets the status callback to the function specified by FUNC. If @@ -386,17 +363,18 @@ class Context(GpgmeWrapper): Please see the GPGME manual for more information. """ - self._free_statuscb() if func == None: hookdata = None else: - self.last_statuscb = pygpgme.new_PyObject_p_p() if hook == None: hookdata = (weakref.ref(self), func) else: hookdata = (weakref.ref(self), func, hook) - pygpgme.pygpgme_set_status_cb(self.wrapped, hookdata, - self.last_statuscb) + pygpgme.pygpgme_set_status_cb(self, hookdata) + + def _free_statuscb(self): + if pygpgme.pygpgme_set_status_cb: + self.set_status_cb(None) def get_engine_info(self): """Returns this context specific engine info""" @@ -547,12 +525,7 @@ class Data(GpgmeWrapper): self.__del__() def _free_datacbs(self): - if self.data_cbs != None: - if pygpgme.pygpgme_clear_generic_cb: - pygpgme.pygpgme_clear_generic_cb(self.data_cbs) - if pygpgme.delete_PyObject_p_p: - pygpgme.delete_PyObject_p_p(self.data_cbs) - self.data_cbs = None + self._data_cbs = None def new(self): tmp = pygpgme.new_gpgme_data_t_p() @@ -579,8 +552,6 @@ class Data(GpgmeWrapper): pygpgme.delete_gpgme_data_t_p(tmp) def new_from_cbs(self, read_cb, write_cb, seek_cb, release_cb, hook=None): - assert self.data_cbs == None - self.data_cbs = pygpgme.new_PyObject_p_p() tmp = pygpgme.new_gpgme_data_t_p() if hook != None: hookdata = (weakref.ref(self), @@ -588,8 +559,7 @@ class Data(GpgmeWrapper): else: hookdata = (weakref.ref(self), read_cb, write_cb, seek_cb, release_cb) - errorcheck( - pygpgme.pygpgme_data_new_from_cbs(tmp, hookdata, self.data_cbs)) + pygpgme.pygpgme_data_new_from_cbs(self, hookdata, tmp) self.wrapped = pygpgme.gpgme_data_t_p_value(tmp) pygpgme.delete_gpgme_data_t_p(tmp)