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