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