LCOV - code coverage report
Current view: top level - build/lang/python - helpers.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 429 523 82.0 %
Date: 2016-09-12 13:07:23 Functions: 21 23 91.3 %

          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          27 : static void _pyme_stash_callback_exception(PyObject *weak_self)
      94             : {
      95             :   PyObject *self, *ptype, *pvalue, *ptraceback, *excinfo;
      96             : 
      97          27 :   PyErr_Fetch(&ptype, &pvalue, &ptraceback);
      98          27 :   excinfo = PyTuple_New(3);
      99          27 :   PyTuple_SetItem(excinfo, 0, ptype);
     100             : 
     101          27 :   if (pvalue)
     102          27 :     PyTuple_SetItem(excinfo, 1, pvalue);
     103             :   else {
     104           0 :     Py_INCREF(Py_None);
     105           0 :     PyTuple_SetItem(excinfo, 1, Py_None);
     106             :   }
     107             : 
     108          27 :   if (ptraceback)
     109          22 :     PyTuple_SetItem(excinfo, 2, ptraceback);
     110             :   else {
     111           5 :     Py_INCREF(Py_None);
     112           5 :     PyTuple_SetItem(excinfo, 2, Py_None);
     113             :   }
     114             : 
     115          27 :   self = PyWeakref_GetObject(weak_self);
     116             :   /* self only has a borrowed reference.  */
     117          27 :   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          27 :     PyObject_SetAttrString(self, EXCINFO, excinfo);
     132          27 :   Py_DECREF(excinfo);
     133          27 : }
     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          30 : static void pyProgressCb(void *hook, const char *what, int type, int current,
     468             :                          int total) {
     469          30 :   PyObject *func = NULL, *dataarg = NULL, *args = NULL, *retval = NULL;
     470          30 :   PyObject *pyhook = (PyObject *) hook;
     471          30 :   PyObject *self = NULL;
     472             : 
     473             :   assert (PyTuple_Check(pyhook));
     474             :   assert (PyTuple_Size(pyhook) == 2 || PyTuple_Size(pyhook) == 3);
     475          30 :   self = PyTuple_GetItem(pyhook, 0);
     476          30 :   func = PyTuple_GetItem(pyhook, 1);
     477          30 :   if (PyTuple_Size(pyhook) == 3) {
     478          14 :     dataarg = PyTuple_GetItem(pyhook, 2);
     479          14 :     args = PyTuple_New(5);
     480             :   } else {
     481          16 :     args = PyTuple_New(4);
     482             :   }
     483             : 
     484          30 :   PyTuple_SetItem(args, 0, PyUnicode_DecodeUTF8(what, strlen (what),
     485             :                                                 "strict"));
     486          30 :   if (PyErr_Occurred()) {
     487           0 :     _pyme_stash_callback_exception(self);
     488           0 :     Py_DECREF(args);
     489          30 :     return;
     490             :   }
     491          30 :   PyTuple_SetItem(args, 1, PyLong_FromLong((long) type));
     492          30 :   PyTuple_SetItem(args, 2, PyLong_FromLong((long) current));
     493          30 :   PyTuple_SetItem(args, 3, PyLong_FromLong((long) total));
     494          30 :   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          30 :   retval = PyObject_CallObject(func, args);
     500          30 :   if (PyErr_Occurred())
     501          16 :     _pyme_stash_callback_exception(self);
     502          30 :   Py_DECREF(args);
     503          30 :   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             : }

Generated by: LCOV version 1.11