python: Simplify wrapping glue.
[gpgme.git] / lang / python / pyme / core.py
1 # Copyright (C) 2016 g10 Code GmbH
2 # Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net>
3 # Copyright (C) 2002 John Goerzen <jgoerzen@complete.org>
4 #
5 #    This library is free software; you can redistribute it and/or
6 #    modify it under the terms of the GNU Lesser General Public
7 #    License as published by the Free Software Foundation; either
8 #    version 2.1 of the License, or (at your option) any later version.
9 #
10 #    This library is distributed in the hope that it will be useful,
11 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 #    Lesser General Public License for more details.
14 #
15 #    You should have received a copy of the GNU Lesser General Public
16 #    License along with this library; if not, write to the Free Software
17 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
18
19 """Core functionality
20
21 Core functionality of GPGME wrapped in a object-oriented fashion.
22 Provides the 'Context' class for performing cryptographic operations,
23 and the 'Data' class describing buffers of data.
24
25 """
26
27 import weakref
28 from . import pygpgme
29 from .errors import errorcheck, GPGMEError
30 from . import constants
31 from . import errors
32
33 class GpgmeWrapper(object):
34     """Base wrapper class
35
36     Not to be instantiated directly.
37
38     """
39
40     def __init__(self, wrapped):
41         self._callback_excinfo = None
42         self.wrapped = wrapped
43
44     def __repr__(self):
45         return '<{}/{!r}>'.format(super().__repr__(), self.wrapped)
46
47     def __str__(self):
48         acc = ['{}.{}'.format(__name__, self.__class__.__name__)]
49         flags = [f for f in self._boolean_properties if getattr(self, f)]
50         if flags:
51             acc.append('({})'.format(' '.join(flags)))
52
53         return '<{}>'.format(' '.join(acc))
54
55     def __hash__(self):
56         return hash(repr(self.wrapped))
57
58     def __eq__(self, other):
59         if other == None:
60             return False
61         else:
62             return repr(self.wrapped) == repr(other.wrapped)
63
64     @property
65     def _ctype(self):
66         """The name of the c type wrapped by this class
67
68         Must be set by child classes.
69
70         """
71         raise NotImplementedError()
72
73     @property
74     def _cprefix(self):
75         """The common prefix of c functions wrapped by this class
76
77         Must be set by child classes.
78
79         """
80         raise NotImplementedError()
81
82     def _errorcheck(self, name):
83         """Must be implemented by child classes.
84
85         This function must return a trueish value for all c functions
86         returning gpgme_error_t."""
87         raise NotImplementedError()
88
89     """The set of all boolean properties"""
90     _boolean_properties = set()
91
92     def __wrap_boolean_property(self, key, do_set=False, value=None):
93         get_func = getattr(pygpgme,
94                            "{}get_{}".format(self._cprefix, key))
95         set_func = getattr(pygpgme,
96                            "{}set_{}".format(self._cprefix, key))
97         def get(slf):
98             return bool(get_func(slf.wrapped))
99         def set_(slf, value):
100             set_func(slf.wrapped, bool(value))
101
102         p = property(get, set_, doc="{} flag".format(key))
103         setattr(self.__class__, key, p)
104
105         if do_set:
106             set_(self, bool(value))
107         else:
108             return get(self)
109
110     def __getattr__(self, key):
111         """On-the-fly generation of wrapper methods and properties"""
112         if key[0] == '_' or self._cprefix == None:
113             return None
114
115         if key in self._boolean_properties:
116             return self.__wrap_boolean_property(key)
117
118         name = self._cprefix + key
119         func = getattr(pygpgme, name)
120
121         if self._errorcheck(name):
122             def _funcwrap(slf, *args, **kwargs):
123                 result = func(slf.wrapped, *args, **kwargs)
124                 if slf._callback_excinfo:
125                     pygpgme.pygpgme_raise_callback_exception(slf)
126                 return errorcheck(result, "Invocation of " + name)
127         else:
128             def _funcwrap(slf, *args, **kwargs):
129                 result = func(slf.wrapped, *args, **kwargs)
130                 if slf._callback_excinfo:
131                     pygpgme.pygpgme_raise_callback_exception(slf)
132                 return result
133
134         _funcwrap.__doc__ = getattr(func, "__doc__")
135
136         # Monkey-patch the class.
137         setattr(self.__class__, key, _funcwrap)
138
139         # Bind the method to 'self'.
140         def wrapper(*args, **kwargs):
141             return _funcwrap(self, *args, **kwargs)
142         _funcwrap.__doc__ = getattr(func, "__doc__")
143
144         return wrapper
145
146     def __setattr__(self, key, value):
147         """On-the-fly generation of properties"""
148         if key in self._boolean_properties:
149             self.__wrap_boolean_property(key, True, value)
150         else:
151             super().__setattr__(key, value)
152
153 class Context(GpgmeWrapper):
154     """Context for cryptographic operations
155
156     All cryptographic operations in GPGME are performed within a
157     context, which contains the internal state of the operation as
158     well as configuration parameters.  By using several contexts you
159     can run several cryptographic operations in parallel, with
160     different configuration.
161
162     Access to a context must be synchronized.
163
164     """
165
166     @property
167     def signers(self):
168         """Keys used for signing"""
169         return [self.signers_enum(i) for i in range(self.signers_count())]
170     @signers.setter
171     def signers(self, signers):
172         old = self.signers
173         self.signers_clear()
174         try:
175             for key in signers:
176                 self.signers_add(key)
177         except:
178             self.signers = old
179             raise
180
181     @property
182     def pinentry_mode(self):
183         """Pinentry mode"""
184         return self.get_pinentry_mode()
185     @pinentry_mode.setter
186     def pinentry_mode(self, value):
187         self.set_pinentry_mode(value)
188
189     _ctype = 'gpgme_ctx_t'
190     _cprefix = 'gpgme_'
191
192     def _errorcheck(self, name):
193         """This function should list all functions returning gpgme_error_t"""
194         if (name.startswith('gpgme_op_') and \
195             not name.endswith('_result')) or \
196             name == 'gpgme_signers_add' or \
197             name == 'gpgme_set_locale' or \
198             name == 'gpgme_set_keylist_mode' or \
199             name == 'gpgme_set_protocol':
200             return 1
201         return 0
202
203     _boolean_properties = {'armor', 'textmode', 'offline'}
204     def __init__(self, armor=False, textmode=False, offline=False,
205                  signers=[], pinentry_mode=constants.PINENTRY_MODE_DEFAULT,
206                  wrapped=None):
207         """Construct a context object
208
209         Keyword arguments:
210         armor           -- enable ASCII armoring (default False)
211         textmode        -- enable canonical text mode (default False)
212         offline         -- do not contact external key sources (default False)
213         signers         -- list of keys used for signing (default [])
214         pinentry_mode   -- pinentry mode (default PINENTRY_MODE_DEFAULT)
215         """
216         if wrapped:
217             self.own = False
218         else:
219             tmp = pygpgme.new_gpgme_ctx_t_p()
220             errorcheck(pygpgme.gpgme_new(tmp))
221             wrapped = pygpgme.gpgme_ctx_t_p_value(tmp)
222             pygpgme.delete_gpgme_ctx_t_p(tmp)
223             self.own = True
224         super().__init__(wrapped)
225         self.armor = armor
226         self.textmode = textmode
227         self.offline = offline
228         self.signers = signers
229         self.pinentry_mode = pinentry_mode
230
231     def __del__(self):
232         if not pygpgme:
233             # At interpreter shutdown, pygpgme is set to NONE.
234             return
235
236         self._free_passcb()
237         self._free_progresscb()
238         self._free_statuscb()
239         if self.own and self.wrapped and pygpgme.gpgme_release:
240             pygpgme.gpgme_release(self.wrapped)
241             self.wrapped = None
242
243     # Implement the context manager protocol.
244     def __enter__(self):
245         return self
246     def __exit__(self, type, value, tb):
247         self.__del__()
248
249     def op_keylist_all(self, *args, **kwargs):
250         self.op_keylist_start(*args, **kwargs)
251         key = self.op_keylist_next()
252         while key:
253             yield key
254             key = self.op_keylist_next()
255
256     def op_keylist_next(self):
257         """Returns the next key in the list created
258         by a call to op_keylist_start().  The object returned
259         is of type Key."""
260         ptr = pygpgme.new_gpgme_key_t_p()
261         try:
262             errorcheck(pygpgme.gpgme_op_keylist_next(self.wrapped, ptr))
263             key = pygpgme.gpgme_key_t_p_value(ptr)
264         except errors.GPGMEError as excp:
265             key = None
266             if excp.getcode() != errors.EOF:
267                 raise excp
268         pygpgme.delete_gpgme_key_t_p(ptr)
269         if key:
270             key.__del__ = lambda self: pygpgme.gpgme_key_unref(self)
271             return key
272
273     def get_key(self, fpr, secret):
274         """Return the key corresponding to the fingerprint 'fpr'"""
275         ptr = pygpgme.new_gpgme_key_t_p()
276         errorcheck(pygpgme.gpgme_get_key(self.wrapped, fpr, ptr, secret))
277         key = pygpgme.gpgme_key_t_p_value(ptr)
278         pygpgme.delete_gpgme_key_t_p(ptr)
279         if key:
280             key.__del__ = lambda self: pygpgme.gpgme_key_unref(self)
281             return key
282
283     def op_trustlist_all(self, *args, **kwargs):
284         self.op_trustlist_start(*args, **kwargs)
285         trust = self.ctx.op_trustlist_next()
286         while trust:
287             yield trust
288             trust = self.ctx.op_trustlist_next()
289
290     def op_trustlist_next(self):
291         """Returns the next trust item in the list created
292         by a call to op_trustlist_start().  The object returned
293         is of type TrustItem."""
294         ptr = pygpgme.new_gpgme_trust_item_t_p()
295         try:
296             errorcheck(pygpgme.gpgme_op_trustlist_next(self.wrapped, ptr))
297             trust = pygpgme.gpgme_trust_item_t_p_value(ptr)
298         except errors.GPGMEError as excp:
299             trust = None
300             if excp.getcode() != errors.EOF:
301                 raise
302         pygpgme.delete_gpgme_trust_item_t_p(ptr)
303         return trust
304
305     def set_passphrase_cb(self, func, hook=None):
306         """Sets the passphrase callback to the function specified by func.
307
308         When the system needs a passphrase, it will call func with three args:
309         hint, a string describing the key it needs the passphrase for;
310         desc, a string describing the passphrase it needs;
311         prev_bad, a boolean equal True if this is a call made after
312         unsuccessful previous attempt.
313
314         If hook has a value other than None it will be passed into the func
315         as a forth argument.
316
317         Please see the GPGME manual for more information.
318         """
319         if func == None:
320             hookdata = None
321         else:
322             if hook == None:
323                 hookdata = (weakref.ref(self), func)
324             else:
325                 hookdata = (weakref.ref(self), func, hook)
326         pygpgme.pygpgme_set_passphrase_cb(self, hookdata)
327
328     def _free_passcb(self):
329         if pygpgme.pygpgme_set_passphrase_cb:
330             self.set_passphrase_cb(None)
331
332     def set_progress_cb(self, func, hook=None):
333         """Sets the progress meter callback to the function specified by FUNC.
334         If FUNC is None, the callback will be cleared.
335
336         This function will be called to provide an interactive update
337         of the system's progress.  The function will be called with
338         three arguments, type, total, and current.  If HOOK is not
339         None, it will be supplied as fourth argument.
340
341         Please see the GPGME manual for more information.
342
343         """
344         if func == None:
345             hookdata = None
346         else:
347             if hook == None:
348                 hookdata = (weakref.ref(self), func)
349             else:
350                 hookdata = (weakref.ref(self), func, hook)
351         pygpgme.pygpgme_set_progress_cb(self, hookdata)
352
353     def _free_progresscb(self):
354         if pygpgme.pygpgme_set_progress_cb:
355             self.set_progress_cb(None)
356
357     def set_status_cb(self, func, hook=None):
358         """Sets the status callback to the function specified by FUNC.  If
359         FUNC is None, the callback will be cleared.
360
361         The function will be called with two arguments, keyword and
362         args.  If HOOK is not None, it will be supplied as third
363         argument.
364
365         Please see the GPGME manual for more information.
366
367         """
368         if func == None:
369             hookdata = None
370         else:
371             if hook == None:
372                 hookdata = (weakref.ref(self), func)
373             else:
374                 hookdata = (weakref.ref(self), func, hook)
375         pygpgme.pygpgme_set_status_cb(self, hookdata)
376
377     def _free_statuscb(self):
378         if pygpgme.pygpgme_set_status_cb:
379             self.set_status_cb(None)
380
381     def get_engine_info(self):
382         """Returns this context specific engine info"""
383         return pygpgme.gpgme_ctx_get_engine_info(self.wrapped)
384
385     def set_engine_info(self, proto, file_name, home_dir=None):
386         """Changes the configuration of the crypto engine implementing the
387     protocol 'proto' for the context. 'file_name' is the file name of
388     the executable program implementing this protocol. 'home_dir' is the
389     directory name of the configuration directory (engine's default is
390     used if omitted)."""
391         errorcheck(pygpgme.gpgme_ctx_set_engine_info(self.wrapped, proto, file_name, home_dir))
392
393     def wait(self, hang):
394         """Wait for asynchronous call to finish. Wait forever if hang is True.
395         Raises an exception on errors.
396
397         Please read the GPGME manual for more information.
398
399         """
400         ptr = pygpgme.new_gpgme_error_t_p()
401         pygpgme.gpgme_wait(self.wrapped, ptr, hang)
402         status = pygpgme.gpgme_error_t_p_value(ptr)
403         pygpgme.delete_gpgme_error_t_p(ptr)
404         errorcheck(status)
405
406     def op_edit(self, key, func, fnc_value, out):
407         """Start key editing using supplied callback function"""
408         if key == None:
409             raise ValueError("op_edit: First argument cannot be None")
410         if fnc_value:
411             opaquedata = (weakref.ref(self), func, fnc_value)
412         else:
413             opaquedata = (weakref.ref(self), func)
414
415         result = pygpgme.gpgme_op_edit(self.wrapped, key, opaquedata, out)
416         if self._callback_excinfo:
417             pygpgme.pygpgme_raise_callback_exception(self)
418         errorcheck(result)
419
420 class Data(GpgmeWrapper):
421     """Data buffer
422
423     A lot of data has to be exchanged between the user and the crypto
424     engine, like plaintext messages, ciphertext, signatures and
425     information about the keys.  The technical details about
426     exchanging the data information are completely abstracted by
427     GPGME.  The user provides and receives the data via `gpgme_data_t'
428     objects, regardless of the communication protocol between GPGME
429     and the crypto engine in use.
430
431     This Data class is the implementation of the GpgmeData objects.
432
433     Please see the information about __init__ for instantiation.
434
435     """
436
437     _ctype = 'gpgme_data_t'
438     _cprefix = 'gpgme_data_'
439
440     def _errorcheck(self, name):
441         """This function should list all functions returning gpgme_error_t"""
442         return name not in {
443             'gpgme_data_release_and_get_mem',
444             'gpgme_data_get_encoding',
445             'gpgme_data_seek',
446             'gpgme_data_get_file_name',
447         }
448
449     def __init__(self, string=None, file=None, offset=None,
450                  length=None, cbs=None, copy=True):
451         """Initialize a new gpgme_data_t object.
452
453         If no args are specified, make it an empty object.
454
455         If string alone is specified, initialize it with the data
456         contained there.
457
458         If file, offset, and length are all specified, file must
459         be either a filename or a file-like object, and the object
460         will be initialized by reading the specified chunk from the file.
461
462         If cbs is specified, it MUST be a tuple of the form:
463
464         (read_cb, write_cb, seek_cb, release_cb[, hook])
465
466         where the first four items are functions implementing reading,
467         writing, seeking the data, and releasing any resources once
468         the data object is deallocated.  The functions must match the
469         following prototypes:
470
471             def read(amount, hook=None):
472                 return <a b"bytes" object>
473
474             def write(data, hook=None):
475                 return <the number of bytes written>
476
477             def seek(offset, whence, hook=None):
478                 return <the new file position>
479
480             def release(hook=None):
481                 <return value and exceptions are ignored>
482
483         The functions may be bound methods.  In that case, you can
484         simply use the 'self' reference instead of using a hook.
485
486         If file is specified without any other arguments, then
487         it must be a filename, and the object will be initialized from
488         that file.
489
490         """
491         super().__init__(None)
492         self.data_cbs = None
493
494         if cbs != None:
495             self.new_from_cbs(*cbs)
496         elif string != None:
497             self.new_from_mem(string, copy)
498         elif file != None and offset != None and length != None:
499             self.new_from_filepart(file, offset, length)
500         elif file != None:
501             if type(file) == type("x"):
502                 self.new_from_file(file, copy)
503             else:
504                 self.new_from_fd(file)
505         else:
506             self.new()
507
508     def __del__(self):
509         if not pygpgme:
510             # At interpreter shutdown, pygpgme is set to NONE.
511             return
512
513         if self.wrapped != None and pygpgme.gpgme_data_release:
514             pygpgme.gpgme_data_release(self.wrapped)
515             if self._callback_excinfo:
516                 pygpgme.pygpgme_raise_callback_exception(self)
517             self.wrapped = None
518         self._free_datacbs()
519
520     # Implement the context manager protocol.
521     def __enter__(self):
522         return self
523     def __exit__(self, type, value, tb):
524         self.__del__()
525
526     def _free_datacbs(self):
527         self._data_cbs = None
528
529     def new(self):
530         tmp = pygpgme.new_gpgme_data_t_p()
531         errorcheck(pygpgme.gpgme_data_new(tmp))
532         self.wrapped = pygpgme.gpgme_data_t_p_value(tmp)
533         pygpgme.delete_gpgme_data_t_p(tmp)
534
535     def new_from_mem(self, string, copy=True):
536         tmp = pygpgme.new_gpgme_data_t_p()
537         errorcheck(pygpgme.gpgme_data_new_from_mem(tmp,string,len(string),copy))
538         self.wrapped = pygpgme.gpgme_data_t_p_value(tmp)
539         pygpgme.delete_gpgme_data_t_p(tmp)
540
541     def new_from_file(self, filename, copy=True):
542         tmp = pygpgme.new_gpgme_data_t_p()
543         try:
544             errorcheck(pygpgme.gpgme_data_new_from_file(tmp, filename, copy))
545         except errors.GPGMEError as e:
546             if e.getcode() == errors.INV_VALUE and not copy:
547                 raise ValueError("delayed reads are not yet supported")
548             else:
549                 raise e
550         self.wrapped = pygpgme.gpgme_data_t_p_value(tmp)
551         pygpgme.delete_gpgme_data_t_p(tmp)
552
553     def new_from_cbs(self, read_cb, write_cb, seek_cb, release_cb, hook=None):
554         tmp = pygpgme.new_gpgme_data_t_p()
555         if hook != None:
556             hookdata = (weakref.ref(self),
557                         read_cb, write_cb, seek_cb, release_cb, hook)
558         else:
559             hookdata = (weakref.ref(self),
560                         read_cb, write_cb, seek_cb, release_cb)
561         pygpgme.pygpgme_data_new_from_cbs(self, hookdata, tmp)
562         self.wrapped = pygpgme.gpgme_data_t_p_value(tmp)
563         pygpgme.delete_gpgme_data_t_p(tmp)
564
565     def new_from_filepart(self, file, offset, length):
566         """This wraps the GPGME gpgme_data_new_from_filepart() function.
567         The argument "file" may be:
568
569         * a string specifying a file name, or
570         * a file-like object supporting the fileno() and the mode attribute.
571
572         """
573
574         tmp = pygpgme.new_gpgme_data_t_p()
575         filename = None
576         fp = None
577
578         if type(file) == type("x"):
579             filename = file
580         else:
581             fp = pygpgme.fdopen(file.fileno(), file.mode)
582             if fp == None:
583                 raise ValueError("Failed to open file from %s arg %s" % \
584                       (str(type(file)), str(file)))
585
586         errorcheck(pygpgme.gpgme_data_new_from_filepart(tmp, filename, fp,
587                                                       offset, length))
588         self.wrapped = pygpgme.gpgme_data_t_p_value(tmp)
589         pygpgme.delete_gpgme_data_t_p(tmp)
590
591     def new_from_fd(self, file):
592         """This wraps the GPGME gpgme_data_new_from_fd() function.  The
593         argument "file" must be a file-like object, supporting the
594         fileno() method.
595
596         """
597         tmp = pygpgme.new_gpgme_data_t_p()
598         errorcheck(pygpgme.gpgme_data_new_from_fd(tmp, file.fileno()))
599         self.wrapped = pygpgme.gpgme_data_t_p_value(tmp)
600         pygpgme.delete_gpgme_data_t_p(tmp)
601
602     def new_from_stream(self, file):
603         """This wrap around gpgme_data_new_from_stream is an alias for
604         new_from_fd() method since in python there's not difference
605         between file stream and file descriptor"""
606         self.new_from_fd(file)
607
608     def write(self, buffer):
609         """Write buffer given as string or bytes.
610
611         If a string is given, it is implicitly encoded using UTF-8."""
612         written = pygpgme.gpgme_data_write(self.wrapped, buffer)
613         if written < 0:
614             if self._callback_excinfo:
615                 pygpgme.pygpgme_raise_callback_exception(self)
616             else:
617                 raise GPGMEError.fromSyserror()
618         return written
619
620     def read(self, size = -1):
621         """Read at most size bytes, returned as bytes.
622
623         If the size argument is negative or omitted, read until EOF is reached.
624
625         Returns the data read, or the empty string if there was no data
626         to read before EOF was reached."""
627
628         if size == 0:
629             return ''
630
631         if size > 0:
632             try:
633                 result = pygpgme.gpgme_data_read(self.wrapped, size)
634             except:
635                 if self._callback_excinfo:
636                     pygpgme.pygpgme_raise_callback_exception(self)
637                 else:
638                     raise
639             return result
640         else:
641             chunks = []
642             while True:
643                 try:
644                     result = pygpgme.gpgme_data_read(self.wrapped, 4096)
645                 except:
646                     if self._callback_excinfo:
647                         pygpgme.pygpgme_raise_callback_exception(self)
648                     else:
649                         raise
650                 if len(result) == 0:
651                     break
652                 chunks.append(result)
653             return b''.join(chunks)
654
655 def pubkey_algo_name(algo):
656     return pygpgme.gpgme_pubkey_algo_name(algo)
657
658 def hash_algo_name(algo):
659     return pygpgme.gpgme_hash_algo_name(algo)
660
661 def get_protocol_name(proto):
662     return pygpgme.gpgme_get_protocol_name(proto)
663
664 def check_version(version=None):
665     return pygpgme.gpgme_check_version(version)
666
667 # check_version also makes sure that several subsystems are properly
668 # initialized, and it must be run at least once before invoking any
669 # other function.  We do it here so that the user does not have to do
670 # it unless she really wants to check for a certain version.
671 check_version()
672
673 def engine_check_version (proto):
674     try:
675         errorcheck(pygpgme.gpgme_engine_check_version(proto))
676         return True
677     except errors.GPGMEError:
678         return False
679
680 def get_engine_info():
681     ptr = pygpgme.new_gpgme_engine_info_t_p()
682     try:
683         errorcheck(pygpgme.gpgme_get_engine_info(ptr))
684         info = pygpgme.gpgme_engine_info_t_p_value(ptr)
685     except errors.GPGMEError:
686         info = None
687     pygpgme.delete_gpgme_engine_info_t_p(ptr)
688     return info
689
690 def set_engine_info(proto, file_name, home_dir=None):
691     """Changes the default configuration of the crypto engine implementing
692     the protocol 'proto'. 'file_name' is the file name of
693     the executable program implementing this protocol. 'home_dir' is the
694     directory name of the configuration directory (engine's default is
695     used if omitted)."""
696     errorcheck(pygpgme.gpgme_set_engine_info(proto, file_name, home_dir))
697
698 def set_locale(category, value):
699     """Sets the default locale used by contexts"""
700     errorcheck(pygpgme.gpgme_set_locale(None, category, value))
701
702 def wait(hang):
703     """Wait for asynchronous call on any Context  to finish.
704     Wait forever if hang is True.
705
706     For finished anynch calls it returns a tuple (status, context):
707         status  - status return by asnynchronous call.
708         context - context which caused this call to return.
709
710     Please read the GPGME manual of more information."""
711     ptr = pygpgme.new_gpgme_error_t_p()
712     context = pygpgme.gpgme_wait(None, ptr, hang)
713     status = pygpgme.gpgme_error_t_p_value(ptr)
714     pygpgme.delete_gpgme_error_t_p(ptr)
715     if context == None:
716         errorcheck(status)
717     else:
718         context = Context(context)
719     return (status, context)