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