js: Error handling for browser errors
[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 gpgme
21 %include "cpointer.i"
22 %include "cstring.i"
23
24 /* no need to record whether GPGME's c++ bindings were built
25    concurrently with the python bindings */
26 %ignore HAVE_CXX11;
27
28 %{
29 /* We use public symbols (eg. "_obsolete_class") which are marked as
30  * deprecated but we need to keep them.  Silence the warning.  */
31 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
32 %}
33
34 /* Generate doc strings for all methods.
35
36    This will generate docstrings of the form
37
38      gpgme_op_encrypt(ctx, recp, flags, plain, cipher) -> gpgme_error_t
39
40    which we transform into
41
42      ctx.op_encrypt(recp, flags, plain, cipher) -> gpgme_error_t
43
44    for automagically wrapped functions.  */
45 %feature("autodoc", "0");
46
47
48 /* Allow use of Unicode objects, bytes, and None for strings.  */
49 %typemap(in) const char *(PyObject *encodedInput = NULL) {
50   if ($input == Py_None)
51     $1 = NULL;
52   else if (PyUnicode_Check($input))
53     {
54       encodedInput = PyUnicode_AsUTF8String($input);
55       if (encodedInput == NULL)
56         return NULL;
57       $1 = PyBytes_AsString(encodedInput);
58     }
59   else if (PyBytes_Check($input))
60     $1 = PyBytes_AsString($input);
61   else {
62     PyErr_Format(PyExc_TypeError,
63                  "arg %d: expected str, bytes, or None, got %s",
64                  $argnum, $input->ob_type->tp_name);
65     return NULL;
66   }
67 }
68 %typemap(freearg) const char * {
69   Py_XDECREF(encodedInput$argnum);
70 }
71
72 /* Likewise for a list of strings.  */
73 %typemap(in) const char *[] (void *vector = NULL,
74                              size_t size,
75                              PyObject **pyVector = NULL) {
76   /* Check if is a list */
77   if (PyList_Check($input)) {
78     size_t i, j;
79     size = PyList_Size($input);
80     $1 = (char **) (vector = malloc((size+1) * sizeof(char *)));
81     pyVector = calloc(sizeof *pyVector, size);
82
83     for (i = 0; i < size; i++) {
84       PyObject *o = PyList_GetItem($input,i);
85       if (PyUnicode_Check(o))
86         {
87           pyVector[i] = PyUnicode_AsUTF8String(o);
88           if (pyVector[i] == NULL)
89             {
90               free(vector);
91               for (j = 0; j < i; j++)
92                 Py_XDECREF(pyVector[j]);
93               return NULL;
94             }
95           $1[i] = PyBytes_AsString(pyVector[i]);
96         }
97       else if (PyString_Check(o))
98         $1[i] = PyString_AsString(o);
99       else {
100         PyErr_Format(PyExc_TypeError,
101                      "arg %d: list must contain only str or bytes, got %s "
102                      "at position %d",
103                      $argnum, o->ob_type->tp_name, i);
104         free($1);
105         return NULL;
106       }
107     }
108     $1[i] = NULL;
109   } else {
110     PyErr_Format(PyExc_TypeError,
111                  "arg %d: expected a list of str or bytes, got %s",
112                  $argnum, $input->ob_type->tp_name);
113     return NULL;
114   }
115 }
116 %typemap(freearg) const char *[] {
117   size_t i;
118   free(vector$argnum);
119   for (i = 0; i < size$argnum; i++)
120     Py_XDECREF(pyVector$argnum[i]);
121 }
122
123 /* Release returned buffers as necessary.  */
124 %typemap(newfree) char * "gpgme_free($1);";
125 %newobject gpgme_data_release_and_get_mem;
126 %newobject gpgme_pubkey_algo_string;
127 %newobject gpgme_addrspec_from_uid;
128
129 %typemap(arginit) gpgme_key_t [] {
130   $1 = NULL;
131 }
132
133 %typemap(in) gpgme_key_t [] {
134   int i, numb = 0;
135   if (!PySequence_Check($input)) {
136     PyErr_Format(PyExc_ValueError, "arg %d: Expected a list of gpgme_key_t",
137                  $argnum);
138     return NULL;
139   }
140   if((numb = PySequence_Length($input)) != 0) {
141     $1 = (gpgme_key_t*)malloc((numb+1)*sizeof(gpgme_key_t));
142     for(i=0; i<numb; i++) {
143       PyObject *pypointer = PySequence_GetItem($input, i);
144
145       /* input = $input, 1 = $1, 1_descriptor = $1_descriptor */
146       /* &1_descriptor = $&1_descriptor *1_descriptor = $*1_descriptor */
147
148       /* Following code is from swig's python.swg.  */
149       if ((SWIG_ConvertPtr(pypointer,(void **) &$1[i], $*1_descriptor,SWIG_POINTER_EXCEPTION | $disown )) == -1) {
150         Py_DECREF(pypointer);
151         PyErr_Format(PyExc_TypeError,
152                      "arg %d: list must contain only gpgme_key_ts, got %s "
153                      "at position %d",
154                      $argnum, pypointer->ob_type->tp_name, i);
155         free($1);
156         return NULL;
157       }
158       Py_DECREF(pypointer);
159     }
160     $1[numb] = NULL;
161   }
162 }
163 %typemap(freearg) gpgme_key_t [] {
164   if ($1) free($1);
165 }
166
167 /* Special handling for references to our objects.  */
168 %typemap(in) gpgme_data_t DATAIN (gpgme_data_t wrapper = NULL,
169                                   PyObject *bytesio = NULL,
170                                   Py_buffer view, int have_view = 0) {
171   /* If we create a temporary wrapper object, we will store it in
172      wrapperN, where N is $argnum.  Here in this fragment, SWIG will
173      automatically append $argnum.  */
174   memset(&view, 0, sizeof view);
175   if ($input == Py_None)
176     $1 = NULL;
177   else {
178     PyObject *pypointer;
179     pypointer = _gpg_obj2gpgme_data_t($input, $argnum, &wrapper,
180                                        &bytesio, &view);
181     if (pypointer == NULL)
182       return NULL;
183     have_view = !! view.obj;
184
185     /* input = $input, 1 = $1, 1_descriptor = $1_descriptor */
186
187     /* Following code is from swig's python.swg.  */
188
189     if ((SWIG_ConvertPtr(pypointer,(void **) &$1, $1_descriptor,
190          SWIG_POINTER_EXCEPTION | $disown )) == -1) {
191       Py_DECREF(pypointer);
192       return NULL;
193     }
194     Py_DECREF(pypointer);
195   }
196 }
197
198 #if HAVE_DATA_H
199 /* If we are doing an in-tree build, we can use the internal
200    representation of struct gpgme_data for an very efficient check if
201    the buffer has been modified.  */
202 %{
203 #include "data.h"       /* For struct gpgme_data.  */
204 %}
205 #endif
206
207 %typemap(freearg) gpgme_data_t DATAIN {
208   /* See whether we need to update the Python buffer.  */
209   if (resultobj && wrapper$argnum && view$argnum.buf)
210     {
211       int dirty;
212       char *new_data = NULL;
213       size_t new_size;
214
215 #if HAVE_DATA_H
216       new_data = wrapper$argnum->data.mem.buffer;
217       new_size = wrapper$argnum->data.mem.length;
218       dirty = new_data != NULL;
219 #else
220       new_data = gpgme_data_release_and_get_mem (wrapper$argnum, &new_size);
221       wrapper$argnum = NULL;
222       dirty = new_size != view$argnum.len
223         || memcmp (new_data, view$argnum.buf, view$argnum.len);
224 #endif
225
226       if (dirty)
227         {
228           /* The buffer is dirty.  */
229           if (view$argnum.readonly)
230             {
231               Py_XDECREF(resultobj);
232               resultobj = NULL;
233               PyErr_SetString(PyExc_ValueError,
234                               "cannot update read-only buffer");
235             }
236
237           /* See if we need to truncate the buffer.  */
238           if (resultobj && view$argnum.len != new_size)
239             {
240               if (bytesio$argnum == NULL)
241                 {
242                   Py_XDECREF(resultobj);
243                   resultobj = NULL;
244                   PyErr_SetString(PyExc_ValueError, "cannot resize buffer");
245                 }
246               else
247                 {
248                   PyObject *retval;
249                   PyBuffer_Release(&view$argnum);
250                   assert(view$argnum.obj == NULL);
251                   retval = PyObject_CallMethod(bytesio$argnum, "truncate",
252                                                "l", (long) new_size);
253                   if (retval == NULL)
254                     {
255                       Py_XDECREF(resultobj);
256                       resultobj = NULL;
257                     }
258                   else
259                     {
260                       Py_DECREF(retval);
261
262                       retval = PyObject_CallMethod(bytesio$argnum,
263                                                    "getbuffer", NULL);
264                       if (retval == NULL
265                           || PyObject_GetBuffer(retval, &view$argnum,
266                                            PyBUF_SIMPLE|PyBUF_WRITABLE) < 0)
267                         {
268                           Py_XDECREF(resultobj);
269                           resultobj = NULL;
270                         }
271
272                       Py_XDECREF(retval);
273
274                       if (resultobj && view$argnum.len
275                           != new_size)
276                         {
277                           Py_XDECREF(resultobj);
278                           resultobj = NULL;
279                           PyErr_Format(PyExc_ValueError,
280                                        "Expected buffer of length %zu, got %zi",
281                                        new_size,
282                                        view$argnum.len);
283                         }
284                     }
285                 }
286             }
287           if (resultobj)
288             memcpy(view$argnum.buf, new_data, new_size);
289         }
290 #if ! HAVE_DATA_H
291       free (new_data);
292 #endif
293     }
294
295   /* Free the temporary wrapper, if any.  */
296   if (wrapper$argnum)
297     gpgme_data_release(wrapper$argnum);
298   Py_XDECREF (bytesio$argnum);
299   if (have_view$argnum && view$argnum.buf)
300     PyBuffer_Release(&view$argnum);
301 }
302
303 %apply gpgme_data_t DATAIN {gpgme_data_t plain, gpgme_data_t cipher,
304                         gpgme_data_t sig, gpgme_data_t signed_text,
305                         gpgme_data_t plaintext, gpgme_data_t keydata,
306                         gpgme_data_t pubkey, gpgme_data_t seckey,
307                         gpgme_data_t out, gpgme_data_t data};
308
309 /* SWIG has problems interpreting ssize_t, off_t or gpgme_error_t in
310    gpgme.h.  */
311 %typemap(out) ssize_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t {
312   $result = PyLong_FromLong($1);
313 }
314
315 %typemap(in) ssize_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t {
316   if (PyLong_Check($input))
317     $1 = PyLong_AsLong($input);
318 #if PY_MAJOR_VERSION < 3
319   else if (PyInt_Check($input))
320     $1 = PyInt_AsLong($input);
321 #endif
322   else
323     PyErr_SetString(PyExc_TypeError, "Numeric argument expected");
324 }
325
326 %typemap(out) off_t {
327 #if _FILE_OFFSET_BITS == 64
328   $result = PyLong_FromLongLong($1);
329 #else
330   $result = PyLong_FromLong($1);
331 #endif
332 }
333
334 %typemap(in) off_t {
335   if (PyLong_Check($input))
336 #if _FILE_OFFSET_BITS == 64
337     $1 = PyLong_AsLongLong($input);
338 #else
339     $1 = PyLong_AsLong($input);
340 #endif
341 #if PY_MAJOR_VERSION < 3
342   else if (PyInt_Check($input))
343     $1 = PyInt_AsLong($input);
344 #endif
345   else
346     PyErr_SetString(PyExc_TypeError, "Numeric argument expected");
347 }
348
349 /* Those are for gpgme_data_read() and gpgme_strerror_r().  */
350 %typemap(in) (void *buffer, size_t size), (char *buf, size_t buflen) {
351   {
352     long tmp$argnum;
353     if (PyLong_Check($input))
354       tmp$argnum = PyLong_AsLong($input);
355 #if PY_MAJOR_VERSION < 3
356     else if (PyInt_Check($input))
357       tmp$argnum = PyInt_AsLong($input);
358 #endif
359     else
360       {
361         PyErr_SetString(PyExc_TypeError, "Numeric argument expected");
362         return NULL;
363       }
364
365     if (tmp$argnum < 0) {
366       PyErr_SetString(PyExc_ValueError, "Positive integer expected");
367       return NULL;
368     }
369     $2 = (size_t) tmp$argnum;
370     $1 = ($1_ltype) malloc($2+1);
371   }
372 }
373 %typemap(argout) (void *buffer, size_t size), (char *buf, size_t buflen) {
374   Py_XDECREF($result);   /* Blow away any previous result */
375   if (result < 0) {      /* Check for I/O error */
376     free($1);
377     return PyErr_SetFromErrno(PyExc_RuntimeError);
378   }
379   $result = PyBytes_FromStringAndSize($1,result);
380   free($1);
381 }
382
383 /* For gpgme_data_write, but should be universal.  */
384 %typemap(in) (const void *buffer, size_t size)(PyObject *encodedInput = NULL) {
385   Py_ssize_t ssize;
386
387   if ($input == Py_None)
388     $1 = NULL, $2 = 0;
389   else if (PyUnicode_Check($input))
390     {
391       encodedInput = PyUnicode_AsUTF8String($input);
392       if (encodedInput == NULL)
393         return NULL;
394       if (PyBytes_AsStringAndSize(encodedInput, (char **) &$1, &ssize) == -1)
395         {
396           Py_DECREF(encodedInput);
397           return NULL;
398         }
399     }
400   else if (PyBytes_Check($input))
401     PyBytes_AsStringAndSize($input, (char **) &$1, &ssize);
402   else {
403     PyErr_Format(PyExc_TypeError,
404                  "arg %d: expected str, bytes, or None, got %s",
405                  $argnum, $input->ob_type->tp_name);
406     return NULL;
407   }
408
409   if (! $1)
410     $2 = 0;
411   else
412     {
413       assert (ssize >= 0);
414       $2 = (size_t) ssize;
415     }
416 }
417 %typemap(freearg) (const void *buffer, size_t size) {
418   Py_XDECREF(encodedInput$argnum);
419 }
420
421 /* Make types containing 'next' field to be lists.  */
422 %ignore next;
423 %typemap(out) gpgme_sig_notation_t, gpgme_subkey_t,
424    gpgme_key_sig_t, gpgme_user_id_t, gpgme_invalid_key_t,
425    gpgme_recipient_t, gpgme_new_signature_t, gpgme_signature_t,
426    gpgme_import_status_t, gpgme_conf_arg_t, gpgme_conf_opt_t,
427    gpgme_conf_comp_t, gpgme_tofu_info_t {
428   int i;
429   int size = 0;
430   $1_ltype curr;
431   for (curr = $1; curr != NULL; curr = curr->next) {
432     size++;
433   }
434   $result = PyList_New(size);
435   for (i=0,curr=$1; i<size; i++,curr=curr->next) {
436     PyObject *o = SWIG_NewPointerObj(SWIG_as_voidptr(curr), $1_descriptor, %newpointer_flags);
437     PyList_SetItem($result, i, o);
438   }
439 }
440
441 \f
442
443 /* Wrap the fragile result objects into robust Python ones.  */
444 %define wrapresult(cls, name)
445 %typemap(out) cls {
446   PyObject *fragile;
447   fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor,
448                                %newpointer_flags);
449   $result = _gpg_wrap_result(fragile, name);
450   Py_DECREF(fragile);
451 }
452 %enddef
453
454 wrapresult(gpgme_encrypt_result_t, "EncryptResult")
455 wrapresult(gpgme_decrypt_result_t, "DecryptResult")
456 wrapresult(gpgme_sign_result_t, "SignResult")
457 wrapresult(gpgme_verify_result_t, "VerifyResult")
458 wrapresult(gpgme_import_result_t, "ImportResult")
459 wrapresult(gpgme_genkey_result_t, "GenkeyResult")
460 wrapresult(gpgme_keylist_result_t, "KeylistResult")
461 wrapresult(gpgme_vfs_mount_result_t, "VFSMountResult")
462
463 %typemap(out) gpgme_engine_info_t {
464   int i;
465   int size = 0;
466   $1_ltype curr;
467   for (curr = $1; curr != NULL; curr = curr->next) {
468     size++;
469   }
470   $result = PyList_New(size);
471   if ($result == NULL)
472     return NULL;        /* raise */
473   for (i=0,curr=$1; i<size; i++,curr=curr->next) {
474     PyObject *fragile, *o;
475     fragile = SWIG_NewPointerObj(SWIG_as_voidptr(curr), $1_descriptor,
476                                  %newpointer_flags);
477     if (fragile == NULL)
478       {
479         Py_DECREF($result);
480         return NULL;    /* raise */
481       }
482     o = _gpg_wrap_result(fragile, "EngineInfo");
483     Py_DECREF(fragile);
484     if (o == NULL)
485       {
486         Py_DECREF($result);
487         return NULL;    /* raise */
488       }
489     PyList_SetItem($result, i, o);
490   }
491 }
492
493 \f
494
495 /* Include mapper for interact callbacks.  */
496 %typemap(in) (gpgme_interact_cb_t fnc, void *fnc_value) {
497   if (! PyTuple_Check($input))
498     return PyErr_Format(PyExc_TypeError, "interact callback must be a tuple");
499   if (PyTuple_Size($input) != 2 && PyTuple_Size($input) != 3)
500     return PyErr_Format(PyExc_TypeError,
501                         "interact callback must be a tuple of size 2 or 3");
502
503   $1 = (gpgme_interact_cb_t) _gpg_interact_cb;
504   $2 = $input;
505 }
506
507 \f
508
509 /* The assuan protocol callbacks.  */
510 %typemap(in) (gpgme_assuan_data_cb_t data_cb, void *data_cb_value) {
511   if ($input == Py_None)
512     $1 = $2 = NULL;
513   else
514     {
515       if (! PyTuple_Check($input))
516         return PyErr_Format(PyExc_TypeError, "callback must be a tuple");
517       if (PyTuple_Size($input) != 2)
518         return PyErr_Format(PyExc_TypeError,
519                             "callback must be a tuple of size 2");
520       if (! PyCallable_Check(PyTuple_GetItem($input, 1)))
521         return PyErr_Format(PyExc_TypeError, "second item must be callable");
522       $1 = _gpg_assuan_data_cb;
523       $2 = $input;
524     }
525 }
526
527 %typemap(in) (gpgme_assuan_inquire_cb_t inq_cb, void *inq_cb_value) {
528   if ($input == Py_None)
529     $1 = $2 = NULL;
530   else
531     {
532       if (! PyTuple_Check($input))
533         return PyErr_Format(PyExc_TypeError, "callback must be a tuple");
534       if (PyTuple_Size($input) != 2)
535         return PyErr_Format(PyExc_TypeError,
536                             "callback must be a tuple of size 2");
537       if (! PyCallable_Check(PyTuple_GetItem($input, 1)))
538         return PyErr_Format(PyExc_TypeError, "second item must be callable");
539       $1 = _gpg_assuan_inquire_cb;
540       $2 = $input;
541     }
542 }
543
544 %typemap(in) (gpgme_assuan_status_cb_t stat_cb, void *stat_cb_value) {
545   if ($input == Py_None)
546     $1 = $2 = NULL;
547   else
548     {
549       if (! PyTuple_Check($input))
550         return PyErr_Format(PyExc_TypeError, "callback must be a tuple");
551       if (PyTuple_Size($input) != 2)
552         return PyErr_Format(PyExc_TypeError,
553                             "callback must be a tuple of size 2");
554       if (! PyCallable_Check(PyTuple_GetItem($input, 1)))
555         return PyErr_Format(PyExc_TypeError, "second item must be callable");
556       $1 = _gpg_assuan_status_cb;
557       $2 = $input;
558     }
559 }
560
561
562 /* With SWIG, you can define default arguments for parameters.
563  * While it's legal in C++ it is not in C, so we cannot change the
564  * already existing gpgme.h. We need, however, to declare the function
565  * *before* SWIG loads it from gpgme.h. Hence, we define it here.     */
566 gpgme_error_t gpgme_op_keylist_start (gpgme_ctx_t ctx,
567                       const char *pattern="",
568                       int secret_only=0);
569
570 /* The whence argument is surprising in Python-land,
571    because BytesIO or StringIO objects do not require it.
572    It defaults to SEEK_SET. Let's do that for Data objects, too */
573 off_t gpgme_data_seek (gpgme_data_t dh, off_t offset, int whence=SEEK_SET);
574
575 /* Include the unmodified <gpgme.h> for cc, and the cleaned-up local
576    version for SWIG.  We do, however, want to hide certain fields on
577    some structs, which we provide prior to including the version for
578    SWIG.  */
579 %{
580 #ifdef HAVE_CONFIG_H
581 #include "config.h"
582 #endif
583
584 #include <gpgme.h>
585 %}
586
587 /* This is for notations, where we want to hide the length fields, and
588  * the unused bit field block.  We silence the warning.  */
589 %warnfilter(302) _gpgme_sig_notation;
590 struct _gpgme_sig_notation
591 {
592   struct _gpgme_sig_notation *next;
593
594   /* If NAME is a null pointer, then VALUE contains a policy URL
595      rather than a notation.  */
596   char *name;
597
598   /* The value of the notation data.  */
599   char *value;
600
601   /* The accumulated flags.  */
602   gpgme_sig_notation_flags_t flags;
603
604   /* Notation data is human-readable.  */
605   unsigned int human_readable : 1;
606
607   /* Notation data is critical.  */
608   unsigned int critical : 1;
609 };
610
611 /* Now include our local modified version.  Any structs defined above
612    are ignored.  */
613 #ifdef HAVE_CONFIG_H
614 %include "config.h"
615 #endif
616
617 %include "gpgme.h"
618
619 %include "errors.i"
620
621 /* Generating and handling pointers-to-pointers.  */
622
623 %pointer_functions(gpgme_ctx_t, gpgme_ctx_t_p);
624 %pointer_functions(gpgme_data_t, gpgme_data_t_p);
625 %pointer_functions(gpgme_key_t, gpgme_key_t_p);
626 %pointer_functions(gpgme_error_t, gpgme_error_t_p);
627 %pointer_functions(gpgme_trust_item_t, gpgme_trust_item_t_p);
628 %pointer_functions(gpgme_engine_info_t, gpgme_engine_info_t_p);
629
630 /* Helper functions.  */
631
632 %{
633 #include <stdio.h>
634 %}
635 FILE *fdopen(int fildes, const char *mode);
636
637 /* We include both headers in the generated c code...  */
638 %{
639 #include "helpers.h"
640 #include "private.h"
641
642 /* SWIG runtime support for helpers.c  */
643 PyObject *
644 _gpg_wrap_gpgme_data_t(gpgme_data_t data)
645 {
646   /*
647    * If SWIG is invoked without -builtin, the macro SWIG_NewPointerObj
648    * expects a variable named "self".
649    *
650    * XXX: It is not quite clear why passing NULL as self is okay, but
651    * it works with -builtin, and it seems to work just fine without
652    * it too.
653    */
654   PyObject* self = NULL;
655   (void) self;
656   return SWIG_NewPointerObj(data, SWIGTYPE_p_gpgme_data, 0);
657 }
658
659 gpgme_ctx_t
660 _gpg_unwrap_gpgme_ctx_t(PyObject *wrapped)
661 {
662   gpgme_ctx_t result;
663   if (SWIG_ConvertPtr(wrapped,
664                       (void **) &result,
665                       SWIGTYPE_p_gpgme_context,
666                       SWIG_POINTER_EXCEPTION) == -1)
667     return NULL;
668   return result;
669 }
670 %}
671
672 /* ... but only the public definitions here.  They will be exposed to
673    the Python world, so let's be careful.  */
674 %include "helpers.h"
675
676
677 %define genericrepr(cls)
678 %pythoncode %{
679     def __repr__(self):
680         names = [name for name in dir(self)
681             if not name.startswith("_") and name != "this"]
682         props = ", ".join(("{}={!r}".format(name, getattr(self, name))
683             for name in names)
684         )
685         return "cls({})".format(props)
686 %}
687
688 %enddef
689
690 %extend _gpgme_key {
691   genericrepr(Key)
692 };
693
694
695 %extend _gpgme_subkey {
696   genericrepr(SubKey)
697 };
698
699 %extend _gpgme_key_sig {
700   genericrepr(KeySig)
701 };
702
703 %extend _gpgme_user_id {
704   genericrepr(UID)
705 };
706
707 %extend _gpgme_tofu_info {
708   genericrepr(TofuInfo)
709 };