diff options
Diffstat (limited to 'lang/python/gpgme.i')
-rw-r--r-- | lang/python/gpgme.i | 625 |
1 files changed, 625 insertions, 0 deletions
diff --git a/lang/python/gpgme.i b/lang/python/gpgme.i new file mode 100644 index 0000000..84addae --- /dev/null +++ b/lang/python/gpgme.i @@ -0,0 +1,625 @@ +/* +# Copyright (C) 2016 g10 Code GmbH +# Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net> +# Copyright (C) 2002 John Goerzen <jgoerzen@complete.org> +# +# This library 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. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +%module gpgme +%include "cpointer.i" +%include "cstring.i" + +/* Generate doc strings for all methods. + + This will generate docstrings of the form + + gpgme_op_encrypt(ctx, recp, flags, plain, cipher) -> gpgme_error_t + + which we transform into + + ctx.op_encrypt(recp, flags, plain, cipher) -> gpgme_error_t + + for automagically wrapped functions. */ +%feature("autodoc", "0"); + + +/* Allow use of Unicode objects, bytes, and None for strings. */ +%typemap(in) const char *(PyObject *encodedInput = NULL) { + if ($input == Py_None) + $1 = NULL; + else if (PyUnicode_Check($input)) + { + encodedInput = PyUnicode_AsUTF8String($input); + if (encodedInput == NULL) + return NULL; + $1 = PyBytes_AsString(encodedInput); + } + else if (PyBytes_Check($input)) + $1 = PyBytes_AsString($input); + else { + PyErr_Format(PyExc_TypeError, + "arg %d: expected str, bytes, or None, got %s", + $argnum, $input->ob_type->tp_name); + return NULL; + } +} +%typemap(freearg) const char * { + Py_XDECREF(encodedInput$argnum); +} + +/* Likewise for a list of strings. */ +%typemap(in) const char *[] (void *vector = NULL, + size_t size, + PyObject **pyVector = NULL) { + /* Check if is a list */ + if (PyList_Check($input)) { + size_t i, j; + size = PyList_Size($input); + $1 = (char **) (vector = malloc((size+1) * sizeof(char *))); + pyVector = calloc(sizeof *pyVector, size); + + for (i = 0; i < size; i++) { + PyObject *o = PyList_GetItem($input,i); + if (PyUnicode_Check(o)) + { + pyVector[i] = PyUnicode_AsUTF8String(o); + if (pyVector[i] == NULL) + { + free(vector); + for (j = 0; j < i; j++) + Py_XDECREF(pyVector[j]); + return NULL; + } + $1[i] = PyBytes_AsString(pyVector[i]); + } + else if (PyString_Check(o)) + $1[i] = PyString_AsString(o); + else { + PyErr_Format(PyExc_TypeError, + "arg %d: list must contain only str or bytes, got %s " + "at position %d", + $argnum, o->ob_type->tp_name, i); + free($1); + return NULL; + } + } + $1[i] = NULL; + } else { + PyErr_Format(PyExc_TypeError, + "arg %d: expected a list of str or bytes, got %s", + $argnum, $input->ob_type->tp_name); + return NULL; + } +} +%typemap(freearg) const char *[] { + size_t i; + free(vector$argnum); + for (i = 0; i < size$argnum; i++) + Py_XDECREF(pyVector$argnum[i]); +} + +// Release returned buffers as necessary. +%typemap(newfree) char * "free($1);"; +%newobject gpgme_data_release_and_get_mem; + +%typemap(arginit) gpgme_key_t [] { + $1 = NULL; +} + +%typemap(in) gpgme_key_t [] { + int i, numb = 0; + if (!PySequence_Check($input)) { + PyErr_Format(PyExc_ValueError, "arg %d: Expected a list of gpgme_key_t", + $argnum); + return NULL; + } + if((numb = PySequence_Length($input)) != 0) { + $1 = (gpgme_key_t*)malloc((numb+1)*sizeof(gpgme_key_t)); + for(i=0; i<numb; i++) { + PyObject *pypointer = PySequence_GetItem($input, i); + + /* input = $input, 1 = $1, 1_descriptor = $1_descriptor */ + /* &1_descriptor = $&1_descriptor *1_descriptor = $*1_descriptor */ + + // Following code is from swig's python.swg + if ((SWIG_ConvertPtr(pypointer,(void **) &$1[i], $*1_descriptor,SWIG_POINTER_EXCEPTION | $disown )) == -1) { + Py_DECREF(pypointer); + return NULL; + } + Py_DECREF(pypointer); + } + $1[numb] = NULL; + } +} +%typemap(freearg) gpgme_key_t [] { + if ($1) free($1); +} + +// Special handling for references to our objects. +%typemap(in) gpgme_data_t DATAIN (gpgme_data_t wrapper = NULL, + PyObject *bytesio = NULL, + Py_buffer view, int have_view = 0) { + /* If we create a temporary wrapper object, we will store it in + wrapperN, where N is $argnum. Here in this fragment, SWIG will + automatically append $argnum. */ + memset(&view, 0, sizeof view); + if ($input == Py_None) + $1 = NULL; + else { + PyObject *pypointer; + pypointer = _pyme_obj2gpgme_data_t($input, $argnum, &wrapper, + &bytesio, &view); + if (pypointer == NULL) + return NULL; + have_view = !! view.obj; + + /* input = $input, 1 = $1, 1_descriptor = $1_descriptor */ + + // Following code is from swig's python.swg + + if ((SWIG_ConvertPtr(pypointer,(void **) &$1, $1_descriptor, + SWIG_POINTER_EXCEPTION | $disown )) == -1) { + Py_DECREF(pypointer); + return NULL; + } + Py_DECREF(pypointer); + } +} + +#if HAVE_DATA_H +/* If we are doing an in-tree build, we can use the internal + representation of struct gpgme_data for an very efficient check if + the buffer has been modified. */ +%{ +#include "src/data.h" /* For struct gpgme_data. */ +%} +#endif + +%typemap(freearg) gpgme_data_t DATAIN { + /* See whether we need to update the Python buffer. */ + if (resultobj && wrapper$argnum && view$argnum.buf) + { + int dirty; + char *new_data = NULL; + size_t new_size; + +#if HAVE_DATA_H + new_data = wrapper$argnum->data.mem.buffer; + new_size = wrapper$argnum->data.mem.length; + dirty = new_data != NULL; +#else + new_data = gpgme_data_release_and_get_mem (wrapper$argnum, &new_size); + wrapper$argnum = NULL; + dirty = new_size != view$argnum.len + || memcmp (new_data, view$argnum.buf, view$argnum.len); +#endif + + if (dirty) + { + /* The buffer is dirty. */ + if (view$argnum.readonly) + { + Py_XDECREF(resultobj); + resultobj = NULL; + PyErr_SetString(PyExc_ValueError, + "cannot update read-only buffer"); + } + + /* See if we need to truncate the buffer. */ + if (resultobj && view$argnum.len != new_size) + { + if (bytesio$argnum == NULL) + { + Py_XDECREF(resultobj); + resultobj = NULL; + PyErr_SetString(PyExc_ValueError, "cannot resize buffer"); + } + else + { + PyObject *retval; + PyBuffer_Release(&view$argnum); + assert(view$argnum.obj == NULL); + retval = PyObject_CallMethod(bytesio$argnum, "truncate", + "l", (long) new_size); + if (retval == NULL) + { + Py_XDECREF(resultobj); + resultobj = NULL; + } + else + { + Py_DECREF(retval); + + retval = PyObject_CallMethod(bytesio$argnum, + "getbuffer", NULL); + if (retval == NULL + || PyObject_GetBuffer(retval, &view$argnum, + PyBUF_SIMPLE|PyBUF_WRITABLE) < 0) + { + Py_XDECREF(resultobj); + resultobj = NULL; + } + + Py_XDECREF(retval); + + if (resultobj && view$argnum.len + != new_size) + { + Py_XDECREF(resultobj); + resultobj = NULL; + PyErr_Format(PyExc_ValueError, + "Expected buffer of length %zu, got %zi", + new_size, + view$argnum.len); + } + } + } + } + if (resultobj) + memcpy(view$argnum.buf, new_data, new_size); + } +#if ! HAVE_DATA_H + free (new_data); +#endif + } + + /* Free the temporary wrapper, if any. */ + if (wrapper$argnum) + gpgme_data_release(wrapper$argnum); + Py_XDECREF (bytesio$argnum); + if (have_view$argnum && view$argnum.buf) + PyBuffer_Release(&view$argnum); +} + +%apply gpgme_data_t DATAIN {gpgme_data_t plain, gpgme_data_t cipher, + gpgme_data_t sig, gpgme_data_t signed_text, + gpgme_data_t plaintext, gpgme_data_t keydata, + gpgme_data_t pubkey, gpgme_data_t seckey, + gpgme_data_t out}; + +/* SWIG has problems interpreting ssize_t, off_t or gpgme_error_t in + gpgme.h. */ +/* XXX: This is wrong at least for off_t if compiled with LFS. */ +%typemap(out) ssize_t, off_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t { + $result = PyLong_FromLong($1); +} +/* XXX: This is wrong at least for off_t if compiled with LFS. */ +%typemap(in) ssize_t, off_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t { + $1 = PyLong_AsLong($input); +} + +// Those are for gpgme_data_read() and gpgme_strerror_r() +%typemap(in) (void *buffer, size_t size), (char *buf, size_t buflen) { + $2 = PyLong_AsLong($input); + if ($2 < 0) { + PyErr_SetString(PyExc_ValueError, "Positive integer expected"); + return NULL; + } + $1 = ($1_ltype) malloc($2+1); +} +%typemap(argout) (void *buffer, size_t size), (char *buf, size_t buflen) { + Py_XDECREF($result); /* Blow away any previous result */ + if (result < 0) { /* Check for I/O error */ + free($1); + return PyErr_SetFromErrno(PyExc_RuntimeError); + } + $result = PyBytes_FromStringAndSize($1,result); + free($1); +} + +/* For gpgme_data_write, but should be universal. */ +%typemap(in) (const void *buffer, size_t size)(PyObject *encodedInput = NULL) { + Py_ssize_t ssize; + + if ($input == Py_None) + $1 = NULL, $2 = 0; + else if (PyUnicode_Check($input)) + { + encodedInput = PyUnicode_AsUTF8String($input); + if (encodedInput == NULL) + return NULL; + if (PyBytes_AsStringAndSize(encodedInput, (char **) &$1, &ssize) == -1) + { + Py_DECREF(encodedInput); + return NULL; + } + } + else if (PyBytes_Check($input)) + PyBytes_AsStringAndSize($input, (char **) &$1, &ssize); + else { + PyErr_Format(PyExc_TypeError, + "arg %d: expected str, bytes, or None, got %s", + $argnum, $input->ob_type->tp_name); + return NULL; + } + + if (! $1) + $2 = 0; + else + { + assert (ssize >= 0); + $2 = (size_t) ssize; + } +} +%typemap(freearg) (const void *buffer, size_t size) { + Py_XDECREF(encodedInput$argnum); +} + +// Make types containing 'next' field to be lists +%ignore next; +%typemap(out) gpgme_sig_notation_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; + for (curr = $1; curr != NULL; curr = curr->next) { + size++; + } + $result = PyList_New(size); + for (i=0,curr=$1; i<size; i++,curr=curr->next) { + PyObject *o = SWIG_NewPointerObj(SWIG_as_voidptr(curr), $1_descriptor, %newpointer_flags); + PyList_SetItem($result, i, o); + } +} + + + +/* 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 = _pyme_wrap_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 = _pyme_wrap_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 = _pyme_wrap_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 = _pyme_wrap_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 = _pyme_wrap_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 = _pyme_wrap_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 = _pyme_wrap_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 = _pyme_wrap_result(fragile, "VFSMountResult"); + Py_DECREF(fragile); +} + +%typemap(out) gpgme_engine_info_t { + int i; + int size = 0; + $1_ltype curr; + for (curr = $1; curr != NULL; curr = curr->next) { + size++; + } + $result = PyList_New(size); + if ($result == NULL) + return NULL; /* raise */ + for (i=0,curr=$1; i<size; i++,curr=curr->next) { + PyObject *fragile, *o; + fragile = SWIG_NewPointerObj(SWIG_as_voidptr(curr), $1_descriptor, + %newpointer_flags); + if (fragile == NULL) + { + Py_DECREF($result); + return NULL; /* raise */ + } + o = _pyme_wrap_result(fragile, "EngineInfo"); + Py_DECREF(fragile); + if (o == NULL) + { + Py_DECREF($result); + return NULL; /* raise */ + } + PyList_SetItem($result, i, o); + } +} + + + +/* Include mapper for interact callbacks. */ +%typemap(in) (gpgme_interact_cb_t fnc, void *fnc_value) { + if (! PyTuple_Check($input)) + return PyErr_Format(PyExc_TypeError, "interact callback must be a tuple"); + if (PyTuple_Size($input) != 2 && PyTuple_Size($input) != 3) + return PyErr_Format(PyExc_TypeError, + "interact callback must be a tuple of size 2 or 3"); + + $1 = (gpgme_interact_cb_t) _pyme_interact_cb; + $2 = $input; +} + + + +/* The assuan protocol callbacks. */ +%typemap(in) (gpgme_assuan_data_cb_t data_cb, void *data_cb_value) { + if ($input == Py_None) + $1 = $2 = NULL; + else + { + if (! PyTuple_Check($input)) + return PyErr_Format(PyExc_TypeError, "callback must be a tuple"); + if (PyTuple_Size($input) != 2) + return PyErr_Format(PyExc_TypeError, + "callback must be a tuple of size 2"); + if (! PyCallable_Check(PyTuple_GetItem($input, 1))) + return PyErr_Format(PyExc_TypeError, "second item must be callable"); + $1 = _pyme_assuan_data_cb; + $2 = $input; + } +} + +%typemap(in) (gpgme_assuan_inquire_cb_t inq_cb, void *inq_cb_value) { + if ($input == Py_None) + $1 = $2 = NULL; + else + { + if (! PyTuple_Check($input)) + return PyErr_Format(PyExc_TypeError, "callback must be a tuple"); + if (PyTuple_Size($input) != 2) + return PyErr_Format(PyExc_TypeError, + "callback must be a tuple of size 2"); + if (! PyCallable_Check(PyTuple_GetItem($input, 1))) + return PyErr_Format(PyExc_TypeError, "second item must be callable"); + $1 = _pyme_assuan_inquire_cb; + $2 = $input; + } +} + +%typemap(in) (gpgme_assuan_status_cb_t stat_cb, void *stat_cb_value) { + if ($input == Py_None) + $1 = $2 = NULL; + else + { + if (! PyTuple_Check($input)) + return PyErr_Format(PyExc_TypeError, "callback must be a tuple"); + if (PyTuple_Size($input) != 2) + return PyErr_Format(PyExc_TypeError, + "callback must be a tuple of size 2"); + if (! PyCallable_Check(PyTuple_GetItem($input, 1))) + return PyErr_Format(PyExc_TypeError, "second item must be callable"); + $1 = _pyme_assuan_status_cb; + $2 = $input; + } +} + +/* Include the unmodified <gpgme.h> for cc, and the cleaned-up local + version for SWIG. We do, however, want to hide certain fields on + some structs, which we provide prior to including the version for + SWIG. */ +%{ +#include <gpgme.h> +%} + +/* This is for notations, where we want to hide the length fields, and + the unused bit field block. */ +struct _gpgme_sig_notation +{ + struct _gpgme_sig_notation *next; + + /* If NAME is a null pointer, then VALUE contains a policy URL + rather than a notation. */ + char *name; + + /* The value of the notation data. */ + char *value; + + /* The accumulated flags. */ + gpgme_sig_notation_flags_t flags; + + /* Notation data is human-readable. */ + unsigned int human_readable : 1; + + /* Notation data is critical. */ + unsigned int critical : 1; +}; + +/* Now include our local modified version. Any structs defined above + are ignored. */ +%include "gpgme.h" + +%include "errors.i" + +// Generating and handling pointers-to-pointers. + +%pointer_functions(gpgme_ctx_t, gpgme_ctx_t_p); +%pointer_functions(gpgme_data_t, gpgme_data_t_p); +%pointer_functions(gpgme_key_t, gpgme_key_t_p); +%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); + +// Helper functions. + +%{ +#include <stdio.h> +%} +FILE *fdopen(int fildes, const char *mode); + +/* We include both headers in the generated c code... */ +%{ +#include "helpers.h" +#include "private.h" + +/* SWIG runtime support for helpers.c */ +PyObject * +_pyme_wrap_gpgme_data_t(gpgme_data_t data) +{ + return SWIG_Python_NewPointerObj(NULL, data, SWIGTYPE_p_gpgme_data, 0); +} + +gpgme_ctx_t +_pyme_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; +} +%} + +/* ... but only the public definitions here. They will be exposed to + the Python world, so let's be careful. */ +%include "helpers.h" |