gpgme/lang/python/gpgme.i
Tobias Mueller 3cf9aedc92
python: Default whence argument for Data() to SEEK_SET.
* lang/python/gpgme.i: copied signature from gpgme.h and defaulted the
value to SEEK_SET.
* lang/python/tests/t-data.py: Added a test for no second argument
--

Having to import the os package when wanting to read a Data object is a
slight annoyance. With SWIG, we can define default parameters. This
change defaults the whence argument to SEEK_SET which is how StringIO
and BytesIO behave.

Signed-off-by: Tobias Mueller <muelli@cryptobitch.de>
2017-12-04 08:10:06 +01:00

699 lines
20 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 * "gpgme_free($1);";
%newobject gpgme_data_release_and_get_mem;
%newobject gpgme_pubkey_algo_string;
%newobject gpgme_addrspec_from_uid;
%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);
PyErr_Format(PyExc_TypeError,
"arg %d: list must contain only gpgme_key_ts, got %s "
"at position %d",
$argnum, pypointer->ob_type->tp_name, i);
free($1);
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 = _gpg_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 "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, gpgme_data_t data};
/* SWIG has problems interpreting ssize_t, off_t or gpgme_error_t in
gpgme.h. */
%typemap(out) ssize_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t {
$result = PyLong_FromLong($1);
}
%typemap(in) ssize_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t {
if (PyLong_Check($input))
$1 = PyLong_AsLong($input);
#if PY_MAJOR_VERSION < 3
else if (PyInt_Check($input))
$1 = PyInt_AsLong($input);
#endif
else
PyErr_SetString(PyExc_TypeError, "Numeric argument expected");
}
%typemap(out) off_t {
#if _FILE_OFFSET_BITS == 64
$result = PyLong_FromLongLong($1);
#else
$result = PyLong_FromLong($1);
#endif
}
%typemap(in) off_t {
if (PyLong_Check($input))
#if _FILE_OFFSET_BITS == 64
$1 = PyLong_AsLongLong($input);
#else
$1 = PyLong_AsLong($input);
#endif
#if PY_MAJOR_VERSION < 3
else if (PyInt_Check($input))
$1 = PyInt_AsLong($input);
#endif
else
PyErr_SetString(PyExc_TypeError, "Numeric argument expected");
}
/* Those are for gpgme_data_read() and gpgme_strerror_r(). */
%typemap(in) (void *buffer, size_t size), (char *buf, size_t buflen) {
{
long tmp$argnum;
if (PyLong_Check($input))
tmp$argnum = PyLong_AsLong($input);
#if PY_MAJOR_VERSION < 3
else if (PyInt_Check($input))
tmp$argnum = PyInt_AsLong($input);
#endif
else
{
PyErr_SetString(PyExc_TypeError, "Numeric argument expected");
return NULL;
}
if (tmp$argnum < 0) {
PyErr_SetString(PyExc_ValueError, "Positive integer expected");
return NULL;
}
$2 = (size_t) tmp$argnum;
$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. */
%define wrapresult(cls, name)
%typemap(out) cls {
PyObject *fragile;
fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor,
%newpointer_flags);
$result = _gpg_wrap_result(fragile, name);
Py_DECREF(fragile);
}
%enddef
wrapresult(gpgme_encrypt_result_t, "EncryptResult")
wrapresult(gpgme_decrypt_result_t, "DecryptResult")
wrapresult(gpgme_sign_result_t, "SignResult")
wrapresult(gpgme_verify_result_t, "VerifyResult")
wrapresult(gpgme_import_result_t, "ImportResult")
wrapresult(gpgme_genkey_result_t, "GenkeyResult")
wrapresult(gpgme_keylist_result_t, "KeylistResult")
wrapresult(gpgme_vfs_mount_result_t, "VFSMountResult")
%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 = _gpg_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) _gpg_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 = _gpg_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 = _gpg_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 = _gpg_assuan_status_cb;
$2 = $input;
}
}
/* With SWIG, you can define default arguments for parameters.
* While it's legal in C++ it is not in C, so we cannot change the
* already existing gpgme.h. We need, however, to declare the function
* *before* SWIG loads it from gpgme.h. Hence, we define it here. */
gpgme_error_t gpgme_op_keylist_start (gpgme_ctx_t ctx,
const char *pattern="",
int secret_only=0);
/* The whence argument is surprising in Python-land,
because BytesIO or StringIO objects do not require it.
It defaults to SEEK_SET. Let's do that for Data objects, too */
off_t gpgme_data_seek (gpgme_data_t dh, off_t offset, int whence=SEEK_SET);
/* 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. */
%{
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#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. */
#ifdef HAVE_CONFIG_H
%include "config.h"
#endif
%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 *
_gpg_wrap_gpgme_data_t(gpgme_data_t data)
{
/*
* If SWIG is invoked without -builtin, the macro SWIG_NewPointerObj
* expects a variable named "self".
*
* XXX: It is not quite clear why passing NULL as self is okay, but
* it works with -builtin, and it seems to work just fine without
* it too.
*/
PyObject* self = NULL;
(void) self;
return SWIG_NewPointerObj(data, SWIGTYPE_p_gpgme_data, 0);
}
gpgme_ctx_t
_gpg_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"
%define genericrepr(cls)
%pythoncode %{
def __repr__(self):
names = [name for name in dir(self)
if not name.startswith("_") and name != "this"]
props = ", ".join(("{}={!r}".format(name, getattr(self, name))
for name in names)
)
return "cls({})".format(props)
%}
%enddef
%extend _gpgme_key {
genericrepr(Key)
};
%extend _gpgme_subkey {
genericrepr(SubKey)
};
%extend _gpgme_key_sig {
genericrepr(KeySig)
};
%extend _gpgme_user_id {
genericrepr(UID)
};
%extend _gpgme_tofu_info {
genericrepr(TofuInfo)
};