3ecbacc71a7e8d083bce2d9bb6aed7edbf89568a
[gpgme.git] / lang / python / helpers.c
1 /*
2 # Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
3 # Copyright (C) 2002 John Goerzen <jgoerzen@complete.org>
4 #
5 #    This library is free software; you can redistribute it and/or
6 #    modify it under the terms of the GNU Lesser General Public
7 #    License as published by the Free Software Foundation; either
8 #    version 2.1 of the License, or (at your option) any later version.
9 #
10 #    This library is distributed in the hope that it will be useful,
11 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 #    Lesser General Public License for more details.
14 #
15 #    You should have received a copy of the GNU Lesser General Public
16 #    License along with this library; if not, write to the Free Software
17 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
18 */
19
20 #include <assert.h>
21 #include <stdio.h>
22 #include <gpgme.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include "Python.h"
26 #include "helpers.h"
27
28 static PyObject *GPGMEError = NULL;
29
30 void pygpgme_exception_init(void) {
31   if (GPGMEError == NULL) {
32     PyObject *errors;
33     PyObject *from_list = PyList_New(0);
34     errors = PyImport_ImportModuleLevel("errors", PyEval_GetGlobals(),
35                                         PyEval_GetLocals(), from_list, 1);
36     Py_XDECREF(from_list);
37     if (errors) {
38       GPGMEError=PyDict_GetItemString(PyModule_GetDict(errors), "GPGMEError");
39       Py_XINCREF(GPGMEError);
40     }
41   }
42 }
43
44 gpgme_error_t pygpgme_exception2code(void) {
45   gpgme_error_t err_status = gpg_error(GPG_ERR_GENERAL);
46   if (GPGMEError && PyErr_ExceptionMatches(GPGMEError)) {
47     PyObject *type = 0, *value = 0, *traceback = 0;
48     PyObject *error = 0;
49     PyErr_Fetch(&type, &value, &traceback);
50     PyErr_NormalizeException(&type, &value, &traceback);
51     error = PyObject_GetAttrString(value, "error");
52     err_status = PyLong_AsLong(error);
53     Py_DECREF(error);
54     PyErr_Restore(type, value, traceback);
55   }
56   return err_status;
57 }
58
59 void pygpgme_clear_generic_cb(PyObject **cb) {
60   Py_DECREF(*cb);
61 }
62
63 /* Exception support for callbacks.  */
64 #define EXCINFO "_callback_excinfo"
65
66 static void pygpgme_stash_callback_exception(PyObject *weak_self)
67 {
68   PyObject *self, *ptype, *pvalue, *ptraceback, *excinfo;
69
70   PyErr_Fetch(&ptype, &pvalue, &ptraceback);
71   excinfo = PyTuple_New(3);
72   PyTuple_SetItem(excinfo, 0, ptype);
73
74   if (pvalue)
75     PyTuple_SetItem(excinfo, 1, pvalue);
76   else {
77     Py_INCREF(Py_None);
78     PyTuple_SetItem(excinfo, 1, Py_None);
79   }
80
81   if (ptraceback)
82     PyTuple_SetItem(excinfo, 2, ptraceback);
83   else {
84     Py_INCREF(Py_None);
85     PyTuple_SetItem(excinfo, 2, Py_None);
86   }
87
88   self = PyWeakref_GetObject(weak_self);
89   /* self only has a borrowed reference.  */
90   if (self == Py_None) {
91     /* This should not happen, as even if we're called from the data
92        release callback triggered from the wrappers destructor, the
93        object is still alive and hence the weak reference still refers
94        to the object.  However, in case this ever changes, not seeing
95        any exceptions is worse than having a little extra code, so
96        here we go.  */
97       fprintf(stderr,
98               "Error occurred in callback, but the wrapper object "
99               "has been deallocated.\n");
100       PyErr_Restore(ptype, pvalue, ptraceback);
101       PyErr_Print();
102     }
103   else
104     PyObject_SetAttrString(self, EXCINFO, excinfo);
105 }
106
107 PyObject *pygpgme_raise_callback_exception(PyObject *self)
108 {
109   PyObject *ptype, *pvalue, *ptraceback, *excinfo;
110
111   if (! PyObject_HasAttrString(self, EXCINFO))
112     goto leave;
113
114   excinfo = PyObject_GetAttrString(self, EXCINFO);
115   if (! PyTuple_Check(excinfo))
116     {
117       Py_DECREF(excinfo);
118       goto leave;
119     }
120
121   ptype = PyTuple_GetItem(excinfo, 0);
122   Py_INCREF(excinfo);
123
124   pvalue = PyTuple_GetItem(excinfo, 1);
125   if (pvalue == Py_None)
126     pvalue = NULL;
127   else
128     Py_INCREF(pvalue);
129
130   ptraceback = PyTuple_GetItem(excinfo, 2);
131   if (ptraceback == Py_None)
132     ptraceback = NULL;
133   else
134     Py_INCREF(ptraceback);
135
136   Py_DECREF(excinfo);
137   PyErr_Restore(ptype, pvalue, ptraceback);
138
139   Py_INCREF(Py_None);
140   PyObject_SetAttrString(self, EXCINFO, Py_None);
141
142   return NULL; /* Raise exception.  */
143
144  leave:
145   Py_INCREF(Py_None);
146   return Py_None;
147 }
148 #undef EXCINFO
149 \f
150 /* Argument conversion.  */
151
152 /* Convert object to a pointer to gpgme type, generic version.  */
153 PyObject *
154 object_to_gpgme_t(PyObject *input, const char *objtype, int argnum)
155 {
156   PyObject *pyname = NULL, *pypointer = NULL;
157   pyname = PyObject_CallMethod(input, "_getctype", NULL);
158   if (pyname && PyUnicode_Check(pyname))
159     {
160       if (strcmp(PyUnicode_AsUTF8(pyname), objtype) != 0)
161         {
162           PyErr_Format(PyExc_TypeError,
163                        "arg %d: Expected value of type %s, but got %s",
164                        argnum, objtype, PyUnicode_AsUTF8(pyname));
165           Py_DECREF(pyname);
166           return NULL;
167         }
168     }
169   else
170     return NULL;
171
172   Py_DECREF(pyname);
173   pypointer = PyObject_GetAttrString(input, "wrapped");
174   if (pypointer == NULL) {
175     PyErr_Format(PyExc_TypeError,
176                  "arg %d: Use of uninitialized Python object %s",
177                  argnum, objtype);
178     return NULL;
179   }
180   return pypointer;
181 }
182
183 \f
184
185 /* Callback support.  */
186 static gpgme_error_t pyPassphraseCb(void *hook,
187                                     const char *uid_hint,
188                                     const char *passphrase_info,
189                                     int prev_was_bad,
190                                     int fd) {
191   PyObject *pyhook = (PyObject *) hook;
192   PyObject *self = NULL;
193   PyObject *func = NULL;
194   PyObject *args = NULL;
195   PyObject *retval = NULL;
196   PyObject *dataarg = NULL;
197   gpgme_error_t err_status = 0;
198
199   pygpgme_exception_init();
200
201   assert (PyTuple_Check(pyhook));
202   self = PyTuple_GetItem(pyhook, 0);
203   func = PyTuple_GetItem(pyhook, 1);
204   if (PyTuple_Size(pyhook) == 3) {
205     dataarg = PyTuple_GetItem(pyhook, 2);
206     args = PyTuple_New(4);
207   } else {
208     args = PyTuple_New(3);
209   }
210
211   if (uid_hint == NULL)
212     {
213       Py_INCREF(Py_None);
214       PyTuple_SetItem(args, 0, Py_None);
215     }
216   else
217     PyTuple_SetItem(args, 0, PyUnicode_DecodeUTF8(uid_hint, strlen (uid_hint),
218                                                   "strict"));
219   if (PyErr_Occurred()) {
220     Py_DECREF(args);
221     err_status = gpg_error(GPG_ERR_GENERAL);
222     goto leave;
223   }
224
225   PyTuple_SetItem(args, 1, PyBytes_FromString(passphrase_info));
226   PyTuple_SetItem(args, 2, PyBool_FromLong((long)prev_was_bad));
227   if (dataarg) {
228     Py_INCREF(dataarg);         /* Because GetItem doesn't give a ref but SetItem taketh away */
229     PyTuple_SetItem(args, 3, dataarg);
230   }
231
232   retval = PyObject_CallObject(func, args);
233   Py_DECREF(args);
234   if (PyErr_Occurred()) {
235     err_status = pygpgme_exception2code();
236   } else {
237     if (!retval) {
238       write(fd, "\n", 1);
239     } else {
240       char *buf;
241       size_t len;
242       if (PyBytes_Check(retval))
243         buf = PyBytes_AsString(retval), len = PyBytes_Size(retval);
244       else if (PyUnicode_Check(retval))
245         {
246           Py_ssize_t ssize;
247           buf = PyUnicode_AsUTF8AndSize(retval, &ssize);
248           assert (! buf || ssize >= 0);
249           len = (size_t) ssize;
250         }
251       else
252         {
253           PyErr_Format(PyExc_TypeError,
254                        "expected str or bytes from passphrase callback, got %s",
255                        retval->ob_type->tp_name);
256           err_status = gpg_error(GPG_ERR_GENERAL);
257           goto leave;
258         }
259
260       write(fd, buf, len);
261       write(fd, "\n", 1);
262       Py_DECREF(retval);
263     }
264   }
265
266  leave:
267   if (err_status)
268     pygpgme_stash_callback_exception(self);
269
270   return err_status;
271 }
272
273 void pygpgme_set_passphrase_cb(gpgme_ctx_t ctx, PyObject *cb,
274                                PyObject **freelater) {
275   if (cb == Py_None) {
276     gpgme_set_passphrase_cb(ctx, NULL, NULL);
277     return;
278   }
279   Py_INCREF(cb);
280   *freelater = cb;
281   gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t)pyPassphraseCb, (void *) cb);
282 }
283
284 static void pyProgressCb(void *hook, const char *what, int type, int current,
285                          int total) {
286   PyObject *func = NULL, *dataarg = NULL, *args = NULL, *retval = NULL;
287   PyObject *pyhook = (PyObject *) hook;
288   PyObject *self = NULL;
289
290   assert (PyTuple_Check(pyhook));
291   self = PyTuple_GetItem(pyhook, 0);
292   func = PyTuple_GetItem(pyhook, 1);
293   if (PyTuple_Size(pyhook) == 3) {
294     dataarg = PyTuple_GetItem(pyhook, 2);
295     args = PyTuple_New(5);
296   } else {
297     args = PyTuple_New(4);
298   }
299
300   PyTuple_SetItem(args, 0, PyUnicode_DecodeUTF8(what, strlen (what),
301                                                 "strict"));
302   if (PyErr_Occurred()) {
303     pygpgme_stash_callback_exception(self);
304     Py_DECREF(args);
305     return;
306   }
307   PyTuple_SetItem(args, 1, PyLong_FromLong((long) type));
308   PyTuple_SetItem(args, 2, PyLong_FromLong((long) current));
309   PyTuple_SetItem(args, 3, PyLong_FromLong((long) total));
310   if (dataarg) {
311     Py_INCREF(dataarg);         /* Because GetItem doesn't give a ref but SetItem taketh away */
312     PyTuple_SetItem(args, 4, dataarg);
313   }
314
315   retval = PyObject_CallObject(func, args);
316   if (PyErr_Occurred())
317     pygpgme_stash_callback_exception(self);
318   Py_DECREF(args);
319   Py_XDECREF(retval);
320 }
321
322 void pygpgme_set_progress_cb(gpgme_ctx_t ctx, PyObject *cb, PyObject **freelater){
323   if (cb == Py_None) {
324     gpgme_set_progress_cb(ctx, NULL, NULL);
325     return;
326   }
327   Py_INCREF(cb);
328   *freelater = cb;
329   gpgme_set_progress_cb(ctx, (gpgme_progress_cb_t) pyProgressCb, (void *) cb);
330 }
331 \f
332 /* Status callbacks.  */
333 static gpgme_error_t pyStatusCb(void *hook, const char *keyword,
334                                 const char *args) {
335   gpgme_error_t err = 0;
336   PyObject *pyhook = (PyObject *) hook;
337   PyObject *self = NULL;
338   PyObject *func = NULL;
339   PyObject *dataarg = NULL;
340   PyObject *pyargs = NULL;
341   PyObject *retval = NULL;
342
343   assert (PyTuple_Check(pyhook));
344   assert (PyTuple_Size(pyhook) == 2 || PyTuple_Size(pyhook) == 3);
345   self = PyTuple_GetItem(pyhook, 0);
346   func = PyTuple_GetItem(pyhook, 1);
347   if (PyTuple_Size(pyhook) == 3) {
348     dataarg = PyTuple_GetItem(pyhook, 2);
349     pyargs = PyTuple_New(3);
350   } else {
351     pyargs = PyTuple_New(2);
352   }
353
354   if (keyword)
355     PyTuple_SetItem(pyargs, 0, PyUnicode_DecodeUTF8(keyword, strlen (keyword),
356                                                     "strict"));
357   else
358     {
359       Py_INCREF(Py_None);
360       PyTuple_SetItem(pyargs, 0, Py_None);
361     }
362   PyTuple_SetItem(pyargs, 1, PyUnicode_DecodeUTF8(args, strlen (args),
363                                                 "strict"));
364   if (PyErr_Occurred()) {
365     err = gpg_error(GPG_ERR_GENERAL);
366     Py_DECREF(pyargs);
367     goto leave;
368   }
369
370   if (dataarg) {
371     Py_INCREF(dataarg);
372     PyTuple_SetItem(pyargs, 2, dataarg);
373   }
374
375   retval = PyObject_CallObject(func, pyargs);
376   if (PyErr_Occurred())
377     err = pygpgme_exception2code();
378   Py_DECREF(pyargs);
379   Py_XDECREF(retval);
380
381  leave:
382   if (err)
383     pygpgme_stash_callback_exception(self);
384   return err;
385 }
386
387 void pygpgme_set_status_cb(gpgme_ctx_t ctx, PyObject *cb,
388                            PyObject **freelater) {
389   if (cb == Py_None) {
390     gpgme_set_status_cb(ctx, NULL, NULL);
391     return;
392   }
393   Py_INCREF(cb);
394   *freelater = cb;
395   gpgme_set_status_cb(ctx, (gpgme_status_cb_t) pyStatusCb, (void *) cb);
396 }
397 \f
398 /* Edit callbacks.  */
399 gpgme_error_t pyEditCb(void *opaque, gpgme_status_code_t status,
400                        const char *args, int fd) {
401   PyObject *func = NULL, *dataarg = NULL, *pyargs = NULL, *retval = NULL;
402   PyObject *pyopaque = (PyObject *) opaque;
403   gpgme_error_t err_status = 0;
404   PyObject *self = NULL;
405
406   pygpgme_exception_init();
407
408   assert (PyTuple_Check(pyopaque));
409   assert (PyTuple_Size(pyopaque) == 2 || PyTuple_Size(pyopaque) == 3);
410   self = PyTuple_GetItem(pyopaque, 0);
411   func = PyTuple_GetItem(pyopaque, 1);
412   if (PyTuple_Size(pyopaque) == 3) {
413     dataarg = PyTuple_GetItem(pyopaque, 2);
414     pyargs = PyTuple_New(3);
415   } else {
416     pyargs = PyTuple_New(2);
417   }
418
419   PyTuple_SetItem(pyargs, 0, PyLong_FromLong((long) status));
420   PyTuple_SetItem(pyargs, 1, PyUnicode_FromString(args));
421   if (dataarg) {
422     Py_INCREF(dataarg);         /* Because GetItem doesn't give a ref but SetItem taketh away */
423     PyTuple_SetItem(pyargs, 2, dataarg);
424   }
425
426   retval = PyObject_CallObject(func, pyargs);
427   Py_DECREF(pyargs);
428   if (PyErr_Occurred()) {
429     err_status = pygpgme_exception2code();
430     pygpgme_stash_callback_exception(self);
431   } else {
432     if (fd>=0 && retval && PyUnicode_Check(retval)) {
433       const char *buffer;
434       Py_ssize_t size;
435
436       buffer = PyUnicode_AsUTF8AndSize(retval, &size);
437       write(fd, buffer, size);
438       write(fd, "\n", 1);
439     }
440   }
441
442   Py_XDECREF(retval);
443   return err_status;
444 }
445 \f
446 /* Data callbacks.  */
447
448 /* Read up to SIZE bytes into buffer BUFFER from the data object with
449    the handle HOOK.  Return the number of characters read, 0 on EOF
450    and -1 on error.  If an error occurs, errno is set.  */
451 static ssize_t pyDataReadCb(void *hook, void *buffer, size_t size)
452 {
453   ssize_t result;
454   PyObject *pyhook = (PyObject *) hook;
455   PyObject *self = NULL;
456   PyObject *func = NULL;
457   PyObject *dataarg = NULL;
458   PyObject *pyargs = NULL;
459   PyObject *retval = NULL;
460
461   assert (PyTuple_Check(pyhook));
462   assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
463
464   self = PyTuple_GetItem(pyhook, 0);
465   func = PyTuple_GetItem(pyhook, 1);
466   if (PyTuple_Size(pyhook) == 6) {
467     dataarg = PyTuple_GetItem(pyhook, 5);
468     pyargs = PyTuple_New(2);
469   } else {
470     pyargs = PyTuple_New(1);
471   }
472
473   PyTuple_SetItem(pyargs, 0, PyLong_FromSize_t(size));
474   if (dataarg) {
475     Py_INCREF(dataarg);
476     PyTuple_SetItem(pyargs, 1, dataarg);
477   }
478
479   retval = PyObject_CallObject(func, pyargs);
480   Py_DECREF(pyargs);
481   if (PyErr_Occurred()) {
482     pygpgme_stash_callback_exception(self);
483     result = -1;
484     goto leave;
485   }
486
487   if (! PyBytes_Check(retval)) {
488     PyErr_Format(PyExc_TypeError,
489                  "expected bytes from read callback, got %s",
490                  retval->ob_type->tp_name);
491     pygpgme_stash_callback_exception(self);
492     result = -1;
493     goto leave;
494   }
495
496   if (PyBytes_Size(retval) > size) {
497     PyErr_Format(PyExc_TypeError,
498                  "expected %zu bytes from read callback, got %zu",
499                  size, PyBytes_Size(retval));
500     pygpgme_stash_callback_exception(self);
501     result = -1;
502     goto leave;
503   }
504
505   memcpy(buffer, PyBytes_AsString(retval), PyBytes_Size(retval));
506   result = PyBytes_Size(retval);
507
508  leave:
509   Py_XDECREF(retval);
510   return result;
511 }
512
513 /* Write up to SIZE bytes from buffer BUFFER to the data object with
514    the handle HOOK.  Return the number of characters written, or -1
515    on error.  If an error occurs, errno is set.  */
516 static ssize_t pyDataWriteCb(void *hook, const void *buffer, size_t size)
517 {
518   ssize_t result;
519   PyObject *pyhook = (PyObject *) hook;
520   PyObject *self = NULL;
521   PyObject *func = NULL;
522   PyObject *dataarg = NULL;
523   PyObject *pyargs = NULL;
524   PyObject *retval = NULL;
525
526   assert (PyTuple_Check(pyhook));
527   assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
528
529   self = PyTuple_GetItem(pyhook, 0);
530   func = PyTuple_GetItem(pyhook, 2);
531   if (PyTuple_Size(pyhook) == 6) {
532     dataarg = PyTuple_GetItem(pyhook, 5);
533     pyargs = PyTuple_New(2);
534   } else {
535     pyargs = PyTuple_New(1);
536   }
537
538   PyTuple_SetItem(pyargs, 0, PyBytes_FromStringAndSize(buffer, size));
539   if (dataarg) {
540     Py_INCREF(dataarg);
541     PyTuple_SetItem(pyargs, 1, dataarg);
542   }
543
544   retval = PyObject_CallObject(func, pyargs);
545   Py_DECREF(pyargs);
546   if (PyErr_Occurred()) {
547     pygpgme_stash_callback_exception(self);
548     result = -1;
549     goto leave;
550   }
551
552   if (! PyLong_Check(retval)) {
553     PyErr_Format(PyExc_TypeError,
554                  "expected int from read callback, got %s",
555                  retval->ob_type->tp_name);
556     pygpgme_stash_callback_exception(self);
557     result = -1;
558     goto leave;
559   }
560
561   result = PyLong_AsSsize_t(retval);
562
563  leave:
564   Py_XDECREF(retval);
565   return result;
566 }
567
568 /* Set the current position from where the next read or write starts
569    in the data object with the handle HOOK to OFFSET, relativ to
570    WHENCE.  Returns the new offset in bytes from the beginning of the
571    data object.  */
572 static off_t pyDataSeekCb(void *hook, off_t offset, int whence)
573 {
574   off_t result;
575   PyObject *pyhook = (PyObject *) hook;
576   PyObject *self = NULL;
577   PyObject *func = NULL;
578   PyObject *dataarg = NULL;
579   PyObject *pyargs = NULL;
580   PyObject *retval = NULL;
581
582   assert (PyTuple_Check(pyhook));
583   assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
584
585   self = PyTuple_GetItem(pyhook, 0);
586   func = PyTuple_GetItem(pyhook, 3);
587   if (PyTuple_Size(pyhook) == 6) {
588     dataarg = PyTuple_GetItem(pyhook, 5);
589     pyargs = PyTuple_New(3);
590   } else {
591     pyargs = PyTuple_New(2);
592   }
593
594 #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
595   PyTuple_SetItem(pyargs, 0, PyLong_FromLongLong((long long) offset));
596 #else
597   PyTuple_SetItem(pyargs, 0, PyLong_FromLong((long) offset));
598 #endif
599   PyTuple_SetItem(pyargs, 1, PyLong_FromLong((long) whence));
600   if (dataarg) {
601     Py_INCREF(dataarg);
602     PyTuple_SetItem(pyargs, 2, dataarg);
603   }
604
605   retval = PyObject_CallObject(func, pyargs);
606   Py_DECREF(pyargs);
607   if (PyErr_Occurred()) {
608     pygpgme_stash_callback_exception(self);
609     result = -1;
610     goto leave;
611   }
612
613   if (! PyLong_Check(retval)) {
614     PyErr_Format(PyExc_TypeError,
615                  "expected int from read callback, got %s",
616                  retval->ob_type->tp_name);
617     pygpgme_stash_callback_exception(self);
618     result = -1;
619     goto leave;
620   }
621
622 #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
623   result = PyLong_AsLongLong(retval);
624 #else
625   result = PyLong_AsLong(retval);
626 #endif
627
628  leave:
629   Py_XDECREF(retval);
630   return result;
631 }
632
633 /* Close the data object with the handle HOOK.  */
634 static void pyDataReleaseCb(void *hook)
635 {
636   PyObject *pyhook = (PyObject *) hook;
637   PyObject *self = NULL;
638   PyObject *func = NULL;
639   PyObject *dataarg = NULL;
640   PyObject *pyargs = NULL;
641   PyObject *retval = NULL;
642
643   assert (PyTuple_Check(pyhook));
644   assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
645
646   self = PyTuple_GetItem(pyhook, 0);
647   func = PyTuple_GetItem(pyhook, 4);
648   if (PyTuple_Size(pyhook) == 6) {
649     dataarg = PyTuple_GetItem(pyhook, 5);
650     pyargs = PyTuple_New(1);
651   } else {
652     pyargs = PyTuple_New(0);
653   }
654
655   if (dataarg) {
656     Py_INCREF(dataarg);
657     PyTuple_SetItem(pyargs, 0, dataarg);
658   }
659
660   retval = PyObject_CallObject(func, pyargs);
661   Py_XDECREF(retval);
662   Py_DECREF(pyargs);
663   if (PyErr_Occurred())
664     pygpgme_stash_callback_exception(self);
665 }
666
667 gpgme_error_t pygpgme_data_new_from_cbs(gpgme_data_t *r_data,
668                                         PyObject *pycbs,
669                                         PyObject **freelater)
670 {
671   static struct gpgme_data_cbs cbs = {
672     pyDataReadCb,
673     pyDataWriteCb,
674     pyDataSeekCb,
675     pyDataReleaseCb,
676   };
677
678   assert (PyTuple_Check(pycbs));
679   assert (PyTuple_Size(pycbs) == 5 || PyTuple_Size(pycbs) == 6);
680
681   Py_INCREF(pycbs);
682   *freelater = pycbs;
683
684   return gpgme_data_new_from_cbs(r_data, &cbs, (void *) pycbs);
685 }