python: Avoid creating SWIG proxy classes.
[gpgme.git] / lang / python / gpgme.i
1 /*
2 # Copyright (C) 2016 g10 Code GmbH
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 /* Likewise for a list of strings.  */
46 %typemap(in) const char *[] (void *vector = NULL) {
47   /* Check if is a list */
48   if (PyList_Check($input)) {
49     size_t i, size = PyList_Size($input);
50     $1 = (char **) (vector = malloc((size+1) * sizeof(char *)));
51
52     for (i = 0; i < size; i++) {
53       PyObject *o = PyList_GetItem($input,i);
54       if (PyUnicode_Check(o))
55         $1[i] = PyUnicode_AsUTF8(o);
56       else if (PyString_Check(o))
57         $1[i] = PyString_AsString(o);
58       else {
59         PyErr_Format(PyExc_TypeError,
60                      "arg %d: list must contain only str or bytes, got %s "
61                      "at position %d",
62                      $argnum, o->ob_type->tp_name, i);
63         free($1);
64         return NULL;
65       }
66     }
67     $1[i] = NULL;
68   } else {
69     PyErr_Format(PyExc_TypeError,
70                  "arg %d: expected a list of str or bytes, got %s",
71                  $argnum, $input->ob_type->tp_name);
72     return NULL;
73   }
74 }
75 %typemap(freearg) const char *[] {
76   free(vector$argnum);
77 }
78
79 // Release returned buffers as necessary.
80 %typemap(newfree) char * "free($1);";
81 %newobject gpgme_data_release_and_get_mem;
82
83 %typemap(arginit) gpgme_key_t [] {
84   $1 = NULL;
85 }
86
87 %typemap(in) gpgme_key_t [] {
88   int i, numb = 0;
89   if (!PySequence_Check($input)) {
90     PyErr_Format(PyExc_ValueError, "arg %d: Expected a list of gpgme_key_t",
91                  $argnum);
92     return NULL;
93   }
94   if((numb = PySequence_Length($input)) != 0) {
95     $1 = (gpgme_key_t*)malloc((numb+1)*sizeof(gpgme_key_t));
96     for(i=0; i<numb; i++) {
97       PyObject *pypointer = PySequence_GetItem($input, i);
98
99       /* input = $input, 1 = $1, 1_descriptor = $1_descriptor */
100       /* &1_descriptor = $&1_descriptor *1_descriptor = $*1_descriptor */
101
102       // Following code is from swig's python.swg
103       if ((SWIG_ConvertPtr(pypointer,(void **) &$1[i], $*1_descriptor,SWIG_POINTER_EXCEPTION | $disown )) == -1) {
104         Py_DECREF(pypointer);
105         return NULL;
106       }
107       Py_DECREF(pypointer);
108     }
109     $1[numb] = NULL;
110   }
111 }
112 %typemap(freearg) gpgme_key_t [] {
113   if ($1) free($1);
114 }
115
116 // Special handling for references to our objects.
117 %typemap(in) gpgme_data_t DATAIN (gpgme_data_t wrapper = NULL,
118                                   PyObject *bytesio = NULL, Py_buffer view) {
119   /* If we create a temporary wrapper object, we will store it in
120      wrapperN, where N is $argnum.  Here in this fragment, SWIG will
121      automatically append $argnum.  */
122   memset(&view, 0, sizeof view);
123   if ($input == Py_None)
124     $1 = NULL;
125   else {
126     PyObject *pypointer;
127     pypointer = object_to_gpgme_data_t($input, $argnum, &wrapper,
128                                        &bytesio, &view);
129     if (pypointer == NULL)
130       return NULL;
131
132     /* input = $input, 1 = $1, 1_descriptor = $1_descriptor */
133
134     // Following code is from swig's python.swg
135
136     if ((SWIG_ConvertPtr(pypointer,(void **) &$1, $1_descriptor,
137          SWIG_POINTER_EXCEPTION | $disown )) == -1) {
138       Py_DECREF(pypointer);
139       return NULL;
140     }
141     Py_DECREF(pypointer);
142   }
143 }
144
145 %typemap(freearg) gpgme_data_t DATAIN {
146   /* See whether we need to update the Python buffer.  */
147   if (resultobj && wrapper$argnum && view$argnum.buf
148       && wrapper$argnum->data.mem.buffer != NULL)
149     {
150       /* The buffer is dirty.  */
151       if (view$argnum.readonly)
152         {
153           Py_XDECREF(resultobj);
154           resultobj = NULL;
155           PyErr_SetString(PyExc_ValueError, "cannot update read-only buffer");
156         }
157
158       /* See if we need to truncate the buffer.  */
159       if (resultobj && view$argnum.len != wrapper$argnum->data.mem.length)
160         {
161           if (bytesio$argnum == NULL)
162             {
163               Py_XDECREF(resultobj);
164               resultobj = NULL;
165               PyErr_SetString(PyExc_ValueError, "cannot resize buffer");
166             }
167           else
168             {
169               PyObject *retval;
170               PyBuffer_Release(&view$argnum);
171               retval = PyObject_CallMethod(bytesio$argnum, "truncate", "l",
172                                            (long)
173                                            wrapper$argnum->data.mem.length);
174               if (retval == NULL)
175                 {
176                   Py_XDECREF(resultobj);
177                   resultobj = NULL;
178                 }
179               else
180                 {
181                   Py_DECREF(retval);
182
183                   retval = PyObject_CallMethod(bytesio$argnum, "getbuffer", NULL);
184                   if (retval == NULL
185                       || PyObject_GetBuffer(retval, &view$argnum,
186                                             PyBUF_SIMPLE|PyBUF_WRITABLE) < 0)
187                     {
188                       Py_XDECREF(resultobj);
189                       resultobj = NULL;
190                     }
191
192                   Py_XDECREF(retval);
193
194                   if (resultobj && view$argnum.len
195                       != wrapper$argnum->data.mem.length)
196                     {
197                       Py_XDECREF(resultobj);
198                       resultobj = NULL;
199                       PyErr_Format(PyExc_ValueError,
200                                    "Expected buffer of length %zu, got %zi",
201                                    wrapper$argnum->data.mem.length,
202                                    view$argnum.len);
203                     }
204                 }
205             }
206         }
207
208       if (resultobj)
209         memcpy(view$argnum.buf, wrapper$argnum->data.mem.buffer,
210                wrapper$argnum->data.mem.length);
211     }
212
213   /* Free the temporary wrapper, if any.  */
214   if (wrapper$argnum)
215     gpgme_data_release(wrapper$argnum);
216   Py_XDECREF (bytesio$argnum);
217   if (wrapper$argnum && view$argnum.buf)
218     PyBuffer_Release(&view$argnum);
219 }
220
221 %apply gpgme_data_t DATAIN {gpgme_data_t plain, gpgme_data_t cipher,
222                         gpgme_data_t sig, gpgme_data_t signed_text,
223                         gpgme_data_t plaintext, gpgme_data_t keydata,
224                         gpgme_data_t pubkey, gpgme_data_t seckey,
225                         gpgme_data_t out};
226
227 /* SWIG has problems interpreting ssize_t, off_t or gpgme_error_t in
228    gpgme.h.  */
229 /* XXX: This is wrong at least for off_t if compiled with LFS.  */
230 %typemap(out) ssize_t, off_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t {
231   $result = PyLong_FromLong($1);
232 }
233 /* XXX: This is wrong at least for off_t if compiled with LFS.  */
234 %typemap(in) ssize_t, off_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t {
235   $1 = PyLong_AsLong($input);
236 }
237
238 // Those are for gpgme_data_read() and gpgme_strerror_r()
239 %typemap(in) (void *buffer, size_t size), (char *buf, size_t buflen) {
240    $2 = PyLong_AsLong($input);
241    if ($2 < 0) {
242      PyErr_SetString(PyExc_ValueError, "Positive integer expected");
243      return NULL;
244    }
245    $1 = ($1_ltype) malloc($2+1);
246 }
247 %typemap(argout) (void *buffer, size_t size), (char *buf, size_t buflen) {
248   Py_XDECREF($result);   /* Blow away any previous result */
249   if (result < 0) {      /* Check for I/O error */
250     free($1);
251     return PyErr_SetFromErrno(PyExc_RuntimeError);
252   }
253   $result = PyBytes_FromStringAndSize($1,result);
254   free($1);
255 }
256
257 /* For gpgme_data_write, but should be universal.  */
258 %typemap(in) (const void *buffer, size_t size) {
259   Py_ssize_t ssize;
260
261   if ($input == Py_None)
262     $1 = NULL, $2 = 0;
263   else if (PyUnicode_Check($input))
264     $1 = PyUnicode_AsUTF8AndSize($input, &ssize);
265   else if (PyBytes_Check($input))
266     PyBytes_AsStringAndSize($input, (char **) &$1, &ssize);
267   else {
268     PyErr_Format(PyExc_TypeError,
269                  "arg %d: expected str, bytes, or None, got %s",
270                  $argnum, $input->ob_type->tp_name);
271     return NULL;
272   }
273
274   if (! $1)
275     $2 = 0;
276   else
277     {
278       assert (ssize >= 0);
279       $2 = (size_t) ssize;
280     }
281 }
282 %typemap(freearg) (const void *buffer, size_t size) "";
283
284 // Make types containing 'next' field to be lists
285 %ignore next;
286 %typemap(out) gpgme_sig_notation_t, gpgme_engine_info_t, gpgme_subkey_t, gpgme_key_sig_t,
287         gpgme_user_id_t, gpgme_invalid_key_t, gpgme_recipient_t, gpgme_new_signature_t,
288         gpgme_signature_t, gpgme_import_status_t, gpgme_conf_arg_t, gpgme_conf_opt_t,
289         gpgme_conf_comp_t {
290   int i;
291   int size = 0;
292   $1_ltype curr;
293   for (curr = $1; curr != NULL; curr = curr->next) {
294     size++;
295   }
296   $result = PyList_New(size);
297   for (i=0,curr=$1; i<size; i++,curr=curr->next) {
298     PyObject *o = SWIG_NewPointerObj(SWIG_as_voidptr(curr), $1_descriptor, %newpointer_flags);
299     PyList_SetItem($result, i, o);
300   }
301 }
302
303 // Include mapper for edit callbacks
304 %typemap(in) (gpgme_edit_cb_t fnc, void *fnc_value) {
305   if (! PyTuple_Check($input))
306     return PyErr_Format(PyExc_TypeError, "edit callback must be a tuple");
307   if (PyTuple_Size($input) != 2 && PyTuple_Size($input) != 3)
308     return PyErr_Format(PyExc_TypeError,
309                         "edit callback must be a tuple of size 2 or 3");
310
311   $1 = (gpgme_edit_cb_t) pyEditCb;
312   $2 = $input;
313 }
314
315 /* Include the unmodified <gpgme.h> for cc, and the cleaned-up local
316    version for SWIG.  We do, however, want to hide certain fields on
317    some structs, which we provide prior to including the version for
318    SWIG.  */
319 %{
320 #include <gpgme.h>
321 #include "src/data.h"   /* For struct gpgme_data.  */
322 %}
323
324 /* This is for notations, where we want to hide the length fields, and
325    the unused bit field block.  */
326 struct _gpgme_sig_notation
327 {
328   struct _gpgme_sig_notation *next;
329
330   /* If NAME is a null pointer, then VALUE contains a policy URL
331      rather than a notation.  */
332   char *name;
333
334   /* The value of the notation data.  */
335   char *value;
336
337   /* The accumulated flags.  */
338   gpgme_sig_notation_flags_t flags;
339
340   /* Notation data is human-readable.  */
341   unsigned int human_readable : 1;
342
343   /* Notation data is critical.  */
344   unsigned int critical : 1;
345 };
346
347 /* Now include our local modified version.  Any structs defined above
348    are ignored.  */
349 %include "gpgme.h"
350
351 %include "errors.i"
352
353 // Generating and handling pointers-to-pointers.
354
355 %pointer_functions(gpgme_ctx_t, gpgme_ctx_t_p);
356 %pointer_functions(gpgme_data_t, gpgme_data_t_p);
357 %pointer_functions(gpgme_key_t, gpgme_key_t_p);
358 %pointer_functions(gpgme_error_t, gpgme_error_t_p);
359 %pointer_functions(gpgme_trust_item_t, gpgme_trust_item_t_p);
360 %pointer_functions(gpgme_engine_info_t, gpgme_engine_info_t_p);
361
362 // Helper functions.
363
364 %{
365 #include <stdio.h>
366 %}
367 FILE *fdopen(int fildes, const char *mode);
368
369 %{
370 #include "helpers.h"
371
372 /* SWIG support for helpers.c  */
373 PyObject *
374 pygpgme_wrap_gpgme_data_t(gpgme_data_t data)
375 {
376   return SWIG_Python_NewPointerObj(NULL, data, SWIGTYPE_p_gpgme_data, 0);
377 }
378
379 gpgme_ctx_t
380 pygpgme_unwrap_gpgme_ctx_t(PyObject *wrapped)
381 {
382   gpgme_ctx_t result;
383   if (SWIG_ConvertPtr(wrapped,
384                       (void **) &result,
385                       SWIGTYPE_p_gpgme_context,
386                       SWIG_POINTER_EXCEPTION) == -1)
387     return NULL;
388   return result;
389 }
390 %}
391
392 %include "helpers.h"