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
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
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
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 *
_gpg_wrap_gpgme_data_t(gpgme_data_t data)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
_gpg_unwrap_gpgme_ctx_t(PyObject * wrapped)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 };
710