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