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