python: Add an idiomatic interface.
[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 re
28 import os
29 import weakref
30 from . import pygpgme
31 from .errors import errorcheck, GPGMEError
32 from . import constants
33 from . import errors
34
35 class GpgmeWrapper(object):
36     """Base wrapper class
37
38     Not to be instantiated directly.
39
40     """
41
42     def __init__(self, wrapped):
43         self._callback_excinfo = None
44         self.wrapped = wrapped
45
46     def __repr__(self):
47         return '<{}/{!r}>'.format(super().__repr__(), self.wrapped)
48
49     def __str__(self):
50         acc = ['{}.{}'.format(__name__, self.__class__.__name__)]
51         flags = [f for f in self._boolean_properties if getattr(self, f)]
52         if flags:
53             acc.append('({})'.format(' '.join(flags)))
54
55         return '<{}>'.format(' '.join(acc))
56
57     def __hash__(self):
58         return hash(repr(self.wrapped))
59
60     def __eq__(self, other):
61         if other == None:
62             return False
63         else:
64             return repr(self.wrapped) == repr(other.wrapped)
65
66     @property
67     def _ctype(self):
68         """The name of the c type wrapped by this class
69
70         Must be set by child classes.
71
72         """
73         raise NotImplementedError()
74
75     @property
76     def _cprefix(self):
77         """The common prefix of c functions wrapped by this class
78
79         Must be set by child classes.
80
81         """
82         raise NotImplementedError()
83
84     def _errorcheck(self, name):
85         """Must be implemented by child classes.
86
87         This function must return a trueish value for all c functions
88         returning gpgme_error_t."""
89         raise NotImplementedError()
90
91     """The set of all boolean properties"""
92     _boolean_properties = set()
93
94     def __wrap_boolean_property(self, key, do_set=False, value=None):
95         get_func = getattr(pygpgme,
96                            "{}get_{}".format(self._cprefix, key))
97         set_func = getattr(pygpgme,
98                            "{}set_{}".format(self._cprefix, key))
99         def get(slf):
100             return bool(get_func(slf.wrapped))
101         def set_(slf, value):
102             set_func(slf.wrapped, bool(value))
103
104         p = property(get, set_, doc="{} flag".format(key))
105         setattr(self.__class__, key, p)
106
107         if do_set:
108             set_(self, bool(value))
109         else:
110             return get(self)
111
112     _munge_docstring = re.compile(r'gpgme_([^(]*)\(([^,]*), (.*\) -> .*)')
113     def __getattr__(self, key):
114         """On-the-fly generation of wrapper methods and properties"""
115         if key[0] == '_' or self._cprefix == None:
116             return None
117
118         if key in self._boolean_properties:
119             return self.__wrap_boolean_property(key)
120
121         name = self._cprefix + key
122         func = getattr(pygpgme, name)
123
124         if self._errorcheck(name):
125             def _funcwrap(slf, *args):
126                 result = func(slf.wrapped, *args)
127                 if slf._callback_excinfo:
128                     pygpgme.pygpgme_raise_callback_exception(slf)
129                 return errorcheck(result, "Invocation of " + name)
130         else:
131             def _funcwrap(slf, *args):
132                 result = func(slf.wrapped, *args)
133                 if slf._callback_excinfo:
134                     pygpgme.pygpgme_raise_callback_exception(slf)
135                 return result
136
137         doc = self._munge_docstring.sub(r'\2.\1(\3', getattr(func, "__doc__"))
138         _funcwrap.__doc__ = doc
139
140         # Monkey-patch the class.
141         setattr(self.__class__, key, _funcwrap)
142
143         # Bind the method to 'self'.
144         def wrapper(*args):
145             return _funcwrap(self, *args)
146         wrapper.__doc__ = doc
147
148         return wrapper
149
150     def __setattr__(self, key, value):
151         """On-the-fly generation of properties"""
152         if key in self._boolean_properties:
153             self.__wrap_boolean_property(key, True, value)
154         else:
155             super().__setattr__(key, value)
156
157 class Context(GpgmeWrapper):
158     """Context for cryptographic operations
159
160     All cryptographic operations in GPGME are performed within a
161     context, which contains the internal state of the operation as
162     well as configuration parameters.  By using several contexts you
163     can run several cryptographic operations in parallel, with
164     different configuration.
165
166     Access to a context must be synchronized.
167
168     """
169
170     def __init__(self, armor=False, textmode=False, offline=False,
171                  signers=[], pinentry_mode=constants.PINENTRY_MODE_DEFAULT,
172                  wrapped=None):
173         """Construct a context object
174
175         Keyword arguments:
176         armor           -- enable ASCII armoring (default False)
177         textmode        -- enable canonical text mode (default False)
178         offline         -- do not contact external key sources (default False)
179         signers         -- list of keys used for signing (default [])
180         pinentry_mode   -- pinentry mode (default PINENTRY_MODE_DEFAULT)
181
182         """
183         if wrapped:
184             self.own = False
185         else:
186             tmp = pygpgme.new_gpgme_ctx_t_p()
187             errorcheck(pygpgme.gpgme_new(tmp))
188             wrapped = pygpgme.gpgme_ctx_t_p_value(tmp)
189             pygpgme.delete_gpgme_ctx_t_p(tmp)
190             self.own = True
191         super().__init__(wrapped)
192         self.armor = armor
193         self.textmode = textmode
194         self.offline = offline
195         self.signers = signers
196         self.pinentry_mode = pinentry_mode
197
198     def encrypt(self, plaintext, recipients=[], sign=True, sink=None,
199                 passphrase=None, always_trust=False, add_encrypt_to=False,
200                 prepare=False, expect_sign=False, compress=True):
201         """Encrypt data
202
203         Encrypt the given plaintext for the given recipients.  If the
204         list of recipients is empty, the data is encrypted
205         symmetrically with a passphrase.
206
207         The passphrase can be given as parameter, using a callback
208         registered at the context, or out-of-band via pinentry.
209
210         Keyword arguments:
211         recipients      -- list of keys to encrypt to
212         sign            -- sign plaintext (default True)
213         sink            -- write result to sink instead of returning it
214         passphrase      -- for symmetric encryption
215         always_trust    -- always trust the keys (default False)
216         add_encrypt_to  -- encrypt to configured additional keys (default False)
217         prepare         -- (ui) prepare for encryption (default False)
218         expect_sign     -- (ui) prepare for signing (default False)
219         compress        -- compress plaintext (default True)
220
221         Returns:
222         ciphertext      -- the encrypted data (or None if sink is given)
223         result          -- additional information about the encryption
224         sign_result     -- additional information about the signature(s)
225
226         Raises:
227         InvalidRecipients -- if encryption using a particular key failed
228         InvalidSigners  -- if signing using a particular key failed
229         GPGMEError      -- as signaled by the underlying library
230
231         """
232         ciphertext = sink if sink else Data()
233         flags = 0
234         flags |= always_trust * constants.ENCRYPT_ALWAYS_TRUST
235         flags |= (not add_encrypt_to) * constants.ENCRYPT_NO_ENCRYPT_TO
236         flags |= prepare * constants.ENCRYPT_PREPARE
237         flags |= expect_sign * constants.ENCRYPT_EXPECT_SIGN
238         flags |= (not compress) * constants.ENCRYPT_NO_COMPRESS
239
240         if passphrase != None:
241             old_pinentry_mode = self.pinentry_mode
242             old_passphrase_cb = getattr(self, '_passphrase_cb', None)
243             self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
244             def passphrase_cb(hint, desc, prev_bad, hook=None):
245                 return passphrase
246             self.set_passphrase_cb(passphrase_cb)
247
248         try:
249             if sign:
250                 self.op_encrypt_sign(recipients, flags, plaintext, ciphertext)
251             else:
252                 self.op_encrypt(recipients, flags, plaintext, ciphertext)
253         except errors.GPGMEError as e:
254             if e.getcode() == errors.UNUSABLE_PUBKEY:
255                 result = self.op_encrypt_result()
256                 if result.invalid_recipients:
257                     raise errors.InvalidRecipients(result.invalid_recipients)
258             if e.getcode() == errors.UNUSABLE_SECKEY:
259                 sig_result = self.op_sign_result()
260                 if sig_result.invalid_signers:
261                     raise errors.InvalidSigners(sig_result.invalid_signers)
262             raise
263         finally:
264             if passphrase != None:
265                 self.pinentry_mode = old_pinentry_mode
266                 if old_passphrase_cb:
267                     self.set_passphrase_cb(*old_passphrase_cb[1:])
268
269         result = self.op_encrypt_result()
270         assert not result.invalid_recipients
271         sig_result = self.op_sign_result() if sign else None
272         assert not sig_result or not sig_result.invalid_signers
273
274         cipherbytes = None
275         if not sink:
276             ciphertext.seek(0, os.SEEK_SET)
277             cipherbytes = ciphertext.read()
278         return cipherbytes, result, sig_result
279
280     def decrypt(self, ciphertext, sink=None, passphrase=None, verify=True):
281         """Decrypt data
282
283         Decrypt the given ciphertext and verify any signatures.  If
284         VERIFY is an iterable of keys, the ciphertext must be signed
285         by all those keys, otherwise an error is raised.
286
287         If the ciphertext is symmetrically encrypted using a
288         passphrase, that passphrase can be given as parameter, using a
289         callback registered at the context, or out-of-band via
290         pinentry.
291
292         Keyword arguments:
293         sink            -- write result to sink instead of returning it
294         passphrase      -- for symmetric decryption
295         verify          -- check signatures (default True)
296
297         Returns:
298         plaintext       -- the decrypted data (or None if sink is given)
299         result          -- additional information about the decryption
300         verify_result   -- additional information about the signature(s)
301
302         Raises:
303         UnsupportedAlgorithm -- if an unsupported algorithm was used
304         BadSignatures   -- if a bad signature is encountered
305         MissingSignatures -- if expected signatures are missing or bad
306         GPGMEError      -- as signaled by the underlying library
307
308         """
309         plaintext = sink if sink else Data()
310
311         if passphrase != None:
312             old_pinentry_mode = self.pinentry_mode
313             old_passphrase_cb = getattr(self, '_passphrase_cb', None)
314             self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
315             def passphrase_cb(hint, desc, prev_bad, hook=None):
316                 return passphrase
317             self.set_passphrase_cb(passphrase_cb)
318
319         try:
320             if verify:
321                 self.op_decrypt_verify(ciphertext, plaintext)
322             else:
323                 self.op_decrypt(ciphertext, plaintext)
324         finally:
325             if passphrase != None:
326                 self.pinentry_mode = old_pinentry_mode
327                 if old_passphrase_cb:
328                     self.set_passphrase_cb(*old_passphrase_cb[1:])
329
330         result = self.op_decrypt_result()
331         verify_result = self.op_verify_result() if verify else None
332         if result.unsupported_algorithm:
333             raise errors.UnsupportedAlgorithm(result.unsupported_algorithm)
334
335         if verify:
336             if any(s.status != errors.NO_ERROR
337                    for s in verify_result.signatures):
338                 raise errors.BadSignatures(verify_result)
339
340         if verify and verify != True:
341             missing = list()
342             for key in verify:
343                 ok = False
344                 for subkey in key.subkeys:
345                     for sig in verify_result.signatures:
346                         if sig.summary & constants.SIGSUM_VALID == 0:
347                             continue
348                         if subkey.can_sign and subkey.fpr == sig.fpr:
349                             ok = True
350                             break
351                     if ok:
352                         break
353                 if not ok:
354                     missing.append(key)
355             if missing:
356                 raise errors.MissingSignatures(verify_result, missing)
357
358         plainbytes = None
359         if not sink:
360             plaintext.seek(0, os.SEEK_SET)
361             plainbytes = plaintext.read()
362         return plainbytes, result, verify_result
363
364     def sign(self, data, sink=None, mode=constants.SIG_MODE_NORMAL):
365         """Sign data
366
367         Sign the given data with either the configured default local
368         key, or the 'signers' keys of this context.
369
370         Keyword arguments:
371         mode            -- signature mode (default: normal, see below)
372         sink            -- write result to sink instead of returning it
373
374         Returns:
375         either
376           signed_data   -- encoded data and signature (normal mode)
377           signature     -- only the signature data (detached mode)
378           cleartext     -- data and signature as text (cleartext mode)
379             (or None if sink is given)
380         result          -- additional information about the signature(s)
381
382         Raises:
383         InvalidSigners  -- if signing using a particular key failed
384         GPGMEError      -- as signaled by the underlying library
385
386         """
387         signeddata = sink if sink else Data()
388
389         try:
390             self.op_sign(data, signeddata, mode)
391         except errors.GPGMEError as e:
392             if e.getcode() == errors.UNUSABLE_SECKEY:
393                 result = self.op_sign_result()
394                 if result.invalid_signers:
395                     raise errors.InvalidSigners(result.invalid_signers)
396             raise
397
398         result = self.op_sign_result()
399         assert not result.invalid_signers
400
401         signedbytes = None
402         if not sink:
403             signeddata.seek(0, os.SEEK_SET)
404             signedbytes = signeddata.read()
405         return signedbytes, result
406
407     def verify(self, signed_data, signature=None, sink=None, verify=[]):
408         """Verify signatures
409
410         Verify signatures over data.  If VERIFY is an iterable of
411         keys, the ciphertext must be signed by all those keys,
412         otherwise an error is raised.
413
414         Keyword arguments:
415         signature       -- detached signature data
416         sink            -- write result to sink instead of returning it
417
418         Returns:
419         data            -- the plain data
420             (or None if sink is given, or we verified a detached signature)
421         result          -- additional information about the signature(s)
422
423         Raises:
424         BadSignatures   -- if a bad signature is encountered
425         MissingSignatures -- if expected signatures are missing or bad
426         GPGMEError      -- as signaled by the underlying library
427
428         """
429         if signature:
430             # Detached signature, we don't return the plain text.
431             data = None
432         else:
433             data = sink if sink else Data()
434
435         if signature:
436             self.op_verify(signature, signed_data, None)
437         else:
438             self.op_verify(signed_data, None, data)
439
440         result = self.op_verify_result()
441         if any(s.status != errors.NO_ERROR for s in result.signatures):
442             raise errors.BadSignatures(result)
443
444         missing = list()
445         for key in verify:
446             ok = False
447             for subkey in key.subkeys:
448                 for sig in result.signatures:
449                     if sig.summary & constants.SIGSUM_VALID == 0:
450                         continue
451                     if subkey.can_sign and subkey.fpr == sig.fpr:
452                         ok = True
453                         break
454                 if ok:
455                     break
456             if not ok:
457                 missing.append(key)
458         if missing:
459             raise errors.MissingSignatures(result, missing)
460
461         plainbytes = None
462         if data and not sink:
463             data.seek(0, os.SEEK_SET)
464             plainbytes = data.read()
465         return plainbytes, result
466
467     @property
468     def signers(self):
469         """Keys used for signing"""
470         return [self.signers_enum(i) for i in range(self.signers_count())]
471     @signers.setter
472     def signers(self, signers):
473         old = self.signers
474         self.signers_clear()
475         try:
476             for key in signers:
477                 self.signers_add(key)
478         except:
479             self.signers = old
480             raise
481
482     @property
483     def pinentry_mode(self):
484         """Pinentry mode"""
485         return self.get_pinentry_mode()
486     @pinentry_mode.setter
487     def pinentry_mode(self, value):
488         self.set_pinentry_mode(value)
489
490     _ctype = 'gpgme_ctx_t'
491     _cprefix = 'gpgme_'
492
493     def _errorcheck(self, name):
494         """This function should list all functions returning gpgme_error_t"""
495         if (name.startswith('gpgme_op_') and \
496             not name.endswith('_result')) or \
497             name == 'gpgme_signers_add' or \
498             name == 'gpgme_set_locale' or \
499             name == 'gpgme_set_keylist_mode' or \
500             name == 'gpgme_set_protocol':
501             return 1
502         return 0
503
504     _boolean_properties = {'armor', 'textmode', 'offline'}
505
506     def __del__(self):
507         if not pygpgme:
508             # At interpreter shutdown, pygpgme is set to NONE.
509             return
510
511         self._free_passcb()
512         self._free_progresscb()
513         self._free_statuscb()
514         if self.own and self.wrapped and pygpgme.gpgme_release:
515             pygpgme.gpgme_release(self.wrapped)
516             self.wrapped = None
517
518     # Implement the context manager protocol.
519     def __enter__(self):
520         return self
521     def __exit__(self, type, value, tb):
522         self.__del__()
523
524     def op_keylist_all(self, *args, **kwargs):
525         self.op_keylist_start(*args, **kwargs)
526         key = self.op_keylist_next()
527         while key:
528             yield key
529             key = self.op_keylist_next()
530         self.op_keylist_end()
531
532     def op_keylist_next(self):
533         """Returns the next key in the list created
534         by a call to op_keylist_start().  The object returned
535         is of type Key."""
536         ptr = pygpgme.new_gpgme_key_t_p()
537         try:
538             errorcheck(pygpgme.gpgme_op_keylist_next(self.wrapped, ptr))
539             key = pygpgme.gpgme_key_t_p_value(ptr)
540         except errors.GPGMEError as excp:
541             key = None
542             if excp.getcode() != errors.EOF:
543                 raise excp
544         pygpgme.delete_gpgme_key_t_p(ptr)
545         if key:
546             key.__del__ = lambda self: pygpgme.gpgme_key_unref(self)
547             return key
548
549     def get_key(self, fpr, secret):
550         """Return the key corresponding to the fingerprint 'fpr'"""
551         ptr = pygpgme.new_gpgme_key_t_p()
552         errorcheck(pygpgme.gpgme_get_key(self.wrapped, fpr, ptr, secret))
553         key = pygpgme.gpgme_key_t_p_value(ptr)
554         pygpgme.delete_gpgme_key_t_p(ptr)
555         if key:
556             key.__del__ = lambda self: pygpgme.gpgme_key_unref(self)
557             return key
558
559     def op_trustlist_all(self, *args, **kwargs):
560         self.op_trustlist_start(*args, **kwargs)
561         trust = self.op_trustlist_next()
562         while trust:
563             yield trust
564             trust = self.op_trustlist_next()
565         self.op_trustlist_end()
566
567     def op_trustlist_next(self):
568         """Returns the next trust item in the list created
569         by a call to op_trustlist_start().  The object returned
570         is of type TrustItem."""
571         ptr = pygpgme.new_gpgme_trust_item_t_p()
572         try:
573             errorcheck(pygpgme.gpgme_op_trustlist_next(self.wrapped, ptr))
574             trust = pygpgme.gpgme_trust_item_t_p_value(ptr)
575         except errors.GPGMEError as excp:
576             trust = None
577             if excp.getcode() != errors.EOF:
578                 raise
579         pygpgme.delete_gpgme_trust_item_t_p(ptr)
580         return trust
581
582     def set_passphrase_cb(self, func, hook=None):
583         """Sets the passphrase callback to the function specified by func.
584
585         When the system needs a passphrase, it will call func with three args:
586         hint, a string describing the key it needs the passphrase for;
587         desc, a string describing the passphrase it needs;
588         prev_bad, a boolean equal True if this is a call made after
589         unsuccessful previous attempt.
590
591         If hook has a value other than None it will be passed into the func
592         as a forth argument.
593
594         Please see the GPGME manual for more information.
595         """
596         if func == None:
597             hookdata = None
598         else:
599             if hook == None:
600                 hookdata = (weakref.ref(self), func)
601             else:
602                 hookdata = (weakref.ref(self), func, hook)
603         pygpgme.pygpgme_set_passphrase_cb(self, hookdata)
604
605     def _free_passcb(self):
606         if pygpgme.pygpgme_set_passphrase_cb:
607             self.set_passphrase_cb(None)
608
609     def set_progress_cb(self, func, hook=None):
610         """Sets the progress meter callback to the function specified by FUNC.
611         If FUNC is None, the callback will be cleared.
612
613         This function will be called to provide an interactive update
614         of the system's progress.  The function will be called with
615         three arguments, type, total, and current.  If HOOK is not
616         None, it will be supplied as fourth argument.
617
618         Please see the GPGME manual for more information.
619
620         """
621         if func == None:
622             hookdata = None
623         else:
624             if hook == None:
625                 hookdata = (weakref.ref(self), func)
626             else:
627                 hookdata = (weakref.ref(self), func, hook)
628         pygpgme.pygpgme_set_progress_cb(self, hookdata)
629
630     def _free_progresscb(self):
631         if pygpgme.pygpgme_set_progress_cb:
632             self.set_progress_cb(None)
633
634     def set_status_cb(self, func, hook=None):
635         """Sets the status callback to the function specified by FUNC.  If
636         FUNC is None, the callback will be cleared.
637
638         The function will be called with two arguments, keyword and
639         args.  If HOOK is not None, it will be supplied as third
640         argument.
641
642         Please see the GPGME manual for more information.
643
644         """
645         if func == None:
646             hookdata = None
647         else:
648             if hook == None:
649                 hookdata = (weakref.ref(self), func)
650             else:
651                 hookdata = (weakref.ref(self), func, hook)
652         pygpgme.pygpgme_set_status_cb(self, hookdata)
653
654     def _free_statuscb(self):
655         if pygpgme.pygpgme_set_status_cb:
656             self.set_status_cb(None)
657
658     def get_engine_info(self):
659         """Returns this context specific engine info"""
660         return pygpgme.gpgme_ctx_get_engine_info(self.wrapped)
661
662     def set_engine_info(self, proto, file_name, home_dir=None):
663         """Changes the configuration of the crypto engine implementing the
664     protocol 'proto' for the context. 'file_name' is the file name of
665     the executable program implementing this protocol. 'home_dir' is the
666     directory name of the configuration directory (engine's default is
667     used if omitted)."""
668         errorcheck(pygpgme.gpgme_ctx_set_engine_info(self.wrapped, proto, file_name, home_dir))
669
670     def wait(self, hang):
671         """Wait for asynchronous call to finish. Wait forever if hang is True.
672         Raises an exception on errors.
673
674         Please read the GPGME manual for more information.
675
676         """
677         ptr = pygpgme.new_gpgme_error_t_p()
678         pygpgme.gpgme_wait(self.wrapped, ptr, hang)
679         status = pygpgme.gpgme_error_t_p_value(ptr)
680         pygpgme.delete_gpgme_error_t_p(ptr)
681         errorcheck(status)
682
683     def op_edit(self, key, func, fnc_value, out):
684         """Start key editing using supplied callback function"""
685         if key == None:
686             raise ValueError("op_edit: First argument cannot be None")
687         if fnc_value:
688             opaquedata = (weakref.ref(self), func, fnc_value)
689         else:
690             opaquedata = (weakref.ref(self), func)
691
692         result = pygpgme.gpgme_op_edit(self.wrapped, key, opaquedata, out)
693         if self._callback_excinfo:
694             pygpgme.pygpgme_raise_callback_exception(self)
695         errorcheck(result)
696
697 class Data(GpgmeWrapper):
698     """Data buffer
699
700     A lot of data has to be exchanged between the user and the crypto
701     engine, like plaintext messages, ciphertext, signatures and
702     information about the keys.  The technical details about
703     exchanging the data information are completely abstracted by
704     GPGME.  The user provides and receives the data via `gpgme_data_t'
705     objects, regardless of the communication protocol between GPGME
706     and the crypto engine in use.
707
708     This Data class is the implementation of the GpgmeData objects.
709
710     Please see the information about __init__ for instantiation.
711
712     """
713
714     _ctype = 'gpgme_data_t'
715     _cprefix = 'gpgme_data_'
716
717     def _errorcheck(self, name):
718         """This function should list all functions returning gpgme_error_t"""
719         return name not in {
720             'gpgme_data_release_and_get_mem',
721             'gpgme_data_get_encoding',
722             'gpgme_data_seek',
723             'gpgme_data_get_file_name',
724         }
725
726     def __init__(self, string=None, file=None, offset=None,
727                  length=None, cbs=None, copy=True):
728         """Initialize a new gpgme_data_t object.
729
730         If no args are specified, make it an empty object.
731
732         If string alone is specified, initialize it with the data
733         contained there.
734
735         If file, offset, and length are all specified, file must
736         be either a filename or a file-like object, and the object
737         will be initialized by reading the specified chunk from the file.
738
739         If cbs is specified, it MUST be a tuple of the form:
740
741         (read_cb, write_cb, seek_cb, release_cb[, hook])
742
743         where the first four items are functions implementing reading,
744         writing, seeking the data, and releasing any resources once
745         the data object is deallocated.  The functions must match the
746         following prototypes:
747
748             def read(amount, hook=None):
749                 return <a b"bytes" object>
750
751             def write(data, hook=None):
752                 return <the number of bytes written>
753
754             def seek(offset, whence, hook=None):
755                 return <the new file position>
756
757             def release(hook=None):
758                 <return value and exceptions are ignored>
759
760         The functions may be bound methods.  In that case, you can
761         simply use the 'self' reference instead of using a hook.
762
763         If file is specified without any other arguments, then
764         it must be a filename, and the object will be initialized from
765         that file.
766
767         """
768         super().__init__(None)
769         self.data_cbs = None
770
771         if cbs != None:
772             self.new_from_cbs(*cbs)
773         elif string != None:
774             self.new_from_mem(string, copy)
775         elif file != None and offset != None and length != None:
776             self.new_from_filepart(file, offset, length)
777         elif file != None:
778             if type(file) == type("x"):
779                 self.new_from_file(file, copy)
780             else:
781                 self.new_from_fd(file)
782         else:
783             self.new()
784
785     def __del__(self):
786         if not pygpgme:
787             # At interpreter shutdown, pygpgme is set to NONE.
788             return
789
790         if self.wrapped != None and pygpgme.gpgme_data_release:
791             pygpgme.gpgme_data_release(self.wrapped)
792             if self._callback_excinfo:
793                 pygpgme.pygpgme_raise_callback_exception(self)
794             self.wrapped = None
795         self._free_datacbs()
796
797     # Implement the context manager protocol.
798     def __enter__(self):
799         return self
800     def __exit__(self, type, value, tb):
801         self.__del__()
802
803     def _free_datacbs(self):
804         self._data_cbs = None
805
806     def new(self):
807         tmp = pygpgme.new_gpgme_data_t_p()
808         errorcheck(pygpgme.gpgme_data_new(tmp))
809         self.wrapped = pygpgme.gpgme_data_t_p_value(tmp)
810         pygpgme.delete_gpgme_data_t_p(tmp)
811
812     def new_from_mem(self, string, copy=True):
813         tmp = pygpgme.new_gpgme_data_t_p()
814         errorcheck(pygpgme.gpgme_data_new_from_mem(tmp,string,len(string),copy))
815         self.wrapped = pygpgme.gpgme_data_t_p_value(tmp)
816         pygpgme.delete_gpgme_data_t_p(tmp)
817
818     def new_from_file(self, filename, copy=True):
819         tmp = pygpgme.new_gpgme_data_t_p()
820         try:
821             errorcheck(pygpgme.gpgme_data_new_from_file(tmp, filename, copy))
822         except errors.GPGMEError as e:
823             if e.getcode() == errors.INV_VALUE and not copy:
824                 raise ValueError("delayed reads are not yet supported")
825             else:
826                 raise e
827         self.wrapped = pygpgme.gpgme_data_t_p_value(tmp)
828         pygpgme.delete_gpgme_data_t_p(tmp)
829
830     def new_from_cbs(self, read_cb, write_cb, seek_cb, release_cb, hook=None):
831         tmp = pygpgme.new_gpgme_data_t_p()
832         if hook != None:
833             hookdata = (weakref.ref(self),
834                         read_cb, write_cb, seek_cb, release_cb, hook)
835         else:
836             hookdata = (weakref.ref(self),
837                         read_cb, write_cb, seek_cb, release_cb)
838         pygpgme.pygpgme_data_new_from_cbs(self, hookdata, tmp)
839         self.wrapped = pygpgme.gpgme_data_t_p_value(tmp)
840         pygpgme.delete_gpgme_data_t_p(tmp)
841
842     def new_from_filepart(self, file, offset, length):
843         """This wraps the GPGME gpgme_data_new_from_filepart() function.
844         The argument "file" may be:
845
846         * a string specifying a file name, or
847         * a file-like object supporting the fileno() and the mode attribute.
848
849         """
850
851         tmp = pygpgme.new_gpgme_data_t_p()
852         filename = None
853         fp = None
854
855         if type(file) == type("x"):
856             filename = file
857         else:
858             fp = pygpgme.fdopen(file.fileno(), file.mode)
859             if fp == None:
860                 raise ValueError("Failed to open file from %s arg %s" % \
861                       (str(type(file)), str(file)))
862
863         errorcheck(pygpgme.gpgme_data_new_from_filepart(tmp, filename, fp,
864                                                       offset, length))
865         self.wrapped = pygpgme.gpgme_data_t_p_value(tmp)
866         pygpgme.delete_gpgme_data_t_p(tmp)
867
868     def new_from_fd(self, file):
869         """This wraps the GPGME gpgme_data_new_from_fd() function.  The
870         argument "file" must be a file-like object, supporting the
871         fileno() method.
872
873         """
874         tmp = pygpgme.new_gpgme_data_t_p()
875         errorcheck(pygpgme.gpgme_data_new_from_fd(tmp, file.fileno()))
876         self.wrapped = pygpgme.gpgme_data_t_p_value(tmp)
877         pygpgme.delete_gpgme_data_t_p(tmp)
878
879     def new_from_stream(self, file):
880         """This wrap around gpgme_data_new_from_stream is an alias for
881         new_from_fd() method since in python there's not difference
882         between file stream and file descriptor"""
883         self.new_from_fd(file)
884
885     def write(self, buffer):
886         """Write buffer given as string or bytes.
887
888         If a string is given, it is implicitly encoded using UTF-8."""
889         written = pygpgme.gpgme_data_write(self.wrapped, buffer)
890         if written < 0:
891             if self._callback_excinfo:
892                 pygpgme.pygpgme_raise_callback_exception(self)
893             else:
894                 raise GPGMEError.fromSyserror()
895         return written
896
897     def read(self, size = -1):
898         """Read at most size bytes, returned as bytes.
899
900         If the size argument is negative or omitted, read until EOF is reached.
901
902         Returns the data read, or the empty string if there was no data
903         to read before EOF was reached."""
904
905         if size == 0:
906             return ''
907
908         if size > 0:
909             try:
910                 result = pygpgme.gpgme_data_read(self.wrapped, size)
911             except:
912                 if self._callback_excinfo:
913                     pygpgme.pygpgme_raise_callback_exception(self)
914                 else:
915                     raise
916             return result
917         else:
918             chunks = []
919             while True:
920                 try:
921                     result = pygpgme.gpgme_data_read(self.wrapped, 4096)
922                 except:
923                     if self._callback_excinfo:
924                         pygpgme.pygpgme_raise_callback_exception(self)
925                     else:
926                         raise
927                 if len(result) == 0:
928                     break
929                 chunks.append(result)
930             return b''.join(chunks)
931
932 def pubkey_algo_name(algo):
933     return pygpgme.gpgme_pubkey_algo_name(algo)
934
935 def hash_algo_name(algo):
936     return pygpgme.gpgme_hash_algo_name(algo)
937
938 def get_protocol_name(proto):
939     return pygpgme.gpgme_get_protocol_name(proto)
940
941 def check_version(version=None):
942     return pygpgme.gpgme_check_version(version)
943
944 # check_version also makes sure that several subsystems are properly
945 # initialized, and it must be run at least once before invoking any
946 # other function.  We do it here so that the user does not have to do
947 # it unless she really wants to check for a certain version.
948 check_version()
949
950 def engine_check_version (proto):
951     try:
952         errorcheck(pygpgme.gpgme_engine_check_version(proto))
953         return True
954     except errors.GPGMEError:
955         return False
956
957 def get_engine_info():
958     ptr = pygpgme.new_gpgme_engine_info_t_p()
959     try:
960         errorcheck(pygpgme.gpgme_get_engine_info(ptr))
961         info = pygpgme.gpgme_engine_info_t_p_value(ptr)
962     except errors.GPGMEError:
963         info = None
964     pygpgme.delete_gpgme_engine_info_t_p(ptr)
965     return info
966
967 def set_engine_info(proto, file_name, home_dir=None):
968     """Changes the default configuration of the crypto engine implementing
969     the protocol 'proto'. 'file_name' is the file name of
970     the executable program implementing this protocol. 'home_dir' is the
971     directory name of the configuration directory (engine's default is
972     used if omitted)."""
973     errorcheck(pygpgme.gpgme_set_engine_info(proto, file_name, home_dir))
974
975 def set_locale(category, value):
976     """Sets the default locale used by contexts"""
977     errorcheck(pygpgme.gpgme_set_locale(None, category, value))
978
979 def wait(hang):
980     """Wait for asynchronous call on any Context  to finish.
981     Wait forever if hang is True.
982
983     For finished anynch calls it returns a tuple (status, context):
984         status  - status return by asnynchronous call.
985         context - context which caused this call to return.
986
987     Please read the GPGME manual of more information."""
988     ptr = pygpgme.new_gpgme_error_t_p()
989     context = pygpgme.gpgme_wait(None, ptr, hang)
990     status = pygpgme.gpgme_error_t_p_value(ptr)
991     pygpgme.delete_gpgme_error_t_p(ptr)
992     if context == None:
993         errorcheck(status)
994     else:
995         context = Context(context)
996     return (status, context)