python: Support manipulating the TOFU policy.
[gpgme.git] / lang / python / gpg / core.py
1 # Copyright (C) 2016-2017 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 warnings
33 import weakref
34 from . import gpgme
35 from .errors import errorcheck, GPGMEError
36 from . import constants
37 from . import errors
38 from . import util
39
40 class GpgmeWrapper(object):
41     """Base wrapper class
42
43     Not to be instantiated directly.
44
45     """
46
47     def __init__(self, wrapped):
48         self._callback_excinfo = None
49         self.wrapped = wrapped
50
51     def __repr__(self):
52         return '<{}/{!r}>'.format(super(GpgmeWrapper, self).__repr__(),
53                                   self.wrapped)
54
55     def __str__(self):
56         acc = ['{}.{}'.format(__name__, self.__class__.__name__)]
57         flags = [f for f in self._boolean_properties if getattr(self, f)]
58         if flags:
59             acc.append('({})'.format(' '.join(flags)))
60
61         return '<{}>'.format(' '.join(acc))
62
63     def __hash__(self):
64         return hash(repr(self.wrapped))
65
66     def __eq__(self, other):
67         if other == None:
68             return False
69         else:
70             return repr(self.wrapped) == repr(other.wrapped)
71
72     @property
73     def _ctype(self):
74         """The name of the c type wrapped by this class
75
76         Must be set by child classes.
77
78         """
79         raise NotImplementedError()
80
81     @property
82     def _cprefix(self):
83         """The common prefix of c functions wrapped by this class
84
85         Must be set by child classes.
86
87         """
88         raise NotImplementedError()
89
90     def _errorcheck(self, name):
91         """Must be implemented by child classes.
92
93         This function must return a trueish value for all c functions
94         returning gpgme_error_t."""
95         raise NotImplementedError()
96
97     """The set of all boolean properties"""
98     _boolean_properties = set()
99
100     def __wrap_boolean_property(self, key, do_set=False, value=None):
101         get_func = getattr(gpgme,
102                            "{}get_{}".format(self._cprefix, key))
103         set_func = getattr(gpgme,
104                            "{}set_{}".format(self._cprefix, key))
105         def get(slf):
106             return bool(get_func(slf.wrapped))
107         def set_(slf, value):
108             set_func(slf.wrapped, bool(value))
109
110         p = property(get, set_, doc="{} flag".format(key))
111         setattr(self.__class__, key, p)
112
113         if do_set:
114             set_(self, bool(value))
115         else:
116             return get(self)
117
118     _munge_docstring = re.compile(r'gpgme_([^(]*)\(([^,]*), (.*\) -> .*)')
119     def __getattr__(self, key):
120         """On-the-fly generation of wrapper methods and properties"""
121         if key[0] == '_' or self._cprefix == None:
122             return None
123
124         if key in self._boolean_properties:
125             return self.__wrap_boolean_property(key)
126
127         name = self._cprefix + key
128         func = getattr(gpgme, name)
129
130         if self._errorcheck(name):
131             def _funcwrap(slf, *args):
132                 result = func(slf.wrapped, *args)
133                 if slf._callback_excinfo:
134                     gpgme.gpg_raise_callback_exception(slf)
135                 return errorcheck(result, "Invocation of " + name)
136         else:
137             def _funcwrap(slf, *args):
138                 result = func(slf.wrapped, *args)
139                 if slf._callback_excinfo:
140                     gpgme.gpg_raise_callback_exception(slf)
141                 return result
142
143         doc = self._munge_docstring.sub(r'\2.\1(\3', getattr(func, "__doc__"))
144         _funcwrap.__doc__ = doc
145
146         # Monkey-patch the class.
147         setattr(self.__class__, key, _funcwrap)
148
149         # Bind the method to 'self'.
150         def wrapper(*args):
151             return _funcwrap(self, *args)
152         wrapper.__doc__ = doc
153
154         return wrapper
155
156     def __setattr__(self, key, value):
157         """On-the-fly generation of properties"""
158         if key in self._boolean_properties:
159             self.__wrap_boolean_property(key, True, value)
160         else:
161             super(GpgmeWrapper, self).__setattr__(key, value)
162
163 class Context(GpgmeWrapper):
164     """Context for cryptographic operations
165
166     All cryptographic operations in GPGME are performed within a
167     context, which contains the internal state of the operation as
168     well as configuration parameters.  By using several contexts you
169     can run several cryptographic operations in parallel, with
170     different configuration.
171
172     Access to a context must be synchronized.
173
174     """
175
176     def __init__(self, armor=False, textmode=False, offline=False,
177                  signers=[], pinentry_mode=constants.PINENTRY_MODE_DEFAULT,
178                  protocol=constants.PROTOCOL_OpenPGP,
179                  wrapped=None, home_dir=None):
180         """Construct a context object
181
182         Keyword arguments:
183         armor           -- enable ASCII armoring (default False)
184         textmode        -- enable canonical text mode (default False)
185         offline         -- do not contact external key sources (default False)
186         signers         -- list of keys used for signing (default [])
187         pinentry_mode   -- pinentry mode (default PINENTRY_MODE_DEFAULT)
188         protocol        -- protocol to use (default PROTOCOL_OpenPGP)
189         home_dir        -- state directory (default is the engine default)
190
191         """
192         if wrapped:
193             self.own = False
194         else:
195             tmp = gpgme.new_gpgme_ctx_t_p()
196             errorcheck(gpgme.gpgme_new(tmp))
197             wrapped = gpgme.gpgme_ctx_t_p_value(tmp)
198             gpgme.delete_gpgme_ctx_t_p(tmp)
199             self.own = True
200         super(Context, self).__init__(wrapped)
201         self.armor = armor
202         self.textmode = textmode
203         self.offline = offline
204         self.signers = signers
205         self.pinentry_mode = pinentry_mode
206         self.protocol = protocol
207         self.home_dir = home_dir
208
209     def __repr__(self):
210         return (
211             "Context(armor={0.armor}, "
212             "textmode={0.textmode}, offline={0.offline}, "
213             "signers={0.signers}, pinentry_mode={0.pinentry_mode}, "
214             "protocol={0.protocol}, home_dir={0.home_dir}"
215             ")").format(self)
216
217     def encrypt(self, plaintext, recipients=[], sign=True, sink=None,
218                 passphrase=None, always_trust=False, add_encrypt_to=False,
219                 prepare=False, expect_sign=False, compress=True):
220         """Encrypt data
221
222         Encrypt the given plaintext for the given recipients.  If the
223         list of recipients is empty, the data is encrypted
224         symmetrically with a passphrase.
225
226         The passphrase can be given as parameter, using a callback
227         registered at the context, or out-of-band via pinentry.
228
229         Keyword arguments:
230         recipients      -- list of keys to encrypt to
231         sign            -- sign plaintext (default True)
232         sink            -- write result to sink instead of returning it
233         passphrase      -- for symmetric encryption
234         always_trust    -- always trust the keys (default False)
235         add_encrypt_to  -- encrypt to configured additional keys (default False)
236         prepare         -- (ui) prepare for encryption (default False)
237         expect_sign     -- (ui) prepare for signing (default False)
238         compress        -- compress plaintext (default True)
239
240         Returns:
241         ciphertext      -- the encrypted data (or None if sink is given)
242         result          -- additional information about the encryption
243         sign_result     -- additional information about the signature(s)
244
245         Raises:
246         InvalidRecipients -- if encryption using a particular key failed
247         InvalidSigners  -- if signing using a particular key failed
248         GPGMEError      -- as signaled by the underlying library
249
250         """
251         ciphertext = sink if sink else Data()
252         flags = 0
253         flags |= always_trust * constants.ENCRYPT_ALWAYS_TRUST
254         flags |= (not add_encrypt_to) * constants.ENCRYPT_NO_ENCRYPT_TO
255         flags |= prepare * constants.ENCRYPT_PREPARE
256         flags |= expect_sign * constants.ENCRYPT_EXPECT_SIGN
257         flags |= (not compress) * constants.ENCRYPT_NO_COMPRESS
258
259         if passphrase != None:
260             old_pinentry_mode = self.pinentry_mode
261             old_passphrase_cb = getattr(self, '_passphrase_cb', None)
262             self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
263             def passphrase_cb(hint, desc, prev_bad, hook=None):
264                 return passphrase
265             self.set_passphrase_cb(passphrase_cb)
266
267         try:
268             if sign:
269                 self.op_encrypt_sign(recipients, flags, plaintext, ciphertext)
270             else:
271                 self.op_encrypt(recipients, flags, plaintext, ciphertext)
272         except errors.GPGMEError as e:
273             if e.getcode() == errors.UNUSABLE_PUBKEY:
274                 result = self.op_encrypt_result()
275                 if result.invalid_recipients:
276                     raise errors.InvalidRecipients(result.invalid_recipients)
277             if e.getcode() == errors.UNUSABLE_SECKEY:
278                 sig_result = self.op_sign_result()
279                 if sig_result.invalid_signers:
280                     raise errors.InvalidSigners(sig_result.invalid_signers)
281             raise
282         finally:
283             if passphrase != None:
284                 self.pinentry_mode = old_pinentry_mode
285                 if old_passphrase_cb:
286                     self.set_passphrase_cb(*old_passphrase_cb[1:])
287
288         result = self.op_encrypt_result()
289         assert not result.invalid_recipients
290         sig_result = self.op_sign_result() if sign else None
291         assert not sig_result or not sig_result.invalid_signers
292
293         cipherbytes = None
294         if not sink:
295             ciphertext.seek(0, os.SEEK_SET)
296             cipherbytes = ciphertext.read()
297         return cipherbytes, result, sig_result
298
299     def decrypt(self, ciphertext, sink=None, passphrase=None, verify=True):
300         """Decrypt data
301
302         Decrypt the given ciphertext and verify any signatures.  If
303         VERIFY is an iterable of keys, the ciphertext must be signed
304         by all those keys, otherwise an error is raised.
305
306         If the ciphertext is symmetrically encrypted using a
307         passphrase, that passphrase can be given as parameter, using a
308         callback registered at the context, or out-of-band via
309         pinentry.
310
311         Keyword arguments:
312         sink            -- write result to sink instead of returning it
313         passphrase      -- for symmetric decryption
314         verify          -- check signatures (default True)
315
316         Returns:
317         plaintext       -- the decrypted data (or None if sink is given)
318         result          -- additional information about the decryption
319         verify_result   -- additional information about the signature(s)
320
321         Raises:
322         UnsupportedAlgorithm -- if an unsupported algorithm was used
323         BadSignatures   -- if a bad signature is encountered
324         MissingSignatures -- if expected signatures are missing or bad
325         GPGMEError      -- as signaled by the underlying library
326
327         """
328         plaintext = sink if sink else Data()
329
330         if passphrase != None:
331             old_pinentry_mode = self.pinentry_mode
332             old_passphrase_cb = getattr(self, '_passphrase_cb', None)
333             self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
334             def passphrase_cb(hint, desc, prev_bad, hook=None):
335                 return passphrase
336             self.set_passphrase_cb(passphrase_cb)
337
338         try:
339             if verify:
340                 self.op_decrypt_verify(ciphertext, plaintext)
341             else:
342                 self.op_decrypt(ciphertext, plaintext)
343         finally:
344             if passphrase != None:
345                 self.pinentry_mode = old_pinentry_mode
346                 if old_passphrase_cb:
347                     self.set_passphrase_cb(*old_passphrase_cb[1:])
348
349         result = self.op_decrypt_result()
350         verify_result = self.op_verify_result() if verify else None
351         if result.unsupported_algorithm:
352             raise errors.UnsupportedAlgorithm(result.unsupported_algorithm)
353
354         if verify:
355             if any(s.status != errors.NO_ERROR
356                    for s in verify_result.signatures):
357                 raise errors.BadSignatures(verify_result)
358
359         if verify and verify != True:
360             missing = list()
361             for key in verify:
362                 ok = False
363                 for subkey in key.subkeys:
364                     for sig in verify_result.signatures:
365                         if sig.summary & constants.SIGSUM_VALID == 0:
366                             continue
367                         if subkey.can_sign and subkey.fpr == sig.fpr:
368                             ok = True
369                             break
370                     if ok:
371                         break
372                 if not ok:
373                     missing.append(key)
374             if missing:
375                 raise errors.MissingSignatures(verify_result, missing)
376
377         plainbytes = None
378         if not sink:
379             plaintext.seek(0, os.SEEK_SET)
380             plainbytes = plaintext.read()
381         return plainbytes, result, verify_result
382
383     def sign(self, data, sink=None, mode=constants.SIG_MODE_NORMAL):
384         """Sign data
385
386         Sign the given data with either the configured default local
387         key, or the 'signers' keys of this context.
388
389         Keyword arguments:
390         mode            -- signature mode (default: normal, see below)
391         sink            -- write result to sink instead of returning it
392
393         Returns:
394         either
395           signed_data   -- encoded data and signature (normal mode)
396           signature     -- only the signature data (detached mode)
397           cleartext     -- data and signature as text (cleartext mode)
398             (or None if sink is given)
399         result          -- additional information about the signature(s)
400
401         Raises:
402         InvalidSigners  -- if signing using a particular key failed
403         GPGMEError      -- as signaled by the underlying library
404
405         """
406         signeddata = sink if sink else Data()
407
408         try:
409             self.op_sign(data, signeddata, mode)
410         except errors.GPGMEError as e:
411             if e.getcode() == errors.UNUSABLE_SECKEY:
412                 result = self.op_sign_result()
413                 if result.invalid_signers:
414                     raise errors.InvalidSigners(result.invalid_signers)
415             raise
416
417         result = self.op_sign_result()
418         assert not result.invalid_signers
419
420         signedbytes = None
421         if not sink:
422             signeddata.seek(0, os.SEEK_SET)
423             signedbytes = signeddata.read()
424         return signedbytes, result
425
426     def verify(self, signed_data, signature=None, sink=None, verify=[]):
427         """Verify signatures
428
429         Verify signatures over data.  If VERIFY is an iterable of
430         keys, the ciphertext must be signed by all those keys,
431         otherwise an error is raised.
432
433         Keyword arguments:
434         signature       -- detached signature data
435         sink            -- write result to sink instead of returning it
436
437         Returns:
438         data            -- the plain data
439             (or None if sink is given, or we verified a detached signature)
440         result          -- additional information about the signature(s)
441
442         Raises:
443         BadSignatures   -- if a bad signature is encountered
444         MissingSignatures -- if expected signatures are missing or bad
445         GPGMEError      -- as signaled by the underlying library
446
447         """
448         if signature:
449             # Detached signature, we don't return the plain text.
450             data = None
451         else:
452             data = sink if sink else Data()
453
454         if signature:
455             self.op_verify(signature, signed_data, None)
456         else:
457             self.op_verify(signed_data, None, data)
458
459         result = self.op_verify_result()
460         if any(s.status != errors.NO_ERROR for s in result.signatures):
461             raise errors.BadSignatures(result)
462
463         missing = list()
464         for key in verify:
465             ok = False
466             for subkey in key.subkeys:
467                 for sig in result.signatures:
468                     if sig.summary & constants.SIGSUM_VALID == 0:
469                         continue
470                     if subkey.can_sign and subkey.fpr == sig.fpr:
471                         ok = True
472                         break
473                 if ok:
474                     break
475             if not ok:
476                 missing.append(key)
477         if missing:
478             raise errors.MissingSignatures(result, missing)
479
480         plainbytes = None
481         if data and not sink:
482             data.seek(0, os.SEEK_SET)
483             plainbytes = data.read()
484         return plainbytes, result
485
486     def keylist(self, pattern=None, secret=False,
487                 mode=constants.keylist.mode.LOCAL):
488         """List keys
489
490         Keyword arguments:
491         pattern -- return keys matching pattern (default: all keys)
492         secret  -- return only secret keys (default: False)
493         mode    -- keylist mode (default: list local keys)
494
495         Returns:
496                 -- an iterator returning key objects
497
498         Raises:
499         GPGMEError      -- as signaled by the underlying library
500         """
501         self.set_keylist_mode(mode)
502         return self.op_keylist_all(pattern, secret)
503
504     def create_key(self, userid, algorithm=None, expires_in=0, expires=True,
505                    sign=False, encrypt=False, certify=False, authenticate=False,
506                    passphrase=None, force=False):
507         """Create a primary key
508
509         Create a primary key for the user id USERID.
510
511         ALGORITHM may be used to specify the public key encryption
512         algorithm for the new key.  By default, a reasonable default
513         is chosen.  You may use "future-default" to select an
514         algorithm that will be the default in a future implementation
515         of the engine.  ALGORITHM may be a string like "rsa", or
516         "rsa2048" to explicitly request an algorithm and a key size.
517
518         EXPIRES_IN specifies the expiration time of the key in number
519         of seconds since the keys creation.  By default, a reasonable
520         expiration time is chosen.  If you want to create a key that
521         does not expire, use the keyword argument EXPIRES.
522
523         SIGN, ENCRYPT, CERTIFY, and AUTHENTICATE can be used to
524         request the capabilities of the new key.  If you don't request
525         any, a reasonable set of capabilities is selected, and in case
526         of OpenPGP, a subkey with a reasonable set of capabilities is
527         created.
528
529         If PASSPHRASE is None (the default), then the key will not be
530         protected with a passphrase.  If PASSPHRASE is a string, it
531         will be used to protect the key.  If PASSPHRASE is True, the
532         passphrase must be supplied using a passphrase callback or
533         out-of-band with a pinentry.
534
535         Keyword arguments:
536         algorithm    -- public key algorithm, see above (default: reasonable)
537         expires_in   -- expiration time in seconds (default: reasonable)
538         expires      -- whether or not the key should expire (default: True)
539         sign         -- request the signing capability (see above)
540         encrypt      -- request the encryption capability (see above)
541         certify      -- request the certification capability (see above)
542         authenticate -- request the authentication capability (see above)
543         passphrase   -- protect the key with a passphrase (default: no passphrase)
544         force        -- force key creation even if a key with the same userid exists
545                                                           (default: False)
546
547         Returns:
548                      -- an object describing the result of the key creation
549
550         Raises:
551         GPGMEError   -- as signaled by the underlying library
552
553         """
554         if util.is_a_string(passphrase):
555             old_pinentry_mode = self.pinentry_mode
556             old_passphrase_cb = getattr(self, '_passphrase_cb', None)
557             self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
558             def passphrase_cb(hint, desc, prev_bad, hook=None):
559                 return passphrase
560             self.set_passphrase_cb(passphrase_cb)
561
562         try:
563             self.op_createkey(userid, algorithm,
564                               0, # reserved
565                               expires_in,
566                               None, # extrakey
567                               ((constants.create.SIGN if sign else 0)
568                                | (constants.create.ENCR if encrypt else 0)
569                                | (constants.create.CERT if certify else 0)
570                                | (constants.create.AUTH if authenticate else 0)
571                                | (constants.create.NOPASSWD if passphrase == None else 0)
572                                | (0 if expires else constants.create.NOEXPIRE)
573                                | (constants.create.FORCE if force else 0)))
574         finally:
575             if util.is_a_string(passphrase):
576                 self.pinentry_mode = old_pinentry_mode
577                 if old_passphrase_cb:
578                     self.set_passphrase_cb(*old_passphrase_cb[1:])
579
580         return self.op_genkey_result()
581
582     def create_subkey(self, key, algorithm=None, expires_in=0, expires=True,
583                       sign=False, encrypt=False, authenticate=False, passphrase=None):
584         """Create a subkey
585
586         Create a subkey for the given KEY.  As subkeys are a concept
587         of OpenPGP, calling this is only valid for the OpenPGP
588         protocol.
589
590         ALGORITHM may be used to specify the public key encryption
591         algorithm for the new subkey.  By default, a reasonable
592         default is chosen.  You may use "future-default" to select an
593         algorithm that will be the default in a future implementation
594         of the engine.  ALGORITHM may be a string like "rsa", or
595         "rsa2048" to explicitly request an algorithm and a key size.
596
597         EXPIRES_IN specifies the expiration time of the subkey in
598         number of seconds since the subkeys creation.  By default, a
599         reasonable expiration time is chosen.  If you want to create a
600         subkey that does not expire, use the keyword argument EXPIRES.
601
602         SIGN, ENCRYPT, and AUTHENTICATE can be used to request the
603         capabilities of the new subkey.  If you don't request any, an
604         encryption subkey is generated.
605
606         If PASSPHRASE is None (the default), then the subkey will not
607         be protected with a passphrase.  If PASSPHRASE is a string, it
608         will be used to protect the subkey.  If PASSPHRASE is True,
609         the passphrase must be supplied using a passphrase callback or
610         out-of-band with a pinentry.
611
612         Keyword arguments:
613         algorithm    -- public key algorithm, see above (default: reasonable)
614         expires_in   -- expiration time in seconds (default: reasonable)
615         expires      -- whether or not the subkey should expire (default: True)
616         sign         -- request the signing capability (see above)
617         encrypt      -- request the encryption capability (see above)
618         authenticate -- request the authentication capability (see above)
619         passphrase   -- protect the subkey with a passphrase (default: no passphrase)
620
621         Returns:
622                      -- an object describing the result of the subkey creation
623
624         Raises:
625         GPGMEError   -- as signaled by the underlying library
626
627         """
628         if util.is_a_string(passphrase):
629             old_pinentry_mode = self.pinentry_mode
630             old_passphrase_cb = getattr(self, '_passphrase_cb', None)
631             self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
632             def passphrase_cb(hint, desc, prev_bad, hook=None):
633                 return passphrase
634             self.set_passphrase_cb(passphrase_cb)
635
636         try:
637             self.op_createsubkey(key, algorithm,
638                                  0, # reserved
639                                  expires_in,
640                                  ((constants.create.SIGN if sign else 0)
641                                   | (constants.create.ENCR if encrypt else 0)
642                                   | (constants.create.AUTH if authenticate else 0)
643                                   | (constants.create.NOPASSWD
644                                      if passphrase == None else 0)
645                                   | (0 if expires else constants.create.NOEXPIRE)))
646         finally:
647             if util.is_a_string(passphrase):
648                 self.pinentry_mode = old_pinentry_mode
649                 if old_passphrase_cb:
650                     self.set_passphrase_cb(*old_passphrase_cb[1:])
651
652         return self.op_genkey_result()
653
654     def key_add_uid(self, key, uid):
655         """Add a UID
656
657         Add the uid UID to the given KEY.  Calling this function is
658         only valid for the OpenPGP protocol.
659
660         Raises:
661         GPGMEError   -- as signaled by the underlying library
662
663         """
664         self.op_adduid(key, uid, 0)
665
666     def key_revoke_uid(self, key, uid):
667         """Revoke a UID
668
669         Revoke the uid UID from the given KEY.  Calling this function
670         is only valid for the OpenPGP protocol.
671
672         Raises:
673         GPGMEError   -- as signaled by the underlying library
674
675         """
676         self.op_revuid(key, uid, 0)
677
678     def key_sign(self, key, uids=None, expires_in=False, local=False):
679         """Sign a key
680
681         Sign a key with the current set of signing keys.  Calling this
682         function is only valid for the OpenPGP protocol.
683
684         If UIDS is None (the default), then all UIDs are signed.  If
685         it is a string, then only the matching UID is signed.  If it
686         is a list of strings, then all matching UIDs are signed.  Note
687         that a case-sensitive exact string comparison is done.
688
689         EXPIRES_IN specifies the expiration time of the signature in
690         seconds.  If EXPIRES_IN is False, the signature does not
691         expire.
692
693         Keyword arguments:
694         uids         -- user ids to sign, see above (default: sign all)
695         expires_in   -- validity period of the signature in seconds
696                                                (default: do not expire)
697         local        -- create a local, non-exportable signature
698                                                (default: False)
699
700         Raises:
701         GPGMEError   -- as signaled by the underlying library
702
703         """
704         flags = 0
705         if uids == None or util.is_a_string(uids):
706             pass#through unchanged
707         else:
708             flags |= constants.keysign.LFSEP
709             uids = "\n".join(uids)
710
711         if not expires_in:
712             flags |= constants.keysign.NOEXPIRE
713
714         if local:
715             flags |= constants.keysign.LOCAL
716
717         self.op_keysign(key, uids, expires_in, flags)
718
719     def key_tofu_policy(self, key, policy):
720         """Set a keys' TOFU policy
721
722         Set the TOFU policy associated with KEY to POLICY.  Calling
723         this function is only valid for the OpenPGP protocol.
724
725         Raises:
726         GPGMEError   -- as signaled by the underlying library
727
728         """
729         self.op_tofu_policy(key, policy)
730
731     def assuan_transact(self, command,
732                         data_cb=None, inquire_cb=None, status_cb=None):
733         """Issue a raw assuan command
734
735         This function can be used to issue a raw assuan command to the
736         engine.
737
738         If command is a string or bytes, it will be used as-is.  If it
739         is an iterable of strings, it will be properly escaped and
740         joined into an well-formed assuan command.
741
742         Keyword arguments:
743         data_cb         -- a callback receiving data lines
744         inquire_cb      -- a callback providing more information
745         status_cb       -- a callback receiving status lines
746
747         Returns:
748         result          -- the result of command as GPGMEError
749
750         Raises:
751         GPGMEError      -- as signaled by the underlying library
752
753         """
754
755         if util.is_a_string(command) or isinstance(command, bytes):
756             cmd = command
757         else:
758             cmd = " ".join(util.percent_escape(f) for f in command)
759
760         errptr = gpgme.new_gpgme_error_t_p()
761
762         err = gpgme.gpgme_op_assuan_transact_ext(
763             self.wrapped,
764             cmd,
765             (weakref.ref(self), data_cb) if data_cb else None,
766             (weakref.ref(self), inquire_cb) if inquire_cb else None,
767             (weakref.ref(self), status_cb) if status_cb else None,
768             errptr)
769
770         if self._callback_excinfo:
771             gpgme.gpg_raise_callback_exception(self)
772
773         errorcheck(err)
774
775         status = gpgme.gpgme_error_t_p_value(errptr)
776         gpgme.delete_gpgme_error_t_p(errptr)
777
778         return GPGMEError(status) if status != 0 else None
779
780     def interact(self, key, func, sink=None, flags=0, fnc_value=None):
781         """Interact with the engine
782
783         This method can be used to edit keys and cards interactively.
784         KEY is the key to edit, FUNC is called repeatedly with two
785         unicode arguments, 'keyword' and 'args'.  See the GPGME manual
786         for details.
787
788         Keyword arguments:
789         sink            -- if given, additional output is written here
790         flags           -- use constants.INTERACT_CARD to edit a card
791
792         Raises:
793         GPGMEError      -- as signaled by the underlying library
794
795         """
796         if key == None:
797             raise ValueError("First argument cannot be None")
798
799         if sink == None:
800             sink = Data()
801
802         if fnc_value:
803             opaquedata = (weakref.ref(self), func, fnc_value)
804         else:
805             opaquedata = (weakref.ref(self), func)
806
807         result = gpgme.gpgme_op_interact(self.wrapped, key, flags,
808                                          opaquedata, sink)
809         if self._callback_excinfo:
810             gpgme.gpg_raise_callback_exception(self)
811         errorcheck(result)
812
813     @property
814     def signers(self):
815         """Keys used for signing"""
816         return [self.signers_enum(i) for i in range(self.signers_count())]
817     @signers.setter
818     def signers(self, signers):
819         old = self.signers
820         self.signers_clear()
821         try:
822             for key in signers:
823                 self.signers_add(key)
824         except:
825             self.signers = old
826             raise
827
828     @property
829     def pinentry_mode(self):
830         """Pinentry mode"""
831         return self.get_pinentry_mode()
832     @pinentry_mode.setter
833     def pinentry_mode(self, value):
834         self.set_pinentry_mode(value)
835
836     @property
837     def protocol(self):
838         """Protocol to use"""
839         return self.get_protocol()
840     @protocol.setter
841     def protocol(self, value):
842         errorcheck(gpgme.gpgme_engine_check_version(value))
843         self.set_protocol(value)
844
845     @property
846     def home_dir(self):
847         """Engine's home directory"""
848         return self.engine_info.home_dir
849     @home_dir.setter
850     def home_dir(self, value):
851         self.set_engine_info(self.protocol, home_dir=value)
852
853     _ctype = 'gpgme_ctx_t'
854     _cprefix = 'gpgme_'
855
856     def _errorcheck(self, name):
857         """This function should list all functions returning gpgme_error_t"""
858         # The list of functions is created using:
859         #
860         # $ grep '^gpgme_error_t ' obj/lang/python/python3.5-gpg/gpgme.h \
861         #   | grep -v _op_ | awk "/\(gpgme_ctx/ { printf (\"'%s',\\n\", \$2) } "
862         return ((name.startswith('gpgme_op_')
863                  and not name.endswith('_result'))
864                 or name in {
865                     'gpgme_new',
866                     'gpgme_set_ctx_flag',
867                     'gpgme_set_protocol',
868                     'gpgme_set_sub_protocol',
869                     'gpgme_set_keylist_mode',
870                     'gpgme_set_pinentry_mode',
871                     'gpgme_set_locale',
872                     'gpgme_ctx_set_engine_info',
873                     'gpgme_signers_add',
874                     'gpgme_sig_notation_add',
875                     'gpgme_set_sender',
876                     'gpgme_cancel',
877                     'gpgme_cancel_async',
878                     'gpgme_get_key',
879                 })
880
881     _boolean_properties = {'armor', 'textmode', 'offline'}
882
883     def __del__(self):
884         if not gpgme:
885             # At interpreter shutdown, gpgme is set to NONE.
886             return
887
888         self._free_passcb()
889         self._free_progresscb()
890         self._free_statuscb()
891         if self.own and self.wrapped and gpgme.gpgme_release:
892             gpgme.gpgme_release(self.wrapped)
893             self.wrapped = None
894
895     # Implement the context manager protocol.
896     def __enter__(self):
897         return self
898     def __exit__(self, type, value, tb):
899         self.__del__()
900
901     def op_keylist_all(self, *args, **kwargs):
902         self.op_keylist_start(*args, **kwargs)
903         key = self.op_keylist_next()
904         while key:
905             yield key
906             key = self.op_keylist_next()
907         self.op_keylist_end()
908
909     def op_keylist_next(self):
910         """Returns the next key in the list created
911         by a call to op_keylist_start().  The object returned
912         is of type Key."""
913         ptr = gpgme.new_gpgme_key_t_p()
914         try:
915             errorcheck(gpgme.gpgme_op_keylist_next(self.wrapped, ptr))
916             key = gpgme.gpgme_key_t_p_value(ptr)
917         except errors.GPGMEError as excp:
918             key = None
919             if excp.getcode() != errors.EOF:
920                 raise excp
921         gpgme.delete_gpgme_key_t_p(ptr)
922         if key:
923             key.__del__ = lambda self: gpgme.gpgme_key_unref(self)
924             return key
925
926     def get_key(self, fpr, secret=False):
927         """Get a key given a fingerprint
928
929         Keyword arguments:
930         secret          -- to request a secret key
931
932         Returns:
933                         -- the matching key
934
935         Raises:
936         KeyError        -- if the key was not found
937         GPGMEError      -- as signaled by the underlying library
938
939         """
940         ptr = gpgme.new_gpgme_key_t_p()
941
942         try:
943             errorcheck(gpgme.gpgme_get_key(self.wrapped, fpr, ptr, secret))
944         except errors.GPGMEError as e:
945             if e.getcode() == errors.EOF:
946                 raise errors.KeyNotFound(fpr)
947             raise e
948
949         key = gpgme.gpgme_key_t_p_value(ptr)
950         gpgme.delete_gpgme_key_t_p(ptr)
951         assert key
952         key.__del__ = lambda self: gpgme.gpgme_key_unref(self)
953         return key
954
955     def op_trustlist_all(self, *args, **kwargs):
956         self.op_trustlist_start(*args, **kwargs)
957         trust = self.op_trustlist_next()
958         while trust:
959             yield trust
960             trust = self.op_trustlist_next()
961         self.op_trustlist_end()
962
963     def op_trustlist_next(self):
964         """Returns the next trust item in the list created
965         by a call to op_trustlist_start().  The object returned
966         is of type TrustItem."""
967         ptr = gpgme.new_gpgme_trust_item_t_p()
968         try:
969             errorcheck(gpgme.gpgme_op_trustlist_next(self.wrapped, ptr))
970             trust = gpgme.gpgme_trust_item_t_p_value(ptr)
971         except errors.GPGMEError as excp:
972             trust = None
973             if excp.getcode() != errors.EOF:
974                 raise
975         gpgme.delete_gpgme_trust_item_t_p(ptr)
976         return trust
977
978     def set_passphrase_cb(self, func, hook=None):
979         """Sets the passphrase callback to the function specified by func.
980
981         When the system needs a passphrase, it will call func with three args:
982         hint, a string describing the key it needs the passphrase for;
983         desc, a string describing the passphrase it needs;
984         prev_bad, a boolean equal True if this is a call made after
985         unsuccessful previous attempt.
986
987         If hook has a value other than None it will be passed into the func
988         as a forth argument.
989
990         Please see the GPGME manual for more information.
991         """
992         if func == None:
993             hookdata = None
994         else:
995             if hook == None:
996                 hookdata = (weakref.ref(self), func)
997             else:
998                 hookdata = (weakref.ref(self), func, hook)
999         gpgme.gpg_set_passphrase_cb(self, hookdata)
1000
1001     def _free_passcb(self):
1002         if gpgme.gpg_set_passphrase_cb:
1003             self.set_passphrase_cb(None)
1004
1005     def set_progress_cb(self, func, hook=None):
1006         """Sets the progress meter callback to the function specified by FUNC.
1007         If FUNC is None, the callback will be cleared.
1008
1009         This function will be called to provide an interactive update
1010         of the system's progress.  The function will be called with
1011         three arguments, type, total, and current.  If HOOK is not
1012         None, it will be supplied as fourth argument.
1013
1014         Please see the GPGME manual for more information.
1015
1016         """
1017         if func == None:
1018             hookdata = None
1019         else:
1020             if hook == None:
1021                 hookdata = (weakref.ref(self), func)
1022             else:
1023                 hookdata = (weakref.ref(self), func, hook)
1024         gpgme.gpg_set_progress_cb(self, hookdata)
1025
1026     def _free_progresscb(self):
1027         if gpgme.gpg_set_progress_cb:
1028             self.set_progress_cb(None)
1029
1030     def set_status_cb(self, func, hook=None):
1031         """Sets the status callback to the function specified by FUNC.  If
1032         FUNC is None, the callback will be cleared.
1033
1034         The function will be called with two arguments, keyword and
1035         args.  If HOOK is not None, it will be supplied as third
1036         argument.
1037
1038         Please see the GPGME manual for more information.
1039
1040         """
1041         if func == None:
1042             hookdata = None
1043         else:
1044             if hook == None:
1045                 hookdata = (weakref.ref(self), func)
1046             else:
1047                 hookdata = (weakref.ref(self), func, hook)
1048         gpgme.gpg_set_status_cb(self, hookdata)
1049
1050     def _free_statuscb(self):
1051         if gpgme.gpg_set_status_cb:
1052             self.set_status_cb(None)
1053
1054     @property
1055     def engine_info(self):
1056         """Configuration of the engine currently in use"""
1057         p = self.protocol
1058         infos = [i for i in self.get_engine_info() if i.protocol == p]
1059         assert len(infos) == 1
1060         return infos[0]
1061
1062     def get_engine_info(self):
1063         """Get engine configuration
1064
1065         Returns information about all configured and installed
1066         engines.
1067
1068         Returns:
1069         infos           -- a list of engine infos
1070
1071         """
1072         return gpgme.gpgme_ctx_get_engine_info(self.wrapped)
1073
1074     def set_engine_info(self, proto, file_name=None, home_dir=None):
1075         """Change engine configuration
1076
1077         Changes the configuration of the crypto engine implementing
1078         the protocol 'proto' for the context.
1079
1080         Keyword arguments:
1081         file_name       -- engine program file name (unchanged if None)
1082         home_dir        -- configuration directory (unchanged if None)
1083
1084         """
1085         self.ctx_set_engine_info(proto, file_name, home_dir)
1086
1087     def wait(self, hang):
1088         """Wait for asynchronous call to finish. Wait forever if hang is True.
1089         Raises an exception on errors.
1090
1091         Please read the GPGME manual for more information.
1092
1093         """
1094         ptr = gpgme.new_gpgme_error_t_p()
1095         gpgme.gpgme_wait(self.wrapped, ptr, hang)
1096         status = gpgme.gpgme_error_t_p_value(ptr)
1097         gpgme.delete_gpgme_error_t_p(ptr)
1098         errorcheck(status)
1099
1100     def op_edit(self, key, func, fnc_value, out):
1101         """Start key editing using supplied callback function
1102
1103         Note: This interface is deprecated and will be removed with
1104         GPGME 1.8.  Please use .interact instead.  Furthermore, we
1105         implement this using gpgme_op_interact, so callbacks will get
1106         called with string keywords instead of numeric status
1107         messages.  Code that is using constants.STATUS_X or
1108         constants.status.X will continue to work, whereas code using
1109         magic numbers will break as a result.
1110
1111         """
1112         warnings.warn("Call to deprecated method op_edit.",
1113                       category=DeprecationWarning)
1114         return self.interact(key, func, sink=out, fnc_value=fnc_value)
1115
1116
1117 class Data(GpgmeWrapper):
1118     """Data buffer
1119
1120     A lot of data has to be exchanged between the user and the crypto
1121     engine, like plaintext messages, ciphertext, signatures and
1122     information about the keys.  The technical details about
1123     exchanging the data information are completely abstracted by
1124     GPGME.  The user provides and receives the data via `gpgme_data_t'
1125     objects, regardless of the communication protocol between GPGME
1126     and the crypto engine in use.
1127
1128     This Data class is the implementation of the GpgmeData objects.
1129
1130     Please see the information about __init__ for instantiation.
1131
1132     """
1133
1134     _ctype = 'gpgme_data_t'
1135     _cprefix = 'gpgme_data_'
1136
1137     def _errorcheck(self, name):
1138         """This function should list all functions returning gpgme_error_t"""
1139         # This list is compiled using
1140         #
1141         # $ grep -v '^gpgme_error_t ' obj/lang/python/python3.5-gpg/gpgme.h \
1142         #   | awk "/\(gpgme_data_t/ { printf (\"'%s',\\n\", \$2) } " | sed "s/'\\*/'/"
1143         return name not in {
1144             'gpgme_data_read',
1145             'gpgme_data_write',
1146             'gpgme_data_seek',
1147             'gpgme_data_release',
1148             'gpgme_data_release_and_get_mem',
1149             'gpgme_data_get_encoding',
1150             'gpgme_data_get_file_name',
1151             'gpgme_data_identify',
1152         }
1153
1154     def __init__(self, string=None, file=None, offset=None,
1155                  length=None, cbs=None, copy=True):
1156         """Initialize a new gpgme_data_t object.
1157
1158         If no args are specified, make it an empty object.
1159
1160         If string alone is specified, initialize it with the data
1161         contained there.
1162
1163         If file, offset, and length are all specified, file must
1164         be either a filename or a file-like object, and the object
1165         will be initialized by reading the specified chunk from the file.
1166
1167         If cbs is specified, it MUST be a tuple of the form:
1168
1169         (read_cb, write_cb, seek_cb, release_cb[, hook])
1170
1171         where the first four items are functions implementing reading,
1172         writing, seeking the data, and releasing any resources once
1173         the data object is deallocated.  The functions must match the
1174         following prototypes:
1175
1176             def read(amount, hook=None):
1177                 return <a b"bytes" object>
1178
1179             def write(data, hook=None):
1180                 return <the number of bytes written>
1181
1182             def seek(offset, whence, hook=None):
1183                 return <the new file position>
1184
1185             def release(hook=None):
1186                 <return value and exceptions are ignored>
1187
1188         The functions may be bound methods.  In that case, you can
1189         simply use the 'self' reference instead of using a hook.
1190
1191         If file is specified without any other arguments, then
1192         it must be a filename, and the object will be initialized from
1193         that file.
1194
1195         """
1196         super(Data, self).__init__(None)
1197         self.data_cbs = None
1198
1199         if cbs != None:
1200             self.new_from_cbs(*cbs)
1201         elif string != None:
1202             self.new_from_mem(string, copy)
1203         elif file != None and offset != None and length != None:
1204             self.new_from_filepart(file, offset, length)
1205         elif file != None:
1206             if util.is_a_string(file):
1207                 self.new_from_file(file, copy)
1208             else:
1209                 self.new_from_fd(file)
1210         else:
1211             self.new()
1212
1213     def __del__(self):
1214         if not gpgme:
1215             # At interpreter shutdown, gpgme is set to NONE.
1216             return
1217
1218         if self.wrapped != None and gpgme.gpgme_data_release:
1219             gpgme.gpgme_data_release(self.wrapped)
1220             if self._callback_excinfo:
1221                 gpgme.gpg_raise_callback_exception(self)
1222             self.wrapped = None
1223         self._free_datacbs()
1224
1225     # Implement the context manager protocol.
1226     def __enter__(self):
1227         return self
1228     def __exit__(self, type, value, tb):
1229         self.__del__()
1230
1231     def _free_datacbs(self):
1232         self._data_cbs = None
1233
1234     def new(self):
1235         tmp = gpgme.new_gpgme_data_t_p()
1236         errorcheck(gpgme.gpgme_data_new(tmp))
1237         self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
1238         gpgme.delete_gpgme_data_t_p(tmp)
1239
1240     def new_from_mem(self, string, copy=True):
1241         tmp = gpgme.new_gpgme_data_t_p()
1242         errorcheck(gpgme.gpgme_data_new_from_mem(tmp,string,len(string),copy))
1243         self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
1244         gpgme.delete_gpgme_data_t_p(tmp)
1245
1246     def new_from_file(self, filename, copy=True):
1247         tmp = gpgme.new_gpgme_data_t_p()
1248         try:
1249             errorcheck(gpgme.gpgme_data_new_from_file(tmp, filename, copy))
1250         except errors.GPGMEError as e:
1251             if e.getcode() == errors.INV_VALUE and not copy:
1252                 raise ValueError("delayed reads are not yet supported")
1253             else:
1254                 raise e
1255         self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
1256         gpgme.delete_gpgme_data_t_p(tmp)
1257
1258     def new_from_cbs(self, read_cb, write_cb, seek_cb, release_cb, hook=None):
1259         tmp = gpgme.new_gpgme_data_t_p()
1260         if hook != None:
1261             hookdata = (weakref.ref(self),
1262                         read_cb, write_cb, seek_cb, release_cb, hook)
1263         else:
1264             hookdata = (weakref.ref(self),
1265                         read_cb, write_cb, seek_cb, release_cb)
1266         gpgme.gpg_data_new_from_cbs(self, hookdata, tmp)
1267         self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
1268         gpgme.delete_gpgme_data_t_p(tmp)
1269
1270     def new_from_filepart(self, file, offset, length):
1271         """This wraps the GPGME gpgme_data_new_from_filepart() function.
1272         The argument "file" may be:
1273
1274         * a string specifying a file name, or
1275         * a file-like object supporting the fileno() and the mode attribute.
1276
1277         """
1278
1279         tmp = gpgme.new_gpgme_data_t_p()
1280         filename = None
1281         fp = None
1282
1283         if util.is_a_string(file):
1284             filename = file
1285         else:
1286             fp = gpgme.fdopen(file.fileno(), file.mode)
1287             if fp == None:
1288                 raise ValueError("Failed to open file from %s arg %s" % \
1289                       (str(type(file)), str(file)))
1290
1291         errorcheck(gpgme.gpgme_data_new_from_filepart(tmp, filename, fp,
1292                                                       offset, length))
1293         self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
1294         gpgme.delete_gpgme_data_t_p(tmp)
1295
1296     def new_from_fd(self, file):
1297         """This wraps the GPGME gpgme_data_new_from_fd() function.  The
1298         argument "file" must be a file-like object, supporting the
1299         fileno() method.
1300
1301         """
1302         tmp = gpgme.new_gpgme_data_t_p()
1303         errorcheck(gpgme.gpgme_data_new_from_fd(tmp, file.fileno()))
1304         self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
1305         gpgme.delete_gpgme_data_t_p(tmp)
1306
1307     def new_from_stream(self, file):
1308         """This wrap around gpgme_data_new_from_stream is an alias for
1309         new_from_fd() method since in python there's not difference
1310         between file stream and file descriptor"""
1311         self.new_from_fd(file)
1312
1313     def write(self, buffer):
1314         """Write buffer given as string or bytes.
1315
1316         If a string is given, it is implicitly encoded using UTF-8."""
1317         written = gpgme.gpgme_data_write(self.wrapped, buffer)
1318         if written < 0:
1319             if self._callback_excinfo:
1320                 gpgme.gpg_raise_callback_exception(self)
1321             else:
1322                 raise GPGMEError.fromSyserror()
1323         return written
1324
1325     def read(self, size = -1):
1326         """Read at most size bytes, returned as bytes.
1327
1328         If the size argument is negative or omitted, read until EOF is reached.
1329
1330         Returns the data read, or the empty string if there was no data
1331         to read before EOF was reached."""
1332
1333         if size == 0:
1334             return ''
1335
1336         if size > 0:
1337             try:
1338                 result = gpgme.gpgme_data_read(self.wrapped, size)
1339             except:
1340                 if self._callback_excinfo:
1341                     gpgme.gpg_raise_callback_exception(self)
1342                 else:
1343                     raise
1344             return result
1345         else:
1346             chunks = []
1347             while True:
1348                 try:
1349                     result = gpgme.gpgme_data_read(self.wrapped, 4096)
1350                 except:
1351                     if self._callback_excinfo:
1352                         gpgme.gpg_raise_callback_exception(self)
1353                     else:
1354                         raise
1355                 if len(result) == 0:
1356                     break
1357                 chunks.append(result)
1358             return b''.join(chunks)
1359
1360 def pubkey_algo_string(subkey):
1361     """Return short algorithm string
1362
1363     Return a public key algorithm string (e.g. "rsa2048") for a given
1364     SUBKEY.
1365
1366     Returns:
1367     algo      - a string
1368
1369     """
1370     return gpgme.gpgme_pubkey_algo_string(subkey)
1371
1372 def pubkey_algo_name(algo):
1373     """Return name of public key algorithm
1374
1375     Return the name of the public key algorithm for a given numeric
1376     algorithm id ALGO (cf. RFC4880).
1377
1378     Returns:
1379     algo      - a string
1380
1381     """
1382     return gpgme.gpgme_pubkey_algo_name(algo)
1383
1384 def hash_algo_name(algo):
1385     """Return name of hash algorithm
1386
1387     Return the name of the hash algorithm for a given numeric
1388     algorithm id ALGO (cf. RFC4880).
1389
1390     Returns:
1391     algo      - a string
1392
1393     """
1394     return gpgme.gpgme_hash_algo_name(algo)
1395
1396 def get_protocol_name(proto):
1397     """Get protocol description
1398
1399     Get the string describing protocol PROTO.
1400
1401     Returns:
1402     proto     - a string
1403
1404     """
1405     return gpgme.gpgme_get_protocol_name(proto)
1406
1407 def addrspec_from_uid(uid):
1408     """Return the address spec
1409
1410     Return the addr-spec (cf. RFC2822 section 4.3) from a user id UID.
1411
1412     Returns:
1413     addr_spec - a string
1414
1415     """
1416     return gpgme.gpgme_addrspec_from_uid(uid)
1417
1418 def check_version(version=None):
1419     return gpgme.gpgme_check_version(version)
1420
1421 # check_version also makes sure that several subsystems are properly
1422 # initialized, and it must be run at least once before invoking any
1423 # other function.  We do it here so that the user does not have to do
1424 # it unless she really wants to check for a certain version.
1425 check_version()
1426
1427 def engine_check_version (proto):
1428     try:
1429         errorcheck(gpgme.gpgme_engine_check_version(proto))
1430         return True
1431     except errors.GPGMEError:
1432         return False
1433
1434 def get_engine_info():
1435     ptr = gpgme.new_gpgme_engine_info_t_p()
1436     try:
1437         errorcheck(gpgme.gpgme_get_engine_info(ptr))
1438         info = gpgme.gpgme_engine_info_t_p_value(ptr)
1439     except errors.GPGMEError:
1440         info = None
1441     gpgme.delete_gpgme_engine_info_t_p(ptr)
1442     return info
1443
1444 def set_engine_info(proto, file_name, home_dir=None):
1445     """Changes the default configuration of the crypto engine implementing
1446     the protocol 'proto'. 'file_name' is the file name of
1447     the executable program implementing this protocol. 'home_dir' is the
1448     directory name of the configuration directory (engine's default is
1449     used if omitted)."""
1450     errorcheck(gpgme.gpgme_set_engine_info(proto, file_name, home_dir))
1451
1452 def set_locale(category, value):
1453     """Sets the default locale used by contexts"""
1454     errorcheck(gpgme.gpgme_set_locale(None, category, value))
1455
1456 def wait(hang):
1457     """Wait for asynchronous call on any Context  to finish.
1458     Wait forever if hang is True.
1459
1460     For finished anynch calls it returns a tuple (status, context):
1461         status  - status return by asnynchronous call.
1462         context - context which caused this call to return.
1463
1464     Please read the GPGME manual of more information."""
1465     ptr = gpgme.new_gpgme_error_t_p()
1466     context = gpgme.gpgme_wait(None, ptr, hang)
1467     status = gpgme.gpgme_error_t_p_value(ptr)
1468     gpgme.delete_gpgme_error_t_p(ptr)
1469     if context == None:
1470         errorcheck(status)
1471     else:
1472         context = Context(context)
1473     return (status, context)