gpgme/lang/python/gpgme.i
Justus Winter 44d18200d5 python: Improve error handling.
* lang/python/gpgme.i (gpgme_engine_info_t): Improve error handling.

Signed-off-by: Justus Winter <justus@g10code.com>
2016-09-14 14:34:14 +02:00

626 lines
19 KiB
OpenEdge ABL
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
# 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 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) _pyme_edit_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"