From a982f9131520bce0b25f84cba19040bbe5f275bb Mon Sep 17 00:00:00 2001 From: Ben McGinnes Date: Thu, 4 Oct 2018 06:57:51 +1000 Subject: docs: python bindings * Restructured the docs directory to account for the GNU preferred source doc format (.texi) and the Python preferred source doc format (.rst) and the real source doc format (.org). * Both the perceived source formats will need to be generated from the .org files and included at this stage. Unfortunately there is not yet a native org-to-rst transformation method in the org-mode software in Emacs nor is there a a direct means of going from reST to Org-mode from Docutils. There's only third party packages like Pandoc and, while very good, there is no guarantee of consistency; so we can't entirely automate this bit (yet). --- lang/python/docs/TODO.org | 219 -- lang/python/docs/gpgme-python-howto.org | 3028 --------------------------- lang/python/docs/meta/TODO.org | 219 ++ lang/python/docs/meta/old-commits.log | 2445 +++++++++++++++++++++ lang/python/docs/old-commits.log | 2445 --------------------- lang/python/docs/short-history.org | 172 -- lang/python/docs/src/gpgme-python-howto.org | 3028 +++++++++++++++++++++++++++ lang/python/docs/src/short-history.org | 172 ++ 8 files changed, 5864 insertions(+), 5864 deletions(-) delete mode 100644 lang/python/docs/TODO.org delete mode 100644 lang/python/docs/gpgme-python-howto.org create mode 100644 lang/python/docs/meta/TODO.org create mode 100644 lang/python/docs/meta/old-commits.log delete mode 100644 lang/python/docs/old-commits.log delete mode 100644 lang/python/docs/short-history.org create mode 100644 lang/python/docs/src/gpgme-python-howto.org create mode 100644 lang/python/docs/src/short-history.org diff --git a/lang/python/docs/TODO.org b/lang/python/docs/TODO.org deleted file mode 100644 index add8f4ff..00000000 --- a/lang/python/docs/TODO.org +++ /dev/null @@ -1,219 +0,0 @@ -#+TITLE: Stuff To Do -#+LATEX_COMPILER: xelatex -#+LATEX_CLASS: article -#+LATEX_CLASS_OPTIONS: [12pt] -#+LATEX_HEADER: \usepackage{xltxtra} -#+LATEX_HEADER: \usepackage[margin=1in]{geometry} -#+LATEX_HEADER: \setmainfont[Ligatures={Common}]{Latin Modern Roman} - -* Project Task List - :PROPERTIES: - :CUSTOM_ID: task-list - :END: - -** DONE Documentation default format - CLOSED: [2018-02-15 Thu 21:29] - :PROPERTIES: - :CUSTOM_ID: todo-docs-default - :END: - - Decide on a default file format for documentation. The two main - contenders being Org Mode, the default for the GnuPG Project and - reStructuredText, the default for Python projects. A third option - of DITA XML was considered due to a number of beneficial features - it provides. - - The decision was made to use Org Mode in order to fully integrate - with the rest of the GPGME and GnuPG documentation. It is possible - to produce reST versions via Pandoc and DITA XML can be reached - through converting to either Markdown or XHTML first. - - -** STARTED Documentation HOWTO - :PROPERTIES: - :CUSTOM_ID: todo-docs-howto - :END: - - - State "STARTED" from "TODO" [2018-03-08 Thu 13:59] \\ - Started yesterday. - Write a HOWTO style guide for the current Python bindings. - -*** DONE Start python bindings HOWTO - CLOSED: [2018-03-07 Wed 18:14] - :PROPERTIES: - :CUSTOM_ID: howto-start - :END: - - -*** STARTED Include certain specific instructions in the HOWTO - :PROPERTIES: - :CUSTOM_ID: howto-requests - :END: - - Note: moved the S/MIME bits out to their own section of the TODO - list and may be served better by separate HOWTO documentation - anyway. - - - State "STARTED" from "TODO" [2018-03-09 Fri 15:27] - Some functions can be worked out from the handful of examples - available, but many more can't and I've already begun receiving - requests for certain functions to be explained. - - -**** DONE Standard scenarios - CLOSED: [2018-03-19 Mon 12:34] - :PROPERTIES: - :CUSTOM_ID: howto-the-basics - :END: - - - State "DONE" from "STARTED" [2018-03-19 Mon 12:34] \\ - All four of those are done. - - State "STARTED" from "TODO" [2018-03-09 Fri 15:26] \\ - Began with the example code, now to add the text. - What everyone expects: encryption, decryption, signing and verifying. - - -**** STARTED Key control - :PROPERTIES: - :CUSTOM_ID: howto-key-control - :END: - - - State "STARTED" from "TODO" [2018-03-19 Mon 12:35] \\ - Generating keys and subkeys are done, but revocation is still to be done. - Generating keys, adding subkeys, revoking subkeys (and keeping - the cert key), adding and revoking UIDs, signing/certifying keys. - - -**** DONE More key control - CLOSED: [2018-03-19 Mon 12:36] - :PROPERTIES: - :CUSTOM_ID: howto-key-selection - :END: - - - State "DONE" from "TODO" [2018-03-19 Mon 12:36] \\ - Key selection, searching, matching and counting is done. - Selecting keys to encrypt to or manipulate in other ways (e.g. as - with key control or the basics). - - -** TODO Documentation SWIG - :PROPERTIES: - :CUSTOM_ID: todo-docs-swig - :END: - - Write documentation for the complete SWIG bindings demonstrating - the correspondence with GPGME itself. - - Note: it is likely that this will be more in the nature of - something to be used in conjunction with the existing GPGME - documentation which makes it easier for Python developers to use. - - -** TODO GUI examples - :PROPERTIES: - :CUSTOM_ID: todo-gui-examples - :END: - - Create some examples of using Python bindings in a GUI application - to either match or be similar to the old GTK2 examples available - with PyME. - - -** TODO Replace SWIG - :PROPERTIES: - :CUSTOM_ID: todo-replace-swig - :END: - - Selecting SWIG for this project in 2002 was understandable and - effectively the only viable option. The options available now, - however, are significantly improved and some of those would resolve - a number of existing problems with using SWIG, particularly when - running code on both POSIX compliant and Windows platforms. - - The long term goal is to replace SWIG by reimplementing the Python - bindings using a more suitable means of interfacing with the GPGME - C source code. - - -*** TODO Replacement for SWIG - :PROPERTIES: - :CUSTOM_ID: todo-replace-swig-replacement - :END: - - Decide on a replacement for SWIG. Currently CFFI is looking like - the most viable candidate, but some additional testing and checks - are yet to be completed. - - -** TODO API for an API - :PROPERTIES: - :CUSTOM_ID: todo-api-squared - :END: - - A C API like GPGME is not what most modern developers think of when - they hear the term API. Normally they think of something they can - interact with like a RESTful web API. Though RESTful is unlikely - given the nature of GPGME and the process of encryption, it may be - possible to provide a more familiar interface which can be utilised - by developers of other languages for which bindings are not - available or for which it is too difficult to create proper - bindings. - - -** TODO S/MIME - :PROPERTIES: - :CUSTOM_ID: s-mime - :END: - - Eventually add some of this, but the OpenPGP details are far more - important at the moment. - - -* Project Task Details - :PROPERTIES: - :CUSTOM_ID: detailed-tasks - :END: - -** Working examples - :PROPERTIES: - :CUSTOM_ID: working-examples - :END: - - The old GUI examples were unable to be retained since they depended - on GTK2 and Python 2's integration with GTK2. - - Current GPGME examples so far only include command line tools or - basic Python code for use with either Python 2.7 or Python 3.4 and - above. - - Future GUI examples ought to utilise available GUI modules and - libraries supported by Python 3. This may include Qt frameworks, - Tkinter, GTK3 or something else entirely. - -** Documentation - :PROPERTIES: - :CUSTOM_ID: documentation - :END: - - The legacy documentation which no longer applies to the Python - bindings has been removed. - - Current and future documentation will adhere to the GnuPG standard - of using Org Mode and not use the reStructuredText (reST) format - more commonly associated with Python documentation. The reasons - for this are that this project is best served as shipping with the - rest of GPGME and the documentation ought to match that. There are - also aspects of Org Mode's publishing features which are superior - to the defaults of reST, including the capacity to generate fully - validating strict XHTML output. - - If reST files are required at a later point for future inclusion - with other Python packages, then that format can be generated from - the .org files with Pandoc before being leveraged by either - Docutils, Sphinx or something else. - - While there are some advanced typesetting features of reST which - are not directly available to Org Mode, more often than not those - features are best implemented with either HTML and CSS, with LaTeX - to produce a PDF or via a number of XML solutions. Both reST and - Org Mode have multiple paths by which to achieve all of these. diff --git a/lang/python/docs/gpgme-python-howto.org b/lang/python/docs/gpgme-python-howto.org deleted file mode 100644 index c7a1f823..00000000 --- a/lang/python/docs/gpgme-python-howto.org +++ /dev/null @@ -1,3028 +0,0 @@ -#+TITLE: GNU Privacy Guard (GnuPG) Made Easy Python Bindings HOWTO (English) -#+AUTHOR: Ben McGinnes -#+LATEX_COMPILER: xelatex -#+LATEX_CLASS: article -#+LATEX_CLASS_OPTIONS: [12pt] -#+LATEX_HEADER: \usepackage{xltxtra} -#+LATEX_HEADER: \usepackage[margin=1in]{geometry} -#+LATEX_HEADER: \setmainfont[Ligatures={Common}]{Times New Roman} -#+LATEX_HEADER: \author{Ben McGinnes } -#+HTML_HEAD_EXTRA: - - -* Introduction - :PROPERTIES: - :CUSTOM_ID: intro - :END: - -| Version: | 0.1.4 | -| GPGME Version: | 1.12.0 | -| Author: | [[https://gnupg.org/people/index.html#sec-1-5][Ben McGinnes]] | -| Author GPG Key: | DB4724E6FA4286C92B4E55C4321E4E2373590E5D | -| Language: | Australian English, British English | -| xml:lang: | en-AU, en-GB, en | - -This document provides basic instruction in how to use the GPGME -Python bindings to programmatically leverage the GPGME library. - - -** Python 2 versus Python 3 - :PROPERTIES: - :CUSTOM_ID: py2-vs-py3 - :END: - -Though the GPGME Python bindings themselves provide support for both -Python 2 and 3, the focus is unequivocally on Python 3 and -specifically from Python 3.4 and above. As a consequence all the -examples and instructions in this guide use Python 3 code. - -Much of it will work with Python 2, but much of it also deals with -Python 3 byte literals, particularly when reading and writing data. -Developers concentrating on Python 2.7, and possibly even 2.6, will -need to make the appropriate modifications to support the older string -and unicode types as opposed to bytes. - -There are multiple reasons for concentrating on Python 3; some of -which relate to the immediate integration of these bindings, some of -which relate to longer term plans for both GPGME and the python -bindings and some of which relate to the impending EOL period for -Python 2.7. Essentially, though, there is little value in tying the -bindings to a version of the language which is a dead end and the -advantages offered by Python 3 over Python 2 make handling the data -types with which GPGME deals considerably easier. - - -** Examples - :PROPERTIES: - :CUSTOM_ID: howto-python3-examples - :END: - -All of the examples found in this document can be found as Python 3 -scripts in the =lang/python/examples/howto= directory. - - -** Unofficial Drafts - :PROPERTIES: - :CUSTOM_ID: unofficial-drafts - :END: - -In addition to shipping with each release of GPGME, there is a section -on locations to read or download [[#draft-editions][draft editions]] of this document from -at the end of it. These are unofficial versions produced in between -major releases. - - -** What's New - :PROPERTIES: - :CUSTOM_ID: new-stuff - :END: - -The most obviously new point for those reading this guide is this -section on other new things, but that's hardly important. Not given -all the other things which spurred the need for adding this section -and its subsections. - -*** New in GPGME 1·12·0 - :PROPERTIES: - :CUSTOM_ID: new-stuff-1-12-0 - :END: - -There have been quite a number of additions to GPGME and the Python -bindings to it since the last release of GPGME with versions 1.11.0 -and 1.11.1 in April, 2018. - -The bullet points of new additiions are: - -- an expanded section on [[#installation][installing]] and [[#snafu][troubleshooting]] the Python - bindings. -- The release of Python 3.7.0; which appears to be working just fine - with our bindings, in spite of intermittent reports of problems for - many other Python projects with that new release. -- Python 3.7 has been moved to the head of the specified python - versions list in the build process. -- In order to fix some other issues, there are certain underlying - functions which are more exposed through the [[#howto-get-context][gpg.Context()]], but - ongoing documentation ought to clarify that or otherwise provide the - best means of using the bindings. Some additions to =gpg.core= and - the =Context()=, however, were intended (see below). -- Continuing work in identifying and confirming the cause of - oft-reported [[#snafu-runtime-not-funtime][problems installing the Python bindings on Windows]]. -- GSOC: Google's Surreptitiously Ordered Conscription ... erm ... oh, - right; Google's Summer of Code. Though there were two hopeful - candidates this year; only one ended up involved with the GnuPG - Project directly, the other concentrated on an unrelated third party - project with closer ties to one of the GNU/Linux distributions than - to the GnuPG Project. Thus the Python bindings benefited from GSOC - participant Jacob Adams, who added the key_import function; building - on prior work by Tobias Mueller. -- Several new methods functions were added to the gpg.Context(), - including: [[#howto-import-key][key_import]], [[#howto-export-key][key_export]], [[#howto-export-public-key][key_export_minimal]] and - [[#howto-export-secret-key][key_export_secret]]. -- Importing and exporting examples include versions integrated with - Marcel Fest's recently released [[https://github.com/Selfnet/hkp4py][HKP for Python]] module. Some - [[#hkp4py][additional notes on this module]] are included at the end of the HOWTO. -- Instructions for dealing with semi-walled garden implementations - like ProtonMail are also included. This is intended to make things - a little easier when communicating with users of ProtonMail's - services and should not be construed as an endorsement of said - service. The GnuPG Project neither favours, nor disfavours - ProtonMail and the majority of this deals with interacting with the - ProtonMail keyserver. -- Semi-formalised the location where [[#draft-editions][draft versions]] of this HOWTO may - periodically be accessible. This is both for the reference of - others and testing the publishing of the document itself. Renamed - the file at around the same time. -- Added a new section for [[#advanced-use][advanced or experimental use]]. -- Began the advanced use cases with [[#cython][a section]] on using the module with - [[http://cython.org/][Cython]]. -- Added a number of new scripts to the =example/howto/= directory; - some of which may be in advance of their planned sections of the - HOWTO (and some are just there because it seemed like a good idea at - the time). -- Cleaned up a lot of things under the hood. - - -* GPGME Concepts - :PROPERTIES: - :CUSTOM_ID: gpgme-concepts - :END: - - -** A C API - :PROPERTIES: - :CUSTOM_ID: gpgme-c-api - :END: - -Unlike many modern APIs with which programmers will be more familiar -with these days, the GPGME API is a C API. The API is intended for -use by C coders who would be able to access its features by including -the =gpgme.h= header file with their own C source code and then access -its functions just as they would any other C headers. - -This is a very effective method of gaining complete access to the API -and in the most efficient manner possible. It does, however, have the -drawback that it cannot be directly used by other languages without -some means of providing an interface to those languages. This is -where the need for bindings in various languages stems. - - -** Python bindings - :PROPERTIES: - :CUSTOM_ID: gpgme-python-bindings - :END: - -The Python bindings for GPGME provide a higher level means of -accessing the complete feature set of GPGME itself. It also provides -a more pythonic means of calling these API functions. - -The bindings are generated dynamically with SWIG and the copy of -=gpgme.h= generated when GPGME is compiled. - -This means that a version of the Python bindings is fundamentally tied -to the exact same version of GPGME used to generate that copy of -=gpgme.h=. - - -** Difference between the Python bindings and other GnuPG Python packages - :PROPERTIES: - :CUSTOM_ID: gpgme-python-bindings-diffs - :END: - -There have been numerous attempts to add GnuPG support to Python over -the years. Some of the most well known are listed here, along with -what differentiates them. - - -*** The python-gnupg package maintained by Vinay Sajip - :PROPERTIES: - :CUSTOM_ID: diffs-python-gnupg - :END: - -This is arguably the most popular means of integrating GPG with -Python. The package utilises the =subprocess= module to implement -wrappers for the =gpg= and =gpg2= executables normally invoked on the -command line (=gpg.exe= and =gpg2.exe= on Windows). - -The popularity of this package stemmed from its ease of use and -capability in providing the most commonly required features. - -Unfortunately it has been beset by a number of security issues in the -past; most of which stemmed from using unsafe methods of accessing the -command line via the =subprocess= calls. While some effort has been -made over the last two to three years (as of 2018) to mitigate this, -particularly by no longer providing shell access through those -subprocess calls, the wrapper is still somewhat limited in the scope -of its GnuPG features coverage. - -The python-gnupg package is available under the MIT license. - - -*** The gnupg package created and maintained by Isis Lovecruft - :PROPERTIES: - :CUSTOM_ID: diffs-isis-gnupg - :END: - -In 2015 Isis Lovecruft from the Tor Project forked and then -re-implemented the python-gnupg package as just gnupg. This new -package also relied on subprocess to call the =gpg= or =gpg2= -binaries, but did so somewhat more securely. - -The naming and version numbering selected for this package, however, -resulted in conflicts with the original python-gnupg and since its -functions were called in a different manner to python-gnupg, the -release of this package also resulted in a great deal of consternation -when people installed what they thought was an upgrade that -subsequently broke the code relying on it. - -The gnupg package is available under the GNU General Public License -version 3.0 (or any later version). - - -*** The PyME package maintained by Martin Albrecht - :PROPERTIES: - :CUSTOM_ID: diffs-pyme - :END: - -This package is the origin of these bindings, though they are somewhat -different now. For details of when and how the PyME package was -folded back into GPGME itself see the /Short History/ document[fn:1] -in the Python bindings =docs= directory.[fn:2] - -The PyME package was first released in 2002 and was also the first -attempt to implement a low level binding to GPGME. In doing so it -provided access to considerably more functionality than either the -=python-gnupg= or =gnupg= packages. - -The PyME package is only available for Python 2.6 and 2.7. - -Porting the PyME package to Python 3.4 in 2015 is what resulted in it -being folded into the GPGME project and the current bindings are the -end result of that effort. - -The PyME package is available under the same dual licensing as GPGME -itself: the GNU General Public License version 2.0 (or any later -version) and the GNU Lesser General Public License version 2.1 (or any -later version). - - -* GPGME Python bindings installation - :PROPERTIES: - :CUSTOM_ID: gpgme-python-install - :END: - - -** No PyPI - :PROPERTIES: - :CUSTOM_ID: do-not-use-pypi - :END: - -Most third-party Python packages and modules are available and -distributed through the Python Package Installer, known as PyPI. - -Due to the nature of what these bindings are and how they work, it is -infeasible to install the GPGME Python bindings in the same way. - -This is because the bindings use SWIG to dynamically generate C -bindings against =gpgme.h= and =gpgme.h= is generated from -=gpgme.h.in= at compile time when GPGME is built from source. Thus to -include a package in PyPI which actually built correctly would require -either statically built libraries for every architecture bundled with -it or a full implementation of C for each architecture. - -See the additional notes regarding [[#snafu-cffi][CFFI and SWIG]] at the end of this -section for further details. - - -** Requirements - :PROPERTIES: - :CUSTOM_ID: gpgme-python-requirements - :END: - -The GPGME Python bindings only have three requirements: - -1. A suitable version of Python 2 or Python 3. With Python 2 that - means CPython 2.7 and with Python 3 that means CPython 3.4 or - higher. -2. [[https://www.swig.org][SWIG]]. -3. GPGME itself. Which also means that all of GPGME's dependencies - must be installed too. - - -*** Recommended Additions - :PROPERTIES: - :CUSTOM_ID: gpgme-python-recommendations - :END: - -Though none of the following are absolute requirements, they are all -recommended for use with the Python bindings. In some cases these -recommendations refer to which version(s) of CPython to use the -bindings with, while others refer to third party modules which provide -a significant advantage in some way. - -1. If possible, use Python 3 instead of 2. -2. Favour a more recent version of Python since even 3.4 is due to - reach EOL soon. In production systems and services, Python 3.6 - should be robust enough to be relied on. -3. If possible add the following Python modules which are not part of - the standard library: [[http://docs.python-requests.org/en/latest/index.html][Requests]], [[http://cython.org/][Cython]] and [[https://github.com/Selfnet/hkp4py][hkp4py]]. Chances are - quite high that at least the first one and maybe two of those will - already be installed. - -Note that, as with Cython, some of the planned additions to the -[[#advanced-use][Advanced]] section, will bring with them additional requirements. Most -of these will be fairly well known and commonly installed ones, -however, which are in many cases likely to have already been installed -on many systems or be familiar to Python programmers. - - -** Installation - :PROPERTIES: - :CUSTOM_ID: installation - :END: - -Installing the Python bindings is effectively achieved by compiling -and installing GPGME itself. - -Once SWIG is installed with Python and all the dependencies for GPGME -are installed you only need to confirm that the version(s) of Python -you want the bindings installed for are in your =$PATH=. - -By default GPGME will attempt to install the bindings for the most -recent or highest version number of Python 2 and Python 3 it detects -in =$PATH=. It specifically checks for the =python= and =python3= -executables first and then checks for specific version numbers. - -For Python 2 it checks for these executables in this order: =python=, -=python2= and =python2.7=. - -For Python 3 it checks for these executables in this order: =python3=, - =python3.7=, =python3.6=, =python3.5= and =python3.4=.[fn:3] - -On systems where =python= is actually =python3= and not =python2= it -may be possible that =python2= may be overlooked, but there have been -no reports of that actually occurring as yet. - -In the three months or so since the release of Python 3.7.0 there has -been extensive testing and work with these bindings with no issues -specifically relating to the new version of Python or any of the new -features of either the language or the bindings. This has also been -the case with Python 3.7.1rc1. With that in mind and given the -release of Python 3.7.1 is scheduled for around the same time as GPGME -1.12.0, the order of preferred Python versions has been changed to -move Python 3.7 ahead of Python 3.6. - - -*** Installing GPGME - :PROPERTIES: - :CUSTOM_ID: install-gpgme - :END: - -See the GPGME =README= file for details of how to install GPGME from -source. - - -** Known Issues - :PROPERTIES: - :CUSTOM_ID: snafu - :END: - -There are a few known issues with the current build process and the -Python bindings. For the most part these are easily addressed should -they be encountered. - - -*** Breaking Builds - :PROPERTIES: - :CUSTOM_ID: snafu-a-swig-of-this-builds-character - :END: - -Occasionally when installing GPGME with the Python bindings included -it may be observed that the =make= portion of that process induces a -large very number of warnings and, eventually errors which end that -part of the build process. Yet following that with =make check= and -=make install= appears to work seamlessly. - -The cause of this is related to the way SWIG needs to be called to -dynamically generate the C bindings for GPGME in the first place. So -the entire process will always produce =lang/python/python2-gpg/= and -=lang/python/python3-gpg/= directories. These should contain the -build output generated during compilation, including the complete -bindings and module installed into =site-packages=. - -Occasionally the errors in the early part or some other conflict -(e.g. not installing as */root/* or */su/*) may result in nothing -being installed to the relevant =site-packages= directory and the -build directory missing a lot of expected files. Even when this -occurs, the solution is actually quite simple and will always work. - -That solution is simply to run the following commands as either the -*root* user or prepended with =sudo -H=[fn:4] in the =lang/python/= -directory: - -#+BEGIN_SRC shell - /path/to/pythonX.Y setup.py build - /path/to/pythonX.Y setup.py build - /path/to/pythonX.Y setup.py install -#+END_SRC - -Yes, the build command does need to be run twice. Yes, you still need -to run the potentially failing or incomplete steps during the -=configure=, =make= and =make install= steps with installing GPGME. -This is because those steps generate a lot of essential files needed, -both by and in order to create, the bindings (including both the -=setup.py= and =gpgme.h= files). - - -**** IMPORTANT Note - :PROPERTIES: - :CUSTOM_ID: snafu-swig-build-note - :END: - -If specifying a selected number of languages to create bindings for, -try to leave Python last. Currently the majority of the other -language bindings are also preceding Python of either version when -listed alphabetically and so that just happens by default currently. - -If Python is set to precede one of the other languages then it is -possible that the errors described here may interrupt the build -process before generating bindings for those other languages. In -these cases it may be preferable to configure all preferred language -bindings separately with alternative =configure= steps for GPGME using -the =--enable-languages=$LANGUAGE= option. - - -*** Reinstalling Responsibly - :PROPERTIES: - :CUSTOM_ID: snafu-lessons-for-the-lazy - :END: - -Regardless of whether you're installing for one version of Python or -several, there will come a point where reinstallation is required. -With most Python module installations, the installed files go into the -relevant site-packages directory and are then forgotten about. Then -the module is upgraded, the new files are copied over the old and -that's the end of the matter. - -While the same is true of these bindings, there have been intermittent -issues observed on some platforms which have benefited significantly -from removing all the previous installations of the bindings before -installing the updated versions. - -Removing the previous version(s) is simply a matter of changing to the -relevant =site-packages= directory for the version of Python in -question and removing the =gpg/= directory and any accompanying -egg-info files for that module. - -In most cases this will require root or administration privileges on -the system, but the same is true of installing the module in the first -place. - - -*** Multiple installations - :PROPERTIES: - :CUSTOM_ID: snafu-the-full-monty - :END: - -For a veriety of reasons it may be either necessary or just preferable -to install the bindings to alternative installed Python versions which -meet the requirements of these bindings. - -On POSIX systems this will generally be most simply achieved by -running the manual installation commands (build, build, install) as -described in the previous section for each Python installation the -bindings need to be installed to. - -As per the SWIG documentation: the compilers, libraries and runtime -used to build GPGME and the Python Bindings *must* match those used to -compile Python itself, including the version number(s) (at least going -by major version numbers and probably minor numbers too). - -On most POSIX systems, including OS X, this will very likely be the -case in most, if not all, cases. - - -*** Won't Work With Windows - :PROPERTIES: - :CUSTOM_ID: snafu-runtime-not-funtime - :END: - -There are semi-regular reports of Windows users having considerable -difficulty in installing and using the Python bindings at all. Very -often, possibly even always, these reports come from Cygwin users -and/or MinGW users and/or Msys2 users. Though not all of them have -been confirmed, it appears that these reports have also come from -people who installed Python using the Windows installer files from the -[[https://python.org][Python website]] (i.e. mostly MSI installers, sometimes self-extracting -=.exe= files). - -The Windows versions of Python are not built using Cygwin, MinGW or -Msys2; they're built using Microsoft Visual Studio. Furthermore the -version used is /considerably/ more advanced than the version which -MinGW obtained a small number of files from many years ago in order to -be able to compile anything at all. Not only that, but there are -changes to the version of Visual Studio between some micro releases, -though that is is particularly the case with Python 2.7, since it has -been kept around far longer than it should have been. - -There are two theoretical solutions to this issue: - - 1. Compile and install the GnuPG stack, including GPGME and the - Python bibdings using the same version of Microsoft Visual Studio - used by the Python Foundation to compile the version of Python - installed. - - If there are multiple versions of Python then this will need to be - done with each different version of Visual Studio used. - - 2. Compile and install Python using the same tools used by choice, - such as MinGW or Msys2. - -Do *not* use the official Windows installer for Python unless -following the first method. - -In this type of situation it may even be for the best to accept that -there are less limitations on permissive software than free software -and simply opt to use a recent version of the Community Edition of -Microsoft Visual Studio to compile and build all of it, no matter -what. - -Investigations into the extent or the limitations of this issue are -ongoing. - - -*** CFFI is the Best™ and GPGME should use it instead of SWIG - :PROPERTIES: - :CUSTOM_ID: snafu-cffi - :END: - -There are many reasons for favouring [[https://cffi.readthedocs.io/en/latest/overview.html][CFFI]] and proponents of it are -quite happy to repeat these things as if all it would take to switch -from SWIG to CFFI is repeating that list as if it were a new concept. - -The fact is that there are things which Python's CFFI implementation -cannot handle in the GPGME C code. Beyond that there are features of -SWIG which are simply not available with CFFI at all. SWIG generates -the bindings to Python using the =gpgme.h= file, but that file is not -a single version shipped with each release, it too is generated when -GPGME is compiled. - -CFFI is currently unable to adapt to such a potentially mutable -codebase. If there were some means of applying SWIG's dynamic code -generation to produce the Python/CFFI API modes of accessing the GPGME -libraries (or the source source code directly), but such a thing does -not exist yet either and it currently appears that work is needed in -at least one of CFFI's dependencies before any of this can be -addressed. - -So if you're a massive fan of CFFI; that's great, but if you want this -project to switch to CFFI then rather than just insisting that it -should, I'd suggest you volunteer to bring CFFI up to the level this -project needs. - -If you're actually seriously considering doing so, then I'd suggest -taking the =gpgme-tool.c= file in the GPGME =src/= directory and -getting that to work with any of the CFFI API methods (not the ABI -methods, they'll work with pretty much anything). When you start -running into trouble with "ifdefs" then you'll know what sort of -things are lacking. That doesn't even take into account the amount of -work saved via SWIG's code generation techniques either. - - -*** Virtualised Environments - :PROPERTIES: - :CUSTOM_ID: snafu-venv - :END: - -It is fairly common practice amongst Python developers to, as much as -possible, use packages like virtualenv to keep various things that are -to be installed from interfering with each other. Given how much of -the GPGME bindings is often at odds with the usual pythonic way of -doing things, it stands to reason that this would be called into -question too. - -As it happens the answer as to whether or not the bindings can be used -with virtualenv, the answer is both yes and no. - -In general we recommend installing to the relevant path and matching -prefix of GPGME itself. Which means that when GPGME, and ideally the -rest of the GnuPG stack, is installed to a prefix like =/usr/local= or -=/opt/local= then the bindings would need to be installed to the main -Python installation and not a virtualised abstraction. Attempts to -separate the two in the past have been known to cause weird and -intermittent errors ranging from minor annoyances to complete failures -in the build process. - -As a consequence we only recommend building with and installing to the -main Python installations within the same prefix as GPGME is installed -to or which are found by GPGME's configuration stage immediately prior -to running the make commands. Which is exactly what the compiling and -installing process of GPGME does by default. - -Once that is done, however, it appears that a copy the compiled module -may be installed into a virtualenv of the same major and minor version -matching the build. Alternatively it is possible to utilise a -=sites.pth= file in the =site-packages/= directory of a viertualenv -installation, which links back to the system installations -corresponding directory in order to import anything installed system -wide. This may or may not be appropriate on a case by case basis. - -Though extensive testing of either of these options is not yet -complete, preliminary testing of them indicates that both are viable -as long as the main installation is complete. Which means that -certain other options normally restricted to virtual environments are -also available, including integration with pythonic test suites -(e.g. [[https://docs.pytest.org/en/latest/index.html][pytest]]) and other large projects. - -That said, it is worth reiterating the warning regarding non-standard -installations. If one were to attempt to install the bindings only to -a virtual environment without somehow also including the full GnuPG -stack (or enough of it as to include GPGME) then it is highly likely -that errors would be encountered at some point and more than a little -likely that the build process itself would break. - -If a degree of separation from the main operating system is still -required in spite of these warnings, then consider other forms of -virtualisation. Either a virtual machine (e.g. [[https://www.virtualbox.org/][VirtualBox]]), a -hardware emulation layer (e.g. [[https://www.qemu.org/][QEMU]]) or an application container -(e.g. [[https://www.docker.com/why-docker][Docker]]). - -Finally it should be noted that the limited tests conducted thus far -have been using the =virtualenv= command in a new directory to create -the virtual python environment. As opposed to the standard =python3 --m venv= and it is possible that this will make a difference depending -on the system and version of Python in use. Another option is to run -the command =python3 -m virtualenv /path/to/install/virtual/thingy= -instead. - - -* Fundamentals - :PROPERTIES: - :CUSTOM_ID: howto-fund-a-mental - :END: - -Before we can get to the fun stuff, there are a few matters regarding -GPGME's design which hold true whether you're dealing with the C code -directly or these Python bindings. - - -** No REST - :PROPERTIES: - :CUSTOM_ID: no-rest-for-the-wicked - :END: - -The first part of which is or will be fairly blatantly obvious upon -viewing the first example, but it's worth reiterating anyway. That -being that this API is /*not*/ a REST API. Nor indeed could it ever -be one. - -Most, if not all, Python programmers (and not just Python programmers) -know how easy it is to work with a RESTful API. In fact they've -become so popular that many other APIs attempt to emulate REST-like -behaviour as much as they are able. Right down to the use of JSON -formatted output to facilitate the use of their API without having to -retrain developers. - -This API does not do that. It would not be able to do that and also -provide access to the entire C API on which it's built. It does, -however, provide a very pythonic interface on top of the direct -bindings and it's this pythonic layer that this HOWTO deals with. - - -** Context - :PROPERTIES: - :CUSTOM_ID: howto-get-context - :END: - -One of the reasons which prevents this API from being RESTful is that -most operations require more than one instruction to the API to -perform the task. Sure, there are certain functions which can be -performed simultaneously, particularly if the result known or strongly -anticipated (e.g. selecting and encrypting to a key known to be in the -public keybox). - -There are many more, however, which cannot be manipulated so readily: -they must be performed in a specific sequence and the result of one -operation has a direct bearing on the outcome of subsequent -operations. Not merely by generating an error either. - -When dealing with this type of persistent state on the web, full of -both the RESTful and REST-like, it's most commonly referred to as a -session. In GPGME, however, it is called a context and every -operation type has one. - - -* Working with keys - :PROPERTIES: - :CUSTOM_ID: howto-keys - :END: - - -** Key selection - :PROPERTIES: - :CUSTOM_ID: howto-keys-selection - :END: - -Selecting keys to encrypt to or to sign with will be a common -occurrence when working with GPGMe and the means available for doing -so are quite simple. - -They do depend on utilising a Context; however once the data is -recorded in another variable, that Context does not need to be the -same one which subsequent operations are performed. - -The easiest way to select a specific key is by searching for that -key's key ID or fingerprint, preferably the full fingerprint without -any spaces in it. A long key ID will probably be okay, but is not -advised and short key IDs are already a problem with some being -generated to match specific patterns. It does not matter whether the -pattern is upper or lower case. - -So this is the best method: - -#+BEGIN_SRC python -i -import gpg - -k = gpg.Context().keylist(pattern="258E88DCBD3CD44D8E7AB43F6ECB6AF0DEADBEEF") -keys = list(k) -#+END_SRC - -This is passable and very likely to be common: - -#+BEGIN_SRC python -i -import gpg - -k = gpg.Context().keylist(pattern="0x6ECB6AF0DEADBEEF") -keys = list(k) -#+END_SRC - -And this is a really bad idea: - -#+BEGIN_SRC python -i -import gpg - -k = gpg.Context().keylist(pattern="0xDEADBEEF") -keys = list(k) -#+END_SRC - -Alternatively it may be that the intention is to create a list of keys -which all match a particular search string. For instance all the -addresses at a particular domain, like this: - -#+BEGIN_SRC python -i -import gpg - -ncsc = gpg.Context().keylist(pattern="ncsc.mil") -nsa = list(ncsc) -#+END_SRC - - -*** Counting keys - :PROPERTIES: - :CUSTOM_ID: howto-keys-counting - :END: - -Counting the number of keys in your public keybox (=pubring.kbx=), the -format which has superseded the old keyring format (=pubring.gpg= and -=secring.gpg=), or the number of secret keys is a very simple task. - -#+BEGIN_SRC python -i -import gpg - -c = gpg.Context() -seckeys = c.keylist(pattern=None, secret=True) -pubkeys = c.keylist(pattern=None, secret=False) - -seclist = list(seckeys) -secnum = len(seclist) - -publist = list(pubkeys) -pubnum = len(publist) - -print(""" - Number of secret keys: {0} - Number of public keys: {1} -""".format(secnum, pubnum)) -#+END_SRC - -*NOTE:* The [[#cython][Cython]] introduction in the [[#advanced-use][Advanced and Experimental]] -section uses this same key counting code with Cython to demonstrate -some areas where Cython can improve performance even with the -bindings. Users with large public keyrings or keyboxes, for instance, -should consider these options if they are comfortable with using -Cython. - - -** Get key - :PROPERTIES: - :CUSTOM_ID: howto-get-key - :END: - -An alternative method of getting a single key via its fingerprint is -available directly within a Context with =Context().get_key=. This is -the preferred method of selecting a key in order to modify it, sign or -certify it and for obtaining relevant data about a single key as a -part of other functions; when verifying a signature made by that key, -for instance. - -By default this method will select public keys, but it can select -secret keys as well. - -This first example demonstrates selecting the current key of Werner -Koch, which is due to expire at the end of 2018: - -#+BEGIN_SRC python -i -import gpg - -fingerprint = "80615870F5BAD690333686D0F2AD85AC1E42B367" -key = gpg.Context().get_key(fingerprint) -#+END_SRC - -Whereas this example demonstrates selecting the author's current key -with the =secret= key word argument set to =True=: - -#+BEGIN_SRC python -i -import gpg - -fingerprint = "DB4724E6FA4286C92B4E55C4321E4E2373590E5D" -key = gpg.Context().get_key(fingerprint, secret=True) -#+END_SRC - -It is, of course, quite possible to select expired, disabled and -revoked keys with this function, but only to effectively display -information about those keys. - -It is also possible to use both unicode or string literals and byte -literals with the fingerprint when getting a key in this way. - - -** Importing keys - :PROPERTIES: - :CUSTOM_ID: howto-import-key - :END: - -Importing keys is possible with the =key_import()= method and takes -one argument which is a bytes literal object containing either the -binary or ASCII armoured key data for one or more keys. - -The following example retrieves one or more keys from the SKS -keyservers via the web using the requests module. Since requests -returns the content as a bytes literal object, we can then use that -directly to import the resulting data into our keybox. - -#+BEGIN_SRC python -i -import gpg -import os.path -import requests - -c = gpg.Context() -url = "https://sks-keyservers.net/pks/lookup" -pattern = input("Enter the pattern to search for key or user IDs: ") -payload = {"op": "get", "search": pattern} - -r = requests.get(url, verify=True, params=payload) -result = c.key_import(r.content) - -if result is not None and hasattr(result, "considered") is False: - print(result) -elif result is not None and hasattr(result, "considered") is True: - num_keys = len(result.imports) - new_revs = result.new_revocations - new_sigs = result.new_signatures - new_subs = result.new_sub_keys - new_uids = result.new_user_ids - new_scrt = result.secret_imported - nochange = result.unchanged - print(""" - The total number of keys considered for import was: {0} - - Number of keys revoked: {1} - Number of new signatures: {2} - Number of new subkeys: {3} - Number of new user IDs: {4} - Number of new secret keys: {5} - Number of unchanged keys: {6} - - The key IDs for all considered keys were: -""".format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt, - nochange)) - for i in range(num_keys): - print("{0}\n".format(result.imports[i].fpr)) -else: - pass -#+END_SRC - -*NOTE:* When searching for a key ID of any length or a fingerprint -(without spaces), the SKS servers require the the leading =0x= -indicative of hexadecimal be included. Also note that the old short -key IDs (e.g. =0xDEADBEEF=) should no longer be used due to the -relative ease by which such key IDs can be reproduced, as demonstrated -by the Evil32 Project in 2014 (which was subsequently exploited in -2016). - - -*** Working with ProtonMail - :PROPERTIES: - :CUSTOM_ID: import-protonmail - :END: - -Here is a variation on the example above which checks the constrained -ProtonMail keyserver for ProtonMail public keys. - -#+BEGIN_SRC python -i -import gpg -import requests -import sys - -print(""" -This script searches the ProtonMail key server for the specified key and -imports it. -""") - -c = gpg.Context(armor=True) -url = "https://api.protonmail.ch/pks/lookup" -ksearch = [] - -if len(sys.argv) >= 2: - keyterm = sys.argv[1] -else: - keyterm = input("Enter the key ID, UID or search string: ") - -if keyterm.count("@") == 2 and keyterm.startswith("@") is True: - ksearch.append(keyterm[1:]) - ksearch.append(keyterm[1:]) - ksearch.append(keyterm[1:]) -elif keyterm.count("@") == 1 and keyterm.startswith("@") is True: - ksearch.append("{0}@protonmail.com".format(keyterm[1:])) - ksearch.append("{0}@protonmail.ch".format(keyterm[1:])) - ksearch.append("{0}@pm.me".format(keyterm[1:])) -elif keyterm.count("@") == 0: - ksearch.append("{0}@protonmail.com".format(keyterm)) - ksearch.append("{0}@protonmail.ch".format(keyterm)) - ksearch.append("{0}@pm.me".format(keyterm)) -elif keyterm.count("@") == 2 and keyterm.startswith("@") is False: - uidlist = keyterm.split("@") - for uid in uidlist: - ksearch.append("{0}@protonmail.com".format(uid)) - ksearch.append("{0}@protonmail.ch".format(uid)) - ksearch.append("{0}@pm.me".format(uid)) -elif keyterm.count("@") > 2: - uidlist = keyterm.split("@") - for uid in uidlist: - ksearch.append("{0}@protonmail.com".format(uid)) - ksearch.append("{0}@protonmail.ch".format(uid)) - ksearch.append("{0}@pm.me".format(uid)) -else: - ksearch.append(keyterm) - -for k in ksearch: - payload = {"op": "get", "search": k} - try: - r = requests.get(url, verify=True, params=payload) - if r.ok is True: - result = c.key_import(r.content) - elif r.ok is False: - result = r.content - except Exception as e: - result = None - - if result is not None and hasattr(result, "considered") is False: - print("{0} for {1}".format(result.decode(), k)) - elif result is not None and hasattr(result, "considered") is True: - num_keys = len(result.imports) - new_revs = result.new_revocations - new_sigs = result.new_signatures - new_subs = result.new_sub_keys - new_uids = result.new_user_ids - new_scrt = result.secret_imported - nochange = result.unchanged - print(""" -The total number of keys considered for import was: {0} - -With UIDs wholely or partially matching the following string: - - {1} - - Number of keys revoked: {2} - Number of new signatures: {3} - Number of new subkeys: {4} - Number of new user IDs: {5} -Number of new secret keys: {6} - Number of unchanged keys: {7} - -The key IDs for all considered keys were: -""".format(num_keys, k, new_revs, new_sigs, new_subs, new_uids, new_scrt, - nochange)) - for i in range(num_keys): - print(result.imports[i].fpr) - print("") - elif result is None: - print(e) -#+END_SRC - -Both the above example, [[../examples/howto/pmkey-import.py][pmkey-import.py]], and a version which prompts -for an alternative GnuPG home directory, [[../examples/howto/pmkey-import-alt.py][pmkey-import-alt.py]], are -available with the other examples and are executable scripts. - -Note that while the ProtonMail servers are based on the SKS servers, -their server is related more to their API and is not feature complete -by comparison to the servers in the SKS pool. One notable difference -being that the ProtonMail server does not permit non ProtonMail users -to update their own keys, which could be a vector for attacking -ProtonMail users who may not receive a key's revocation if it had been -compromised. - - -*** Importing with HKP for Python - :PROPERTIES: - :CUSTOM_ID: import-hkp4py - :END: - -Performing the same tasks with the [[https://github.com/Selfnet/hkp4py][hkp4py module]] (available via PyPI) -is not too much different, but does provide a number of options of -benefit to end users. Not least of which being the ability to perform -some checks on a key before importing it or not. For instance it may -be the policy of a site or project to only import keys which have not -been revoked. The hkp4py module permits such checks prior to the -importing of the keys found. - -#+BEGIN_SRC python -i -import gpg -import hkp4py -import sys - -c = gpg.Context() -server = hkp4py.KeyServer("hkps://hkps.pool.sks-keyservers.net") -results = [] - -if len(sys.argv) > 2: - pattern = " ".join(sys.argv[1:]) -elif len(sys.argv) == 2: - pattern = sys.argv[1] -else: - pattern = input("Enter the pattern to search for keys or user IDs: ") - -try: - keys = server.search(pattern) - print("Found {0} key(s).".format(len(keys))) -except Exception as e: - keys = [] - for logrus in pattern.split(): - if logrus.startswith("0x") is True: - key = server.search(logrus) - else: - key = server.search("0x{0}".format(logrus)) - keys.append(key[0]) - print("Found {0} key(s).".format(len(keys))) - -for key in keys: - import_result = c.key_import(key.key_blob) - results.append(import_result) - -for result in results: - if result is not None and hasattr(result, "considered") is False: - print(result) - elif result is not None and hasattr(result, "considered") is True: - num_keys = len(result.imports) - new_revs = result.new_revocations - new_sigs = result.new_signatures - new_subs = result.new_sub_keys - new_uids = result.new_user_ids - new_scrt = result.secret_imported - nochange = result.unchanged - print(""" -The total number of keys considered for import was: {0} - - Number of keys revoked: {1} - Number of new signatures: {2} - Number of new subkeys: {3} - Number of new user IDs: {4} -Number of new secret keys: {5} - Number of unchanged keys: {6} - -The key IDs for all considered keys were: -""".format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt, - nochange)) - for i in range(num_keys): - print(result.imports[i].fpr) - print("") - else: - pass -#+END_SRC - -Since the hkp4py module handles multiple keys just as effectively as -one (=keys= is a list of responses per matching key), the example -above is able to do a little bit more with the returned data before -anything is actually imported. - - -*** Importing from ProtonMail with HKP for Python - :PROPERTIES: - :CUSTOM_ID: import-protonmail-hkp4py - :END: - -Though this can provide certain benefits even when working with -ProtonMail, the scope is somewhat constrained there due to the -limitations of the ProtonMail keyserver. - -For instance, searching the SKS keyserver pool for the term "gnupg" -produces hundreds of results from any time the word appears in any -part of a user ID. Performing the same search on the ProtonMail -keyserver returns zero results, even though there are at least two -test accounts which include it as part of the username. - -The cause of this discrepancy is the deliberate configuration of that -server by ProtonMail to require an exact match of the full email -address of the ProtonMail user whose key is being requested. -Presumably this is intended to reduce breaches of privacy of their -users as an email address must already be known before a key for that -address can be obtained. - - -**** Import from ProtonMail via HKP for Python Example no. 1 - :PROPERTIES: - :CUSTOM_ID: import-hkp4py-pm1 - :END: - -The following script is avalable with the rest of the examples under -the somewhat less than original name, =pmkey-import-hkp.py=. - -#+BEGIN_SRC python -i -import gpg -import hkp4py -import os.path -import sys - -print(""" -This script searches the ProtonMail key server for the specified key and -imports it. - -Usage: pmkey-import-hkp.py [search strings] -""") - -c = gpg.Context(armor=True) -server = hkp4py.KeyServer("hkps://api.protonmail.ch") -keyterms = [] -ksearch = [] -allkeys = [] -results = [] -paradox = [] -homeless = None - -if len(sys.argv) > 2: - keyterms = sys.argv[1:] -elif len(sys.argv) == 2: - keyterm = sys.argv[1] - keyterms.append(keyterm) -else: - key_term = input("Enter the key ID, UID or search string: ") - keyterms = key_term.split() - -for keyterm in keyterms: - if keyterm.count("@") == 2 and keyterm.startswith("@") is True: - ksearch.append(keyterm[1:]) - ksearch.append(keyterm[1:]) - ksearch.append(keyterm[1:]) - elif keyterm.count("@") == 1 and keyterm.startswith("@") is True: - ksearch.append("{0}@protonmail.com".format(keyterm[1:])) - ksearch.append("{0}@protonmail.ch".format(keyterm[1:])) - ksearch.append("{0}@pm.me".format(keyterm[1:])) - elif keyterm.count("@") == 0: - ksearch.append("{0}@protonmail.com".format(keyterm)) - ksearch.append("{0}@protonmail.ch".format(keyterm)) - ksearch.append("{0}@pm.me".format(keyterm)) - elif keyterm.count("@") == 2 and keyterm.startswith("@") is False: - uidlist = keyterm.split("@") - for uid in uidlist: - ksearch.append("{0}@protonmail.com".format(uid)) - ksearch.append("{0}@protonmail.ch".format(uid)) - ksearch.append("{0}@pm.me".format(uid)) - elif keyterm.count("@") > 2: - uidlist = keyterm.split("@") - for uid in uidlist: - ksearch.append("{0}@protonmail.com".format(uid)) - ksearch.append("{0}@protonmail.ch".format(uid)) - ksearch.append("{0}@pm.me".format(uid)) - else: - ksearch.append(keyterm) - -for k in ksearch: - print("Checking for key for: {0}".format(k)) - try: - keys = server.search(k) - if isinstance(keys, list) is True: - for key in keys: - allkeys.append(key) - try: - import_result = c.key_import(key.key_blob) - except Exception as e: - import_result = c.key_import(key.key) - else: - paradox.append(keys) - import_result = None - except Exception as e: - import_result = None - results.append(import_result) - -for result in results: - if result is not None and hasattr(result, "considered") is False: - print("{0} for {1}".format(result.decode(), k)) - elif result is not None and hasattr(result, "considered") is True: - num_keys = len(result.imports) - new_revs = result.new_revocations - new_sigs = result.new_signatures - new_subs = result.new_sub_keys - new_uids = result.new_user_ids - new_scrt = result.secret_imported - nochange = result.unchanged - print(""" -The total number of keys considered for import was: {0} - -With UIDs wholely or partially matching the following string: - - {1} - - Number of keys revoked: {2} - Number of new signatures: {3} - Number of new subkeys: {4} - Number of new user IDs: {5} -Number of new secret keys: {6} - Number of unchanged keys: {7} - -The key IDs for all considered keys were: -""".format(num_keys, k, new_revs, new_sigs, new_subs, new_uids, new_scrt, - nochange)) - for i in range(num_keys): - print(result.imports[i].fpr) - print("") - elif result is None: - pass -#+END_SRC - - -**** Import from ProtonMail via HKP for Python Example no. 2 - :PROPERTIES: - :CUSTOM_ID: import-hkp4py-pm2 - :END: - -Like its counterpart above, this script can also be found with the -rest of the examples, by the name pmkey-import-hkp-alt.py. - -With this script a modicum of effort has been made to treat anything -passed as a =homedir= which either does not exist or which is not a -directory, as also being a pssible user ID to check for. It's not -guaranteed to pick up on all such cases, but it should cover most of -them. - -#+BEGIN_SRC python -i -import gpg -import hkp4py -import os.path -import sys - -print(""" -This script searches the ProtonMail key server for the specified key and -imports it. Optionally enables specifying a different GnuPG home directory. - -Usage: pmkey-import-hkp.py [homedir] [search string] - or: pmkey-import-hkp.py [search string] -""") - -c = gpg.Context(armor=True) -server = hkp4py.KeyServer("hkps://api.protonmail.ch") -keyterms = [] -ksearch = [] -allkeys = [] -results = [] -paradox = [] -homeless = None - -if len(sys.argv) > 3: - homedir = sys.argv[1] - keyterms = sys.argv[2:] -elif len(sys.argv) == 3: - homedir = sys.argv[1] - keyterm = sys.argv[2] - keyterms.append(keyterm) -elif len(sys.argv) == 2: - homedir = "" - keyterm = sys.argv[1] - keyterms.append(keyterm) -else: - keyterm = input("Enter the key ID, UID or search string: ") - homedir = input("Enter the GPG configuration directory path (optional): ") - keyterms.append(keyterm) - -if len(homedir) == 0: - homedir = None - homeless = False - -if homedir is not None: - if homedir.startswith("~"): - if os.path.exists(os.path.expanduser(homedir)) is True: - if os.path.isdir(os.path.expanduser(homedir)) is True: - c.home_dir = os.path.realpath(os.path.expanduser(homedir)) - else: - homeless = True - else: - homeless = True - elif os.path.exists(os.path.realpath(homedir)) is True: - if os.path.isdir(os.path.realpath(homedir)) is True: - c.home_dir = os.path.realpath(homedir) - else: - homeless = True - else: - homeless = True - -# First check to see if the homedir really is a homedir and if not, treat it as -# a search string. -if homeless is True: - keyterms.append(homedir) - c.home_dir = None -else: - pass - -for keyterm in keyterms: - if keyterm.count("@") == 2 and keyterm.startswith("@") is True: - ksearch.append(keyterm[1:]) - ksearch.append(keyterm[1:]) - ksearch.append(keyterm[1:]) - elif keyterm.count("@") == 1 and keyterm.startswith("@") is True: - ksearch.append("{0}@protonmail.com".format(keyterm[1:])) - ksearch.append("{0}@protonmail.ch".format(keyterm[1:])) - ksearch.append("{0}@pm.me".format(keyterm[1:])) - elif keyterm.count("@") == 0: - ksearch.append("{0}@protonmail.com".format(keyterm)) - ksearch.append("{0}@protonmail.ch".format(keyterm)) - ksearch.append("{0}@pm.me".format(keyterm)) - elif keyterm.count("@") == 2 and keyterm.startswith("@") is False: - uidlist = keyterm.split("@") - for uid in uidlist: - ksearch.append("{0}@protonmail.com".format(uid)) - ksearch.append("{0}@protonmail.ch".format(uid)) - ksearch.append("{0}@pm.me".format(uid)) - elif keyterm.count("@") > 2: - uidlist = keyterm.split("@") - for uid in uidlist: - ksearch.append("{0}@protonmail.com".format(uid)) - ksearch.append("{0}@protonmail.ch".format(uid)) - ksearch.append("{0}@pm.me".format(uid)) - else: - ksearch.append(keyterm) - -for k in ksearch: - print("Checking for key for: {0}".format(k)) - try: - keys = server.search(k) - if isinstance(keys, list) is True: - for key in keys: - allkeys.append(key) - try: - import_result = c.key_import(key.key_blob) - except Exception as e: - import_result = c.key_import(key.key) - else: - paradox.append(keys) - import_result = None - except Exception as e: - import_result = None - results.append(import_result) - -for result in results: - if result is not None and hasattr(result, "considered") is False: - print("{0} for {1}".format(result.decode(), k)) - elif result is not None and hasattr(result, "considered") is True: - num_keys = len(result.imports) - new_revs = result.new_revocations - new_sigs = result.new_signatures - new_subs = result.new_sub_keys - new_uids = result.new_user_ids - new_scrt = result.secret_imported - nochange = result.unchanged - print(""" -The total number of keys considered for import was: {0} - -With UIDs wholely or partially matching the following string: - - {1} - - Number of keys revoked: {2} - Number of new signatures: {3} - Number of new subkeys: {4} - Number of new user IDs: {5} -Number of new secret keys: {6} - Number of unchanged keys: {7} - -The key IDs for all considered keys were: -""".format(num_keys, k, new_revs, new_sigs, new_subs, new_uids, new_scrt, - nochange)) - for i in range(num_keys): - print(result.imports[i].fpr) - print("") - elif result is None: - pass -#+END_SRC - - -** Exporting keys - :PROPERTIES: - :CUSTOM_ID: howto-export-key - :END: - -Exporting keys remains a reasonably simple task, but has been -separated into three different functions for the OpenPGP cryptographic -engine. Two of those functions are for exporting public keys and the -third is for exporting secret keys. - - -*** Exporting public keys - :PROPERTIES: - :CUSTOM_ID: howto-export-public-key - :END: - -There are two methods of exporting public keys, both of which are very -similar to the other. The default method, =key_export()=, will export -a public key or keys matching a specified pattern as normal. The -alternative, the =key_export_minimal()= method, will do the same thing -except producing a minimised output with extra signatures and third -party signatures or certifications removed. - -#+BEGIN_SRC python -i -import gpg -import os.path -import sys - -print(""" -This script exports one or more public keys. -""") - -c = gpg.Context(armor=True) - -if len(sys.argv) >= 4: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = sys.argv[3] -elif len(sys.argv) == 3: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = input("Enter the GPG configuration directory path (optional): ") -elif len(sys.argv) == 2: - keyfile = sys.argv[1] - logrus = input("Enter the UID matching the key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") -else: - keyfile = input("Enter the path and filename to save the secret key to: ") - logrus = input("Enter the UID matching the key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") - -if homedir.startswith("~"): - if os.path.exists(os.path.expanduser(homedir)) is True: - c.home_dir = os.path.expanduser(homedir) - else: - pass -elif os.path.exists(homedir) is True: - c.home_dir = homedir -else: - pass - -try: - result = c.key_export(pattern=logrus) -except: - result = c.key_export(pattern=None) - -if result is not None: - with open(keyfile, "wb") as f: - f.write(result) -else: - pass -#+END_SRC - -It should be noted that the result will only return =None= when a -search pattern has been entered, but has not matched any keys. When -the search pattern itself is set to =None= this triggers the exporting -of the entire public keybox. - -#+BEGIN_SRC python -i -import gpg -import os.path -import sys - -print(""" -This script exports one or more public keys in minimised form. -""") - -c = gpg.Context(armor=True) - -if len(sys.argv) >= 4: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = sys.argv[3] -elif len(sys.argv) == 3: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = input("Enter the GPG configuration directory path (optional): ") -elif len(sys.argv) == 2: - keyfile = sys.argv[1] - logrus = input("Enter the UID matching the key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") -else: - keyfile = input("Enter the path and filename to save the secret key to: ") - logrus = input("Enter the UID matching the key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") - -if homedir.startswith("~"): - if os.path.exists(os.path.expanduser(homedir)) is True: - c.home_dir = os.path.expanduser(homedir) - else: - pass -elif os.path.exists(homedir) is True: - c.home_dir = homedir -else: - pass - -try: - result = c.key_export_minimal(pattern=logrus) -except: - result = c.key_export_minimal(pattern=None) - -if result is not None: - with open(keyfile, "wb") as f: - f.write(result) -else: - pass -#+END_SRC - - -*** Exporting secret keys - :PROPERTIES: - :CUSTOM_ID: howto-export-secret-key - :END: - -Exporting secret keys is, functionally, very similar to exporting -public keys; save for the invocation of =pinentry= via =gpg-agent= in -order to securely enter the key's passphrase and authorise the export. - -The following example exports the secret key to a file which is then -set with the same permissions as the output files created by the -command line secret key export options. - -#+BEGIN_SRC python -i -import gpg -import os -import os.path -import sys - -print(""" -This script exports one or more secret keys. - -The gpg-agent and pinentry are invoked to authorise the export. -""") - -c = gpg.Context(armor=True) - -if len(sys.argv) >= 4: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = sys.argv[3] -elif len(sys.argv) == 3: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = input("Enter the GPG configuration directory path (optional): ") -elif len(sys.argv) == 2: - keyfile = sys.argv[1] - logrus = input("Enter the UID matching the secret key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") -else: - keyfile = input("Enter the path and filename to save the secret key to: ") - logrus = input("Enter the UID matching the secret key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") - -if len(homedir) == 0: - homedir = None -elif homedir.startswith("~"): - userdir = os.path.expanduser(homedir) - if os.path.exists(userdir) is True: - homedir = os.path.realpath(userdir) - else: - homedir = None -else: - homedir = os.path.realpath(homedir) - -if os.path.exists(homedir) is False: - homedir = None -else: - if os.path.isdir(homedir) is False: - homedir = None - else: - pass - -if homedir is not None: - c.home_dir = homedir -else: - pass - -try: - result = c.key_export_secret(pattern=logrus) -except: - result = c.key_export_secret(pattern=None) - -if result is not None: - with open(keyfile, "wb") as f: - f.write(result) - os.chmod(keyfile, 0o600) -else: - pass -#+END_SRC - -Alternatively the approach of the following script can be used. This -longer example saves the exported secret key(s) in files in the GnuPG -home directory, in addition to setting the file permissions as only -readable and writable by the user. It also exports the secret key(s) -twice in order to output both GPG binary (=.gpg=) and ASCII armoured -(=.asc=) files. - -#+BEGIN_SRC python -i -import gpg -import os -import os.path -import subprocess -import sys - -print(""" -This script exports one or more secret keys as both ASCII armored and binary -file formats, saved in files within the user's GPG home directory. - -The gpg-agent and pinentry are invoked to authorise the export. -""") - -if sys.platform == "win32": - gpgconfcmd = "gpgconf.exe --list-dirs homedir" -else: - gpgconfcmd = "gpgconf --list-dirs homedir" - -a = gpg.Context(armor=True) -b = gpg.Context() -c = gpg.Context() - -if len(sys.argv) >= 4: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = sys.argv[3] -elif len(sys.argv) == 3: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = input("Enter the GPG configuration directory path (optional): ") -elif len(sys.argv) == 2: - keyfile = sys.argv[1] - logrus = input("Enter the UID matching the secret key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") -else: - keyfile = input("Enter the filename to save the secret key to: ") - logrus = input("Enter the UID matching the secret key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") - -if len(homedir) == 0: - homedir = None -elif homedir.startswith("~"): - userdir = os.path.expanduser(homedir) - if os.path.exists(userdir) is True: - homedir = os.path.realpath(userdir) - else: - homedir = None -else: - homedir = os.path.realpath(homedir) - -if os.path.exists(homedir) is False: - homedir = None -else: - if os.path.isdir(homedir) is False: - homedir = None - else: - pass - -if homedir is not None: - c.home_dir = homedir -else: - pass - -if c.home_dir is not None: - if c.home_dir.endswith("/"): - gpgfile = "{0}{1}.gpg".format(c.home_dir, keyfile) - ascfile = "{0}{1}.asc".format(c.home_dir, keyfile) - else: - gpgfile = "{0}/{1}.gpg".format(c.home_dir, keyfile) - ascfile = "{0}/{1}.asc".format(c.home_dir, keyfile) -else: - if os.path.exists(os.environ["GNUPGHOME"]) is True: - hd = os.environ["GNUPGHOME"] - else: - try: - hd = subprocess.getoutput(gpgconfcmd) - except: - process = subprocess.Popen(gpgconfcmd.split(), - stdout=subprocess.PIPE) - procom = process.communicate() - if sys.version_info[0] == 2: - hd = procom[0].strip() - else: - hd = procom[0].decode().strip() - gpgfile = "{0}/{1}.gpg".format(hd, keyfile) - ascfile = "{0}/{1}.asc".format(hd, keyfile) - -try: - a_result = a.key_export_secret(pattern=logrus) - b_result = b.key_export_secret(pattern=logrus) -except: - a_result = a.key_export_secret(pattern=None) - b_result = b.key_export_secret(pattern=None) - -if a_result is not None: - with open(ascfile, "wb") as f: - f.write(a_result) - os.chmod(ascfile, 0o600) -else: - pass - -if b_result is not None: - with open(gpgfile, "wb") as f: - f.write(b_result) - os.chmod(gpgfile, 0o600) -else: - pass -#+END_SRC - - -*** Sending public keys to the SKS Keyservers - :PROPERTIES: - :CUSTOM_ID: howto-send-public-key - :END: - -As with the previous section on importing keys, the =hkp4py= module -adds another option with exporting keys in order to send them to the -public keyservers. - -The following example demonstrates how this may be done. - -#+BEGIN_SRC python -i -import gpg -import hkp4py -import os.path -import sys - -print(""" -This script sends one or more public keys to the SKS keyservers and is -essentially a slight variation on the export-key.py script. -""") - -c = gpg.Context(armor=True) -server = hkp4py.KeyServer("hkps://hkps.pool.sks-keyservers.net") - -if len(sys.argv) > 2: - logrus = " ".join(sys.argv[1:]) -elif len(sys.argv) == 2: - logrus = sys.argv[1] -else: - logrus = input("Enter the UID matching the key(s) to send: ") - -if len(logrus) > 0: - try: - export_result = c.key_export(pattern=logrus) - except Exception as e: - print(e) - export_result = None -else: - export_result = c.key_export(pattern=None) - -if export_result is not None: - try: - try: - send_result = server.add(export_result) - except: - send_result = server.add(export_result.decode()) - if send_result is not None: - print(send_result) - else: - pass - except Exception as e: - print(e) -else: - pass -#+END_SRC - -An expanded version of this script with additional functions for -specifying an alternative homedir location is in the examples -directory as =send-key-to-keyserver.py=. - -The =hkp4py= module appears to handle both string and byte literal text -data equally well, but the GPGME bindings deal primarily with byte -literal data only and so this script sends in that format first, then -tries the string literal form. - - -* Basic Functions - :PROPERTIES: - :CUSTOM_ID: howto-the-basics - :END: - -The most frequently called features of any cryptographic library will -be the most fundamental tasks for encryption software. In this -section we will look at how to programmatically encrypt data, decrypt -it, sign it and verify signatures. - - -** Encryption - :PROPERTIES: - :CUSTOM_ID: howto-basic-encryption - :END: - -Encrypting is very straight forward. In the first example below the -message, =text=, is encrypted to a single recipient's key. In the -second example the message will be encrypted to multiple recipients. - - -*** Encrypting to one key - :PROPERTIES: - :CUSTOM_ID: howto-basic-encryption-single - :END: - -Once the the Context is set the main issues with encrypting data is -essentially reduced to key selection and the keyword arguments -specified in the =gpg.Context().encrypt()= method. - -Those keyword arguments are: =recipients=, a list of keys encrypted to -(covered in greater detail in the following section); =sign=, whether -or not to sign the plaintext data, see subsequent sections on signing -and verifying signatures below (defaults to =True=); =sink=, to write -results or partial results to a secure sink instead of returning it -(defaults to =None=); =passphrase=, only used when utilising symmetric -encryption (defaults to =None=); =always_trust=, used to override the -trust model settings for recipient keys (defaults to =False=); -=add_encrypt_to=, utilises any preconfigured =encrypt-to= or -=default-key= settings in the user's =gpg.conf= file (defaults to -=False=); =prepare=, prepare for encryption (defaults to =False=); -=expect_sign=, prepare for signing (defaults to =False=); =compress=, -compresses the plaintext prior to encryption (defaults to =True=). - -#+BEGIN_SRC python -i -import gpg - -a_key = "0x12345678DEADBEEF" -text = b"""Some text to test with. - -Since the text in this case must be bytes, it is most likely that -the input form will be a separate file which is opened with "rb" -as this is the simplest method of obtaining the correct data format. -""" - -c = gpg.Context(armor=True) -rkey = list(c.keylist(pattern=a_key, secret=False)) -ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=False) - -with open("secret_plans.txt.asc", "wb") as afile: - afile.write(ciphertext) -#+END_SRC - -Though this is even more likely to be used like this; with the -plaintext input read from a file, the recipient keys used for -encryption regardless of key trust status and the encrypted output -also encrypted to any preconfigured keys set in the =gpg.conf= file: - -#+BEGIN_SRC python -i -import gpg - -a_key = "0x12345678DEADBEEF" - -with open("secret_plans.txt", "rb") as afile: - text = afile.read() - -c = gpg.Context(armor=True) -rkey = list(c.keylist(pattern=a_key, secret=False)) -ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=True, - always_trust=True, - add_encrypt_to=True) - -with open("secret_plans.txt.asc", "wb") as afile: - afile.write(ciphertext) -#+END_SRC - -If the =recipients= paramater is empty then the plaintext is encrypted -symmetrically. If no =passphrase= is supplied as a parameter or via a -callback registered with the =Context()= then an out-of-band prompt -for the passphrase via pinentry will be invoked. - - -*** Encrypting to multiple keys - :PROPERTIES: - :CUSTOM_ID: howto-basic-encryption-multiple - :END: - -Encrypting to multiple keys essentially just expands upon the key -selection process and the recipients from the previous examples. - -The following example encrypts a message (=text=) to everyone with an -email address on the =gnupg.org= domain,[fn:5] but does /not/ encrypt -to a default key or other key which is configured to normally encrypt -to. - -#+BEGIN_SRC python -i -import gpg - -text = b"""Oh look, another test message. - -The same rules apply as with the previous example and more likely -than not, the message will actually be drawn from reading the -contents of a file or, maybe, from entering data at an input() -prompt. - -Since the text in this case must be bytes, it is most likely that -the input form will be a separate file which is opened with "rb" -as this is the simplest method of obtaining the correct data -format. -""" - -c = gpg.Context(armor=True) -rpattern = list(c.keylist(pattern="@gnupg.org", secret=False)) -logrus = [] - -for i in range(len(rpattern)): - if rpattern[i].can_encrypt == 1: - logrus.append(rpattern[i]) - -ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, - sign=False, always_trust=True) - -with open("secret_plans.txt.asc", "wb") as afile: - afile.write(ciphertext) -#+END_SRC - -All it would take to change the above example to sign the message -and also encrypt the message to any configured default keys would -be to change the =c.encrypt= line to this: - -#+BEGIN_SRC python -i -ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, - always_trust=True, - add_encrypt_to=True) -#+END_SRC - -The only keyword arguments requiring modification are those for which -the default values are changing. The default value of =sign= is -=True=, the default of =always_trust= is =False=, the default of -=add_encrypt_to= is =False=. - -If =always_trust= is not set to =True= and any of the recipient keys -are not trusted (e.g. not signed or locally signed) then the -encryption will raise an error. It is possible to mitigate this -somewhat with something more like this: - -#+BEGIN_SRC python -i -import gpg - -with open("secret_plans.txt.asc", "rb") as afile: - text = afile.read() - -c = gpg.Context(armor=True) -rpattern = list(c.keylist(pattern="@gnupg.org", secret=False)) -logrus = [] - -for i in range(len(rpattern)): - if rpattern[i].can_encrypt == 1: - logrus.append(rpattern[i]) - - try: - ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, - add_encrypt_to=True) - except gpg.errors.InvalidRecipients as e: - for i in range(len(e.recipients)): - for n in range(len(logrus)): - if logrus[n].fpr == e.recipients[i].fpr: - logrus.remove(logrus[n]) - else: - pass - try: - ciphertext, result, sign_result = c.encrypt(text, - recipients=logrus, - add_encrypt_to=True) - with open("secret_plans.txt.asc", "wb") as afile: - afile.write(ciphertext) - except: - pass -#+END_SRC - -This will attempt to encrypt to all the keys searched for, then remove -invalid recipients if it fails and try again. - - -** Decryption - :PROPERTIES: - :CUSTOM_ID: howto-basic-decryption - :END: - -Decrypting something encrypted to a key in one's secret keyring is -fairly straight forward. - -In this example code, however, preconfiguring either =gpg.Context()= -or =gpg.core.Context()= as =c= is unnecessary because there is no need -to modify the Context prior to conducting the decryption and since the -Context is only used once, setting it to =c= simply adds lines for no -gain. - -#+BEGIN_SRC python -i -import gpg - -ciphertext = input("Enter path and filename of encrypted file: ") -newfile = input("Enter path and filename of file to save decrypted data to: ") - -with open(ciphertext, "rb") as cfile: - try: - plaintext, result, verify_result = gpg.Context().decrypt(cfile) - except gpg.errors.GPGMEError as e: - plaintext = None - print(e) - -if plaintext is not None: - with open(newfile, "wb") as nfile: - nfile.write(plaintext) - else: - pass -#+END_SRC - -The data available in =plaintext= in this example is the decrypted -content as a byte object, the recipient key IDs and algorithms in -=result= and the results of verifying any signatures of the data in -=verify_result=. - - -** Signing text and files - :PROPERTIES: - :CUSTOM_ID: howto-basic-signing - :END: - -The following sections demonstrate how to specify keys to sign with. - - -*** Signing key selection - :PROPERTIES: - :CUSTOM_ID: howto-basic-signing-signers - :END: - -By default GPGME and the Python bindings will use the default key -configured for the user invoking the GPGME API. If there is no -default key specified and there is more than one secret key available -it may be necessary to specify the key or keys with which to sign -messages and files. - -#+BEGIN_SRC python -i -import gpg - -logrus = input("Enter the email address or string to match signing keys to: ") -hancock = gpg.Context().keylist(pattern=logrus, secret=True) -sig_src = list(hancock) -#+END_SRC - -The signing examples in the following sections include the explicitly -designated =signers= parameter in two of the five examples; once where -the resulting signature would be ASCII armoured and once where it -would not be armoured. - -While it would be possible to enter a key ID or fingerprint here to -match a specific key, it is not possible to enter two fingerprints and -match two keys since the patten expects a string, bytes or None and -not a list. A string with two fingerprints won't match any single -key. - - -*** Normal or default signing messages or files - :PROPERTIES: - :CUSTOM_ID: howto-basic-signing-normal - :END: - -The normal or default signing process is essentially the same as is -most often invoked when also encrypting a message or file. So when -the encryption component is not utilised, the result is to produce an -encoded and signed output which may or may not be ASCII armoured and -which may or may not also be compressed. - -By default compression will be used unless GnuPG detects that the -plaintext is already compressed. ASCII armouring will be determined -according to the value of =gpg.Context().armor=. - -The compression algorithm is selected in much the same way as the -symmetric encryption algorithm or the hash digest algorithm is when -multiple keys are involved; from the preferences saved into the key -itself or by comparison with the preferences with all other keys -involved. - -#+BEGIN_SRC python -i -import gpg - -text0 = """Declaration of ... something. - -""" -text = text0.encode() - -c = gpg.Context(armor=True, signers=sig_src) -signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) - -with open("/path/to/statement.txt.asc", "w") as afile: - afile.write(signed_data.decode()) -#+END_SRC - -Though everything in this example is accurate, it is more likely that -reading the input data from another file and writing the result to a -new file will be performed more like the way it is done in the next -example. Even if the output format is ASCII armoured. - -#+BEGIN_SRC python -i -import gpg - -with open("/path/to/statement.txt", "rb") as tfile: - text = tfile.read() - -c = gpg.Context() -signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) - -with open("/path/to/statement.txt.sig", "wb") as afile: - afile.write(signed_data) -#+END_SRC - - -*** Detached signing messages and files - :PROPERTIES: - :CUSTOM_ID: howto-basic-signing-detached - :END: - -Detached signatures will often be needed in programmatic uses of -GPGME, either for signing files (e.g. tarballs of code releases) or as -a component of message signing (e.g. PGP/MIME encoded email). - -#+BEGIN_SRC python -i -import gpg - -text0 = """Declaration of ... something. - -""" -text = text0.encode() - -c = gpg.Context(armor=True) -signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) - -with open("/path/to/statement.txt.asc", "w") as afile: - afile.write(signed_data.decode()) -#+END_SRC - -As with normal signatures, detached signatures are best handled as -byte literals, even when the output is ASCII armoured. - -#+BEGIN_SRC python -i -import gpg - -with open("/path/to/statement.txt", "rb") as tfile: - text = tfile.read() - -c = gpg.Context(signers=sig_src) -signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) - -with open("/path/to/statement.txt.sig", "wb") as afile: - afile.write(signed_data) -#+END_SRC - - -*** Clearsigning messages or text - :PROPERTIES: - :CUSTOM_ID: howto-basic-signing-clear - :END: - -Though PGP/in-line messages are no longer encouraged in favour of -PGP/MIME, there is still sometimes value in utilising in-line -signatures. This is where clear-signed messages or text is of value. - -#+BEGIN_SRC python -i -import gpg - -text0 = """Declaration of ... something. - -""" -text = text0.encode() - -c = gpg.Context() -signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) - -with open("/path/to/statement.txt.asc", "w") as afile: - afile.write(signed_data.decode()) -#+END_SRC - -In spite of the appearance of a clear-signed message, the data handled -by GPGME in signing it must still be byte literals. - -#+BEGIN_SRC python -i -import gpg - -with open("/path/to/statement.txt", "rb") as tfile: - text = tfile.read() - -c = gpg.Context() -signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) - -with open("/path/to/statement.txt.asc", "wb") as afile: - afile.write(signed_data) -#+END_SRC - - -** Signature verification - :PROPERTIES: - :CUSTOM_ID: howto-basic-verification - :END: - -Essentially there are two principal methods of verification of a -signature. The first of these is for use with the normal or default -signing method and for clear-signed messages. The second is for use -with files and data with detached signatures. - -The following example is intended for use with the default signing -method where the file was not ASCII armoured: - -#+BEGIN_SRC python -i -import gpg -import time - -filename = "statement.txt" -gpg_file = "statement.txt.gpg" - -c = gpg.Context() - -try: - data, result = c.verify(open(gpg_file)) - verified = True -except gpg.errors.BadSignatures as e: - verified = False - print(e) - -if verified is True: - for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: -{0} -with key {1} -made at {2} -""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) -else: - pass -#+END_SRC - -Whereas this next example, which is almost identical would work with -normal ASCII armoured files and with clear-signed files: - -#+BEGIN_SRC python -i -import gpg -import time - -filename = "statement.txt" -asc_file = "statement.txt.asc" - -c = gpg.Context() - -try: - data, result = c.verify(open(asc_file)) - verified = True -except gpg.errors.BadSignatures as e: - verified = False - print(e) - -if verified is True: - for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: -{0} -with key {1} -made at {2} -""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) -else: - pass -#+END_SRC - -In both of the previous examples it is also possible to compare the -original data that was signed against the signed data in =data= to see -if it matches with something like this: - -#+BEGIN_SRC python -i -with open(filename, "rb") as afile: - text = afile.read() - -if text == data: - print("Good signature.") -else: - pass -#+END_SRC - -The following two examples, however, deal with detached signatures. -With his method of verification the data that was signed does not get -returned since it is already being explicitly referenced in the first -argument of =c.verify=. So =data= is =None= and only the information -in =result= is available. - -#+BEGIN_SRC python -i -import gpg -import time - -filename = "statement.txt" -sig_file = "statement.txt.sig" - -c = gpg.Context() - -try: - data, result = c.verify(open(filename), open(sig_file)) - verified = True -except gpg.errors.BadSignatures as e: - verified = False - print(e) - -if verified is True: - for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: -{0} -with key {1} -made at {2} -""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) -else: - pass -#+END_SRC - -#+BEGIN_SRC python -i -import gpg -import time - -filename = "statement.txt" -asc_file = "statement.txt.asc" - -c = gpg.Context() - -try: - data, result = c.verify(open(filename), open(asc_file)) - verified = True -except gpg.errors.BadSignatures as e: - verified = False - print(e) - -if verified is True: - for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: -{0} -with key {1} -made at {2} -""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) -else: - pass -#+END_SRC - - -* Creating keys and subkeys - :PROPERTIES: - :CUSTOM_ID: key-generation - :END: - -The one thing, aside from GnuPG itself, that GPGME depends on, of -course, is the keys themselves. So it is necessary to be able to -generate them and modify them by adding subkeys, revoking or disabling -them, sometimes deleting them and doing the same for user IDs. - -In the following examples a key will be created for the world's -greatest secret agent, Danger Mouse. Since Danger Mouse is a secret -agent he needs to be able to protect information to =SECRET= level -clearance, so his keys will be 3072-bit keys. - -The pre-configured =gpg.conf= file which sets cipher, digest and other -preferences contains the following configuration parameters: - -#+BEGIN_SRC conf - expert - allow-freeform-uid - allow-secret-key-import - trust-model tofu+pgp - tofu-default-policy unknown - enable-large-rsa - enable-dsa2 - cert-digest-algo SHA512 - default-preference-list TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1 ZLIB BZIP2 ZIP Uncompressed - personal-cipher-preferences TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES - personal-digest-preferences SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1 - personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed -#+END_SRC - - -** Primary key - :PROPERTIES: - :CUSTOM_ID: keygen-primary - :END: - -Generating a primary key uses the =create_key= method in a Context. -It contains multiple arguments and keyword arguments, including: -=userid=, =algorithm=, =expires_in=, =expires=, =sign=, =encrypt=, -=certify=, =authenticate=, =passphrase= and =force=. The defaults for -all of those except =userid=, =algorithm=, =expires_in=, =expires= and -=passphrase= is =False=. The defaults for =algorithm= and -=passphrase= is =None=. The default for =expires_in= is =0=. The -default for =expires= is =True=. There is no default for =userid=. - -If =passphrase= is left as =None= then the key will not be generated -with a passphrase, if =passphrase= is set to a string then that will -be the passphrase and if =passphrase= is set to =True= then gpg-agent -will launch pinentry to prompt for a passphrase. For the sake of -convenience, these examples will keep =passphrase= set to =None=. - -#+BEGIN_SRC python -i -import gpg - -c = gpg.Context() - -c.home_dir = "~/.gnupg-dm" -userid = "Danger Mouse " - -dmkey = c.create_key(userid, algorithm="rsa3072", expires_in=31536000, - sign=True, certify=True) -#+END_SRC - -One thing to note here is the use of setting the =c.home_dir= -parameter. This enables generating the key or keys in a different -location. In this case to keep the new key data created for this -example in a separate location rather than adding it to existing and -active key store data. As with the default directory, =~/.gnupg=, any -temporary or separate directory needs the permissions set to only -permit access by the directory owner. On posix systems this means -setting the directory permissions to 700. - -The =temp-homedir-config.py= script in the HOWTO examples directory -will create an alternative homedir with these configuration options -already set and the correct directory and file permissions. - -The successful generation of the key can be confirmed via the returned -=GenkeyResult= object, which includes the following data: - -#+BEGIN_SRC python -i -print(""" - Fingerprint: {0} - Primary Key: {1} - Public Key: {2} - Secret Key: {3} - Sub Key: {4} -User IDs: {5} -""".format(dmkey.fpr, dmkey.primary, dmkey.pubkey, dmkey.seckey, dmkey.sub, - dmkey.uid)) -#+END_SRC - -Alternatively the information can be confirmed using the command line -program: - -#+BEGIN_SRC shell - bash-4.4$ gpg --homedir ~/.gnupg-dm -K - ~/.gnupg-dm/pubring.kbx - ---------------------- - sec rsa3072 2018-03-15 [SC] [expires: 2019-03-15] - 177B7C25DB99745EE2EE13ED026D2F19E99E63AA - uid [ultimate] Danger Mouse - - bash-4.4$ -#+END_SRC - -As with generating keys manually, to preconfigure expanded preferences -for the cipher, digest and compression algorithms, the =gpg.conf= file -must contain those details in the home directory in which the new key -is being generated. I used a cut down version of my own =gpg.conf= -file in order to be able to generate this: - -#+BEGIN_SRC shell - bash-4.4$ gpg --homedir ~/.gnupg-dm --edit-key 177B7C25DB99745EE2EE13ED026D2F19E99E63AA showpref quit - Secret key is available. - - sec rsa3072/026D2F19E99E63AA - created: 2018-03-15 expires: 2019-03-15 usage: SC - trust: ultimate validity: ultimate - [ultimate] (1). Danger Mouse - - [ultimate] (1). Danger Mouse - Cipher: TWOFISH, CAMELLIA256, AES256, CAMELLIA192, AES192, CAMELLIA128, AES, BLOWFISH, IDEA, CAST5, 3DES - Digest: SHA512, SHA384, SHA256, SHA224, RIPEMD160, SHA1 - Compression: ZLIB, BZIP2, ZIP, Uncompressed - Features: MDC, Keyserver no-modify - - bash-4.4$ -#+END_SRC - - -** Subkeys - :PROPERTIES: - :CUSTOM_ID: keygen-subkeys - :END: - -Adding subkeys to a primary key is fairly similar to creating the -primary key with the =create_subkey= method. Most of the arguments -are the same, but not quite all. Instead of the =userid= argument -there is now a =key= argument for selecting which primary key to add -the subkey to. - -In the following example an encryption subkey will be added to the -primary key. Since Danger Mouse is a security conscious secret agent, -this subkey will only be valid for about six months, half the length -of the primary key. - -#+BEGIN_SRC python -i -import gpg - -c = gpg.Context() -c.home_dir = "~/.gnupg-dm" - -key = c.get_key(dmkey.fpr, secret=True) -dmsub = c.create_subkey(key, algorithm="rsa3072", expires_in=15768000, - encrypt=True) -#+END_SRC - -As with the primary key, the results here can be checked with: - -#+BEGIN_SRC python -i -print(""" - Fingerprint: {0} - Primary Key: {1} - Public Key: {2} - Secret Key: {3} - Sub Key: {4} -User IDs: {5} -""".format(dmsub.fpr, dmsub.primary, dmsub.pubkey, dmsub.seckey, dmsub.sub, - dmsub.uid)) -#+END_SRC - -As well as on the command line with: - -#+BEGIN_SRC shell - bash-4.4$ gpg --homedir ~/.gnupg-dm -K - ~/.gnupg-dm/pubring.kbx - ---------------------- - sec rsa3072 2018-03-15 [SC] [expires: 2019-03-15] - 177B7C25DB99745EE2EE13ED026D2F19E99E63AA - uid [ultimate] Danger Mouse - ssb rsa3072 2018-03-15 [E] [expires: 2018-09-13] - - bash-4.4$ -#+END_SRC - - -** User IDs - :PROPERTIES: - :CUSTOM_ID: keygen-uids - :END: - - -*** Adding User IDs - :PROPERTIES: - :CUSTOM_ID: keygen-uids-add - :END: - -By comparison to creating primary keys and subkeys, adding a new user -ID to an existing key is much simpler. The method used to do this is -=key_add_uid= and the only arguments it takes are for the =key= and -the new =uid=. - -#+BEGIN_SRC python -i -import gpg - -c = gpg.Context() -c.home_dir = "~/.gnupg-dm" - -dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" -key = c.get_key(dmfpr, secret=True) -uid = "Danger Mouse " - -c.key_add_uid(key, uid) -#+END_SRC - -Unsurprisingly the result of this is: - -#+BEGIN_SRC shell - bash-4.4$ gpg --homedir ~/.gnupg-dm -K - ~/.gnupg-dm/pubring.kbx - ---------------------- - sec rsa3072 2018-03-15 [SC] [expires: 2019-03-15] - 177B7C25DB99745EE2EE13ED026D2F19E99E63AA - uid [ultimate] Danger Mouse - uid [ultimate] Danger Mouse - ssb rsa3072 2018-03-15 [E] [expires: 2018-09-13] - - bash-4.4$ -#+END_SRC - - -*** Revokinging User IDs - :PROPERTIES: - :CUSTOM_ID: keygen-uids-revoke - :END: - -Revoking a user ID is a fairly similar process, except that it uses -the =key_revoke_uid= method. - -#+BEGIN_SRC python -i -import gpg - -c = gpg.Context() -c.home_dir = "~/.gnupg-dm" - -dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" -key = c.get_key(dmfpr, secret=True) -uid = "Danger Mouse " - -c.key_revoke_uid(key, uid) -#+END_SRC - - -** Key certification - :PROPERTIES: - :CUSTOM_ID: key-sign - :END: - -Since key certification is more frequently referred to as key signing, -the method used to perform this function is =key_sign=. - -The =key_sign= method takes four arguments: =key=, =uids=, -=expires_in= and =local=. The default value of =uids= is =None= and -which results in all user IDs being selected. The default value of -both =expires_in= and =local= is =False=; which results in the -signature never expiring and being able to be exported. - -The =key= is the key being signed rather than the key doing the -signing. To change the key doing the signing refer to the signing key -selection above for signing messages and files. - -If the =uids= value is not =None= then it must either be a string to -match a single user ID or a list of strings to match multiple user -IDs. In this case the matching of those strings must be precise and -it is case sensitive. - -To sign Danger Mouse's key for just the initial user ID with a -signature which will last a little over a month, do this: - -#+BEGIN_SRC python -i -import gpg - -c = gpg.Context() -uid = "Danger Mouse " - -dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" -key = c.get_key(dmfpr, secret=True) -c.key_sign(key, uids=uid, expires_in=2764800) -#+END_SRC - - -* Advanced or Experimental Use Cases - :PROPERTIES: - :CUSTOM_ID: advanced-use - :END: - - -** C plus Python plus SWIG plus Cython - :PROPERTIES: - :CUSTOM_ID: cython - :END: - -In spite of the apparent incongruence of using Python bindings to a C -interface only to generate more C from the Python; it is in fact quite -possible to use the GPGME bindings with [[http://docs.cython.org/en/latest/index.html][Cython]]. Though in many cases -the benefits may not be obvious since the most computationally -intensive work never leaves the level of the C code with which GPGME -itself is interacting with. - -Nevertheless, there are some situations where the benefits are -demonstrable. One of the better and easier examples being the one of -the early examples in this HOWTO, the [[#howto-keys-counting][key counting]] code. Running that -example as an executable Python script, =keycount.py= (available in -the =examples/howto/= directory), will take a noticable amount of time -to run on most systems where the public keybox or keyring contains a -few thousand public keys. - -Earlier in the evening, prior to starting this section, I ran that -script on my laptop; as I tend to do periodically and timed it using -=time= utility, with the following results: - -#+BEGIN_SRC shell - bash-4.4$ time keycount.py - - Number of secret keys: 23 - Number of public keys: 12112 - - - real 11m52.945s - user 0m0.913s - sys 0m0.752s - - bash-4.4$ -#+END_SRC - -Sometime after that I imported another key and followed it with a -little test of Cython. This test was kept fairly basic, essentially -lifting the material from the [[http://docs.cython.org/en/latest/src/tutorial/cython_tutorial.html][Cython Basic Tutorial]] to demonstrate -compiling Python code to C. The first step was to take the example -key counting code quoted previously, essentially from the importing of -the =gpg= module to the end of the script: - -#+BEGIN_SRC python -i -import gpg - -c = gpg.Context() -seckeys = c.keylist(pattern=None, secret=True) -pubkeys = c.keylist(pattern=None, secret=False) - -seclist = list(seckeys) -secnum = len(seclist) - -publist = list(pubkeys) -pubnum = len(publist) - -print(""" - Number of secret keys: {0} - Number of public keys: {1} - -""".format(secnum, pubnum)) -#+END_SRC - -Save that into a file called =keycount.pyx= and then create a -=setup.py= file which contains this: - -#+BEGIN_SRC python -i -from distutils.core import setup -from Cython.Build import cythonize - -setup( - ext_modules = cythonize("keycount.pyx") -) -#+END_SRC - -Compile it: - -#+BEGIN_SRC shell - bash-4.4$ python setup.py build_ext --inplace - bash-4.4$ -#+END_SRC - -Then run it in a similar manner to =keycount.py=: - -#+BEGIN_SRC shell - bash-4.4$ time python3.7 -c "import keycount" - - Number of secret keys: 23 - Number of public keys: 12113 - - - real 6m47.905s - user 0m0.785s - sys 0m0.331s - - bash-4.4$ -#+END_SRC - -Cython turned =keycount.pyx= into an 81KB =keycount.o= file in the -=build/= directory, a 24KB =keycount.cpython-37m-darwin.so= file to be -imported into Python 3.7 and a 113KB =keycount.c= generated C source -code file of nearly three thousand lines. Quite a bit bigger than the -314 bytes of the =keycount.pyx= file or the full 1,452 bytes of the -full executable =keycount.py= example script. - -On the other hand it ran in nearly half the time; taking 6 minutes and -47.905 seconds to run. As opposed to the 11 minutes and 52.945 seconds -which the CPython script alone took. - -The =keycount.pyx= and =setup.py= files used to generate this example -have been added to the =examples/howto/advanced/cython/= directory -The example versions include some additional options to annotate the -existing code and to detect Cython's use. The latter comes from the -[[http://docs.cython.org/en/latest/src/tutorial/pure.html#magic-attributes-within-the-pxd][Magic Attributes]] section of the Cython documentation. - - -* Miscellaneous extras and work-arounds - :PROPERTIES: - :CUSTOM_ID: cheats-and-hacks - :END: - -Most of the things in the following sections are here simply because -there was no better place to put them, even though some are only -peripherally related to the GPGME Python bindings. Some are also -workarounds for functions not integrated with GPGME as yet. This is -especially true of the first of these, dealing with [[#group-lines][group lines]]. - - -** Group lines - :PROPERTIES: - :CUSTOM_ID: group-lines - :END: - -There is not yet an easy way to access groups configured in the -gpg.conf file from within GPGME. As a consequence these central -groupings of keys cannot be shared amongst multiple programs, such as -MUAs readily. - -The following code, however, provides a work-around for obtaining this -information in Python. - -#+BEGIN_SRC python -i -import subprocess -import sys - -if sys.platform == "win32": - gpgconfcmd = "gpgconf.exe --list-options gpg" -else: - gpgconfcmd = "gpgconf --list-options gpg" - -try: - lines = subprocess.getoutput(gpgconfcmd).splitlines() -except: - process = subprocess.Popen(gpgconfcmd.split(), stdout=subprocess.PIPE) - procom = process.communicate() - if sys.version_info[0] == 2: - lines = procom[0].splitlines() - else: - lines = procom[0].decode().splitlines() - -for i in range(len(lines)): - if lines[i].startswith("group") is True: - line = lines[i] - else: - pass - -groups = line.split(":")[-1].replace('"', '').split(',') - -group_lines = [] -group_lists = [] - -for i in range(len(groups)): - group_lines.append(groups[i].split("=")) - group_lists.append(groups[i].split("=")) - -for i in range(len(group_lists)): - group_lists[i][1] = group_lists[i][1].split() -#+END_SRC - -The result of that code is that =group_lines= is a list of lists where -=group_lines[i][0]= is the name of the group and =group_lines[i][1]= -is the key IDs of the group as a string. - -The =group_lists= result is very similar in that it is a list of -lists. The first part, =group_lists[i][0]= matches -=group_lines[i][0]= as the name of the group, but =group_lists[i][1]= -is the key IDs of the group as a string. - -A demonstration of using the =groups.py= module is also available in -the form of the executable =mutt-groups.py= script. This second -script reads all the group entries in a user's =gpg.conf= file and -converts them into crypt-hooks suitable for use with the Mutt and -Neomutt mail clients. - - -** Keyserver access for Python - :PROPERTIES: - :CUSTOM_ID: hkp4py - :END: - -The [[https://github.com/Selfnet/hkp4py][hkp4py]] module by Marcel Fest was originally a port of the old -[[https://github.com/dgladkov/python-hkp][python-hkp]] module from Python 2 to Python 3 and updated to use the -[[http://docs.python-requests.org/en/latest/index.html][requests]] module instead. It has since been modified to provide -support for Python 2.7 as well and is available via PyPI. - -Since it rewrites the =hkp= protocol prefix as =http= and =hkps= as -=https=, the module is able to be used even with servers which do not -support the full scope of keyserver functions.[fn:6] It also works quite -readily when incorporated into a [[#cython][Cython]] generated and compiled version -of any code. - - -*** Key import format - :PROPERTIES: - :CUSTOM_ID: hkp4py-strings - :END: - -The hkp4py module returns key data via requests as string literals -(=r.text=) instead of byte literals (=r.content=). This means that -the retrurned key data must be encoded to UTF-8 when importing that -key material using a =gpg.Context().key_import()= method. - -For this reason an alternative method has been added to the =search= -function of =hkp4py.KeyServer()= which returns the key in the correct -format as expected by =key_import=. When importing using this module, -it is now possible to import with this: - -#+BEGIN_SRC python -i -for key in keys: - if key.revoked is False: - gpg.Context().key_import(key.key_blob) - else: - pass -#+END_SRC - -Without that recent addition it would have been necessary to encode -the contents of each =hkp4py.KeyServer().search()[i].key= in -=hkp4py.KeyServer().search()= before trying to import it. - -An example of this is included in the [[#howto-import-key][Importing Keys]] section of this -HOWTO and the corresponding executable version of that example is -available in the =lang/python/examples/howto= directory as normal; the -executable version is the =import-keys-hkp.py= file. - - -* Copyright and Licensing - :PROPERTIES: - :CUSTOM_ID: copyright-and-license - :END: - - -** Copyright - :PROPERTIES: - :CUSTOM_ID: copyright - :END: - -Copyright © The GnuPG Project, 2018. - -Copyright (C) The GnuPG Project, 2018. - - -** Draft Editions of this HOWTO - :PROPERTIES: - :CUSTOM_ID: draft-editions - :END: - -Draft editions of this HOWTO may be periodically available directly -from the author at any of the following URLs: - -- [[https://files.au.adversary.org/crypto/gpgme-python-howto.html][GPGME Python Bindings HOWTO draft (XHTML AWS S3 SSL)]] -- [[http://files.au.adversary.org/crypto/gpgme-python-howto.html][GPGME Python Bindings HOWTO draft (XHTML AWS S3 no SSL)]] -- [[https://files.au.adversary.org/crypto/gpgme-python-howto.texi][GPGME Python Bindings HOWTO draft (Texinfo file AWS S3 SSL)]] -- [[http://files.au.adversary.org/crypto/gpgme-python-howto.texi][GPGME Python Bindings HOWTO draft (Texinfo file AWS S3 no SSL)]] -- [[https://files.au.adversary.org/crypto/gpgme-python-howto.info][GPGME Python Bindings HOWTO draft (Info file AWS S3 SSL)]] -- [[http://files.au.adversary.org/crypto/gpgme-python-howto.info][GPGME Python Bindings HOWTO draft (Info file AWS S3 no SSL)]] -- [[https://files.au.adversary.org/crypto/gpgme-python-howto.xml][GPGME Python Bindings HOWTO draft (Docbook 4.2 AWS S3 SSL)]] -- [[http://files.au.adversary.org/crypto/gpgme-python-howto.xml][GPGME Python Bindings HOWTO draft (Docbook 4.2 AWS S3 no SSL)]] - -All of these draft versions are generated from this document via Emacs -[[https://orgmode.org/][Org mode]] and [[https://www.gnu.org/software/texinfo/][GNU Texinfo]]. Though it is likely that the specific [[https://files.au.adversary.org/crypto/gpgme-python-howto.org][file]] -[[http://files.au.adversary.org/crypto/gpgme-python-howto.org][version]] used will be on the same server with the generated output -formats. - -In addition to these there is a significantly less frequently updated -version as a HTML [[https://files.au.adversary.org/crypto/gpgme-python-howto/webhelp/index.html][WebHelp site]] (AWS S3 SSL); generated from DITA XML -source files, which can be found in [[https://dev.gnupg.org/source/gpgme/browse/ben%252Fhowto-dita/][an alternative branch]] of the GPGME -git repository. - -These draft editions are not official documents and the version of -documentation in the master branch or which ships with released -versions is the only official documentation. Nevertheless, these -draft editions may occasionally be of use by providing more accessible -web versions which are updated between releases. They are provided on -the understanding that they may contain errors or may contain content -subject to change prior to an official release. - - -** License GPL compatible - :PROPERTIES: - :CUSTOM_ID: license - :END: - -This file is free software; as a special exception the author gives -unlimited permission to copy and/or distribute it, with or without -modifications, as long as this notice is preserved. - -This file is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -PURPOSE. - - -* Footnotes - -[fn:1] =Short_History.org= and/or =Short_History.html=. - -[fn:2] The =lang/python/docs/= directory in the GPGME source. - -[fn:3] With no issues reported specific to Python 3.7, the release of -Python 3.7.1 at around the same time as GPGME 1.12.0 and the testing -with Python 3.7.1rc1, there is no reason to delay moving 3.7 ahead of -3.6 now. Production environments with more conservative requirements -will always enforce their own policies anyway and installation to each -supported minor release is quite possible too. - -[fn:4] Yes, even if you use virtualenv with everything you do in -Python. If you want to install this module as just your user account -then you will need to manually configure, compile and install the -/entire/ GnuPG stack as that user as well. This includes libraries -which are not often installed that way. It can be done and there are -circumstances under which it is worthwhile, but generally only on -POSIX systems which utilise single user mode (some even require it). - -[fn:5] You probably don't really want to do this. Searching the -keyservers for "gnupg.org" produces over 400 results, the majority of -which aren't actually at the gnupg.org domain, but just included a -comment regarding the project in their key somewhere. - -[fn:6] Such as with ProtonMail servers. This also means that -restricted servers which only advertise either HTTP or HTTPS end -points and not HKP or HKPS end points must still be identified as as -HKP or HKPS within the Python Code. The =hkp4py= module will rewrite -these appropriately when the connection is made to the server. diff --git a/lang/python/docs/meta/TODO.org b/lang/python/docs/meta/TODO.org new file mode 100644 index 00000000..add8f4ff --- /dev/null +++ b/lang/python/docs/meta/TODO.org @@ -0,0 +1,219 @@ +#+TITLE: Stuff To Do +#+LATEX_COMPILER: xelatex +#+LATEX_CLASS: article +#+LATEX_CLASS_OPTIONS: [12pt] +#+LATEX_HEADER: \usepackage{xltxtra} +#+LATEX_HEADER: \usepackage[margin=1in]{geometry} +#+LATEX_HEADER: \setmainfont[Ligatures={Common}]{Latin Modern Roman} + +* Project Task List + :PROPERTIES: + :CUSTOM_ID: task-list + :END: + +** DONE Documentation default format + CLOSED: [2018-02-15 Thu 21:29] + :PROPERTIES: + :CUSTOM_ID: todo-docs-default + :END: + + Decide on a default file format for documentation. The two main + contenders being Org Mode, the default for the GnuPG Project and + reStructuredText, the default for Python projects. A third option + of DITA XML was considered due to a number of beneficial features + it provides. + + The decision was made to use Org Mode in order to fully integrate + with the rest of the GPGME and GnuPG documentation. It is possible + to produce reST versions via Pandoc and DITA XML can be reached + through converting to either Markdown or XHTML first. + + +** STARTED Documentation HOWTO + :PROPERTIES: + :CUSTOM_ID: todo-docs-howto + :END: + + - State "STARTED" from "TODO" [2018-03-08 Thu 13:59] \\ + Started yesterday. + Write a HOWTO style guide for the current Python bindings. + +*** DONE Start python bindings HOWTO + CLOSED: [2018-03-07 Wed 18:14] + :PROPERTIES: + :CUSTOM_ID: howto-start + :END: + + +*** STARTED Include certain specific instructions in the HOWTO + :PROPERTIES: + :CUSTOM_ID: howto-requests + :END: + + Note: moved the S/MIME bits out to their own section of the TODO + list and may be served better by separate HOWTO documentation + anyway. + + - State "STARTED" from "TODO" [2018-03-09 Fri 15:27] + Some functions can be worked out from the handful of examples + available, but many more can't and I've already begun receiving + requests for certain functions to be explained. + + +**** DONE Standard scenarios + CLOSED: [2018-03-19 Mon 12:34] + :PROPERTIES: + :CUSTOM_ID: howto-the-basics + :END: + + - State "DONE" from "STARTED" [2018-03-19 Mon 12:34] \\ + All four of those are done. + - State "STARTED" from "TODO" [2018-03-09 Fri 15:26] \\ + Began with the example code, now to add the text. + What everyone expects: encryption, decryption, signing and verifying. + + +**** STARTED Key control + :PROPERTIES: + :CUSTOM_ID: howto-key-control + :END: + + - State "STARTED" from "TODO" [2018-03-19 Mon 12:35] \\ + Generating keys and subkeys are done, but revocation is still to be done. + Generating keys, adding subkeys, revoking subkeys (and keeping + the cert key), adding and revoking UIDs, signing/certifying keys. + + +**** DONE More key control + CLOSED: [2018-03-19 Mon 12:36] + :PROPERTIES: + :CUSTOM_ID: howto-key-selection + :END: + + - State "DONE" from "TODO" [2018-03-19 Mon 12:36] \\ + Key selection, searching, matching and counting is done. + Selecting keys to encrypt to or manipulate in other ways (e.g. as + with key control or the basics). + + +** TODO Documentation SWIG + :PROPERTIES: + :CUSTOM_ID: todo-docs-swig + :END: + + Write documentation for the complete SWIG bindings demonstrating + the correspondence with GPGME itself. + + Note: it is likely that this will be more in the nature of + something to be used in conjunction with the existing GPGME + documentation which makes it easier for Python developers to use. + + +** TODO GUI examples + :PROPERTIES: + :CUSTOM_ID: todo-gui-examples + :END: + + Create some examples of using Python bindings in a GUI application + to either match or be similar to the old GTK2 examples available + with PyME. + + +** TODO Replace SWIG + :PROPERTIES: + :CUSTOM_ID: todo-replace-swig + :END: + + Selecting SWIG for this project in 2002 was understandable and + effectively the only viable option. The options available now, + however, are significantly improved and some of those would resolve + a number of existing problems with using SWIG, particularly when + running code on both POSIX compliant and Windows platforms. + + The long term goal is to replace SWIG by reimplementing the Python + bindings using a more suitable means of interfacing with the GPGME + C source code. + + +*** TODO Replacement for SWIG + :PROPERTIES: + :CUSTOM_ID: todo-replace-swig-replacement + :END: + + Decide on a replacement for SWIG. Currently CFFI is looking like + the most viable candidate, but some additional testing and checks + are yet to be completed. + + +** TODO API for an API + :PROPERTIES: + :CUSTOM_ID: todo-api-squared + :END: + + A C API like GPGME is not what most modern developers think of when + they hear the term API. Normally they think of something they can + interact with like a RESTful web API. Though RESTful is unlikely + given the nature of GPGME and the process of encryption, it may be + possible to provide a more familiar interface which can be utilised + by developers of other languages for which bindings are not + available or for which it is too difficult to create proper + bindings. + + +** TODO S/MIME + :PROPERTIES: + :CUSTOM_ID: s-mime + :END: + + Eventually add some of this, but the OpenPGP details are far more + important at the moment. + + +* Project Task Details + :PROPERTIES: + :CUSTOM_ID: detailed-tasks + :END: + +** Working examples + :PROPERTIES: + :CUSTOM_ID: working-examples + :END: + + The old GUI examples were unable to be retained since they depended + on GTK2 and Python 2's integration with GTK2. + + Current GPGME examples so far only include command line tools or + basic Python code for use with either Python 2.7 or Python 3.4 and + above. + + Future GUI examples ought to utilise available GUI modules and + libraries supported by Python 3. This may include Qt frameworks, + Tkinter, GTK3 or something else entirely. + +** Documentation + :PROPERTIES: + :CUSTOM_ID: documentation + :END: + + The legacy documentation which no longer applies to the Python + bindings has been removed. + + Current and future documentation will adhere to the GnuPG standard + of using Org Mode and not use the reStructuredText (reST) format + more commonly associated with Python documentation. The reasons + for this are that this project is best served as shipping with the + rest of GPGME and the documentation ought to match that. There are + also aspects of Org Mode's publishing features which are superior + to the defaults of reST, including the capacity to generate fully + validating strict XHTML output. + + If reST files are required at a later point for future inclusion + with other Python packages, then that format can be generated from + the .org files with Pandoc before being leveraged by either + Docutils, Sphinx or something else. + + While there are some advanced typesetting features of reST which + are not directly available to Org Mode, more often than not those + features are best implemented with either HTML and CSS, with LaTeX + to produce a PDF or via a number of XML solutions. Both reST and + Org Mode have multiple paths by which to achieve all of these. diff --git a/lang/python/docs/meta/old-commits.log b/lang/python/docs/meta/old-commits.log new file mode 100644 index 00000000..93661e35 --- /dev/null +++ b/lang/python/docs/meta/old-commits.log @@ -0,0 +1,2445 @@ +commit 2145348ec54c6027f2ea20f695de0277e2871405 +Merge: 348ba88 2036f1a +Author: Ben McGinnes +Date: Wed May 6 03:04:19 2015 +1000 + + Merge pull request #4 from Hasimir/master + + history + +commit 2036f1a0a670a0561993e195c458059220b36114 +Merge: dbabf0c 348ba88 +Author: Ben McGinnes +Date: Wed May 6 02:57:44 2015 +1000 + + Merge branch 'master' of github:adversary-org/pyme3 + +commit dbabf0cf1f2985755c2293b619011832e34faa9c +Author: Ben McGinnes +Date: Wed May 6 02:52:23 2015 +1000 + + Added a short history + + * A (very) brief summary of the project's history since 2002. + * Deals with why the commit log in the GPGME repo does not include the + history of PyME. + * Mentions that intact git repos will be maintained, but not where they + are (one will be on github, another will be in a user directory on + playfair.gnupg.org). + + docs/Short_History.rst | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +commit 348ba883424778c711c04ae9b66035ccdb36eb8c +Merge: 127d0a5 7c37a27 +Author: Ben McGinnes +Date: Wed May 6 02:21:34 2015 +1000 + + Merge pull request #3 from Hasimir/master + + Version release preparation + +commit 7c37a27a6845c58222d4d947c2efbe38e955b612 +Merge: f692cff 127d0a5 +Author: Ben McGinnes +Date: Wed May 6 02:17:14 2015 +1000 + + Merge branch 'master' of github:adversary-org/pyme3 + +commit f692cff50a89c2c61acdbd3d7dd60f5ce3cd15af +Author: Ben McGinnes +Date: Wed May 6 02:09:44 2015 +1000 + + TODO update + + * Removed reference to GitHub, replaced with impending new home at gnupg.org. + + docs/TODO.rst | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +commit bd5ccf9e3bfe69fa681613757577e87b72ca08ec +Author: Ben McGinnes +Date: Wed May 6 02:00:44 2015 +1000 + + Version bump + + * Bumped version number to 0.9.1 to keep it somewhat in line with the + existing PyME project, even though there will be some divergence at + some point (or even re-merging, depending on how many of the Python 3 + modifications can be back-ported to the Python 2 version). + * Updated the author and copyright information to reflect the two + current authors (Martin and I). + * Replaced Igor's contact details with mine. + * Replaced project home page with the GnuPG one. + + pyme/version.py | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +commit ec167512f4ca88d8f6e89e2ae831798c8283b4df +Author: Ben McGinnes +Date: Wed May 6 01:48:01 2015 +1000 + + README preparation. + + * Changes in preparation for impending move of code to the GnuPG git + server as a part of GPGME. + + README.rst | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +commit 8a48515e884c36b5bdb24a13cb4d2e49f4ee6f17 +Author: Ben McGinnes +Date: Wed May 6 01:43:53 2015 +1000 + + TODO moved to docs + + * As it says. + + TODO.rst | 25 ------------------------- + docs/TODO.rst | 25 +++++++++++++++++++++++++ + 2 files changed, 25 insertions(+), 25 deletions(-) + +commit f968c777472f01f308f6e57eac1740bf5c76c205 +Author: Ben McGinnes +Date: Sun May 3 16:52:13 2015 +1000 + + Started another TODO file. + + TODO.rst | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +commit 127d0a56fa9f7ad1d4fb39d0b529b890a8d67365 +Merge: db72dea 44837f6 +Author: Ben McGinnes +Date: Sun May 3 14:59:44 2015 +1000 + + Merge pull request #2 from Hasimir/master + + Minor editing. + +commit 44837f6e50fc539c86aef1f75a6a3538b02029ea +Author: Ben McGinnes +Date: Sun May 3 14:56:55 2015 +1000 + + Minor editing. + + * Fixed another URL. + * Changed Py3 version's version number to v0.9.1-beta0. + + README.rst | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +commit db72deaae19c3513391df040bcaf66a88d9213af +Merge: db34286 48eb185 +Author: Ben McGinnes +Date: Sun May 3 14:26:11 2015 +1000 + + Merge pull request #1 from Hasimir/master + + Links + +commit 48eb1856cb0739cc9f0b9084da9d965e1fc7fddd +Author: Ben McGinnes +Date: Sun May 3 14:22:30 2015 +1000 + + Links + + * Fixed URLs for authors. + * Updated my entry to point to github location. + ** I strongly suspect the result of this work will be concurrent + projects, so preparing for that eventuality with this repo. + + README.rst | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +commit db3428659783f30b9a76204403daedf9fc4cf7cf +Author: Ben McGinnes +Date: Sun May 3 11:29:00 2015 +1000 + + Explicit over Implicit ... + + ... isn't just for code. + + * Removed the 2to3 working directory and its contents. + * Made the README.rst file a little more clear that this branch is for + Python 3 (set Python 3.2 as a fairly arbitrary requirement for the + moment, but will probably raise this to 3.3). + + 2to3/2to3-output-remaining.log | 60 --- + 2to3/2to3-output-setup.log | 35 -- + 2to3/2to3-output.log | 950 ----------------------------------------- + README.rst | 10 +- + 4 files changed, 7 insertions(+), 1048 deletions(-) + +commit 3edf07a4ba8a86af3a33246234d6e133074862af +Author: Ben McGinnes +Date: Sun May 3 11:19:41 2015 +1000 + + Added authors. + + * In alphabetical order. + * Mine will need updating once Martin and I have decided what to do + regarding the two main branches. + + README.rst | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +commit 811eb14b53e8856312d99f46b77215f7f9bd672c +Author: Ben McGinnes +Date: Sun May 3 10:23:00 2015 +1000 + + Docs and other things. + + * Now able to import pyme.core without error, indicates port process is + successful. + * Code is *not* compatible with the Python 2 version. + * Will need to consider making this a parallel project with the master + branch. + * Got rid of the .org TODO file. + * Changed the README to use the reST file extension since it's full of + reST anyway. + + 2to3/TODO.org | 5 ----- + README.rst | 32 ++++++++++++++++++++++++++++++++ + README.txt | 32 -------------------------------- + 3 files changed, 32 insertions(+), 37 deletions(-) + +commit 79e784bdcce1de6f7856921b5431044c62c6f015 +Author: Ben McGinnes +Date: Sun May 3 10:18:40 2015 +1000 + + Fixed another implicit import by making it explicit. Hopefully this is the last one. + + pyme/util.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 2b52b46ccda3e7abcc50eed0745062259d698661 +Author: Ben McGinnes +Date: Sun May 3 10:16:01 2015 +1000 + + Fixed another implicit import by making it explicit. + + pyme/errors.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 409c8fd565e21f23cd41daaeffc867e6d23a0863 +Author: Ben McGinnes +Date: Sun May 3 10:08:22 2015 +1000 + + Bytes vs. Unicode + + * Trying PyBytes instead of PyUnicode. + + gpgme.i | 14 +++++++------- + helpers.c | 8 ++++---- + 2 files changed, 11 insertions(+), 11 deletions(-) + +commit d8164aa2ae98bf8c807c16e2d9be12c5fbea7cfd +Author: Ben McGinnes +Date: Sun May 3 09:22:58 2015 +1000 + + String to Unicode + + * Replaced all instances of PyString with PyUnicode (and hoping there's + no byte data in there). + + gpgme.i | 14 +++++++------- + helpers.c | 8 ++++---- + 2 files changed, 11 insertions(+), 11 deletions(-) + +commit bd99b7865656e559b17c419c6b64b412a22c6c44 +Author: Ben McGinnes +Date: Sun May 3 09:17:06 2015 +1000 + + PyInt_AsLong + + * Replaced all instances of PyInt with PyLong, as per C API docs. + + gpgme.i | 4 ++-- + helpers.c | 8 ++++---- + 2 files changed, 6 insertions(+), 6 deletions(-) + +commit 3c91e2ccf8ca788b51e3308e292c6b64888fdb15 +Author: Ben McGinnes +Date: Sun May 3 05:59:36 2015 +1000 + + Import correction + + * Once pygpgme.py is generated and moved, it will be in the right + directory for the explicit "from . import pygpgme" to be correct. + + pyme/core.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 23a49e7070812ff1ce138d8d4cc46d0b80328897 +Author: Ben McGinnes +Date: Sun May 3 05:38:29 2015 +1000 + + The -py3 flag. + + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit b1549587d6db5e33081b9c20f75d1348a1d25938 +Author: Ben McGinnes +Date: Sun May 3 05:01:42 2015 +1000 + + Fixed indentation - 4. + + pyme/core.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit a685142ce46761ee6f5176e90717176e38e0d24f +Author: Ben McGinnes +Date: Sun May 3 05:00:16 2015 +1000 + + Fixed indentation - 3. + + pyme/core.py | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +commit 488a70b490cc64eb1c47d2483cb2f4079c6767f7 +Author: Ben McGinnes +Date: Sun May 3 04:53:21 2015 +1000 + + Pet Peeve + + def pet_peeve(self): + peeve = print("people who don't press return after a colon!") + + FFS! + + pyme/core.py | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +commit a5d38eb47d64bb17bb609fe594dae2aca480bac9 +Author: Ben McGinnes +Date: Sun May 3 04:47:54 2015 +1000 + + Fixed indentation - 2. + + pyme/core.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 476a207f732b8559abb1ea3c23147c0e34804730 +Author: Ben McGinnes +Date: Sun May 3 04:46:01 2015 +1000 + + Fixed indentation. + + pyme/core.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +commit 0572900eba9bcd9b0283c7d8e022e8972f06f9f8 +Author: Ben McGinnes +Date: Sun May 3 04:43:49 2015 +1000 + + Replaced all tabs with 4 spaces. + + pyme/core.py | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +commit 78c0b7677e94ce1e11b8cdb833a9064527187330 +Author: Ben McGinnes +Date: Sun May 3 04:39:07 2015 +1000 + + SWIG flags in the wrong place. + + Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +commit dfa7f2589963494a8f89277560d8c1116604a3c8 +Author: Ben McGinnes +Date: Sun May 3 04:35:09 2015 +1000 + + Fixed subprocess call for swig (again). + + setup.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 249bfd8c714dcda53127b99b6cc8a6c7c4a99f20 +Author: Ben McGinnes +Date: Sun May 3 04:32:40 2015 +1000 + + Fixed subprocess call for swig. + + setup.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 6fd7e719cf4c975f466ceb39835db7007df36fb2 +Author: Ben McGinnes +Date: Sun May 3 03:51:48 2015 +1000 + + Linking swig to py3 + + * Changed the swig invocations to run with the -python -py3 flags explicitly. + + Makefile | 4 ++-- + setup.py | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +commit 7a6b584f50ed6ddc8617a642185eea1f24ff791a +Author: Ben McGinnes +Date: Sat May 2 11:12:00 2015 +1000 + + String fun + + * streamlined confdata details, including decoding strom binary to string. + + setup.py | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +commit f7fd3f270592021a95a8f779bfe85ac18f4e390b +Author: Ben McGinnes +Date: Sat May 2 10:46:59 2015 +1000 + + Open File + + * Removed deprecated file() and replaced with open(). + + examples/PyGtkGpgKeys.py | 2 +- + examples/pygpa.py | 6 +++--- + gpgme-h-clean.py | 2 +- + 3 files changed, 5 insertions(+), 5 deletions(-) + +commit 4227d486f9558015e7e548d71085e58e1b50ec08 +Author: Ben McGinnes +Date: Sat May 2 10:36:15 2015 +1000 + + print() fix + + * Makefile includes a python print, changed from statement to function. + + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 406f7f2567b701502186fe0a325dc2a3491ff7f8 +Author: Ben McGinnes +Date: Sat May 2 10:28:42 2015 +1000 + + Updated Makefile + + * set make to use python3 instead. + * This will mean a successful port may need to be maintained seperately + from the original python2 code instead of merged, but ought to be able + to share most things. So maybe merge with separated make files or a + pre-make script to set python2 or python3 prior to building ... decide + later, after it works. + + Makefile | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +commit 90b3efa5b193d37e08dc9b4ee766ba9ebc9412af +Author: Ben McGinnes +Date: Sat May 2 10:15:20 2015 +1000 + + Env and a little license issue + + * Updated all the /usr/bin/env paths to point to python3. + * Also fixed the hard coded /usr/bin/python paths. + * Updated part of setup.py which gave the impression this package was + only licensed under the GPL (it's actually licensed under the LGPL as + well, essentially the same dual licensing as the GPGME library). + + examples/PyGtkGpgKeys.py | 2 +- + examples/delkey.py | 2 +- + examples/encrypt-to-all.py | 2 +- + examples/exportimport.py | 2 +- + examples/genkey.py | 2 +- + examples/inter-edit.py | 2 +- + examples/pygpa.py | 2 +- + examples/sign.py | 2 +- + examples/signverify.py | 2 +- + examples/simple.py | 2 +- + examples/t-edit.py | 2 +- + examples/testCMSgetkey.py | 2 +- + examples/verifydetails.py | 2 +- + gpgme-h-clean.py | 2 +- + setup.py | 4 ++-- + 15 files changed, 16 insertions(+), 16 deletions(-) + +commit 1a4b55dbccd2774344352e579130bf494bc5fa4b +Author: Ben McGinnes +Date: Sat May 2 08:50:54 2015 +1000 + + Removed extraneous files. + + * The two .bak files. + + pyme/errors.py.bak | 46 --------------------- + setup.py.bak | 116 ----------------------------------------------------- + 2 files changed, 162 deletions(-) + +commit 208879d4f2a6d0514c3f8ee2fc0da8bba42350de +Author: Ben McGinnes +Date: Sat May 2 08:19:37 2015 +1000 + + Added TODO.org + + * TODO list in Emacs org-mode. + * Will eventually be removed along with this entire directory when the + porting process is complete. + + 2to3/TODO.org | 5 +++++ + 1 file changed, 5 insertions(+) + +commit 1548bf201059638675c5387c6f124d4b703363a9 +Author: Ben McGinnes +Date: Sat May 2 07:58:40 2015 +1000 + + 2to3 conversion of remaining files + + * Ran the extended version against all the unmodified python files. + * Only pyme/errors.py required additional work. + + 2to3/2to3-output-remaining.log | 60 ++++++++++++++++++++++++++++++++++++++++++ + pyme/errors.py | 2 +- + pyme/errors.py.bak | 46 ++++++++++++++++++++++++++++++++ + 3 files changed, 107 insertions(+), 1 deletion(-) + +commit 1230650bc6bbe4c14d1284f7877aa932f3e86eb4 +Author: Ben McGinnes +Date: Sat May 2 07:50:39 2015 +1000 + + 2to3 conversion of setup.py + + * Ran extended 2to3 command to produce python 3 code for setup.py. + * Effectively testing for what to run against the other originally + unmodified py2 files. + + 2to3/2to3-output-setup.log | 35 ++++++++++++++ + setup.py | 7 ++- + setup.py.bak | 116 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 154 insertions(+), 4 deletions(-) + +commit edad44955f59aa879e95a369591717fb19eec6b7 +Author: Ben McGinnes +Date: Fri May 1 21:50:07 2015 +1000 + + Removing 2to3 generated .bak files. + + * Not really needed with a real VCS, but couldn't hurt to have them for + a couple of revisions. ;) + + examples/PyGtkGpgKeys.py.bak | 663 --------------- + examples/encrypt-to-all.py.bak | 65 -- + examples/exportimport.py.bak | 75 -- + examples/genkey.py.bak | 45 - + examples/inter-edit.py.bak | 57 -- + examples/pygpa.py.bak | 1457 -------------------------------- + examples/sign.py.bak | 31 - + examples/signverify.py.bak | 78 -- + examples/simple.py.bak | 52 -- + examples/t-edit.py.bak | 59 -- + examples/testCMSgetkey.py.bak | 45 - + examples/verifydetails.py.bak | 100 --- + gpgme-h-clean.py.bak | 42 - + pyme/callbacks.py.bak | 47 -- + pyme/constants/data/__init__.py.bak | 4 - + pyme/constants/keylist/__init__.py.bak | 4 - + pyme/constants/sig/__init__.py.bak | 4 - + pyme/core.py.bak | 463 ---------- + pyme/util.py.bak | 72 -- + pyme/version.py.bak | 41 - + 20 files changed, 3404 deletions(-) + +commit 1cfc3c969f885ed191610bffbbd60ac23fdd349e +Author: Ben McGinnes +Date: Fri May 1 21:45:50 2015 +1000 + + 2to3 conversion log + + * The output of the command to convert the code from Python 2 to 3. + * Note: this contains the list of files which were not modified and + which will or may need to be modified. + + 2to3/2to3-output.log | 950 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 950 insertions(+) + +commit 078f6cf878aa62d12704fab424198a613a24cc8c +Author: Ben McGinnes +Date: Fri May 1 21:36:58 2015 +1000 + + 2to3 conversion of pyme master + + * Branch from commit 459f3eca659b4949e394c4a032d9ce2053e6c721 + * Ran this: or x in `find . | egrep .py$` ; do 2to3 -w $x; done ; + * Multiple files not modified, will record elsewhere (see next commit). + + examples/PyGtkGpgKeys.py | 10 +- + examples/PyGtkGpgKeys.py.bak | 663 +++++++++++++++ + examples/encrypt-to-all.py | 12 +- + examples/encrypt-to-all.py.bak | 65 ++ + examples/exportimport.py | 20 +- + examples/exportimport.py.bak | 75 ++ + examples/genkey.py | 2 +- + examples/genkey.py.bak | 45 + + examples/inter-edit.py | 8 +- + examples/inter-edit.py.bak | 57 ++ + examples/pygpa.py | 40 +- + examples/pygpa.py.bak | 1457 ++++++++++++++++++++++++++++++++ + examples/sign.py | 2 +- + examples/sign.py.bak | 31 + + examples/signverify.py | 18 +- + examples/signverify.py.bak | 78 ++ + examples/simple.py | 8 +- + examples/simple.py.bak | 52 ++ + examples/t-edit.py | 12 +- + examples/t-edit.py.bak | 59 ++ + examples/testCMSgetkey.py | 8 +- + examples/testCMSgetkey.py.bak | 45 + + examples/verifydetails.py | 34 +- + examples/verifydetails.py.bak | 100 +++ + gpgme-h-clean.py | 2 +- + gpgme-h-clean.py.bak | 42 + + pyme/callbacks.py | 6 +- + pyme/callbacks.py.bak | 47 ++ + pyme/constants/data/__init__.py | 2 +- + pyme/constants/data/__init__.py.bak | 4 + + pyme/constants/keylist/__init__.py | 2 +- + pyme/constants/keylist/__init__.py.bak | 4 + + pyme/constants/sig/__init__.py | 2 +- + pyme/constants/sig/__init__.py.bak | 4 + + pyme/core.py | 26 +- + pyme/core.py.bak | 463 ++++++++++ + pyme/util.py | 6 +- + pyme/util.py.bak | 72 ++ + pyme/version.py | 2 +- + pyme/version.py.bak | 41 + + 40 files changed, 3515 insertions(+), 111 deletions(-) + +commit 459f3eca659b4949e394c4a032d9ce2053e6c721 +Merge: c5966ab dae7f14 +Author: Martin Albrecht +Date: Wed Jul 9 10:48:33 2014 +0100 + + Merged in jerrykan/pyme/fix_setup_26 (pull request #1) + + Provide support for using setup.py with Python v2.6 + +commit dae7f14a54e6c2bde0ad4da7308cc7fc0d0c0469 +Author: John Kristensen +Date: Wed Jul 9 15:54:39 2014 +1000 + + Provide support for using setup.py with Python v2.6 + + The setup.py script uses subprocess.check_output() which was introduced + in Python v2.7. The equivalent functionality can be achieved without + adding much extra code and provide support for Python v2.6. + + setup.py | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +commit c5966abec9d772b3922d32650da288fd50a217be +Author: Martin Albrecht +Date: Thu May 15 19:43:00 2014 +0100 + + README.txt in ReST, including headlines + + README.txt | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +commit 43ee8c6f34fa9b6d3975aa6ea60b3d4a741fa721 +Author: Martin Albrecht +Date: Thu May 15 19:37:15 2014 +0100 + + README.txt in ReST + + README.txt | 25 +++++++++++++------------ + 1 file changed, 13 insertions(+), 12 deletions(-) + +commit f71a369484cba8801df23ccc5842335fa496c0df +Author: Martin Albrecht +Date: Thu May 15 19:28:12 2014 +0100 + + added MANIFEST.in and README.txt (instead of .md) + + MANIFEST.in | 6 ++++++ + README.md | 27 --------------------------- + README.txt | 27 +++++++++++++++++++++++++++ + 3 files changed, 33 insertions(+), 27 deletions(-) + +commit d0d6755229f920b0bed043e9c2731de2d57c096c +Author: Martin Albrecht +Date: Tue May 13 09:52:44 2014 +0100 + + added mailing list to README + + README.md | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +commit 30ca60ddf92df684de261cb24c83c68089be0adc +Author: Martin Albrecht +Date: Sun May 11 13:34:28 2014 +0100 + + we don't need a separate out of date ChangeLog file + + ChangeLog | 802 -------------------------------------------------------------- + 1 file changed, 802 deletions(-) + +commit 8263f1a6d38fdb7f5f3dd5c7e28f83caa7528a08 +Author: Martin Albrecht +Date: Sun May 11 13:32:31 2014 +0100 + + adding README.md + + README.md | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +commit 3fc71b47e9e14b0b984801c28d722723baa4b406 +Author: Martin Albrecht +Date: Sat May 10 15:43:06 2014 +0100 + + ValueError -> RuntimeError + + setup.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +commit eec432abea56296b9fa36aac0d10926a2335b739 +Merge: eea6537 d2738b3 +Author: Martin Albrecht +Date: Sat May 10 15:41:02 2014 +0100 + + Merge branch 'master' of bitbucket.org:malb/pyme + + Conflicts: + setup.py + +commit eea6537921061b4dcfc54e00a99d3fa110e71433 +Author: Martin Albrecht +Date: Sat May 10 15:39:51 2014 +0100 + + check for swig + + setup.py | 8 ++++++++ + 1 file changed, 8 insertions(+) + +commit 53867bf9715ee1b4ea873bf5e2fbb7d9740a2b4a +Author: Martin Albrecht +Date: Sat May 10 15:35:04 2014 +0100 + + more friendly error message if gpgme is missing + + setup.py | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +commit d2738b35d63b1492d69641c5466103685f2d3a30 +Author: Martin Albrecht +Date: Sat May 10 15:35:04 2014 +0100 + + more friendly error message if gpgme is missing + + setup.py | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +commit c0b01240becf8ba6cf1d4c1f64b2cb4c056f5163 +Author: Martin Albrecht +Date: Fri May 9 15:20:24 2014 +0100 + + version number should have three digits + + pyme/version.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 6672bb60b9bec60d38e854016c48658b57774578 +Author: Martin Albrecht +Date: Wed May 7 15:11:08 2014 +0100 + + bump version number for upcoming release + + pyme/version.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 7bd6de700f33ca5d1f27bc16ebbd401f21d2e788 +Author: Martin Albrecht +Date: Sat May 3 19:36:25 2014 +0100 + + bump version number to indicate changes + + pyme/version.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 4fb6bd9b3f47c1a343242ac83b326cacd12a136e +Author: Martin Albrecht +Date: Sat May 3 19:34:07 2014 +0100 + + pyme instead of pygpgme + + setup.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 9548973138d78241a45ccb82333b25f2cf36ce7d +Author: Martin Albrecht +Date: Sat May 3 19:31:10 2014 +0100 + + dirty hack to make 'python setup.py install' work + + setup.py | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +commit a961d7eab9db478b7e603324bc5d243bd3c84bad +Author: Martin Albrecht +Date: Sat May 3 19:05:44 2014 +0100 + + moved everything down to the toplevel directory + + COPYING | 340 ++ + COPYING.LESSER | 510 +++ + ChangeLog | 802 +++++ + INSTALL | 15 + + Makefile | 104 + + debian/README.Debian | 6 + + debian/changelog | 93 + + debian/control | 34 + + debian/copyright | 25 + + debian/docs | 2 + + debian/examples | 2 + + debian/rules | 99 + + examples/PyGtkGpgKeys.glade | 1394 ++++++++ + examples/PyGtkGpgKeys.gladep | 8 + + examples/PyGtkGpgKeys.py | 663 ++++ + examples/delkey.py | 34 + + examples/encrypt-to-all.py | 65 + + examples/exportimport.py | 75 + + examples/genkey.py | 45 + + examples/inter-edit.py | 57 + + examples/pygpa.glade | 5546 +++++++++++++++++++++++++++++++ + examples/pygpa.py | 1457 ++++++++ + examples/sign.py | 31 + + examples/signverify.py | 78 + + examples/simple.py | 52 + + examples/t-edit.py | 59 + + examples/testCMSgetkey.py | 45 + + examples/verifydetails.py | 100 + + gpgme-h-clean.py | 42 + + gpgme.i | 267 ++ + helpers.c | 154 + + helpers.h | 36 + + pyme/COPYING | 340 -- + pyme/COPYING.LESSER | 510 --- + pyme/ChangeLog | 802 ----- + pyme/INSTALL | 15 - + pyme/Makefile | 104 - + pyme/__init__.py | 137 + + pyme/callbacks.py | 47 + + pyme/constants/__init__.py | 7 + + pyme/constants/data/__init__.py | 4 + + pyme/constants/data/encoding.py | 20 + + pyme/constants/event.py | 20 + + pyme/constants/import.py | 20 + + pyme/constants/keylist/__init__.py | 4 + + pyme/constants/keylist/mode.py | 20 + + pyme/constants/md.py | 20 + + pyme/constants/pk.py | 20 + + pyme/constants/protocol.py | 20 + + pyme/constants/sig/__init__.py | 4 + + pyme/constants/sig/mode.py | 20 + + pyme/constants/sigsum.py | 20 + + pyme/constants/status.py | 20 + + pyme/constants/validity.py | 20 + + pyme/core.py | 463 +++ + pyme/debian/README.Debian | 6 - + pyme/debian/changelog | 93 - + pyme/debian/control | 34 - + pyme/debian/copyright | 25 - + pyme/debian/docs | 2 - + pyme/debian/examples | 2 - + pyme/debian/rules | 99 - + pyme/errors.py | 46 + + pyme/examples/PyGtkGpgKeys.glade | 1394 -------- + pyme/examples/PyGtkGpgKeys.gladep | 8 - + pyme/examples/PyGtkGpgKeys.py | 663 ---- + pyme/examples/delkey.py | 34 - + pyme/examples/encrypt-to-all.py | 65 - + pyme/examples/exportimport.py | 75 - + pyme/examples/genkey.py | 45 - + pyme/examples/inter-edit.py | 57 - + pyme/examples/pygpa.glade | 5546 ------------------------------- + pyme/examples/pygpa.py | 1457 -------- + pyme/examples/sign.py | 31 - + pyme/examples/signverify.py | 78 - + pyme/examples/simple.py | 52 - + pyme/examples/t-edit.py | 59 - + pyme/examples/testCMSgetkey.py | 45 - + pyme/examples/verifydetails.py | 100 - + pyme/gpgme-h-clean.py | 42 - + pyme/gpgme.i | 267 -- + pyme/helpers.c | 154 - + pyme/helpers.h | 36 - + pyme/pyme/__init__.py | 137 - + pyme/pyme/callbacks.py | 47 - + pyme/pyme/constants/__init__.py | 7 - + pyme/pyme/constants/data/__init__.py | 4 - + pyme/pyme/constants/data/encoding.py | 20 - + pyme/pyme/constants/event.py | 20 - + pyme/pyme/constants/import.py | 20 - + pyme/pyme/constants/keylist/__init__.py | 4 - + pyme/pyme/constants/keylist/mode.py | 20 - + pyme/pyme/constants/md.py | 20 - + pyme/pyme/constants/pk.py | 20 - + pyme/pyme/constants/protocol.py | 20 - + pyme/pyme/constants/sig/__init__.py | 4 - + pyme/pyme/constants/sig/mode.py | 20 - + pyme/pyme/constants/sigsum.py | 20 - + pyme/pyme/constants/status.py | 20 - + pyme/pyme/constants/validity.py | 20 - + pyme/pyme/core.py | 463 --- + pyme/pyme/errors.py | 46 - + pyme/pyme/util.py | 72 - + pyme/pyme/version.py | 41 - + pyme/setup.py | 99 - + pyme/util.py | 72 + + pyme/version.py | 41 + + setup.py | 99 + + 108 files changed, 13384 insertions(+), 13384 deletions(-) + +commit 8148cdd424c434e833ce427612ea8c89abc6e41c +Author: Martin Albrecht +Date: Sat May 3 18:58:52 2014 +0100 + + removing pyme-web + + pyme-web/Makefile | 15 - + pyme-web/default.css | 37 -- + pyme-web/doc/gpgme/ASCII-Armor.html | 57 --- + pyme-web/doc/gpgme/Advanced-Key-Editing.html | 98 ---- + pyme-web/doc/gpgme/Algorithms.html | 47 -- + pyme-web/doc/gpgme/Building-the-Source.html | 82 ---- + .../doc/gpgme/Callback-Based-Data-Buffers.html | 148 ------ + pyme-web/doc/gpgme/Cancellation.html | 67 --- + pyme-web/doc/gpgme/Concept-Index.html | 186 ------- + pyme-web/doc/gpgme/Context-Attributes.html | 52 -- + pyme-web/doc/gpgme/Contexts.html | 61 --- + pyme-web/doc/gpgme/Creating-Contexts.html | 49 -- + pyme-web/doc/gpgme/Creating-Data-Buffers.html | 47 -- + pyme-web/doc/gpgme/Creating-a-Signature.html | 143 ------ + pyme-web/doc/gpgme/Crypto-Engine.html | 79 --- + pyme-web/doc/gpgme/Crypto-Operations.html | 67 --- + .../doc/gpgme/Cryptographic-Message-Syntax.html | 42 -- + .../doc/gpgme/Data-Buffer-I_002fO-Operations.html | 104 ---- + pyme-web/doc/gpgme/Data-Buffer-Meta_002dData.html | 100 ---- + pyme-web/doc/gpgme/Decrypt-and-Verify.html | 79 --- + pyme-web/doc/gpgme/Decrypt.html | 123 ----- + pyme-web/doc/gpgme/Deleting-Keys.html | 67 --- + pyme-web/doc/gpgme/Destroying-Contexts.html | 46 -- + pyme-web/doc/gpgme/Destroying-Data-Buffers.html | 70 --- + pyme-web/doc/gpgme/Encrypt.html | 45 -- + pyme-web/doc/gpgme/Encrypting-a-Plaintext.html | 147 ------ + pyme-web/doc/gpgme/Engine-Configuration.html | 65 --- + pyme-web/doc/gpgme/Engine-Information.html | 119 ----- + pyme-web/doc/gpgme/Engine-Version-Check.html | 48 -- + pyme-web/doc/gpgme/Error-Codes.html | 133 ----- + pyme-web/doc/gpgme/Error-Handling.html | 72 --- + pyme-web/doc/gpgme/Error-Sources.html | 89 ---- + pyme-web/doc/gpgme/Error-Strings.html | 80 --- + pyme-web/doc/gpgme/Error-Values.html | 159 ------ + pyme-web/doc/gpgme/Exchanging-Data.html | 58 --- + pyme-web/doc/gpgme/Exporting-Keys.html | 101 ---- + pyme-web/doc/gpgme/Features.html | 59 --- + pyme-web/doc/gpgme/File-Based-Data-Buffers.html | 74 --- + pyme-web/doc/gpgme/Function-and-Data-Index.html | 229 --------- + pyme-web/doc/gpgme/Generating-Keys.html | 144 ------ + pyme-web/doc/gpgme/Getting-Started.html | 55 --- + pyme-web/doc/gpgme/Hash-Algorithms.html | 59 --- + pyme-web/doc/gpgme/Header.html | 53 -- + .../doc/gpgme/I_002fO-Callback-Example-GDK.html | 85 ---- + .../gpgme/I_002fO-Callback-Example-GTK_002b.html | 86 ---- + .../doc/gpgme/I_002fO-Callback-Example-Qt.html | 99 ---- + pyme-web/doc/gpgme/I_002fO-Callback-Example.html | 259 ---------- + pyme-web/doc/gpgme/I_002fO-Callback-Interface.html | 142 ------ + pyme-web/doc/gpgme/Importing-Keys.html | 171 ------- + pyme-web/doc/gpgme/Included-Certificates.html | 70 --- + pyme-web/doc/gpgme/Information-About-Keys.html | 207 -------- + .../doc/gpgme/Information-About-Trust-Items.html | 75 --- + pyme-web/doc/gpgme/Introduction.html | 53 -- + pyme-web/doc/gpgme/Key-Listing-Mode.html | 99 ---- + pyme-web/doc/gpgme/Key-Management.html | 260 ---------- + pyme-web/doc/gpgme/Key-Signatures.html | 130 ----- + .../doc/gpgme/Largefile-Support-_0028LFS_0029.html | 110 ----- + pyme-web/doc/gpgme/Library-Copying.html | 542 --------------------- + pyme-web/doc/gpgme/Library-Version-Check.html | 97 ---- + pyme-web/doc/gpgme/Listing-Keys.html | 204 -------- + pyme-web/doc/gpgme/Listing-Trust-Items.html | 88 ---- + pyme-web/doc/gpgme/Locale.html | 69 --- + pyme-web/doc/gpgme/Manipulating-Data-Buffers.html | 45 -- + pyme-web/doc/gpgme/Manipulating-Keys.html | 63 --- + pyme-web/doc/gpgme/Manipulating-Trust-Items.html | 62 --- + pyme-web/doc/gpgme/Memory-Based-Data-Buffers.html | 107 ---- + pyme-web/doc/gpgme/Multi-Threading.html | 93 ---- + pyme-web/doc/gpgme/OpenPGP.html | 44 -- + pyme-web/doc/gpgme/Overview.html | 57 --- + pyme-web/doc/gpgme/Passphrase-Callback.html | 101 ---- + pyme-web/doc/gpgme/Preparation.html | 54 -- + pyme-web/doc/gpgme/Progress-Meter-Callback.html | 80 --- + pyme-web/doc/gpgme/Protocol-Selection.html | 60 --- + pyme-web/doc/gpgme/Protocols-and-Engines.html | 82 ---- + pyme-web/doc/gpgme/Public-Key-Algorithms.html | 74 --- + .../doc/gpgme/Registering-I_002fO-Callbacks.html | 81 --- + pyme-web/doc/gpgme/Run-Control.html | 53 -- + pyme-web/doc/gpgme/Selecting-Signers.html | 64 --- + pyme-web/doc/gpgme/Sign.html | 50 -- + pyme-web/doc/gpgme/Signal-Handling.html | 61 --- + pyme-web/doc/gpgme/Signature-Notation-Data.html | 85 ---- + pyme-web/doc/gpgme/Text-Mode.html | 63 --- + pyme-web/doc/gpgme/Trust-Item-Management.html | 68 --- + pyme-web/doc/gpgme/Using-Automake.html | 74 --- + pyme-web/doc/gpgme/Using-External-Event-Loops.html | 74 --- + pyme-web/doc/gpgme/Using-Libtool.html | 44 -- + pyme-web/doc/gpgme/Verify.html | 492 ------------------- + pyme-web/doc/gpgme/Waiting-For-Completion.html | 77 --- + pyme-web/doc/gpgme/index.html | 169 ------- + pyme-web/doc/pyme/index.html | 164 ------- + pyme-web/doc/pyme/pyme.callbacks.html | 42 -- + .../doc/pyme/pyme.constants.data.encoding.html | 48 -- + pyme-web/doc/pyme/pyme.constants.data.html | 29 -- + pyme-web/doc/pyme/pyme.constants.event.html | 48 -- + pyme-web/doc/pyme/pyme.constants.html | 39 -- + pyme-web/doc/pyme/pyme.constants.import.html | 49 -- + pyme-web/doc/pyme/pyme.constants.keylist.html | 29 -- + pyme-web/doc/pyme/pyme.constants.keylist.mode.html | 49 -- + pyme-web/doc/pyme/pyme.constants.md.html | 58 --- + pyme-web/doc/pyme/pyme.constants.pk.html | 50 -- + pyme-web/doc/pyme/pyme.constants.protocol.html | 48 -- + pyme-web/doc/pyme/pyme.constants.sig.html | 29 -- + pyme-web/doc/pyme/pyme.constants.sig.mode.html | 47 -- + pyme-web/doc/pyme/pyme.constants.sigsum.html | 55 --- + pyme-web/doc/pyme/pyme.constants.status.html | 126 ----- + pyme-web/doc/pyme/pyme.constants.validity.html | 50 -- + pyme-web/doc/pyme/pyme.core.html | 277 ----------- + pyme-web/doc/pyme/pyme.errors.html | 82 ---- + pyme-web/doc/pyme/pyme.html | 164 ------- + pyme-web/doc/pyme/pyme.util.html | 81 --- + pyme-web/doc/pyme/pyme.version.html | 37 -- + pyme-web/index.html | 72 --- + 112 files changed, 10551 deletions(-) + +commit 684d95feb7e10e538a56fb1b27f1456111bacb60 +Author: Martin Albrecht +Date: Mon Jan 6 17:44:20 2014 +0100 + + fixing op_export_keys() + + the conversion of gpgme_key_t [] was restricted to gpgme_key_t [] with the + name recv, i.e. only the use-cases of encryption were covered. + + see: http://sourceforge.net/mailarchive/forum.php?forum_name=pyme-help&max_rows=25&style=nested&viewmonth=201309 + + pyme/gpgme.i | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +commit 658d23b95110d21eeb50abf4e74701a667521a88 +Author: Martin Albrecht +Date: Mon Jan 6 17:41:33 2014 +0100 + + deleting CVSROOT + + CVSROOT/checkoutlist | 13 ------------- + CVSROOT/commitinfo | 15 --------------- + CVSROOT/config | 21 --------------------- + CVSROOT/cvswrappers | 19 ------------------- + CVSROOT/editinfo | 21 --------------------- + CVSROOT/loginfo | 26 -------------------------- + CVSROOT/modules | 26 -------------------------- + CVSROOT/notify | 12 ------------ + CVSROOT/rcsinfo | 13 ------------- + CVSROOT/taginfo | 20 -------------------- + CVSROOT/verifymsg | 21 --------------------- + 11 files changed, 207 deletions(-) + +commit 576b555499c094c4786d42de9e59aa9826009b89 +Author: convert-repo +Date: Mon Jan 6 15:22:44 2014 +0000 + + update tags + +commit 2dcf0c5b702eb5a18c66ff1e42a72eaa7427af1d +Author: belyi +Date: Wed Nov 26 02:38:33 2008 +0000 + + Move Windows specific fix from helpers.c to helpers.h so that it works + for edit callback as well as for the passphrase one. + + pyme/helpers.c | 5 ----- + pyme/helpers.h | 5 +++++ + 2 files changed, 5 insertions(+), 5 deletions(-) + +commit 42a035f2ef62470fea7a7f8ee33a1297fa90a603 +Author: belyi +Date: Mon Nov 24 21:44:30 2008 +0000 + + Update the way build directives are constructed on MinGW to have a bit + more robust. Update PyMe build version to 0.8.1 in version.py + + pyme/pyme/version.py | 2 +- + pyme/setup.py | 10 ++++++++-- + 2 files changed, 9 insertions(+), 3 deletions(-) + +commit 3aaa20fbcba17066c9ffd580f5209946022793a2 +Author: belyi +Date: Mon Nov 24 06:57:11 2008 +0000 + + Update changelog + + pyme/debian/changelog | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +commit 689ff46b2550547e3883f809a6dc40c22c3e137e +Author: belyi +Date: Mon Nov 24 06:50:41 2008 +0000 + + Fix hang problem on Windows when password is written to a filehandle. + Fix the way path is constructed on MinGW platform. + + pyme/helpers.c | 5 +++++ + pyme/setup.py | 4 ++-- + 2 files changed, 7 insertions(+), 2 deletions(-) + +commit 852a60d541d66cb56f40378182b976fd87a02c46 +Author: belyi +Date: Sun Nov 23 04:31:31 2008 +0000 + + Add Bernard's example testCMSgetkey.py and his updates for + verifydetails.py + + pyme/examples/testCMSgetkey.py | 45 ++++++++++++++++++++++++++++++++++++++++++ + pyme/examples/verifydetails.py | 43 +++++++++++++++++++++++++++++----------- + 2 files changed, 77 insertions(+), 11 deletions(-) + +commit f080527d9184f3360f0a8ef6136b9a188d8e7d2a +Author: belyi +Date: Thu May 29 18:29:37 2008 +0000 + + Remove debian packaging for python2.3 since it is removed from both + testing and unstable dists. + Update docs build target to have correct PYTHONPATH set. + + pyme/Makefile | 2 +- + pyme/debian/changelog | 4 +++- + pyme/debian/control | 4 ++-- + pyme/debian/rules | 2 -- + 4 files changed, 6 insertions(+), 6 deletions(-) + +commit c25d133fcbadf3c7f6e655586b4a05d6e3cf6f0b +Author: belyi +Date: Thu Apr 3 13:37:12 2008 +0000 + + Forgot to adjust mainText margin. Doing it now. + + pyme-web/default.css | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 897286a54a32336d060cd03305cdecb7905f34f1 +Author: belyi +Date: Thu Apr 3 13:00:11 2008 +0000 + + Fix an error in default.css and make index.html "Standards Compliant". + + pyme-web/default.css | 2 +- + pyme-web/index.html | 7 ++++--- + 2 files changed, 5 insertions(+), 4 deletions(-) + +commit 4e049212bd214449cc0ba1ce06e00782783f328a +Author: belyi +Date: Thu Apr 3 12:38:42 2008 +0000 + + Adjust spacing between links. + + pyme-web/default.css | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +commit cb2bddfbd77483b1deb14f2eab0715a03dd33fcd +Author: belyi +Date: Wed Apr 2 22:50:21 2008 +0000 + + Make style a big more IE friendly. + + pyme-web/default.css | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +commit ad66f0a1bb01b46baac328e9fee439b35a60c232 +Author: belyi +Date: Wed Apr 2 11:58:32 2008 +0000 + + Make GPGME documentation a bit more web friendly on the index.html page. + + pyme-web/doc/gpgme/Algorithms.html | 2 +- + pyme-web/doc/gpgme/Concept-Index.html | 2 +- + pyme-web/doc/gpgme/Contexts.html | 2 +- + pyme-web/doc/gpgme/Error-Handling.html | 2 +- + pyme-web/doc/gpgme/Exchanging-Data.html | 2 +- + pyme-web/doc/gpgme/Function-and-Data-Index.html | 2 +- + pyme-web/doc/gpgme/Introduction.html | 4 +- + pyme-web/doc/gpgme/Library-Copying.html | 2 +- + pyme-web/doc/gpgme/Preparation.html | 2 +- + pyme-web/doc/gpgme/Protocols-and-Engines.html | 2 +- + pyme-web/doc/gpgme/index.html | 229 +----------------------- + 11 files changed, 12 insertions(+), 239 deletions(-) + +commit 4f57c0ccb049d4442e7732e2d1d05dabffd2a21d +Author: belyi +Date: Wed Apr 2 06:12:57 2008 +0000 + + Add missing core.set_locale() to set default locale for contexts. + + pyme/debian/changelog | 2 +- + pyme/pyme/core.py | 4 ++++ + 2 files changed, 5 insertions(+), 1 deletion(-) + +commit acf7ead3dea8590cf9fe86b67bb125837ad6ed4f +Author: belyi +Date: Wed Apr 2 05:50:24 2008 +0000 + + Avoid leaks caused by keys. + Add set/get methods for engine info. + + pyme/debian/changelog | 10 ++++++++++ + pyme/pyme/core.py | 24 ++++++++++++++++++++++++ + 2 files changed, 34 insertions(+) + +commit df4a2fb518adbb6420d95ce74af212c87abff7e7 +Author: belyi +Date: Wed Apr 2 04:04:41 2008 +0000 + + Update index.html to reflect new versions on the web. + + pyme-web/Makefile | 3 ++- + pyme-web/doc/gpgme/index.html | 4 +--- + pyme-web/index.html | 4 ++-- + 3 files changed, 5 insertions(+), 6 deletions(-) + +commit bd3ffc9bdf98d6aafde6b689c6c8215fa468612d +Author: belyi +Date: Wed Apr 2 04:01:04 2008 +0000 + + Update PyMe documentation to match 0.8.0 version of the package. + + pyme-web/doc/pyme/index.html | 14 ++++----- + pyme-web/doc/pyme/pyme.constants.keylist.mode.html | 1 + + pyme-web/doc/pyme/pyme.constants.protocol.html | 4 ++- + pyme-web/doc/pyme/pyme.constants.status.html | 9 ++++++ + pyme-web/doc/pyme/pyme.core.html | 36 ++++++++++++++++++---- + pyme-web/doc/pyme/pyme.errors.html | 8 ++--- + pyme-web/doc/pyme/pyme.html | 14 ++++----- + pyme-web/doc/pyme/pyme.util.html | 17 ++++++++-- + pyme-web/doc/pyme/pyme.version.html | 14 ++++----- + 9 files changed, 82 insertions(+), 35 deletions(-) + +commit 6973a69a317608a0d0661590d701f4e3f3a21b32 +Author: belyi +Date: Wed Apr 2 02:35:24 2008 +0000 + + Have a fix for Contents being put onto 'Function and Data Index' page. + + pyme-web/doc/gpgme/Concept-Index.html | 2 +- + pyme-web/doc/gpgme/Function-and-Data-Index.html | 153 +---------------------- + pyme-web/doc/gpgme/index.html | 154 +++++++++++++++++++++++- + 3 files changed, 155 insertions(+), 154 deletions(-) + +commit 086315964cbc2abad1187f306dcb9c72ac3257f3 +Author: belyi +Date: Wed Apr 2 01:00:29 2008 +0000 + + Update GPGME documentation. It's for v1.1.6 now. + + pyme-web/doc/gpgme/ASCII-Armor.html | 57 ++ + pyme-web/doc/gpgme/Advanced-Key-Editing.html | 98 +++ + pyme-web/doc/gpgme/Algorithms.html | 47 ++ + pyme-web/doc/gpgme/Building-the-Source.html | 82 +++ + .../doc/gpgme/Callback-Based-Data-Buffers.html | 148 +++++ + pyme-web/doc/gpgme/Cancellation.html | 67 ++ + pyme-web/doc/gpgme/Concept-Index.html | 186 ++++++ + pyme-web/doc/gpgme/Context-Attributes.html | 52 ++ + pyme-web/doc/gpgme/Contexts.html | 61 ++ + pyme-web/doc/gpgme/Creating-Contexts.html | 49 ++ + pyme-web/doc/gpgme/Creating-Data-Buffers.html | 47 ++ + pyme-web/doc/gpgme/Creating-a-Signature.html | 143 +++++ + pyme-web/doc/gpgme/Crypto-Engine.html | 79 +++ + pyme-web/doc/gpgme/Crypto-Operations.html | 67 ++ + .../doc/gpgme/Cryptographic-Message-Syntax.html | 42 ++ + .../doc/gpgme/Data-Buffer-I_002fO-Operations.html | 104 ++++ + pyme-web/doc/gpgme/Data-Buffer-Meta_002dData.html | 100 +++ + pyme-web/doc/gpgme/Decrypt-and-Verify.html | 79 +++ + pyme-web/doc/gpgme/Decrypt.html | 123 ++++ + pyme-web/doc/gpgme/Deleting-Keys.html | 67 ++ + pyme-web/doc/gpgme/Destroying-Contexts.html | 46 ++ + pyme-web/doc/gpgme/Destroying-Data-Buffers.html | 70 +++ + pyme-web/doc/gpgme/Encrypt.html | 45 ++ + pyme-web/doc/gpgme/Encrypting-a-Plaintext.html | 147 +++++ + pyme-web/doc/gpgme/Engine-Configuration.html | 65 ++ + pyme-web/doc/gpgme/Engine-Information.html | 119 ++++ + pyme-web/doc/gpgme/Engine-Version-Check.html | 48 ++ + pyme-web/doc/gpgme/Error-Codes.html | 133 ++++ + pyme-web/doc/gpgme/Error-Handling.html | 72 +++ + pyme-web/doc/gpgme/Error-Sources.html | 89 +++ + pyme-web/doc/gpgme/Error-Strings.html | 80 +++ + pyme-web/doc/gpgme/Error-Values.html | 159 +++++ + pyme-web/doc/gpgme/Exchanging-Data.html | 58 ++ + pyme-web/doc/gpgme/Exporting-Keys.html | 101 +++ + pyme-web/doc/gpgme/Features.html | 59 ++ + pyme-web/doc/gpgme/File-Based-Data-Buffers.html | 74 +++ + pyme-web/doc/gpgme/Function-and-Data-Index.html | 380 ++++++++++++ + pyme-web/doc/gpgme/Generating-Keys.html | 144 +++++ + pyme-web/doc/gpgme/Getting-Started.html | 55 ++ + pyme-web/doc/gpgme/Hash-Algorithms.html | 59 ++ + pyme-web/doc/gpgme/Header.html | 53 ++ + .../doc/gpgme/I_002fO-Callback-Example-GDK.html | 85 +++ + .../gpgme/I_002fO-Callback-Example-GTK_002b.html | 86 +++ + .../doc/gpgme/I_002fO-Callback-Example-Qt.html | 99 +++ + pyme-web/doc/gpgme/I_002fO-Callback-Example.html | 259 ++++++++ + pyme-web/doc/gpgme/I_002fO-Callback-Interface.html | 142 +++++ + pyme-web/doc/gpgme/Importing-Keys.html | 171 +++++ + pyme-web/doc/gpgme/Included-Certificates.html | 70 +++ + pyme-web/doc/gpgme/Information-About-Keys.html | 207 +++++++ + .../doc/gpgme/Information-About-Trust-Items.html | 75 +++ + pyme-web/doc/gpgme/Introduction.html | 53 ++ + pyme-web/doc/gpgme/Key-Listing-Mode.html | 99 +++ + pyme-web/doc/gpgme/Key-Management.html | 260 ++++++++ + pyme-web/doc/gpgme/Key-Signatures.html | 130 ++++ + .../doc/gpgme/Largefile-Support-_0028LFS_0029.html | 110 ++++ + pyme-web/doc/gpgme/Library-Copying.html | 542 ++++++++++++++++ + pyme-web/doc/gpgme/Library-Version-Check.html | 97 +++ + pyme-web/doc/gpgme/Listing-Keys.html | 204 ++++++ + pyme-web/doc/gpgme/Listing-Trust-Items.html | 88 +++ + pyme-web/doc/gpgme/Locale.html | 69 +++ + pyme-web/doc/gpgme/Manipulating-Data-Buffers.html | 45 ++ + pyme-web/doc/gpgme/Manipulating-Keys.html | 63 ++ + pyme-web/doc/gpgme/Manipulating-Trust-Items.html | 62 ++ + pyme-web/doc/gpgme/Memory-Based-Data-Buffers.html | 107 ++++ + pyme-web/doc/gpgme/Multi-Threading.html | 93 +++ + pyme-web/doc/gpgme/OpenPGP.html | 44 ++ + pyme-web/doc/gpgme/Overview.html | 57 ++ + pyme-web/doc/gpgme/Passphrase-Callback.html | 101 +++ + pyme-web/doc/gpgme/Preparation.html | 54 ++ + pyme-web/doc/gpgme/Progress-Meter-Callback.html | 80 +++ + pyme-web/doc/gpgme/Protocol-Selection.html | 60 ++ + pyme-web/doc/gpgme/Protocols-and-Engines.html | 82 +++ + pyme-web/doc/gpgme/Public-Key-Algorithms.html | 74 +++ + .../doc/gpgme/Registering-I_002fO-Callbacks.html | 81 +++ + pyme-web/doc/gpgme/Run-Control.html | 53 ++ + pyme-web/doc/gpgme/Selecting-Signers.html | 64 ++ + pyme-web/doc/gpgme/Sign.html | 50 ++ + pyme-web/doc/gpgme/Signal-Handling.html | 61 ++ + pyme-web/doc/gpgme/Signature-Notation-Data.html | 85 +++ + pyme-web/doc/gpgme/Text-Mode.html | 63 ++ + pyme-web/doc/gpgme/Trust-Item-Management.html | 68 ++ + pyme-web/doc/gpgme/Using-Automake.html | 74 +++ + pyme-web/doc/gpgme/Using-External-Event-Loops.html | 74 +++ + pyme-web/doc/gpgme/Using-Libtool.html | 44 ++ + pyme-web/doc/gpgme/Verify.html | 492 +++++++++++++++ + pyme-web/doc/gpgme/Waiting-For-Completion.html | 77 +++ + pyme-web/doc/gpgme/gpgme.html | 251 -------- + pyme-web/doc/gpgme/gpgme_1.html | 76 --- + pyme-web/doc/gpgme/gpgme_10.html | 61 -- + pyme-web/doc/gpgme/gpgme_11.html | 130 ---- + pyme-web/doc/gpgme/gpgme_12.html | 82 --- + pyme-web/doc/gpgme/gpgme_13.html | 130 ---- + pyme-web/doc/gpgme/gpgme_14.html | 108 ---- + pyme-web/doc/gpgme/gpgme_15.html | 69 --- + pyme-web/doc/gpgme/gpgme_16.html | 169 ----- + pyme-web/doc/gpgme/gpgme_17.html | 63 -- + pyme-web/doc/gpgme/gpgme_18.html | 63 -- + pyme-web/doc/gpgme/gpgme_19.html | 66 -- + pyme-web/doc/gpgme/gpgme_2.html | 79 --- + pyme-web/doc/gpgme/gpgme_20.html | 120 ---- + pyme-web/doc/gpgme/gpgme_21.html | 102 --- + pyme-web/doc/gpgme/gpgme_22.html | 108 ---- + pyme-web/doc/gpgme/gpgme_23.html | 237 ------- + pyme-web/doc/gpgme/gpgme_24.html | 154 ----- + pyme-web/doc/gpgme/gpgme_25.html | 248 -------- + pyme-web/doc/gpgme/gpgme_26.html | 107 ---- + pyme-web/doc/gpgme/gpgme_27.html | 80 --- + pyme-web/doc/gpgme/gpgme_28.html | 67 -- + pyme-web/doc/gpgme/gpgme_29.html | 164 ----- + pyme-web/doc/gpgme/gpgme_3.html | 86 --- + pyme-web/doc/gpgme/gpgme_30.html | 106 ---- + pyme-web/doc/gpgme/gpgme_31.html | 232 ------- + pyme-web/doc/gpgme/gpgme_32.html | 85 --- + pyme-web/doc/gpgme/gpgme_33.html | 223 ------- + pyme-web/doc/gpgme/gpgme_34.html | 83 --- + pyme-web/doc/gpgme/gpgme_35.html | 70 --- + pyme-web/doc/gpgme/gpgme_36.html | 63 -- + pyme-web/doc/gpgme/gpgme_37.html | 66 -- + pyme-web/doc/gpgme/gpgme_38.html | 86 --- + pyme-web/doc/gpgme/gpgme_39.html | 79 --- + pyme-web/doc/gpgme/gpgme_4.html | 83 --- + pyme-web/doc/gpgme/gpgme_40.html | 89 --- + pyme-web/doc/gpgme/gpgme_41.html | 99 --- + pyme-web/doc/gpgme/gpgme_42.html | 144 ----- + pyme-web/doc/gpgme/gpgme_43.html | 152 ----- + pyme-web/doc/gpgme/gpgme_44.html | 112 ---- + pyme-web/doc/gpgme/gpgme_45.html | 101 --- + pyme-web/doc/gpgme/gpgme_46.html | 459 -------------- + pyme-web/doc/gpgme/gpgme_47.html | 292 --------- + pyme-web/doc/gpgme/gpgme_48.html | 363 ----------- + pyme-web/doc/gpgme/gpgme_49.html | 209 ------- + pyme-web/doc/gpgme/gpgme_5.html | 74 --- + pyme-web/doc/gpgme/gpgme_50.html | 88 --- + pyme-web/doc/gpgme/gpgme_51.html | 208 ------- + pyme-web/doc/gpgme/gpgme_52.html | 154 ----- + pyme-web/doc/gpgme/gpgme_53.html | 291 --------- + pyme-web/doc/gpgme/gpgme_54.html | 91 --- + pyme-web/doc/gpgme/gpgme_55.html | 107 ---- + pyme-web/doc/gpgme/gpgme_56.html | 140 ----- + pyme-web/doc/gpgme/gpgme_57.html | 106 ---- + pyme-web/doc/gpgme/gpgme_58.html | 89 --- + pyme-web/doc/gpgme/gpgme_59.html | 97 --- + pyme-web/doc/gpgme/gpgme_6.html | 77 --- + pyme-web/doc/gpgme/gpgme_60.html | 142 ----- + pyme-web/doc/gpgme/gpgme_61.html | 626 ------------------- + pyme-web/doc/gpgme/gpgme_62.html | 107 ---- + pyme-web/doc/gpgme/gpgme_63.html | 67 -- + pyme-web/doc/gpgme/gpgme_64.html | 95 --- + pyme-web/doc/gpgme/gpgme_65.html | 233 ------- + pyme-web/doc/gpgme/gpgme_66.html | 65 -- + pyme-web/doc/gpgme/gpgme_67.html | 220 ------- + pyme-web/doc/gpgme/gpgme_68.html | 75 --- + pyme-web/doc/gpgme/gpgme_69.html | 119 ---- + pyme-web/doc/gpgme/gpgme_7.html | 123 ---- + pyme-web/doc/gpgme/gpgme_70.html | 107 ---- + pyme-web/doc/gpgme/gpgme_71.html | 218 ------- + pyme-web/doc/gpgme/gpgme_72.html | 134 ---- + pyme-web/doc/gpgme/gpgme_73.html | 299 --------- + pyme-web/doc/gpgme/gpgme_74.html | 103 ---- + pyme-web/doc/gpgme/gpgme_75.html | 104 ---- + pyme-web/doc/gpgme/gpgme_76.html | 118 ---- + pyme-web/doc/gpgme/gpgme_77.html | 95 --- + pyme-web/doc/gpgme/gpgme_78.html | 71 --- + pyme-web/doc/gpgme/gpgme_79.html | 686 --------------------- + pyme-web/doc/gpgme/gpgme_8.html | 155 ----- + pyme-web/doc/gpgme/gpgme_80.html | 120 ---- + pyme-web/doc/gpgme/gpgme_81.html | 278 --------- + pyme-web/doc/gpgme/gpgme_82.html | 272 -------- + pyme-web/doc/gpgme/gpgme_83.html | 180 ------ + pyme-web/doc/gpgme/gpgme_84.html | 99 --- + pyme-web/doc/gpgme/gpgme_9.html | 104 ---- + pyme-web/doc/gpgme/gpgme_abt.html | 206 ------- + pyme-web/doc/gpgme/gpgme_fot.html | 53 -- + pyme-web/doc/gpgme/gpgme_ovr.html | 68 -- + pyme-web/doc/gpgme/gpgme_toc.html | 247 -------- + pyme-web/doc/gpgme/index.html | 497 ++++++++------- + 176 files changed, 9054 insertions(+), 13378 deletions(-) + +commit 163c1053dc761682f5a4231da163bdd0ff7162d7 +Author: belyi +Date: Tue Apr 1 21:14:29 2008 +0000 + + Update Home page to be a bit more visitor friendly. + + pyme-web/Makefile | 2 +- + pyme-web/default.css | 27 ++++++++++++++++++++ + pyme-web/index.html | 70 +++++++++++++++++++++++++++++++++++----------------- + 3 files changed, 75 insertions(+), 24 deletions(-) + +commit 05db2d17d8fda0ab8c948bbdc0643dfc1466830d +Author: belyi +Date: Sun Mar 30 21:27:38 2008 +0000 + + Add a rule to build binary distribution for Windows. + + pyme/Makefile | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +commit 57acb1089f5f8c24323ee62fc0a7f492a496b9c0 +Author: belyi +Date: Sat Mar 29 22:50:11 2008 +0000 + + Switch to using central location for python files (pycentral) + Update docs rule to fix location of the python source files. + + pyme/Makefile | 5 +++- + pyme/debian/changelog | 4 ++- + pyme/debian/control | 74 +++++------------------------------------------ + pyme/debian/dirs | 2 -- + pyme/debian/docs | 1 + + pyme/debian/postinst.ex | 48 ------------------------------ + pyme/debian/postrm.ex | 38 ------------------------ + pyme/debian/preinst.ex | 44 ---------------------------- + pyme/debian/prerm.ex | 39 ------------------------- + pyme/debian/rules | 50 ++++++-------------------------- + pyme/debian/setup.cfg-2.2 | 8 ----- + pyme/debian/setup.cfg-2.3 | 8 ----- + pyme/debian/setup.cfg-2.4 | 8 ----- + pyme/gpgme-h-clean.py | 2 +- + pyme/pyme/core.py | 2 +- + pyme/pyme/util.py | 2 +- + 16 files changed, 28 insertions(+), 307 deletions(-) + +commit 2b56fd10517cfbcffaa4ba98d8ea42f40f0d38a9 +Author: belyi +Date: Sun Mar 23 02:01:12 2008 +0000 + + Turn SWIG's autodoc feature on. Ignore 'next' in the types which are lists now. + Use new style for class declarations. Specify None as a default value for + core.check_version() method. Update version.py for 0.8.0 version. + + pyme/examples/pygpa.py | 2 +- + pyme/gpgme.i | 5 +++++ + pyme/pyme/core.py | 2 +- + pyme/pyme/util.py | 5 +++-- + pyme/pyme/version.py | 6 +++--- + 5 files changed, 13 insertions(+), 7 deletions(-) + +commit df5e25d7ee4dc0aa0d429f9d009322dd8ac33bb8 +Author: belyi +Date: Thu Mar 20 19:07:00 2008 +0000 + + Improve matching for DEPRECATED typedefs + + pyme/gpgme-h-clean.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +commit 78d8fc732848ac267ec65e9069265cd500587cdf +Author: belyi +Date: Wed Mar 19 19:28:40 2008 +0000 + + Update API to use list when types containing 'next' field are return. + Update examples accordingly + Add verifydetails.py example + Start adding bullets for 0.8.0 version. + + pyme/Makefile | 2 +- + pyme/debian/changelog | 14 +++++++- + pyme/examples/PyGtkGpgKeys.py | 53 +++++++++++++-------------- + pyme/examples/delkey.py | 7 ++-- + pyme/examples/encrypt-to-all.py | 7 ++-- + pyme/examples/exportimport.py | 7 ++-- + pyme/examples/pygpa.py | 70 ++++++++++++++++-------------------- + pyme/examples/signverify.py | 11 +++--- + pyme/examples/verifydetails.py | 79 +++++++++++++++++++++++++++++++++++++++++ + pyme/gpgme.i | 19 +++++++++- + 10 files changed, 180 insertions(+), 89 deletions(-) + +commit 342d85b07475e7360bcd62804bf5facda039494f +Author: belyi +Date: Mon Mar 10 01:14:16 2008 +0000 + + Change references to source files so that they point to the WebCVS browse + location. + + pyme-web/doc/pyme/index.html | 2 +- + pyme-web/doc/pyme/pyme.callbacks.html | 2 +- + pyme-web/doc/pyme/pyme.constants.data.encoding.html | 2 +- + pyme-web/doc/pyme/pyme.constants.data.html | 2 +- + pyme-web/doc/pyme/pyme.constants.event.html | 2 +- + pyme-web/doc/pyme/pyme.constants.html | 2 +- + pyme-web/doc/pyme/pyme.constants.import.html | 2 +- + pyme-web/doc/pyme/pyme.constants.keylist.html | 2 +- + pyme-web/doc/pyme/pyme.constants.keylist.mode.html | 2 +- + pyme-web/doc/pyme/pyme.constants.md.html | 2 +- + pyme-web/doc/pyme/pyme.constants.pk.html | 2 +- + pyme-web/doc/pyme/pyme.constants.protocol.html | 2 +- + pyme-web/doc/pyme/pyme.constants.sig.html | 2 +- + pyme-web/doc/pyme/pyme.constants.sig.mode.html | 2 +- + pyme-web/doc/pyme/pyme.constants.sigsum.html | 2 +- + pyme-web/doc/pyme/pyme.constants.status.html | 2 +- + pyme-web/doc/pyme/pyme.constants.validity.html | 2 +- + pyme-web/doc/pyme/pyme.core.html | 2 +- + pyme-web/doc/pyme/pyme.errors.html | 2 +- + pyme-web/doc/pyme/pyme.html | 2 +- + pyme-web/doc/pyme/pyme.util.html | 2 +- + pyme-web/doc/pyme/pyme.version.html | 2 +- + 22 files changed, 22 insertions(+), 22 deletions(-) + +commit 4139dd1d066c1a6c892d84fe45dc3e6c4aa1b803 +Author: belyi +Date: Sat Mar 8 18:21:08 2008 +0000 + + Add core.check_version(None) to all examples since this function is used by + Gpgme to do internal initialization. Update debian/rules to use dh_pysupport + instead of deprecated dh_python. + + pyme/debian/rules | 8 +++----- + pyme/examples/PyGtkGpgKeys.py | 7 ++++++- + pyme/examples/delkey.py | 2 ++ + pyme/examples/encrypt-to-all.py | 3 +++ + pyme/examples/exportimport.py | 2 ++ + pyme/examples/genkey.py | 1 + + pyme/examples/inter-edit.py | 3 +++ + pyme/examples/pygpa.py | 5 +++++ + pyme/examples/sign.py | 2 ++ + pyme/examples/signverify.py | 2 ++ + pyme/examples/simple.py | 2 ++ + pyme/examples/t-edit.py | 3 +++ + 12 files changed, 34 insertions(+), 6 deletions(-) + +commit ae76c6176457dd38e0634cbc17d794294a3a81d2 +Author: belyi +Date: Wed Apr 12 22:20:38 2006 +0000 + + Change name of internal package name from 'gpgme' to 'pygpgme' to avoid + conflict with gpgme.dll on Windows. + Fix build with SWIG 1.3.28. + Change version to 0.7.1 in a preparation for new release. + + pyme/Makefile | 3 +- + pyme/debian/changelog | 12 ++++ + pyme/gpgme.i | 19 +++--- + pyme/pyme/callbacks.py | 1 - + pyme/pyme/core.py | 153 +++++++++++++++++++++++++------------------------ + pyme/pyme/errors.py | 12 ++-- + pyme/pyme/util.py | 10 ++-- + pyme/pyme/version.py | 2 +- + pyme/setup.py | 4 +- + 9 files changed, 116 insertions(+), 100 deletions(-) + +commit d644383a76e9f83bc2d426628319e3c4a989dc2d +Author: belyi +Date: Sat Dec 17 01:34:53 2005 +0000 + + Put all constants into pyme.constants package to avoid stepping on python + reserved words. + Add build rules for Mingw32 and Cygwin on Windows. Rules for Mingw under + Debian are still to come. + Fixed a small bug in pygpa.py example. + + pyme/Makefile | 11 ++++++++--- + pyme/examples/pygpa.py | 3 ++- + pyme/pyme/__init__.py | 2 +- + pyme/pyme/constants/__init__.py | 3 +++ + pyme/setup.py | 42 ++++++++++++++++++++++++++++++++++++----- + 5 files changed, 51 insertions(+), 10 deletions(-) + +commit 89eb370fcaa8adc9d219eadbaa579dde7bf06329 +Author: belyi +Date: Mon Aug 1 03:08:32 2005 +0000 + + Imported changes provided by Joost van Baal: + Use dh_python in debian/rules and change the Section pyme belongs to from + 'libs' to 'python'. + + pyme/debian/control | 6 +++--- + pyme/debian/rules | 2 ++ + 2 files changed, 5 insertions(+), 3 deletions(-) + +commit ad76d10c2a77b45b7459c62131279e946b860891 +Author: belyi +Date: Fri Jun 10 03:01:22 2005 +0000 + + Update 'docs' rule in Makefile to build packages first to ensure that + documentation is build for the current version of pyme and not for the + installed one. + + Added 'callbacks' into the list of visible pyme modules (__all__ var.) + + Slightly updated INSTALL file. + + pyme/INSTALL | 11 ++++++++--- + pyme/Makefile | 4 ++-- + pyme/pyme/__init__.py | 2 +- + 3 files changed, 11 insertions(+), 6 deletions(-) + +commit 2fe1a81e00721698bfa6850b3db2eb85e43d1724 +Author: belyi +Date: Wed Jun 8 16:16:18 2005 +0000 + + Update pyme documentation to remove dead links to pyme.gpgme.html and + pyme._gpgme.html + Added reference to the installed GPGME and PyMe documentation to the head + web page. + Updated Makefile to install all *.html files and to clean *~ files in all + subdirectories + + pyme-web/Makefile | 10 ++++++---- + pyme-web/doc/pyme/index.html | 8 +++----- + pyme-web/doc/pyme/pyme.callbacks.html | 8 -------- + pyme-web/doc/pyme/pyme.core.html | 1 - + pyme-web/doc/pyme/pyme.errors.html | 8 -------- + pyme-web/doc/pyme/pyme.html | 8 +++----- + pyme-web/doc/pyme/pyme.util.html | 8 -------- + pyme-web/index.html | 9 +++++++-- + 8 files changed, 19 insertions(+), 41 deletions(-) + +commit 6aa34cce4ea0099e50b4936dfee59778157b8ca8 +Author: belyi +Date: Wed Jun 8 15:18:20 2005 +0000 + + Added pyme and gpgme documentation. + + pyme-web/doc/gpgme/gpgme.html | 251 ++++++++ + pyme-web/doc/gpgme/gpgme_1.html | 76 +++ + pyme-web/doc/gpgme/gpgme_10.html | 61 ++ + pyme-web/doc/gpgme/gpgme_11.html | 130 ++++ + pyme-web/doc/gpgme/gpgme_12.html | 82 +++ + pyme-web/doc/gpgme/gpgme_13.html | 130 ++++ + pyme-web/doc/gpgme/gpgme_14.html | 108 ++++ + pyme-web/doc/gpgme/gpgme_15.html | 69 +++ + pyme-web/doc/gpgme/gpgme_16.html | 169 +++++ + pyme-web/doc/gpgme/gpgme_17.html | 63 ++ + pyme-web/doc/gpgme/gpgme_18.html | 63 ++ + pyme-web/doc/gpgme/gpgme_19.html | 66 ++ + pyme-web/doc/gpgme/gpgme_2.html | 79 +++ + pyme-web/doc/gpgme/gpgme_20.html | 120 ++++ + pyme-web/doc/gpgme/gpgme_21.html | 102 +++ + pyme-web/doc/gpgme/gpgme_22.html | 108 ++++ + pyme-web/doc/gpgme/gpgme_23.html | 237 +++++++ + pyme-web/doc/gpgme/gpgme_24.html | 154 +++++ + pyme-web/doc/gpgme/gpgme_25.html | 248 ++++++++ + pyme-web/doc/gpgme/gpgme_26.html | 107 ++++ + pyme-web/doc/gpgme/gpgme_27.html | 80 +++ + pyme-web/doc/gpgme/gpgme_28.html | 67 ++ + pyme-web/doc/gpgme/gpgme_29.html | 164 +++++ + pyme-web/doc/gpgme/gpgme_3.html | 86 +++ + pyme-web/doc/gpgme/gpgme_30.html | 106 ++++ + pyme-web/doc/gpgme/gpgme_31.html | 232 +++++++ + pyme-web/doc/gpgme/gpgme_32.html | 85 +++ + pyme-web/doc/gpgme/gpgme_33.html | 223 +++++++ + pyme-web/doc/gpgme/gpgme_34.html | 83 +++ + pyme-web/doc/gpgme/gpgme_35.html | 70 +++ + pyme-web/doc/gpgme/gpgme_36.html | 63 ++ + pyme-web/doc/gpgme/gpgme_37.html | 66 ++ + pyme-web/doc/gpgme/gpgme_38.html | 86 +++ + pyme-web/doc/gpgme/gpgme_39.html | 79 +++ + pyme-web/doc/gpgme/gpgme_4.html | 83 +++ + pyme-web/doc/gpgme/gpgme_40.html | 89 +++ + pyme-web/doc/gpgme/gpgme_41.html | 99 +++ + pyme-web/doc/gpgme/gpgme_42.html | 144 +++++ + pyme-web/doc/gpgme/gpgme_43.html | 152 +++++ + pyme-web/doc/gpgme/gpgme_44.html | 112 ++++ + pyme-web/doc/gpgme/gpgme_45.html | 101 +++ + pyme-web/doc/gpgme/gpgme_46.html | 459 ++++++++++++++ + pyme-web/doc/gpgme/gpgme_47.html | 292 +++++++++ + pyme-web/doc/gpgme/gpgme_48.html | 363 +++++++++++ + pyme-web/doc/gpgme/gpgme_49.html | 209 +++++++ + pyme-web/doc/gpgme/gpgme_5.html | 74 +++ + pyme-web/doc/gpgme/gpgme_50.html | 88 +++ + pyme-web/doc/gpgme/gpgme_51.html | 208 +++++++ + pyme-web/doc/gpgme/gpgme_52.html | 154 +++++ + pyme-web/doc/gpgme/gpgme_53.html | 291 +++++++++ + pyme-web/doc/gpgme/gpgme_54.html | 91 +++ + pyme-web/doc/gpgme/gpgme_55.html | 107 ++++ + pyme-web/doc/gpgme/gpgme_56.html | 140 +++++ + pyme-web/doc/gpgme/gpgme_57.html | 106 ++++ + pyme-web/doc/gpgme/gpgme_58.html | 89 +++ + pyme-web/doc/gpgme/gpgme_59.html | 97 +++ + pyme-web/doc/gpgme/gpgme_6.html | 77 +++ + pyme-web/doc/gpgme/gpgme_60.html | 142 +++++ + pyme-web/doc/gpgme/gpgme_61.html | 626 +++++++++++++++++++ + pyme-web/doc/gpgme/gpgme_62.html | 107 ++++ + pyme-web/doc/gpgme/gpgme_63.html | 67 ++ + pyme-web/doc/gpgme/gpgme_64.html | 95 +++ + pyme-web/doc/gpgme/gpgme_65.html | 233 +++++++ + pyme-web/doc/gpgme/gpgme_66.html | 65 ++ + pyme-web/doc/gpgme/gpgme_67.html | 220 +++++++ + pyme-web/doc/gpgme/gpgme_68.html | 75 +++ + pyme-web/doc/gpgme/gpgme_69.html | 119 ++++ + pyme-web/doc/gpgme/gpgme_7.html | 123 ++++ + pyme-web/doc/gpgme/gpgme_70.html | 107 ++++ + pyme-web/doc/gpgme/gpgme_71.html | 218 +++++++ + pyme-web/doc/gpgme/gpgme_72.html | 134 ++++ + pyme-web/doc/gpgme/gpgme_73.html | 299 +++++++++ + pyme-web/doc/gpgme/gpgme_74.html | 103 ++++ + pyme-web/doc/gpgme/gpgme_75.html | 104 ++++ + pyme-web/doc/gpgme/gpgme_76.html | 118 ++++ + pyme-web/doc/gpgme/gpgme_77.html | 95 +++ + pyme-web/doc/gpgme/gpgme_78.html | 71 +++ + pyme-web/doc/gpgme/gpgme_79.html | 686 +++++++++++++++++++++ + pyme-web/doc/gpgme/gpgme_8.html | 155 +++++ + pyme-web/doc/gpgme/gpgme_80.html | 120 ++++ + pyme-web/doc/gpgme/gpgme_81.html | 278 +++++++++ + pyme-web/doc/gpgme/gpgme_82.html | 272 ++++++++ + pyme-web/doc/gpgme/gpgme_83.html | 180 ++++++ + pyme-web/doc/gpgme/gpgme_84.html | 99 +++ + pyme-web/doc/gpgme/gpgme_9.html | 104 ++++ + pyme-web/doc/gpgme/gpgme_abt.html | 206 +++++++ + pyme-web/doc/gpgme/gpgme_fot.html | 53 ++ + pyme-web/doc/gpgme/gpgme_ovr.html | 68 ++ + pyme-web/doc/gpgme/gpgme_toc.html | 247 ++++++++ + pyme-web/doc/gpgme/index.html | 251 ++++++++ + pyme-web/doc/pyme/index.html | 166 +++++ + pyme-web/doc/pyme/pyme.callbacks.html | 50 ++ + .../doc/pyme/pyme.constants.data.encoding.html | 48 ++ + pyme-web/doc/pyme/pyme.constants.data.html | 29 + + pyme-web/doc/pyme/pyme.constants.event.html | 48 ++ + pyme-web/doc/pyme/pyme.constants.html | 39 ++ + pyme-web/doc/pyme/pyme.constants.import.html | 49 ++ + pyme-web/doc/pyme/pyme.constants.keylist.html | 29 + + pyme-web/doc/pyme/pyme.constants.keylist.mode.html | 48 ++ + pyme-web/doc/pyme/pyme.constants.md.html | 58 ++ + pyme-web/doc/pyme/pyme.constants.pk.html | 50 ++ + pyme-web/doc/pyme/pyme.constants.protocol.html | 46 ++ + pyme-web/doc/pyme/pyme.constants.sig.html | 29 + + pyme-web/doc/pyme/pyme.constants.sig.mode.html | 47 ++ + pyme-web/doc/pyme/pyme.constants.sigsum.html | 55 ++ + pyme-web/doc/pyme/pyme.constants.status.html | 117 ++++ + pyme-web/doc/pyme/pyme.constants.validity.html | 50 ++ + pyme-web/doc/pyme/pyme.core.html | 254 ++++++++ + pyme-web/doc/pyme/pyme.errors.html | 90 +++ + pyme-web/doc/pyme/pyme.html | 166 +++++ + pyme-web/doc/pyme/pyme.util.html | 78 +++ + pyme-web/doc/pyme/pyme.version.html | 37 ++ + pyme-web/index.html | 6 +- + 113 files changed, 14966 insertions(+), 1 deletion(-) + +commit 2d6fe54479f042644f7b0f3d2fe35877d2056144 +Author: belyi +Date: Thu May 19 02:06:09 2005 +0000 + + Added INSTALL file. + + pyme/INSTALL | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +commit d6892fff0c3cedf41dba4c25ab8608e7f2bc039c +Author: belyi +Date: Tue May 17 16:49:28 2005 +0000 + + Update copyright note on simple.py + + pyme/examples/simple.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +commit c2cd9cdf5995843aad7b200b929db2969effc9d2 +Author: belyi +Date: Tue May 17 15:03:58 2005 +0000 + + Update simple.py to catch errors. + + pyme/examples/simple.py | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +commit eaedae7c6a0ea993caab067efe781a59b6769c44 +Author: belyi +Date: Tue May 17 01:18:23 2005 +0000 + + Added 'PYTHON = python' into Makefile for bug #1199122 + + pyme/Makefile | 1 + + pyme/examples/signverify.py | 1 + + 2 files changed, 2 insertions(+) + +commit 56fd244bb2636a4d58629899ea3cde1d96428198 +Author: belyi +Date: Wed Apr 27 21:37:06 2005 +0000 + + Added pygpa example. + + pyme/debian/changelog | 3 +- + pyme/examples/pygpa.glade | 5546 +++++++++++++++++++++++++++++++++++++++++++++ + pyme/examples/pygpa.py | 1459 ++++++++++++ + 3 files changed, 7007 insertions(+), 1 deletion(-) + +commit 2d9a2a91a59ac3fee5410c953b7e0859e9e7cd35 +Author: belyi +Date: Thu Apr 21 15:17:51 2005 +0000 + + Change version to 0.7.0 due to the change in license. + + pyme/debian/changelog | 2 +- + pyme/pyme/version.py | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +commit 94e34e38d742f145385bd235825b6ba1e30d8339 +Author: belyi +Date: Thu Apr 21 03:53:12 2005 +0000 + + Changed license on PyMe from GPL to LGPL. + PyMe examples keep GPL license. + + pyme/COPYING.LESSER | 510 +++++++++++++++++++++++++++++++++++ + pyme/Makefile | 20 +- + pyme/debian/changelog | 4 +- + pyme/debian/copyright | 22 +- + pyme/gpgme-h-clean.py | 16 ++ + pyme/gpgme.i | 20 +- + pyme/helpers.c | 20 +- + pyme/helpers.h | 20 +- + pyme/pyme/__init__.py | 20 +- + pyme/pyme/callbacks.py | 20 +- + pyme/pyme/constants/data/encoding.py | 20 +- + pyme/pyme/constants/event.py | 20 +- + pyme/pyme/constants/import.py | 20 +- + pyme/pyme/constants/keylist/mode.py | 20 +- + pyme/pyme/constants/md.py | 20 +- + pyme/pyme/constants/pk.py | 20 +- + pyme/pyme/constants/protocol.py | 20 +- + pyme/pyme/constants/sig/mode.py | 20 +- + pyme/pyme/constants/sigsum.py | 20 +- + pyme/pyme/constants/status.py | 20 +- + pyme/pyme/constants/validity.py | 20 +- + pyme/pyme/core.py | 20 +- + pyme/pyme/errors.py | 20 +- + pyme/pyme/util.py | 20 +- + pyme/pyme/version.py | 22 +- + pyme/setup.py | 20 +- + 26 files changed, 761 insertions(+), 233 deletions(-) + +commit 0d8aa0f6335cb1506a37085095ed45173b099a02 +Author: belyi +Date: Tue Apr 19 01:46:06 2005 +0000 + + Added __hash__ and __eq__ methods to GpgmeWrapper to allow both Context() + and Data() to be used as a dictionary key. + Changed core.wait() function to always return a tuple. On timeout now it + returns (0, None) instead of just None. Plus, return context is now a + Context() object instead of a wrapper return by underlying gpgme. + + pyme/helpers.c | 1 - + pyme/pyme/core.py | 25 +++++++++++++++---------- + pyme/pyme/util.py | 9 +++++++++ + 3 files changed, 24 insertions(+), 11 deletions(-) + +commit 63ff6d10637be1dcbcd78c939ac1ef1ac30b1024 +Author: belyi +Date: Wed Apr 6 04:58:40 2005 +0000 + + Made hook parameter optional in passphrase_cb and progress_cb. + Allowed None for callbacks to unset ones set previously. + Removed cleanup of exception in callbacks - now just retrieve the error code. + Added prev_bad parameter in passphrase_cb since it can be used in + change password protocols. + Updated examples to follow new sets of arguments in callbacks + Updated op_edit to check if passed key is None (otherwise gpgme dumps core) + God rid of annoying warning "function declaration isn't a prototype" in + helpers.c and helpers.h by changing from () to (void) list of arguments. + + pyme/debian/changelog | 10 +++++--- + pyme/examples/signverify.py | 2 +- + pyme/examples/t-edit.py | 2 +- + pyme/gpgme.i | 18 +++++++++----- + pyme/helpers.c | 60 ++++++++++++++++++++++++++++++--------------- + pyme/helpers.h | 4 +-- + pyme/pyme/callbacks.py | 6 +++-- + pyme/pyme/core.py | 47 +++++++++++++++++++++-------------- + pyme/pyme/errors.py | 2 +- + 9 files changed, 96 insertions(+), 55 deletions(-) + +commit 8f0ab8138c7aa190936376ccbbf33bb09c64d6f1 +Author: belyi +Date: Thu Mar 31 23:50:59 2005 +0000 + + Added exception handling in passphrase_cb and edit_cb. If GPGMEError + exception is thrown in those callbacks it will be converted into its + core representation and return as an error code to the caller. + On all other exceptions error code will be GPG_ERR_GENERAL. + + pyme/Makefile | 1 + + pyme/debian/changelog | 8 ++++++++ + pyme/gpgme.i | 20 ++++++++++++++------ + pyme/helpers.c | 51 +++++++++++++++++++++++++++++++++++++++++++++------ + pyme/helpers.h | 3 +++ + 5 files changed, 71 insertions(+), 12 deletions(-) + +commit 9903d1fb11231e7e3d920e58d1ecb674c5988b07 +Author: belyi +Date: Thu Mar 31 05:12:15 2005 +0000 + + Remove workaround from Context.wait() method since the bug report and + patch fixing gpgme_wait's behavior is sent to GPMGE developers already. + Added errorcheck into op_edit() so that it can report an error. + + pyme/pyme/core.py | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +commit 45e8a5f4e13d3ca797ec3b0037242874a6be5562 +Author: belyi +Date: Sat Mar 26 19:44:18 2005 +0000 + + Updated verion number to 0.6.2 in version.py + Added examples/*.glade files into documentation package. + + pyme/debian/examples | 1 + + pyme/pyme/version.py | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +commit 270b87bb40e180cb6e8f1de9a0e8161525ffa4ab +Author: belyi +Date: Sat Mar 26 19:31:14 2005 +0000 + + Updated debian/changelog regarding PyGtkGpgKeys example and a fix in errors. + + pyme/debian/changelog | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +commit ea4682009a506db91e5174ffd038fe7e4406b591 +Author: belyi +Date: Sat Mar 26 19:25:36 2005 +0000 + + Added handling of right mouse button click. + Changed reporting a string instead of a number on key generation failure. + + pyme/examples/PyGtkGpgKeys.glade | 2 ++ + pyme/examples/PyGtkGpgKeys.py | 30 +++++++++++++++++++++++++++--- + 2 files changed, 29 insertions(+), 3 deletions(-) + +commit f65ad1a703d0098a3204fb8527a54d253e5847e7 +Author: belyi +Date: Sat Mar 26 18:11:11 2005 +0000 + + Added another column indicating if a key has a secret part. + Automated generation of the View menu from the view field of the KeyColumn + class. + + pyme/examples/PyGtkGpgKeys.glade | 93 ++-------------------------------------- + pyme/examples/PyGtkGpgKeys.py | 74 +++++++++++++++++--------------- + 2 files changed, 44 insertions(+), 123 deletions(-) + +commit b54e83a7a7a5785502f3c7e8b95f15e23b40e65a +Author: belyi +Date: Sat Mar 26 16:45:13 2005 +0000 + + Small change to the way gtk.TreeModel object is used. + + pyme/examples/PyGtkGpgKeys.py | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +commit 7078db75cef4c1fd70cf03e37172bdb4f933fd1b +Author: belyi +Date: Fri Mar 25 23:33:06 2005 +0000 + + Use more comprehansible error reporting since gpgme_strerror_r returns None + all the time. + + pyme/pyme/errors.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +commit 151213f4344d9984975721440af07de09e3df61c +Author: belyi +Date: Fri Mar 25 04:30:17 2005 +0000 + + Improved PyGtkGpgKeys example to manage owner_trust on keys. + Added another example inter-edit.py which is just a hepler to write + scripts for Context.op_edit() command. + + pyme/examples/PyGtkGpgKeys.glade | 78 ++++++++++++++++++++++++++++++++++++++++ + pyme/examples/PyGtkGpgKeys.py | 68 +++++++++++++++++++++++++++++++---- + pyme/examples/inter-edit.py | 54 ++++++++++++++++++++++++++++ + pyme/examples/t-edit.py | 18 ++++++++++ + 4 files changed, 212 insertions(+), 6 deletions(-) + +commit fc7235af217bcee5231ce7fbd7f234712d5ad3b0 +Author: belyi +Date: Fri Mar 25 00:30:39 2005 +0000 + + Updated PyGtkGpgKeys example to include import, export and reload + functionality. Also added ability to remove number of keys simultanously. + Rearanged how KeyColumn is used to avoid unnecessary sorts and duplication + of information in different parts of the code. + + pyme/examples/PyGtkGpgKeys.glade | 86 +++++++++- + pyme/examples/PyGtkGpgKeys.py | 332 ++++++++++++++++++++++++++++----------- + 2 files changed, 325 insertions(+), 93 deletions(-) + +commit 9f65749ccb1b7cab562e19c03f4371d5f7d94912 +Author: belyi +Date: Thu Mar 24 05:51:03 2005 +0000 + + Added example of PyGTK+ and PyMe integration. + For now it does only simple things - listing, deleting, and generating keys. + + pyme/examples/PyGtkGpgKeys.glade | 1321 +++++++++++++++++++++++++++++++++++++ + pyme/examples/PyGtkGpgKeys.gladep | 8 + + pyme/examples/PyGtkGpgKeys.py | 424 ++++++++++++ + 3 files changed, 1753 insertions(+) + +commit 59e23f32c3b46413c9ec09e23e1a385a110fb103 +Author: belyi +Date: Thu Mar 24 05:44:58 2005 +0000 + + Added wait method Context class which handles asynchornous calls a little + bit better than the one generated by SWIG. + + pyme/debian/changelog | 7 +++++++ + pyme/gpgme.i | 1 + + pyme/pyme/core.py | 40 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 48 insertions(+) + +commit 4c1b5259e4985df2cba0ae4fc09f12cd94603a75 +Author: belyi +Date: Tue Mar 22 18:29:31 2005 +0000 + + Added correct handling of Context.op_edit() method. + Added example/t-edit.py showing usage for this method. + Output of this example should match output of the tests/gpg/t-edit + from the GPGME test suite. + Remove unused static function from helpers.c + + pyme/examples/t-edit.py | 38 ++++++++++++++++++++++++++++++++++++++ + pyme/gpgme.i | 36 ++++++++++++++++++++++++++++++++++++ + pyme/helpers.c | 36 ------------------------------------ + pyme/pyme/core.py | 5 ++++- + 4 files changed, 78 insertions(+), 37 deletions(-) + +commit dc587e215283bfef2dd594f86a7b2945f74f5155 +Author: belyi +Date: Sat Mar 19 01:43:59 2005 +0000 + + Update changelog to include note about deprecated function in 0.6.1 release + + pyme/debian/changelog | 3 ++- + pyme/examples/encrypt-to-all.py | 3 +-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +commit 86de4b3ad777f980ccf7ba3462c85bbe1787d1fd +Author: belyi +Date: Sat Mar 19 01:40:07 2005 +0000 + + Remove deprecated functions from helpers.[ch] + Use gpgme-h-clean.py to remove deprecated functions and typedefs from + the GPGME header file. This will reduce the number of unused methods. + + pyme/Makefile | 4 ++-- + pyme/gpgme-h-clean.py | 26 ++++++++++++++++++++++++++ + pyme/helpers.c | 8 -------- + pyme/helpers.h | 2 -- + 4 files changed, 28 insertions(+), 12 deletions(-) + +commit 2483efcbd0d73c628c4d7717928a766c3b58f0aa +Author: belyi +Date: Fri Mar 18 22:15:52 2005 +0000 + + Update copyright and author values in pyme/version.py + Create rules to build distribution files - one full and one without + debian bits. + + pyme/Makefile | 28 ++++++++++++++++++++++------ + pyme/pyme/version.py | 12 ++++++------ + 2 files changed, 28 insertions(+), 12 deletions(-) + +commit 168593285380f5a7805f3dd08657d429a72d3621 +Author: belyi +Date: Fri Mar 18 19:09:33 2005 +0000 + + Added package building for python2.4 + + Updated copyright notes to include myslef and avoid confusion who's the + maintainer. In John's own words: "I'd prefer to just step out of the picture". + Jonh's copyright notice left intact. + + pyme/Makefile | 6 +++--- + pyme/debian/changelog | 7 +++++++ + pyme/debian/control | 30 +++++++++++++++++++++++++++--- + pyme/debian/copyright | 10 ++++------ + pyme/debian/rules | 4 ++++ + pyme/debian/setup.cfg-2.4 | 8 ++++++++ + pyme/examples/genkey.py | 4 ++-- + pyme/gpgme.i | 4 ++-- + pyme/helpers.c | 4 ++-- + pyme/helpers.h | 4 ++-- + pyme/pyme/__init__.py | 4 ++-- + pyme/pyme/callbacks.py | 4 ++-- + pyme/pyme/constants/data/encoding.py | 4 ++-- + pyme/pyme/constants/event.py | 4 ++-- + pyme/pyme/constants/import.py | 4 ++-- + pyme/pyme/constants/keylist/mode.py | 4 ++-- + pyme/pyme/constants/md.py | 4 ++-- + pyme/pyme/constants/pk.py | 4 ++-- + pyme/pyme/constants/protocol.py | 4 ++-- + pyme/pyme/constants/sig/mode.py | 4 ++-- + pyme/pyme/constants/sigsum.py | 4 ++-- + pyme/pyme/constants/status.py | 4 ++-- + pyme/pyme/constants/validity.py | 4 ++-- + pyme/pyme/core.py | 4 ++-- + pyme/pyme/errors.py | 4 ++-- + pyme/pyme/util.py | 4 ++-- + pyme/pyme/version.py | 2 +- + pyme/setup.py | 3 ++- + 28 files changed, 96 insertions(+), 54 deletions(-) + +commit 6dbbb252771133724b2879ed6d767cd708196dae +Author: belyi +Date: Fri Mar 18 18:04:35 2005 +0000 + + Remove the note about gpgme.i to be generated - it's been the primary source + for some time. + + pyme/gpgme.i | 6 ------ + 1 file changed, 6 deletions(-) + +commit 9d449fa4889c6bda6d14583c0625b8d5c4ffe759 +Author: belyi +Date: Fri May 7 18:31:22 2004 +0000 + + Added my copyright in genkey.py since there's enough changes made. + Updated signverify to use only keys generated by genkey.py, to check + that keys added to singers are able to sign and to check that the + list of signers is not empty. The last check is necessary to prevent + signing with the key of the user running signverify.py script. + Added delkey.py script to delete keys generated by genkey.py + Added exportimport.py example for key export/import. + + pyme/examples/delkey.py | 29 +++++++++++++++++ + pyme/examples/exportimport.py | 76 +++++++++++++++++++++++++++++++++++++++++++ + pyme/examples/genkey.py | 6 ++-- + pyme/examples/signverify.py | 18 ++++++---- + 4 files changed, 119 insertions(+), 10 deletions(-) + +commit df98c8d28245ad2c14b0ab50fc8f8932853bec8b +Author: belyi +Date: Tue May 4 17:34:15 2004 +0000 + + Added examples/signverify.py for unattended sing/verify. + Updated examples/genkey.py to work correctly. + Updated gpgme.i to allow None as a value for gpgme_data_t + + pyme/examples/genkey.py | 14 ++------- + pyme/examples/signverify.py | 72 +++++++++++++++++++++++++++++++++++++++++++++ + pyme/gpgme.i | 21 ++++++++----- + 3 files changed, 87 insertions(+), 20 deletions(-) + +commit ba45931abf530ab89ead46d7233ff1b62b629a18 +Author: belyi +Date: Thu Apr 8 16:15:09 2004 +0000 + + Ensure that we support only python2.2 and up. :-) + Use generators in core.Context class which makes pyme.aux obsolete + Remove importing future nested_scopes since they are standart starting + with python2.2 + + pyme/pyme/__init__.py | 5 ++--- + pyme/pyme/aux.py | 56 --------------------------------------------------- + pyme/pyme/core.py | 15 +++++++++++--- + pyme/pyme/errors.py | 1 - + pyme/pyme/util.py | 2 +- + 5 files changed, 15 insertions(+), 64 deletions(-) + +commit 4e9be5a55ecffa4da7ad5c192cc892eddaaa9586 +Author: belyi +Date: Sun Mar 21 03:53:30 2004 +0000 + + Small change to index.html + Added clean: rule to the Makefile + + pyme-web/Makefile | 3 +++ + pyme-web/index.html | 6 +++--- + 2 files changed, 6 insertions(+), 3 deletions(-) + +commit 2efb95176f4edf56ed61c9ac0c3aa09c56534df0 +Author: belyi +Date: Sun Mar 21 03:00:32 2004 +0000 + + Added Makefile rules for pyme module installation. + + pyme/Makefile | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +commit 2b83d5d8b513029cc3e54f2fa502ccc85618104b +Author: belyi +Date: Sun Mar 21 02:29:54 2004 +0000 + + Decorative change. + + pyme/pyme/aux.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit e3478015d763a036c1d806ae01433fce59712204 +Author: belyi +Date: Sun Mar 21 02:25:55 2004 +0000 + + Added RCS Id: tags + + pyme/Makefile | 1 + + pyme/examples/encrypt-to-all.py | 3 ++- + pyme/examples/genkey.py | 3 ++- + pyme/examples/sign.py | 3 ++- + pyme/examples/simple.py | 3 ++- + pyme/gpgme.i | 1 + + pyme/helpers.c | 1 + + pyme/helpers.h | 1 + + pyme/pyme/__init__.py | 1 + + pyme/pyme/aux.py | 1 + + pyme/pyme/callbacks.py | 1 + + pyme/pyme/constants/__init__.py | 2 ++ + pyme/pyme/constants/data/__init__.py | 2 ++ + pyme/pyme/constants/data/encoding.py | 1 + + pyme/pyme/constants/event.py | 1 + + pyme/pyme/constants/import.py | 1 + + pyme/pyme/constants/keylist/__init__.py | 2 ++ + pyme/pyme/constants/keylist/mode.py | 1 + + pyme/pyme/constants/md.py | 1 + + pyme/pyme/constants/pk.py | 1 + + pyme/pyme/constants/protocol.py | 1 + + pyme/pyme/constants/sig/__init__.py | 2 ++ + pyme/pyme/constants/sig/mode.py | 1 + + pyme/pyme/constants/sigsum.py | 1 + + pyme/pyme/constants/status.py | 1 + + pyme/pyme/constants/validity.py | 1 + + pyme/pyme/core.py | 1 + + pyme/pyme/errors.py | 1 + + pyme/pyme/util.py | 1 + + pyme/pyme/version.py | 2 ++ + 30 files changed, 39 insertions(+), 4 deletions(-) + +commit b3b3712645332c5bc3e8d9d557aab21d48ff0f86 +Author: belyi +Date: Sun Mar 21 02:07:36 2004 +0000 + + Added Id: RCS tags to all files. + + pyme-web/Makefile | 2 ++ + pyme-web/index.html | 3 ++- + 2 files changed, 4 insertions(+), 1 deletion(-) + +commit 6aea2426beaaa8c43e6f2310a37a2737c0c3a1b5 +Author: belyi +Date: Sun Mar 21 01:50:55 2004 +0000 + + Update example on the init pyme.html page to match simple.py example. + Fix core.py to use getcode() instead of getvalue() method of the exception. + + pyme/pyme/__init__.py | 22 ++++++++++++++-------- + pyme/pyme/core.py | 4 ++-- + 2 files changed, 16 insertions(+), 10 deletions(-) + +commit dee337455ffd624d3f83e1c159c4bb2cefc692c9 +Author: belyi +Date: Sat Mar 20 20:32:29 2004 +0000 + + Added Makefile to simplify publishing web files. + + pyme-web/Makefile | 7 +++++++ + 1 file changed, 7 insertions(+) + +commit af7129baa8260697d85c2ddb434562e8a80b62d8 +Author: belyi +Date: Sat Mar 20 20:15:53 2004 +0000 + + Added minimum of formating and SF icon. + + pyme-web/index.html | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +commit 2e64dcbf99cee796b51667b04d8961e390edde87 +Author: belyi +Date: Sat Mar 20 18:30:09 2004 +0000 + + Initial revision + + pyme-web/index.html | 33 +++++++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +commit 1c51644b3d0b6611422d971758e35f303d2ad5df +Author: belyi +Date: Sat Mar 20 05:10:46 2004 +0000 + + Update examples and package information on the initial pyme doc page. + + pyme/pyme/__init__.py | 27 ++++++++++++--------------- + 1 file changed, 12 insertions(+), 15 deletions(-) + +commit b2d31b0bfbffdff5247d6db4e3c95140cc1b1f19 +Author: belyi +Date: Sat Mar 20 04:47:42 2004 +0000 + + Deleted unnecessary files. + Updated debian/control to remove dependency on python-xml package since there's + none now. + Move example files from 'doc' into separate control file. + Update debian/rules to build documentation from *.py files and to exclude + CVS directories from the installation. + + pyme/Makefile | 26 ++----- + pyme/debian/control | 8 +-- + pyme/debian/docs | 1 - + pyme/debian/ex.package.doc-base | 22 ------ + pyme/debian/examples | 1 + + pyme/debian/manpage.1.ex | 60 ---------------- + pyme/debian/manpage.sgml.ex | 152 ---------------------------------------- + pyme/debian/rules | 12 ++-- + 8 files changed, 15 insertions(+), 267 deletions(-) + +commit 1b517dd9b82a433499b4696b06d94d756cd36e53 +Author: belyi +Date: Sat Mar 20 02:59:15 2004 +0000 + + Remove doc/gpgme directory containing GPGME documentation since this belongs + to a different project. Need to add reference in our documentation. + + pyme/doc/gpgme/fdl.texi | 402 ------ + pyme/doc/gpgme/gpgme.texi | 3372 ------------------------------------------- + pyme/doc/gpgme/gpl.texi | 397 ----- + pyme/doc/gpgme/version.texi | 4 - + 4 files changed, 4175 deletions(-) + +commit 95d7d171da115a0fedfe2a4a7e5acc8aa408f673 +Author: belyi +Date: Sat Mar 20 02:45:03 2004 +0000 + + Change debian/rules to generate files by swig during build and to cleanup + those files on 'clean' rule. + Plus, leave generated gpgme_wrap.c in the root directory instead of moving + it into subdirectory 'generated'. + + pyme/Makefile | 8 +++----- + pyme/debian/rules | 3 ++- + pyme/setup.py | 2 +- + 3 files changed, 6 insertions(+), 7 deletions(-) + +commit 545b3d90d445c5c78e8d72b2c1780863e02c789a +Author: belyi +Date: Sat Mar 20 02:18:01 2004 +0000 + + Initial revision + + pyme/COPYING | 340 ++++ + pyme/ChangeLog | 802 ++++++++ + pyme/Makefile | 79 + + pyme/debian/README.Debian | 6 + + pyme/debian/changelog | 19 + + pyme/debian/control | 68 + + pyme/debian/copyright | 27 + + pyme/debian/dirs | 2 + + pyme/debian/docs | 2 + + pyme/debian/ex.package.doc-base | 22 + + pyme/debian/manpage.1.ex | 60 + + pyme/debian/manpage.sgml.ex | 152 ++ + pyme/debian/postinst.ex | 48 + + pyme/debian/postrm.ex | 38 + + pyme/debian/preinst.ex | 44 + + pyme/debian/prerm.ex | 39 + + pyme/debian/rules | 130 ++ + pyme/debian/setup.cfg-2.2 | 8 + + pyme/debian/setup.cfg-2.3 | 8 + + pyme/doc/gpgme/fdl.texi | 402 ++++ + pyme/doc/gpgme/gpgme.texi | 3372 +++++++++++++++++++++++++++++++ + pyme/doc/gpgme/gpl.texi | 397 ++++ + pyme/doc/gpgme/version.texi | 4 + + pyme/examples/encrypt-to-all.py | 63 + + pyme/examples/genkey.py | 55 + + pyme/examples/sign.py | 28 + + pyme/examples/simple.py | 44 + + pyme/gpgme.i | 191 ++ + pyme/helpers.c | 139 ++ + pyme/helpers.h | 29 + + pyme/pyme/__init__.py | 134 ++ + pyme/pyme/aux.py | 55 + + pyme/pyme/callbacks.py | 45 + + pyme/pyme/constants/__init__.py | 2 + + pyme/pyme/constants/data/__init__.py | 2 + + pyme/pyme/constants/data/encoding.py | 19 + + pyme/pyme/constants/event.py | 19 + + pyme/pyme/constants/import.py | 19 + + pyme/pyme/constants/keylist/__init__.py | 2 + + pyme/pyme/constants/keylist/mode.py | 19 + + pyme/pyme/constants/md.py | 19 + + pyme/pyme/constants/pk.py | 19 + + pyme/pyme/constants/protocol.py | 19 + + pyme/pyme/constants/sig/__init__.py | 2 + + pyme/pyme/constants/sig/mode.py | 19 + + pyme/pyme/constants/sigsum.py | 19 + + pyme/pyme/constants/status.py | 19 + + pyme/pyme/constants/validity.py | 19 + + pyme/pyme/core.py | 367 ++++ + pyme/pyme/errors.py | 46 + + pyme/pyme/util.py | 61 + + pyme/pyme/version.py | 39 + + pyme/setup.py | 60 + + 53 files changed, 7642 insertions(+) + +commit a3d5a442dc713b6c4d6fc4134db5b47e379dc41d +Author: root +Date: Fri Mar 19 14:12:30 2004 +0000 + + initial checkin + + CVSROOT/checkoutlist | 13 +++++++++++++ + CVSROOT/commitinfo | 15 +++++++++++++++ + CVSROOT/config | 21 +++++++++++++++++++++ + CVSROOT/cvswrappers | 19 +++++++++++++++++++ + CVSROOT/editinfo | 21 +++++++++++++++++++++ + CVSROOT/loginfo | 26 ++++++++++++++++++++++++++ + CVSROOT/modules | 26 ++++++++++++++++++++++++++ + CVSROOT/notify | 12 ++++++++++++ + CVSROOT/rcsinfo | 13 +++++++++++++ + CVSROOT/taginfo | 20 ++++++++++++++++++++ + CVSROOT/verifymsg | 21 +++++++++++++++++++++ + 11 files changed, 207 insertions(+) diff --git a/lang/python/docs/old-commits.log b/lang/python/docs/old-commits.log deleted file mode 100644 index 93661e35..00000000 --- a/lang/python/docs/old-commits.log +++ /dev/null @@ -1,2445 +0,0 @@ -commit 2145348ec54c6027f2ea20f695de0277e2871405 -Merge: 348ba88 2036f1a -Author: Ben McGinnes -Date: Wed May 6 03:04:19 2015 +1000 - - Merge pull request #4 from Hasimir/master - - history - -commit 2036f1a0a670a0561993e195c458059220b36114 -Merge: dbabf0c 348ba88 -Author: Ben McGinnes -Date: Wed May 6 02:57:44 2015 +1000 - - Merge branch 'master' of github:adversary-org/pyme3 - -commit dbabf0cf1f2985755c2293b619011832e34faa9c -Author: Ben McGinnes -Date: Wed May 6 02:52:23 2015 +1000 - - Added a short history - - * A (very) brief summary of the project's history since 2002. - * Deals with why the commit log in the GPGME repo does not include the - history of PyME. - * Mentions that intact git repos will be maintained, but not where they - are (one will be on github, another will be in a user directory on - playfair.gnupg.org). - - docs/Short_History.rst | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 57 insertions(+) - -commit 348ba883424778c711c04ae9b66035ccdb36eb8c -Merge: 127d0a5 7c37a27 -Author: Ben McGinnes -Date: Wed May 6 02:21:34 2015 +1000 - - Merge pull request #3 from Hasimir/master - - Version release preparation - -commit 7c37a27a6845c58222d4d947c2efbe38e955b612 -Merge: f692cff 127d0a5 -Author: Ben McGinnes -Date: Wed May 6 02:17:14 2015 +1000 - - Merge branch 'master' of github:adversary-org/pyme3 - -commit f692cff50a89c2c61acdbd3d7dd60f5ce3cd15af -Author: Ben McGinnes -Date: Wed May 6 02:09:44 2015 +1000 - - TODO update - - * Removed reference to GitHub, replaced with impending new home at gnupg.org. - - docs/TODO.rst | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -commit bd5ccf9e3bfe69fa681613757577e87b72ca08ec -Author: Ben McGinnes -Date: Wed May 6 02:00:44 2015 +1000 - - Version bump - - * Bumped version number to 0.9.1 to keep it somewhat in line with the - existing PyME project, even though there will be some divergence at - some point (or even re-merging, depending on how many of the Python 3 - modifications can be back-ported to the Python 2 version). - * Updated the author and copyright information to reflect the two - current authors (Martin and I). - * Replaced Igor's contact details with mine. - * Replaced project home page with the GnuPG one. - - pyme/version.py | 16 +++++++++------- - 1 file changed, 9 insertions(+), 7 deletions(-) - -commit ec167512f4ca88d8f6e89e2ae831798c8283b4df -Author: Ben McGinnes -Date: Wed May 6 01:48:01 2015 +1000 - - README preparation. - - * Changes in preparation for impending move of code to the GnuPG git - server as a part of GPGME. - - README.rst | 14 +++++++------- - 1 file changed, 7 insertions(+), 7 deletions(-) - -commit 8a48515e884c36b5bdb24a13cb4d2e49f4ee6f17 -Author: Ben McGinnes -Date: Wed May 6 01:43:53 2015 +1000 - - TODO moved to docs - - * As it says. - - TODO.rst | 25 ------------------------- - docs/TODO.rst | 25 +++++++++++++++++++++++++ - 2 files changed, 25 insertions(+), 25 deletions(-) - -commit f968c777472f01f308f6e57eac1740bf5c76c205 -Author: Ben McGinnes -Date: Sun May 3 16:52:13 2015 +1000 - - Started another TODO file. - - TODO.rst | 25 +++++++++++++++++++++++++ - 1 file changed, 25 insertions(+) - -commit 127d0a56fa9f7ad1d4fb39d0b529b890a8d67365 -Merge: db72dea 44837f6 -Author: Ben McGinnes -Date: Sun May 3 14:59:44 2015 +1000 - - Merge pull request #2 from Hasimir/master - - Minor editing. - -commit 44837f6e50fc539c86aef1f75a6a3538b02029ea -Author: Ben McGinnes -Date: Sun May 3 14:56:55 2015 +1000 - - Minor editing. - - * Fixed another URL. - * Changed Py3 version's version number to v0.9.1-beta0. - - README.rst | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -commit db72deaae19c3513391df040bcaf66a88d9213af -Merge: db34286 48eb185 -Author: Ben McGinnes -Date: Sun May 3 14:26:11 2015 +1000 - - Merge pull request #1 from Hasimir/master - - Links - -commit 48eb1856cb0739cc9f0b9084da9d965e1fc7fddd -Author: Ben McGinnes -Date: Sun May 3 14:22:30 2015 +1000 - - Links - - * Fixed URLs for authors. - * Updated my entry to point to github location. - ** I strongly suspect the result of this work will be concurrent - projects, so preparing for that eventuality with this repo. - - README.rst | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -commit db3428659783f30b9a76204403daedf9fc4cf7cf -Author: Ben McGinnes -Date: Sun May 3 11:29:00 2015 +1000 - - Explicit over Implicit ... - - ... isn't just for code. - - * Removed the 2to3 working directory and its contents. - * Made the README.rst file a little more clear that this branch is for - Python 3 (set Python 3.2 as a fairly arbitrary requirement for the - moment, but will probably raise this to 3.3). - - 2to3/2to3-output-remaining.log | 60 --- - 2to3/2to3-output-setup.log | 35 -- - 2to3/2to3-output.log | 950 ----------------------------------------- - README.rst | 10 +- - 4 files changed, 7 insertions(+), 1048 deletions(-) - -commit 3edf07a4ba8a86af3a33246234d6e133074862af -Author: Ben McGinnes -Date: Sun May 3 11:19:41 2015 +1000 - - Added authors. - - * In alphabetical order. - * Mine will need updating once Martin and I have decided what to do - regarding the two main branches. - - README.rst | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -commit 811eb14b53e8856312d99f46b77215f7f9bd672c -Author: Ben McGinnes -Date: Sun May 3 10:23:00 2015 +1000 - - Docs and other things. - - * Now able to import pyme.core without error, indicates port process is - successful. - * Code is *not* compatible with the Python 2 version. - * Will need to consider making this a parallel project with the master - branch. - * Got rid of the .org TODO file. - * Changed the README to use the reST file extension since it's full of - reST anyway. - - 2to3/TODO.org | 5 ----- - README.rst | 32 ++++++++++++++++++++++++++++++++ - README.txt | 32 -------------------------------- - 3 files changed, 32 insertions(+), 37 deletions(-) - -commit 79e784bdcce1de6f7856921b5431044c62c6f015 -Author: Ben McGinnes -Date: Sun May 3 10:18:40 2015 +1000 - - Fixed another implicit import by making it explicit. Hopefully this is the last one. - - pyme/util.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit 2b52b46ccda3e7abcc50eed0745062259d698661 -Author: Ben McGinnes -Date: Sun May 3 10:16:01 2015 +1000 - - Fixed another implicit import by making it explicit. - - pyme/errors.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit 409c8fd565e21f23cd41daaeffc867e6d23a0863 -Author: Ben McGinnes -Date: Sun May 3 10:08:22 2015 +1000 - - Bytes vs. Unicode - - * Trying PyBytes instead of PyUnicode. - - gpgme.i | 14 +++++++------- - helpers.c | 8 ++++---- - 2 files changed, 11 insertions(+), 11 deletions(-) - -commit d8164aa2ae98bf8c807c16e2d9be12c5fbea7cfd -Author: Ben McGinnes -Date: Sun May 3 09:22:58 2015 +1000 - - String to Unicode - - * Replaced all instances of PyString with PyUnicode (and hoping there's - no byte data in there). - - gpgme.i | 14 +++++++------- - helpers.c | 8 ++++---- - 2 files changed, 11 insertions(+), 11 deletions(-) - -commit bd99b7865656e559b17c419c6b64b412a22c6c44 -Author: Ben McGinnes -Date: Sun May 3 09:17:06 2015 +1000 - - PyInt_AsLong - - * Replaced all instances of PyInt with PyLong, as per C API docs. - - gpgme.i | 4 ++-- - helpers.c | 8 ++++---- - 2 files changed, 6 insertions(+), 6 deletions(-) - -commit 3c91e2ccf8ca788b51e3308e292c6b64888fdb15 -Author: Ben McGinnes -Date: Sun May 3 05:59:36 2015 +1000 - - Import correction - - * Once pygpgme.py is generated and moved, it will be in the right - directory for the explicit "from . import pygpgme" to be correct. - - pyme/core.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit 23a49e7070812ff1ce138d8d4cc46d0b80328897 -Author: Ben McGinnes -Date: Sun May 3 05:38:29 2015 +1000 - - The -py3 flag. - - Makefile | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit b1549587d6db5e33081b9c20f75d1348a1d25938 -Author: Ben McGinnes -Date: Sun May 3 05:01:42 2015 +1000 - - Fixed indentation - 4. - - pyme/core.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit a685142ce46761ee6f5176e90717176e38e0d24f -Author: Ben McGinnes -Date: Sun May 3 05:00:16 2015 +1000 - - Fixed indentation - 3. - - pyme/core.py | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - -commit 488a70b490cc64eb1c47d2483cb2f4079c6767f7 -Author: Ben McGinnes -Date: Sun May 3 04:53:21 2015 +1000 - - Pet Peeve - - def pet_peeve(self): - peeve = print("people who don't press return after a colon!") - - FFS! - - pyme/core.py | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -commit a5d38eb47d64bb17bb609fe594dae2aca480bac9 -Author: Ben McGinnes -Date: Sun May 3 04:47:54 2015 +1000 - - Fixed indentation - 2. - - pyme/core.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit 476a207f732b8559abb1ea3c23147c0e34804730 -Author: Ben McGinnes -Date: Sun May 3 04:46:01 2015 +1000 - - Fixed indentation. - - pyme/core.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -commit 0572900eba9bcd9b0283c7d8e022e8972f06f9f8 -Author: Ben McGinnes -Date: Sun May 3 04:43:49 2015 +1000 - - Replaced all tabs with 4 spaces. - - pyme/core.py | 18 +++++++++--------- - 1 file changed, 9 insertions(+), 9 deletions(-) - -commit 78c0b7677e94ce1e11b8cdb833a9064527187330 -Author: Ben McGinnes -Date: Sun May 3 04:39:07 2015 +1000 - - SWIG flags in the wrong place. - - Makefile | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -commit dfa7f2589963494a8f89277560d8c1116604a3c8 -Author: Ben McGinnes -Date: Sun May 3 04:35:09 2015 +1000 - - Fixed subprocess call for swig (again). - - setup.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit 249bfd8c714dcda53127b99b6cc8a6c7c4a99f20 -Author: Ben McGinnes -Date: Sun May 3 04:32:40 2015 +1000 - - Fixed subprocess call for swig. - - setup.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit 6fd7e719cf4c975f466ceb39835db7007df36fb2 -Author: Ben McGinnes -Date: Sun May 3 03:51:48 2015 +1000 - - Linking swig to py3 - - * Changed the swig invocations to run with the -python -py3 flags explicitly. - - Makefile | 4 ++-- - setup.py | 2 +- - 2 files changed, 3 insertions(+), 3 deletions(-) - -commit 7a6b584f50ed6ddc8617a642185eea1f24ff791a -Author: Ben McGinnes -Date: Sat May 2 11:12:00 2015 +1000 - - String fun - - * streamlined confdata details, including decoding strom binary to string. - - setup.py | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -commit f7fd3f270592021a95a8f779bfe85ac18f4e390b -Author: Ben McGinnes -Date: Sat May 2 10:46:59 2015 +1000 - - Open File - - * Removed deprecated file() and replaced with open(). - - examples/PyGtkGpgKeys.py | 2 +- - examples/pygpa.py | 6 +++--- - gpgme-h-clean.py | 2 +- - 3 files changed, 5 insertions(+), 5 deletions(-) - -commit 4227d486f9558015e7e548d71085e58e1b50ec08 -Author: Ben McGinnes -Date: Sat May 2 10:36:15 2015 +1000 - - print() fix - - * Makefile includes a python print, changed from statement to function. - - Makefile | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit 406f7f2567b701502186fe0a325dc2a3491ff7f8 -Author: Ben McGinnes -Date: Sat May 2 10:28:42 2015 +1000 - - Updated Makefile - - * set make to use python3 instead. - * This will mean a successful port may need to be maintained seperately - from the original python2 code instead of merged, but ought to be able - to share most things. So maybe merge with separated make files or a - pre-make script to set python2 or python3 prior to building ... decide - later, after it works. - - Makefile | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -commit 90b3efa5b193d37e08dc9b4ee766ba9ebc9412af -Author: Ben McGinnes -Date: Sat May 2 10:15:20 2015 +1000 - - Env and a little license issue - - * Updated all the /usr/bin/env paths to point to python3. - * Also fixed the hard coded /usr/bin/python paths. - * Updated part of setup.py which gave the impression this package was - only licensed under the GPL (it's actually licensed under the LGPL as - well, essentially the same dual licensing as the GPGME library). - - examples/PyGtkGpgKeys.py | 2 +- - examples/delkey.py | 2 +- - examples/encrypt-to-all.py | 2 +- - examples/exportimport.py | 2 +- - examples/genkey.py | 2 +- - examples/inter-edit.py | 2 +- - examples/pygpa.py | 2 +- - examples/sign.py | 2 +- - examples/signverify.py | 2 +- - examples/simple.py | 2 +- - examples/t-edit.py | 2 +- - examples/testCMSgetkey.py | 2 +- - examples/verifydetails.py | 2 +- - gpgme-h-clean.py | 2 +- - setup.py | 4 ++-- - 15 files changed, 16 insertions(+), 16 deletions(-) - -commit 1a4b55dbccd2774344352e579130bf494bc5fa4b -Author: Ben McGinnes -Date: Sat May 2 08:50:54 2015 +1000 - - Removed extraneous files. - - * The two .bak files. - - pyme/errors.py.bak | 46 --------------------- - setup.py.bak | 116 ----------------------------------------------------- - 2 files changed, 162 deletions(-) - -commit 208879d4f2a6d0514c3f8ee2fc0da8bba42350de -Author: Ben McGinnes -Date: Sat May 2 08:19:37 2015 +1000 - - Added TODO.org - - * TODO list in Emacs org-mode. - * Will eventually be removed along with this entire directory when the - porting process is complete. - - 2to3/TODO.org | 5 +++++ - 1 file changed, 5 insertions(+) - -commit 1548bf201059638675c5387c6f124d4b703363a9 -Author: Ben McGinnes -Date: Sat May 2 07:58:40 2015 +1000 - - 2to3 conversion of remaining files - - * Ran the extended version against all the unmodified python files. - * Only pyme/errors.py required additional work. - - 2to3/2to3-output-remaining.log | 60 ++++++++++++++++++++++++++++++++++++++++++ - pyme/errors.py | 2 +- - pyme/errors.py.bak | 46 ++++++++++++++++++++++++++++++++ - 3 files changed, 107 insertions(+), 1 deletion(-) - -commit 1230650bc6bbe4c14d1284f7877aa932f3e86eb4 -Author: Ben McGinnes -Date: Sat May 2 07:50:39 2015 +1000 - - 2to3 conversion of setup.py - - * Ran extended 2to3 command to produce python 3 code for setup.py. - * Effectively testing for what to run against the other originally - unmodified py2 files. - - 2to3/2to3-output-setup.log | 35 ++++++++++++++ - setup.py | 7 ++- - setup.py.bak | 116 +++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 154 insertions(+), 4 deletions(-) - -commit edad44955f59aa879e95a369591717fb19eec6b7 -Author: Ben McGinnes -Date: Fri May 1 21:50:07 2015 +1000 - - Removing 2to3 generated .bak files. - - * Not really needed with a real VCS, but couldn't hurt to have them for - a couple of revisions. ;) - - examples/PyGtkGpgKeys.py.bak | 663 --------------- - examples/encrypt-to-all.py.bak | 65 -- - examples/exportimport.py.bak | 75 -- - examples/genkey.py.bak | 45 - - examples/inter-edit.py.bak | 57 -- - examples/pygpa.py.bak | 1457 -------------------------------- - examples/sign.py.bak | 31 - - examples/signverify.py.bak | 78 -- - examples/simple.py.bak | 52 -- - examples/t-edit.py.bak | 59 -- - examples/testCMSgetkey.py.bak | 45 - - examples/verifydetails.py.bak | 100 --- - gpgme-h-clean.py.bak | 42 - - pyme/callbacks.py.bak | 47 -- - pyme/constants/data/__init__.py.bak | 4 - - pyme/constants/keylist/__init__.py.bak | 4 - - pyme/constants/sig/__init__.py.bak | 4 - - pyme/core.py.bak | 463 ---------- - pyme/util.py.bak | 72 -- - pyme/version.py.bak | 41 - - 20 files changed, 3404 deletions(-) - -commit 1cfc3c969f885ed191610bffbbd60ac23fdd349e -Author: Ben McGinnes -Date: Fri May 1 21:45:50 2015 +1000 - - 2to3 conversion log - - * The output of the command to convert the code from Python 2 to 3. - * Note: this contains the list of files which were not modified and - which will or may need to be modified. - - 2to3/2to3-output.log | 950 +++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 950 insertions(+) - -commit 078f6cf878aa62d12704fab424198a613a24cc8c -Author: Ben McGinnes -Date: Fri May 1 21:36:58 2015 +1000 - - 2to3 conversion of pyme master - - * Branch from commit 459f3eca659b4949e394c4a032d9ce2053e6c721 - * Ran this: or x in `find . | egrep .py$` ; do 2to3 -w $x; done ; - * Multiple files not modified, will record elsewhere (see next commit). - - examples/PyGtkGpgKeys.py | 10 +- - examples/PyGtkGpgKeys.py.bak | 663 +++++++++++++++ - examples/encrypt-to-all.py | 12 +- - examples/encrypt-to-all.py.bak | 65 ++ - examples/exportimport.py | 20 +- - examples/exportimport.py.bak | 75 ++ - examples/genkey.py | 2 +- - examples/genkey.py.bak | 45 + - examples/inter-edit.py | 8 +- - examples/inter-edit.py.bak | 57 ++ - examples/pygpa.py | 40 +- - examples/pygpa.py.bak | 1457 ++++++++++++++++++++++++++++++++ - examples/sign.py | 2 +- - examples/sign.py.bak | 31 + - examples/signverify.py | 18 +- - examples/signverify.py.bak | 78 ++ - examples/simple.py | 8 +- - examples/simple.py.bak | 52 ++ - examples/t-edit.py | 12 +- - examples/t-edit.py.bak | 59 ++ - examples/testCMSgetkey.py | 8 +- - examples/testCMSgetkey.py.bak | 45 + - examples/verifydetails.py | 34 +- - examples/verifydetails.py.bak | 100 +++ - gpgme-h-clean.py | 2 +- - gpgme-h-clean.py.bak | 42 + - pyme/callbacks.py | 6 +- - pyme/callbacks.py.bak | 47 ++ - pyme/constants/data/__init__.py | 2 +- - pyme/constants/data/__init__.py.bak | 4 + - pyme/constants/keylist/__init__.py | 2 +- - pyme/constants/keylist/__init__.py.bak | 4 + - pyme/constants/sig/__init__.py | 2 +- - pyme/constants/sig/__init__.py.bak | 4 + - pyme/core.py | 26 +- - pyme/core.py.bak | 463 ++++++++++ - pyme/util.py | 6 +- - pyme/util.py.bak | 72 ++ - pyme/version.py | 2 +- - pyme/version.py.bak | 41 + - 40 files changed, 3515 insertions(+), 111 deletions(-) - -commit 459f3eca659b4949e394c4a032d9ce2053e6c721 -Merge: c5966ab dae7f14 -Author: Martin Albrecht -Date: Wed Jul 9 10:48:33 2014 +0100 - - Merged in jerrykan/pyme/fix_setup_26 (pull request #1) - - Provide support for using setup.py with Python v2.6 - -commit dae7f14a54e6c2bde0ad4da7308cc7fc0d0c0469 -Author: John Kristensen -Date: Wed Jul 9 15:54:39 2014 +1000 - - Provide support for using setup.py with Python v2.6 - - The setup.py script uses subprocess.check_output() which was introduced - in Python v2.7. The equivalent functionality can be achieved without - adding much extra code and provide support for Python v2.6. - - setup.py | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -commit c5966abec9d772b3922d32650da288fd50a217be -Author: Martin Albrecht -Date: Thu May 15 19:43:00 2014 +0100 - - README.txt in ReST, including headlines - - README.txt | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -commit 43ee8c6f34fa9b6d3975aa6ea60b3d4a741fa721 -Author: Martin Albrecht -Date: Thu May 15 19:37:15 2014 +0100 - - README.txt in ReST - - README.txt | 25 +++++++++++++------------ - 1 file changed, 13 insertions(+), 12 deletions(-) - -commit f71a369484cba8801df23ccc5842335fa496c0df -Author: Martin Albrecht -Date: Thu May 15 19:28:12 2014 +0100 - - added MANIFEST.in and README.txt (instead of .md) - - MANIFEST.in | 6 ++++++ - README.md | 27 --------------------------- - README.txt | 27 +++++++++++++++++++++++++++ - 3 files changed, 33 insertions(+), 27 deletions(-) - -commit d0d6755229f920b0bed043e9c2731de2d57c096c -Author: Martin Albrecht -Date: Tue May 13 09:52:44 2014 +0100 - - added mailing list to README - - README.md | 19 ++++++++++++++++--- - 1 file changed, 16 insertions(+), 3 deletions(-) - -commit 30ca60ddf92df684de261cb24c83c68089be0adc -Author: Martin Albrecht -Date: Sun May 11 13:34:28 2014 +0100 - - we don't need a separate out of date ChangeLog file - - ChangeLog | 802 -------------------------------------------------------------- - 1 file changed, 802 deletions(-) - -commit 8263f1a6d38fdb7f5f3dd5c7e28f83caa7528a08 -Author: Martin Albrecht -Date: Sun May 11 13:32:31 2014 +0100 - - adding README.md - - README.md | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -commit 3fc71b47e9e14b0b984801c28d722723baa4b406 -Author: Martin Albrecht -Date: Sat May 10 15:43:06 2014 +0100 - - ValueError -> RuntimeError - - setup.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -commit eec432abea56296b9fa36aac0d10926a2335b739 -Merge: eea6537 d2738b3 -Author: Martin Albrecht -Date: Sat May 10 15:41:02 2014 +0100 - - Merge branch 'master' of bitbucket.org:malb/pyme - - Conflicts: - setup.py - -commit eea6537921061b4dcfc54e00a99d3fa110e71433 -Author: Martin Albrecht -Date: Sat May 10 15:39:51 2014 +0100 - - check for swig - - setup.py | 8 ++++++++ - 1 file changed, 8 insertions(+) - -commit 53867bf9715ee1b4ea873bf5e2fbb7d9740a2b4a -Author: Martin Albrecht -Date: Sat May 10 15:35:04 2014 +0100 - - more friendly error message if gpgme is missing - - setup.py | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -commit d2738b35d63b1492d69641c5466103685f2d3a30 -Author: Martin Albrecht -Date: Sat May 10 15:35:04 2014 +0100 - - more friendly error message if gpgme is missing - - setup.py | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -commit c0b01240becf8ba6cf1d4c1f64b2cb4c056f5163 -Author: Martin Albrecht -Date: Fri May 9 15:20:24 2014 +0100 - - version number should have three digits - - pyme/version.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit 6672bb60b9bec60d38e854016c48658b57774578 -Author: Martin Albrecht -Date: Wed May 7 15:11:08 2014 +0100 - - bump version number for upcoming release - - pyme/version.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit 7bd6de700f33ca5d1f27bc16ebbd401f21d2e788 -Author: Martin Albrecht -Date: Sat May 3 19:36:25 2014 +0100 - - bump version number to indicate changes - - pyme/version.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit 4fb6bd9b3f47c1a343242ac83b326cacd12a136e -Author: Martin Albrecht -Date: Sat May 3 19:34:07 2014 +0100 - - pyme instead of pygpgme - - setup.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit 9548973138d78241a45ccb82333b25f2cf36ce7d -Author: Martin Albrecht -Date: Sat May 3 19:31:10 2014 +0100 - - dirty hack to make 'python setup.py install' work - - setup.py | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -commit a961d7eab9db478b7e603324bc5d243bd3c84bad -Author: Martin Albrecht -Date: Sat May 3 19:05:44 2014 +0100 - - moved everything down to the toplevel directory - - COPYING | 340 ++ - COPYING.LESSER | 510 +++ - ChangeLog | 802 +++++ - INSTALL | 15 + - Makefile | 104 + - debian/README.Debian | 6 + - debian/changelog | 93 + - debian/control | 34 + - debian/copyright | 25 + - debian/docs | 2 + - debian/examples | 2 + - debian/rules | 99 + - examples/PyGtkGpgKeys.glade | 1394 ++++++++ - examples/PyGtkGpgKeys.gladep | 8 + - examples/PyGtkGpgKeys.py | 663 ++++ - examples/delkey.py | 34 + - examples/encrypt-to-all.py | 65 + - examples/exportimport.py | 75 + - examples/genkey.py | 45 + - examples/inter-edit.py | 57 + - examples/pygpa.glade | 5546 +++++++++++++++++++++++++++++++ - examples/pygpa.py | 1457 ++++++++ - examples/sign.py | 31 + - examples/signverify.py | 78 + - examples/simple.py | 52 + - examples/t-edit.py | 59 + - examples/testCMSgetkey.py | 45 + - examples/verifydetails.py | 100 + - gpgme-h-clean.py | 42 + - gpgme.i | 267 ++ - helpers.c | 154 + - helpers.h | 36 + - pyme/COPYING | 340 -- - pyme/COPYING.LESSER | 510 --- - pyme/ChangeLog | 802 ----- - pyme/INSTALL | 15 - - pyme/Makefile | 104 - - pyme/__init__.py | 137 + - pyme/callbacks.py | 47 + - pyme/constants/__init__.py | 7 + - pyme/constants/data/__init__.py | 4 + - pyme/constants/data/encoding.py | 20 + - pyme/constants/event.py | 20 + - pyme/constants/import.py | 20 + - pyme/constants/keylist/__init__.py | 4 + - pyme/constants/keylist/mode.py | 20 + - pyme/constants/md.py | 20 + - pyme/constants/pk.py | 20 + - pyme/constants/protocol.py | 20 + - pyme/constants/sig/__init__.py | 4 + - pyme/constants/sig/mode.py | 20 + - pyme/constants/sigsum.py | 20 + - pyme/constants/status.py | 20 + - pyme/constants/validity.py | 20 + - pyme/core.py | 463 +++ - pyme/debian/README.Debian | 6 - - pyme/debian/changelog | 93 - - pyme/debian/control | 34 - - pyme/debian/copyright | 25 - - pyme/debian/docs | 2 - - pyme/debian/examples | 2 - - pyme/debian/rules | 99 - - pyme/errors.py | 46 + - pyme/examples/PyGtkGpgKeys.glade | 1394 -------- - pyme/examples/PyGtkGpgKeys.gladep | 8 - - pyme/examples/PyGtkGpgKeys.py | 663 ---- - pyme/examples/delkey.py | 34 - - pyme/examples/encrypt-to-all.py | 65 - - pyme/examples/exportimport.py | 75 - - pyme/examples/genkey.py | 45 - - pyme/examples/inter-edit.py | 57 - - pyme/examples/pygpa.glade | 5546 ------------------------------- - pyme/examples/pygpa.py | 1457 -------- - pyme/examples/sign.py | 31 - - pyme/examples/signverify.py | 78 - - pyme/examples/simple.py | 52 - - pyme/examples/t-edit.py | 59 - - pyme/examples/testCMSgetkey.py | 45 - - pyme/examples/verifydetails.py | 100 - - pyme/gpgme-h-clean.py | 42 - - pyme/gpgme.i | 267 -- - pyme/helpers.c | 154 - - pyme/helpers.h | 36 - - pyme/pyme/__init__.py | 137 - - pyme/pyme/callbacks.py | 47 - - pyme/pyme/constants/__init__.py | 7 - - pyme/pyme/constants/data/__init__.py | 4 - - pyme/pyme/constants/data/encoding.py | 20 - - pyme/pyme/constants/event.py | 20 - - pyme/pyme/constants/import.py | 20 - - pyme/pyme/constants/keylist/__init__.py | 4 - - pyme/pyme/constants/keylist/mode.py | 20 - - pyme/pyme/constants/md.py | 20 - - pyme/pyme/constants/pk.py | 20 - - pyme/pyme/constants/protocol.py | 20 - - pyme/pyme/constants/sig/__init__.py | 4 - - pyme/pyme/constants/sig/mode.py | 20 - - pyme/pyme/constants/sigsum.py | 20 - - pyme/pyme/constants/status.py | 20 - - pyme/pyme/constants/validity.py | 20 - - pyme/pyme/core.py | 463 --- - pyme/pyme/errors.py | 46 - - pyme/pyme/util.py | 72 - - pyme/pyme/version.py | 41 - - pyme/setup.py | 99 - - pyme/util.py | 72 + - pyme/version.py | 41 + - setup.py | 99 + - 108 files changed, 13384 insertions(+), 13384 deletions(-) - -commit 8148cdd424c434e833ce427612ea8c89abc6e41c -Author: Martin Albrecht -Date: Sat May 3 18:58:52 2014 +0100 - - removing pyme-web - - pyme-web/Makefile | 15 - - pyme-web/default.css | 37 -- - pyme-web/doc/gpgme/ASCII-Armor.html | 57 --- - pyme-web/doc/gpgme/Advanced-Key-Editing.html | 98 ---- - pyme-web/doc/gpgme/Algorithms.html | 47 -- - pyme-web/doc/gpgme/Building-the-Source.html | 82 ---- - .../doc/gpgme/Callback-Based-Data-Buffers.html | 148 ------ - pyme-web/doc/gpgme/Cancellation.html | 67 --- - pyme-web/doc/gpgme/Concept-Index.html | 186 ------- - pyme-web/doc/gpgme/Context-Attributes.html | 52 -- - pyme-web/doc/gpgme/Contexts.html | 61 --- - pyme-web/doc/gpgme/Creating-Contexts.html | 49 -- - pyme-web/doc/gpgme/Creating-Data-Buffers.html | 47 -- - pyme-web/doc/gpgme/Creating-a-Signature.html | 143 ------ - pyme-web/doc/gpgme/Crypto-Engine.html | 79 --- - pyme-web/doc/gpgme/Crypto-Operations.html | 67 --- - .../doc/gpgme/Cryptographic-Message-Syntax.html | 42 -- - .../doc/gpgme/Data-Buffer-I_002fO-Operations.html | 104 ---- - pyme-web/doc/gpgme/Data-Buffer-Meta_002dData.html | 100 ---- - pyme-web/doc/gpgme/Decrypt-and-Verify.html | 79 --- - pyme-web/doc/gpgme/Decrypt.html | 123 ----- - pyme-web/doc/gpgme/Deleting-Keys.html | 67 --- - pyme-web/doc/gpgme/Destroying-Contexts.html | 46 -- - pyme-web/doc/gpgme/Destroying-Data-Buffers.html | 70 --- - pyme-web/doc/gpgme/Encrypt.html | 45 -- - pyme-web/doc/gpgme/Encrypting-a-Plaintext.html | 147 ------ - pyme-web/doc/gpgme/Engine-Configuration.html | 65 --- - pyme-web/doc/gpgme/Engine-Information.html | 119 ----- - pyme-web/doc/gpgme/Engine-Version-Check.html | 48 -- - pyme-web/doc/gpgme/Error-Codes.html | 133 ----- - pyme-web/doc/gpgme/Error-Handling.html | 72 --- - pyme-web/doc/gpgme/Error-Sources.html | 89 ---- - pyme-web/doc/gpgme/Error-Strings.html | 80 --- - pyme-web/doc/gpgme/Error-Values.html | 159 ------ - pyme-web/doc/gpgme/Exchanging-Data.html | 58 --- - pyme-web/doc/gpgme/Exporting-Keys.html | 101 ---- - pyme-web/doc/gpgme/Features.html | 59 --- - pyme-web/doc/gpgme/File-Based-Data-Buffers.html | 74 --- - pyme-web/doc/gpgme/Function-and-Data-Index.html | 229 --------- - pyme-web/doc/gpgme/Generating-Keys.html | 144 ------ - pyme-web/doc/gpgme/Getting-Started.html | 55 --- - pyme-web/doc/gpgme/Hash-Algorithms.html | 59 --- - pyme-web/doc/gpgme/Header.html | 53 -- - .../doc/gpgme/I_002fO-Callback-Example-GDK.html | 85 ---- - .../gpgme/I_002fO-Callback-Example-GTK_002b.html | 86 ---- - .../doc/gpgme/I_002fO-Callback-Example-Qt.html | 99 ---- - pyme-web/doc/gpgme/I_002fO-Callback-Example.html | 259 ---------- - pyme-web/doc/gpgme/I_002fO-Callback-Interface.html | 142 ------ - pyme-web/doc/gpgme/Importing-Keys.html | 171 ------- - pyme-web/doc/gpgme/Included-Certificates.html | 70 --- - pyme-web/doc/gpgme/Information-About-Keys.html | 207 -------- - .../doc/gpgme/Information-About-Trust-Items.html | 75 --- - pyme-web/doc/gpgme/Introduction.html | 53 -- - pyme-web/doc/gpgme/Key-Listing-Mode.html | 99 ---- - pyme-web/doc/gpgme/Key-Management.html | 260 ---------- - pyme-web/doc/gpgme/Key-Signatures.html | 130 ----- - .../doc/gpgme/Largefile-Support-_0028LFS_0029.html | 110 ----- - pyme-web/doc/gpgme/Library-Copying.html | 542 --------------------- - pyme-web/doc/gpgme/Library-Version-Check.html | 97 ---- - pyme-web/doc/gpgme/Listing-Keys.html | 204 -------- - pyme-web/doc/gpgme/Listing-Trust-Items.html | 88 ---- - pyme-web/doc/gpgme/Locale.html | 69 --- - pyme-web/doc/gpgme/Manipulating-Data-Buffers.html | 45 -- - pyme-web/doc/gpgme/Manipulating-Keys.html | 63 --- - pyme-web/doc/gpgme/Manipulating-Trust-Items.html | 62 --- - pyme-web/doc/gpgme/Memory-Based-Data-Buffers.html | 107 ---- - pyme-web/doc/gpgme/Multi-Threading.html | 93 ---- - pyme-web/doc/gpgme/OpenPGP.html | 44 -- - pyme-web/doc/gpgme/Overview.html | 57 --- - pyme-web/doc/gpgme/Passphrase-Callback.html | 101 ---- - pyme-web/doc/gpgme/Preparation.html | 54 -- - pyme-web/doc/gpgme/Progress-Meter-Callback.html | 80 --- - pyme-web/doc/gpgme/Protocol-Selection.html | 60 --- - pyme-web/doc/gpgme/Protocols-and-Engines.html | 82 ---- - pyme-web/doc/gpgme/Public-Key-Algorithms.html | 74 --- - .../doc/gpgme/Registering-I_002fO-Callbacks.html | 81 --- - pyme-web/doc/gpgme/Run-Control.html | 53 -- - pyme-web/doc/gpgme/Selecting-Signers.html | 64 --- - pyme-web/doc/gpgme/Sign.html | 50 -- - pyme-web/doc/gpgme/Signal-Handling.html | 61 --- - pyme-web/doc/gpgme/Signature-Notation-Data.html | 85 ---- - pyme-web/doc/gpgme/Text-Mode.html | 63 --- - pyme-web/doc/gpgme/Trust-Item-Management.html | 68 --- - pyme-web/doc/gpgme/Using-Automake.html | 74 --- - pyme-web/doc/gpgme/Using-External-Event-Loops.html | 74 --- - pyme-web/doc/gpgme/Using-Libtool.html | 44 -- - pyme-web/doc/gpgme/Verify.html | 492 ------------------- - pyme-web/doc/gpgme/Waiting-For-Completion.html | 77 --- - pyme-web/doc/gpgme/index.html | 169 ------- - pyme-web/doc/pyme/index.html | 164 ------- - pyme-web/doc/pyme/pyme.callbacks.html | 42 -- - .../doc/pyme/pyme.constants.data.encoding.html | 48 -- - pyme-web/doc/pyme/pyme.constants.data.html | 29 -- - pyme-web/doc/pyme/pyme.constants.event.html | 48 -- - pyme-web/doc/pyme/pyme.constants.html | 39 -- - pyme-web/doc/pyme/pyme.constants.import.html | 49 -- - pyme-web/doc/pyme/pyme.constants.keylist.html | 29 -- - pyme-web/doc/pyme/pyme.constants.keylist.mode.html | 49 -- - pyme-web/doc/pyme/pyme.constants.md.html | 58 --- - pyme-web/doc/pyme/pyme.constants.pk.html | 50 -- - pyme-web/doc/pyme/pyme.constants.protocol.html | 48 -- - pyme-web/doc/pyme/pyme.constants.sig.html | 29 -- - pyme-web/doc/pyme/pyme.constants.sig.mode.html | 47 -- - pyme-web/doc/pyme/pyme.constants.sigsum.html | 55 --- - pyme-web/doc/pyme/pyme.constants.status.html | 126 ----- - pyme-web/doc/pyme/pyme.constants.validity.html | 50 -- - pyme-web/doc/pyme/pyme.core.html | 277 ----------- - pyme-web/doc/pyme/pyme.errors.html | 82 ---- - pyme-web/doc/pyme/pyme.html | 164 ------- - pyme-web/doc/pyme/pyme.util.html | 81 --- - pyme-web/doc/pyme/pyme.version.html | 37 -- - pyme-web/index.html | 72 --- - 112 files changed, 10551 deletions(-) - -commit 684d95feb7e10e538a56fb1b27f1456111bacb60 -Author: Martin Albrecht -Date: Mon Jan 6 17:44:20 2014 +0100 - - fixing op_export_keys() - - the conversion of gpgme_key_t [] was restricted to gpgme_key_t [] with the - name recv, i.e. only the use-cases of encryption were covered. - - see: http://sourceforge.net/mailarchive/forum.php?forum_name=pyme-help&max_rows=25&style=nested&viewmonth=201309 - - pyme/gpgme.i | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -commit 658d23b95110d21eeb50abf4e74701a667521a88 -Author: Martin Albrecht -Date: Mon Jan 6 17:41:33 2014 +0100 - - deleting CVSROOT - - CVSROOT/checkoutlist | 13 ------------- - CVSROOT/commitinfo | 15 --------------- - CVSROOT/config | 21 --------------------- - CVSROOT/cvswrappers | 19 ------------------- - CVSROOT/editinfo | 21 --------------------- - CVSROOT/loginfo | 26 -------------------------- - CVSROOT/modules | 26 -------------------------- - CVSROOT/notify | 12 ------------ - CVSROOT/rcsinfo | 13 ------------- - CVSROOT/taginfo | 20 -------------------- - CVSROOT/verifymsg | 21 --------------------- - 11 files changed, 207 deletions(-) - -commit 576b555499c094c4786d42de9e59aa9826009b89 -Author: convert-repo -Date: Mon Jan 6 15:22:44 2014 +0000 - - update tags - -commit 2dcf0c5b702eb5a18c66ff1e42a72eaa7427af1d -Author: belyi -Date: Wed Nov 26 02:38:33 2008 +0000 - - Move Windows specific fix from helpers.c to helpers.h so that it works - for edit callback as well as for the passphrase one. - - pyme/helpers.c | 5 ----- - pyme/helpers.h | 5 +++++ - 2 files changed, 5 insertions(+), 5 deletions(-) - -commit 42a035f2ef62470fea7a7f8ee33a1297fa90a603 -Author: belyi -Date: Mon Nov 24 21:44:30 2008 +0000 - - Update the way build directives are constructed on MinGW to have a bit - more robust. Update PyMe build version to 0.8.1 in version.py - - pyme/pyme/version.py | 2 +- - pyme/setup.py | 10 ++++++++-- - 2 files changed, 9 insertions(+), 3 deletions(-) - -commit 3aaa20fbcba17066c9ffd580f5209946022793a2 -Author: belyi -Date: Mon Nov 24 06:57:11 2008 +0000 - - Update changelog - - pyme/debian/changelog | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -commit 689ff46b2550547e3883f809a6dc40c22c3e137e -Author: belyi -Date: Mon Nov 24 06:50:41 2008 +0000 - - Fix hang problem on Windows when password is written to a filehandle. - Fix the way path is constructed on MinGW platform. - - pyme/helpers.c | 5 +++++ - pyme/setup.py | 4 ++-- - 2 files changed, 7 insertions(+), 2 deletions(-) - -commit 852a60d541d66cb56f40378182b976fd87a02c46 -Author: belyi -Date: Sun Nov 23 04:31:31 2008 +0000 - - Add Bernard's example testCMSgetkey.py and his updates for - verifydetails.py - - pyme/examples/testCMSgetkey.py | 45 ++++++++++++++++++++++++++++++++++++++++++ - pyme/examples/verifydetails.py | 43 +++++++++++++++++++++++++++++----------- - 2 files changed, 77 insertions(+), 11 deletions(-) - -commit f080527d9184f3360f0a8ef6136b9a188d8e7d2a -Author: belyi -Date: Thu May 29 18:29:37 2008 +0000 - - Remove debian packaging for python2.3 since it is removed from both - testing and unstable dists. - Update docs build target to have correct PYTHONPATH set. - - pyme/Makefile | 2 +- - pyme/debian/changelog | 4 +++- - pyme/debian/control | 4 ++-- - pyme/debian/rules | 2 -- - 4 files changed, 6 insertions(+), 6 deletions(-) - -commit c25d133fcbadf3c7f6e655586b4a05d6e3cf6f0b -Author: belyi -Date: Thu Apr 3 13:37:12 2008 +0000 - - Forgot to adjust mainText margin. Doing it now. - - pyme-web/default.css | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit 897286a54a32336d060cd03305cdecb7905f34f1 -Author: belyi -Date: Thu Apr 3 13:00:11 2008 +0000 - - Fix an error in default.css and make index.html "Standards Compliant". - - pyme-web/default.css | 2 +- - pyme-web/index.html | 7 ++++--- - 2 files changed, 5 insertions(+), 4 deletions(-) - -commit 4e049212bd214449cc0ba1ce06e00782783f328a -Author: belyi -Date: Thu Apr 3 12:38:42 2008 +0000 - - Adjust spacing between links. - - pyme-web/default.css | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -commit cb2bddfbd77483b1deb14f2eab0715a03dd33fcd -Author: belyi -Date: Wed Apr 2 22:50:21 2008 +0000 - - Make style a big more IE friendly. - - pyme-web/default.css | 15 +++++++++++---- - 1 file changed, 11 insertions(+), 4 deletions(-) - -commit ad66f0a1bb01b46baac328e9fee439b35a60c232 -Author: belyi -Date: Wed Apr 2 11:58:32 2008 +0000 - - Make GPGME documentation a bit more web friendly on the index.html page. - - pyme-web/doc/gpgme/Algorithms.html | 2 +- - pyme-web/doc/gpgme/Concept-Index.html | 2 +- - pyme-web/doc/gpgme/Contexts.html | 2 +- - pyme-web/doc/gpgme/Error-Handling.html | 2 +- - pyme-web/doc/gpgme/Exchanging-Data.html | 2 +- - pyme-web/doc/gpgme/Function-and-Data-Index.html | 2 +- - pyme-web/doc/gpgme/Introduction.html | 4 +- - pyme-web/doc/gpgme/Library-Copying.html | 2 +- - pyme-web/doc/gpgme/Preparation.html | 2 +- - pyme-web/doc/gpgme/Protocols-and-Engines.html | 2 +- - pyme-web/doc/gpgme/index.html | 229 +----------------------- - 11 files changed, 12 insertions(+), 239 deletions(-) - -commit 4f57c0ccb049d4442e7732e2d1d05dabffd2a21d -Author: belyi -Date: Wed Apr 2 06:12:57 2008 +0000 - - Add missing core.set_locale() to set default locale for contexts. - - pyme/debian/changelog | 2 +- - pyme/pyme/core.py | 4 ++++ - 2 files changed, 5 insertions(+), 1 deletion(-) - -commit acf7ead3dea8590cf9fe86b67bb125837ad6ed4f -Author: belyi -Date: Wed Apr 2 05:50:24 2008 +0000 - - Avoid leaks caused by keys. - Add set/get methods for engine info. - - pyme/debian/changelog | 10 ++++++++++ - pyme/pyme/core.py | 24 ++++++++++++++++++++++++ - 2 files changed, 34 insertions(+) - -commit df4a2fb518adbb6420d95ce74af212c87abff7e7 -Author: belyi -Date: Wed Apr 2 04:04:41 2008 +0000 - - Update index.html to reflect new versions on the web. - - pyme-web/Makefile | 3 ++- - pyme-web/doc/gpgme/index.html | 4 +--- - pyme-web/index.html | 4 ++-- - 3 files changed, 5 insertions(+), 6 deletions(-) - -commit bd3ffc9bdf98d6aafde6b689c6c8215fa468612d -Author: belyi -Date: Wed Apr 2 04:01:04 2008 +0000 - - Update PyMe documentation to match 0.8.0 version of the package. - - pyme-web/doc/pyme/index.html | 14 ++++----- - pyme-web/doc/pyme/pyme.constants.keylist.mode.html | 1 + - pyme-web/doc/pyme/pyme.constants.protocol.html | 4 ++- - pyme-web/doc/pyme/pyme.constants.status.html | 9 ++++++ - pyme-web/doc/pyme/pyme.core.html | 36 ++++++++++++++++++---- - pyme-web/doc/pyme/pyme.errors.html | 8 ++--- - pyme-web/doc/pyme/pyme.html | 14 ++++----- - pyme-web/doc/pyme/pyme.util.html | 17 ++++++++-- - pyme-web/doc/pyme/pyme.version.html | 14 ++++----- - 9 files changed, 82 insertions(+), 35 deletions(-) - -commit 6973a69a317608a0d0661590d701f4e3f3a21b32 -Author: belyi -Date: Wed Apr 2 02:35:24 2008 +0000 - - Have a fix for Contents being put onto 'Function and Data Index' page. - - pyme-web/doc/gpgme/Concept-Index.html | 2 +- - pyme-web/doc/gpgme/Function-and-Data-Index.html | 153 +---------------------- - pyme-web/doc/gpgme/index.html | 154 +++++++++++++++++++++++- - 3 files changed, 155 insertions(+), 154 deletions(-) - -commit 086315964cbc2abad1187f306dcb9c72ac3257f3 -Author: belyi -Date: Wed Apr 2 01:00:29 2008 +0000 - - Update GPGME documentation. It's for v1.1.6 now. - - pyme-web/doc/gpgme/ASCII-Armor.html | 57 ++ - pyme-web/doc/gpgme/Advanced-Key-Editing.html | 98 +++ - pyme-web/doc/gpgme/Algorithms.html | 47 ++ - pyme-web/doc/gpgme/Building-the-Source.html | 82 +++ - .../doc/gpgme/Callback-Based-Data-Buffers.html | 148 +++++ - pyme-web/doc/gpgme/Cancellation.html | 67 ++ - pyme-web/doc/gpgme/Concept-Index.html | 186 ++++++ - pyme-web/doc/gpgme/Context-Attributes.html | 52 ++ - pyme-web/doc/gpgme/Contexts.html | 61 ++ - pyme-web/doc/gpgme/Creating-Contexts.html | 49 ++ - pyme-web/doc/gpgme/Creating-Data-Buffers.html | 47 ++ - pyme-web/doc/gpgme/Creating-a-Signature.html | 143 +++++ - pyme-web/doc/gpgme/Crypto-Engine.html | 79 +++ - pyme-web/doc/gpgme/Crypto-Operations.html | 67 ++ - .../doc/gpgme/Cryptographic-Message-Syntax.html | 42 ++ - .../doc/gpgme/Data-Buffer-I_002fO-Operations.html | 104 ++++ - pyme-web/doc/gpgme/Data-Buffer-Meta_002dData.html | 100 +++ - pyme-web/doc/gpgme/Decrypt-and-Verify.html | 79 +++ - pyme-web/doc/gpgme/Decrypt.html | 123 ++++ - pyme-web/doc/gpgme/Deleting-Keys.html | 67 ++ - pyme-web/doc/gpgme/Destroying-Contexts.html | 46 ++ - pyme-web/doc/gpgme/Destroying-Data-Buffers.html | 70 +++ - pyme-web/doc/gpgme/Encrypt.html | 45 ++ - pyme-web/doc/gpgme/Encrypting-a-Plaintext.html | 147 +++++ - pyme-web/doc/gpgme/Engine-Configuration.html | 65 ++ - pyme-web/doc/gpgme/Engine-Information.html | 119 ++++ - pyme-web/doc/gpgme/Engine-Version-Check.html | 48 ++ - pyme-web/doc/gpgme/Error-Codes.html | 133 ++++ - pyme-web/doc/gpgme/Error-Handling.html | 72 +++ - pyme-web/doc/gpgme/Error-Sources.html | 89 +++ - pyme-web/doc/gpgme/Error-Strings.html | 80 +++ - pyme-web/doc/gpgme/Error-Values.html | 159 +++++ - pyme-web/doc/gpgme/Exchanging-Data.html | 58 ++ - pyme-web/doc/gpgme/Exporting-Keys.html | 101 +++ - pyme-web/doc/gpgme/Features.html | 59 ++ - pyme-web/doc/gpgme/File-Based-Data-Buffers.html | 74 +++ - pyme-web/doc/gpgme/Function-and-Data-Index.html | 380 ++++++++++++ - pyme-web/doc/gpgme/Generating-Keys.html | 144 +++++ - pyme-web/doc/gpgme/Getting-Started.html | 55 ++ - pyme-web/doc/gpgme/Hash-Algorithms.html | 59 ++ - pyme-web/doc/gpgme/Header.html | 53 ++ - .../doc/gpgme/I_002fO-Callback-Example-GDK.html | 85 +++ - .../gpgme/I_002fO-Callback-Example-GTK_002b.html | 86 +++ - .../doc/gpgme/I_002fO-Callback-Example-Qt.html | 99 +++ - pyme-web/doc/gpgme/I_002fO-Callback-Example.html | 259 ++++++++ - pyme-web/doc/gpgme/I_002fO-Callback-Interface.html | 142 +++++ - pyme-web/doc/gpgme/Importing-Keys.html | 171 +++++ - pyme-web/doc/gpgme/Included-Certificates.html | 70 +++ - pyme-web/doc/gpgme/Information-About-Keys.html | 207 +++++++ - .../doc/gpgme/Information-About-Trust-Items.html | 75 +++ - pyme-web/doc/gpgme/Introduction.html | 53 ++ - pyme-web/doc/gpgme/Key-Listing-Mode.html | 99 +++ - pyme-web/doc/gpgme/Key-Management.html | 260 ++++++++ - pyme-web/doc/gpgme/Key-Signatures.html | 130 ++++ - .../doc/gpgme/Largefile-Support-_0028LFS_0029.html | 110 ++++ - pyme-web/doc/gpgme/Library-Copying.html | 542 ++++++++++++++++ - pyme-web/doc/gpgme/Library-Version-Check.html | 97 +++ - pyme-web/doc/gpgme/Listing-Keys.html | 204 ++++++ - pyme-web/doc/gpgme/Listing-Trust-Items.html | 88 +++ - pyme-web/doc/gpgme/Locale.html | 69 +++ - pyme-web/doc/gpgme/Manipulating-Data-Buffers.html | 45 ++ - pyme-web/doc/gpgme/Manipulating-Keys.html | 63 ++ - pyme-web/doc/gpgme/Manipulating-Trust-Items.html | 62 ++ - pyme-web/doc/gpgme/Memory-Based-Data-Buffers.html | 107 ++++ - pyme-web/doc/gpgme/Multi-Threading.html | 93 +++ - pyme-web/doc/gpgme/OpenPGP.html | 44 ++ - pyme-web/doc/gpgme/Overview.html | 57 ++ - pyme-web/doc/gpgme/Passphrase-Callback.html | 101 +++ - pyme-web/doc/gpgme/Preparation.html | 54 ++ - pyme-web/doc/gpgme/Progress-Meter-Callback.html | 80 +++ - pyme-web/doc/gpgme/Protocol-Selection.html | 60 ++ - pyme-web/doc/gpgme/Protocols-and-Engines.html | 82 +++ - pyme-web/doc/gpgme/Public-Key-Algorithms.html | 74 +++ - .../doc/gpgme/Registering-I_002fO-Callbacks.html | 81 +++ - pyme-web/doc/gpgme/Run-Control.html | 53 ++ - pyme-web/doc/gpgme/Selecting-Signers.html | 64 ++ - pyme-web/doc/gpgme/Sign.html | 50 ++ - pyme-web/doc/gpgme/Signal-Handling.html | 61 ++ - pyme-web/doc/gpgme/Signature-Notation-Data.html | 85 +++ - pyme-web/doc/gpgme/Text-Mode.html | 63 ++ - pyme-web/doc/gpgme/Trust-Item-Management.html | 68 ++ - pyme-web/doc/gpgme/Using-Automake.html | 74 +++ - pyme-web/doc/gpgme/Using-External-Event-Loops.html | 74 +++ - pyme-web/doc/gpgme/Using-Libtool.html | 44 ++ - pyme-web/doc/gpgme/Verify.html | 492 +++++++++++++++ - pyme-web/doc/gpgme/Waiting-For-Completion.html | 77 +++ - pyme-web/doc/gpgme/gpgme.html | 251 -------- - pyme-web/doc/gpgme/gpgme_1.html | 76 --- - pyme-web/doc/gpgme/gpgme_10.html | 61 -- - pyme-web/doc/gpgme/gpgme_11.html | 130 ---- - pyme-web/doc/gpgme/gpgme_12.html | 82 --- - pyme-web/doc/gpgme/gpgme_13.html | 130 ---- - pyme-web/doc/gpgme/gpgme_14.html | 108 ---- - pyme-web/doc/gpgme/gpgme_15.html | 69 --- - pyme-web/doc/gpgme/gpgme_16.html | 169 ----- - pyme-web/doc/gpgme/gpgme_17.html | 63 -- - pyme-web/doc/gpgme/gpgme_18.html | 63 -- - pyme-web/doc/gpgme/gpgme_19.html | 66 -- - pyme-web/doc/gpgme/gpgme_2.html | 79 --- - pyme-web/doc/gpgme/gpgme_20.html | 120 ---- - pyme-web/doc/gpgme/gpgme_21.html | 102 --- - pyme-web/doc/gpgme/gpgme_22.html | 108 ---- - pyme-web/doc/gpgme/gpgme_23.html | 237 ------- - pyme-web/doc/gpgme/gpgme_24.html | 154 ----- - pyme-web/doc/gpgme/gpgme_25.html | 248 -------- - pyme-web/doc/gpgme/gpgme_26.html | 107 ---- - pyme-web/doc/gpgme/gpgme_27.html | 80 --- - pyme-web/doc/gpgme/gpgme_28.html | 67 -- - pyme-web/doc/gpgme/gpgme_29.html | 164 ----- - pyme-web/doc/gpgme/gpgme_3.html | 86 --- - pyme-web/doc/gpgme/gpgme_30.html | 106 ---- - pyme-web/doc/gpgme/gpgme_31.html | 232 ------- - pyme-web/doc/gpgme/gpgme_32.html | 85 --- - pyme-web/doc/gpgme/gpgme_33.html | 223 ------- - pyme-web/doc/gpgme/gpgme_34.html | 83 --- - pyme-web/doc/gpgme/gpgme_35.html | 70 --- - pyme-web/doc/gpgme/gpgme_36.html | 63 -- - pyme-web/doc/gpgme/gpgme_37.html | 66 -- - pyme-web/doc/gpgme/gpgme_38.html | 86 --- - pyme-web/doc/gpgme/gpgme_39.html | 79 --- - pyme-web/doc/gpgme/gpgme_4.html | 83 --- - pyme-web/doc/gpgme/gpgme_40.html | 89 --- - pyme-web/doc/gpgme/gpgme_41.html | 99 --- - pyme-web/doc/gpgme/gpgme_42.html | 144 ----- - pyme-web/doc/gpgme/gpgme_43.html | 152 ----- - pyme-web/doc/gpgme/gpgme_44.html | 112 ---- - pyme-web/doc/gpgme/gpgme_45.html | 101 --- - pyme-web/doc/gpgme/gpgme_46.html | 459 -------------- - pyme-web/doc/gpgme/gpgme_47.html | 292 --------- - pyme-web/doc/gpgme/gpgme_48.html | 363 ----------- - pyme-web/doc/gpgme/gpgme_49.html | 209 ------- - pyme-web/doc/gpgme/gpgme_5.html | 74 --- - pyme-web/doc/gpgme/gpgme_50.html | 88 --- - pyme-web/doc/gpgme/gpgme_51.html | 208 ------- - pyme-web/doc/gpgme/gpgme_52.html | 154 ----- - pyme-web/doc/gpgme/gpgme_53.html | 291 --------- - pyme-web/doc/gpgme/gpgme_54.html | 91 --- - pyme-web/doc/gpgme/gpgme_55.html | 107 ---- - pyme-web/doc/gpgme/gpgme_56.html | 140 ----- - pyme-web/doc/gpgme/gpgme_57.html | 106 ---- - pyme-web/doc/gpgme/gpgme_58.html | 89 --- - pyme-web/doc/gpgme/gpgme_59.html | 97 --- - pyme-web/doc/gpgme/gpgme_6.html | 77 --- - pyme-web/doc/gpgme/gpgme_60.html | 142 ----- - pyme-web/doc/gpgme/gpgme_61.html | 626 ------------------- - pyme-web/doc/gpgme/gpgme_62.html | 107 ---- - pyme-web/doc/gpgme/gpgme_63.html | 67 -- - pyme-web/doc/gpgme/gpgme_64.html | 95 --- - pyme-web/doc/gpgme/gpgme_65.html | 233 ------- - pyme-web/doc/gpgme/gpgme_66.html | 65 -- - pyme-web/doc/gpgme/gpgme_67.html | 220 ------- - pyme-web/doc/gpgme/gpgme_68.html | 75 --- - pyme-web/doc/gpgme/gpgme_69.html | 119 ---- - pyme-web/doc/gpgme/gpgme_7.html | 123 ---- - pyme-web/doc/gpgme/gpgme_70.html | 107 ---- - pyme-web/doc/gpgme/gpgme_71.html | 218 ------- - pyme-web/doc/gpgme/gpgme_72.html | 134 ---- - pyme-web/doc/gpgme/gpgme_73.html | 299 --------- - pyme-web/doc/gpgme/gpgme_74.html | 103 ---- - pyme-web/doc/gpgme/gpgme_75.html | 104 ---- - pyme-web/doc/gpgme/gpgme_76.html | 118 ---- - pyme-web/doc/gpgme/gpgme_77.html | 95 --- - pyme-web/doc/gpgme/gpgme_78.html | 71 --- - pyme-web/doc/gpgme/gpgme_79.html | 686 --------------------- - pyme-web/doc/gpgme/gpgme_8.html | 155 ----- - pyme-web/doc/gpgme/gpgme_80.html | 120 ---- - pyme-web/doc/gpgme/gpgme_81.html | 278 --------- - pyme-web/doc/gpgme/gpgme_82.html | 272 -------- - pyme-web/doc/gpgme/gpgme_83.html | 180 ------ - pyme-web/doc/gpgme/gpgme_84.html | 99 --- - pyme-web/doc/gpgme/gpgme_9.html | 104 ---- - pyme-web/doc/gpgme/gpgme_abt.html | 206 ------- - pyme-web/doc/gpgme/gpgme_fot.html | 53 -- - pyme-web/doc/gpgme/gpgme_ovr.html | 68 -- - pyme-web/doc/gpgme/gpgme_toc.html | 247 -------- - pyme-web/doc/gpgme/index.html | 497 ++++++++------- - 176 files changed, 9054 insertions(+), 13378 deletions(-) - -commit 163c1053dc761682f5a4231da163bdd0ff7162d7 -Author: belyi -Date: Tue Apr 1 21:14:29 2008 +0000 - - Update Home page to be a bit more visitor friendly. - - pyme-web/Makefile | 2 +- - pyme-web/default.css | 27 ++++++++++++++++++++ - pyme-web/index.html | 70 +++++++++++++++++++++++++++++++++++----------------- - 3 files changed, 75 insertions(+), 24 deletions(-) - -commit 05db2d17d8fda0ab8c948bbdc0643dfc1466830d -Author: belyi -Date: Sun Mar 30 21:27:38 2008 +0000 - - Add a rule to build binary distribution for Windows. - - pyme/Makefile | 16 ++++++++++++++-- - 1 file changed, 14 insertions(+), 2 deletions(-) - -commit 57acb1089f5f8c24323ee62fc0a7f492a496b9c0 -Author: belyi -Date: Sat Mar 29 22:50:11 2008 +0000 - - Switch to using central location for python files (pycentral) - Update docs rule to fix location of the python source files. - - pyme/Makefile | 5 +++- - pyme/debian/changelog | 4 ++- - pyme/debian/control | 74 +++++------------------------------------------ - pyme/debian/dirs | 2 -- - pyme/debian/docs | 1 + - pyme/debian/postinst.ex | 48 ------------------------------ - pyme/debian/postrm.ex | 38 ------------------------ - pyme/debian/preinst.ex | 44 ---------------------------- - pyme/debian/prerm.ex | 39 ------------------------- - pyme/debian/rules | 50 ++++++-------------------------- - pyme/debian/setup.cfg-2.2 | 8 ----- - pyme/debian/setup.cfg-2.3 | 8 ----- - pyme/debian/setup.cfg-2.4 | 8 ----- - pyme/gpgme-h-clean.py | 2 +- - pyme/pyme/core.py | 2 +- - pyme/pyme/util.py | 2 +- - 16 files changed, 28 insertions(+), 307 deletions(-) - -commit 2b56fd10517cfbcffaa4ba98d8ea42f40f0d38a9 -Author: belyi -Date: Sun Mar 23 02:01:12 2008 +0000 - - Turn SWIG's autodoc feature on. Ignore 'next' in the types which are lists now. - Use new style for class declarations. Specify None as a default value for - core.check_version() method. Update version.py for 0.8.0 version. - - pyme/examples/pygpa.py | 2 +- - pyme/gpgme.i | 5 +++++ - pyme/pyme/core.py | 2 +- - pyme/pyme/util.py | 5 +++-- - pyme/pyme/version.py | 6 +++--- - 5 files changed, 13 insertions(+), 7 deletions(-) - -commit df5e25d7ee4dc0aa0d429f9d009322dd8ac33bb8 -Author: belyi -Date: Thu Mar 20 19:07:00 2008 +0000 - - Improve matching for DEPRECATED typedefs - - pyme/gpgme-h-clean.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -commit 78d8fc732848ac267ec65e9069265cd500587cdf -Author: belyi -Date: Wed Mar 19 19:28:40 2008 +0000 - - Update API to use list when types containing 'next' field are return. - Update examples accordingly - Add verifydetails.py example - Start adding bullets for 0.8.0 version. - - pyme/Makefile | 2 +- - pyme/debian/changelog | 14 +++++++- - pyme/examples/PyGtkGpgKeys.py | 53 +++++++++++++-------------- - pyme/examples/delkey.py | 7 ++-- - pyme/examples/encrypt-to-all.py | 7 ++-- - pyme/examples/exportimport.py | 7 ++-- - pyme/examples/pygpa.py | 70 ++++++++++++++++-------------------- - pyme/examples/signverify.py | 11 +++--- - pyme/examples/verifydetails.py | 79 +++++++++++++++++++++++++++++++++++++++++ - pyme/gpgme.i | 19 +++++++++- - 10 files changed, 180 insertions(+), 89 deletions(-) - -commit 342d85b07475e7360bcd62804bf5facda039494f -Author: belyi -Date: Mon Mar 10 01:14:16 2008 +0000 - - Change references to source files so that they point to the WebCVS browse - location. - - pyme-web/doc/pyme/index.html | 2 +- - pyme-web/doc/pyme/pyme.callbacks.html | 2 +- - pyme-web/doc/pyme/pyme.constants.data.encoding.html | 2 +- - pyme-web/doc/pyme/pyme.constants.data.html | 2 +- - pyme-web/doc/pyme/pyme.constants.event.html | 2 +- - pyme-web/doc/pyme/pyme.constants.html | 2 +- - pyme-web/doc/pyme/pyme.constants.import.html | 2 +- - pyme-web/doc/pyme/pyme.constants.keylist.html | 2 +- - pyme-web/doc/pyme/pyme.constants.keylist.mode.html | 2 +- - pyme-web/doc/pyme/pyme.constants.md.html | 2 +- - pyme-web/doc/pyme/pyme.constants.pk.html | 2 +- - pyme-web/doc/pyme/pyme.constants.protocol.html | 2 +- - pyme-web/doc/pyme/pyme.constants.sig.html | 2 +- - pyme-web/doc/pyme/pyme.constants.sig.mode.html | 2 +- - pyme-web/doc/pyme/pyme.constants.sigsum.html | 2 +- - pyme-web/doc/pyme/pyme.constants.status.html | 2 +- - pyme-web/doc/pyme/pyme.constants.validity.html | 2 +- - pyme-web/doc/pyme/pyme.core.html | 2 +- - pyme-web/doc/pyme/pyme.errors.html | 2 +- - pyme-web/doc/pyme/pyme.html | 2 +- - pyme-web/doc/pyme/pyme.util.html | 2 +- - pyme-web/doc/pyme/pyme.version.html | 2 +- - 22 files changed, 22 insertions(+), 22 deletions(-) - -commit 4139dd1d066c1a6c892d84fe45dc3e6c4aa1b803 -Author: belyi -Date: Sat Mar 8 18:21:08 2008 +0000 - - Add core.check_version(None) to all examples since this function is used by - Gpgme to do internal initialization. Update debian/rules to use dh_pysupport - instead of deprecated dh_python. - - pyme/debian/rules | 8 +++----- - pyme/examples/PyGtkGpgKeys.py | 7 ++++++- - pyme/examples/delkey.py | 2 ++ - pyme/examples/encrypt-to-all.py | 3 +++ - pyme/examples/exportimport.py | 2 ++ - pyme/examples/genkey.py | 1 + - pyme/examples/inter-edit.py | 3 +++ - pyme/examples/pygpa.py | 5 +++++ - pyme/examples/sign.py | 2 ++ - pyme/examples/signverify.py | 2 ++ - pyme/examples/simple.py | 2 ++ - pyme/examples/t-edit.py | 3 +++ - 12 files changed, 34 insertions(+), 6 deletions(-) - -commit ae76c6176457dd38e0634cbc17d794294a3a81d2 -Author: belyi -Date: Wed Apr 12 22:20:38 2006 +0000 - - Change name of internal package name from 'gpgme' to 'pygpgme' to avoid - conflict with gpgme.dll on Windows. - Fix build with SWIG 1.3.28. - Change version to 0.7.1 in a preparation for new release. - - pyme/Makefile | 3 +- - pyme/debian/changelog | 12 ++++ - pyme/gpgme.i | 19 +++--- - pyme/pyme/callbacks.py | 1 - - pyme/pyme/core.py | 153 +++++++++++++++++++++++++------------------------ - pyme/pyme/errors.py | 12 ++-- - pyme/pyme/util.py | 10 ++-- - pyme/pyme/version.py | 2 +- - pyme/setup.py | 4 +- - 9 files changed, 116 insertions(+), 100 deletions(-) - -commit d644383a76e9f83bc2d426628319e3c4a989dc2d -Author: belyi -Date: Sat Dec 17 01:34:53 2005 +0000 - - Put all constants into pyme.constants package to avoid stepping on python - reserved words. - Add build rules for Mingw32 and Cygwin on Windows. Rules for Mingw under - Debian are still to come. - Fixed a small bug in pygpa.py example. - - pyme/Makefile | 11 ++++++++--- - pyme/examples/pygpa.py | 3 ++- - pyme/pyme/__init__.py | 2 +- - pyme/pyme/constants/__init__.py | 3 +++ - pyme/setup.py | 42 ++++++++++++++++++++++++++++++++++++----- - 5 files changed, 51 insertions(+), 10 deletions(-) - -commit 89eb370fcaa8adc9d219eadbaa579dde7bf06329 -Author: belyi -Date: Mon Aug 1 03:08:32 2005 +0000 - - Imported changes provided by Joost van Baal: - Use dh_python in debian/rules and change the Section pyme belongs to from - 'libs' to 'python'. - - pyme/debian/control | 6 +++--- - pyme/debian/rules | 2 ++ - 2 files changed, 5 insertions(+), 3 deletions(-) - -commit ad76d10c2a77b45b7459c62131279e946b860891 -Author: belyi -Date: Fri Jun 10 03:01:22 2005 +0000 - - Update 'docs' rule in Makefile to build packages first to ensure that - documentation is build for the current version of pyme and not for the - installed one. - - Added 'callbacks' into the list of visible pyme modules (__all__ var.) - - Slightly updated INSTALL file. - - pyme/INSTALL | 11 ++++++++--- - pyme/Makefile | 4 ++-- - pyme/pyme/__init__.py | 2 +- - 3 files changed, 11 insertions(+), 6 deletions(-) - -commit 2fe1a81e00721698bfa6850b3db2eb85e43d1724 -Author: belyi -Date: Wed Jun 8 16:16:18 2005 +0000 - - Update pyme documentation to remove dead links to pyme.gpgme.html and - pyme._gpgme.html - Added reference to the installed GPGME and PyMe documentation to the head - web page. - Updated Makefile to install all *.html files and to clean *~ files in all - subdirectories - - pyme-web/Makefile | 10 ++++++---- - pyme-web/doc/pyme/index.html | 8 +++----- - pyme-web/doc/pyme/pyme.callbacks.html | 8 -------- - pyme-web/doc/pyme/pyme.core.html | 1 - - pyme-web/doc/pyme/pyme.errors.html | 8 -------- - pyme-web/doc/pyme/pyme.html | 8 +++----- - pyme-web/doc/pyme/pyme.util.html | 8 -------- - pyme-web/index.html | 9 +++++++-- - 8 files changed, 19 insertions(+), 41 deletions(-) - -commit 6aa34cce4ea0099e50b4936dfee59778157b8ca8 -Author: belyi -Date: Wed Jun 8 15:18:20 2005 +0000 - - Added pyme and gpgme documentation. - - pyme-web/doc/gpgme/gpgme.html | 251 ++++++++ - pyme-web/doc/gpgme/gpgme_1.html | 76 +++ - pyme-web/doc/gpgme/gpgme_10.html | 61 ++ - pyme-web/doc/gpgme/gpgme_11.html | 130 ++++ - pyme-web/doc/gpgme/gpgme_12.html | 82 +++ - pyme-web/doc/gpgme/gpgme_13.html | 130 ++++ - pyme-web/doc/gpgme/gpgme_14.html | 108 ++++ - pyme-web/doc/gpgme/gpgme_15.html | 69 +++ - pyme-web/doc/gpgme/gpgme_16.html | 169 +++++ - pyme-web/doc/gpgme/gpgme_17.html | 63 ++ - pyme-web/doc/gpgme/gpgme_18.html | 63 ++ - pyme-web/doc/gpgme/gpgme_19.html | 66 ++ - pyme-web/doc/gpgme/gpgme_2.html | 79 +++ - pyme-web/doc/gpgme/gpgme_20.html | 120 ++++ - pyme-web/doc/gpgme/gpgme_21.html | 102 +++ - pyme-web/doc/gpgme/gpgme_22.html | 108 ++++ - pyme-web/doc/gpgme/gpgme_23.html | 237 +++++++ - pyme-web/doc/gpgme/gpgme_24.html | 154 +++++ - pyme-web/doc/gpgme/gpgme_25.html | 248 ++++++++ - pyme-web/doc/gpgme/gpgme_26.html | 107 ++++ - pyme-web/doc/gpgme/gpgme_27.html | 80 +++ - pyme-web/doc/gpgme/gpgme_28.html | 67 ++ - pyme-web/doc/gpgme/gpgme_29.html | 164 +++++ - pyme-web/doc/gpgme/gpgme_3.html | 86 +++ - pyme-web/doc/gpgme/gpgme_30.html | 106 ++++ - pyme-web/doc/gpgme/gpgme_31.html | 232 +++++++ - pyme-web/doc/gpgme/gpgme_32.html | 85 +++ - pyme-web/doc/gpgme/gpgme_33.html | 223 +++++++ - pyme-web/doc/gpgme/gpgme_34.html | 83 +++ - pyme-web/doc/gpgme/gpgme_35.html | 70 +++ - pyme-web/doc/gpgme/gpgme_36.html | 63 ++ - pyme-web/doc/gpgme/gpgme_37.html | 66 ++ - pyme-web/doc/gpgme/gpgme_38.html | 86 +++ - pyme-web/doc/gpgme/gpgme_39.html | 79 +++ - pyme-web/doc/gpgme/gpgme_4.html | 83 +++ - pyme-web/doc/gpgme/gpgme_40.html | 89 +++ - pyme-web/doc/gpgme/gpgme_41.html | 99 +++ - pyme-web/doc/gpgme/gpgme_42.html | 144 +++++ - pyme-web/doc/gpgme/gpgme_43.html | 152 +++++ - pyme-web/doc/gpgme/gpgme_44.html | 112 ++++ - pyme-web/doc/gpgme/gpgme_45.html | 101 +++ - pyme-web/doc/gpgme/gpgme_46.html | 459 ++++++++++++++ - pyme-web/doc/gpgme/gpgme_47.html | 292 +++++++++ - pyme-web/doc/gpgme/gpgme_48.html | 363 +++++++++++ - pyme-web/doc/gpgme/gpgme_49.html | 209 +++++++ - pyme-web/doc/gpgme/gpgme_5.html | 74 +++ - pyme-web/doc/gpgme/gpgme_50.html | 88 +++ - pyme-web/doc/gpgme/gpgme_51.html | 208 +++++++ - pyme-web/doc/gpgme/gpgme_52.html | 154 +++++ - pyme-web/doc/gpgme/gpgme_53.html | 291 +++++++++ - pyme-web/doc/gpgme/gpgme_54.html | 91 +++ - pyme-web/doc/gpgme/gpgme_55.html | 107 ++++ - pyme-web/doc/gpgme/gpgme_56.html | 140 +++++ - pyme-web/doc/gpgme/gpgme_57.html | 106 ++++ - pyme-web/doc/gpgme/gpgme_58.html | 89 +++ - pyme-web/doc/gpgme/gpgme_59.html | 97 +++ - pyme-web/doc/gpgme/gpgme_6.html | 77 +++ - pyme-web/doc/gpgme/gpgme_60.html | 142 +++++ - pyme-web/doc/gpgme/gpgme_61.html | 626 +++++++++++++++++++ - pyme-web/doc/gpgme/gpgme_62.html | 107 ++++ - pyme-web/doc/gpgme/gpgme_63.html | 67 ++ - pyme-web/doc/gpgme/gpgme_64.html | 95 +++ - pyme-web/doc/gpgme/gpgme_65.html | 233 +++++++ - pyme-web/doc/gpgme/gpgme_66.html | 65 ++ - pyme-web/doc/gpgme/gpgme_67.html | 220 +++++++ - pyme-web/doc/gpgme/gpgme_68.html | 75 +++ - pyme-web/doc/gpgme/gpgme_69.html | 119 ++++ - pyme-web/doc/gpgme/gpgme_7.html | 123 ++++ - pyme-web/doc/gpgme/gpgme_70.html | 107 ++++ - pyme-web/doc/gpgme/gpgme_71.html | 218 +++++++ - pyme-web/doc/gpgme/gpgme_72.html | 134 ++++ - pyme-web/doc/gpgme/gpgme_73.html | 299 +++++++++ - pyme-web/doc/gpgme/gpgme_74.html | 103 ++++ - pyme-web/doc/gpgme/gpgme_75.html | 104 ++++ - pyme-web/doc/gpgme/gpgme_76.html | 118 ++++ - pyme-web/doc/gpgme/gpgme_77.html | 95 +++ - pyme-web/doc/gpgme/gpgme_78.html | 71 +++ - pyme-web/doc/gpgme/gpgme_79.html | 686 +++++++++++++++++++++ - pyme-web/doc/gpgme/gpgme_8.html | 155 +++++ - pyme-web/doc/gpgme/gpgme_80.html | 120 ++++ - pyme-web/doc/gpgme/gpgme_81.html | 278 +++++++++ - pyme-web/doc/gpgme/gpgme_82.html | 272 ++++++++ - pyme-web/doc/gpgme/gpgme_83.html | 180 ++++++ - pyme-web/doc/gpgme/gpgme_84.html | 99 +++ - pyme-web/doc/gpgme/gpgme_9.html | 104 ++++ - pyme-web/doc/gpgme/gpgme_abt.html | 206 +++++++ - pyme-web/doc/gpgme/gpgme_fot.html | 53 ++ - pyme-web/doc/gpgme/gpgme_ovr.html | 68 ++ - pyme-web/doc/gpgme/gpgme_toc.html | 247 ++++++++ - pyme-web/doc/gpgme/index.html | 251 ++++++++ - pyme-web/doc/pyme/index.html | 166 +++++ - pyme-web/doc/pyme/pyme.callbacks.html | 50 ++ - .../doc/pyme/pyme.constants.data.encoding.html | 48 ++ - pyme-web/doc/pyme/pyme.constants.data.html | 29 + - pyme-web/doc/pyme/pyme.constants.event.html | 48 ++ - pyme-web/doc/pyme/pyme.constants.html | 39 ++ - pyme-web/doc/pyme/pyme.constants.import.html | 49 ++ - pyme-web/doc/pyme/pyme.constants.keylist.html | 29 + - pyme-web/doc/pyme/pyme.constants.keylist.mode.html | 48 ++ - pyme-web/doc/pyme/pyme.constants.md.html | 58 ++ - pyme-web/doc/pyme/pyme.constants.pk.html | 50 ++ - pyme-web/doc/pyme/pyme.constants.protocol.html | 46 ++ - pyme-web/doc/pyme/pyme.constants.sig.html | 29 + - pyme-web/doc/pyme/pyme.constants.sig.mode.html | 47 ++ - pyme-web/doc/pyme/pyme.constants.sigsum.html | 55 ++ - pyme-web/doc/pyme/pyme.constants.status.html | 117 ++++ - pyme-web/doc/pyme/pyme.constants.validity.html | 50 ++ - pyme-web/doc/pyme/pyme.core.html | 254 ++++++++ - pyme-web/doc/pyme/pyme.errors.html | 90 +++ - pyme-web/doc/pyme/pyme.html | 166 +++++ - pyme-web/doc/pyme/pyme.util.html | 78 +++ - pyme-web/doc/pyme/pyme.version.html | 37 ++ - pyme-web/index.html | 6 +- - 113 files changed, 14966 insertions(+), 1 deletion(-) - -commit 2d6fe54479f042644f7b0f3d2fe35877d2056144 -Author: belyi -Date: Thu May 19 02:06:09 2005 +0000 - - Added INSTALL file. - - pyme/INSTALL | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -commit d6892fff0c3cedf41dba4c25ab8608e7f2bc039c -Author: belyi -Date: Tue May 17 16:49:28 2005 +0000 - - Update copyright note on simple.py - - pyme/examples/simple.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -commit c2cd9cdf5995843aad7b200b929db2969effc9d2 -Author: belyi -Date: Tue May 17 15:03:58 2005 +0000 - - Update simple.py to catch errors. - - pyme/examples/simple.py | 17 +++++++++++------ - 1 file changed, 11 insertions(+), 6 deletions(-) - -commit eaedae7c6a0ea993caab067efe781a59b6769c44 -Author: belyi -Date: Tue May 17 01:18:23 2005 +0000 - - Added 'PYTHON = python' into Makefile for bug #1199122 - - pyme/Makefile | 1 + - pyme/examples/signverify.py | 1 + - 2 files changed, 2 insertions(+) - -commit 56fd244bb2636a4d58629899ea3cde1d96428198 -Author: belyi -Date: Wed Apr 27 21:37:06 2005 +0000 - - Added pygpa example. - - pyme/debian/changelog | 3 +- - pyme/examples/pygpa.glade | 5546 +++++++++++++++++++++++++++++++++++++++++++++ - pyme/examples/pygpa.py | 1459 ++++++++++++ - 3 files changed, 7007 insertions(+), 1 deletion(-) - -commit 2d9a2a91a59ac3fee5410c953b7e0859e9e7cd35 -Author: belyi -Date: Thu Apr 21 15:17:51 2005 +0000 - - Change version to 0.7.0 due to the change in license. - - pyme/debian/changelog | 2 +- - pyme/pyme/version.py | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -commit 94e34e38d742f145385bd235825b6ba1e30d8339 -Author: belyi -Date: Thu Apr 21 03:53:12 2005 +0000 - - Changed license on PyMe from GPL to LGPL. - PyMe examples keep GPL license. - - pyme/COPYING.LESSER | 510 +++++++++++++++++++++++++++++++++++ - pyme/Makefile | 20 +- - pyme/debian/changelog | 4 +- - pyme/debian/copyright | 22 +- - pyme/gpgme-h-clean.py | 16 ++ - pyme/gpgme.i | 20 +- - pyme/helpers.c | 20 +- - pyme/helpers.h | 20 +- - pyme/pyme/__init__.py | 20 +- - pyme/pyme/callbacks.py | 20 +- - pyme/pyme/constants/data/encoding.py | 20 +- - pyme/pyme/constants/event.py | 20 +- - pyme/pyme/constants/import.py | 20 +- - pyme/pyme/constants/keylist/mode.py | 20 +- - pyme/pyme/constants/md.py | 20 +- - pyme/pyme/constants/pk.py | 20 +- - pyme/pyme/constants/protocol.py | 20 +- - pyme/pyme/constants/sig/mode.py | 20 +- - pyme/pyme/constants/sigsum.py | 20 +- - pyme/pyme/constants/status.py | 20 +- - pyme/pyme/constants/validity.py | 20 +- - pyme/pyme/core.py | 20 +- - pyme/pyme/errors.py | 20 +- - pyme/pyme/util.py | 20 +- - pyme/pyme/version.py | 22 +- - pyme/setup.py | 20 +- - 26 files changed, 761 insertions(+), 233 deletions(-) - -commit 0d8aa0f6335cb1506a37085095ed45173b099a02 -Author: belyi -Date: Tue Apr 19 01:46:06 2005 +0000 - - Added __hash__ and __eq__ methods to GpgmeWrapper to allow both Context() - and Data() to be used as a dictionary key. - Changed core.wait() function to always return a tuple. On timeout now it - returns (0, None) instead of just None. Plus, return context is now a - Context() object instead of a wrapper return by underlying gpgme. - - pyme/helpers.c | 1 - - pyme/pyme/core.py | 25 +++++++++++++++---------- - pyme/pyme/util.py | 9 +++++++++ - 3 files changed, 24 insertions(+), 11 deletions(-) - -commit 63ff6d10637be1dcbcd78c939ac1ef1ac30b1024 -Author: belyi -Date: Wed Apr 6 04:58:40 2005 +0000 - - Made hook parameter optional in passphrase_cb and progress_cb. - Allowed None for callbacks to unset ones set previously. - Removed cleanup of exception in callbacks - now just retrieve the error code. - Added prev_bad parameter in passphrase_cb since it can be used in - change password protocols. - Updated examples to follow new sets of arguments in callbacks - Updated op_edit to check if passed key is None (otherwise gpgme dumps core) - God rid of annoying warning "function declaration isn't a prototype" in - helpers.c and helpers.h by changing from () to (void) list of arguments. - - pyme/debian/changelog | 10 +++++--- - pyme/examples/signverify.py | 2 +- - pyme/examples/t-edit.py | 2 +- - pyme/gpgme.i | 18 +++++++++----- - pyme/helpers.c | 60 ++++++++++++++++++++++++++++++--------------- - pyme/helpers.h | 4 +-- - pyme/pyme/callbacks.py | 6 +++-- - pyme/pyme/core.py | 47 +++++++++++++++++++++-------------- - pyme/pyme/errors.py | 2 +- - 9 files changed, 96 insertions(+), 55 deletions(-) - -commit 8f0ab8138c7aa190936376ccbbf33bb09c64d6f1 -Author: belyi -Date: Thu Mar 31 23:50:59 2005 +0000 - - Added exception handling in passphrase_cb and edit_cb. If GPGMEError - exception is thrown in those callbacks it will be converted into its - core representation and return as an error code to the caller. - On all other exceptions error code will be GPG_ERR_GENERAL. - - pyme/Makefile | 1 + - pyme/debian/changelog | 8 ++++++++ - pyme/gpgme.i | 20 ++++++++++++++------ - pyme/helpers.c | 51 +++++++++++++++++++++++++++++++++++++++++++++------ - pyme/helpers.h | 3 +++ - 5 files changed, 71 insertions(+), 12 deletions(-) - -commit 9903d1fb11231e7e3d920e58d1ecb674c5988b07 -Author: belyi -Date: Thu Mar 31 05:12:15 2005 +0000 - - Remove workaround from Context.wait() method since the bug report and - patch fixing gpgme_wait's behavior is sent to GPMGE developers already. - Added errorcheck into op_edit() so that it can report an error. - - pyme/pyme/core.py | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -commit 45e8a5f4e13d3ca797ec3b0037242874a6be5562 -Author: belyi -Date: Sat Mar 26 19:44:18 2005 +0000 - - Updated verion number to 0.6.2 in version.py - Added examples/*.glade files into documentation package. - - pyme/debian/examples | 1 + - pyme/pyme/version.py | 2 +- - 2 files changed, 2 insertions(+), 1 deletion(-) - -commit 270b87bb40e180cb6e8f1de9a0e8161525ffa4ab -Author: belyi -Date: Sat Mar 26 19:31:14 2005 +0000 - - Updated debian/changelog regarding PyGtkGpgKeys example and a fix in errors. - - pyme/debian/changelog | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -commit ea4682009a506db91e5174ffd038fe7e4406b591 -Author: belyi -Date: Sat Mar 26 19:25:36 2005 +0000 - - Added handling of right mouse button click. - Changed reporting a string instead of a number on key generation failure. - - pyme/examples/PyGtkGpgKeys.glade | 2 ++ - pyme/examples/PyGtkGpgKeys.py | 30 +++++++++++++++++++++++++++--- - 2 files changed, 29 insertions(+), 3 deletions(-) - -commit f65ad1a703d0098a3204fb8527a54d253e5847e7 -Author: belyi -Date: Sat Mar 26 18:11:11 2005 +0000 - - Added another column indicating if a key has a secret part. - Automated generation of the View menu from the view field of the KeyColumn - class. - - pyme/examples/PyGtkGpgKeys.glade | 93 ++-------------------------------------- - pyme/examples/PyGtkGpgKeys.py | 74 +++++++++++++++++--------------- - 2 files changed, 44 insertions(+), 123 deletions(-) - -commit b54e83a7a7a5785502f3c7e8b95f15e23b40e65a -Author: belyi -Date: Sat Mar 26 16:45:13 2005 +0000 - - Small change to the way gtk.TreeModel object is used. - - pyme/examples/PyGtkGpgKeys.py | 21 ++++++++++----------- - 1 file changed, 10 insertions(+), 11 deletions(-) - -commit 7078db75cef4c1fd70cf03e37172bdb4f933fd1b -Author: belyi -Date: Fri Mar 25 23:33:06 2005 +0000 - - Use more comprehansible error reporting since gpgme_strerror_r returns None - all the time. - - pyme/pyme/errors.py | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -commit 151213f4344d9984975721440af07de09e3df61c -Author: belyi -Date: Fri Mar 25 04:30:17 2005 +0000 - - Improved PyGtkGpgKeys example to manage owner_trust on keys. - Added another example inter-edit.py which is just a hepler to write - scripts for Context.op_edit() command. - - pyme/examples/PyGtkGpgKeys.glade | 78 ++++++++++++++++++++++++++++++++++++++++ - pyme/examples/PyGtkGpgKeys.py | 68 +++++++++++++++++++++++++++++++---- - pyme/examples/inter-edit.py | 54 ++++++++++++++++++++++++++++ - pyme/examples/t-edit.py | 18 ++++++++++ - 4 files changed, 212 insertions(+), 6 deletions(-) - -commit fc7235af217bcee5231ce7fbd7f234712d5ad3b0 -Author: belyi -Date: Fri Mar 25 00:30:39 2005 +0000 - - Updated PyGtkGpgKeys example to include import, export and reload - functionality. Also added ability to remove number of keys simultanously. - Rearanged how KeyColumn is used to avoid unnecessary sorts and duplication - of information in different parts of the code. - - pyme/examples/PyGtkGpgKeys.glade | 86 +++++++++- - pyme/examples/PyGtkGpgKeys.py | 332 ++++++++++++++++++++++++++++----------- - 2 files changed, 325 insertions(+), 93 deletions(-) - -commit 9f65749ccb1b7cab562e19c03f4371d5f7d94912 -Author: belyi -Date: Thu Mar 24 05:51:03 2005 +0000 - - Added example of PyGTK+ and PyMe integration. - For now it does only simple things - listing, deleting, and generating keys. - - pyme/examples/PyGtkGpgKeys.glade | 1321 +++++++++++++++++++++++++++++++++++++ - pyme/examples/PyGtkGpgKeys.gladep | 8 + - pyme/examples/PyGtkGpgKeys.py | 424 ++++++++++++ - 3 files changed, 1753 insertions(+) - -commit 59e23f32c3b46413c9ec09e23e1a385a110fb103 -Author: belyi -Date: Thu Mar 24 05:44:58 2005 +0000 - - Added wait method Context class which handles asynchornous calls a little - bit better than the one generated by SWIG. - - pyme/debian/changelog | 7 +++++++ - pyme/gpgme.i | 1 + - pyme/pyme/core.py | 40 ++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 48 insertions(+) - -commit 4c1b5259e4985df2cba0ae4fc09f12cd94603a75 -Author: belyi -Date: Tue Mar 22 18:29:31 2005 +0000 - - Added correct handling of Context.op_edit() method. - Added example/t-edit.py showing usage for this method. - Output of this example should match output of the tests/gpg/t-edit - from the GPGME test suite. - Remove unused static function from helpers.c - - pyme/examples/t-edit.py | 38 ++++++++++++++++++++++++++++++++++++++ - pyme/gpgme.i | 36 ++++++++++++++++++++++++++++++++++++ - pyme/helpers.c | 36 ------------------------------------ - pyme/pyme/core.py | 5 ++++- - 4 files changed, 78 insertions(+), 37 deletions(-) - -commit dc587e215283bfef2dd594f86a7b2945f74f5155 -Author: belyi -Date: Sat Mar 19 01:43:59 2005 +0000 - - Update changelog to include note about deprecated function in 0.6.1 release - - pyme/debian/changelog | 3 ++- - pyme/examples/encrypt-to-all.py | 3 +-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -commit 86de4b3ad777f980ccf7ba3462c85bbe1787d1fd -Author: belyi -Date: Sat Mar 19 01:40:07 2005 +0000 - - Remove deprecated functions from helpers.[ch] - Use gpgme-h-clean.py to remove deprecated functions and typedefs from - the GPGME header file. This will reduce the number of unused methods. - - pyme/Makefile | 4 ++-- - pyme/gpgme-h-clean.py | 26 ++++++++++++++++++++++++++ - pyme/helpers.c | 8 -------- - pyme/helpers.h | 2 -- - 4 files changed, 28 insertions(+), 12 deletions(-) - -commit 2483efcbd0d73c628c4d7717928a766c3b58f0aa -Author: belyi -Date: Fri Mar 18 22:15:52 2005 +0000 - - Update copyright and author values in pyme/version.py - Create rules to build distribution files - one full and one without - debian bits. - - pyme/Makefile | 28 ++++++++++++++++++++++------ - pyme/pyme/version.py | 12 ++++++------ - 2 files changed, 28 insertions(+), 12 deletions(-) - -commit 168593285380f5a7805f3dd08657d429a72d3621 -Author: belyi -Date: Fri Mar 18 19:09:33 2005 +0000 - - Added package building for python2.4 - - Updated copyright notes to include myslef and avoid confusion who's the - maintainer. In John's own words: "I'd prefer to just step out of the picture". - Jonh's copyright notice left intact. - - pyme/Makefile | 6 +++--- - pyme/debian/changelog | 7 +++++++ - pyme/debian/control | 30 +++++++++++++++++++++++++++--- - pyme/debian/copyright | 10 ++++------ - pyme/debian/rules | 4 ++++ - pyme/debian/setup.cfg-2.4 | 8 ++++++++ - pyme/examples/genkey.py | 4 ++-- - pyme/gpgme.i | 4 ++-- - pyme/helpers.c | 4 ++-- - pyme/helpers.h | 4 ++-- - pyme/pyme/__init__.py | 4 ++-- - pyme/pyme/callbacks.py | 4 ++-- - pyme/pyme/constants/data/encoding.py | 4 ++-- - pyme/pyme/constants/event.py | 4 ++-- - pyme/pyme/constants/import.py | 4 ++-- - pyme/pyme/constants/keylist/mode.py | 4 ++-- - pyme/pyme/constants/md.py | 4 ++-- - pyme/pyme/constants/pk.py | 4 ++-- - pyme/pyme/constants/protocol.py | 4 ++-- - pyme/pyme/constants/sig/mode.py | 4 ++-- - pyme/pyme/constants/sigsum.py | 4 ++-- - pyme/pyme/constants/status.py | 4 ++-- - pyme/pyme/constants/validity.py | 4 ++-- - pyme/pyme/core.py | 4 ++-- - pyme/pyme/errors.py | 4 ++-- - pyme/pyme/util.py | 4 ++-- - pyme/pyme/version.py | 2 +- - pyme/setup.py | 3 ++- - 28 files changed, 96 insertions(+), 54 deletions(-) - -commit 6dbbb252771133724b2879ed6d767cd708196dae -Author: belyi -Date: Fri Mar 18 18:04:35 2005 +0000 - - Remove the note about gpgme.i to be generated - it's been the primary source - for some time. - - pyme/gpgme.i | 6 ------ - 1 file changed, 6 deletions(-) - -commit 9d449fa4889c6bda6d14583c0625b8d5c4ffe759 -Author: belyi -Date: Fri May 7 18:31:22 2004 +0000 - - Added my copyright in genkey.py since there's enough changes made. - Updated signverify to use only keys generated by genkey.py, to check - that keys added to singers are able to sign and to check that the - list of signers is not empty. The last check is necessary to prevent - signing with the key of the user running signverify.py script. - Added delkey.py script to delete keys generated by genkey.py - Added exportimport.py example for key export/import. - - pyme/examples/delkey.py | 29 +++++++++++++++++ - pyme/examples/exportimport.py | 76 +++++++++++++++++++++++++++++++++++++++++++ - pyme/examples/genkey.py | 6 ++-- - pyme/examples/signverify.py | 18 ++++++---- - 4 files changed, 119 insertions(+), 10 deletions(-) - -commit df98c8d28245ad2c14b0ab50fc8f8932853bec8b -Author: belyi -Date: Tue May 4 17:34:15 2004 +0000 - - Added examples/signverify.py for unattended sing/verify. - Updated examples/genkey.py to work correctly. - Updated gpgme.i to allow None as a value for gpgme_data_t - - pyme/examples/genkey.py | 14 ++------- - pyme/examples/signverify.py | 72 +++++++++++++++++++++++++++++++++++++++++++++ - pyme/gpgme.i | 21 ++++++++----- - 3 files changed, 87 insertions(+), 20 deletions(-) - -commit ba45931abf530ab89ead46d7233ff1b62b629a18 -Author: belyi -Date: Thu Apr 8 16:15:09 2004 +0000 - - Ensure that we support only python2.2 and up. :-) - Use generators in core.Context class which makes pyme.aux obsolete - Remove importing future nested_scopes since they are standart starting - with python2.2 - - pyme/pyme/__init__.py | 5 ++--- - pyme/pyme/aux.py | 56 --------------------------------------------------- - pyme/pyme/core.py | 15 +++++++++++--- - pyme/pyme/errors.py | 1 - - pyme/pyme/util.py | 2 +- - 5 files changed, 15 insertions(+), 64 deletions(-) - -commit 4e9be5a55ecffa4da7ad5c192cc892eddaaa9586 -Author: belyi -Date: Sun Mar 21 03:53:30 2004 +0000 - - Small change to index.html - Added clean: rule to the Makefile - - pyme-web/Makefile | 3 +++ - pyme-web/index.html | 6 +++--- - 2 files changed, 6 insertions(+), 3 deletions(-) - -commit 2efb95176f4edf56ed61c9ac0c3aa09c56534df0 -Author: belyi -Date: Sun Mar 21 03:00:32 2004 +0000 - - Added Makefile rules for pyme module installation. - - pyme/Makefile | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -commit 2b83d5d8b513029cc3e54f2fa502ccc85618104b -Author: belyi -Date: Sun Mar 21 02:29:54 2004 +0000 - - Decorative change. - - pyme/pyme/aux.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit e3478015d763a036c1d806ae01433fce59712204 -Author: belyi -Date: Sun Mar 21 02:25:55 2004 +0000 - - Added RCS Id: tags - - pyme/Makefile | 1 + - pyme/examples/encrypt-to-all.py | 3 ++- - pyme/examples/genkey.py | 3 ++- - pyme/examples/sign.py | 3 ++- - pyme/examples/simple.py | 3 ++- - pyme/gpgme.i | 1 + - pyme/helpers.c | 1 + - pyme/helpers.h | 1 + - pyme/pyme/__init__.py | 1 + - pyme/pyme/aux.py | 1 + - pyme/pyme/callbacks.py | 1 + - pyme/pyme/constants/__init__.py | 2 ++ - pyme/pyme/constants/data/__init__.py | 2 ++ - pyme/pyme/constants/data/encoding.py | 1 + - pyme/pyme/constants/event.py | 1 + - pyme/pyme/constants/import.py | 1 + - pyme/pyme/constants/keylist/__init__.py | 2 ++ - pyme/pyme/constants/keylist/mode.py | 1 + - pyme/pyme/constants/md.py | 1 + - pyme/pyme/constants/pk.py | 1 + - pyme/pyme/constants/protocol.py | 1 + - pyme/pyme/constants/sig/__init__.py | 2 ++ - pyme/pyme/constants/sig/mode.py | 1 + - pyme/pyme/constants/sigsum.py | 1 + - pyme/pyme/constants/status.py | 1 + - pyme/pyme/constants/validity.py | 1 + - pyme/pyme/core.py | 1 + - pyme/pyme/errors.py | 1 + - pyme/pyme/util.py | 1 + - pyme/pyme/version.py | 2 ++ - 30 files changed, 39 insertions(+), 4 deletions(-) - -commit b3b3712645332c5bc3e8d9d557aab21d48ff0f86 -Author: belyi -Date: Sun Mar 21 02:07:36 2004 +0000 - - Added Id: RCS tags to all files. - - pyme-web/Makefile | 2 ++ - pyme-web/index.html | 3 ++- - 2 files changed, 4 insertions(+), 1 deletion(-) - -commit 6aea2426beaaa8c43e6f2310a37a2737c0c3a1b5 -Author: belyi -Date: Sun Mar 21 01:50:55 2004 +0000 - - Update example on the init pyme.html page to match simple.py example. - Fix core.py to use getcode() instead of getvalue() method of the exception. - - pyme/pyme/__init__.py | 22 ++++++++++++++-------- - pyme/pyme/core.py | 4 ++-- - 2 files changed, 16 insertions(+), 10 deletions(-) - -commit dee337455ffd624d3f83e1c159c4bb2cefc692c9 -Author: belyi -Date: Sat Mar 20 20:32:29 2004 +0000 - - Added Makefile to simplify publishing web files. - - pyme-web/Makefile | 7 +++++++ - 1 file changed, 7 insertions(+) - -commit af7129baa8260697d85c2ddb434562e8a80b62d8 -Author: belyi -Date: Sat Mar 20 20:15:53 2004 +0000 - - Added minimum of formating and SF icon. - - pyme-web/index.html | 18 +++++++++++------- - 1 file changed, 11 insertions(+), 7 deletions(-) - -commit 2e64dcbf99cee796b51667b04d8961e390edde87 -Author: belyi -Date: Sat Mar 20 18:30:09 2004 +0000 - - Initial revision - - pyme-web/index.html | 33 +++++++++++++++++++++++++++++++++ - 1 file changed, 33 insertions(+) - -commit 1c51644b3d0b6611422d971758e35f303d2ad5df -Author: belyi -Date: Sat Mar 20 05:10:46 2004 +0000 - - Update examples and package information on the initial pyme doc page. - - pyme/pyme/__init__.py | 27 ++++++++++++--------------- - 1 file changed, 12 insertions(+), 15 deletions(-) - -commit b2d31b0bfbffdff5247d6db4e3c95140cc1b1f19 -Author: belyi -Date: Sat Mar 20 04:47:42 2004 +0000 - - Deleted unnecessary files. - Updated debian/control to remove dependency on python-xml package since there's - none now. - Move example files from 'doc' into separate control file. - Update debian/rules to build documentation from *.py files and to exclude - CVS directories from the installation. - - pyme/Makefile | 26 ++----- - pyme/debian/control | 8 +-- - pyme/debian/docs | 1 - - pyme/debian/ex.package.doc-base | 22 ------ - pyme/debian/examples | 1 + - pyme/debian/manpage.1.ex | 60 ---------------- - pyme/debian/manpage.sgml.ex | 152 ---------------------------------------- - pyme/debian/rules | 12 ++-- - 8 files changed, 15 insertions(+), 267 deletions(-) - -commit 1b517dd9b82a433499b4696b06d94d756cd36e53 -Author: belyi -Date: Sat Mar 20 02:59:15 2004 +0000 - - Remove doc/gpgme directory containing GPGME documentation since this belongs - to a different project. Need to add reference in our documentation. - - pyme/doc/gpgme/fdl.texi | 402 ------ - pyme/doc/gpgme/gpgme.texi | 3372 ------------------------------------------- - pyme/doc/gpgme/gpl.texi | 397 ----- - pyme/doc/gpgme/version.texi | 4 - - 4 files changed, 4175 deletions(-) - -commit 95d7d171da115a0fedfe2a4a7e5acc8aa408f673 -Author: belyi -Date: Sat Mar 20 02:45:03 2004 +0000 - - Change debian/rules to generate files by swig during build and to cleanup - those files on 'clean' rule. - Plus, leave generated gpgme_wrap.c in the root directory instead of moving - it into subdirectory 'generated'. - - pyme/Makefile | 8 +++----- - pyme/debian/rules | 3 ++- - pyme/setup.py | 2 +- - 3 files changed, 6 insertions(+), 7 deletions(-) - -commit 545b3d90d445c5c78e8d72b2c1780863e02c789a -Author: belyi -Date: Sat Mar 20 02:18:01 2004 +0000 - - Initial revision - - pyme/COPYING | 340 ++++ - pyme/ChangeLog | 802 ++++++++ - pyme/Makefile | 79 + - pyme/debian/README.Debian | 6 + - pyme/debian/changelog | 19 + - pyme/debian/control | 68 + - pyme/debian/copyright | 27 + - pyme/debian/dirs | 2 + - pyme/debian/docs | 2 + - pyme/debian/ex.package.doc-base | 22 + - pyme/debian/manpage.1.ex | 60 + - pyme/debian/manpage.sgml.ex | 152 ++ - pyme/debian/postinst.ex | 48 + - pyme/debian/postrm.ex | 38 + - pyme/debian/preinst.ex | 44 + - pyme/debian/prerm.ex | 39 + - pyme/debian/rules | 130 ++ - pyme/debian/setup.cfg-2.2 | 8 + - pyme/debian/setup.cfg-2.3 | 8 + - pyme/doc/gpgme/fdl.texi | 402 ++++ - pyme/doc/gpgme/gpgme.texi | 3372 +++++++++++++++++++++++++++++++ - pyme/doc/gpgme/gpl.texi | 397 ++++ - pyme/doc/gpgme/version.texi | 4 + - pyme/examples/encrypt-to-all.py | 63 + - pyme/examples/genkey.py | 55 + - pyme/examples/sign.py | 28 + - pyme/examples/simple.py | 44 + - pyme/gpgme.i | 191 ++ - pyme/helpers.c | 139 ++ - pyme/helpers.h | 29 + - pyme/pyme/__init__.py | 134 ++ - pyme/pyme/aux.py | 55 + - pyme/pyme/callbacks.py | 45 + - pyme/pyme/constants/__init__.py | 2 + - pyme/pyme/constants/data/__init__.py | 2 + - pyme/pyme/constants/data/encoding.py | 19 + - pyme/pyme/constants/event.py | 19 + - pyme/pyme/constants/import.py | 19 + - pyme/pyme/constants/keylist/__init__.py | 2 + - pyme/pyme/constants/keylist/mode.py | 19 + - pyme/pyme/constants/md.py | 19 + - pyme/pyme/constants/pk.py | 19 + - pyme/pyme/constants/protocol.py | 19 + - pyme/pyme/constants/sig/__init__.py | 2 + - pyme/pyme/constants/sig/mode.py | 19 + - pyme/pyme/constants/sigsum.py | 19 + - pyme/pyme/constants/status.py | 19 + - pyme/pyme/constants/validity.py | 19 + - pyme/pyme/core.py | 367 ++++ - pyme/pyme/errors.py | 46 + - pyme/pyme/util.py | 61 + - pyme/pyme/version.py | 39 + - pyme/setup.py | 60 + - 53 files changed, 7642 insertions(+) - -commit a3d5a442dc713b6c4d6fc4134db5b47e379dc41d -Author: root -Date: Fri Mar 19 14:12:30 2004 +0000 - - initial checkin - - CVSROOT/checkoutlist | 13 +++++++++++++ - CVSROOT/commitinfo | 15 +++++++++++++++ - CVSROOT/config | 21 +++++++++++++++++++++ - CVSROOT/cvswrappers | 19 +++++++++++++++++++ - CVSROOT/editinfo | 21 +++++++++++++++++++++ - CVSROOT/loginfo | 26 ++++++++++++++++++++++++++ - CVSROOT/modules | 26 ++++++++++++++++++++++++++ - CVSROOT/notify | 12 ++++++++++++ - CVSROOT/rcsinfo | 13 +++++++++++++ - CVSROOT/taginfo | 20 ++++++++++++++++++++ - CVSROOT/verifymsg | 21 +++++++++++++++++++++ - 11 files changed, 207 insertions(+) diff --git a/lang/python/docs/short-history.org b/lang/python/docs/short-history.org deleted file mode 100644 index 31b7d446..00000000 --- a/lang/python/docs/short-history.org +++ /dev/null @@ -1,172 +0,0 @@ -#+TITLE: A Short History of the GPGME bindings for Python -#+LATEX_COMPILER: xelatex -#+LATEX_CLASS: article -#+LATEX_CLASS_OPTIONS: [12pt] -#+LATEX_HEADER: \usepackage{xltxtra} -#+LATEX_HEADER: \usepackage[margin=1in]{geometry} -#+LATEX_HEADER: \setmainfont[Ligatures={Common}]{Latin Modern Roman} - -* Overview - :PROPERTIES: - :CUSTOM_ID: overview - :END: - -The GPGME Python bindings passed through many hands and numerous -phases before, after a fifteen year journey, coming full circle to -return to the source. This is a short explanation of that journey. - -** In the beginning - :PROPERTIES: - :CUSTOM_ID: in-the-begining - :END: - - In 2002 John Goerzen released PyME; Python bindings for the GPGME - module which utilised the current release of Python of the time and - SWIG.[fn:1] Shortly after creating it and ensuring it worked he stopped - supporting it, though he left his work available on his Gopher - site. - -** Keeping the flame alive - :PROPERTIES: - :CUSTOM_ID: keeping-the-flame-alive - :END: - - A couple of years later the project was picked up by Igor Belyi and - actively developed and maintained by him from 2004 to 2008. Igor's - whereabouts at the time of this document's creation are unknown, - but the current authors do hope he is well. We're assuming (or - hoping) that life did what life does and made continuing untenable. - -** Passing the torch - :PROPERTIES: - :CUSTOM_ID: passing-the-torch - :END: - - In 2014 Martin Albrecht wanted to patch a bug in the PyME code and - discovered the absence of Igor. Following a discussion on the PyME - mailing list he became the new maintainer for PyME, releasing - version 0.9.0 in May of that year. He remains the maintainer of - the original PyME release in Python 2.6 and 2.7 (available via - PyPI). - -** Coming full circle - :PROPERTIES: - :CUSTOM_ID: ouroboros - :END: - - In 2015 Ben McGinnes approached Martin about a Python 3 version, - while investigating how complex a task this would be the task ended - up being completed. A subsequent discussion with Werner Koch led - to the decision to fold the Python 3 port back into the original - GPGME release in the languages subdirectory for non-C bindings - under the module name of =pyme3=. - - In 2016 this PyME module was integrated back into the GPGME project - by Justus Winter. During the course of this work Justus adjusted - the port to restore limited support for Python 2, but not as many - minor point releases as the original PyME package supports. During - the course of this integration the package was renamed to more - accurately reflect its status as a component of GPGME. The =pyme3= - module was renamed to =gpg= and adopted by the upstream GnuPG team. - - In 2017 Justus departed G10code and the GnuPG team. Following this - Ben returned to maintain of gpgme Python bindings and continue - building them from that point. - -* Relics of the past - :PROPERTIES: - :CUSTOM_ID: relics-past - :END: - -There are a few things, in addition to code specific factors, such as -SWIG itself, which are worth noting here. - -** The Annoyances of Git - :PROPERTIES: - :CUSTOM_ID: the-annoyances-of-git - :END: - - As anyone who has ever worked with git knows, submodules are - horrible way to deal with pretty much anything. In the interests - of avoiding migraines, that was skipped with addition of the PyME - code to GPGME. - - Instead the files were added to a subdirectory of the =lang/= - directory, along with a copy of the entire git log up to that point - as a separate file within the =lang/python/docs/= directory.[fn:2] - As the log for PyME is nearly 100KB and the log for GPGME is - approximately 1MB, this would cause considerable bloat, as well as - some confusion, should the two be merged. - - Hence the unfortunate, but necessary, step to simply move the - files. A regular repository version has been maintained should it - be possible to implement this better in the future. - -** The Perils of PyPI - :PROPERTIES: - :CUSTOM_ID: the-perils-of-pypi - :END: - - The early port of the Python 2 =pyme= module as =pyme3= was never - added to PyPI while the focus remained on development and testing - during 2015 and early 2016. Later in 2016, however, when Justus - completed his major integration work and subsequently renamed the - module from =pyme3= to =gpg=, some prior releases were also - provided through PyPI. - - Since these bindings require a matching release of the GPGME - libraries in order to function, it was determined that there was - little benefit in also providing a copy through PyPI since anyone - obtaining the GPGME source code would obtain the Python bindings - source code at the same time. Whereas there was the potential to - sew confusion amongst Python users installing the module from PyPI, - only to discover that without the relevant C files, header files or - SWIG compiled binaries, the Python module did them little good. - - There are only two files on PyPI which might turn up in a search - for this module or a sample of its content: - - 1. gpg (1.8.0) - Python bindings for GPGME GnuPG cryptography library - 2. pyme (0.9.0) - Python support for GPGME GnuPG cryptography library - -*** GPG 1.8.0 - Python bindings for GPGME GnuPG cryptography library - :PROPERTIES: - :CUSTOM_ID: pypi-gpgme-180 - :END: - - This is the most recent version to reach PyPI and is the version - of the official Pyhon bindings which shipped with GPGME 1.8.0. If - you have GPGME 1.8.0 installed and /only/ 1.8.0 installed, then it - is probably safe to use this copy from PyPI. - - As there have been a lot of changes since the release of GPGME - 1.8.0, the GnuPG Project recommends not using this version of the - module and instead installing the current version of GPGME along - with the Python bindings included with that package. - -*** PyME 0.9.0 - Python support for GPGME GnuPG cryptography library - :PROPERTIES: - :CUSTOM_ID: pypi-gpgme-90 - :END: - - This is the last release of the PyME bindings maintained by Martin - Albrecht and is only compatible with Python 2, it will not work - with Python 3. This is the version of the software from which the - port from Python 2 to Python 3 code was made in 2015. - - Users of the more recent Python bindings will recognise numerous - points of similarity, but also significant differences. It is - likely that the more recent official bindings will feel "more - pythonic." - - For those using Python 2, there is essentially no harm in using - this module, but it may lack a number of more recent features - added to GPGME. - -* Footnotes - -[fn:1] In all likelihood thos would have been Python 2.2 or possibly -Python 2.3. - -[fn:2] The entire PyME git log and other preceding VCS logs are -located in the =gpgme/lang/python/docs/old-commits.log= file. diff --git a/lang/python/docs/src/gpgme-python-howto.org b/lang/python/docs/src/gpgme-python-howto.org new file mode 100644 index 00000000..c7a1f823 --- /dev/null +++ b/lang/python/docs/src/gpgme-python-howto.org @@ -0,0 +1,3028 @@ +#+TITLE: GNU Privacy Guard (GnuPG) Made Easy Python Bindings HOWTO (English) +#+AUTHOR: Ben McGinnes +#+LATEX_COMPILER: xelatex +#+LATEX_CLASS: article +#+LATEX_CLASS_OPTIONS: [12pt] +#+LATEX_HEADER: \usepackage{xltxtra} +#+LATEX_HEADER: \usepackage[margin=1in]{geometry} +#+LATEX_HEADER: \setmainfont[Ligatures={Common}]{Times New Roman} +#+LATEX_HEADER: \author{Ben McGinnes } +#+HTML_HEAD_EXTRA: + + +* Introduction + :PROPERTIES: + :CUSTOM_ID: intro + :END: + +| Version: | 0.1.4 | +| GPGME Version: | 1.12.0 | +| Author: | [[https://gnupg.org/people/index.html#sec-1-5][Ben McGinnes]] | +| Author GPG Key: | DB4724E6FA4286C92B4E55C4321E4E2373590E5D | +| Language: | Australian English, British English | +| xml:lang: | en-AU, en-GB, en | + +This document provides basic instruction in how to use the GPGME +Python bindings to programmatically leverage the GPGME library. + + +** Python 2 versus Python 3 + :PROPERTIES: + :CUSTOM_ID: py2-vs-py3 + :END: + +Though the GPGME Python bindings themselves provide support for both +Python 2 and 3, the focus is unequivocally on Python 3 and +specifically from Python 3.4 and above. As a consequence all the +examples and instructions in this guide use Python 3 code. + +Much of it will work with Python 2, but much of it also deals with +Python 3 byte literals, particularly when reading and writing data. +Developers concentrating on Python 2.7, and possibly even 2.6, will +need to make the appropriate modifications to support the older string +and unicode types as opposed to bytes. + +There are multiple reasons for concentrating on Python 3; some of +which relate to the immediate integration of these bindings, some of +which relate to longer term plans for both GPGME and the python +bindings and some of which relate to the impending EOL period for +Python 2.7. Essentially, though, there is little value in tying the +bindings to a version of the language which is a dead end and the +advantages offered by Python 3 over Python 2 make handling the data +types with which GPGME deals considerably easier. + + +** Examples + :PROPERTIES: + :CUSTOM_ID: howto-python3-examples + :END: + +All of the examples found in this document can be found as Python 3 +scripts in the =lang/python/examples/howto= directory. + + +** Unofficial Drafts + :PROPERTIES: + :CUSTOM_ID: unofficial-drafts + :END: + +In addition to shipping with each release of GPGME, there is a section +on locations to read or download [[#draft-editions][draft editions]] of this document from +at the end of it. These are unofficial versions produced in between +major releases. + + +** What's New + :PROPERTIES: + :CUSTOM_ID: new-stuff + :END: + +The most obviously new point for those reading this guide is this +section on other new things, but that's hardly important. Not given +all the other things which spurred the need for adding this section +and its subsections. + +*** New in GPGME 1·12·0 + :PROPERTIES: + :CUSTOM_ID: new-stuff-1-12-0 + :END: + +There have been quite a number of additions to GPGME and the Python +bindings to it since the last release of GPGME with versions 1.11.0 +and 1.11.1 in April, 2018. + +The bullet points of new additiions are: + +- an expanded section on [[#installation][installing]] and [[#snafu][troubleshooting]] the Python + bindings. +- The release of Python 3.7.0; which appears to be working just fine + with our bindings, in spite of intermittent reports of problems for + many other Python projects with that new release. +- Python 3.7 has been moved to the head of the specified python + versions list in the build process. +- In order to fix some other issues, there are certain underlying + functions which are more exposed through the [[#howto-get-context][gpg.Context()]], but + ongoing documentation ought to clarify that or otherwise provide the + best means of using the bindings. Some additions to =gpg.core= and + the =Context()=, however, were intended (see below). +- Continuing work in identifying and confirming the cause of + oft-reported [[#snafu-runtime-not-funtime][problems installing the Python bindings on Windows]]. +- GSOC: Google's Surreptitiously Ordered Conscription ... erm ... oh, + right; Google's Summer of Code. Though there were two hopeful + candidates this year; only one ended up involved with the GnuPG + Project directly, the other concentrated on an unrelated third party + project with closer ties to one of the GNU/Linux distributions than + to the GnuPG Project. Thus the Python bindings benefited from GSOC + participant Jacob Adams, who added the key_import function; building + on prior work by Tobias Mueller. +- Several new methods functions were added to the gpg.Context(), + including: [[#howto-import-key][key_import]], [[#howto-export-key][key_export]], [[#howto-export-public-key][key_export_minimal]] and + [[#howto-export-secret-key][key_export_secret]]. +- Importing and exporting examples include versions integrated with + Marcel Fest's recently released [[https://github.com/Selfnet/hkp4py][HKP for Python]] module. Some + [[#hkp4py][additional notes on this module]] are included at the end of the HOWTO. +- Instructions for dealing with semi-walled garden implementations + like ProtonMail are also included. This is intended to make things + a little easier when communicating with users of ProtonMail's + services and should not be construed as an endorsement of said + service. The GnuPG Project neither favours, nor disfavours + ProtonMail and the majority of this deals with interacting with the + ProtonMail keyserver. +- Semi-formalised the location where [[#draft-editions][draft versions]] of this HOWTO may + periodically be accessible. This is both for the reference of + others and testing the publishing of the document itself. Renamed + the file at around the same time. +- Added a new section for [[#advanced-use][advanced or experimental use]]. +- Began the advanced use cases with [[#cython][a section]] on using the module with + [[http://cython.org/][Cython]]. +- Added a number of new scripts to the =example/howto/= directory; + some of which may be in advance of their planned sections of the + HOWTO (and some are just there because it seemed like a good idea at + the time). +- Cleaned up a lot of things under the hood. + + +* GPGME Concepts + :PROPERTIES: + :CUSTOM_ID: gpgme-concepts + :END: + + +** A C API + :PROPERTIES: + :CUSTOM_ID: gpgme-c-api + :END: + +Unlike many modern APIs with which programmers will be more familiar +with these days, the GPGME API is a C API. The API is intended for +use by C coders who would be able to access its features by including +the =gpgme.h= header file with their own C source code and then access +its functions just as they would any other C headers. + +This is a very effective method of gaining complete access to the API +and in the most efficient manner possible. It does, however, have the +drawback that it cannot be directly used by other languages without +some means of providing an interface to those languages. This is +where the need for bindings in various languages stems. + + +** Python bindings + :PROPERTIES: + :CUSTOM_ID: gpgme-python-bindings + :END: + +The Python bindings for GPGME provide a higher level means of +accessing the complete feature set of GPGME itself. It also provides +a more pythonic means of calling these API functions. + +The bindings are generated dynamically with SWIG and the copy of +=gpgme.h= generated when GPGME is compiled. + +This means that a version of the Python bindings is fundamentally tied +to the exact same version of GPGME used to generate that copy of +=gpgme.h=. + + +** Difference between the Python bindings and other GnuPG Python packages + :PROPERTIES: + :CUSTOM_ID: gpgme-python-bindings-diffs + :END: + +There have been numerous attempts to add GnuPG support to Python over +the years. Some of the most well known are listed here, along with +what differentiates them. + + +*** The python-gnupg package maintained by Vinay Sajip + :PROPERTIES: + :CUSTOM_ID: diffs-python-gnupg + :END: + +This is arguably the most popular means of integrating GPG with +Python. The package utilises the =subprocess= module to implement +wrappers for the =gpg= and =gpg2= executables normally invoked on the +command line (=gpg.exe= and =gpg2.exe= on Windows). + +The popularity of this package stemmed from its ease of use and +capability in providing the most commonly required features. + +Unfortunately it has been beset by a number of security issues in the +past; most of which stemmed from using unsafe methods of accessing the +command line via the =subprocess= calls. While some effort has been +made over the last two to three years (as of 2018) to mitigate this, +particularly by no longer providing shell access through those +subprocess calls, the wrapper is still somewhat limited in the scope +of its GnuPG features coverage. + +The python-gnupg package is available under the MIT license. + + +*** The gnupg package created and maintained by Isis Lovecruft + :PROPERTIES: + :CUSTOM_ID: diffs-isis-gnupg + :END: + +In 2015 Isis Lovecruft from the Tor Project forked and then +re-implemented the python-gnupg package as just gnupg. This new +package also relied on subprocess to call the =gpg= or =gpg2= +binaries, but did so somewhat more securely. + +The naming and version numbering selected for this package, however, +resulted in conflicts with the original python-gnupg and since its +functions were called in a different manner to python-gnupg, the +release of this package also resulted in a great deal of consternation +when people installed what they thought was an upgrade that +subsequently broke the code relying on it. + +The gnupg package is available under the GNU General Public License +version 3.0 (or any later version). + + +*** The PyME package maintained by Martin Albrecht + :PROPERTIES: + :CUSTOM_ID: diffs-pyme + :END: + +This package is the origin of these bindings, though they are somewhat +different now. For details of when and how the PyME package was +folded back into GPGME itself see the /Short History/ document[fn:1] +in the Python bindings =docs= directory.[fn:2] + +The PyME package was first released in 2002 and was also the first +attempt to implement a low level binding to GPGME. In doing so it +provided access to considerably more functionality than either the +=python-gnupg= or =gnupg= packages. + +The PyME package is only available for Python 2.6 and 2.7. + +Porting the PyME package to Python 3.4 in 2015 is what resulted in it +being folded into the GPGME project and the current bindings are the +end result of that effort. + +The PyME package is available under the same dual licensing as GPGME +itself: the GNU General Public License version 2.0 (or any later +version) and the GNU Lesser General Public License version 2.1 (or any +later version). + + +* GPGME Python bindings installation + :PROPERTIES: + :CUSTOM_ID: gpgme-python-install + :END: + + +** No PyPI + :PROPERTIES: + :CUSTOM_ID: do-not-use-pypi + :END: + +Most third-party Python packages and modules are available and +distributed through the Python Package Installer, known as PyPI. + +Due to the nature of what these bindings are and how they work, it is +infeasible to install the GPGME Python bindings in the same way. + +This is because the bindings use SWIG to dynamically generate C +bindings against =gpgme.h= and =gpgme.h= is generated from +=gpgme.h.in= at compile time when GPGME is built from source. Thus to +include a package in PyPI which actually built correctly would require +either statically built libraries for every architecture bundled with +it or a full implementation of C for each architecture. + +See the additional notes regarding [[#snafu-cffi][CFFI and SWIG]] at the end of this +section for further details. + + +** Requirements + :PROPERTIES: + :CUSTOM_ID: gpgme-python-requirements + :END: + +The GPGME Python bindings only have three requirements: + +1. A suitable version of Python 2 or Python 3. With Python 2 that + means CPython 2.7 and with Python 3 that means CPython 3.4 or + higher. +2. [[https://www.swig.org][SWIG]]. +3. GPGME itself. Which also means that all of GPGME's dependencies + must be installed too. + + +*** Recommended Additions + :PROPERTIES: + :CUSTOM_ID: gpgme-python-recommendations + :END: + +Though none of the following are absolute requirements, they are all +recommended for use with the Python bindings. In some cases these +recommendations refer to which version(s) of CPython to use the +bindings with, while others refer to third party modules which provide +a significant advantage in some way. + +1. If possible, use Python 3 instead of 2. +2. Favour a more recent version of Python since even 3.4 is due to + reach EOL soon. In production systems and services, Python 3.6 + should be robust enough to be relied on. +3. If possible add the following Python modules which are not part of + the standard library: [[http://docs.python-requests.org/en/latest/index.html][Requests]], [[http://cython.org/][Cython]] and [[https://github.com/Selfnet/hkp4py][hkp4py]]. Chances are + quite high that at least the first one and maybe two of those will + already be installed. + +Note that, as with Cython, some of the planned additions to the +[[#advanced-use][Advanced]] section, will bring with them additional requirements. Most +of these will be fairly well known and commonly installed ones, +however, which are in many cases likely to have already been installed +on many systems or be familiar to Python programmers. + + +** Installation + :PROPERTIES: + :CUSTOM_ID: installation + :END: + +Installing the Python bindings is effectively achieved by compiling +and installing GPGME itself. + +Once SWIG is installed with Python and all the dependencies for GPGME +are installed you only need to confirm that the version(s) of Python +you want the bindings installed for are in your =$PATH=. + +By default GPGME will attempt to install the bindings for the most +recent or highest version number of Python 2 and Python 3 it detects +in =$PATH=. It specifically checks for the =python= and =python3= +executables first and then checks for specific version numbers. + +For Python 2 it checks for these executables in this order: =python=, +=python2= and =python2.7=. + +For Python 3 it checks for these executables in this order: =python3=, + =python3.7=, =python3.6=, =python3.5= and =python3.4=.[fn:3] + +On systems where =python= is actually =python3= and not =python2= it +may be possible that =python2= may be overlooked, but there have been +no reports of that actually occurring as yet. + +In the three months or so since the release of Python 3.7.0 there has +been extensive testing and work with these bindings with no issues +specifically relating to the new version of Python or any of the new +features of either the language or the bindings. This has also been +the case with Python 3.7.1rc1. With that in mind and given the +release of Python 3.7.1 is scheduled for around the same time as GPGME +1.12.0, the order of preferred Python versions has been changed to +move Python 3.7 ahead of Python 3.6. + + +*** Installing GPGME + :PROPERTIES: + :CUSTOM_ID: install-gpgme + :END: + +See the GPGME =README= file for details of how to install GPGME from +source. + + +** Known Issues + :PROPERTIES: + :CUSTOM_ID: snafu + :END: + +There are a few known issues with the current build process and the +Python bindings. For the most part these are easily addressed should +they be encountered. + + +*** Breaking Builds + :PROPERTIES: + :CUSTOM_ID: snafu-a-swig-of-this-builds-character + :END: + +Occasionally when installing GPGME with the Python bindings included +it may be observed that the =make= portion of that process induces a +large very number of warnings and, eventually errors which end that +part of the build process. Yet following that with =make check= and +=make install= appears to work seamlessly. + +The cause of this is related to the way SWIG needs to be called to +dynamically generate the C bindings for GPGME in the first place. So +the entire process will always produce =lang/python/python2-gpg/= and +=lang/python/python3-gpg/= directories. These should contain the +build output generated during compilation, including the complete +bindings and module installed into =site-packages=. + +Occasionally the errors in the early part or some other conflict +(e.g. not installing as */root/* or */su/*) may result in nothing +being installed to the relevant =site-packages= directory and the +build directory missing a lot of expected files. Even when this +occurs, the solution is actually quite simple and will always work. + +That solution is simply to run the following commands as either the +*root* user or prepended with =sudo -H=[fn:4] in the =lang/python/= +directory: + +#+BEGIN_SRC shell + /path/to/pythonX.Y setup.py build + /path/to/pythonX.Y setup.py build + /path/to/pythonX.Y setup.py install +#+END_SRC + +Yes, the build command does need to be run twice. Yes, you still need +to run the potentially failing or incomplete steps during the +=configure=, =make= and =make install= steps with installing GPGME. +This is because those steps generate a lot of essential files needed, +both by and in order to create, the bindings (including both the +=setup.py= and =gpgme.h= files). + + +**** IMPORTANT Note + :PROPERTIES: + :CUSTOM_ID: snafu-swig-build-note + :END: + +If specifying a selected number of languages to create bindings for, +try to leave Python last. Currently the majority of the other +language bindings are also preceding Python of either version when +listed alphabetically and so that just happens by default currently. + +If Python is set to precede one of the other languages then it is +possible that the errors described here may interrupt the build +process before generating bindings for those other languages. In +these cases it may be preferable to configure all preferred language +bindings separately with alternative =configure= steps for GPGME using +the =--enable-languages=$LANGUAGE= option. + + +*** Reinstalling Responsibly + :PROPERTIES: + :CUSTOM_ID: snafu-lessons-for-the-lazy + :END: + +Regardless of whether you're installing for one version of Python or +several, there will come a point where reinstallation is required. +With most Python module installations, the installed files go into the +relevant site-packages directory and are then forgotten about. Then +the module is upgraded, the new files are copied over the old and +that's the end of the matter. + +While the same is true of these bindings, there have been intermittent +issues observed on some platforms which have benefited significantly +from removing all the previous installations of the bindings before +installing the updated versions. + +Removing the previous version(s) is simply a matter of changing to the +relevant =site-packages= directory for the version of Python in +question and removing the =gpg/= directory and any accompanying +egg-info files for that module. + +In most cases this will require root or administration privileges on +the system, but the same is true of installing the module in the first +place. + + +*** Multiple installations + :PROPERTIES: + :CUSTOM_ID: snafu-the-full-monty + :END: + +For a veriety of reasons it may be either necessary or just preferable +to install the bindings to alternative installed Python versions which +meet the requirements of these bindings. + +On POSIX systems this will generally be most simply achieved by +running the manual installation commands (build, build, install) as +described in the previous section for each Python installation the +bindings need to be installed to. + +As per the SWIG documentation: the compilers, libraries and runtime +used to build GPGME and the Python Bindings *must* match those used to +compile Python itself, including the version number(s) (at least going +by major version numbers and probably minor numbers too). + +On most POSIX systems, including OS X, this will very likely be the +case in most, if not all, cases. + + +*** Won't Work With Windows + :PROPERTIES: + :CUSTOM_ID: snafu-runtime-not-funtime + :END: + +There are semi-regular reports of Windows users having considerable +difficulty in installing and using the Python bindings at all. Very +often, possibly even always, these reports come from Cygwin users +and/or MinGW users and/or Msys2 users. Though not all of them have +been confirmed, it appears that these reports have also come from +people who installed Python using the Windows installer files from the +[[https://python.org][Python website]] (i.e. mostly MSI installers, sometimes self-extracting +=.exe= files). + +The Windows versions of Python are not built using Cygwin, MinGW or +Msys2; they're built using Microsoft Visual Studio. Furthermore the +version used is /considerably/ more advanced than the version which +MinGW obtained a small number of files from many years ago in order to +be able to compile anything at all. Not only that, but there are +changes to the version of Visual Studio between some micro releases, +though that is is particularly the case with Python 2.7, since it has +been kept around far longer than it should have been. + +There are two theoretical solutions to this issue: + + 1. Compile and install the GnuPG stack, including GPGME and the + Python bibdings using the same version of Microsoft Visual Studio + used by the Python Foundation to compile the version of Python + installed. + + If there are multiple versions of Python then this will need to be + done with each different version of Visual Studio used. + + 2. Compile and install Python using the same tools used by choice, + such as MinGW or Msys2. + +Do *not* use the official Windows installer for Python unless +following the first method. + +In this type of situation it may even be for the best to accept that +there are less limitations on permissive software than free software +and simply opt to use a recent version of the Community Edition of +Microsoft Visual Studio to compile and build all of it, no matter +what. + +Investigations into the extent or the limitations of this issue are +ongoing. + + +*** CFFI is the Best™ and GPGME should use it instead of SWIG + :PROPERTIES: + :CUSTOM_ID: snafu-cffi + :END: + +There are many reasons for favouring [[https://cffi.readthedocs.io/en/latest/overview.html][CFFI]] and proponents of it are +quite happy to repeat these things as if all it would take to switch +from SWIG to CFFI is repeating that list as if it were a new concept. + +The fact is that there are things which Python's CFFI implementation +cannot handle in the GPGME C code. Beyond that there are features of +SWIG which are simply not available with CFFI at all. SWIG generates +the bindings to Python using the =gpgme.h= file, but that file is not +a single version shipped with each release, it too is generated when +GPGME is compiled. + +CFFI is currently unable to adapt to such a potentially mutable +codebase. If there were some means of applying SWIG's dynamic code +generation to produce the Python/CFFI API modes of accessing the GPGME +libraries (or the source source code directly), but such a thing does +not exist yet either and it currently appears that work is needed in +at least one of CFFI's dependencies before any of this can be +addressed. + +So if you're a massive fan of CFFI; that's great, but if you want this +project to switch to CFFI then rather than just insisting that it +should, I'd suggest you volunteer to bring CFFI up to the level this +project needs. + +If you're actually seriously considering doing so, then I'd suggest +taking the =gpgme-tool.c= file in the GPGME =src/= directory and +getting that to work with any of the CFFI API methods (not the ABI +methods, they'll work with pretty much anything). When you start +running into trouble with "ifdefs" then you'll know what sort of +things are lacking. That doesn't even take into account the amount of +work saved via SWIG's code generation techniques either. + + +*** Virtualised Environments + :PROPERTIES: + :CUSTOM_ID: snafu-venv + :END: + +It is fairly common practice amongst Python developers to, as much as +possible, use packages like virtualenv to keep various things that are +to be installed from interfering with each other. Given how much of +the GPGME bindings is often at odds with the usual pythonic way of +doing things, it stands to reason that this would be called into +question too. + +As it happens the answer as to whether or not the bindings can be used +with virtualenv, the answer is both yes and no. + +In general we recommend installing to the relevant path and matching +prefix of GPGME itself. Which means that when GPGME, and ideally the +rest of the GnuPG stack, is installed to a prefix like =/usr/local= or +=/opt/local= then the bindings would need to be installed to the main +Python installation and not a virtualised abstraction. Attempts to +separate the two in the past have been known to cause weird and +intermittent errors ranging from minor annoyances to complete failures +in the build process. + +As a consequence we only recommend building with and installing to the +main Python installations within the same prefix as GPGME is installed +to or which are found by GPGME's configuration stage immediately prior +to running the make commands. Which is exactly what the compiling and +installing process of GPGME does by default. + +Once that is done, however, it appears that a copy the compiled module +may be installed into a virtualenv of the same major and minor version +matching the build. Alternatively it is possible to utilise a +=sites.pth= file in the =site-packages/= directory of a viertualenv +installation, which links back to the system installations +corresponding directory in order to import anything installed system +wide. This may or may not be appropriate on a case by case basis. + +Though extensive testing of either of these options is not yet +complete, preliminary testing of them indicates that both are viable +as long as the main installation is complete. Which means that +certain other options normally restricted to virtual environments are +also available, including integration with pythonic test suites +(e.g. [[https://docs.pytest.org/en/latest/index.html][pytest]]) and other large projects. + +That said, it is worth reiterating the warning regarding non-standard +installations. If one were to attempt to install the bindings only to +a virtual environment without somehow also including the full GnuPG +stack (or enough of it as to include GPGME) then it is highly likely +that errors would be encountered at some point and more than a little +likely that the build process itself would break. + +If a degree of separation from the main operating system is still +required in spite of these warnings, then consider other forms of +virtualisation. Either a virtual machine (e.g. [[https://www.virtualbox.org/][VirtualBox]]), a +hardware emulation layer (e.g. [[https://www.qemu.org/][QEMU]]) or an application container +(e.g. [[https://www.docker.com/why-docker][Docker]]). + +Finally it should be noted that the limited tests conducted thus far +have been using the =virtualenv= command in a new directory to create +the virtual python environment. As opposed to the standard =python3 +-m venv= and it is possible that this will make a difference depending +on the system and version of Python in use. Another option is to run +the command =python3 -m virtualenv /path/to/install/virtual/thingy= +instead. + + +* Fundamentals + :PROPERTIES: + :CUSTOM_ID: howto-fund-a-mental + :END: + +Before we can get to the fun stuff, there are a few matters regarding +GPGME's design which hold true whether you're dealing with the C code +directly or these Python bindings. + + +** No REST + :PROPERTIES: + :CUSTOM_ID: no-rest-for-the-wicked + :END: + +The first part of which is or will be fairly blatantly obvious upon +viewing the first example, but it's worth reiterating anyway. That +being that this API is /*not*/ a REST API. Nor indeed could it ever +be one. + +Most, if not all, Python programmers (and not just Python programmers) +know how easy it is to work with a RESTful API. In fact they've +become so popular that many other APIs attempt to emulate REST-like +behaviour as much as they are able. Right down to the use of JSON +formatted output to facilitate the use of their API without having to +retrain developers. + +This API does not do that. It would not be able to do that and also +provide access to the entire C API on which it's built. It does, +however, provide a very pythonic interface on top of the direct +bindings and it's this pythonic layer that this HOWTO deals with. + + +** Context + :PROPERTIES: + :CUSTOM_ID: howto-get-context + :END: + +One of the reasons which prevents this API from being RESTful is that +most operations require more than one instruction to the API to +perform the task. Sure, there are certain functions which can be +performed simultaneously, particularly if the result known or strongly +anticipated (e.g. selecting and encrypting to a key known to be in the +public keybox). + +There are many more, however, which cannot be manipulated so readily: +they must be performed in a specific sequence and the result of one +operation has a direct bearing on the outcome of subsequent +operations. Not merely by generating an error either. + +When dealing with this type of persistent state on the web, full of +both the RESTful and REST-like, it's most commonly referred to as a +session. In GPGME, however, it is called a context and every +operation type has one. + + +* Working with keys + :PROPERTIES: + :CUSTOM_ID: howto-keys + :END: + + +** Key selection + :PROPERTIES: + :CUSTOM_ID: howto-keys-selection + :END: + +Selecting keys to encrypt to or to sign with will be a common +occurrence when working with GPGMe and the means available for doing +so are quite simple. + +They do depend on utilising a Context; however once the data is +recorded in another variable, that Context does not need to be the +same one which subsequent operations are performed. + +The easiest way to select a specific key is by searching for that +key's key ID or fingerprint, preferably the full fingerprint without +any spaces in it. A long key ID will probably be okay, but is not +advised and short key IDs are already a problem with some being +generated to match specific patterns. It does not matter whether the +pattern is upper or lower case. + +So this is the best method: + +#+BEGIN_SRC python -i +import gpg + +k = gpg.Context().keylist(pattern="258E88DCBD3CD44D8E7AB43F6ECB6AF0DEADBEEF") +keys = list(k) +#+END_SRC + +This is passable and very likely to be common: + +#+BEGIN_SRC python -i +import gpg + +k = gpg.Context().keylist(pattern="0x6ECB6AF0DEADBEEF") +keys = list(k) +#+END_SRC + +And this is a really bad idea: + +#+BEGIN_SRC python -i +import gpg + +k = gpg.Context().keylist(pattern="0xDEADBEEF") +keys = list(k) +#+END_SRC + +Alternatively it may be that the intention is to create a list of keys +which all match a particular search string. For instance all the +addresses at a particular domain, like this: + +#+BEGIN_SRC python -i +import gpg + +ncsc = gpg.Context().keylist(pattern="ncsc.mil") +nsa = list(ncsc) +#+END_SRC + + +*** Counting keys + :PROPERTIES: + :CUSTOM_ID: howto-keys-counting + :END: + +Counting the number of keys in your public keybox (=pubring.kbx=), the +format which has superseded the old keyring format (=pubring.gpg= and +=secring.gpg=), or the number of secret keys is a very simple task. + +#+BEGIN_SRC python -i +import gpg + +c = gpg.Context() +seckeys = c.keylist(pattern=None, secret=True) +pubkeys = c.keylist(pattern=None, secret=False) + +seclist = list(seckeys) +secnum = len(seclist) + +publist = list(pubkeys) +pubnum = len(publist) + +print(""" + Number of secret keys: {0} + Number of public keys: {1} +""".format(secnum, pubnum)) +#+END_SRC + +*NOTE:* The [[#cython][Cython]] introduction in the [[#advanced-use][Advanced and Experimental]] +section uses this same key counting code with Cython to demonstrate +some areas where Cython can improve performance even with the +bindings. Users with large public keyrings or keyboxes, for instance, +should consider these options if they are comfortable with using +Cython. + + +** Get key + :PROPERTIES: + :CUSTOM_ID: howto-get-key + :END: + +An alternative method of getting a single key via its fingerprint is +available directly within a Context with =Context().get_key=. This is +the preferred method of selecting a key in order to modify it, sign or +certify it and for obtaining relevant data about a single key as a +part of other functions; when verifying a signature made by that key, +for instance. + +By default this method will select public keys, but it can select +secret keys as well. + +This first example demonstrates selecting the current key of Werner +Koch, which is due to expire at the end of 2018: + +#+BEGIN_SRC python -i +import gpg + +fingerprint = "80615870F5BAD690333686D0F2AD85AC1E42B367" +key = gpg.Context().get_key(fingerprint) +#+END_SRC + +Whereas this example demonstrates selecting the author's current key +with the =secret= key word argument set to =True=: + +#+BEGIN_SRC python -i +import gpg + +fingerprint = "DB4724E6FA4286C92B4E55C4321E4E2373590E5D" +key = gpg.Context().get_key(fingerprint, secret=True) +#+END_SRC + +It is, of course, quite possible to select expired, disabled and +revoked keys with this function, but only to effectively display +information about those keys. + +It is also possible to use both unicode or string literals and byte +literals with the fingerprint when getting a key in this way. + + +** Importing keys + :PROPERTIES: + :CUSTOM_ID: howto-import-key + :END: + +Importing keys is possible with the =key_import()= method and takes +one argument which is a bytes literal object containing either the +binary or ASCII armoured key data for one or more keys. + +The following example retrieves one or more keys from the SKS +keyservers via the web using the requests module. Since requests +returns the content as a bytes literal object, we can then use that +directly to import the resulting data into our keybox. + +#+BEGIN_SRC python -i +import gpg +import os.path +import requests + +c = gpg.Context() +url = "https://sks-keyservers.net/pks/lookup" +pattern = input("Enter the pattern to search for key or user IDs: ") +payload = {"op": "get", "search": pattern} + +r = requests.get(url, verify=True, params=payload) +result = c.key_import(r.content) + +if result is not None and hasattr(result, "considered") is False: + print(result) +elif result is not None and hasattr(result, "considered") is True: + num_keys = len(result.imports) + new_revs = result.new_revocations + new_sigs = result.new_signatures + new_subs = result.new_sub_keys + new_uids = result.new_user_ids + new_scrt = result.secret_imported + nochange = result.unchanged + print(""" + The total number of keys considered for import was: {0} + + Number of keys revoked: {1} + Number of new signatures: {2} + Number of new subkeys: {3} + Number of new user IDs: {4} + Number of new secret keys: {5} + Number of unchanged keys: {6} + + The key IDs for all considered keys were: +""".format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt, + nochange)) + for i in range(num_keys): + print("{0}\n".format(result.imports[i].fpr)) +else: + pass +#+END_SRC + +*NOTE:* When searching for a key ID of any length or a fingerprint +(without spaces), the SKS servers require the the leading =0x= +indicative of hexadecimal be included. Also note that the old short +key IDs (e.g. =0xDEADBEEF=) should no longer be used due to the +relative ease by which such key IDs can be reproduced, as demonstrated +by the Evil32 Project in 2014 (which was subsequently exploited in +2016). + + +*** Working with ProtonMail + :PROPERTIES: + :CUSTOM_ID: import-protonmail + :END: + +Here is a variation on the example above which checks the constrained +ProtonMail keyserver for ProtonMail public keys. + +#+BEGIN_SRC python -i +import gpg +import requests +import sys + +print(""" +This script searches the ProtonMail key server for the specified key and +imports it. +""") + +c = gpg.Context(armor=True) +url = "https://api.protonmail.ch/pks/lookup" +ksearch = [] + +if len(sys.argv) >= 2: + keyterm = sys.argv[1] +else: + keyterm = input("Enter the key ID, UID or search string: ") + +if keyterm.count("@") == 2 and keyterm.startswith("@") is True: + ksearch.append(keyterm[1:]) + ksearch.append(keyterm[1:]) + ksearch.append(keyterm[1:]) +elif keyterm.count("@") == 1 and keyterm.startswith("@") is True: + ksearch.append("{0}@protonmail.com".format(keyterm[1:])) + ksearch.append("{0}@protonmail.ch".format(keyterm[1:])) + ksearch.append("{0}@pm.me".format(keyterm[1:])) +elif keyterm.count("@") == 0: + ksearch.append("{0}@protonmail.com".format(keyterm)) + ksearch.append("{0}@protonmail.ch".format(keyterm)) + ksearch.append("{0}@pm.me".format(keyterm)) +elif keyterm.count("@") == 2 and keyterm.startswith("@") is False: + uidlist = keyterm.split("@") + for uid in uidlist: + ksearch.append("{0}@protonmail.com".format(uid)) + ksearch.append("{0}@protonmail.ch".format(uid)) + ksearch.append("{0}@pm.me".format(uid)) +elif keyterm.count("@") > 2: + uidlist = keyterm.split("@") + for uid in uidlist: + ksearch.append("{0}@protonmail.com".format(uid)) + ksearch.append("{0}@protonmail.ch".format(uid)) + ksearch.append("{0}@pm.me".format(uid)) +else: + ksearch.append(keyterm) + +for k in ksearch: + payload = {"op": "get", "search": k} + try: + r = requests.get(url, verify=True, params=payload) + if r.ok is True: + result = c.key_import(r.content) + elif r.ok is False: + result = r.content + except Exception as e: + result = None + + if result is not None and hasattr(result, "considered") is False: + print("{0} for {1}".format(result.decode(), k)) + elif result is not None and hasattr(result, "considered") is True: + num_keys = len(result.imports) + new_revs = result.new_revocations + new_sigs = result.new_signatures + new_subs = result.new_sub_keys + new_uids = result.new_user_ids + new_scrt = result.secret_imported + nochange = result.unchanged + print(""" +The total number of keys considered for import was: {0} + +With UIDs wholely or partially matching the following string: + + {1} + + Number of keys revoked: {2} + Number of new signatures: {3} + Number of new subkeys: {4} + Number of new user IDs: {5} +Number of new secret keys: {6} + Number of unchanged keys: {7} + +The key IDs for all considered keys were: +""".format(num_keys, k, new_revs, new_sigs, new_subs, new_uids, new_scrt, + nochange)) + for i in range(num_keys): + print(result.imports[i].fpr) + print("") + elif result is None: + print(e) +#+END_SRC + +Both the above example, [[../examples/howto/pmkey-import.py][pmkey-import.py]], and a version which prompts +for an alternative GnuPG home directory, [[../examples/howto/pmkey-import-alt.py][pmkey-import-alt.py]], are +available with the other examples and are executable scripts. + +Note that while the ProtonMail servers are based on the SKS servers, +their server is related more to their API and is not feature complete +by comparison to the servers in the SKS pool. One notable difference +being that the ProtonMail server does not permit non ProtonMail users +to update their own keys, which could be a vector for attacking +ProtonMail users who may not receive a key's revocation if it had been +compromised. + + +*** Importing with HKP for Python + :PROPERTIES: + :CUSTOM_ID: import-hkp4py + :END: + +Performing the same tasks with the [[https://github.com/Selfnet/hkp4py][hkp4py module]] (available via PyPI) +is not too much different, but does provide a number of options of +benefit to end users. Not least of which being the ability to perform +some checks on a key before importing it or not. For instance it may +be the policy of a site or project to only import keys which have not +been revoked. The hkp4py module permits such checks prior to the +importing of the keys found. + +#+BEGIN_SRC python -i +import gpg +import hkp4py +import sys + +c = gpg.Context() +server = hkp4py.KeyServer("hkps://hkps.pool.sks-keyservers.net") +results = [] + +if len(sys.argv) > 2: + pattern = " ".join(sys.argv[1:]) +elif len(sys.argv) == 2: + pattern = sys.argv[1] +else: + pattern = input("Enter the pattern to search for keys or user IDs: ") + +try: + keys = server.search(pattern) + print("Found {0} key(s).".format(len(keys))) +except Exception as e: + keys = [] + for logrus in pattern.split(): + if logrus.startswith("0x") is True: + key = server.search(logrus) + else: + key = server.search("0x{0}".format(logrus)) + keys.append(key[0]) + print("Found {0} key(s).".format(len(keys))) + +for key in keys: + import_result = c.key_import(key.key_blob) + results.append(import_result) + +for result in results: + if result is not None and hasattr(result, "considered") is False: + print(result) + elif result is not None and hasattr(result, "considered") is True: + num_keys = len(result.imports) + new_revs = result.new_revocations + new_sigs = result.new_signatures + new_subs = result.new_sub_keys + new_uids = result.new_user_ids + new_scrt = result.secret_imported + nochange = result.unchanged + print(""" +The total number of keys considered for import was: {0} + + Number of keys revoked: {1} + Number of new signatures: {2} + Number of new subkeys: {3} + Number of new user IDs: {4} +Number of new secret keys: {5} + Number of unchanged keys: {6} + +The key IDs for all considered keys were: +""".format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt, + nochange)) + for i in range(num_keys): + print(result.imports[i].fpr) + print("") + else: + pass +#+END_SRC + +Since the hkp4py module handles multiple keys just as effectively as +one (=keys= is a list of responses per matching key), the example +above is able to do a little bit more with the returned data before +anything is actually imported. + + +*** Importing from ProtonMail with HKP for Python + :PROPERTIES: + :CUSTOM_ID: import-protonmail-hkp4py + :END: + +Though this can provide certain benefits even when working with +ProtonMail, the scope is somewhat constrained there due to the +limitations of the ProtonMail keyserver. + +For instance, searching the SKS keyserver pool for the term "gnupg" +produces hundreds of results from any time the word appears in any +part of a user ID. Performing the same search on the ProtonMail +keyserver returns zero results, even though there are at least two +test accounts which include it as part of the username. + +The cause of this discrepancy is the deliberate configuration of that +server by ProtonMail to require an exact match of the full email +address of the ProtonMail user whose key is being requested. +Presumably this is intended to reduce breaches of privacy of their +users as an email address must already be known before a key for that +address can be obtained. + + +**** Import from ProtonMail via HKP for Python Example no. 1 + :PROPERTIES: + :CUSTOM_ID: import-hkp4py-pm1 + :END: + +The following script is avalable with the rest of the examples under +the somewhat less than original name, =pmkey-import-hkp.py=. + +#+BEGIN_SRC python -i +import gpg +import hkp4py +import os.path +import sys + +print(""" +This script searches the ProtonMail key server for the specified key and +imports it. + +Usage: pmkey-import-hkp.py [search strings] +""") + +c = gpg.Context(armor=True) +server = hkp4py.KeyServer("hkps://api.protonmail.ch") +keyterms = [] +ksearch = [] +allkeys = [] +results = [] +paradox = [] +homeless = None + +if len(sys.argv) > 2: + keyterms = sys.argv[1:] +elif len(sys.argv) == 2: + keyterm = sys.argv[1] + keyterms.append(keyterm) +else: + key_term = input("Enter the key ID, UID or search string: ") + keyterms = key_term.split() + +for keyterm in keyterms: + if keyterm.count("@") == 2 and keyterm.startswith("@") is True: + ksearch.append(keyterm[1:]) + ksearch.append(keyterm[1:]) + ksearch.append(keyterm[1:]) + elif keyterm.count("@") == 1 and keyterm.startswith("@") is True: + ksearch.append("{0}@protonmail.com".format(keyterm[1:])) + ksearch.append("{0}@protonmail.ch".format(keyterm[1:])) + ksearch.append("{0}@pm.me".format(keyterm[1:])) + elif keyterm.count("@") == 0: + ksearch.append("{0}@protonmail.com".format(keyterm)) + ksearch.append("{0}@protonmail.ch".format(keyterm)) + ksearch.append("{0}@pm.me".format(keyterm)) + elif keyterm.count("@") == 2 and keyterm.startswith("@") is False: + uidlist = keyterm.split("@") + for uid in uidlist: + ksearch.append("{0}@protonmail.com".format(uid)) + ksearch.append("{0}@protonmail.ch".format(uid)) + ksearch.append("{0}@pm.me".format(uid)) + elif keyterm.count("@") > 2: + uidlist = keyterm.split("@") + for uid in uidlist: + ksearch.append("{0}@protonmail.com".format(uid)) + ksearch.append("{0}@protonmail.ch".format(uid)) + ksearch.append("{0}@pm.me".format(uid)) + else: + ksearch.append(keyterm) + +for k in ksearch: + print("Checking for key for: {0}".format(k)) + try: + keys = server.search(k) + if isinstance(keys, list) is True: + for key in keys: + allkeys.append(key) + try: + import_result = c.key_import(key.key_blob) + except Exception as e: + import_result = c.key_import(key.key) + else: + paradox.append(keys) + import_result = None + except Exception as e: + import_result = None + results.append(import_result) + +for result in results: + if result is not None and hasattr(result, "considered") is False: + print("{0} for {1}".format(result.decode(), k)) + elif result is not None and hasattr(result, "considered") is True: + num_keys = len(result.imports) + new_revs = result.new_revocations + new_sigs = result.new_signatures + new_subs = result.new_sub_keys + new_uids = result.new_user_ids + new_scrt = result.secret_imported + nochange = result.unchanged + print(""" +The total number of keys considered for import was: {0} + +With UIDs wholely or partially matching the following string: + + {1} + + Number of keys revoked: {2} + Number of new signatures: {3} + Number of new subkeys: {4} + Number of new user IDs: {5} +Number of new secret keys: {6} + Number of unchanged keys: {7} + +The key IDs for all considered keys were: +""".format(num_keys, k, new_revs, new_sigs, new_subs, new_uids, new_scrt, + nochange)) + for i in range(num_keys): + print(result.imports[i].fpr) + print("") + elif result is None: + pass +#+END_SRC + + +**** Import from ProtonMail via HKP for Python Example no. 2 + :PROPERTIES: + :CUSTOM_ID: import-hkp4py-pm2 + :END: + +Like its counterpart above, this script can also be found with the +rest of the examples, by the name pmkey-import-hkp-alt.py. + +With this script a modicum of effort has been made to treat anything +passed as a =homedir= which either does not exist or which is not a +directory, as also being a pssible user ID to check for. It's not +guaranteed to pick up on all such cases, but it should cover most of +them. + +#+BEGIN_SRC python -i +import gpg +import hkp4py +import os.path +import sys + +print(""" +This script searches the ProtonMail key server for the specified key and +imports it. Optionally enables specifying a different GnuPG home directory. + +Usage: pmkey-import-hkp.py [homedir] [search string] + or: pmkey-import-hkp.py [search string] +""") + +c = gpg.Context(armor=True) +server = hkp4py.KeyServer("hkps://api.protonmail.ch") +keyterms = [] +ksearch = [] +allkeys = [] +results = [] +paradox = [] +homeless = None + +if len(sys.argv) > 3: + homedir = sys.argv[1] + keyterms = sys.argv[2:] +elif len(sys.argv) == 3: + homedir = sys.argv[1] + keyterm = sys.argv[2] + keyterms.append(keyterm) +elif len(sys.argv) == 2: + homedir = "" + keyterm = sys.argv[1] + keyterms.append(keyterm) +else: + keyterm = input("Enter the key ID, UID or search string: ") + homedir = input("Enter the GPG configuration directory path (optional): ") + keyterms.append(keyterm) + +if len(homedir) == 0: + homedir = None + homeless = False + +if homedir is not None: + if homedir.startswith("~"): + if os.path.exists(os.path.expanduser(homedir)) is True: + if os.path.isdir(os.path.expanduser(homedir)) is True: + c.home_dir = os.path.realpath(os.path.expanduser(homedir)) + else: + homeless = True + else: + homeless = True + elif os.path.exists(os.path.realpath(homedir)) is True: + if os.path.isdir(os.path.realpath(homedir)) is True: + c.home_dir = os.path.realpath(homedir) + else: + homeless = True + else: + homeless = True + +# First check to see if the homedir really is a homedir and if not, treat it as +# a search string. +if homeless is True: + keyterms.append(homedir) + c.home_dir = None +else: + pass + +for keyterm in keyterms: + if keyterm.count("@") == 2 and keyterm.startswith("@") is True: + ksearch.append(keyterm[1:]) + ksearch.append(keyterm[1:]) + ksearch.append(keyterm[1:]) + elif keyterm.count("@") == 1 and keyterm.startswith("@") is True: + ksearch.append("{0}@protonmail.com".format(keyterm[1:])) + ksearch.append("{0}@protonmail.ch".format(keyterm[1:])) + ksearch.append("{0}@pm.me".format(keyterm[1:])) + elif keyterm.count("@") == 0: + ksearch.append("{0}@protonmail.com".format(keyterm)) + ksearch.append("{0}@protonmail.ch".format(keyterm)) + ksearch.append("{0}@pm.me".format(keyterm)) + elif keyterm.count("@") == 2 and keyterm.startswith("@") is False: + uidlist = keyterm.split("@") + for uid in uidlist: + ksearch.append("{0}@protonmail.com".format(uid)) + ksearch.append("{0}@protonmail.ch".format(uid)) + ksearch.append("{0}@pm.me".format(uid)) + elif keyterm.count("@") > 2: + uidlist = keyterm.split("@") + for uid in uidlist: + ksearch.append("{0}@protonmail.com".format(uid)) + ksearch.append("{0}@protonmail.ch".format(uid)) + ksearch.append("{0}@pm.me".format(uid)) + else: + ksearch.append(keyterm) + +for k in ksearch: + print("Checking for key for: {0}".format(k)) + try: + keys = server.search(k) + if isinstance(keys, list) is True: + for key in keys: + allkeys.append(key) + try: + import_result = c.key_import(key.key_blob) + except Exception as e: + import_result = c.key_import(key.key) + else: + paradox.append(keys) + import_result = None + except Exception as e: + import_result = None + results.append(import_result) + +for result in results: + if result is not None and hasattr(result, "considered") is False: + print("{0} for {1}".format(result.decode(), k)) + elif result is not None and hasattr(result, "considered") is True: + num_keys = len(result.imports) + new_revs = result.new_revocations + new_sigs = result.new_signatures + new_subs = result.new_sub_keys + new_uids = result.new_user_ids + new_scrt = result.secret_imported + nochange = result.unchanged + print(""" +The total number of keys considered for import was: {0} + +With UIDs wholely or partially matching the following string: + + {1} + + Number of keys revoked: {2} + Number of new signatures: {3} + Number of new subkeys: {4} + Number of new user IDs: {5} +Number of new secret keys: {6} + Number of unchanged keys: {7} + +The key IDs for all considered keys were: +""".format(num_keys, k, new_revs, new_sigs, new_subs, new_uids, new_scrt, + nochange)) + for i in range(num_keys): + print(result.imports[i].fpr) + print("") + elif result is None: + pass +#+END_SRC + + +** Exporting keys + :PROPERTIES: + :CUSTOM_ID: howto-export-key + :END: + +Exporting keys remains a reasonably simple task, but has been +separated into three different functions for the OpenPGP cryptographic +engine. Two of those functions are for exporting public keys and the +third is for exporting secret keys. + + +*** Exporting public keys + :PROPERTIES: + :CUSTOM_ID: howto-export-public-key + :END: + +There are two methods of exporting public keys, both of which are very +similar to the other. The default method, =key_export()=, will export +a public key or keys matching a specified pattern as normal. The +alternative, the =key_export_minimal()= method, will do the same thing +except producing a minimised output with extra signatures and third +party signatures or certifications removed. + +#+BEGIN_SRC python -i +import gpg +import os.path +import sys + +print(""" +This script exports one or more public keys. +""") + +c = gpg.Context(armor=True) + +if len(sys.argv) >= 4: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = sys.argv[3] +elif len(sys.argv) == 3: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = input("Enter the GPG configuration directory path (optional): ") +elif len(sys.argv) == 2: + keyfile = sys.argv[1] + logrus = input("Enter the UID matching the key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") +else: + keyfile = input("Enter the path and filename to save the secret key to: ") + logrus = input("Enter the UID matching the key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") + +if homedir.startswith("~"): + if os.path.exists(os.path.expanduser(homedir)) is True: + c.home_dir = os.path.expanduser(homedir) + else: + pass +elif os.path.exists(homedir) is True: + c.home_dir = homedir +else: + pass + +try: + result = c.key_export(pattern=logrus) +except: + result = c.key_export(pattern=None) + +if result is not None: + with open(keyfile, "wb") as f: + f.write(result) +else: + pass +#+END_SRC + +It should be noted that the result will only return =None= when a +search pattern has been entered, but has not matched any keys. When +the search pattern itself is set to =None= this triggers the exporting +of the entire public keybox. + +#+BEGIN_SRC python -i +import gpg +import os.path +import sys + +print(""" +This script exports one or more public keys in minimised form. +""") + +c = gpg.Context(armor=True) + +if len(sys.argv) >= 4: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = sys.argv[3] +elif len(sys.argv) == 3: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = input("Enter the GPG configuration directory path (optional): ") +elif len(sys.argv) == 2: + keyfile = sys.argv[1] + logrus = input("Enter the UID matching the key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") +else: + keyfile = input("Enter the path and filename to save the secret key to: ") + logrus = input("Enter the UID matching the key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") + +if homedir.startswith("~"): + if os.path.exists(os.path.expanduser(homedir)) is True: + c.home_dir = os.path.expanduser(homedir) + else: + pass +elif os.path.exists(homedir) is True: + c.home_dir = homedir +else: + pass + +try: + result = c.key_export_minimal(pattern=logrus) +except: + result = c.key_export_minimal(pattern=None) + +if result is not None: + with open(keyfile, "wb") as f: + f.write(result) +else: + pass +#+END_SRC + + +*** Exporting secret keys + :PROPERTIES: + :CUSTOM_ID: howto-export-secret-key + :END: + +Exporting secret keys is, functionally, very similar to exporting +public keys; save for the invocation of =pinentry= via =gpg-agent= in +order to securely enter the key's passphrase and authorise the export. + +The following example exports the secret key to a file which is then +set with the same permissions as the output files created by the +command line secret key export options. + +#+BEGIN_SRC python -i +import gpg +import os +import os.path +import sys + +print(""" +This script exports one or more secret keys. + +The gpg-agent and pinentry are invoked to authorise the export. +""") + +c = gpg.Context(armor=True) + +if len(sys.argv) >= 4: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = sys.argv[3] +elif len(sys.argv) == 3: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = input("Enter the GPG configuration directory path (optional): ") +elif len(sys.argv) == 2: + keyfile = sys.argv[1] + logrus = input("Enter the UID matching the secret key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") +else: + keyfile = input("Enter the path and filename to save the secret key to: ") + logrus = input("Enter the UID matching the secret key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") + +if len(homedir) == 0: + homedir = None +elif homedir.startswith("~"): + userdir = os.path.expanduser(homedir) + if os.path.exists(userdir) is True: + homedir = os.path.realpath(userdir) + else: + homedir = None +else: + homedir = os.path.realpath(homedir) + +if os.path.exists(homedir) is False: + homedir = None +else: + if os.path.isdir(homedir) is False: + homedir = None + else: + pass + +if homedir is not None: + c.home_dir = homedir +else: + pass + +try: + result = c.key_export_secret(pattern=logrus) +except: + result = c.key_export_secret(pattern=None) + +if result is not None: + with open(keyfile, "wb") as f: + f.write(result) + os.chmod(keyfile, 0o600) +else: + pass +#+END_SRC + +Alternatively the approach of the following script can be used. This +longer example saves the exported secret key(s) in files in the GnuPG +home directory, in addition to setting the file permissions as only +readable and writable by the user. It also exports the secret key(s) +twice in order to output both GPG binary (=.gpg=) and ASCII armoured +(=.asc=) files. + +#+BEGIN_SRC python -i +import gpg +import os +import os.path +import subprocess +import sys + +print(""" +This script exports one or more secret keys as both ASCII armored and binary +file formats, saved in files within the user's GPG home directory. + +The gpg-agent and pinentry are invoked to authorise the export. +""") + +if sys.platform == "win32": + gpgconfcmd = "gpgconf.exe --list-dirs homedir" +else: + gpgconfcmd = "gpgconf --list-dirs homedir" + +a = gpg.Context(armor=True) +b = gpg.Context() +c = gpg.Context() + +if len(sys.argv) >= 4: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = sys.argv[3] +elif len(sys.argv) == 3: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = input("Enter the GPG configuration directory path (optional): ") +elif len(sys.argv) == 2: + keyfile = sys.argv[1] + logrus = input("Enter the UID matching the secret key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") +else: + keyfile = input("Enter the filename to save the secret key to: ") + logrus = input("Enter the UID matching the secret key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") + +if len(homedir) == 0: + homedir = None +elif homedir.startswith("~"): + userdir = os.path.expanduser(homedir) + if os.path.exists(userdir) is True: + homedir = os.path.realpath(userdir) + else: + homedir = None +else: + homedir = os.path.realpath(homedir) + +if os.path.exists(homedir) is False: + homedir = None +else: + if os.path.isdir(homedir) is False: + homedir = None + else: + pass + +if homedir is not None: + c.home_dir = homedir +else: + pass + +if c.home_dir is not None: + if c.home_dir.endswith("/"): + gpgfile = "{0}{1}.gpg".format(c.home_dir, keyfile) + ascfile = "{0}{1}.asc".format(c.home_dir, keyfile) + else: + gpgfile = "{0}/{1}.gpg".format(c.home_dir, keyfile) + ascfile = "{0}/{1}.asc".format(c.home_dir, keyfile) +else: + if os.path.exists(os.environ["GNUPGHOME"]) is True: + hd = os.environ["GNUPGHOME"] + else: + try: + hd = subprocess.getoutput(gpgconfcmd) + except: + process = subprocess.Popen(gpgconfcmd.split(), + stdout=subprocess.PIPE) + procom = process.communicate() + if sys.version_info[0] == 2: + hd = procom[0].strip() + else: + hd = procom[0].decode().strip() + gpgfile = "{0}/{1}.gpg".format(hd, keyfile) + ascfile = "{0}/{1}.asc".format(hd, keyfile) + +try: + a_result = a.key_export_secret(pattern=logrus) + b_result = b.key_export_secret(pattern=logrus) +except: + a_result = a.key_export_secret(pattern=None) + b_result = b.key_export_secret(pattern=None) + +if a_result is not None: + with open(ascfile, "wb") as f: + f.write(a_result) + os.chmod(ascfile, 0o600) +else: + pass + +if b_result is not None: + with open(gpgfile, "wb") as f: + f.write(b_result) + os.chmod(gpgfile, 0o600) +else: + pass +#+END_SRC + + +*** Sending public keys to the SKS Keyservers + :PROPERTIES: + :CUSTOM_ID: howto-send-public-key + :END: + +As with the previous section on importing keys, the =hkp4py= module +adds another option with exporting keys in order to send them to the +public keyservers. + +The following example demonstrates how this may be done. + +#+BEGIN_SRC python -i +import gpg +import hkp4py +import os.path +import sys + +print(""" +This script sends one or more public keys to the SKS keyservers and is +essentially a slight variation on the export-key.py script. +""") + +c = gpg.Context(armor=True) +server = hkp4py.KeyServer("hkps://hkps.pool.sks-keyservers.net") + +if len(sys.argv) > 2: + logrus = " ".join(sys.argv[1:]) +elif len(sys.argv) == 2: + logrus = sys.argv[1] +else: + logrus = input("Enter the UID matching the key(s) to send: ") + +if len(logrus) > 0: + try: + export_result = c.key_export(pattern=logrus) + except Exception as e: + print(e) + export_result = None +else: + export_result = c.key_export(pattern=None) + +if export_result is not None: + try: + try: + send_result = server.add(export_result) + except: + send_result = server.add(export_result.decode()) + if send_result is not None: + print(send_result) + else: + pass + except Exception as e: + print(e) +else: + pass +#+END_SRC + +An expanded version of this script with additional functions for +specifying an alternative homedir location is in the examples +directory as =send-key-to-keyserver.py=. + +The =hkp4py= module appears to handle both string and byte literal text +data equally well, but the GPGME bindings deal primarily with byte +literal data only and so this script sends in that format first, then +tries the string literal form. + + +* Basic Functions + :PROPERTIES: + :CUSTOM_ID: howto-the-basics + :END: + +The most frequently called features of any cryptographic library will +be the most fundamental tasks for encryption software. In this +section we will look at how to programmatically encrypt data, decrypt +it, sign it and verify signatures. + + +** Encryption + :PROPERTIES: + :CUSTOM_ID: howto-basic-encryption + :END: + +Encrypting is very straight forward. In the first example below the +message, =text=, is encrypted to a single recipient's key. In the +second example the message will be encrypted to multiple recipients. + + +*** Encrypting to one key + :PROPERTIES: + :CUSTOM_ID: howto-basic-encryption-single + :END: + +Once the the Context is set the main issues with encrypting data is +essentially reduced to key selection and the keyword arguments +specified in the =gpg.Context().encrypt()= method. + +Those keyword arguments are: =recipients=, a list of keys encrypted to +(covered in greater detail in the following section); =sign=, whether +or not to sign the plaintext data, see subsequent sections on signing +and verifying signatures below (defaults to =True=); =sink=, to write +results or partial results to a secure sink instead of returning it +(defaults to =None=); =passphrase=, only used when utilising symmetric +encryption (defaults to =None=); =always_trust=, used to override the +trust model settings for recipient keys (defaults to =False=); +=add_encrypt_to=, utilises any preconfigured =encrypt-to= or +=default-key= settings in the user's =gpg.conf= file (defaults to +=False=); =prepare=, prepare for encryption (defaults to =False=); +=expect_sign=, prepare for signing (defaults to =False=); =compress=, +compresses the plaintext prior to encryption (defaults to =True=). + +#+BEGIN_SRC python -i +import gpg + +a_key = "0x12345678DEADBEEF" +text = b"""Some text to test with. + +Since the text in this case must be bytes, it is most likely that +the input form will be a separate file which is opened with "rb" +as this is the simplest method of obtaining the correct data format. +""" + +c = gpg.Context(armor=True) +rkey = list(c.keylist(pattern=a_key, secret=False)) +ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=False) + +with open("secret_plans.txt.asc", "wb") as afile: + afile.write(ciphertext) +#+END_SRC + +Though this is even more likely to be used like this; with the +plaintext input read from a file, the recipient keys used for +encryption regardless of key trust status and the encrypted output +also encrypted to any preconfigured keys set in the =gpg.conf= file: + +#+BEGIN_SRC python -i +import gpg + +a_key = "0x12345678DEADBEEF" + +with open("secret_plans.txt", "rb") as afile: + text = afile.read() + +c = gpg.Context(armor=True) +rkey = list(c.keylist(pattern=a_key, secret=False)) +ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=True, + always_trust=True, + add_encrypt_to=True) + +with open("secret_plans.txt.asc", "wb") as afile: + afile.write(ciphertext) +#+END_SRC + +If the =recipients= paramater is empty then the plaintext is encrypted +symmetrically. If no =passphrase= is supplied as a parameter or via a +callback registered with the =Context()= then an out-of-band prompt +for the passphrase via pinentry will be invoked. + + +*** Encrypting to multiple keys + :PROPERTIES: + :CUSTOM_ID: howto-basic-encryption-multiple + :END: + +Encrypting to multiple keys essentially just expands upon the key +selection process and the recipients from the previous examples. + +The following example encrypts a message (=text=) to everyone with an +email address on the =gnupg.org= domain,[fn:5] but does /not/ encrypt +to a default key or other key which is configured to normally encrypt +to. + +#+BEGIN_SRC python -i +import gpg + +text = b"""Oh look, another test message. + +The same rules apply as with the previous example and more likely +than not, the message will actually be drawn from reading the +contents of a file or, maybe, from entering data at an input() +prompt. + +Since the text in this case must be bytes, it is most likely that +the input form will be a separate file which is opened with "rb" +as this is the simplest method of obtaining the correct data +format. +""" + +c = gpg.Context(armor=True) +rpattern = list(c.keylist(pattern="@gnupg.org", secret=False)) +logrus = [] + +for i in range(len(rpattern)): + if rpattern[i].can_encrypt == 1: + logrus.append(rpattern[i]) + +ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, + sign=False, always_trust=True) + +with open("secret_plans.txt.asc", "wb") as afile: + afile.write(ciphertext) +#+END_SRC + +All it would take to change the above example to sign the message +and also encrypt the message to any configured default keys would +be to change the =c.encrypt= line to this: + +#+BEGIN_SRC python -i +ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, + always_trust=True, + add_encrypt_to=True) +#+END_SRC + +The only keyword arguments requiring modification are those for which +the default values are changing. The default value of =sign= is +=True=, the default of =always_trust= is =False=, the default of +=add_encrypt_to= is =False=. + +If =always_trust= is not set to =True= and any of the recipient keys +are not trusted (e.g. not signed or locally signed) then the +encryption will raise an error. It is possible to mitigate this +somewhat with something more like this: + +#+BEGIN_SRC python -i +import gpg + +with open("secret_plans.txt.asc", "rb") as afile: + text = afile.read() + +c = gpg.Context(armor=True) +rpattern = list(c.keylist(pattern="@gnupg.org", secret=False)) +logrus = [] + +for i in range(len(rpattern)): + if rpattern[i].can_encrypt == 1: + logrus.append(rpattern[i]) + + try: + ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, + add_encrypt_to=True) + except gpg.errors.InvalidRecipients as e: + for i in range(len(e.recipients)): + for n in range(len(logrus)): + if logrus[n].fpr == e.recipients[i].fpr: + logrus.remove(logrus[n]) + else: + pass + try: + ciphertext, result, sign_result = c.encrypt(text, + recipients=logrus, + add_encrypt_to=True) + with open("secret_plans.txt.asc", "wb") as afile: + afile.write(ciphertext) + except: + pass +#+END_SRC + +This will attempt to encrypt to all the keys searched for, then remove +invalid recipients if it fails and try again. + + +** Decryption + :PROPERTIES: + :CUSTOM_ID: howto-basic-decryption + :END: + +Decrypting something encrypted to a key in one's secret keyring is +fairly straight forward. + +In this example code, however, preconfiguring either =gpg.Context()= +or =gpg.core.Context()= as =c= is unnecessary because there is no need +to modify the Context prior to conducting the decryption and since the +Context is only used once, setting it to =c= simply adds lines for no +gain. + +#+BEGIN_SRC python -i +import gpg + +ciphertext = input("Enter path and filename of encrypted file: ") +newfile = input("Enter path and filename of file to save decrypted data to: ") + +with open(ciphertext, "rb") as cfile: + try: + plaintext, result, verify_result = gpg.Context().decrypt(cfile) + except gpg.errors.GPGMEError as e: + plaintext = None + print(e) + +if plaintext is not None: + with open(newfile, "wb") as nfile: + nfile.write(plaintext) + else: + pass +#+END_SRC + +The data available in =plaintext= in this example is the decrypted +content as a byte object, the recipient key IDs and algorithms in +=result= and the results of verifying any signatures of the data in +=verify_result=. + + +** Signing text and files + :PROPERTIES: + :CUSTOM_ID: howto-basic-signing + :END: + +The following sections demonstrate how to specify keys to sign with. + + +*** Signing key selection + :PROPERTIES: + :CUSTOM_ID: howto-basic-signing-signers + :END: + +By default GPGME and the Python bindings will use the default key +configured for the user invoking the GPGME API. If there is no +default key specified and there is more than one secret key available +it may be necessary to specify the key or keys with which to sign +messages and files. + +#+BEGIN_SRC python -i +import gpg + +logrus = input("Enter the email address or string to match signing keys to: ") +hancock = gpg.Context().keylist(pattern=logrus, secret=True) +sig_src = list(hancock) +#+END_SRC + +The signing examples in the following sections include the explicitly +designated =signers= parameter in two of the five examples; once where +the resulting signature would be ASCII armoured and once where it +would not be armoured. + +While it would be possible to enter a key ID or fingerprint here to +match a specific key, it is not possible to enter two fingerprints and +match two keys since the patten expects a string, bytes or None and +not a list. A string with two fingerprints won't match any single +key. + + +*** Normal or default signing messages or files + :PROPERTIES: + :CUSTOM_ID: howto-basic-signing-normal + :END: + +The normal or default signing process is essentially the same as is +most often invoked when also encrypting a message or file. So when +the encryption component is not utilised, the result is to produce an +encoded and signed output which may or may not be ASCII armoured and +which may or may not also be compressed. + +By default compression will be used unless GnuPG detects that the +plaintext is already compressed. ASCII armouring will be determined +according to the value of =gpg.Context().armor=. + +The compression algorithm is selected in much the same way as the +symmetric encryption algorithm or the hash digest algorithm is when +multiple keys are involved; from the preferences saved into the key +itself or by comparison with the preferences with all other keys +involved. + +#+BEGIN_SRC python -i +import gpg + +text0 = """Declaration of ... something. + +""" +text = text0.encode() + +c = gpg.Context(armor=True, signers=sig_src) +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) + +with open("/path/to/statement.txt.asc", "w") as afile: + afile.write(signed_data.decode()) +#+END_SRC + +Though everything in this example is accurate, it is more likely that +reading the input data from another file and writing the result to a +new file will be performed more like the way it is done in the next +example. Even if the output format is ASCII armoured. + +#+BEGIN_SRC python -i +import gpg + +with open("/path/to/statement.txt", "rb") as tfile: + text = tfile.read() + +c = gpg.Context() +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) + +with open("/path/to/statement.txt.sig", "wb") as afile: + afile.write(signed_data) +#+END_SRC + + +*** Detached signing messages and files + :PROPERTIES: + :CUSTOM_ID: howto-basic-signing-detached + :END: + +Detached signatures will often be needed in programmatic uses of +GPGME, either for signing files (e.g. tarballs of code releases) or as +a component of message signing (e.g. PGP/MIME encoded email). + +#+BEGIN_SRC python -i +import gpg + +text0 = """Declaration of ... something. + +""" +text = text0.encode() + +c = gpg.Context(armor=True) +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) + +with open("/path/to/statement.txt.asc", "w") as afile: + afile.write(signed_data.decode()) +#+END_SRC + +As with normal signatures, detached signatures are best handled as +byte literals, even when the output is ASCII armoured. + +#+BEGIN_SRC python -i +import gpg + +with open("/path/to/statement.txt", "rb") as tfile: + text = tfile.read() + +c = gpg.Context(signers=sig_src) +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) + +with open("/path/to/statement.txt.sig", "wb") as afile: + afile.write(signed_data) +#+END_SRC + + +*** Clearsigning messages or text + :PROPERTIES: + :CUSTOM_ID: howto-basic-signing-clear + :END: + +Though PGP/in-line messages are no longer encouraged in favour of +PGP/MIME, there is still sometimes value in utilising in-line +signatures. This is where clear-signed messages or text is of value. + +#+BEGIN_SRC python -i +import gpg + +text0 = """Declaration of ... something. + +""" +text = text0.encode() + +c = gpg.Context() +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) + +with open("/path/to/statement.txt.asc", "w") as afile: + afile.write(signed_data.decode()) +#+END_SRC + +In spite of the appearance of a clear-signed message, the data handled +by GPGME in signing it must still be byte literals. + +#+BEGIN_SRC python -i +import gpg + +with open("/path/to/statement.txt", "rb") as tfile: + text = tfile.read() + +c = gpg.Context() +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) + +with open("/path/to/statement.txt.asc", "wb") as afile: + afile.write(signed_data) +#+END_SRC + + +** Signature verification + :PROPERTIES: + :CUSTOM_ID: howto-basic-verification + :END: + +Essentially there are two principal methods of verification of a +signature. The first of these is for use with the normal or default +signing method and for clear-signed messages. The second is for use +with files and data with detached signatures. + +The following example is intended for use with the default signing +method where the file was not ASCII armoured: + +#+BEGIN_SRC python -i +import gpg +import time + +filename = "statement.txt" +gpg_file = "statement.txt.gpg" + +c = gpg.Context() + +try: + data, result = c.verify(open(gpg_file)) + verified = True +except gpg.errors.BadSignatures as e: + verified = False + print(e) + +if verified is True: + for i in range(len(result.signatures)): + sign = result.signatures[i] + print("""Good signature from: +{0} +with key {1} +made at {2} +""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, + time.ctime(sign.timestamp))) +else: + pass +#+END_SRC + +Whereas this next example, which is almost identical would work with +normal ASCII armoured files and with clear-signed files: + +#+BEGIN_SRC python -i +import gpg +import time + +filename = "statement.txt" +asc_file = "statement.txt.asc" + +c = gpg.Context() + +try: + data, result = c.verify(open(asc_file)) + verified = True +except gpg.errors.BadSignatures as e: + verified = False + print(e) + +if verified is True: + for i in range(len(result.signatures)): + sign = result.signatures[i] + print("""Good signature from: +{0} +with key {1} +made at {2} +""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, + time.ctime(sign.timestamp))) +else: + pass +#+END_SRC + +In both of the previous examples it is also possible to compare the +original data that was signed against the signed data in =data= to see +if it matches with something like this: + +#+BEGIN_SRC python -i +with open(filename, "rb") as afile: + text = afile.read() + +if text == data: + print("Good signature.") +else: + pass +#+END_SRC + +The following two examples, however, deal with detached signatures. +With his method of verification the data that was signed does not get +returned since it is already being explicitly referenced in the first +argument of =c.verify=. So =data= is =None= and only the information +in =result= is available. + +#+BEGIN_SRC python -i +import gpg +import time + +filename = "statement.txt" +sig_file = "statement.txt.sig" + +c = gpg.Context() + +try: + data, result = c.verify(open(filename), open(sig_file)) + verified = True +except gpg.errors.BadSignatures as e: + verified = False + print(e) + +if verified is True: + for i in range(len(result.signatures)): + sign = result.signatures[i] + print("""Good signature from: +{0} +with key {1} +made at {2} +""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, + time.ctime(sign.timestamp))) +else: + pass +#+END_SRC + +#+BEGIN_SRC python -i +import gpg +import time + +filename = "statement.txt" +asc_file = "statement.txt.asc" + +c = gpg.Context() + +try: + data, result = c.verify(open(filename), open(asc_file)) + verified = True +except gpg.errors.BadSignatures as e: + verified = False + print(e) + +if verified is True: + for i in range(len(result.signatures)): + sign = result.signatures[i] + print("""Good signature from: +{0} +with key {1} +made at {2} +""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, + time.ctime(sign.timestamp))) +else: + pass +#+END_SRC + + +* Creating keys and subkeys + :PROPERTIES: + :CUSTOM_ID: key-generation + :END: + +The one thing, aside from GnuPG itself, that GPGME depends on, of +course, is the keys themselves. So it is necessary to be able to +generate them and modify them by adding subkeys, revoking or disabling +them, sometimes deleting them and doing the same for user IDs. + +In the following examples a key will be created for the world's +greatest secret agent, Danger Mouse. Since Danger Mouse is a secret +agent he needs to be able to protect information to =SECRET= level +clearance, so his keys will be 3072-bit keys. + +The pre-configured =gpg.conf= file which sets cipher, digest and other +preferences contains the following configuration parameters: + +#+BEGIN_SRC conf + expert + allow-freeform-uid + allow-secret-key-import + trust-model tofu+pgp + tofu-default-policy unknown + enable-large-rsa + enable-dsa2 + cert-digest-algo SHA512 + default-preference-list TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1 ZLIB BZIP2 ZIP Uncompressed + personal-cipher-preferences TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES + personal-digest-preferences SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1 + personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed +#+END_SRC + + +** Primary key + :PROPERTIES: + :CUSTOM_ID: keygen-primary + :END: + +Generating a primary key uses the =create_key= method in a Context. +It contains multiple arguments and keyword arguments, including: +=userid=, =algorithm=, =expires_in=, =expires=, =sign=, =encrypt=, +=certify=, =authenticate=, =passphrase= and =force=. The defaults for +all of those except =userid=, =algorithm=, =expires_in=, =expires= and +=passphrase= is =False=. The defaults for =algorithm= and +=passphrase= is =None=. The default for =expires_in= is =0=. The +default for =expires= is =True=. There is no default for =userid=. + +If =passphrase= is left as =None= then the key will not be generated +with a passphrase, if =passphrase= is set to a string then that will +be the passphrase and if =passphrase= is set to =True= then gpg-agent +will launch pinentry to prompt for a passphrase. For the sake of +convenience, these examples will keep =passphrase= set to =None=. + +#+BEGIN_SRC python -i +import gpg + +c = gpg.Context() + +c.home_dir = "~/.gnupg-dm" +userid = "Danger Mouse " + +dmkey = c.create_key(userid, algorithm="rsa3072", expires_in=31536000, + sign=True, certify=True) +#+END_SRC + +One thing to note here is the use of setting the =c.home_dir= +parameter. This enables generating the key or keys in a different +location. In this case to keep the new key data created for this +example in a separate location rather than adding it to existing and +active key store data. As with the default directory, =~/.gnupg=, any +temporary or separate directory needs the permissions set to only +permit access by the directory owner. On posix systems this means +setting the directory permissions to 700. + +The =temp-homedir-config.py= script in the HOWTO examples directory +will create an alternative homedir with these configuration options +already set and the correct directory and file permissions. + +The successful generation of the key can be confirmed via the returned +=GenkeyResult= object, which includes the following data: + +#+BEGIN_SRC python -i +print(""" + Fingerprint: {0} + Primary Key: {1} + Public Key: {2} + Secret Key: {3} + Sub Key: {4} +User IDs: {5} +""".format(dmkey.fpr, dmkey.primary, dmkey.pubkey, dmkey.seckey, dmkey.sub, + dmkey.uid)) +#+END_SRC + +Alternatively the information can be confirmed using the command line +program: + +#+BEGIN_SRC shell + bash-4.4$ gpg --homedir ~/.gnupg-dm -K + ~/.gnupg-dm/pubring.kbx + ---------------------- + sec rsa3072 2018-03-15 [SC] [expires: 2019-03-15] + 177B7C25DB99745EE2EE13ED026D2F19E99E63AA + uid [ultimate] Danger Mouse + + bash-4.4$ +#+END_SRC + +As with generating keys manually, to preconfigure expanded preferences +for the cipher, digest and compression algorithms, the =gpg.conf= file +must contain those details in the home directory in which the new key +is being generated. I used a cut down version of my own =gpg.conf= +file in order to be able to generate this: + +#+BEGIN_SRC shell + bash-4.4$ gpg --homedir ~/.gnupg-dm --edit-key 177B7C25DB99745EE2EE13ED026D2F19E99E63AA showpref quit + Secret key is available. + + sec rsa3072/026D2F19E99E63AA + created: 2018-03-15 expires: 2019-03-15 usage: SC + trust: ultimate validity: ultimate + [ultimate] (1). Danger Mouse + + [ultimate] (1). Danger Mouse + Cipher: TWOFISH, CAMELLIA256, AES256, CAMELLIA192, AES192, CAMELLIA128, AES, BLOWFISH, IDEA, CAST5, 3DES + Digest: SHA512, SHA384, SHA256, SHA224, RIPEMD160, SHA1 + Compression: ZLIB, BZIP2, ZIP, Uncompressed + Features: MDC, Keyserver no-modify + + bash-4.4$ +#+END_SRC + + +** Subkeys + :PROPERTIES: + :CUSTOM_ID: keygen-subkeys + :END: + +Adding subkeys to a primary key is fairly similar to creating the +primary key with the =create_subkey= method. Most of the arguments +are the same, but not quite all. Instead of the =userid= argument +there is now a =key= argument for selecting which primary key to add +the subkey to. + +In the following example an encryption subkey will be added to the +primary key. Since Danger Mouse is a security conscious secret agent, +this subkey will only be valid for about six months, half the length +of the primary key. + +#+BEGIN_SRC python -i +import gpg + +c = gpg.Context() +c.home_dir = "~/.gnupg-dm" + +key = c.get_key(dmkey.fpr, secret=True) +dmsub = c.create_subkey(key, algorithm="rsa3072", expires_in=15768000, + encrypt=True) +#+END_SRC + +As with the primary key, the results here can be checked with: + +#+BEGIN_SRC python -i +print(""" + Fingerprint: {0} + Primary Key: {1} + Public Key: {2} + Secret Key: {3} + Sub Key: {4} +User IDs: {5} +""".format(dmsub.fpr, dmsub.primary, dmsub.pubkey, dmsub.seckey, dmsub.sub, + dmsub.uid)) +#+END_SRC + +As well as on the command line with: + +#+BEGIN_SRC shell + bash-4.4$ gpg --homedir ~/.gnupg-dm -K + ~/.gnupg-dm/pubring.kbx + ---------------------- + sec rsa3072 2018-03-15 [SC] [expires: 2019-03-15] + 177B7C25DB99745EE2EE13ED026D2F19E99E63AA + uid [ultimate] Danger Mouse + ssb rsa3072 2018-03-15 [E] [expires: 2018-09-13] + + bash-4.4$ +#+END_SRC + + +** User IDs + :PROPERTIES: + :CUSTOM_ID: keygen-uids + :END: + + +*** Adding User IDs + :PROPERTIES: + :CUSTOM_ID: keygen-uids-add + :END: + +By comparison to creating primary keys and subkeys, adding a new user +ID to an existing key is much simpler. The method used to do this is +=key_add_uid= and the only arguments it takes are for the =key= and +the new =uid=. + +#+BEGIN_SRC python -i +import gpg + +c = gpg.Context() +c.home_dir = "~/.gnupg-dm" + +dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" +key = c.get_key(dmfpr, secret=True) +uid = "Danger Mouse " + +c.key_add_uid(key, uid) +#+END_SRC + +Unsurprisingly the result of this is: + +#+BEGIN_SRC shell + bash-4.4$ gpg --homedir ~/.gnupg-dm -K + ~/.gnupg-dm/pubring.kbx + ---------------------- + sec rsa3072 2018-03-15 [SC] [expires: 2019-03-15] + 177B7C25DB99745EE2EE13ED026D2F19E99E63AA + uid [ultimate] Danger Mouse + uid [ultimate] Danger Mouse + ssb rsa3072 2018-03-15 [E] [expires: 2018-09-13] + + bash-4.4$ +#+END_SRC + + +*** Revokinging User IDs + :PROPERTIES: + :CUSTOM_ID: keygen-uids-revoke + :END: + +Revoking a user ID is a fairly similar process, except that it uses +the =key_revoke_uid= method. + +#+BEGIN_SRC python -i +import gpg + +c = gpg.Context() +c.home_dir = "~/.gnupg-dm" + +dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" +key = c.get_key(dmfpr, secret=True) +uid = "Danger Mouse " + +c.key_revoke_uid(key, uid) +#+END_SRC + + +** Key certification + :PROPERTIES: + :CUSTOM_ID: key-sign + :END: + +Since key certification is more frequently referred to as key signing, +the method used to perform this function is =key_sign=. + +The =key_sign= method takes four arguments: =key=, =uids=, +=expires_in= and =local=. The default value of =uids= is =None= and +which results in all user IDs being selected. The default value of +both =expires_in= and =local= is =False=; which results in the +signature never expiring and being able to be exported. + +The =key= is the key being signed rather than the key doing the +signing. To change the key doing the signing refer to the signing key +selection above for signing messages and files. + +If the =uids= value is not =None= then it must either be a string to +match a single user ID or a list of strings to match multiple user +IDs. In this case the matching of those strings must be precise and +it is case sensitive. + +To sign Danger Mouse's key for just the initial user ID with a +signature which will last a little over a month, do this: + +#+BEGIN_SRC python -i +import gpg + +c = gpg.Context() +uid = "Danger Mouse " + +dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" +key = c.get_key(dmfpr, secret=True) +c.key_sign(key, uids=uid, expires_in=2764800) +#+END_SRC + + +* Advanced or Experimental Use Cases + :PROPERTIES: + :CUSTOM_ID: advanced-use + :END: + + +** C plus Python plus SWIG plus Cython + :PROPERTIES: + :CUSTOM_ID: cython + :END: + +In spite of the apparent incongruence of using Python bindings to a C +interface only to generate more C from the Python; it is in fact quite +possible to use the GPGME bindings with [[http://docs.cython.org/en/latest/index.html][Cython]]. Though in many cases +the benefits may not be obvious since the most computationally +intensive work never leaves the level of the C code with which GPGME +itself is interacting with. + +Nevertheless, there are some situations where the benefits are +demonstrable. One of the better and easier examples being the one of +the early examples in this HOWTO, the [[#howto-keys-counting][key counting]] code. Running that +example as an executable Python script, =keycount.py= (available in +the =examples/howto/= directory), will take a noticable amount of time +to run on most systems where the public keybox or keyring contains a +few thousand public keys. + +Earlier in the evening, prior to starting this section, I ran that +script on my laptop; as I tend to do periodically and timed it using +=time= utility, with the following results: + +#+BEGIN_SRC shell + bash-4.4$ time keycount.py + + Number of secret keys: 23 + Number of public keys: 12112 + + + real 11m52.945s + user 0m0.913s + sys 0m0.752s + + bash-4.4$ +#+END_SRC + +Sometime after that I imported another key and followed it with a +little test of Cython. This test was kept fairly basic, essentially +lifting the material from the [[http://docs.cython.org/en/latest/src/tutorial/cython_tutorial.html][Cython Basic Tutorial]] to demonstrate +compiling Python code to C. The first step was to take the example +key counting code quoted previously, essentially from the importing of +the =gpg= module to the end of the script: + +#+BEGIN_SRC python -i +import gpg + +c = gpg.Context() +seckeys = c.keylist(pattern=None, secret=True) +pubkeys = c.keylist(pattern=None, secret=False) + +seclist = list(seckeys) +secnum = len(seclist) + +publist = list(pubkeys) +pubnum = len(publist) + +print(""" + Number of secret keys: {0} + Number of public keys: {1} + +""".format(secnum, pubnum)) +#+END_SRC + +Save that into a file called =keycount.pyx= and then create a +=setup.py= file which contains this: + +#+BEGIN_SRC python -i +from distutils.core import setup +from Cython.Build import cythonize + +setup( + ext_modules = cythonize("keycount.pyx") +) +#+END_SRC + +Compile it: + +#+BEGIN_SRC shell + bash-4.4$ python setup.py build_ext --inplace + bash-4.4$ +#+END_SRC + +Then run it in a similar manner to =keycount.py=: + +#+BEGIN_SRC shell + bash-4.4$ time python3.7 -c "import keycount" + + Number of secret keys: 23 + Number of public keys: 12113 + + + real 6m47.905s + user 0m0.785s + sys 0m0.331s + + bash-4.4$ +#+END_SRC + +Cython turned =keycount.pyx= into an 81KB =keycount.o= file in the +=build/= directory, a 24KB =keycount.cpython-37m-darwin.so= file to be +imported into Python 3.7 and a 113KB =keycount.c= generated C source +code file of nearly three thousand lines. Quite a bit bigger than the +314 bytes of the =keycount.pyx= file or the full 1,452 bytes of the +full executable =keycount.py= example script. + +On the other hand it ran in nearly half the time; taking 6 minutes and +47.905 seconds to run. As opposed to the 11 minutes and 52.945 seconds +which the CPython script alone took. + +The =keycount.pyx= and =setup.py= files used to generate this example +have been added to the =examples/howto/advanced/cython/= directory +The example versions include some additional options to annotate the +existing code and to detect Cython's use. The latter comes from the +[[http://docs.cython.org/en/latest/src/tutorial/pure.html#magic-attributes-within-the-pxd][Magic Attributes]] section of the Cython documentation. + + +* Miscellaneous extras and work-arounds + :PROPERTIES: + :CUSTOM_ID: cheats-and-hacks + :END: + +Most of the things in the following sections are here simply because +there was no better place to put them, even though some are only +peripherally related to the GPGME Python bindings. Some are also +workarounds for functions not integrated with GPGME as yet. This is +especially true of the first of these, dealing with [[#group-lines][group lines]]. + + +** Group lines + :PROPERTIES: + :CUSTOM_ID: group-lines + :END: + +There is not yet an easy way to access groups configured in the +gpg.conf file from within GPGME. As a consequence these central +groupings of keys cannot be shared amongst multiple programs, such as +MUAs readily. + +The following code, however, provides a work-around for obtaining this +information in Python. + +#+BEGIN_SRC python -i +import subprocess +import sys + +if sys.platform == "win32": + gpgconfcmd = "gpgconf.exe --list-options gpg" +else: + gpgconfcmd = "gpgconf --list-options gpg" + +try: + lines = subprocess.getoutput(gpgconfcmd).splitlines() +except: + process = subprocess.Popen(gpgconfcmd.split(), stdout=subprocess.PIPE) + procom = process.communicate() + if sys.version_info[0] == 2: + lines = procom[0].splitlines() + else: + lines = procom[0].decode().splitlines() + +for i in range(len(lines)): + if lines[i].startswith("group") is True: + line = lines[i] + else: + pass + +groups = line.split(":")[-1].replace('"', '').split(',') + +group_lines = [] +group_lists = [] + +for i in range(len(groups)): + group_lines.append(groups[i].split("=")) + group_lists.append(groups[i].split("=")) + +for i in range(len(group_lists)): + group_lists[i][1] = group_lists[i][1].split() +#+END_SRC + +The result of that code is that =group_lines= is a list of lists where +=group_lines[i][0]= is the name of the group and =group_lines[i][1]= +is the key IDs of the group as a string. + +The =group_lists= result is very similar in that it is a list of +lists. The first part, =group_lists[i][0]= matches +=group_lines[i][0]= as the name of the group, but =group_lists[i][1]= +is the key IDs of the group as a string. + +A demonstration of using the =groups.py= module is also available in +the form of the executable =mutt-groups.py= script. This second +script reads all the group entries in a user's =gpg.conf= file and +converts them into crypt-hooks suitable for use with the Mutt and +Neomutt mail clients. + + +** Keyserver access for Python + :PROPERTIES: + :CUSTOM_ID: hkp4py + :END: + +The [[https://github.com/Selfnet/hkp4py][hkp4py]] module by Marcel Fest was originally a port of the old +[[https://github.com/dgladkov/python-hkp][python-hkp]] module from Python 2 to Python 3 and updated to use the +[[http://docs.python-requests.org/en/latest/index.html][requests]] module instead. It has since been modified to provide +support for Python 2.7 as well and is available via PyPI. + +Since it rewrites the =hkp= protocol prefix as =http= and =hkps= as +=https=, the module is able to be used even with servers which do not +support the full scope of keyserver functions.[fn:6] It also works quite +readily when incorporated into a [[#cython][Cython]] generated and compiled version +of any code. + + +*** Key import format + :PROPERTIES: + :CUSTOM_ID: hkp4py-strings + :END: + +The hkp4py module returns key data via requests as string literals +(=r.text=) instead of byte literals (=r.content=). This means that +the retrurned key data must be encoded to UTF-8 when importing that +key material using a =gpg.Context().key_import()= method. + +For this reason an alternative method has been added to the =search= +function of =hkp4py.KeyServer()= which returns the key in the correct +format as expected by =key_import=. When importing using this module, +it is now possible to import with this: + +#+BEGIN_SRC python -i +for key in keys: + if key.revoked is False: + gpg.Context().key_import(key.key_blob) + else: + pass +#+END_SRC + +Without that recent addition it would have been necessary to encode +the contents of each =hkp4py.KeyServer().search()[i].key= in +=hkp4py.KeyServer().search()= before trying to import it. + +An example of this is included in the [[#howto-import-key][Importing Keys]] section of this +HOWTO and the corresponding executable version of that example is +available in the =lang/python/examples/howto= directory as normal; the +executable version is the =import-keys-hkp.py= file. + + +* Copyright and Licensing + :PROPERTIES: + :CUSTOM_ID: copyright-and-license + :END: + + +** Copyright + :PROPERTIES: + :CUSTOM_ID: copyright + :END: + +Copyright © The GnuPG Project, 2018. + +Copyright (C) The GnuPG Project, 2018. + + +** Draft Editions of this HOWTO + :PROPERTIES: + :CUSTOM_ID: draft-editions + :END: + +Draft editions of this HOWTO may be periodically available directly +from the author at any of the following URLs: + +- [[https://files.au.adversary.org/crypto/gpgme-python-howto.html][GPGME Python Bindings HOWTO draft (XHTML AWS S3 SSL)]] +- [[http://files.au.adversary.org/crypto/gpgme-python-howto.html][GPGME Python Bindings HOWTO draft (XHTML AWS S3 no SSL)]] +- [[https://files.au.adversary.org/crypto/gpgme-python-howto.texi][GPGME Python Bindings HOWTO draft (Texinfo file AWS S3 SSL)]] +- [[http://files.au.adversary.org/crypto/gpgme-python-howto.texi][GPGME Python Bindings HOWTO draft (Texinfo file AWS S3 no SSL)]] +- [[https://files.au.adversary.org/crypto/gpgme-python-howto.info][GPGME Python Bindings HOWTO draft (Info file AWS S3 SSL)]] +- [[http://files.au.adversary.org/crypto/gpgme-python-howto.info][GPGME Python Bindings HOWTO draft (Info file AWS S3 no SSL)]] +- [[https://files.au.adversary.org/crypto/gpgme-python-howto.xml][GPGME Python Bindings HOWTO draft (Docbook 4.2 AWS S3 SSL)]] +- [[http://files.au.adversary.org/crypto/gpgme-python-howto.xml][GPGME Python Bindings HOWTO draft (Docbook 4.2 AWS S3 no SSL)]] + +All of these draft versions are generated from this document via Emacs +[[https://orgmode.org/][Org mode]] and [[https://www.gnu.org/software/texinfo/][GNU Texinfo]]. Though it is likely that the specific [[https://files.au.adversary.org/crypto/gpgme-python-howto.org][file]] +[[http://files.au.adversary.org/crypto/gpgme-python-howto.org][version]] used will be on the same server with the generated output +formats. + +In addition to these there is a significantly less frequently updated +version as a HTML [[https://files.au.adversary.org/crypto/gpgme-python-howto/webhelp/index.html][WebHelp site]] (AWS S3 SSL); generated from DITA XML +source files, which can be found in [[https://dev.gnupg.org/source/gpgme/browse/ben%252Fhowto-dita/][an alternative branch]] of the GPGME +git repository. + +These draft editions are not official documents and the version of +documentation in the master branch or which ships with released +versions is the only official documentation. Nevertheless, these +draft editions may occasionally be of use by providing more accessible +web versions which are updated between releases. They are provided on +the understanding that they may contain errors or may contain content +subject to change prior to an official release. + + +** License GPL compatible + :PROPERTIES: + :CUSTOM_ID: license + :END: + +This file is free software; as a special exception the author gives +unlimited permission to copy and/or distribute it, with or without +modifications, as long as this notice is preserved. + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. + + +* Footnotes + +[fn:1] =Short_History.org= and/or =Short_History.html=. + +[fn:2] The =lang/python/docs/= directory in the GPGME source. + +[fn:3] With no issues reported specific to Python 3.7, the release of +Python 3.7.1 at around the same time as GPGME 1.12.0 and the testing +with Python 3.7.1rc1, there is no reason to delay moving 3.7 ahead of +3.6 now. Production environments with more conservative requirements +will always enforce their own policies anyway and installation to each +supported minor release is quite possible too. + +[fn:4] Yes, even if you use virtualenv with everything you do in +Python. If you want to install this module as just your user account +then you will need to manually configure, compile and install the +/entire/ GnuPG stack as that user as well. This includes libraries +which are not often installed that way. It can be done and there are +circumstances under which it is worthwhile, but generally only on +POSIX systems which utilise single user mode (some even require it). + +[fn:5] You probably don't really want to do this. Searching the +keyservers for "gnupg.org" produces over 400 results, the majority of +which aren't actually at the gnupg.org domain, but just included a +comment regarding the project in their key somewhere. + +[fn:6] Such as with ProtonMail servers. This also means that +restricted servers which only advertise either HTTP or HTTPS end +points and not HKP or HKPS end points must still be identified as as +HKP or HKPS within the Python Code. The =hkp4py= module will rewrite +these appropriately when the connection is made to the server. diff --git a/lang/python/docs/src/short-history.org b/lang/python/docs/src/short-history.org new file mode 100644 index 00000000..31b7d446 --- /dev/null +++ b/lang/python/docs/src/short-history.org @@ -0,0 +1,172 @@ +#+TITLE: A Short History of the GPGME bindings for Python +#+LATEX_COMPILER: xelatex +#+LATEX_CLASS: article +#+LATEX_CLASS_OPTIONS: [12pt] +#+LATEX_HEADER: \usepackage{xltxtra} +#+LATEX_HEADER: \usepackage[margin=1in]{geometry} +#+LATEX_HEADER: \setmainfont[Ligatures={Common}]{Latin Modern Roman} + +* Overview + :PROPERTIES: + :CUSTOM_ID: overview + :END: + +The GPGME Python bindings passed through many hands and numerous +phases before, after a fifteen year journey, coming full circle to +return to the source. This is a short explanation of that journey. + +** In the beginning + :PROPERTIES: + :CUSTOM_ID: in-the-begining + :END: + + In 2002 John Goerzen released PyME; Python bindings for the GPGME + module which utilised the current release of Python of the time and + SWIG.[fn:1] Shortly after creating it and ensuring it worked he stopped + supporting it, though he left his work available on his Gopher + site. + +** Keeping the flame alive + :PROPERTIES: + :CUSTOM_ID: keeping-the-flame-alive + :END: + + A couple of years later the project was picked up by Igor Belyi and + actively developed and maintained by him from 2004 to 2008. Igor's + whereabouts at the time of this document's creation are unknown, + but the current authors do hope he is well. We're assuming (or + hoping) that life did what life does and made continuing untenable. + +** Passing the torch + :PROPERTIES: + :CUSTOM_ID: passing-the-torch + :END: + + In 2014 Martin Albrecht wanted to patch a bug in the PyME code and + discovered the absence of Igor. Following a discussion on the PyME + mailing list he became the new maintainer for PyME, releasing + version 0.9.0 in May of that year. He remains the maintainer of + the original PyME release in Python 2.6 and 2.7 (available via + PyPI). + +** Coming full circle + :PROPERTIES: + :CUSTOM_ID: ouroboros + :END: + + In 2015 Ben McGinnes approached Martin about a Python 3 version, + while investigating how complex a task this would be the task ended + up being completed. A subsequent discussion with Werner Koch led + to the decision to fold the Python 3 port back into the original + GPGME release in the languages subdirectory for non-C bindings + under the module name of =pyme3=. + + In 2016 this PyME module was integrated back into the GPGME project + by Justus Winter. During the course of this work Justus adjusted + the port to restore limited support for Python 2, but not as many + minor point releases as the original PyME package supports. During + the course of this integration the package was renamed to more + accurately reflect its status as a component of GPGME. The =pyme3= + module was renamed to =gpg= and adopted by the upstream GnuPG team. + + In 2017 Justus departed G10code and the GnuPG team. Following this + Ben returned to maintain of gpgme Python bindings and continue + building them from that point. + +* Relics of the past + :PROPERTIES: + :CUSTOM_ID: relics-past + :END: + +There are a few things, in addition to code specific factors, such as +SWIG itself, which are worth noting here. + +** The Annoyances of Git + :PROPERTIES: + :CUSTOM_ID: the-annoyances-of-git + :END: + + As anyone who has ever worked with git knows, submodules are + horrible way to deal with pretty much anything. In the interests + of avoiding migraines, that was skipped with addition of the PyME + code to GPGME. + + Instead the files were added to a subdirectory of the =lang/= + directory, along with a copy of the entire git log up to that point + as a separate file within the =lang/python/docs/= directory.[fn:2] + As the log for PyME is nearly 100KB and the log for GPGME is + approximately 1MB, this would cause considerable bloat, as well as + some confusion, should the two be merged. + + Hence the unfortunate, but necessary, step to simply move the + files. A regular repository version has been maintained should it + be possible to implement this better in the future. + +** The Perils of PyPI + :PROPERTIES: + :CUSTOM_ID: the-perils-of-pypi + :END: + + The early port of the Python 2 =pyme= module as =pyme3= was never + added to PyPI while the focus remained on development and testing + during 2015 and early 2016. Later in 2016, however, when Justus + completed his major integration work and subsequently renamed the + module from =pyme3= to =gpg=, some prior releases were also + provided through PyPI. + + Since these bindings require a matching release of the GPGME + libraries in order to function, it was determined that there was + little benefit in also providing a copy through PyPI since anyone + obtaining the GPGME source code would obtain the Python bindings + source code at the same time. Whereas there was the potential to + sew confusion amongst Python users installing the module from PyPI, + only to discover that without the relevant C files, header files or + SWIG compiled binaries, the Python module did them little good. + + There are only two files on PyPI which might turn up in a search + for this module or a sample of its content: + + 1. gpg (1.8.0) - Python bindings for GPGME GnuPG cryptography library + 2. pyme (0.9.0) - Python support for GPGME GnuPG cryptography library + +*** GPG 1.8.0 - Python bindings for GPGME GnuPG cryptography library + :PROPERTIES: + :CUSTOM_ID: pypi-gpgme-180 + :END: + + This is the most recent version to reach PyPI and is the version + of the official Pyhon bindings which shipped with GPGME 1.8.0. If + you have GPGME 1.8.0 installed and /only/ 1.8.0 installed, then it + is probably safe to use this copy from PyPI. + + As there have been a lot of changes since the release of GPGME + 1.8.0, the GnuPG Project recommends not using this version of the + module and instead installing the current version of GPGME along + with the Python bindings included with that package. + +*** PyME 0.9.0 - Python support for GPGME GnuPG cryptography library + :PROPERTIES: + :CUSTOM_ID: pypi-gpgme-90 + :END: + + This is the last release of the PyME bindings maintained by Martin + Albrecht and is only compatible with Python 2, it will not work + with Python 3. This is the version of the software from which the + port from Python 2 to Python 3 code was made in 2015. + + Users of the more recent Python bindings will recognise numerous + points of similarity, but also significant differences. It is + likely that the more recent official bindings will feel "more + pythonic." + + For those using Python 2, there is essentially no harm in using + this module, but it may lack a number of more recent features + added to GPGME. + +* Footnotes + +[fn:1] In all likelihood thos would have been Python 2.2 or possibly +Python 2.3. + +[fn:2] The entire PyME git log and other preceding VCS logs are +located in the =gpgme/lang/python/docs/old-commits.log= file. -- cgit v1.2.3