python: Robust exception handling in callbacks.
[gpgme.git] / lang / python / gpgme.i
1 /*
2 # $Id$
3 # Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net>
4 # Copyright (C) 2002 John Goerzen <jgoerzen@complete.org>
5 #
6 #    This library is free software; you can redistribute it and/or
7 #    modify it under the terms of the GNU Lesser General Public
8 #    License as published by the Free Software Foundation; either
9 #    version 2.1 of the License, or (at your option) any later version.
10 #
11 #    This library is distributed in the hope that it will be useful,
12 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 #    Lesser General Public License for more details.
15 #
16 #    You should have received a copy of the GNU Lesser General Public
17 #    License along with this library; if not, write to the Free Software
18 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
19 */
20 %module pygpgme
21 %include "cpointer.i"
22 %include "cstring.i"
23
24 // Generate doc strings for all methods.
25 %feature("autodoc", "0");
26
27 /* Allow use of Unicode objects, bytes, and None for strings.  */
28
29 %typemap(in) const char * {
30   if ($input == Py_None)
31     $1 = NULL;
32   else if (PyUnicode_Check($input))
33     $1 = PyUnicode_AsUTF8($input);
34   else if (PyBytes_Check($input))
35     $1 = PyBytes_AsString($input);
36   else {
37     PyErr_Format(PyExc_TypeError,
38                  "arg %d: expected str, bytes, or None, got %s",
39                  $argnum, $input->ob_type->tp_name);
40     return NULL;
41   }
42 }
43 %typemap(freearg) const char * "";
44
45 // Release returned buffers as necessary.
46 %typemap(newfree) char * "free($1);";
47 %newobject gpgme_data_release_and_get_mem;
48
49 %{
50 /* Convert object to a pointer to gpgme type */
51 PyObject* object_to_gpgme_t(PyObject* input, const char* objtype, int argnum) {
52   PyObject *pyname = NULL, *pypointer = NULL;
53   pyname = PyObject_CallMethod(input, "_getctype", NULL);
54   if (pyname && PyUnicode_Check(pyname))
55     {
56       if (strcmp(PyUnicode_AsUTF8(pyname), objtype) != 0)
57         {
58           PyErr_Format(PyExc_TypeError,
59                        "arg %d: Expected value of type %s, but got %s",
60                        argnum, objtype, PyUnicode_AsUTF8(pyname));
61           Py_DECREF(pyname);
62           return NULL;
63         }
64     }
65   else
66     {
67       PyErr_Format(PyExc_TypeError,
68                    "Protocol violation: Expected an instance of type str "
69                    "from _getctype, but got %s",
70                    pyname == NULL ? "NULL"
71                    : (pyname == Py_None ? "None" : pyname->ob_type->tp_name));
72       return NULL;
73     }
74
75   Py_DECREF(pyname);
76   pypointer = PyObject_GetAttrString(input, "wrapped");
77   if (pypointer == NULL) {
78     PyErr_Format(PyExc_TypeError,
79                  "arg %d: Use of uninitialized Python object %s",
80                  argnum, objtype);
81     return NULL;
82   }
83   return pypointer;
84 }
85 %}
86
87 %typemap(arginit) gpgme_key_t [] {
88   $1 = NULL;
89 }
90
91 %typemap(in) gpgme_key_t [] {
92   int i, numb = 0;
93   if (!PySequence_Check($input)) {
94     PyErr_Format(PyExc_ValueError, "arg %d: Expected a list of gpgme_key_t",
95                  $argnum);
96     return NULL;
97   }
98   if((numb = PySequence_Length($input)) != 0) {
99     $1 = (gpgme_key_t*)malloc((numb+1)*sizeof(gpgme_key_t));
100     for(i=0; i<numb; i++) {
101       PyObject *pypointer = PySequence_GetItem($input, i);
102
103       /* input = $input, 1 = $1, 1_descriptor = $1_descriptor */
104       /* &1_descriptor = $&1_descriptor *1_descriptor = $*1_descriptor */
105
106       // Following code is from swig's python.swg
107       if ((SWIG_ConvertPtr(pypointer,(void **) &$1[i], $*1_descriptor,SWIG_POINTER_EXCEPTION | $disown )) == -1) {
108         Py_DECREF(pypointer);
109         return NULL;
110       }
111       Py_DECREF(pypointer);
112     }
113     $1[numb] = NULL;
114   }
115 }
116 %typemap(freearg) gpgme_key_t [] {
117   if ($1) free($1);
118 }
119
120 // Special handling for references to our objects.
121 %typemap(in) gpgme_data_t DATAIN {
122   if ($input == Py_None)
123     $1 = NULL;
124   else {
125     PyObject *pypointer = NULL;
126
127     if((pypointer=object_to_gpgme_t($input, "$1_ltype", $argnum)) == NULL)
128       return NULL;
129
130     /* input = $input, 1 = $1, 1_descriptor = $1_descriptor */
131
132     // Following code is from swig's python.swg
133
134     if ((SWIG_ConvertPtr(pypointer,(void **) &$1, $1_descriptor,
135          SWIG_POINTER_EXCEPTION | $disown )) == -1) {
136       Py_DECREF(pypointer);
137       return NULL;
138     }
139     Py_DECREF(pypointer);
140   }
141 }
142
143 %apply gpgme_data_t DATAIN {gpgme_data_t plain, gpgme_data_t cipher,
144                         gpgme_data_t sig, gpgme_data_t signed_text,
145                         gpgme_data_t plaintext, gpgme_data_t keydata,
146                         gpgme_data_t pubkey, gpgme_data_t seckey,
147                         gpgme_data_t out};
148
149 // SWIG has problem interpreting ssize_t, off_t or gpgme_error_t in gpgme.h
150 %typemap(out) ssize_t, off_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t {
151   $result = PyLong_FromLong($1);
152 }
153 %typemap(in) ssize_t, off_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t {
154   $1 = PyLong_AsLong($input);
155 }
156
157 // Those are for gpgme_data_read() and gpgme_strerror_r()
158 %typemap(in) (void *buffer, size_t size), (char *buf, size_t buflen) {
159    $2 = PyLong_AsLong($input);
160    if ($2 < 0) {
161      PyErr_SetString(PyExc_ValueError, "Positive integer expected");
162      return NULL;
163    }
164    $1 = ($1_ltype) malloc($2+1);
165 }
166 %typemap(argout) (void *buffer, size_t size), (char *buf, size_t buflen) {
167   Py_XDECREF($result);   /* Blow away any previous result */
168   if (result < 0) {      /* Check for I/O error */
169     free($1);
170     return NULL;
171   }
172   $result = PyBytes_FromStringAndSize($1,result);
173   free($1);
174 }
175
176 /* For gpgme_data_write, but should be universal.  */
177 %typemap(in) (const void *buffer, size_t size) {
178   if ($input == Py_None)
179     $1 = NULL, $2 = 0;
180   else if (PyUnicode_Check($input))
181     $1 = PyUnicode_AsUTF8AndSize($input, (size_t *) &$2);
182   else if (PyBytes_Check($input))
183     PyBytes_AsStringAndSize($input, (char **) &$1, (size_t *) &$2);
184   else {
185     PyErr_Format(PyExc_TypeError,
186                  "arg %d: expected str, bytes, or None, got %s",
187                  $argnum, $input->ob_type->tp_name);
188     return NULL;
189   }
190 }
191 %typemap(freearg) (const void *buffer, size_t size) "";
192
193 // Make types containing 'next' field to be lists
194 %ignore next;
195 %typemap(out) gpgme_sig_notation_t, gpgme_engine_info_t, gpgme_subkey_t, gpgme_key_sig_t,
196         gpgme_user_id_t, gpgme_invalid_key_t, gpgme_recipient_t, gpgme_new_signature_t,
197         gpgme_signature_t, gpgme_import_status_t, gpgme_conf_arg_t, gpgme_conf_opt_t,
198         gpgme_conf_comp_t {
199   int i;
200   int size = 0;
201   $1_ltype curr;
202   for (curr = $1; curr != NULL; curr = curr->next) {
203     size++;
204   }
205   $result = PyList_New(size);
206   for (i=0,curr=$1; i<size; i++,curr=curr->next) {
207     PyObject *o = SWIG_NewPointerObj(SWIG_as_voidptr(curr), $1_descriptor, %newpointer_flags);
208     PyList_SetItem($result, i, o);
209   }
210 }
211
212 // Include mapper for edit callbacks
213 %typemap(in) (gpgme_edit_cb_t fnc, void *fnc_value) {
214   $1 = (gpgme_edit_cb_t) pyEditCb;
215   if ($input == Py_None)
216     $2 = NULL;
217   else
218     $2 = $input;
219 }
220
221 // Include the header file both for cc (first) and for swig (second)
222 // Include for swig locally since we need to fix 'class' usage there.
223 %{
224 #include <gpgme.h>
225 %}
226 %include "gpgme.h"
227
228 %constant long EOF = GPG_ERR_EOF;
229
230 // Generating and handling pointers-to-pointers.
231
232 %pointer_functions(gpgme_ctx_t, gpgme_ctx_t_p);
233 %pointer_functions(gpgme_data_t, gpgme_data_t_p);
234 %pointer_functions(gpgme_key_t, gpgme_key_t_p);
235 %pointer_functions(gpgme_error_t, gpgme_error_t_p);
236 %pointer_functions(gpgme_trust_item_t, gpgme_trust_item_t_p);
237 %pointer_functions(gpgme_engine_info_t, gpgme_engine_info_t_p);
238 %pointer_functions(PyObject *, PyObject_p_p);
239 %pointer_functions(void *, void_p_p);
240
241 // Helper functions.
242
243 %{
244 #include <stdio.h>
245 %}
246 FILE *fdopen(int fildes, const char *mode);
247
248 %{
249 #include "helpers.h"
250 %}
251 %include "helpers.h"
252
253 %{
254 gpgme_error_t pyEditCb(void *opaque, gpgme_status_code_t status,
255                        const char *args, int fd) {
256   PyObject *func = NULL, *dataarg = NULL, *pyargs = NULL, *retval = NULL;
257   PyObject *pyopaque = (PyObject *) opaque;
258   gpgme_error_t err_status = 0;
259
260   pygpgme_exception_init();
261
262   if (PyTuple_Check(pyopaque)) {
263     func = PyTuple_GetItem(pyopaque, 0);
264     dataarg = PyTuple_GetItem(pyopaque, 1);
265     pyargs = PyTuple_New(3);
266   } else {
267     func = pyopaque;
268     pyargs = PyTuple_New(2);
269   }
270
271   PyTuple_SetItem(pyargs, 0, PyLong_FromLong((long) status));
272   PyTuple_SetItem(pyargs, 1, PyUnicode_FromString(args));
273   if (dataarg) {
274     Py_INCREF(dataarg);         /* Because GetItem doesn't give a ref but SetItem taketh away */
275     PyTuple_SetItem(pyargs, 2, dataarg);
276   }
277
278   retval = PyObject_CallObject(func, pyargs);
279   Py_DECREF(pyargs);
280   if (PyErr_Occurred()) {
281     err_status = pygpgme_exception2code();
282   } else {
283     if (fd>=0 && retval && PyUnicode_Check(retval)) {
284       const char *buffer;
285       Py_ssize_t size;
286
287       buffer = PyUnicode_AsUTF8AndSize(retval, &size);
288       write(fd, buffer, size);
289       write(fd, "\n", 1);
290     }
291   }
292
293   Py_XDECREF(retval);
294   return err_status;
295 }
296 %}