python: Release the GIL during calls into GPGME.
[gpgme.git] / lang / python / helpers.c
1 /*
2 # Copyright (C) 2016 g10 Code GmbH
3 # Copyright (C) 2004 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
21 #include <assert.h>
22 #include <stdio.h>
23 #include <gpgme.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include "Python.h"
27
28 #include "helpers.h"
29 #include "private.h"
30
31 /* Flag specifying whether this is an in-tree build.  */
32 int pyme_in_tree_build =
33 #if IN_TREE_BUILD
34   1
35 #else
36   0
37 #endif
38   ;
39
40 static PyObject *GPGMEError = NULL;
41
42 void _pyme_exception_init(void) {
43   if (GPGMEError == NULL) {
44     PyObject *errors;
45     PyObject *from_list = PyList_New(0);
46     errors = PyImport_ImportModuleLevel("errors", PyEval_GetGlobals(),
47                                         PyEval_GetLocals(), from_list, 1);
48     Py_XDECREF(from_list);
49     if (errors) {
50       GPGMEError=PyDict_GetItemString(PyModule_GetDict(errors), "GPGMEError");
51       Py_XINCREF(GPGMEError);
52     }
53   }
54 }
55
56 static PyObject *
57 _pyme_raise_exception(gpgme_error_t err)
58 {
59   PyObject *e;
60
61   _pyme_exception_init();
62   if (GPGMEError == NULL)
63     return PyErr_Format(PyExc_RuntimeError, "Got gpgme_error_t %d", err);
64
65   e = PyObject_CallFunction(GPGMEError, "l", (long) err);
66   if (e == NULL)
67     return NULL;
68
69   PyErr_SetObject(GPGMEError, e);
70   Py_DECREF(e);
71
72   return NULL;  /* raise */
73 }
74
75 gpgme_error_t _pyme_exception2code(void) {
76   gpgme_error_t err_status = gpg_error(GPG_ERR_GENERAL);
77   if (GPGMEError && PyErr_ExceptionMatches(GPGMEError)) {
78     PyObject *type = 0, *value = 0, *traceback = 0;
79     PyObject *error = 0;
80     PyErr_Fetch(&type, &value, &traceback);
81     PyErr_NormalizeException(&type, &value, &traceback);
82     error = PyObject_GetAttrString(value, "error");
83     err_status = PyLong_AsLong(error);
84     Py_DECREF(error);
85     PyErr_Restore(type, value, traceback);
86   }
87   return err_status;
88 }
89
90 /* Exception support for callbacks.  */
91 #define EXCINFO "_callback_excinfo"
92
93 static void _pyme_stash_callback_exception(PyObject *weak_self)
94 {
95   PyObject *self, *ptype, *pvalue, *ptraceback, *excinfo;
96
97   PyErr_Fetch(&ptype, &pvalue, &ptraceback);
98   excinfo = PyTuple_New(3);
99   PyTuple_SetItem(excinfo, 0, ptype);
100
101   if (pvalue)
102     PyTuple_SetItem(excinfo, 1, pvalue);
103   else {
104     Py_INCREF(Py_None);
105     PyTuple_SetItem(excinfo, 1, Py_None);
106   }
107
108   if (ptraceback)
109     PyTuple_SetItem(excinfo, 2, ptraceback);
110   else {
111     Py_INCREF(Py_None);
112     PyTuple_SetItem(excinfo, 2, Py_None);
113   }
114
115   self = PyWeakref_GetObject(weak_self);
116   /* self only has a borrowed reference.  */
117   if (self == Py_None) {
118     /* This should not happen, as even if we're called from the data
119        release callback triggered from the wrappers destructor, the
120        object is still alive and hence the weak reference still refers
121        to the object.  However, in case this ever changes, not seeing
122        any exceptions is worse than having a little extra code, so
123        here we go.  */
124       fprintf(stderr,
125               "Error occurred in callback, but the wrapper object "
126               "has been deallocated.\n");
127       PyErr_Restore(ptype, pvalue, ptraceback);
128       PyErr_Print();
129     }
130   else
131     PyObject_SetAttrString(self, EXCINFO, excinfo);
132   Py_DECREF(excinfo);
133 }
134
135 PyObject *pyme_raise_callback_exception(PyObject *self)
136 {
137   PyGILState_STATE state = PyGILState_Ensure();
138   PyObject *ptype, *pvalue, *ptraceback, *excinfo;
139
140   if (! PyObject_HasAttrString(self, EXCINFO))
141     goto leave;
142
143   excinfo = PyObject_GetAttrString(self, EXCINFO);
144   if (! PyTuple_Check(excinfo))
145     {
146       Py_DECREF(excinfo);
147       goto leave;
148     }
149
150   ptype = PyTuple_GetItem(excinfo, 0);
151   Py_INCREF(excinfo);
152
153   pvalue = PyTuple_GetItem(excinfo, 1);
154   if (pvalue == Py_None)
155     pvalue = NULL;
156   else
157     Py_INCREF(pvalue);
158
159   ptraceback = PyTuple_GetItem(excinfo, 2);
160   if (ptraceback == Py_None)
161     ptraceback = NULL;
162   else
163     Py_INCREF(ptraceback);
164
165   /* We now have references for the extracted items.  */
166   Py_DECREF(excinfo);
167
168   /* Clear the exception information.  It is important to do this
169      before setting the error, because setting the attribute may
170      execute python code, and the runtime system raises a SystemError
171      if an exception is set but values are returned.  */
172   Py_INCREF(Py_None);
173   PyObject_SetAttrString(self, EXCINFO, Py_None);
174
175   /* Restore exception.  */
176   PyErr_Restore(ptype, pvalue, ptraceback);
177   PyGILState_Release(state);
178   return NULL; /* Raise exception.  */
179
180  leave:
181   Py_INCREF(Py_None);
182   PyGILState_Release(state);
183   return Py_None;
184 }
185 #undef EXCINFO
186 \f
187 /* Argument conversion.  */
188
189 /* Convert object to a pointer to gpgme type, generic version.  */
190 PyObject *
191 _pyme_obj2gpgme_t(PyObject *input, const char *objtype, int argnum)
192 {
193   PyObject *pyname = NULL, *pypointer = NULL;
194   pyname = PyObject_GetAttrString(input, "_ctype");
195   if (pyname && PyUnicode_Check(pyname))
196     {
197       PyObject *encoded = PyUnicode_AsUTF8String(pyname);
198       if (strcmp(PyBytes_AsString(encoded), objtype) != 0)
199         {
200           PyErr_Format(PyExc_TypeError,
201                        "arg %d: Expected value of type %s, but got %s",
202                        argnum, objtype, PyBytes_AsString(encoded));
203           Py_DECREF(encoded);
204           Py_DECREF(pyname);
205           return NULL;
206         }
207       Py_DECREF(encoded);
208     }
209   else
210     return NULL;
211
212   Py_DECREF(pyname);
213   pypointer = PyObject_GetAttrString(input, "wrapped");
214   if (pypointer == NULL) {
215     PyErr_Format(PyExc_TypeError,
216                  "arg %d: Use of uninitialized Python object %s",
217                  argnum, objtype);
218     return NULL;
219   }
220   return pypointer;
221 }
222
223 /* Convert object to a pointer to gpgme type, version for data
224    objects.  Constructs a wrapper Python on the fly e.g. for file-like
225    objects with a fileno method, returning it in WRAPPER.  This object
226    must be de-referenced when no longer needed.  */
227 PyObject *
228 _pyme_obj2gpgme_data_t(PyObject *input, int argnum, gpgme_data_t *wrapper,
229                        PyObject **bytesio, Py_buffer *view)
230 {
231   gpgme_error_t err;
232   PyObject *data;
233   PyObject *fd;
234
235   /* See if it is a file-like object with file number.  */
236   fd = PyObject_CallMethod(input, "fileno", NULL);
237   if (fd) {
238     err = gpgme_data_new_from_fd(wrapper, (int) PyLong_AsLong(fd));
239     Py_DECREF(fd);
240     if (err)
241       return _pyme_raise_exception (err);
242
243     return _pyme_wrap_gpgme_data_t(*wrapper);
244   }
245   else
246     PyErr_Clear();
247
248   /* No?  Maybe it implements the buffer protocol.  */
249   data = PyObject_CallMethod(input, "getbuffer", NULL);
250   if (data)
251     {
252       /* Save a reference to input, which seems to be a BytesIO
253          object.  */
254       Py_INCREF(input);
255       *bytesio = input;
256     }
257   else
258     {
259       PyErr_Clear();
260
261       /* No, but maybe the user supplied a buffer object?  */
262       data = input;
263     }
264
265   /* Do we have a buffer object?  */
266   if (PyObject_CheckBuffer(data))
267     {
268       if (PyObject_GetBuffer(data, view, PyBUF_SIMPLE) < 0)
269         return NULL;
270
271       if (data != input)
272         Py_DECREF(data);
273
274       assert (view->obj);
275       assert (view->ndim == 1);
276       assert (view->shape == NULL);
277       assert (view->strides == NULL);
278       assert (view->suboffsets == NULL);
279
280       err = gpgme_data_new_from_mem(wrapper, view->buf, (size_t) view->len, 0);
281       if (err)
282         return _pyme_raise_exception (err);
283
284       return _pyme_wrap_gpgme_data_t(*wrapper);
285     }
286
287   /* As last resort we assume it is a wrapped data object.  */
288   if (PyObject_HasAttrString(data, "_ctype"))
289     return _pyme_obj2gpgme_t(data, "gpgme_data_t", argnum);
290
291   return PyErr_Format(PyExc_TypeError,
292                       "arg %d: expected pyme.Data, file, or an object "
293                       "implementing the buffer protocol, got %s",
294                       argnum, data->ob_type->tp_name);
295 }
296
297 \f
298
299 PyObject *
300 _pyme_wrap_result(PyObject *fragile, const char *classname)
301 {
302   static PyObject *results;
303   PyObject *class;
304   PyObject *replacement;
305
306   if (results == NULL)
307     {
308       PyObject *from_list = PyList_New(0);
309       if (from_list == NULL)
310         return NULL;
311
312       results = PyImport_ImportModuleLevel("results", PyEval_GetGlobals(),
313                                            PyEval_GetLocals(), from_list, 1);
314       Py_DECREF(from_list);
315
316       if (results == NULL)
317         return NULL;
318     }
319
320   class = PyMapping_GetItemString(PyModule_GetDict(results), classname);
321   if (class == NULL)
322     return NULL;
323
324   replacement = PyObject_CallFunctionObjArgs(class, fragile, NULL);
325   Py_DECREF(class);
326   return replacement;
327 }
328
329 \f
330
331 /* Callback support.  */
332 static gpgme_error_t pyPassphraseCb(void *hook,
333                                     const char *uid_hint,
334                                     const char *passphrase_info,
335                                     int prev_was_bad,
336                                     int fd) {
337   PyGILState_STATE state = PyGILState_Ensure();
338   PyObject *pyhook = (PyObject *) hook;
339   PyObject *self = NULL;
340   PyObject *func = NULL;
341   PyObject *args = NULL;
342   PyObject *retval = NULL;
343   PyObject *dataarg = NULL;
344   PyObject *encoded = NULL;
345   gpgme_error_t err_status = 0;
346
347   _pyme_exception_init();
348
349   assert (PyTuple_Check(pyhook));
350   assert (PyTuple_Size(pyhook) == 2 || PyTuple_Size(pyhook) == 3);
351   self = PyTuple_GetItem(pyhook, 0);
352   func = PyTuple_GetItem(pyhook, 1);
353   if (PyTuple_Size(pyhook) == 3) {
354     dataarg = PyTuple_GetItem(pyhook, 2);
355     args = PyTuple_New(4);
356   } else {
357     args = PyTuple_New(3);
358   }
359
360   if (uid_hint == NULL)
361     {
362       Py_INCREF(Py_None);
363       PyTuple_SetItem(args, 0, Py_None);
364     }
365   else
366     PyTuple_SetItem(args, 0, PyUnicode_DecodeUTF8(uid_hint, strlen (uid_hint),
367                                                   "strict"));
368   if (PyErr_Occurred()) {
369     Py_DECREF(args);
370     err_status = gpg_error(GPG_ERR_GENERAL);
371     goto leave;
372   }
373
374   PyTuple_SetItem(args, 1, PyBytes_FromString(passphrase_info));
375   PyTuple_SetItem(args, 2, PyBool_FromLong((long)prev_was_bad));
376   if (dataarg) {
377     Py_INCREF(dataarg);         /* Because GetItem doesn't give a ref but SetItem taketh away */
378     PyTuple_SetItem(args, 3, dataarg);
379   }
380
381   retval = PyObject_CallObject(func, args);
382   Py_DECREF(args);
383   if (PyErr_Occurred()) {
384     err_status = _pyme_exception2code();
385   } else {
386     if (!retval) {
387       if (write(fd, "\n", 1) < 0) {
388         err_status = gpgme_error_from_syserror ();
389         _pyme_raise_exception (err_status);
390       }
391     } else {
392       char *buf;
393       size_t len;
394       if (PyBytes_Check(retval))
395         buf = PyBytes_AsString(retval), len = PyBytes_Size(retval);
396       else if (PyUnicode_Check(retval))
397         {
398           Py_ssize_t ssize;
399           encoded = PyUnicode_AsUTF8String(retval);
400           if (encoded == NULL)
401             {
402               err_status = gpg_error(GPG_ERR_GENERAL);
403               goto leave;
404             }
405           if (PyBytes_AsStringAndSize(encoded, &buf, &ssize) == -1)
406             {
407               err_status = gpg_error(GPG_ERR_GENERAL);
408               goto leave;
409             }
410           assert (! buf || ssize >= 0);
411           len = (size_t) ssize;
412         }
413       else
414         {
415           PyErr_Format(PyExc_TypeError,
416                        "expected str or bytes from passphrase callback, got %s",
417                        retval->ob_type->tp_name);
418           err_status = gpg_error(GPG_ERR_GENERAL);
419           goto leave;
420         }
421
422       if (write(fd, buf, len) < 0) {
423         err_status = gpgme_error_from_syserror ();
424         _pyme_raise_exception (err_status);
425       }
426       if (! err_status && write(fd, "\n", 1) < 0) {
427         err_status = gpgme_error_from_syserror ();
428         _pyme_raise_exception (err_status);
429       }
430
431       Py_DECREF(retval);
432     }
433   }
434
435  leave:
436   if (err_status)
437     _pyme_stash_callback_exception(self);
438
439   Py_XDECREF(encoded);
440   PyGILState_Release(state);
441   return err_status;
442 }
443
444 PyObject *
445 pyme_set_passphrase_cb(PyObject *self, PyObject *cb) {
446   PyGILState_STATE state = PyGILState_Ensure();
447   PyObject *wrapped;
448   gpgme_ctx_t ctx;
449
450   wrapped = PyObject_GetAttrString(self, "wrapped");
451   if (wrapped == NULL)
452     {
453       assert (PyErr_Occurred ());
454       PyGILState_Release(state);
455       return NULL;
456     }
457
458   ctx = _pyme_unwrap_gpgme_ctx_t(wrapped);
459   Py_DECREF(wrapped);
460   if (ctx == NULL)
461     {
462       if (cb == Py_None)
463         goto out;
464       else
465         return PyErr_Format(PyExc_RuntimeError, "wrapped is NULL");
466     }
467
468   if (cb == Py_None) {
469     gpgme_set_passphrase_cb(ctx, NULL, NULL);
470     PyObject_SetAttrString(self, "_passphrase_cb", Py_None);
471     goto out;
472   }
473
474   if (! PyTuple_Check(cb))
475     return PyErr_Format(PyExc_TypeError, "cb must be a tuple");
476   if (PyTuple_Size(cb) != 2 && PyTuple_Size(cb) != 3)
477     return PyErr_Format(PyExc_TypeError,
478                         "cb must be a tuple of size 2 or 3");
479
480   gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t) pyPassphraseCb,
481                           (void *) cb);
482   PyObject_SetAttrString(self, "_passphrase_cb", cb);
483
484  out:
485   Py_INCREF(Py_None);
486   PyGILState_Release(state);
487   return Py_None;
488 }
489
490 static void pyProgressCb(void *hook, const char *what, int type, int current,
491                          int total) {
492   PyGILState_STATE state = PyGILState_Ensure();
493   PyObject *func = NULL, *dataarg = NULL, *args = NULL, *retval = NULL;
494   PyObject *pyhook = (PyObject *) hook;
495   PyObject *self = NULL;
496
497   assert (PyTuple_Check(pyhook));
498   assert (PyTuple_Size(pyhook) == 2 || PyTuple_Size(pyhook) == 3);
499   self = PyTuple_GetItem(pyhook, 0);
500   func = PyTuple_GetItem(pyhook, 1);
501   if (PyTuple_Size(pyhook) == 3) {
502     dataarg = PyTuple_GetItem(pyhook, 2);
503     args = PyTuple_New(5);
504   } else {
505     args = PyTuple_New(4);
506   }
507
508   PyTuple_SetItem(args, 0, PyUnicode_DecodeUTF8(what, strlen (what),
509                                                 "strict"));
510   if (PyErr_Occurred()) {
511     _pyme_stash_callback_exception(self);
512     Py_DECREF(args);
513     PyGILState_Release(state);
514     return;
515   }
516   PyTuple_SetItem(args, 1, PyLong_FromLong((long) type));
517   PyTuple_SetItem(args, 2, PyLong_FromLong((long) current));
518   PyTuple_SetItem(args, 3, PyLong_FromLong((long) total));
519   if (dataarg) {
520     Py_INCREF(dataarg);         /* Because GetItem doesn't give a ref but SetItem taketh away */
521     PyTuple_SetItem(args, 4, dataarg);
522   }
523
524   retval = PyObject_CallObject(func, args);
525   if (PyErr_Occurred())
526     _pyme_stash_callback_exception(self);
527   Py_DECREF(args);
528   Py_XDECREF(retval);
529   PyGILState_Release(state);
530 }
531
532 PyObject *
533 pyme_set_progress_cb(PyObject *self, PyObject *cb) {
534   PyGILState_STATE state = PyGILState_Ensure();
535   PyObject *wrapped;
536   gpgme_ctx_t ctx;
537
538   wrapped = PyObject_GetAttrString(self, "wrapped");
539   if (wrapped == NULL)
540     {
541       assert (PyErr_Occurred ());
542       PyGILState_Release(state);
543       return NULL;
544     }
545
546   ctx = _pyme_unwrap_gpgme_ctx_t(wrapped);
547   Py_DECREF(wrapped);
548   if (ctx == NULL)
549     {
550       if (cb == Py_None)
551         goto out;
552       else
553         return PyErr_Format(PyExc_RuntimeError, "wrapped is NULL");
554     }
555
556   if (cb == Py_None) {
557     gpgme_set_progress_cb(ctx, NULL, NULL);
558     PyObject_SetAttrString(self, "_progress_cb", Py_None);
559     goto out;
560   }
561
562   if (! PyTuple_Check(cb))
563     return PyErr_Format(PyExc_TypeError, "cb must be a tuple");
564   if (PyTuple_Size(cb) != 2 && PyTuple_Size(cb) != 3)
565     return PyErr_Format(PyExc_TypeError,
566                         "cb must be a tuple of size 2 or 3");
567
568   gpgme_set_progress_cb(ctx, (gpgme_progress_cb_t) pyProgressCb, (void *) cb);
569   PyObject_SetAttrString(self, "_progress_cb", cb);
570
571  out:
572   Py_INCREF(Py_None);
573   PyGILState_Release(state);
574   return Py_None;
575 }
576 \f
577 /* Status callbacks.  */
578 static gpgme_error_t pyStatusCb(void *hook, const char *keyword,
579                                 const char *args) {
580   PyGILState_STATE state = PyGILState_Ensure();
581   gpgme_error_t err = 0;
582   PyObject *pyhook = (PyObject *) hook;
583   PyObject *self = NULL;
584   PyObject *func = NULL;
585   PyObject *dataarg = NULL;
586   PyObject *pyargs = NULL;
587   PyObject *retval = NULL;
588
589   assert (PyTuple_Check(pyhook));
590   assert (PyTuple_Size(pyhook) == 2 || PyTuple_Size(pyhook) == 3);
591   self = PyTuple_GetItem(pyhook, 0);
592   func = PyTuple_GetItem(pyhook, 1);
593   if (PyTuple_Size(pyhook) == 3) {
594     dataarg = PyTuple_GetItem(pyhook, 2);
595     pyargs = PyTuple_New(3);
596   } else {
597     pyargs = PyTuple_New(2);
598   }
599
600   if (keyword)
601     PyTuple_SetItem(pyargs, 0, PyUnicode_DecodeUTF8(keyword, strlen (keyword),
602                                                     "strict"));
603   else
604     {
605       Py_INCREF(Py_None);
606       PyTuple_SetItem(pyargs, 0, Py_None);
607     }
608   PyTuple_SetItem(pyargs, 1, PyUnicode_DecodeUTF8(args, strlen (args),
609                                                 "strict"));
610   if (PyErr_Occurred()) {
611     err = gpg_error(GPG_ERR_GENERAL);
612     Py_DECREF(pyargs);
613     goto leave;
614   }
615
616   if (dataarg) {
617     Py_INCREF(dataarg);
618     PyTuple_SetItem(pyargs, 2, dataarg);
619   }
620
621   retval = PyObject_CallObject(func, pyargs);
622   if (PyErr_Occurred())
623     err = _pyme_exception2code();
624   Py_DECREF(pyargs);
625   Py_XDECREF(retval);
626
627  leave:
628   if (err)
629     _pyme_stash_callback_exception(self);
630   PyGILState_Release(state);
631   return err;
632 }
633
634 PyObject *
635 pyme_set_status_cb(PyObject *self, PyObject *cb) {
636   PyGILState_STATE state = PyGILState_Ensure();
637   PyObject *wrapped;
638   gpgme_ctx_t ctx;
639
640   wrapped = PyObject_GetAttrString(self, "wrapped");
641   if (wrapped == NULL)
642     {
643       assert (PyErr_Occurred ());
644       PyGILState_Release(state);
645       return NULL;
646     }
647
648   ctx = _pyme_unwrap_gpgme_ctx_t(wrapped);
649   Py_DECREF(wrapped);
650   if (ctx == NULL)
651     {
652       if (cb == Py_None)
653         goto out;
654       else
655         return PyErr_Format(PyExc_RuntimeError, "wrapped is NULL");
656     }
657
658   if (cb == Py_None) {
659     gpgme_set_status_cb(ctx, NULL, NULL);
660     PyObject_SetAttrString(self, "_status_cb", Py_None);
661     goto out;
662   }
663
664   if (! PyTuple_Check(cb))
665     return PyErr_Format(PyExc_TypeError, "cb must be a tuple");
666   if (PyTuple_Size(cb) != 2 && PyTuple_Size(cb) != 3)
667     return PyErr_Format(PyExc_TypeError,
668                         "cb must be a tuple of size 2 or 3");
669
670   gpgme_set_status_cb(ctx, (gpgme_status_cb_t) pyStatusCb, (void *) cb);
671   PyObject_SetAttrString(self, "_status_cb", cb);
672
673  out:
674   Py_INCREF(Py_None);
675   PyGILState_Release(state);
676   return Py_None;
677 }
678
679 \f
680
681 /* Interact callbacks.  */
682 gpgme_error_t
683 _pyme_interact_cb(void *opaque, const char *keyword,
684                   const char *args, int fd)
685 {
686   PyGILState_STATE state = PyGILState_Ensure();
687   PyObject *func = NULL, *dataarg = NULL, *pyargs = NULL, *retval = NULL;
688   PyObject *py_keyword;
689   PyObject *pyopaque = (PyObject *) opaque;
690   gpgme_error_t err_status = 0;
691   PyObject *self = NULL;
692
693   _pyme_exception_init();
694
695   assert (PyTuple_Check(pyopaque));
696   assert (PyTuple_Size(pyopaque) == 2 || PyTuple_Size(pyopaque) == 3);
697   self = PyTuple_GetItem(pyopaque, 0);
698   func = PyTuple_GetItem(pyopaque, 1);
699   if (PyTuple_Size(pyopaque) == 3) {
700     dataarg = PyTuple_GetItem(pyopaque, 2);
701     pyargs = PyTuple_New(3);
702   } else {
703     pyargs = PyTuple_New(2);
704   }
705
706   if (keyword)
707     py_keyword = PyUnicode_FromString(keyword);
708   else
709     {
710       Py_INCREF(Py_None);
711       py_keyword = Py_None;
712     }
713
714   PyTuple_SetItem(pyargs, 0, py_keyword);
715   PyTuple_SetItem(pyargs, 1, PyUnicode_FromString(args));
716   if (dataarg) {
717     Py_INCREF(dataarg);         /* Because GetItem doesn't give a ref but SetItem taketh away */
718     PyTuple_SetItem(pyargs, 2, dataarg);
719   }
720
721   retval = PyObject_CallObject(func, pyargs);
722   Py_DECREF(pyargs);
723   if (PyErr_Occurred()) {
724     err_status = _pyme_exception2code();
725   } else {
726     if (fd>=0 && retval && PyUnicode_Check(retval)) {
727       PyObject *encoded = NULL;
728       char *buffer;
729       Py_ssize_t size;
730
731       encoded = PyUnicode_AsUTF8String(retval);
732       if (encoded == NULL)
733         {
734           err_status = gpg_error(GPG_ERR_GENERAL);
735           goto leave;
736         }
737       if (PyBytes_AsStringAndSize(encoded, &buffer, &size) == -1)
738         {
739           Py_DECREF(encoded);
740           err_status = gpg_error(GPG_ERR_GENERAL);
741           goto leave;
742         }
743
744       if (write(fd, buffer, size) < 0) {
745         err_status = gpgme_error_from_syserror ();
746         _pyme_raise_exception (err_status);
747       }
748       if (! err_status && write(fd, "\n", 1) < 0) {
749         err_status = gpgme_error_from_syserror ();
750         _pyme_raise_exception (err_status);
751       }
752       Py_DECREF(encoded);
753     }
754   }
755  leave:
756   if (err_status)
757     _pyme_stash_callback_exception(self);
758
759   Py_XDECREF(retval);
760   PyGILState_Release(state);
761   return err_status;
762 }
763
764 \f
765
766 /* Data callbacks.  */
767
768 /* Read up to SIZE bytes into buffer BUFFER from the data object with
769    the handle HOOK.  Return the number of characters read, 0 on EOF
770    and -1 on error.  If an error occurs, errno is set.  */
771 static ssize_t pyDataReadCb(void *hook, void *buffer, size_t size)
772 {
773   PyGILState_STATE state = PyGILState_Ensure();
774   ssize_t result;
775   PyObject *pyhook = (PyObject *) hook;
776   PyObject *self = NULL;
777   PyObject *func = NULL;
778   PyObject *dataarg = NULL;
779   PyObject *pyargs = NULL;
780   PyObject *retval = NULL;
781
782   assert (PyTuple_Check(pyhook));
783   assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
784
785   self = PyTuple_GetItem(pyhook, 0);
786   func = PyTuple_GetItem(pyhook, 1);
787   if (PyTuple_Size(pyhook) == 6) {
788     dataarg = PyTuple_GetItem(pyhook, 5);
789     pyargs = PyTuple_New(2);
790   } else {
791     pyargs = PyTuple_New(1);
792   }
793
794   PyTuple_SetItem(pyargs, 0, PyLong_FromSize_t(size));
795   if (dataarg) {
796     Py_INCREF(dataarg);
797     PyTuple_SetItem(pyargs, 1, dataarg);
798   }
799
800   retval = PyObject_CallObject(func, pyargs);
801   Py_DECREF(pyargs);
802   if (PyErr_Occurred()) {
803     _pyme_stash_callback_exception(self);
804     result = -1;
805     goto leave;
806   }
807
808   if (! PyBytes_Check(retval)) {
809     PyErr_Format(PyExc_TypeError,
810                  "expected bytes from read callback, got %s",
811                  retval->ob_type->tp_name);
812     _pyme_stash_callback_exception(self);
813     result = -1;
814     goto leave;
815   }
816
817   if (PyBytes_Size(retval) > size) {
818     PyErr_Format(PyExc_TypeError,
819                  "expected %zu bytes from read callback, got %zu",
820                  size, PyBytes_Size(retval));
821     _pyme_stash_callback_exception(self);
822     result = -1;
823     goto leave;
824   }
825
826   memcpy(buffer, PyBytes_AsString(retval), PyBytes_Size(retval));
827   result = PyBytes_Size(retval);
828
829  leave:
830   Py_XDECREF(retval);
831   PyGILState_Release(state);
832   return result;
833 }
834
835 /* Write up to SIZE bytes from buffer BUFFER to the data object with
836    the handle HOOK.  Return the number of characters written, or -1
837    on error.  If an error occurs, errno is set.  */
838 static ssize_t pyDataWriteCb(void *hook, const void *buffer, size_t size)
839 {
840   PyGILState_STATE state = PyGILState_Ensure();
841   ssize_t result;
842   PyObject *pyhook = (PyObject *) hook;
843   PyObject *self = NULL;
844   PyObject *func = NULL;
845   PyObject *dataarg = NULL;
846   PyObject *pyargs = NULL;
847   PyObject *retval = NULL;
848
849   assert (PyTuple_Check(pyhook));
850   assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
851
852   self = PyTuple_GetItem(pyhook, 0);
853   func = PyTuple_GetItem(pyhook, 2);
854   if (PyTuple_Size(pyhook) == 6) {
855     dataarg = PyTuple_GetItem(pyhook, 5);
856     pyargs = PyTuple_New(2);
857   } else {
858     pyargs = PyTuple_New(1);
859   }
860
861   PyTuple_SetItem(pyargs, 0, PyBytes_FromStringAndSize(buffer, size));
862   if (dataarg) {
863     Py_INCREF(dataarg);
864     PyTuple_SetItem(pyargs, 1, dataarg);
865   }
866
867   retval = PyObject_CallObject(func, pyargs);
868   Py_DECREF(pyargs);
869   if (PyErr_Occurred()) {
870     _pyme_stash_callback_exception(self);
871     result = -1;
872     goto leave;
873   }
874
875 #if PY_MAJOR_VERSION < 3
876   if (PyInt_Check(retval))
877     result = PyInt_AsSsize_t(retval);
878   else
879 #endif
880   if (PyLong_Check(retval))
881     result = PyLong_AsSsize_t(retval);
882   else {
883     PyErr_Format(PyExc_TypeError,
884                  "expected int from write callback, got %s",
885                  retval->ob_type->tp_name);
886     _pyme_stash_callback_exception(self);
887     result = -1;
888   }
889
890  leave:
891   Py_XDECREF(retval);
892   PyGILState_Release(state);
893   return result;
894 }
895
896 /* Set the current position from where the next read or write starts
897    in the data object with the handle HOOK to OFFSET, relativ to
898    WHENCE.  Returns the new offset in bytes from the beginning of the
899    data object.  */
900 static off_t pyDataSeekCb(void *hook, off_t offset, int whence)
901 {
902   PyGILState_STATE state = PyGILState_Ensure();
903   off_t result;
904   PyObject *pyhook = (PyObject *) hook;
905   PyObject *self = NULL;
906   PyObject *func = NULL;
907   PyObject *dataarg = NULL;
908   PyObject *pyargs = NULL;
909   PyObject *retval = NULL;
910
911   assert (PyTuple_Check(pyhook));
912   assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
913
914   self = PyTuple_GetItem(pyhook, 0);
915   func = PyTuple_GetItem(pyhook, 3);
916   if (PyTuple_Size(pyhook) == 6) {
917     dataarg = PyTuple_GetItem(pyhook, 5);
918     pyargs = PyTuple_New(3);
919   } else {
920     pyargs = PyTuple_New(2);
921   }
922
923 #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
924   PyTuple_SetItem(pyargs, 0, PyLong_FromLongLong((long long) offset));
925 #else
926   PyTuple_SetItem(pyargs, 0, PyLong_FromLong((long) offset));
927 #endif
928   PyTuple_SetItem(pyargs, 1, PyLong_FromLong((long) whence));
929   if (dataarg) {
930     Py_INCREF(dataarg);
931     PyTuple_SetItem(pyargs, 2, dataarg);
932   }
933
934   retval = PyObject_CallObject(func, pyargs);
935   Py_DECREF(pyargs);
936   if (PyErr_Occurred()) {
937     _pyme_stash_callback_exception(self);
938     result = -1;
939     goto leave;
940   }
941
942 #if PY_MAJOR_VERSION < 3
943   if (PyInt_Check(retval))
944     result = PyInt_AsLong(retval);
945   else
946 #endif
947   if (PyLong_Check(retval))
948 #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
949     result = PyLong_AsLongLong(retval);
950 #else
951     result = PyLong_AsLong(retval);
952 #endif
953   else {
954     PyErr_Format(PyExc_TypeError,
955                  "expected int from seek callback, got %s",
956                  retval->ob_type->tp_name);
957     _pyme_stash_callback_exception(self);
958     result = -1;
959   }
960
961  leave:
962   Py_XDECREF(retval);
963   PyGILState_Release(state);
964   return result;
965 }
966
967 /* Close the data object with the handle HOOK.  */
968 static void pyDataReleaseCb(void *hook)
969 {
970   PyGILState_STATE state = PyGILState_Ensure();
971   PyObject *pyhook = (PyObject *) hook;
972   PyObject *self = NULL;
973   PyObject *func = NULL;
974   PyObject *dataarg = NULL;
975   PyObject *pyargs = NULL;
976   PyObject *retval = NULL;
977
978   assert (PyTuple_Check(pyhook));
979   assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
980
981   self = PyTuple_GetItem(pyhook, 0);
982   func = PyTuple_GetItem(pyhook, 4);
983   if (PyTuple_Size(pyhook) == 6) {
984     dataarg = PyTuple_GetItem(pyhook, 5);
985     pyargs = PyTuple_New(1);
986   } else {
987     pyargs = PyTuple_New(0);
988   }
989
990   if (dataarg) {
991     Py_INCREF(dataarg);
992     PyTuple_SetItem(pyargs, 0, dataarg);
993   }
994
995   retval = PyObject_CallObject(func, pyargs);
996   Py_XDECREF(retval);
997   Py_DECREF(pyargs);
998   if (PyErr_Occurred())
999     _pyme_stash_callback_exception(self);
1000   PyGILState_Release(state);
1001 }
1002
1003 PyObject *
1004 pyme_data_new_from_cbs(PyObject *self,
1005                        PyObject *pycbs,
1006                        gpgme_data_t *r_data)
1007 {
1008   PyGILState_STATE state = PyGILState_Ensure();
1009   static struct gpgme_data_cbs cbs = {
1010     pyDataReadCb,
1011     pyDataWriteCb,
1012     pyDataSeekCb,
1013     pyDataReleaseCb,
1014   };
1015   gpgme_error_t err;
1016
1017   if (! PyTuple_Check(pycbs))
1018     return PyErr_Format(PyExc_TypeError, "pycbs must be a tuple");
1019   if (PyTuple_Size(pycbs) != 5 && PyTuple_Size(pycbs) != 6)
1020     return PyErr_Format(PyExc_TypeError,
1021                         "pycbs must be a tuple of size 5 or 6");
1022
1023   err = gpgme_data_new_from_cbs(r_data, &cbs, (void *) pycbs);
1024   if (err)
1025     return _pyme_raise_exception(err);
1026
1027   PyObject_SetAttrString(self, "_data_cbs", pycbs);
1028
1029   Py_INCREF(Py_None);
1030   PyGILState_Release(state);
1031   return Py_None;
1032 }
1033
1034 \f
1035
1036 /* The assuan callbacks.  */
1037
1038 gpgme_error_t
1039 _pyme_assuan_data_cb (void *hook, const void *data, size_t datalen)
1040 {
1041   PyGILState_STATE state = PyGILState_Ensure();
1042   gpgme_error_t err = 0;
1043   PyObject *pyhook = (PyObject *) hook;
1044   PyObject *self = NULL;
1045   PyObject *func = NULL;
1046   PyObject *py_data = NULL;
1047   PyObject *retval = NULL;
1048
1049   assert (PyTuple_Check(pyhook));
1050   assert (PyTuple_Size(pyhook) == 2);
1051   self = PyTuple_GetItem(pyhook, 0);
1052   func = PyTuple_GetItem(pyhook, 1);
1053   assert (PyCallable_Check(func));
1054
1055   py_data = PyBytes_FromStringAndSize(data, datalen);
1056   if (py_data == NULL)
1057     {
1058       err = _pyme_exception2code();
1059       goto leave;
1060     }
1061
1062   retval = PyObject_CallFunctionObjArgs(func, py_data, NULL);
1063   if (PyErr_Occurred())
1064     err = _pyme_exception2code();
1065   Py_DECREF(py_data);
1066   Py_XDECREF(retval);
1067
1068  leave:
1069   if (err)
1070     _pyme_stash_callback_exception(self);
1071   PyGILState_Release(state);
1072   return err;
1073 }
1074
1075 gpgme_error_t
1076 _pyme_assuan_inquire_cb (void *hook, const char *name, const char *args,
1077                          gpgme_data_t *r_data)
1078 {
1079   PyGILState_STATE state = PyGILState_Ensure();
1080   gpgme_error_t err = 0;
1081   PyObject *pyhook = (PyObject *) hook;
1082   PyObject *self = NULL;
1083   PyObject *func = NULL;
1084   PyObject *py_name = NULL;
1085   PyObject *py_args = NULL;
1086   PyObject *retval = NULL;
1087
1088   assert (PyTuple_Check(pyhook));
1089   assert (PyTuple_Size(pyhook) == 2);
1090   self = PyTuple_GetItem(pyhook, 0);
1091   func = PyTuple_GetItem(pyhook, 1);
1092   assert (PyCallable_Check(func));
1093
1094   py_name = PyUnicode_FromString(name);
1095   if (py_name == NULL)
1096     {
1097       err = _pyme_exception2code();
1098       goto leave;
1099     }
1100
1101   py_args = PyUnicode_FromString(args);
1102   if (py_args == NULL)
1103     {
1104       err = _pyme_exception2code();
1105       goto leave;
1106     }
1107
1108   retval = PyObject_CallFunctionObjArgs(func, py_name, py_args, NULL);
1109   if (PyErr_Occurred())
1110     err = _pyme_exception2code();
1111   Py_XDECREF(retval);
1112
1113   /* FIXME: Returning data is not yet implemented.  */
1114   *r_data = NULL;
1115
1116  leave:
1117   Py_XDECREF(py_name);
1118   Py_XDECREF(py_args);
1119   if (err)
1120     _pyme_stash_callback_exception(self);
1121   PyGILState_Release(state);
1122   return err;
1123 }
1124
1125 gpgme_error_t
1126 _pyme_assuan_status_cb (void *hook, const char *status, const char *args)
1127 {
1128   PyGILState_STATE state = PyGILState_Ensure();
1129   gpgme_error_t err = 0;
1130   PyObject *pyhook = (PyObject *) hook;
1131   PyObject *self = NULL;
1132   PyObject *func = NULL;
1133   PyObject *py_status = NULL;
1134   PyObject *py_args = NULL;
1135   PyObject *retval = NULL;
1136
1137   assert (PyTuple_Check(pyhook));
1138   assert (PyTuple_Size(pyhook) == 2);
1139   self = PyTuple_GetItem(pyhook, 0);
1140   func = PyTuple_GetItem(pyhook, 1);
1141   assert (PyCallable_Check(func));
1142
1143   py_status = PyUnicode_FromString(status);
1144   if (py_status == NULL)
1145     {
1146       err = _pyme_exception2code();
1147       goto leave;
1148     }
1149
1150   py_args = PyUnicode_FromString(args);
1151   if (py_args == NULL)
1152     {
1153       err = _pyme_exception2code();
1154       goto leave;
1155     }
1156
1157   retval = PyObject_CallFunctionObjArgs(func, py_status, py_args, NULL);
1158   if (PyErr_Occurred())
1159     err = _pyme_exception2code();
1160   Py_XDECREF(retval);
1161
1162  leave:
1163   Py_XDECREF(py_status);
1164   Py_XDECREF(py_args);
1165   if (err)
1166     _pyme_stash_callback_exception(self);
1167   PyGILState_Release(state);
1168   return err;
1169 }