
112 changed files with 73 additions and 6499 deletions
@ -1,26 +0,0 @@ |
|||
HERE:=$(dir $(lastword $(MAKEFILE_LIST))) |
|||
|
|||
# Constants
|
|||
BUILD_DIR = ./build |
|||
DIST_DIR = ./dist |
|||
VERSION_FILE = ./src/pEp/__version__.py |
|||
BUILD_INPLACE = ./src/pEp/_pEp.cpython-38-darwin.so |
|||
PYTHON_ARTIFACTS += ./.eggs |
|||
PYTHON_ARTIFACTS += ./src/pEp.egg-info |
|||
PYTHON_ARTIFACTS += ./.pytest_cache |
|||
VENV_DIR = ./venv |
|||
|
|||
# Build config Defaults
|
|||
DEBUG=0 |
|||
PREFIX= |
|||
|
|||
######### Overrides #########
|
|||
-include $(HERE)local.conf |
|||
|
|||
ifeq ($(DEBUG),1) |
|||
DEBUG_OPT+=--debug |
|||
endif |
|||
|
|||
ifneq ($(PREFIX),) |
|||
PREFIX_OPT += --prefix=$(PREFIX) |
|||
endif |
@ -1,22 +0,0 @@ |
|||
pEpPythonAdapter |
|||
================ |
|||
Python adapter for the `pEpEngine <https://pep.foundation/dev/repos/pEpEngine/>`_ |
|||
|
|||
|
|||
Documentation |
|||
------------- |
|||
Please find the documentation in the ``docs`` directory. |
|||
|
|||
|
|||
Issues |
|||
------ |
|||
If you are not pEp internal, please send a mail to: heck@pep.foundation |
|||
|
|||
If you are pEp internal, please open a ticket in our `jira bugtracker <https://pep.foundation/jira/projects/PYADPT/)`_ and for any questions, you are always welcome on #adapter>. |
|||
|
|||
|
|||
License |
|||
------- |
|||
|GNU AFFERO GENERAL PUBLIC LICENSE |
|||
|Version 3, 19 November 2007 |
|||
|See LICENSE.txt |
@ -1,19 +0,0 @@ |
|||
# Minimal makefile for Sphinx documentation
|
|||
#
|
|||
|
|||
# You can set these variables from the command line.
|
|||
SPHINXOPTS = |
|||
SPHINXBUILD = sphinx-build |
|||
SOURCEDIR = source |
|||
BUILDDIR = build |
|||
|
|||
# Put it first so that "make" without argument is like "make help".
|
|||
help: |
|||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) |
|||
|
|||
.PHONY: help Makefile |
|||
|
|||
# Catch-all target: route all unknown targets to Sphinx using the new
|
|||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
|||
%: Makefile |
|||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) |
@ -1,35 +0,0 @@ |
|||
@ECHO OFF |
|||
|
|||
pushd %~dp0 |
|||
|
|||
REM Command file for Sphinx documentation |
|||
|
|||
if "%SPHINXBUILD%" == "" ( |
|||
set SPHINXBUILD=sphinx-build |
|||
) |
|||
set SOURCEDIR=source |
|||
set BUILDDIR=build |
|||
|
|||
if "%1" == "" goto help |
|||
|
|||
%SPHINXBUILD% >NUL 2>NUL |
|||
if errorlevel 9009 ( |
|||
echo. |
|||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx |
|||
echo.installed, then set the SPHINXBUILD environment variable to point |
|||
echo.to the full path of the 'sphinx-build' executable. Alternatively you |
|||
echo.may add the Sphinx directory to PATH. |
|||
echo. |
|||
echo.If you don't have Sphinx installed, grab it from |
|||
echo.http://sphinx-doc.org/ |
|||
exit /b 1 |
|||
) |
|||
|
|||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% |
|||
goto end |
|||
|
|||
:help |
|||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% |
|||
|
|||
:end |
|||
popd |
@ -1,12 +0,0 @@ |
|||
pEp package |
|||
=========== |
|||
|
|||
Module contents |
|||
--------------- |
|||
|
|||
.. automodule:: pEp |
|||
:members: |
|||
:imported-members: |
|||
:undoc-members: |
|||
:show-inheritance: |
|||
|
@ -1,206 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# Configuration file for the Sphinx documentation builder. |
|||
# |
|||
# This file does only contain a selection of the most common options. For a |
|||
# full list see the documentation: |
|||
# http://www.sphinx-doc.org/en/master/config |
|||
|
|||
# -- Path setup -------------------------------------------------------------- |
|||
|
|||
# If extensions (or modules to document with autodoc) are in another directory, |
|||
# add these directories to sys.path here. If the directory is relative to the |
|||
# documentation root, use os.path.abspath to make it absolute, like shown here. |
|||
|
|||
import os |
|||
import sys |
|||
sys.path.insert(0, os.path.abspath('../../src')) |
|||
# -- Project information ----------------------------------------------------- |
|||
|
|||
project = "pEpPythonAdapter" |
|||
copyright = "2020, Volker Birk, heck, Hartmut Goebel, juga" |
|||
author = "Volker Birk, heck, Hartmut Goebel, juga" |
|||
|
|||
import pEp |
|||
# The full version, including alpha/beta/rc tags |
|||
release = pEp.__version__ |
|||
# The short X.Y version |
|||
version = ".".join(release.split(".")[:2]) |
|||
|
|||
# DEBUG |
|||
print("release:", release) |
|||
print("version:", version) |
|||
# -- General configuration --------------------------------------------------- |
|||
|
|||
# If your documentation needs a minimal Sphinx version, state it here. |
|||
# |
|||
# needs_sphinx = '1.0' |
|||
|
|||
# Add any Sphinx extension module names here, as strings. They can be |
|||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom |
|||
# ones. |
|||
extensions = [ |
|||
"sphinx.ext.autodoc", |
|||
"sphinx.ext.doctest", |
|||
"sphinx.ext.intersphinx", |
|||
"sphinx.ext.todo", |
|||
"sphinx.ext.coverage", |
|||
"sphinx.ext.viewcode", |
|||
] |
|||
|
|||
# Add any paths that contain templates here, relative to this directory. |
|||
templates_path = ["_templates"] |
|||
|
|||
# The suffix(es) of source filenames. |
|||
# You can specify multiple suffix as a list of string: |
|||
# |
|||
# source_suffix = ['.rst', '.md'] |
|||
source_suffix = ".rst" |
|||
|
|||
# The master toctree document. |
|||
master_doc = "index" |
|||
|
|||
# The language for content autogenerated by Sphinx. Refer to documentation |
|||
# for a list of supported languages. |
|||
# |
|||
# This is also used if you do content translation via gettext catalogs. |
|||
# Usually you set "language" from the command line for these cases. |
|||
language = None |
|||
|
|||
# List of patterns, relative to source directory, that match files and |
|||
# directories to ignore when looking for source files. |
|||
# This pattern also affects html_static_path and html_extra_path. |
|||
exclude_patterns = [] |
|||
|
|||
# The name of the Pygments (syntax highlighting) style to use. |
|||
pygments_style = None |
|||
|
|||
|
|||
# -- Options for HTML output ------------------------------------------------- |
|||
|
|||
# The theme to use for HTML and HTML Help pages. See the documentation for |
|||
# a list of builtin themes. |
|||
# |
|||
html_theme = "nature" |
|||
|
|||
# Theme options are theme-specific and customize the look and feel of a theme |
|||
# further. For a list of options available for each theme, see the |
|||
# documentation. |
|||
# |
|||
# html_theme_options = {} |
|||
|
|||
# Add any paths that contain custom static files (such as style sheets) here, |
|||
# relative to this directory. They are copied after the builtin static files, |
|||
# so a file named "default.css" will overwrite the builtin "default.css". |
|||
html_static_path = ["_static"] |
|||
|
|||
# Custom sidebar templates, must be a dictionary that maps document names |
|||
# to template names. |
|||
# |
|||
# The default sidebars (for documents that don't match any pattern) are |
|||
# defined by theme itself. Builtin themes are using these templates by |
|||
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', |
|||
# 'searchbox.html']``. |
|||
# |
|||
# html_sidebars = {} |
|||
|
|||
|
|||
# -- Options for HTMLHelp output --------------------------------------------- |
|||
|
|||
# Output file base name for HTML help builder. |
|||
htmlhelp_basename = "pEpPythonAdapterdoc" |
|||
|
|||
|
|||
# -- Options for LaTeX output ------------------------------------------------ |
|||
|
|||
latex_elements = { |
|||
# The paper size ('letterpaper' or 'a4paper'). |
|||
# |
|||
# 'papersize': 'letterpaper', |
|||
# The font size ('10pt', '11pt' or '12pt'). |
|||
# |
|||
# 'pointsize': '10pt', |
|||
# Additional stuff for the LaTeX preamble. |
|||
# |
|||
# 'preamble': '', |
|||
# Latex figure (float) alignment |
|||
# |
|||
# 'figure_align': 'htbp', |
|||
} |
|||
|
|||
# Grouping the document tree into LaTeX files. List of tuples |
|||
# (source start file, target name, title, |
|||
# author, documentclass [howto, manual, or own class]). |
|||
latex_documents = [ |
|||
( |
|||
master_doc, |
|||
"pEpPythonAdapter.tex", |
|||
"pEpPythonAdapter Documentation", |
|||
"2020, Volker Birk, heck, juga", |
|||
"manual", |
|||
) |
|||
] |
|||
|
|||
|
|||
# -- Options for manual page output ------------------------------------------ |
|||
|
|||
# One entry per manual page. List of tuples |
|||
# (source start file, name, description, authors, manual section). |
|||
man_pages = [ |
|||
( |
|||
master_doc, |
|||
"peppythonadapter", |
|||
"pEpPythonAdapter Documentation", |
|||
[author], |
|||
1, |
|||
) |
|||
] |
|||
|
|||
|
|||
# -- Options for Texinfo output ---------------------------------------------- |
|||
|
|||
# Grouping the document tree into Texinfo files. List of tuples |
|||
# (source start file, target name, title, author, |
|||
# dir menu entry, description, category) |
|||
texinfo_documents = [ |
|||
( |
|||
master_doc, |
|||
"pEpPythonAdapter", |
|||
"pEpPythonAdapter Documentation", |
|||
author, |
|||
"pEpPythonAdapter", |
|||
"One line description of project.", |
|||
"Miscellaneous", |
|||
) |
|||
] |
|||
|
|||
|
|||
# -- Options for Epub output ------------------------------------------------- |
|||
|
|||
# Bibliographic Dublin Core info. |
|||
epub_title = project |
|||
|
|||
# The unique identifier of the text. This can be a ISBN number |
|||
# or the project homepage. |
|||
# |
|||
# epub_identifier = '' |
|||
|
|||
# A unique identification for the text. |
|||
# |
|||
# epub_uid = '' |
|||
|
|||
# A list of files that should not be packed into the epub file. |
|||
epub_exclude_files = ["search.html"] |
|||
|
|||
|
|||
# -- Extension configuration ------------------------------------------------- |
|||
|
|||
# -- Options for intersphinx extension --------------------------------------- |
|||
|
|||
# Example configuration for intersphinx: refer to the Python standard library. |
|||
intersphinx_mapping = {"https://docs.python.org/": None} |
|||
|
|||
# -- Options for todo extension ---------------------------------------------- |
|||
|
|||
# If true, `todo` and `todoList` produce output, else they produce nothing. |
|||
todo_include_todos = True |
@ -1,21 +0,0 @@ |
|||
.. pEpPythonAdapter documentation master file, created by |
|||
sphinx-quickstart on Wed Oct 21 12:35:11 2020. |
|||
You can adapt this file completely to your liking, but it should at least |
|||
contain the root `toctree` directive. |
|||
|
|||
Welcome to pEpPythonAdapter's documentation! |
|||
============================================ |
|||
|
|||
.. toctree:: |
|||
:maxdepth: 2 |
|||
:caption: Contents: |
|||
|
|||
install |
|||
software_using |
|||
api/pEp |
|||
Indices and tables |
|||
================== |
|||
|
|||
* :ref:`genindex` |
|||
* :ref:`modindex` |
|||
* :ref:`search` |
@ -1,143 +0,0 @@ |
|||
Installation |
|||
============ |
|||
|
|||
Requirements |
|||
------------ |
|||
In order to build, use or install this extension module, you need to have some |
|||
system dependencies already installed: |
|||
|
|||
* pEp-base (sequoia, libetpan, asn1c, yml2, pEpEngine, libpEpAdapter) |
|||
* boost-python |
|||
|
|||
These `build instructions <https://dev.pep.foundation/Common%20Adapter%20Documentation/Adapter_Build_Instructions>`_ will get you all setup. |
|||
|
|||
Additionally, there is a `build script <http://pep-security.lu/gitlab/juga/Internal-Deployment/-/blob/master/build-pep-stack.sh>`_ |
|||
that executes these build instructions automatically (Debian and MacOS): |
|||
|
|||
.. Note:: If you dont install pEp-base system wide, but under a prefix, like /home/foo/local/, |
|||
you will need to have LD_LIBARY_PATH/DYLD_LIBRARY_PATH adjusted for all the following operations. |
|||
|
|||
|
|||
Build |
|||
----- |
|||
The pEpPythonAdapter is a python extension module that contains C/C++ code that needs to be |
|||
compiled first. So, before any use or installation, the module needs to be built. |
|||
|
|||
Build config |
|||
~~~~~~~~~~~~ |
|||
Create a local build config by creating a 'local.conf' file. There is a 'local.conf.example' describing |
|||
all the build options. You can use this as a template. |
|||
|
|||
``cp local.conf.example local.conf`` |
|||
|
|||
If you have pEp-base installed under a custom prefix (e.g. /home/foo/local) it is important |
|||
that you specify "PREFIX". |
|||
|
|||
Build |
|||
~~~~~ |
|||
To build the module just type: |
|||
|
|||
``make`` |
|||
|
|||
This will compile the C/C++ parts of the module and create the python packages in the .egg and .wheel format |
|||
in the dist/ dir. |
|||
|
|||
|
|||
Virtualenv |
|||
---------- |
|||
We recommend using a venv to work on/with the pEpPythonAdapter. |
|||
There is a convenience make target that will create and activate a venv that already has the LD_LIBRARY_PATH |
|||
or DYLD_LIBRARY_PATH set according to your ``local.conf``. |
|||
If the venv does not exist yet it will be created and activated. |
|||
If the venv already exists it will only be activated. |
|||
|
|||
``make venv`` |
|||
|
|||
After that, to install the pEp module into the venv, do: |
|||
|
|||
``make install`` |
|||
|
|||
|
|||
Installation |
|||
------------ |
|||
You can install the module in the in the following ways. |
|||
|
|||
To install the extension module system wide or into a venv, use: |
|||
|
|||
``make install`` |
|||
|
|||
To install the extension module into your home dir, use: |
|||
|
|||
``make install-user`` |
|||
|
|||
|
|||
Test |
|||
---- |
|||
To run the whole testsuite you need to first create/activate the venv: |
|||
|
|||
``make venv`` |
|||
|
|||
then install the test-dependencies: |
|||
|
|||
``make install-test`` |
|||
|
|||
And finally run the test-suite: |
|||
|
|||
``make test`` |
|||
|
|||
|
|||
Module Development |
|||
------------------ |
|||
To develop on the module itself, first of all create and activate a venv: |
|||
|
|||
``make venv`` |
|||
|
|||
Then, in the venv install the module in development mode. |
|||
|
|||
``make develop`` |
|||
|
|||
While developing there are two levels of changes. Changes to the python part of the module (pEp), and |
|||
changes to the C/C++ part of the module (_pEp). If you change just python code, the changes are effective immediately. |
|||
If you do changes to the C/C++ part you need to issue ``make develop`` again, to recompile the extension and install |
|||
the new binary (.so/.dylib) of the module into the venv. |
|||
|
|||
Documentation |
|||
------------- |
|||
The documentation of the pEpPythonAdapter uses `Sphinx <https://www.sphinx-doc.org/>`_ |
|||
Refer to the `Sphinx installation instructions <https://www.sphinx-doc.org/en/master/usage/installation.html>`_ to install it. |
|||
|
|||
To generate the documentation in the HTML format, there is a make target "docs" |
|||
But first, you need to create/activate the venv or set the LD_LIBRARY_PATH manually. |
|||
|
|||
``make venv`` |
|||
|
|||
``make docs`` |
|||
|
|||
You can see the generated HTML documentation in a browser opening the directory |
|||
`docs/build/html`. |
|||
|
|||
Housekeeping |
|||
------------ |
|||
There are the following "clean" targets. |
|||
|
|||
To delete all the generated documentation, run: |
|||
|
|||
``make docs-clean`` |
|||
|
|||
To delete all the "derived" files including eggs, wheels, shared libs, build files and caches, run: |
|||
|
|||
``make clean`` |
|||
|
|||
To delete all of make clean plus the venv (should equal a complete reset), run: |
|||
``make clean-all`` |
|||
|
|||
|
|||
|
|||
Docker |
|||
------ |
|||
If you know how to use docker, you can avoid having to install all |
|||
the dependencies using the image |
|||
https://registry.gitlab.com/juga0/pepdocker/peppythonadapter. |
|||
|
|||
.. Note:: This docker image is not officially maintained and it exists only |
|||
until there is an official Debian one. |
@ -1,7 +0,0 @@ |
|||
Software using pEpPythonAdapter |
|||
=============================== |
|||
|
|||
- `pEpProxy <https://pep-security.lu/gitlab/marcel/pepproxy>`_ |
|||
- `command-line-tool <https://pep-security.lu/gitlab/enterprise-editon/command-line-tool>`_ |
|||
- `pEpPythonMixnet <https://gitea.pep.foundation/pEp.foundation/pEpPythonMixnet>`_ |
|||
- `pEpSimulator <URL???>`_ |
@ -1,131 +0,0 @@ |
|||
#/!usr/bin/env python3 |
|||
# |
|||
# Copyleft 2020, p≡p Security |
|||
# Copyleft 2020, Hartmut Goebel <h.goebel@crazy-compilers.com> |
|||
# |
|||
# This file is under GNU General Public License 3.0 |
|||
""" |
|||
This examples shows how to transport pEp messages within a |
|||
simple XML based message format which is capable for attachments. |
|||
|
|||
pEp message elements loosely follow the "pEp for XML specification" and |
|||
https://pEp.software/ns/pEp-1.0.xsd. |
|||
|
|||
IMPORTANT: In this example, no error checking is done. Neither is |
|||
the "pEp for XML" specification enforced. |
|||
|
|||
Structure of the simple XML based message: |
|||
<msg> |
|||
<from>from-addr</from> |
|||
<to>to-addr</to> |
|||
<body>text of the messgage (must not be XML)</bod> |
|||
<attachments> |
|||
<attachment>textual data</attachment> |
|||
… |
|||
<attachments> |
|||
</msg> |
|||
""" |
|||
|
|||
from lxml import etree |
|||
import email.utils |
|||
import pEp |
|||
|
|||
__all__ = ["serialize_pEp_message", "parse_serialized_message"] |
|||
|
|||
CT2TAG = { |
|||
'application/pgp-keys': 'keydata', |
|||
'application/pEp.sync': 'sync', |
|||
'application/pEp.distribution': 'distribution', |
|||
'application/pgp-signature': 'signature', |
|||
} |
|||
|
|||
TAG2CT = dict((v,k)for (k,v) in CT2TAG.items()) |
|||
|
|||
PEP_NAMESPACE = "https://pEp.software/ns/pEp-1.0.xsd" |
|||
PEP_NS = '{%s}' % PEP_NAMESPACE |
|||
NSMAP = {'pEp': PEP_NAMESPACE} |
|||
|
|||
INCOMING = 0 |
|||
OUTGOING = 1 |
|||
|
|||
UNENCRYPTED = 0 |
|||
|
|||
def serialize_pEp_message(msg): |
|||
root = etree.Element("msg", nsmap=NSMAP) |
|||
etree.SubElement(root, "to").text = str(msg.to[0]) |
|||
etree.SubElement(root, "from").text = str(msg.from_) |
|||
|
|||
if msg.enc_format == UNENCRYPTED: |
|||
# unencrypted |
|||
etree.SubElement(root, "body").text = msg.longmsg |
|||
attachments = etree.SubElement(root, "attachments") |
|||
# FIXME: Namespace |
|||
attachments = etree.SubElement(attachments, |
|||
PEP_NS + "attachments", |
|||
version=msg.opt_fields['X-pEp-Version']) |
|||
# TODO: opt_fields, esp. auto-consume |
|||
# TODO: Order pEp attachments by type |
|||
for attach in msg.attachments: |
|||
# no need to base64-encode, attachement are ascii-armoured |
|||
# already |
|||
#attachment = base64_encode(attachment) |
|||
# FIXME: Namespace |
|||
a = etree.SubElement(attachments, |
|||
PEP_NS + CT2TAG[attach.mime_type]) |
|||
a.text = attach.decode("ascii") |
|||
else: # encrypted |
|||
# forget about longmsg and original body |
|||
# encrypted message is an attachment and there might be |
|||
# further attachments, e.g. new keys |
|||
# build a new message out of these attachments |
|||
etree.SubElement(root, "body") # emptry body |
|||
attachments = etree.SubElement(root, "attachments") |
|||
assert len(msg.attachments) == 2 |
|||
# first attachment is "Version: 1" |
|||
attach = msg.attachments[1] |
|||
# no need to base64-encode, attachements are ascii-armoured |
|||
# already |
|||
n = etree.SubElement(root, PEP_NS + "message") |
|||
n.text = attach.decode("ascii") |
|||
return etree.tostring(root) |
|||
|
|||
|
|||
def parse_serialized_message(transport_message): |
|||
|
|||
def addr2identity(text): |
|||
name, addr = email.utils.parseaddr(text) |
|||
ident = pEp.Identity(addr, name) |
|||
ident.update() |
|||
return ident |
|||
|
|||
# parse the XML text, fetch from and to |
|||
root = etree.fromstring(transport_message) |
|||
from_ = addr2identity(root.xpath("./from/text()")[0]) |
|||
msg1 = pEp.Message(INCOMING, from_) |
|||
msg1.to.append(addr2identity(root.xpath("./to/text()")[0])) |
|||
enc_msg = root.find("{%s}message" % PEP_NAMESPACE) |
|||
if enc_msg is not None: |
|||
# this is an encrypted message, ignore all but the encrypted message |
|||
msg1.attachments = [ |
|||
# As of Engine r4652 the encrypted message must be the second |
|||
# attachment |
|||
pEp.Blob(b"Version: 1", "application/pgp-encrypted"), |
|||
pEp.Blob(enc_msg.text.encode(), "application/xxpgp-encrypted")] |
|||
else: |
|||
# this is an unencrypted message, might contain pEp attachments |
|||
msg1.longmsg = root.findtext("body") |
|||
pEp_attachments = None |
|||
attachments = root.find("attachments") |
|||
if attachments is not None: |
|||
pEp_attachments = attachments.find("{%s}attachments" % PEP_NAMESPACE) |
|||
if pEp_attachments is not None: |
|||
msg1.opt_fields['X-pEp-Version'] = pEp_attachments.attrib["version"] |
|||
pEp_attachs = [] |
|||
for tagname in ("keydata", "signature", "sync", "distribution"): |
|||
for attach in pEp_attachments.iterfind( |
|||
"{%s}%s" % (PEP_NAMESPACE, tagname)): |
|||
pEp_attachs.append( |
|||
pEp.Blob(attach.text.encode(), TAG2CT[tagname])) |
|||
msg1.attachments = pEp_attachs |
|||
msg2, keys, rating, flags = msg1.decrypt() |
|||
return msg2, rating |
@ -1,661 +0,0 @@ |
|||
GNU AFFERO GENERAL PUBLIC LICENSE |
|||
Version 3, 19 November 2007 |
|||
|
|||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
|||
Everyone is permitted to copy and distribute verbatim copies |
|||
of this license document, but changing it is not allowed. |
|||
|
|||
Preamble |
|||
|
|||
The GNU Affero General Public License is a free, copyleft license for |
|||
software and other kinds of works, specifically designed to ensure |
|||
cooperation with the community in the case of network server software. |
|||
|
|||
The licenses for most software and other practical works are designed |
|||
to take away your freedom to share and change the works. By contrast, |
|||
our General Public Licenses are intended to guarantee your freedom to |
|||
share and change all versions of a program--to make sure it remains free |
|||
software for all its users. |
|||
|
|||
When we speak of free software, we are referring to freedom, not |
|||
price. Our General Public Licenses are designed to make sure that you |
|||
have the freedom to distribute copies of free software (and charge for |
|||
them if you wish), that you receive source code or can get it if you |
|||
want it, that you can change the software or use pieces of it in new |
|||
free programs, and that you know you can do these things. |
|||
|
|||
Developers that use our General Public Licenses protect your rights |
|||
with two steps: (1) assert copyright on the software, and (2) offer |
|||
you this License which gives you legal permission to copy, distribute |
|||
and/or modify the software. |
|||
|
|||
A secondary benefit of defending all users' freedom is that |
|||
improvements made in alternate versions of the program, if they |
|||
receive widespread use, become available for other developers to |
|||
incorporate. Many developers of free software are heartened and |
|||
encouraged by the resulting cooperation. However, in the case of |
|||
software used on network servers, this result may fail to come about. |
|||
The GNU General Public License permits making a modified version and |
|||
letting the public access it on a server without ever releasing its |
|||
source code to the public. |
|||
|
|||
The GNU Affero General Public License is designed specifically to |
|||
ensure that, in such cases, the modified source code becomes available |
|||
to the community. It requires the operator of a network server to |
|||
provide the source code of the modified version running there to the |
|||
users of that server. Therefore, public use of a modified version, on |
|||
a publicly accessible server, gives the public access to the source |
|||
code of the modified version. |
|||
|
|||
An older license, called the Affero General Public License and |
|||
published by Affero, was designed to accomplish similar goals. This is |
|||
a different license, not a version of the Affero GPL, but Affero has |
|||
released a new version of the Affero GPL which permits relicensing under |
|||
this license. |
|||
|
|||
The precise terms and conditions for copying, distribution and |
|||
modification follow. |
|||
|
|||
TERMS AND CONDITIONS |
|||
|
|||
0. Definitions. |
|||
|
|||
"This License" refers to version 3 of the GNU Affero General Public License. |
|||
|
|||
"Copyright" also means copyright-like laws that apply to other kinds of |
|||
works, such as semiconductor masks. |
|||
|
|||
"The Program" refers to any copyrightable work licensed under this |
|||
License. Each licensee is addressed as "you". "Licensees" and |
|||
"recipients" may be individuals or organizations. |
|||
|
|||
To "modify" a work means to copy from or adapt all or part of the work |
|||
in a fashion requiring copyright permission, other than the making of an |
|||
exact copy. The resulting work is called a "modified version" of the |
|||
earlier work or a work "based on" the earlier work. |
|||
|
|||
A "covered work" means either the unmodified Program or a work based |
|||
on the Program. |
|||
|
|||
To "propagate" a work means to do anything with it that, without |
|||
permission, would make you directly or secondarily liable for |
|||
infringement under applicable copyright law, except executing it on a |
|||
computer or modifying a private copy. Propagation includes copying, |
|||
distribution (with or without modification), making available to the |
|||
public, and in some countries other activities as well. |
|||
|
|||
To "convey" a work means any kind of propagation that enables other |
|||
parties to make or receive copies. Mere interaction with a user through |
|||
a computer network, with no transfer of a copy, is not conveying. |
|||
|
|||
An interactive user interface displays "Appropriate Legal Notices" |
|||
to the extent that it includes a convenient and prominently visible |
|||
feature that (1) displays an appropriate copyright notice, and (2) |
|||
tells the user that there is no warranty for the work (except to the |
|||
extent that warranties are provided), that licensees may convey the |
|||
work under this License, and how to view a copy of this License. If |
|||
the interface presents a list of user commands or options, such as a |
|||
menu, a prominent item in the list meets this criterion. |
|||
|
|||
1. Source Code. |
|||
|
|||
The "source code" for a work means the preferred form of the work |
|||
for making modifications to it. "Object code" means any non-source |
|||
form of a work. |
|||
|
|||
A "Standard Interface" means an interface that either is an official |
|||
standard defined by a recognized standards body, or, in the case of |
|||
interfaces specified for a particular programming language, one that |
|||
is widely used among developers working in that language. |
|||
|
|||
The "System Libraries" of an executable work include anything, other |
|||
than the work as a whole, that (a) is included in the normal form of |
|||
packaging a Major Component, but which is not part of that Major |
|||
Component, and (b) serves only to enable use of the work with that |
|||
Major Component, or to implement a Standard Interface for which an |
|||
implementation is available to the public in source code form. A |
|||
"Major Component", in this context, means a major essential component |
|||
(kernel, window system, and so on) of the specific operating system |
|||
(if any) on which the executable work runs, or a compiler used to |
|||
produce the work, or an object code interpreter used to run it. |
|||
|
|||
The "Corresponding Source" for a work in object code form means all |
|||
the source code needed to generate, install, and (for an executable |
|||
work) run the object code and to modify the work, including scripts to |
|||
control those activities. However, it does not include the work's |
|||
System Libraries, or general-purpose tools or generally available free |
|||
programs which are used unmodified in performing those activities but |
|||
which are not part of the work. For example, Corresponding Source |
|||
includes interface definition files associated with source files for |
|||
the work, and the source code for shared libraries and dynamically |
|||
linked subprograms that the work is specifically designed to require, |
|||
such as by intimate data communication or control flow between those |
|||
subprograms and other parts of the work. |
|||
|
|||
The Corresponding Source need not include anything that users |
|||
can regenerate automatically from other parts of the Corresponding |
|||
Source. |
|||
|
|||
The Corresponding Source for a work in source code form is that |
|||
same work. |
|||
|
|||
2. Basic Permissions. |
|||
|
|||
All rights granted under this License are granted for the term of |
|||
copyright on the Program, and are irrevocable provided the stated |
|||
conditions are met. This License explicitly affirms your unlimited |
|||
permission to run the unmodified Program. The output from running a |
|||
covered work is covered by this License only if the output, given its |
|||
content, constitutes a covered work. This License acknowledges your |
|||
rights of fair use or other equivalent, as provided by copyright law. |
|||
|
|||
You may make, run and propagate covered works that you do not |
|||
convey, without conditions so long as your license otherwise remains |
|||
in force. You may convey covered works to others for the sole purpose |
|||
of having them make modifications exclusively for you, or provide you |
|||
with facilities for running those works, provided that you comply with |
|||
the terms of this License in conveying all material for which you do |
|||
not control copyright. Those thus making or running the covered works |
|||
for you must do so exclusively on your behalf, under your direction |
|||
and control, on terms that prohibit them from making any copies of |
|||
your copyrighted material outside their relationship with you. |
|||
|
|||
Conveying under any other circumstances is permitted solely under |
|||
the conditions stated below. Sublicensing is not allowed; section 10 |
|||
makes it unnecessary. |
|||
|
|||
3. Protecting Users' Legal Rights From Anti-Circumvention Law. |
|||
|
|||
No covered work shall be deemed part of an effective technological |
|||
measure under any applicable law fulfilling obligations under article |
|||
11 of the WIPO copyright treaty adopted on 20 December 1996, or |
|||
similar laws prohibiting or restricting circumvention of such |
|||
measures. |
|||
|
|||
When you convey a covered work, you waive any legal power to forbid |
|||
circumvention of technological measures to the extent such circumvention |
|||
is effected by exercising rights under this License with respect to |
|||
the covered work, and you disclaim any intention to limit operation or |
|||
modification of the work as a means of enforcing, against the work's |
|||
users, your or third parties' legal rights to forbid circumvention of |
|||
technological measures. |
|||
|
|||
4. Conveying Verbatim Copies. |
|||
|
|||
You may convey verbatim copies of the Program's source code as you |
|||
receive it, in any medium, provided that you conspicuously and |
|||
appropriately publish on each copy an appropriate copyright notice; |
|||
keep intact all notices stating that this License and any |
|||
non-permissive terms added in accord with section 7 apply to the code; |
|||
keep intact all notices of the absence of any warranty; and give all |
|||
recipients a copy of this License along with the Program. |
|||
|
|||
You may charge any price or no price for each copy that you convey, |
|||
and you may offer support or warranty protection for a fee. |
|||
|
|||
5. Conveying Modified Source Versions. |
|||
|
|||
You may convey a work based on the Program, or the modifications to |
|||
produce it from the Program, in the form of source code under the |
|||
terms of section 4, provided that you also meet all of these conditions: |
|||
|
|||
a) The work must carry prominent notices stating that you modified |
|||
it, and giving a relevant date. |
|||
|
|||
b) The work must carry prominent notices stating that it is |
|||
released under this License and any conditions added under section |
|||
7. This requirement modifies the requirement in section 4 to |
|||
"keep intact all notices". |
|||
|
|||
c) You must license the entire work, as a whole, under this |
|||
License to anyone who comes into possession of a copy. This |
|||
License will therefore apply, along with any applicable section 7 |
|||
additional terms, to the whole of the work, and all its parts, |
|||
regardless of how they are packaged. This License gives no |
|||
permission to license the work in any other way, but it does not |
|||
invalidate such permission if you have separately received it. |
|||
|
|||
d) If the work has interactive user interfaces, each must display |
|||
Appropriate Legal Notices; however, if the Program has interactive |
|||
interfaces that do not display Appropriate Legal Notices, your |
|||
work need not make them do so. |
|||
|
|||
A compilation of a covered work with other separate and independent |
|||
works, which are not by their nature extensions of the covered work, |
|||
and which are not combined with it such as to form a larger program, |
|||
in or on a volume of a storage or distribution medium, is called an |
|||
"aggregate" if the compilation and its resulting copyright are not |
|||
used to limit the access or legal rights of the compilation's users |
|||
beyond what the individual works permit. Inclusion of a covered work |
|||
in an aggregate does not cause this License to apply to the other |
|||
parts of the aggregate. |
|||
|
|||
6. Conveying Non-Source Forms. |
|||
|
|||
You may convey a covered work in object code form under the terms |
|||
of sections 4 and 5, provided that you also convey the |
|||
machine-readable Corresponding Source under the terms of this License, |
|||
in one of these ways: |
|||
|
|||
a) Convey the object code in, or embodied in, a physical product |
|||
(including a physical distribution medium), accompanied by the |
|||
Corresponding Source fixed on a durable physical medium |
|||
customarily used for software interchange. |
|||
|
|||
b) Convey the object code in, or embodied in, a physical product |
|||
(including a physical distribution medium), accompanied by a |
|||
written offer, valid for at least three years and valid for as |
|||
long as you offer spare parts or customer support for that product |
|||
model, to give anyone who possesses the object code either (1) a |
|||
copy of the Corresponding Source for all the software in the |
|||
product that is covered by this License, on a durable physical |
|||
medium customarily used for software interchange, for a price no |
|||
more than your reasonable cost of physically performing this |
|||
conveying of source, or (2) access to copy the |
|||
Corresponding Source from a network server at no charge. |
|||
|
|||
c) Convey individual copies of the object code with a copy of the |
|||
written offer to provide the Corresponding Source. This |
|||
alternative is allowed only occasionally and noncommercially, and |
|||
only if you received the object code with such an offer, in accord |
|||
with subsection 6b. |
|||
|
|||
d) Convey the object code by offering access from a designated |
|||
place (gratis or for a charge), and offer equivalent access to the |
|||
Corresponding Source in the same way through the same place at no |
|||
further charge. You need not require recipients to copy the |
|||
Corresponding Source along with the object code. If the place to |
|||
copy the object code is a network server, the Corresponding Source |
|||
may be on a different server (operated by you or a third party) |
|||
that supports equivalent copying facilities, provided you maintain |
|||
clear directions next to the object code saying where to find the |
|||
Corresponding Source. Regardless of what server hosts the |
|||
Corresponding Source, you remain obligated to ensure that it is |
|||
available for as long as needed to satisfy these requirements. |
|||
|
|||
e) Convey the object code using peer-to-peer transmission, provided |
|||
you inform other peers where the object code and Corresponding |
|||
Source of the work are being offered to the general public at no |
|||
charge under subsection 6d. |
|||
|
|||
A separable portion of the object code, whose source code is excluded |
|||
from the Corresponding Source as a System Library, need not be |
|||
included in conveying the object code work. |
|||
|
|||
A "User Product" is either (1) a "consumer product", which means any |
|||
tangible personal property which is normally used for personal, family, |
|||
or household purposes, or (2) anything designed or sold for incorporation |
|||
into a dwelling. In determining whether a product is a consumer product, |
|||
doubtful cases shall be resolved in favor of coverage. For a particular |
|||
product received by a particular user, "normally used" refers to a |
|||
typical or common use of that class of product, regardless of the status |
|||
of the particular user or of the way in which the particular user |
|||
actually uses, or expects or is expected to use, the product. A product |
|||
is a consumer product regardless of whether the product has substantial |
|||
commercial, industrial or non-consumer uses, unless such uses represent |
|||
the only significant mode of use of the product. |
|||
|
|||
"Installation Information" for a User Product means any methods, |
|||
procedures, authorization keys, or other information required to install |
|||
and execute modified versions of a covered work in that User Product from |
|||
a modified version of its Corresponding Source. The information must |
|||
suffice to ensure that the continued functioning of the modified object |
|||
code is in no case prevented or interfered with solely because |
|||
modification has been made. |
|||
|
|||
If you convey an object code work under this section in, or with, or |
|||
specifically for use in, a User Product, and the conveying occurs as |
|||
part of a transaction in which the right of possession and use of the |
|||
User Product is transferred to the recipient in perpetuity or for a |
|||
fixed term (regardless of how the transaction is characterized), the |
|||
Corresponding Source conveyed under this section must be accompanied |
|||
by the Installation Information. But this requirement does not apply |
|||
if neither you nor any third party retains the ability to install |
|||
modified object code on the User Product (for example, the work has |
|||
been installed in ROM). |
|||
|
|||
The requirement to provide Installation Information does not include a |
|||
requirement to continue to provide support service, warranty, or updates |
|||
for a work that has been modified or installed by the recipient, or for |
|||
the User Product in which it has been modified or installed. Access to a |
|||
network may be denied when the modification itself materially and |
|||
adversely affects the operation of the network or violates the rules and |
|||
protocols for communication across the network. |
|||
|
|||
Corresponding Source conveyed, and Installation Information provided, |
|||
in accord with this section must be in a format that is publicly |
|||
documented (and with an implementation available to the public in |
|||
source code form), and must require no special password or key for |
|||
unpacking, reading or copying. |
|||
|
|||
7. Additional Terms. |
|||
|
|||
"Additional permissions" are terms that supplement the terms of this |
|||
License by making exceptions from one or more of its conditions. |
|||
Additional permissions that are applicable to the entire Program shall |
|||
be treated as though they were included in this License, to the extent |
|||
that they are valid under applicable law. If additional permissions |
|||
apply only to part of the Program, that part may be used separately |
|||
under those permissions, but the entire Program remains governed by |
|||
this License without regard to the additional permissions. |
|||
|
|||
When you convey a copy of a covered work, you may at your option |
|||
remove any additional permissions from that copy, or from any part of |
|||
it. (Additional permissions may be written to require their own |
|||
removal in certain cases when you modify the work.) You may place |
|||
additional permissions on material, added by you to a covered work, |
|||
for which you have or can give appropriate copyright permission. |
|||
|
|||
Notwithstanding any other provision of this License, for material you |
|||
add to a covered work, you may (if authorized by the copyright holders of |
|||
that material) supplement the terms of this License with terms: |
|||
|
|||
a) Disclaiming warranty or limiting liability differently from the |
|||
terms of sections 15 and 16 of this License; or |
|||
|
|||
b) Requiring preservation of specified reasonable legal notices or |
|||
author attributions in that material or in the Appropriate Legal |
|||
Notices displayed by works containing it; or |
|||
|
|||
c) Prohibiting misrepresentation of the origin of that material, or |
|||
requiring that modified versions of such material be marked in |
|||
reasonable ways as different from the original version; or |
|||
|
|||
d) Limiting the use for publicity purposes of names of licensors or |
|||
authors of the material; or |
|||
|
|||
e) Declining to grant rights under trademark law for use of some |
|||
trade names, trademarks, or service marks; or |
|||
|
|||
f) Requiring indemnification of licensors and authors of that |
|||
material by anyone who conveys the material (or modified versions of |
|||
it) with contractual assumptions of liability to the recipient, for |
|||
any liability that these contractual assumptions directly impose on |
|||
those licensors and authors. |
|||
|
|||
All other non-permissive additional terms are considered "further |
|||
restrictions" within the meaning of section 10. If the Program as you |
|||
received it, or any part of it, contains a notice stating that it is |
|||
governed by this License along with a term that is a further |
|||
restriction, you may remove that term. If a license document contains |
|||
a further restriction but permits relicensing or conveying under this |
|||
License, you may add to a covered work material governed by the terms |
|||
of that license document, provided that the further restriction does |
|||
not survive such relicensing or conveying. |
|||
|
|||
If you add terms to a covered work in accord with this section, you |
|||
must place, in the relevant source files, a statement of the |
|||
additional terms that apply to those files, or a notice indicating |
|||
where to find the applicable terms. |
|||
|
|||
Additional terms, permissive or non-permissive, may be stated in the |
|||
form of a separately written license, or stated as exceptions; |
|||
the above requirements apply either way. |
|||
|
|||
8. Termination. |
|||
|
|||
You may not propagate or modify a covered work except as expressly |
|||
provided under this License. Any attempt otherwise to propagate or |
|||
modify it is void, and will automatically terminate your rights under |
|||
this License (including any patent licenses granted under the third |
|||
paragraph of section 11). |
|||
|
|||
However, if you cease all violation of this License, then your |
|||
license from a particular copyright holder is reinstated (a) |
|||
provisionally, unless and until the copyright holder explicitly and |
|||
finally terminates your license, and (b) permanently, if the copyright |
|||
holder fails to notify you of the violation by some reasonable means |
|||
prior to 60 days after the cessation. |
|||
|
|||
Moreover, your license from a particular copyright holder is |
|||
reinstated permanently if the copyright holder notifies you of the |
|||
violation by some reasonable means, this is the first time you have |
|||
received notice of violation of this License (for any work) from that |
|||
copyright holder, and you cure the violation prior to 30 days after |
|||
your receipt of the notice. |
|||
|
|||
Termination of your rights under this section does not terminate the |
|||
licenses of parties who have received copies or rights from you under |
|||
this License. If your rights have been terminated and not permanently |
|||
reinstated, you do not qualify to receive new licenses for the same |
|||
material under section 10. |
|||
|
|||
9. Acceptance Not Required for Having Copies. |
|||
|
|||
You are not required to accept this License in order to receive or |
|||
run a copy of the Program. Ancillary propagation of a covered work |
|||
occurring solely as a consequence of using peer-to-peer transmission |
|||
to receive a copy likewise does not require acceptance. However, |
|||
nothing other than this License grants you permission to propagate or |
|||
modify any covered work. These actions infringe copyright if you do |
|||
not accept this License. Therefore, by modifying or propagating a |
|||
covered work, you indicate your acceptance of this License to do so. |
|||
|
|||
10. Automatic Licensing of Downstream Recipients. |
|||
|
|||
Each time you convey a covered work, the recipient automatically |
|||
receives a license from the original licensors, to run, modify and |
|||
propagate that work, subject to this License. You are not responsible |
|||
for enforcing compliance by third parties with this License. |
|||
|
|||
An "entity transaction" is a transaction transferring control of an |
|||
organization, or substantially all assets of one, or subdividing an |
|||
organization, or merging organizations. If propagation of a covered |
|||
work results from an entity transaction, each party to that |
|||
transaction who receives a copy of the work also receives whatever |
|||
licenses to the work the party's predecessor in interest had or could |
|||
give under the previous paragraph, plus a right to possession of the |
|||
Corresponding Source of the work from the predecessor in interest, if |
|||
the predecessor has it or can get it with reasonable efforts. |
|||
|
|||
You may not impose any further restrictions on the exercise of the |
|||
rights granted or affirmed under this License. For example, you may |
|||
not impose a license fee, royalty, or other charge for exercise of |
|||
rights granted under this License, and you may not initiate litigation |
|||
(including a cross-claim or counterclaim in a lawsuit) alleging that |
|||
any patent claim is infringed by making, using, selling, offering for |
|||
sale, or importing the Program or any portion of it. |
|||
|
|||
11. Patents. |
|||
|
|||
A "contributor" is a copyright holder who authorizes use under this |
|||
License of the Program or a work on which the Program is based. The |
|||
work thus licensed is called the contributor's "contributor version". |
|||
|
|||
A contributor's "essential patent claims" are all patent claims |
|||
owned or controlled by the contributor, whether already acquired or |
|||
hereafter acquired, that would be infringed by some manner, permitted |
|||
by this License, of making, using, or selling its contributor version, |
|||
but do not include claims that would be infringed only as a |
|||
consequence of further modification of the contributor version. For |
|||
purposes of this definition, "control" includes the right to grant |
|||
patent sublicenses in a manner consistent with the requirements of |
|||
this License. |
|||
|
|||
Each contributor grants you a non-exclusive, worldwide, royalty-free |
|||
patent license under the contributor's essential patent claims, to |
|||
make, use, sell, offer for sale, import and otherwise run, modify and |
|||
propagate the contents of its contributor version. |
|||
|
|||
In the following three paragraphs, a "patent license" is any express |
|||
agreement or commitment, however denominated, not to enforce a patent |
|||
(such as an express permission to practice a patent or covenant not to |
|||
sue for patent infringement). To "grant" such a patent license to a |
|||
party means to make such an agreement or commitment not to enforce a |
|||
patent against the party. |
|||
|
|||
If you convey a covered work, knowingly relying on a patent license, |
|||
and the Corresponding Source of the work is not available for anyone |
|||
to copy, free of charge and under the terms of this License, through a |
|||
publicly available network server or other readily accessible means, |
|||
then you must either (1) cause the Corresponding Source to be so |
|||
available, or (2) arrange to deprive yourself of the benefit of the |
|||
patent license for this particular work, or (3) arrange, in a manner |
|||
consistent with the requirements of this License, to extend the patent |
|||
license to downstream recipients. "Knowingly relying" means you have |
|||
actual knowledge that, but for the patent license, your conveying the |
|||
covered work in a country, or your recipient's use of the covered work |
|||
in a country, would infringe one or more identifiable patents in that |
|||
country that you have reason to believe are valid. |
|||
|
|||
If, pursuant to or in connection with a single transaction or |
|||
arrangement, you convey, or propagate by procuring conveyance of, a |
|||
covered work, and grant a patent license to some of the parties |
|||
receiving the covered work authorizing them to use, propagate, modify |
|||
or convey a specific copy of the covered work, then the patent license |
|||
you grant is automatically extended to all recipients of the covered |
|||
work and works based on it. |
|||
|
|||
A patent license is "discriminatory" if it does not include within |
|||
the scope of its coverage, prohibits the exercise of, or is |
|||
conditioned on the non-exercise of one or more of the rights that are |
|||
specifically granted under this License. You may not convey a covered |
|||
work if you are a party to an arrangement with a third party that is |
|||
in the business of distributing software, under which you make payment |
|||
to the third party based on the extent of your activity of conveying |
|||
the work, and under which the third party grants, to any of the |
|||
parties who would receive the covered work from you, a discriminatory |
|||
patent license (a) in connection with copies of the covered work |
|||
conveyed by you (or copies made from those copies), or (b) primarily |
|||
for and in connection with specific products or compilations that |
|||
contain the covered work, unless you entered into that arrangement, |
|||
or that patent license was granted, prior to 28 March 2007. |
|||
|
|||
Nothing in this License shall be construed as excluding or limiting |
|||
any implied license or other defenses to infringement that may |
|||
otherwise be available to you under applicable patent law. |
|||
|
|||
12. No Surrender of Others' Freedom. |
|||
|
|||
If conditions are imposed on you (whether by court order, agreement or |
|||
otherwise) that contradict the conditions of this License, they do not |
|||
excuse you from the conditions of this License. If you cannot convey a |
|||
covered work so as to satisfy simultaneously your obligations under this |
|||
License and any other pertinent obligations, then as a consequence you may |
|||
not convey it at all. For example, if you agree to terms that obligate you |
|||
to collect a royalty for further conveying from those to whom you convey |
|||
the Program, the only way you could satisfy both those terms and this |
|||
License would be to refrain entirely from conveying the Program. |
|||
|
|||
13. Remote Network Interaction; Use with the GNU General Public License. |
|||
|
|||
Notwithstanding any other provision of this License, if you modify the |
|||
Program, your modified version must prominently offer all users |
|||
interacting with it remotely through a computer network (if your version |
|||
supports such interaction) an opportunity to receive the Corresponding |
|||
Source of your version by providing access to the Corresponding Source |
|||
from a network server at no charge, through some standard or customary |
|||
means of facilitating copying of software. This Corresponding Source |
|||
shall include the Corresponding Source for any work covered by version 3 |
|||
of the GNU General Public License that is incorporated pursuant to the |
|||
following paragraph. |
|||
|
|||
Notwithstanding any other provision of this License, you have |
|||
permission to link or combine any covered work with a work licensed |
|||
under version 3 of the GNU General Public License into a single |
|||
combined work, and to convey the resulting work. The terms of this |
|||
License will continue to apply to the part which is the covered work, |
|||
but the work with which it is combined will remain governed by version |
|||
3 of the GNU General Public License. |
|||
|
|||
14. Revised Versions of this License. |
|||
|
|||
The Free Software Foundation may publish revised and/or new versions of |
|||
the GNU Affero General Public License from time to time. Such new versions |
|||
will be similar in spirit to the present version, but may differ in detail to |
|||
address new problems or concerns. |
|||
|
|||
Each version is given a distinguishing version number. If the |
|||
Program specifies that a certain numbered version of the GNU Affero General |
|||
Public License "or any later version" applies to it, you have the |
|||
option of following the terms and conditions either of that numbered |
|||
version or of any later version published by the Free Software |
|||
Foundation. If the Program does not specify a version number of the |
|||
GNU Affero General Public License, you may choose any version ever published |
|||
by the Free Software Foundation. |
|||
|
|||
If the Program specifies that a proxy can decide which future |
|||
versions of the GNU Affero General Public License can be used, that proxy's |
|||
public statement of acceptance of a version permanently authorizes you |
|||
to choose that version for the Program. |
|||
|
|||
Later license versions may give you additional or different |
|||
permissions. However, no additional obligations are imposed on any |
|||
author or copyright holder as a result of your choosing to follow a |
|||
later version. |
|||
|
|||
15. Disclaimer of Warranty. |
|||
|
|||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY |
|||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT |
|||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY |
|||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, |
|||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM |
|||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF |
|||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
|||
|
|||
16. Limitation of Liability. |
|||
|
|||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
|||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS |
|||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY |
|||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE |
|||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF |
|||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD |
|||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), |
|||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |
|||
SUCH DAMAGES. |
|||
|
|||
17. Interpretation of Sections 15 and 16. |
|||
|
|||
If the disclaimer of warranty and limitation of liability provided |
|||
above cannot be given local legal effect according to their terms, |
|||
reviewing courts shall apply local law that most closely approximates |
|||
an absolute waiver of all civil liability in connection with the |
|||
Program, unless a warranty or assumption of liability accompanies a |
|||
copy of the Program in return for a fee. |
|||
|
|||
END OF TERMS AND CONDITIONS |
|||
|
|||
How to Apply These Terms to Your New Programs |
|||
|
|||
If you develop a new program, and you want it to be of the greatest |
|||
possible use to the public, the best way to achieve this is to make it |
|||
free software which everyone can redistribute and change under these terms. |
|||
|
|||
To do so, attach the following notices to the program. It is safest |
|||
to attach them to the start of each source file to most effectively |
|||
state the exclusion of warranty; and each file should have at least |
|||
the "copyright" line and a pointer to where the full notice is found. |
|||
|
|||
<one line to give the program's name and a brief idea of what it does.> |
|||
Copyright (C) <year> <name of author> |
|||
|
|||
This program is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU Affero General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU Affero General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU Affero General Public License |
|||
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
Also add information on how to contact you by electronic and paper mail. |
|||
|
|||
If your software can interact with users remotely through a computer |
|||
network, you should also make sure that it provides a way for users to |
|||
get its source. For example, if your program is a web application, its |
|||
interface could display a "Source" link that leads users to an archive |
|||
of the code. There are many ways you could offer source, and different |
|||
solutions will be better for different programs; see section 13 for the |
|||
specific requirements. |
|||
|
|||
You should also get your employer (if you work as a programmer) or school, |
|||
if any, to sign a "copyright disclaimer" for the program, if necessary. |
|||
For more information on this, and how to apply and follow the GNU AGPL, see |
|||
<http://www.gnu.org/licenses/>. |
@ -1,82 +0,0 @@ |
|||
VENV_DIR = ./venv |
|||
BUILD_DIR = ./build |
|||
DIST_DIR = ./dist |
|||
PYTHON_ARTIFACTS += ./.eggs |
|||
PYTHON_ARTIFACTS += ./pEpACIDgen.egg-info |
|||
PYTHON_ARTIFACTS += ./.pytest_cache |
|||
PYTHON_ARTIFACTS += ./pEpACIDgen/__pycache__ |
|||
PYTHON_ARTIFACTS += ./tests/__pycache__ |
|||
|
|||
|
|||
.PHONY: all build dist dist-egg dist-whl install install-user install-test venv envtest test develop examples clean clean-all |
|||
|
|||
all: dist example-libs |
|||
|
|||
# Build
|
|||
# =====
|
|||
build: |
|||
python3 setup.py build |
|||
|
|||
# Packaging
|
|||
# =========
|
|||
# create wheel and egg package in dist/
|
|||
dist: dist-whl dist-egg |
|||
|
|||
# create wheel package in dist/
|
|||
dist-whl: |
|||
python3 setup.py bdist_wheel |
|||
|
|||
# create egg package in dist/
|
|||
dist-egg: |
|||
python3 setup.py bdist_egg |
|||
|
|||
|
|||
# Installation
|
|||
# ============
|
|||
# installs the package system wide
|
|||
install: |
|||
pip3 install . |
|||
|
|||
# installs the package into your user home
|
|||
install-user: |
|||
pip3 install . --user |
|||
|
|||
|
|||
# Envrionment
|
|||
# ===========
|
|||
# Creates and activates a new venv
|
|||
# Only activates venv if already existing
|
|||
venv: |
|||
python3 -m venv $(VENV_DIR) |
|||
bash --rcfile $(VENV_DIR)/bin/activate |
|||
|
|||
# Test
|
|||
# ====
|
|||
# Use these targets only in venv created with 'make venv'
|
|||
install-test: |
|||
pip3 install .[test] |
|||
|
|||
test: |
|||
pytest |
|||
|
|||
# Development
|
|||
develop: |
|||
pip install -e . |
|||
|
|||
|
|||
# Examples
|
|||
# ========
|
|||
# Use these targets only in venv created with 'make venv'
|
|||
example-libs: |
|||
$(MAKE) -C examples/lib all |
|||
|
|||
# Housekeeping
|
|||
# ============
|
|||
clean-all: clean |
|||
rm -rf $(VENV_DIR) |
|||
|
|||
clean: |
|||
$(MAKE) -C examples/lib clean |
|||
rm -rf $(BUILD_DIR) |
|||
rm -rf $(DIST_DIR) |
|||
rm -rf $(PYTHON_ARTIFACTS) |
@ -1,2 +0,0 @@ |
|||
[build-system] |
|||
requires = ["setuptools>=30.3.0", "wheel >= 0.35.1", "pybind11 >= 2.6.1"] |
@ -1,55 +0,0 @@ |
|||
[metadata] |
|||
name = pEpACIDgen |
|||
version = 1.0 |
|||
url = |
|||
author = Heck |
|||
author_email = heck@pep.foundation |
|||
description = pEp Abstract C Interface Description Generator |
|||
long_description = file: README.rst |
|||
keywords = pyBind11, c, c99, code generator, bindings generator, extension, ffi, cffi, ctypes, cpython, yml2, libclang, |
|||
license = GNU Affero General Public License |
|||
license_files = LICENSE.txt |
|||
classifiers = |
|||
Intended Audience :: Developers |
|||
Topic :: Utilities |
|||
License :: OSI Approved :: GNU Affero General Public License v3 (AGPLv3) |
|||
Natural Language :: English |
|||
Operating System :: OS Independent |
|||
Programming Language :: Python :: 3.6 |
|||
Programming Language :: Python :: 3.7 |
|||
Programming Language :: Python :: 3.8 |
|||
Development Status :: 3 - Alpha |
|||
|
|||
|
|||
[options] |
|||
include_package_data=true |
|||
packages = find: |
|||
python_requires = >= 3.6 |
|||
zip_safe = true |
|||
test_suite = tests |
|||
# deprecated/redundant with pyproject.toml, but lets keep both ways around for now |
|||
setup_requires = |
|||
setuptools >= 39.2.0 |
|||
wheel >= 0.35.1 |
|||
pybind11 >= 2.6.1 |
|||
|
|||
install_requires = |
|||
clang |
|||
yml2 |
|||
pybind11 >= 2.6.1 |
|||
|
|||
[options.entry_points] |
|||
console_scripts = |
|||
pEp_acid_gen = pEpACIDgen.__main__:gen |
|||
pEp_acid_gen-config = pEpACIDgen.__main__:get_gen_backend_pyBind11 |
|||
|
|||
[options.extras_require] |
|||
test = pytest |
|||
|
|||
[options.packages.find] |
|||
exclude = |
|||
tests* |
|||
|
|||
[tool:pytest] |
|||
testpaths = tests |
|||
addopts = -sx |
@ -1,6 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# This file is under GNU Affero General Public License 3.0 |
|||
# see LICENSE.txt |
|||
|
|||
from setuptools import setup |
|||
setup() |
@ -1,3 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# This file is under GNU Affero General Public License 3.0 |
|||
# see LICENSE.txt |
@ -1,11 +0,0 @@ |
|||
# This is an Example build config file (local.conf) |
|||
# you might not need this file, but if the defaults dont work for you |
|||
# You can override them here. |
|||
# Tweak the values to your needs and rename it to local.conf |
|||
|
|||
######### C++ Compiler ######### |
|||
# DEBUG=1 |
|||
# DEBUG=0 |
|||
|
|||
############# DIRS ############# |
|||
# PREFIX=$(HOME)/local |
@ -1,18 +1,2 @@ |
|||
|
|||
[build-system] |
|||
# Preparing for PEP-517/PEP-518, but not in effect yet. |
|||
# These requires are not effective yet, setup.cfg is. |
|||
requires =[ |
|||
"setuptools >=39.2.0", |
|||
"setuptools_scm >= 4.1.2", |
|||
"wheel >= 0.35.1" ] |
|||
|
|||
build-backend = "setuptools.build_meta" |
|||
|
|||
[tool.pytest.ini_options] |
|||
minversion = "6.0" |
|||
addopts = "-rP --forked" |
|||
testpaths = [ |
|||
"tests", |
|||
] |
|||
|
|||
requires = ["setuptools>=30.3.0", "wheel >= 0.35.1", "pybind11 >= 2.6.1"] |
|||
|
@ -1,238 +1,6 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# This file is under GNU Affero General Public License 3.0 |
|||
# see LICENSE.txt |
|||
# |
|||
# For more debugging, export DISTUTILS_DEBUG=True |
|||
|
|||
from __future__ import print_function |
|||
|
|||
import sys |
|||
|
|||
import os |
|||
from os import environ |
|||
from os.path import join |
|||
import platform |
|||
|
|||
from setuptools import setup, Extension |
|||
from glob import glob |
|||
|
|||
from setuptools.command.build_ext import build_ext |
|||
|
|||
|
|||
def pEpLog(*msg): |
|||
import inspect |
|||
msgstr = '' |
|||
separator = ' ' |
|||
for m in msg: |
|||
msgstr += str(m) |
|||
msgstr += separator |
|||
func = inspect.currentframe().f_back.f_code |
|||
print(func.co_filename + " : " + func.co_name + " : " + msgstr) |
|||
|
|||
|
|||
class BuildExtCommand(build_ext): |
|||
user_options = build_ext.user_options + [ |
|||
('prefix=', None, 'Use pEp-base installation in prefix (libs/includes)'), |
|||
] |
|||
|
|||
def initialize_options(self): |
|||
build_ext.initialize_options(self) |
|||
self.prefix = getattr(self, "prefix=", None) |
|||
|
|||
def windowsGetInstallLocation(self): |
|||
# Note: should be installed to 'C:\Program Files (x86)' while a 32-bit distro |
|||
# TODO: Try desktop adapter location first, then COM server |
|||
# FIXME: This is wrong, we should chase the COM server, not the Outlook Plugin (even if they're in the same place) |
|||
reg_path = "Software\\Microsoft\\Office\\Outlook\\Addins\\pEp" |
|||
KeyName = 'FileName' |
|||
regKey = None |
|||
pEpLog("Registry Lookup:", reg_path, KeyName) |
|||
try: |
|||
regKey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_path, 0, winreg.KEY_READ) |
|||
# Keys: Description, FileName, FriendlyName, LoadBehavior |
|||
com_server, regtype = winreg.QueryValueEx(regKey, KeyName) |
|||
winreg.CloseKey(regKey) |
|||
except WindowsError: |
|||
pEpLog("Unknown Error") |
|||
com_server = None |
|||
finally: |
|||
if winreg: |
|||
winreg.CloseKey(regKey) |
|||
# <install-base>\\bin\\COM_Server.exe |
|||
dirname = os.path.dirname |
|||
ret = dirname(dirname(com_server)) |
|||
pEpLog("Value:", ret) |
|||
return ret |
|||
|
|||
def get_build_info_winnt(self): |
|||
home = environ.get('PER_USER_DIRECTORY') or environ.get('USERPROFILE') |
|||
sys_root = environ.get('SystemRoot') |
|||
profile_root = environ.get('AppData') |
|||
local_root = environ.get('LocalAppData') |
|||
inst_prefix = self.windowsGetInstallLocation() |
|||
sys_includes = [ |
|||
join(inst_prefix, 'include'), |
|||
join(profile_root, 'pEp', 'include'), |
|||
join(local_root, 'pEp', 'include'), |
|||
join(sys_root, 'pEp', 'include'), |
|||
] |
|||
sys_libdirs = [ |
|||
join(inst_prefix, 'bin'), |
|||
join(profile_root, 'pEp', 'bin'), |
|||
join(local_root, 'pEp', 'bin'), |
|||
join(sys_root, 'pEp', 'bin'), |
|||
] |
|||
libs = [ |
|||
'pEpEngine', |
|||
'pEpAdapter', |
|||
'boost_python37-mt', |
|||
'boost_locale-mt' |
|||
] |
|||
return (home, sys_includes, sys_libdirs, libs) |
|||
|
|||
def get_build_info_darwin(self): |
|||
home = environ.get('PER_USER_DIRECTORY') or environ.get('HOME') |
|||
sys_includes = [ |
|||
'/opt/local/include', |
|||
] |
|||
sys_libdirs = [ |
|||
'/opt/local/lib', |
|||
] |
|||
libs = [ |
|||
'pEpEngine', |
|||
'pEpAdapter', |
|||
'boost_python38-mt', |
|||
'boost_locale-mt' |
|||
] |
|||
return (home, sys_includes, sys_libdirs, libs) |
|||
|
|||
def get_build_info_linux(self): |
|||
home = environ.get('PER_USER_DIRECTORY') or environ.get('HOME') |
|||
sys_includes = [ |
|||
'/usr/local/include', |
|||
'/usr/include', |
|||
] |
|||
sys_libdirs = [ |
|||
'/usr/local/lib', |
|||
'/usr/lib', |
|||
'/usr/lib/{}-linux-gnu'.format(platform.machine()) |
|||
] |
|||
libs = [ |
|||
'pEpEngine', |
|||
'pEpAdapter', |
|||
'boost_python3', |
|||
'boost_locale' |
|||
] |
|||
return (home, sys_includes, sys_libdirs, libs) |
|||
|
|||
def finalize_options(self): |
|||
build_ext.finalize_options(self) |
|||
|
|||
pEpLog("prefix: ", self.prefix) |
|||
pEpLog("sys.platform: ", sys.platform) |
|||
|
|||
# get build information for platform |
|||
if sys.platform == 'winnt': |
|||
build_info = self.get_build_info_winnt() |
|||
elif sys.platform == 'darwin': |
|||
build_info = self.get_build_info_darwin() |
|||
elif sys.platform == 'linux': |
|||
build_info = self.get_build_info_linux() |
|||
else: |
|||
pEpLog("Platform not supported:" + sys.platform) |
|||
exit() |
|||
|
|||
(home, sys_includes, sys_libdirs, libs) = build_info |
|||
|
|||
# Build the Includes -I and Library paths -L |
|||
# Start empty |
|||
includes = [] |
|||
libdirs = [] |
|||
|
|||
|
|||
# Append prefix-dir |
|||
if self.prefix: |
|||
prefix_include = [join(self.prefix, 'include')] |
|||
prefix_libdirs = [join(self.prefix, 'lib')] |
|||
includes += prefix_include |
|||
libdirs += prefix_libdirs |
|||
|
|||
# Append default system dirs |
|||
includes += sys_includes |
|||
libdirs += sys_libdirs |
|||
|
|||
# Compile flags |
|||
compile_flags = ['-std=c++14', '-fpermissive'] |
|||
if self.debug: |
|||
pEpLog("debug mode") |
|||
compile_flags += ['-O0', '-g', '-UNDEBUG'] |
|||
|
|||
# Apply the build information |
|||
global module_pEp |
|||
module_pEp.include_dirs = includes |
|||
module_pEp.library_dirs = libdirs |
|||
module_pEp.libraries = libs |
|||
module_pEp.extra_compile_args = compile_flags |
|||
|
|||
global module_pybind11 |
|||
module_pybind11.include_dirs = includes |
|||
module_pybind11.library_dirs = libdirs |
|||
# module_pybind11.libraries = libs |
|||
module_pybind11.extra_compile_args = compile_flags |
|||
|
|||
pEpLog("Include Dirs:", module_pEp.include_dirs) |
|||
pEpLog("Libs Dirs:", module_pEp.library_dirs) |
|||
pEpLog("Libraries:", module_pEp.libraries) |
|||
pEpLog("Compile flags:", module_pEp.extra_compile_args) |
|||
|
|||
def run(self): |
|||
build_ext.run(self) |
|||
|
|||
|
|||
if sys.platform == 'winnt': |
|||
if sys.version_info[0] >= 3: |
|||
import winreg |
|||
else: |
|||
import _winreg as winreg |
|||
|
|||
if sys.version_info[0] < 3: |
|||
FileNotFoundError = EnvironmentError |
|||
|
|||
module_pEp = Extension( |
|||
'pEp._pEp', |
|||
sources=[ |
|||
'src/pEp/_pEp/adapter_main.cc', |
|||
'src/pEp/_pEp/pEpmodule.cc', |
|||
'src/pEp/_pEp/basic_api.cc', |
|||
'src/pEp/_pEp/identity.cc', |
|||
'src/pEp/_pEp/message.cc', |
|||
'src/pEp/_pEp/message_api.cc', |
|||
'src/pEp/_pEp/str_attr.cc', |
|||
# 'src/pEp/_pEp/user_interface.cc', |
|||
], |
|||
) |
|||
|
|||
module_pybind11 = Extension( |
|||
'pEp._pybind', |
|||
sources=[ |
|||
'src/pEp/_pybind/pEpmodule.cc', |
|||
], |
|||
) |
|||
|
|||
|
|||
# "MAIN" Function |
|||
setup( |
|||
package_dir={'': 'src'}, |
|||
packages=['pEp'], |
|||
ext_modules=[module_pEp, module_pybind11], |
|||
cmdclass={ |
|||
'build_ext': BuildExtCommand, |
|||
}, |
|||
# While not using a pyproject.toml, support setuptools_scm setup.cfg usage, |
|||
# see https://github.com/pypa/setuptools_scm/#setupcfg-usage |
|||
use_scm_version={ |
|||
'write_to': 'src/pEp/__version__.py', |
|||
#TODO: fallback_version does not seem to work in case os missing tag |
|||
'fallback_version' : '0.0.0-RC0' |
|||
} |
|||
) |
|||
from setuptools import setup |
|||
setup() |
|||
|
@ -1,16 +0,0 @@ |
|||
HERE:=$(dir $(lastword $(MAKEFILE_LIST))) |
|||
-include $(HERE)../../local.conf |
|||
|
|||
TARGET_PEP=_pEp.so |
|||
TARGET_PYBIND=_pybind.so |
|||
|
|||
# General Build settings
|
|||
CXX=g++ |
|||
CXXFLAGS+=-std=c++11 -g |
|||
INCLUDES+=-I$(PREFIX)/include |
|||
INCLUDES+=-I/opt/local/Library/Frameworks/Python.framework/Versions/3.8/include/python3.8 |
|||
LIB_DIRS=-L$(PREFIX)/lib |
|||
LIB_DIRS+=-L/opt/local/lib |
|||
LIBS=-lpEpEngine -lpEpAdapter |
|||
LDFLAGS+=-undefined dynamic_lookup |
|||
|
@ -1,65 +0,0 @@ |
|||
# -*- coding: UTF-8 -*- |
|||
# pEp package |
|||
# |
|||
# The names that are in _pEp that do not begin with an underscore, will be be imported into, and "re-exported" from this module. |
|||
# They are defined in boost-python/C++, and are directly part of the pEpPythonAdapter API |
|||
# The names that are in _pEp that DO begin with an underscore, will not be imported into this module, but will be accessible like _pEp._underscore_function(). |
|||
# They are not directly part of the pEpPythonAdapter API, and are meant to be wrapped in this module. |
|||
# Example: |
|||
# def underscore_function(): |
|||
# _pEp._underscore_function() |
|||
|
|||
# __all__ could be used to limit the symbols exported when using from <pkg> import * |
|||
try: |
|||
from .__version__ import version as __version__ |
|||
except ImportError: |
|||
import warnings |
|||
warnings.warn("Error loading build-time defined __version__.py, trying setuptools now...") |
|||
try: |
|||
import setuptools_scm |
|||
__version__ = setuptools_scm.get_version() |
|||
del setuptools_scm |
|||
except Exception: |
|||
warnings.warn('could not determine %s package version' % __name__) |
|||
__version__ = '0.0.dev0+unknown' |
|||
|
|||
# Imports all symbols EXCEPT the ones beginning with underscore |
|||
from ._pEp import * |
|||
from ._pybind import * |
|||
|
|||
# import the native module into the current namespace because we also need to access the names beginning |
|||
# with an underscore (of _pEp), but we dont want to import them into this module |
|||
import pEp._pEp |
|||
import pEp._pybind |
|||
|
|||
# Executed on module import |
|||
def init(): |
|||
print(init, "called") |
|||
_pEp._init_after_main_module() |
|||
|
|||
|
|||
def message_to_send(msg): |
|||
""" |
|||
message_to_send(msg) |
|||
override pEp.message_to_send(msg) with your own implementation |
|||
this callback is being called when a p≡p management message needs to be sent |
|||
GIL CAVEAT |
|||
""" |
|||
print("message_to_send() - default callback\n") |
|||
print("overwrite this method") |
|||
|
|||
|
|||
def notify_handshake(me, partner, signal): |
|||
""" |
|||
notifyHandshake(self, me, partner) |
|||
me own identity |
|||
partner identity of communication partner |
|||
signal the handshake signal |
|||
overwrite this method with an implementation of a handshake dialog |
|||
GIL CAVEAT |
|||
""" |
|||
print("message_to_send() - default callback\n") |
|||
print("overwrite this method") |
|||
|
|||
|
|||
init() |
@ -1,32 +0,0 @@ |
|||
include ../Makefile.conf |
|||
TARGET=$(TARGET_PEP) |
|||
|
|||
# Specific Build settings
|
|||
CXXFLAGS+=-Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -g -fwrapv -O3 -Wall -pipe -Os -isysroot/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk |
|||
INCLUDES+= |
|||
LIB_DIRS+= |
|||
LIBS+=-lboost_python38-mt -lboost_locale-mt |
|||
LDFLAGS+= |
|||
|
|||
|
|||
|
|||
# Combine Settings
|
|||
CXXFLAGS+=$(INCLUDES) |
|||
LDFLAGS+=$(LIB_DIRS) |
|||
LDFLAGS+=$(LIBS) |
|||
|
|||
SRCS:=$(wildcard *.cc) |
|||
OBJS:=$(SRCS:.cc=.o) |
|||
|
|||
.PHONY: clean |
|||
|
|||
all: $(TARGET) |
|||
|
|||
# Using implicit compile target
|
|||
# And explicit link taget
|
|||
$(TARGET): $(OBJS) |
|||
$(CXX) $(LDFLAGS) -o $@ $^ |
|||
|
|||
clean: |
|||
rm -rf $(TARGET) |
|||
rm -rf $(OBJS) |
@ -1,163 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#include "adapter_main.hh" |
|||
#include "message.hh" |
|||
#include "message_api.hh" |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
|
|||
static const char *version_string = "p≡p Python adapter version 0.3"; |
|||
|
|||
void init_before_main_module() { |
|||
pEpLog("called"); |
|||
} |
|||
|
|||
// hidden init function, wrapped by hello_world.init()
|
|||
void _init_after_main_module() { |
|||
pEpLog("called"); |
|||
callback_dispatcher.add(_messageToSend, notifyHandshake, nullptr, nullptr); |
|||
Adapter::_messageToSend = CallbackDispatcher::messageToSend; |
|||
} |
|||
|
|||
void config_passive_mode(bool enable) { |
|||
::config_passive_mode(Adapter::session(), enable); |
|||
} |
|||
|
|||
void config_unencrypted_subject(bool enable) { |
|||
::config_unencrypted_subject(Adapter::session(), enable); |
|||
} |
|||
|
|||
void key_reset_user(const string &user_id, const string &fpr) { |
|||
if (user_id == "") { |
|||
throw invalid_argument("user_id required"); |
|||
} |
|||
|
|||
::PEP_STATUS status = ::key_reset_user(Adapter::session(), user_id.c_str(), fpr != "" ? fpr.c_str() : nullptr); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
void key_reset_user2(const string &user_id) { |
|||
key_reset_user(user_id, ""); |
|||
} |
|||
|
|||
void key_reset_all_own_keys() { |
|||
::PEP_STATUS status = ::key_reset_all_own_keys(Adapter::session()); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
string about() { |
|||
string version = string(version_string) + "\np≡p version " + PEP_VERSION + "\n"; |
|||
return version; |
|||
} |
|||
|
|||
void _throw_status(::PEP_STATUS status) { |
|||
if (status == ::PEP_STATUS_OK) { |
|||
return; |
|||
} |
|||
if (status >= 0x400 && status <= 0x4ff) { |
|||
return; |
|||
} |
|||
if (status == ::PEP_OUT_OF_MEMORY) { |
|||
throw bad_alloc(); |
|||
} |
|||
if (status == ::PEP_ILLEGAL_VALUE) { |
|||
throw invalid_argument("illegal value"); |
|||
} |
|||
|
|||
if (status_to_string(status) == "unknown status code") { |
|||
stringstream build; |
|||
build << setfill('0') << "p≡p 0x" << setw(4) << hex << status; |
|||
throw runtime_error(build.str()); |
|||
} else { |
|||
throw runtime_error(status_to_string(status)); |
|||
} |
|||
} |
|||
|
|||
::PEP_STATUS _messageToSend(::message *msg) { |
|||
pEpLog("called"); |
|||
try { |
|||
PyGILState_STATE gil = PyGILState_Ensure(); |
|||
pEpLog("GIL Aquired"); |
|||
bp::object modref = bp::import("pEp"); |
|||
bp::object funcref = modref.attr("message_to_send"); |
|||
bp::call<void>(funcref.ptr(), Message()); |
|||
PyGILState_Release(gil); |
|||
pEpLog("GIL released"); |
|||
} catch (exception &e) { |
|||
} |
|||
|
|||
return ::PEP_STATUS_OK; |
|||
} |
|||
|
|||
::PEP_STATUS notifyHandshake(::pEp_identity *me, ::pEp_identity *partner, ::sync_handshake_signal signal) { |
|||
pEpLog("called"); |
|||
try { |
|||
PyGILState_STATE gil = PyGILState_Ensure(); |
|||
pEpLog("GIL Aquired"); |
|||
bp::object modref = bp::import("pEp"); |
|||
bp::object funcref = modref.attr("notify_handshake"); |
|||
bp::call<void>(funcref.ptr(), me, partner, signal); |
|||
PyGILState_Release(gil); |
|||
pEpLog("GIL released"); |
|||
} catch (exception &e) { |
|||
} |
|||
|
|||
return ::PEP_STATUS_OK; |
|||
} |
|||
|
|||
void start_sync() { |
|||
CallbackDispatcher::start_sync(); |
|||
} |
|||
|
|||
void shutdown_sync() { |
|||
CallbackDispatcher::stop_sync(); |
|||
} |
|||
|
|||
void debug_color(int ansi_color) { |
|||
::set_debug_color(Adapter::session(), ansi_color); |
|||
} |
|||
|
|||
void leave_device_group() { |
|||
::leave_device_group(Adapter::session()); |
|||
} |
|||
|
|||
bool is_sync_active() { |
|||
return Adapter::is_sync_running(); |
|||
} |
|||
|
|||
void testfunc() { |
|||
_messageToSend(nullptr); |
|||
} |
|||
|
|||
void deliverHandshakeResult(int result, bp::object identities) { |
|||
identity_list *shared_identities = nullptr; |
|||
if (identities != bp::api::object() && boost::python::len(identities)) { |
|||
shared_identities = ::new_identity_list(nullptr); |
|||
if (!shared_identities) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
try { |
|||
::identity_list *si = shared_identities; |
|||
for (int i = 0; i < bp::len(identities); ++i) { |
|||
Identity ident = bp::extract<Identity>(identities[i]); |
|||
si = ::identity_list_add(si, ident); |
|||
if (!si) { |
|||
throw bad_alloc(); |
|||
} |
|||
} |
|||
} catch (exception &ex) { |
|||
::free_identity_list(shared_identities); |
|||
throw ex; |
|||
} |
|||
} |
|||
|
|||
::PEP_STATUS status = ::deliverHandshakeResult(Adapter::session(), (::sync_handshake_result)result, shared_identities); |
|||
free_identity_list(shared_identities); |
|||
_throw_status(status); |
|||
} |
|||
} // namespace PythonAdapter
|
|||
} // namespace pEp
|
@ -1,84 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#ifndef ADAPTER_MAIN_HH |
|||
#define ADAPTER_MAIN_HH |
|||
|
|||
// System
|
|||
#include <string> |
|||
#include <iomanip> |
|||
|
|||
// Boost
|
|||
#include <boost/python.hpp> |
|||
#include <boost/locale.hpp> |
|||
|
|||
// Engine
|
|||
#include <pEp/pEpEngine.h> |
|||
#include <pEp/keymanagement.h> |
|||
#include <pEp/identity_list.h> |
|||
#include <pEp/key_reset.h> |
|||
#include <pEp/sync_api.h> |
|||
#include <pEp/mime.h> |
|||
#include <pEp/message.h> |
|||
#include <pEp/message_api.h> |
|||
#include <pEp/sync_codec.h> |
|||
#include <pEp/distribution_codec.h> |
|||
#include <pEp/timestamp.h> |
|||
#include <pEp/stringpair.h> |
|||
|
|||
// libpEpAdapter
|
|||
#include <pEp/Adapter.hh> |
|||
#include <pEp/callback_dispatcher.hh> |
|||
#include <pEp/status_to_string.hh> |
|||
#include <pEp/pEpLog.hh> |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
using namespace std; |
|||
namespace bp = boost::python; |
|||
namespace bl = boost::locale; |
|||
|
|||
void init_before_main_module(); |
|||
|
|||
void _init_after_main_module(); |
|||
|
|||
void testfunc(); |
|||
|
|||
|
|||
//extern string device_name;
|
|||
|
|||
string about(); |
|||
|
|||
void config_passive_mode(bool enable); |
|||
|
|||
void start_sync(); |
|||
|
|||
void shutdown_sync(); |
|||
|
|||
void debug_color(int ansi_color); |
|||
|
|||
bool is_sync_active(); |
|||
|
|||
void config_unencrypted_subject(bool enable); |
|||
|
|||
void key_reset_user(const string &user_id, const string &fpr); |
|||
|
|||
void key_reset_user2(const string &user_id); |
|||
|
|||
void key_reset_all_own_keys(); |
|||
|
|||
void _throw_status(::PEP_STATUS status); |
|||
|
|||
void leave_device_group(); |
|||
|
|||
::PEP_STATUS _messageToSend(::message *msg); |
|||
|
|||
::PEP_STATUS notifyHandshake(::pEp_identity *me, ::pEp_identity *partner, ::sync_handshake_signal signal); |
|||
|
|||
void deliverHandshakeResult(int result, bp::object identities); |
|||
|
|||
} // namespace PythonAdapter
|
|||
} // namespace pEp
|
|||
|
|||
#endif // ADAPTER_MAIN_HH
|
@ -1,152 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#include "basic_api.hh" |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
void update_identity(Identity &ident) { |
|||
if (ident.address() == "") { |
|||
throw invalid_argument("address needed"); |
|||
} |
|||
if (ident.user_id() == PEP_OWN_USERID) { |
|||
throw runtime_error("update_identity: '" PEP_OWN_USERID "' may only be used for own identities"); |
|||
} |
|||
::PEP_STATUS status = ::update_identity(Adapter::session(), ident); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
void myself(Identity &ident) { |
|||
if (ident.address() == "") { |
|||
throw invalid_argument("address needed"); |
|||
} |
|||
if (ident.username() == "") { |
|||
throw invalid_argument("username needed"); |
|||
} |
|||
if (ident.user_id() == "") { |
|||
ident.user_id(ident.address()); |
|||
} |
|||
::PEP_STATUS status = ::myself(Adapter::session(), ident); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
string _trustwords(Identity me, Identity partner, string lang, bool full) { |
|||
if (me.fpr() == "" || partner.fpr() == "") { |
|||
throw invalid_argument("fingerprint needed in Identities"); |
|||
} |
|||
if (lang == "" && me.lang() == partner.lang()) { |
|||
lang = me.lang(); |
|||
} |
|||
char *words = nullptr; |
|||
size_t size = 0; |
|||
::PEP_STATUS status = ::get_trustwords(Adapter::session(), me, partner, lang.c_str(), &words, &size, full); |
|||
_throw_status(status); |
|||
return words; |
|||
} |
|||
|
|||
void trust_personal_key(Identity ident) { |
|||
if (ident.fpr() == "") { |
|||
throw invalid_argument("fingerprint needed in Identities"); |
|||
} |
|||
if (ident.user_id() == "") { |
|||
throw invalid_argument("user_id must be provided"); |
|||
} |
|||
::PEP_STATUS status = ::trust_personal_key(Adapter::session(), ident); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
void set_identity_flags(Identity ident,const ::identity_flags_t &flags) { |
|||
if (ident.address() == "") { |
|||
throw invalid_argument("address needed"); |
|||
} |
|||
if (ident.user_id() == "") { |
|||
throw invalid_argument("user_id needed"); |
|||
} |
|||
::PEP_STATUS status = ::set_identity_flags(Adapter::session(), ident, flags); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
void unset_identity_flags(Identity ident,const ::identity_flags_t &flags) { |
|||
if (ident.address() == "") { |
|||
throw invalid_argument("address needed"); |
|||
} |
|||
if (ident.user_id() == "") { |
|||
throw invalid_argument("user_id needed"); |
|||
} |
|||
::PEP_STATUS status = ::unset_identity_flags(Adapter::session(), ident, flags); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
void key_reset_trust(Identity ident) { |
|||
if (ident.fpr() == "") { |
|||
throw invalid_argument("fpr needed"); |
|||
} |
|||
if (ident.address() == "") { |
|||
throw invalid_argument("address needed"); |
|||
} |
|||
if (ident.user_id() == "") { |
|||
throw invalid_argument("user_id needed"); |
|||
} |
|||
::PEP_STATUS status = ::key_reset_trust(Adapter::session(), ident); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
bp::list import_key(const string &key_data) { |
|||
::identity_list *private_keys = nullptr; |
|||
::PEP_STATUS status = ::import_key(Adapter::session(), key_data.c_str(), key_data.size(), &private_keys); |
|||
if (status && status != ::PEP_KEY_IMPORTED) { |
|||
_throw_status(status); |
|||
} |
|||
auto result = bp::list(); |
|||
for (::identity_list *il = private_keys; il && il->ident; il = il->next) { |
|||
::pEp_identity *ident = ::identity_dup(il->ident); |
|||
if (!ident) { |
|||
::free_identity_list(private_keys); |
|||
throw bad_alloc(); |
|||
} |
|||
result.append(Identity(ident)); |
|||
} |
|||
::free_identity_list(private_keys); |
|||
return result; |
|||
} |
|||
|
|||
string export_key(Identity ident) { |
|||
::PEP_STATUS status = ::PEP_STATUS_OK; |
|||
char *key_data = nullptr; |
|||
size_t size; |
|||
status = ::export_key(Adapter::session(), ident.fpr().c_str(), &key_data, &size); |
|||
_throw_status(status); |
|||
return key_data; |
|||
} |
|||
|
|||
string export_secret_key(Identity ident) { |
|||
::PEP_STATUS status = ::PEP_STATUS_OK; |
|||
char *key_data = NULL; |
|||
size_t size; |
|||
status = ::export_secret_key(Adapter::session(), ident.fpr().c_str(), &key_data, &size); |
|||
_throw_status(status); |
|||
return key_data; |
|||
} |
|||
|
|||
void set_own_key(Identity &ident, const string &fpr) { |
|||
if (ident.address() == "") { |
|||
throw invalid_argument("address needed"); |
|||
} |
|||
if (ident.username() == "") { |
|||
throw invalid_argument("username needed"); |
|||
} |
|||
if (ident.user_id() == "") { |
|||
throw invalid_argument("user_id needed"); |
|||
} |
|||
if (fpr == "") { |
|||
throw invalid_argument("fpr needed"); |
|||
} |
|||
const char *fpr_c = fpr.c_str(); |
|||
::PEP_STATUS status = ::set_own_key(Adapter::session(), ident, fpr_c); |
|||
_throw_status(status); |
|||
} |
|||
} // namespace PythonAdapter
|
|||
} // namespace pEp
|
|||
|
|||
|
@ -1,38 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#ifndef BASIC_API_HH |
|||
#define BASIC_API_HH |
|||
|
|||
#include "adapter_main.hh" |
|||
#include "identity.hh" |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
void update_identity(Identity &ident); |
|||
|
|||
void myself(Identity &ident); |
|||
|
|||
string _trustwords(Identity me, Identity partner, string lang, bool full); |
|||
|
|||
void trust_personal_key(Identity ident); |
|||
|
|||
void set_identity_flags(Identity ident,const ::identity_flags_t &flags); |
|||
|
|||
void unset_identity_flags(Identity ident,const ::identity_flags_t &flags); |
|||
|
|||
void key_reset_trust(Identity ident); |
|||
|
|||
bp::list import_key(const string &key_data); |
|||
|
|||
string export_key(Identity ident); |
|||
|
|||
string export_secret_key(Identity ident); |
|||
|
|||
void set_own_key(Identity &ident, const string &fpr); |
|||
|
|||
} /* namespace PythonAdapter */ |
|||
} /* namespace pEp */ |
|||
|
|||
#endif /* BASIC_API_HH */ |
@ -1,258 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#include "identity.hh" |
|||
#include "basic_api.hh" |
|||
#include "message_api.hh" |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
|
|||
Identity::Identity(string address, string username, string user_id, string fpr, int comm_type, string lang, ::identity_flags_t flags) |
|||
: _ident(::new_identity(address.c_str(), fpr.c_str(), user_id.c_str(), username.c_str()), &::free_identity) { |
|||
if (!_ident) { |
|||
throw bad_alloc(); |
|||
} |
|||
_ident->comm_type = (::PEP_comm_type)comm_type; |
|||
_ident->flags = (::identity_flags_t)flags; |
|||
this->lang(lang); |
|||
} |
|||
|
|||
Identity::Identity(const Identity &second) |
|||
: _ident(second._ident) { |
|||
|
|||
} |
|||
|
|||
Identity::Identity(::pEp_identity *ident) |
|||
: _ident(ident, &::free_identity) { |
|||
|
|||
} |
|||
|
|||
Identity::~Identity() { |
|||
|
|||
} |
|||
|
|||
Identity::operator ::pEp_identity *() { |
|||
return _ident.get(); |
|||
} |
|||
|
|||
Identity::operator const ::pEp_identity *() const { |
|||
return _ident.get(); |
|||
} |
|||
|
|||
string Identity::_repr() { |
|||
stringstream build; |
|||
build << "Identity("; |
|||
string address; |
|||
if (_ident->address) { |
|||
address = string(_ident->address); |
|||
} |
|||
build << repr(address) << ", "; |
|||
string username; |
|||
if (_ident->username) { |
|||
username = string(_ident->username); |
|||
} |
|||
build << repr(username) << ", "; |
|||
string user_id; |
|||
if (_ident->user_id) { |
|||
user_id = string(_ident->user_id); |
|||
} |
|||
build << repr(user_id) << ", "; |
|||
string fpr; |
|||
if (_ident->fpr) { |
|||
fpr = string(_ident->fpr); |
|||
} |
|||
build << repr(fpr) << ", "; |
|||
build << (int)_ident->comm_type << ", "; |
|||
string lang = _ident->lang; |
|||
build << repr(lang) << ")"; |
|||
return build.str(); |
|||
} |
|||
|
|||
string Identity::_str() { |
|||
if (!(_ident->address && _ident->address[0])) { |
|||
return ""; |
|||
} |
|||
if (!(_ident->username && _ident->username[0])) { |
|||
return _ident->address; |
|||
} |
|||
return string(_ident->username) + " <" + _ident->address + ">"; |
|||
} |
|||
|
|||
void Identity::username(string value) { |
|||
if (value.length() && value.length() < 5) { |
|||
throw length_error("username must be at least 5 characters"); |
|||
} |
|||
|
|||
str_attr(_ident->username, value); |
|||
} |
|||
|
|||
void Identity::lang(string value) { |
|||
if (value == "") { |
|||
memset(_ident->lang, 0, 3); |
|||
} else if (value.length() != 2) { |
|||
throw length_error("length of lang must be 2"); |
|||
} else { |
|||
memcpy(_ident->lang, value.c_str(), 3); |
|||
} |
|||
} |
|||
|
|||
string Identity::lang() { |
|||
return _ident->lang; |
|||
} |
|||
|
|||
int Identity::rating() { |
|||
if (!(_ident->address)) { |
|||
throw invalid_argument("address must be given"); |
|||
} |
|||
|
|||
::PEP_rating rating = ::PEP_rating_undefined; |
|||
::PEP_STATUS status = ::identity_rating(Adapter::session(), _ident.get(), &rating); |
|||
_throw_status(status); |
|||
|
|||
return (int)rating; |
|||
} |
|||
|
|||
::PEP_color Identity::color() { |
|||
return _color(rating()); |
|||
} |
|||
|
|||
Identity Identity::copy() { |
|||
::pEp_identity *dup = ::identity_dup(*this); |
|||
if (!dup) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
return Identity(dup); |
|||
} |
|||
|
|||
Identity Identity::deepcopy(bp::dict &) { |
|||
return copy(); |
|||
} |
|||
|
|||
void Identity::update() { |
|||
update_identity(*this); |
|||
} |
|||
|
|||
void Identity::key_reset(const string &fpr) { |
|||
::PEP_STATUS status = ::key_reset_identity(Adapter::session(), *this, fpr != "" ? fpr.c_str() : nullptr); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
void Identity::key_mistrusted() { |
|||
::PEP_STATUS status = ::key_mistrusted(Adapter::session(), *this); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
bool Identity::is_pEp_user() { |
|||
bool result; |
|||
::PEP_STATUS status = ::is_pEp_user(Adapter::session(), *this, &result); |
|||
_throw_status(status); |
|||
return result; |
|||
} |
|||
|
|||
void Identity::enable_for_sync() { |
|||
::PEP_STATUS status = ::enable_identity_for_sync(Adapter::session(), *this); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
void Identity::disable_for_sync() { |
|||
::PEP_STATUS status = ::disable_identity_for_sync(Adapter::session(), *this); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
// Myself::Myself(string address, string username, string user_id, string lang)
|
|||
// : Identity(address, username, user_id, "", 0, lang) {
|
|||
// if (!(address.length() && username.length()))
|
|||
// throw invalid_argument("address and username must be set");
|
|||
// if (lang.length() && lang.length() != 2)
|
|||
// throw length_error("lang must be an ISO 639-1 language code or empty");
|
|||
//
|
|||
// // FIXME: should set .me
|
|||
// // _ident->me = true;
|
|||
// if (user_id.length())
|
|||
// throw runtime_error("user_id feature not yet implemented for Myself");
|
|||
// }
|
|||
|
|||
// void Myself::update() {
|
|||
// pEp::PythonAdapter::myself(*this);
|
|||
// }
|
|||
|
|||
Identity identity_attr(::pEp_identity *&ident) { |
|||
if (!ident) { |
|||
throw out_of_range("no identity assigned"); |
|||
} |
|||
|
|||
::pEp_identity *_dup = ::identity_dup(ident); |
|||
if (!_dup) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
Identity _ident(_dup); |
|||
return _ident; |
|||
} |
|||
|
|||
void identity_attr(::pEp_identity *&ident, bp::object value) { |
|||
Identity &_ident = bp::extract<Identity &>(value); |
|||
::pEp_identity *_dup = ::identity_dup(_ident); |
|||
if (!_dup) { |
|||
throw bad_alloc(); |
|||
} |
|||
::PEP_STATUS status = ::update_identity(Adapter::session(), _dup); |
|||
_throw_status(status); |
|||
::free_identity(ident); |
|||
ident = _dup; |
|||
} |
|||
|
|||
bp::list identitylist_attr(::identity_list *&il) { |
|||
bp::list result; |
|||
|
|||
for (::identity_list *_il = il; _il && _il->ident; _il = _il->next) { |
|||
::pEp_identity *ident = ::identity_dup(_il->ident); |
|||
if (!ident) { |
|||
throw bad_alloc(); |
|||
} |
|||
result.append(bp::object(Identity(ident))); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
void identitylist_attr(::identity_list *&il, bp::list value) { |
|||
::identity_list *_il = ::new_identity_list(nullptr); |
|||
if (!_il) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
::identity_list *_i = _il; |
|||
for (int i = 0; i < len(value); i++) { |
|||
bp::extract<Identity &> extract_identity(value[i]); |
|||
if (!extract_identity.check()) { |
|||
::free_identity_list(_il); |
|||
} |
|||
::pEp_identity *_ident = extract_identity(); |
|||
::pEp_identity *_dup = ::identity_dup(_ident); |
|||
if (!_dup) { |
|||
::free_identity_list(_il); |
|||
throw bad_alloc(); |
|||
} |
|||
::PEP_STATUS status = ::update_identity(Adapter::session(), _dup); |
|||
if (status != ::PEP_STATUS_OK) { |
|||
::free_identity_list(_il); |
|||
_throw_status(status); |
|||
} |
|||
_i = ::identity_list_add(_i, _dup); |
|||
if (!_i) { |
|||
::free_identity_list(_il); |
|||
throw bad_alloc(); |
|||
} |
|||
} |
|||
|
|||
::free_identity_list(il); |
|||
il = _il; |
|||
} |
|||
|
|||
} // namespace PythonAdapter
|
|||
} // namespace pEp
|
|||
|
@ -1,103 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#ifndef IDENTITY_HH |
|||
#define IDENTITY_HH |
|||
|
|||
// System
|
|||
#include "adapter_main.hh" |
|||
#include "str_attr.hh" |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
// Identity is owning a pEp_identity
|
|||
class Identity { |
|||
protected: |
|||
shared_ptr<::pEp_identity> _ident; |
|||
|
|||
public: |
|||
Identity(string address = "", string username = "", string user_id = "", string fpr = "", int comm_type = 0, string lang = "", ::identity_flags_t flags = 0); |
|||
|
|||
Identity(const Identity &second); |
|||
|
|||
Identity(::pEp_identity *ident); |
|||
|
|||
virtual ~Identity(); |
|||
|
|||
operator ::pEp_identity *(); |
|||
|
|||
operator const ::pEp_identity *() const; |
|||
|
|||
string _repr(); |
|||
|
|||
string _str(); |
|||
|
|||
string address() { return str_attr(_ident->address); } |
|||
|
|||
void address(string value) { str_attr(_ident->address, value); } |
|||
|
|||
string fpr() { return str_attr(_ident->fpr); } |
|||
|
|||
void fpr(string value) { str_attr(_ident->fpr, value); } |
|||
|
|||
string user_id() { return str_attr(_ident->user_id); } |
|||
|
|||
void user_id(string value) { str_attr(_ident->user_id, value); } |
|||
|
|||
string username() { return str_attr(_ident->username); } |
|||
|
|||
void username(string value); |
|||
|
|||
::PEP_comm_type comm_type() { return _ident->comm_type; } |
|||
|
|||
void comm_type(::PEP_comm_type value) { _ident->comm_type = value; }; |
|||
|
|||
std::string lang(); |
|||
|
|||
void lang(std::string value); |
|||
|
|||
::identity_flags_t flags() { return _ident->flags; } |
|||
|
|||
void flags(::identity_flags_t flags) { _ident->flags = flags; } |
|||
|
|||
int rating(); |
|||
|
|||
::PEP_color color(); |
|||
|
|||
Identity copy(); |
|||
|
|||
Identity deepcopy(bp::dict &memo); |
|||
|
|||
virtual void update(); |
|||
|
|||
void key_reset(const string &fpr = ""); |
|||
|
|||
void key_mistrusted(); |
|||
|
|||
bool is_pEp_user(); |
|||
|
|||
void enable_for_sync(); |
|||
|
|||
void disable_for_sync(); |
|||
}; |
|||
|
|||
// class Myself : public Identity {
|
|||
// public:
|
|||
// Myself(string address, string username, string user_id = "", string lang = "");
|
|||
//
|
|||
// virtual void update();
|
|||
// };
|
|||
|
|||
Identity identity_attr(::pEp_identity *&ident); |
|||
|
|||
void identity_attr(::pEp_identity *&ident, bp::object value); |
|||
|
|||
bp::list identitylist_attr(::identity_list *&il); |
|||
|
|||
void identitylist_attr(::identity_list *&il, bp::list value); |
|||
|
|||
} // namespace PythonAdapter
|
|||
} // namespace pEp
|
|||
|
|||
#endif /* IDENTITY_HH */ |
@ -1,387 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
// local
|
|||
#include "message.hh" |
|||
#include "message_api.hh" |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
|
|||
Message::Blob::Blob(::bloblist_t *bl, bool chained) |
|||
: _bl(bl), |
|||
part_of_chain(chained) { |
|||
if (!_bl) { |
|||
throw bad_alloc(); |
|||
} |
|||
} |
|||
|
|||
Message::Blob::Blob(bp::object data, string mime_type, string filename) |
|||
: _bl(::new_bloblist(nullptr, 0, nullptr, nullptr)), |
|||
part_of_chain(false) { |
|||
if (!_bl) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
Py_buffer src; |
|||
int result = PyObject_GetBuffer(data.ptr(), &src, PyBUF_CONTIG_RO); |
|||
if (result) { |
|||
throw invalid_argument("need a contiguous buffer to read"); |
|||
} |
|||
|
|||
char *mem = (char *)malloc(src.len); |
|||
if (!mem) { |
|||
PyBuffer_Release(&src); |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
memcpy(mem, src.buf, src.len); |
|||
free(_bl->value); |
|||
_bl->size = src.len; |
|||
_bl->value = mem; |
|||
|
|||
PyBuffer_Release(&src); |
|||
|
|||
this->mime_type(mime_type); |
|||
this->filename(filename); |
|||
} |
|||
|
|||
Message::Blob::Blob(const Message::Blob &second) |
|||
: _bl(second._bl), |
|||
part_of_chain(true) { |
|||
} |
|||
|
|||
Message::Blob::~Blob() { |
|||
if (!part_of_chain) { |
|||
free(_bl->value); |
|||
free(_bl); |
|||
} |
|||
} |
|||
|
|||
string Message::Blob::_repr() { |
|||
stringstream build; |
|||
build << "Blob("; |
|||
if (!_bl) { |
|||
build << "b'', '', ''"; |
|||
} else { |
|||
build << "bytes(" << _bl->size << "), "; |
|||
string mime_type; |
|||
if (_bl->mime_type) { |
|||
mime_type = string(_bl->mime_type); |
|||
} |
|||
string filename; |
|||
if (_bl->filename) { |
|||
filename = string(_bl->filename); |
|||
} |
|||
build << repr(mime_type) << ", "; |
|||
build << repr(filename); |
|||
} |
|||
build << ")"; |
|||
return build.str(); |
|||
} |
|||
|
|||
int Message::Blob::getbuffer(PyObject *self, Py_buffer *view, int flags) { |
|||
::bloblist_t *bl = nullptr; |
|||
|
|||
try { |
|||
Message::Blob &blob = bp::extract<Message::Blob &>(self); |
|||
bl = blob._bl; |
|||
} catch (exception &e) { |
|||
PyErr_SetString(PyExc_RuntimeError, "extract not possible"); |
|||
view->obj = nullptr; |
|||
return -1; |
|||
} |
|||
|
|||
if (!(bl && bl->value)) { |
|||
PyErr_SetString(PyExc_RuntimeError, "no data available"); |
|||
view->obj = nullptr; |
|||
return -1; |
|||
} |
|||
|
|||
return PyBuffer_FillInfo(view, self, bl->value, bl->size, 0, flags); |
|||
} |
|||
|
|||
string Message::Blob::decode(string encoding) { |
|||
if (encoding == "") { |
|||
string _mime_type = _bl->mime_type ? _bl->mime_type : ""; |
|||
encoding = "ascii"; |
|||
|
|||
if (_mime_type == "application/pEp.sync") { |
|||
encoding = "pep.sync"; |
|||
} |
|||
|
|||
if (_mime_type == "application/pEp.keyreset") { |
|||
encoding = "pep.distribution"; |
|||
} |
|||
|
|||
} |
|||
bp::object codecs = bp::import("codecs"); |
|||
bp::object _decode = codecs.attr("decode"); |
|||
return bp::call<string>(_decode.ptr(), this, encoding); |
|||
} |
|||
|
|||
PyBufferProcs Message::Blob::bp = {getbuffer, nullptr}; |
|||
|
|||
Message::Message(int dir, Identity *from) |
|||
: _msg(new_message((::PEP_msg_direction)dir), &::free_message) { |
|||
if (!_msg) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
if (from) { |
|||
_msg->from = ::identity_dup(*from); |
|||
if (!_msg->from) { |
|||
throw bad_alloc(); |
|||
} |
|||
_msg->dir = (::PEP_msg_direction)dir; |
|||
} |
|||
} |
|||
|
|||
Message::Message(string mimetext) |
|||
: _msg(nullptr, &::free_message) { |
|||
::message *_cpy; |
|||
::PEP_STATUS status = ::mime_decode_message(mimetext.c_str(), mimetext.size(), &_cpy, nullptr); |
|||
switch (status) { |
|||
case ::PEP_STATUS_OK: |
|||
if (_cpy) { |
|||
_cpy->dir = ::PEP_dir_outgoing; |
|||
} else { |
|||
_cpy = new_message(::PEP_dir_outgoing); |
|||
} |
|||
|
|||
if (!_cpy) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
_msg = shared_ptr<::message>(_cpy); |
|||
break; |
|||
|
|||
case ::PEP_BUFFER_TOO_SMALL: |
|||
throw runtime_error("mime_decode_message: buffer too small"); |
|||
|
|||
case ::PEP_CANNOT_CREATE_TEMP_FILE: |
|||
throw runtime_error("mime_decode_message: cannot create temp file"); |
|||
|
|||
case ::PEP_OUT_OF_MEMORY: |
|||
throw bad_alloc(); |
|||
|
|||
default: |
|||
stringstream build; |
|||
build << "mime_decode_message: unknown error (" << (int)status << ")"; |
|||
throw runtime_error(build.str()); |
|||
} |
|||
} |
|||
|
|||
Message::Message(const Message &second) |
|||
: _msg(second._msg) { |
|||
if (!_msg.get()) { |
|||
throw bad_alloc(); |
|||
} |
|||
} |
|||
|
|||
Message::Message(::message *msg) |
|||
: _msg(::message_dup(msg), &::free_message) {} |
|||
|
|||
Message::~Message() {} |
|||
|
|||
Message::operator ::message *() { |
|||
return _msg.get(); |
|||
} |
|||
|
|||
Message::operator const ::message *() const { |
|||
return _msg.get(); |
|||
} |
|||
|
|||
string Message::_str() { |
|||
if (!(_msg->from && _msg->from->address && _msg->from->address[0])) { |
|||
throw out_of_range(".from_.address missing"); |
|||
} |
|||
|
|||
char *mimetext; |
|||
string result; |
|||
|
|||
::PEP_STATUS status = ::mime_encode_message(*this, false, &mimetext, false); |
|||
switch (status) { |
|||
case ::PEP_STATUS_OK: |
|||
result = mimetext; |
|||
free(mimetext); |
|||
break; |
|||
|
|||
case ::PEP_BUFFER_TOO_SMALL: |
|||
throw runtime_error("mime_encode_message: buffer too small"); |
|||
|
|||
case ::PEP_CANNOT_CREATE_TEMP_FILE: |
|||
throw runtime_error("mime_encode_message: cannot create temp file"); |
|||
|
|||
case ::PEP_OUT_OF_MEMORY: |
|||
throw bad_alloc(); |
|||
|
|||
default: |
|||
stringstream build; |
|||
build << "mime_encode_message: unknown error (" << (int)status << ")"; |
|||
throw runtime_error(build.str()); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
string Message::_repr() { |
|||
stringstream build; |
|||
build << "Message(" << repr(_str()) << ")"; |
|||
return build.str(); |
|||
} |
|||
|
|||
bp::tuple Message::attachments() { |
|||
bp::list l; |
|||
|
|||
for (::bloblist_t *bl = _msg->attachments; bl && bl->value; bl = bl->next) { |
|||
l.append(Blob(bl, true)); |
|||
} |
|||
|
|||
return bp::tuple(l); |
|||
} |
|||
|
|||
void Message::attachments(bp::list value) { |
|||
::bloblist_t *bl = ::new_bloblist(nullptr, 0, nullptr, nullptr); |
|||
if (!bl) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
::bloblist_t *_l = bl; |
|||
for (int i = 0; i < len(value); i++) { |
|||
Message::Blob &blob = bp::extract<Message::Blob &>(value[i]); |
|||
_l = bloblist_add(_l, blob._bl->value, blob._bl->size, blob._bl->mime_type, blob._bl->filename); |
|||
if (!_l) { |
|||
for (_l = bl; _l && _l->value;) { |
|||
free(_l->mime_type); |
|||
free(_l->filename); |
|||
::bloblist_t *_ll = _l; |
|||
_l = _l->next; |
|||
free(_ll); |
|||
} |
|||
throw bad_alloc(); |
|||
} |
|||
} |
|||
|
|||
for (int i = 0; i < len(value); i++) { |
|||
Message::Blob &blob = bp::extract<Message::Blob &>(value[i]); |
|||
blob._bl->value = nullptr; |
|||
blob._bl->size = 0; |
|||
free(blob._bl->mime_type); |
|||
blob._bl->mime_type = nullptr; |
|||
free(blob._bl->filename); |
|||
blob._bl->filename = nullptr; |
|||
} |
|||
|
|||
free_bloblist(_msg->attachments); |
|||
_msg->attachments = bl; |
|||
} |
|||
|
|||
Message Message::encrypt() { |
|||
bp::list extra; |
|||
return encrypt_message(*this, extra, ::PEP_enc_PGP_MIME, 0); |
|||
} |
|||
|
|||
Message Message::_encrypt(bp::list extra, int enc_format, int flags) { |
|||
if (!enc_format) { |
|||
enc_format = ::PEP_enc_PGP_MIME; |
|||
} |
|||
return encrypt_message(*this, extra, enc_format, flags); |
|||
} |
|||
|
|||
bp::tuple Message::decrypt(int flags) { |
|||
return pEp::PythonAdapter::decrypt_message(*this, flags); |
|||
} |
|||
|
|||
::PEP_rating Message::outgoing_rating() { |
|||
if (_msg->dir != ::PEP_dir_outgoing) { |
|||
throw invalid_argument("Message.dir must be outgoing"); |
|||
} |
|||
|
|||
if (from().address() == "") { |
|||
throw invalid_argument("from.address needed"); |
|||
} |
|||
if (from().username() == "") { |
|||
throw invalid_argument("from.username needed"); |
|||
} |
|||
|
|||
if (len(to()) + len(cc()) == 0) { |
|||
throw invalid_argument("either to or cc needed"); |
|||
} |
|||
|
|||
::PEP_STATUS status = myself(Adapter::session(), _msg->from); |
|||
_throw_status(status); |
|||
|
|||
::PEP_rating rating = ::PEP_rating_undefined; |
|||
status = outgoing_message_rating(Adapter::session(), *this, &rating); |
|||
_throw_status(status); |
|||
|
|||
return rating; |
|||
} |
|||
|
|||
::PEP_color Message::outgoing_color() { |
|||
return _color(outgoing_rating()); |
|||
} |
|||
|
|||
Message Message::copy() { |
|||
::message *dup = ::message_dup(*this); |
|||
if (!dup) { |
|||
throw bad_alloc(); |
|||
} |
|||
return Message(dup); |
|||
} |
|||
|
|||
Message Message::deepcopy(bp::dict &) { |
|||
return copy(); |
|||
} |
|||
|
|||
Message outgoing_message(Identity me) { |
|||
if (me.address().empty() || me.user_id().empty()) { |
|||
throw runtime_error("at least address and user_id of own user needed"); |
|||
} |
|||
|
|||
::myself(Adapter::session(), me); |
|||
auto m = Message(::PEP_dir_outgoing, &me); |
|||
return m; |
|||
} |
|||
|
|||
static bp::object update(Identity ident) { |
|||
if (ident.address().empty()) { |
|||
throw runtime_error("at least address needed"); |
|||
} |
|||
::update_identity(Adapter::session(), ident); |
|||
return bp::object(ident); |
|||
} |
|||
|
|||
static bp::list update(bp::list il) { |
|||
for (int i = 0; i < len(il); i++) { |
|||
update(bp::extract<Identity>(il[i])); |
|||
} |
|||
|
|||
return il; |
|||
} |
|||
|
|||
Message incoming_message(string mime_text) { |
|||
auto m = Message(mime_text); |
|||
m.dir(::PEP_dir_incoming); |
|||
|
|||
try { |
|||
m.from(update(m.from())); |
|||
} catch (out_of_range &) { |
|||
} |
|||
|
|||
try { |
|||
m.recv_by(update(m.recv_by())); |
|||
} catch (out_of_range &) { |
|||
} |
|||
|
|||
m.to(update(m.to())); |
|||
m.cc(update(m.cc())); |
|||
m.reply_to(update(m.reply_to())); |
|||
|
|||
return m; |
|||
} |
|||
|
|||
} // namespace PythonAdapter
|
|||
} // namespace pEp
|
@ -1,179 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#ifndef MESSAGE_HH |
|||
#define MESSAGE_HH |
|||
|
|||
#include "adapter_main.hh" |
|||
#include "str_attr.hh" |
|||
#include "identity.hh" |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
// Message is owning a message struct
|
|||
class Message { |
|||
shared_ptr<::message> _msg; |
|||
|
|||
public: |
|||
// Blob is owning a bloblist_t struct - or not and just managing
|
|||
// one depending on part_of_chain
|
|||
|
|||
class Blob { |
|||
::bloblist_t *_bl; |
|||
bool part_of_chain; |
|||
|
|||
public: |
|||
Blob(::bloblist_t *bl = ::new_bloblist(nullptr, 0, nullptr, nullptr), bool chained = false); |
|||
|
|||
Blob(bp::object data, string mime_type = "", string filename = ""); |
|||
|
|||
Blob(const Blob &second); |
|||
|
|||
~Blob(); |
|||
|
|||
string _repr(); |
|||
|
|||
string mime_type() { return _bl ? str_attr(_bl->mime_type) : ""; } |
|||
|
|||
void mime_type(string value) { str_attr(_bl->mime_type, value); } |
|||
|
|||
string filename() { return str_attr(_bl->filename); } |
|||
|
|||
void filename(string value) { str_attr(_bl->filename, value); } |
|||
|
|||
size_t size() { return _bl->size; } |
|||
|
|||
string decode(string encoding); |
|||
|
|||
string decode() { return decode(""); } |
|||
|
|||
static PyBufferProcs bp; |
|||
|
|||
friend class Message; |
|||
|
|||
protected: |
|||
static int getbuffer(PyObject *self, Py_buffer *view, int flags); |
|||
}; |
|||
|
|||
Message(int dir = ::PEP_dir_outgoing, Identity *from = nullptr); |
|||
|
|||
Message(string mimetext); |
|||
|
|||
Message(const Message &second); |
|||
|
|||
Message(::message *msg); |
|||
|
|||
~Message(); |
|||
|
|||
operator ::message *(); |
|||
|
|||
operator const ::message *() const; |
|||
|
|||
string _str(); |
|||
|
|||
string _repr(); |
|||
|
|||
::PEP_msg_direction dir() { return _msg->dir; } |
|||
|
|||
void dir(::PEP_msg_direction value) { _msg->dir = value; } |
|||
|
|||
string id() { return str_attr(_msg->id); } |
|||
|
|||
void id(string value) { str_attr(_msg->id, value); } |
|||
|
|||
string shortmsg() { return str_attr(_msg->shortmsg); } |
|||
|
|||
void shortmsg(string value) { str_attr(_msg->shortmsg, value); } |
|||
|
|||
string longmsg() { return str_attr(_msg->longmsg); } |
|||
|
|||
void longmsg(string value) { str_attr(_msg->longmsg, value); } |
|||
|
|||
string longmsg_formatted() { return str_attr(_msg->longmsg_formatted); } |
|||
|
|||
void longmsg_formatted(string value) { str_attr(_msg->longmsg_formatted, value); } |
|||
|
|||
bp::tuple attachments(); |
|||
|
|||
void attachments(bp::list value); |
|||
|
|||
time_t sent() { return timestamp_attr(_msg->sent); } |
|||
|
|||
void sent(time_t value) { timestamp_attr(_msg->sent, value); } |
|||
|
|||
time_t recv() { return timestamp_attr(_msg->recv); } |
|||
|
|||
void recv(time_t value) { timestamp_attr(_msg->recv, value); } |
|||
|
|||
Identity from() { return identity_attr(_msg->from); } |
|||
|
|||
void from(bp::object value) { identity_attr(_msg->from, value); } |
|||
|
|||
bp::list to() { return identitylist_attr(_msg->to); } |
|||
|
|||
void to(bp::list value) { identitylist_attr(_msg->to, value); } |
|||
|
|||
Identity recv_by() { return identity_attr(_msg->recv_by); } |
|||
|
|||
void recv_by(bp::object value) { identity_attr(_msg->recv_by, value); } |
|||
|
|||
bp::list cc() { return identitylist_attr(_msg->cc); } |
|||
|
|||
void cc(bp::list value) { identitylist_attr(_msg->cc, value); } |
|||
|
|||
bp::list bcc() { return identitylist_attr(_msg->bcc); } |
|||
|
|||
void bcc(bp::list value) { identitylist_attr(_msg->bcc, value); } |
|||
|
|||
bp::list reply_to() { return identitylist_attr(_msg->reply_to); } |
|||
|
|||
void reply_to(bp::list value) { identitylist_attr(_msg->reply_to, value); } |
|||
|
|||
bp::list in_reply_to() { return strlist_attr(_msg->in_reply_to); } |
|||
|
|||
void in_reply_to(bp::list value) { strlist_attr(_msg->in_reply_to, value); } |
|||
|
|||
bp::list references() { return strlist_attr(_msg->references); } |
|||
|
|||
void references(bp::list value) { strlist_attr(_msg->references, value); } |
|||
|
|||
bp::list keywords() { return strlist_attr(_msg->keywords); } |
|||
|
|||
void keywords(bp::list value) { strlist_attr(_msg->keywords, value); } |
|||
|
|||
string comments() { return str_attr(_msg->comments); } |
|||
|
|||
void comments(string value) { str_attr(_msg->comments, value); } |
|||
|
|||
bp::dict opt_fields() { return strdict_attr(_msg->opt_fields); } |
|||
|
|||
void opt_fields(bp::dict value) { return strdict_attr(_msg->opt_fields, value); } |
|||
|
|||
::PEP_enc_format enc_format() { return _msg->enc_format; } |
|||
|
|||
void enc_format(::PEP_enc_format value) { _msg->enc_format = value; } |
|||
|
|||
Message encrypt(); |
|||
|
|||
Message _encrypt(bp::list extra, int enc_format = 4, int flags = 0); |
|||
|
|||
bp::tuple decrypt(int flags = 0); |
|||
|
|||
::PEP_rating outgoing_rating(); |
|||
|
|||
::PEP_color outgoing_color(); |
|||
|
|||
Message deepcopy(bp::dict &memo); |
|||
|
|||
Message copy(); |
|||
}; |
|||
|
|||
Message outgoing_message(Identity me); |
|||
|
|||
Message incoming_message(string mime_text); |
|||
|
|||
} /* namespace PythonAdapter */ |
|||
} /* namespace pEp */ |
|||
|
|||
#endif /* MESSAGE_HH */ |
@ -1,158 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
// local
|
|||
#include "message_api.hh" |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
|
|||
Message encrypt_message(Message src, bp::list extra, int enc_format, int flags) { |
|||
Identity _from = src.from(); |
|||
if (_from.address() == "") { |
|||
throw invalid_argument("encrypt_message: src.from_.address empty"); |
|||
} |
|||
if (_from.username() == "") { |
|||
throw invalid_argument("encrypt_message: src.from_.username empty"); |
|||
} |
|||
|
|||
if (_from.user_id() == "") { |
|||
src.from().user_id(_from.address()); |
|||
} |
|||
|
|||
::stringlist_t *_extra = to_stringlist(extra); |
|||
::PEP_enc_format _enc_format = (::PEP_enc_format)enc_format; |
|||
::PEP_encrypt_flags_t _flags = (::PEP_encrypt_flags_t)flags; |
|||
::message *_dst = nullptr; |
|||
|
|||
::message *_src = src; |
|||
::PEP_STATUS status = ::encrypt_message(Adapter::session(), _src, _extra, &_dst, _enc_format, _flags); |
|||
::free_stringlist(_extra); |
|||
_throw_status(status); |
|||
|
|||
if (!_dst || _dst == _src) { |
|||
return Message(_src); |
|||
} |
|||
|
|||
return Message(_dst); |
|||
} |
|||
|
|||
bp::tuple decrypt_message(Message src, int flags) { |
|||
::message *_dst = nullptr; |
|||
::stringlist_t *_keylist = nullptr; |
|||
::PEP_rating _rating = ::PEP_rating_undefined; |
|||
::PEP_decrypt_flags_t _flags = (::PEP_decrypt_flags_t)flags; |
|||
::message *_src = src; |
|||
|
|||
::PEP_STATUS status = ::decrypt_message(Adapter::session(), _src, &_dst, &_keylist, &_rating, &_flags); |
|||
_throw_status(status); |
|||
|
|||
bp::list keylist; |
|||
if (_keylist) { |
|||
keylist = from_stringlist(_keylist); |
|||
::free_stringlist(_keylist); |
|||
} |
|||
|
|||
Message dst = _dst ? Message(_dst) : Message(src); |
|||
return bp::make_tuple(dst, keylist, _rating, _flags); |
|||
} |
|||
|
|||
::PEP_color _color(int rating) { |
|||
return ::color_from_rating((::PEP_rating)rating); |
|||
} |
|||
|
|||
bp::tuple sync_decode(bp::object buffer) { |
|||
Py_buffer src; |
|||
int result = PyObject_GetBuffer(buffer.ptr(), &src, PyBUF_CONTIG_RO); |
|||
if (result) { |
|||
throw invalid_argument("need a contiguous buffer to read"); |
|||
} |
|||
|
|||
char *dst = nullptr; |
|||
::PEP_STATUS status = ::PER_to_XER_Sync_msg((char *)src.buf, src.len, &dst); |
|||
PyBuffer_Release(&src); |
|||
_throw_status(status); |
|||
|
|||
string _dst(dst); |
|||
free(dst); |
|||
return bp::make_tuple(_dst, 0); |
|||
} |
|||
|
|||
static bp::tuple sync_encode(string text) { |
|||
char *data = nullptr; |
|||
size_t size = 0; |
|||
::PEP_STATUS status = ::XER_to_PER_Sync_msg(text.c_str(), &data, &size); |
|||
_throw_status(status); |
|||
|
|||
PyObject * ba = PyBytes_FromStringAndSize(data, size); |
|||
free(data); |
|||
if (!ba) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
return bp::make_tuple(bp::object(bp::handle<>(ba)), 0); |
|||
} |
|||
|
|||
bp::tuple Distribution_decode(bp::object buffer) { |
|||
Py_buffer src; |
|||
int result = PyObject_GetBuffer(buffer.ptr(), &src, PyBUF_CONTIG_RO); |
|||
if (result) { |
|||
throw invalid_argument("need a contiguous buffer to read"); |
|||
} |
|||
|
|||
char *dst = nullptr; |
|||
::PEP_STATUS status = ::PER_to_XER_Distribution_msg((char *)src.buf, src.len, &dst); |
|||
PyBuffer_Release(&src); |
|||
_throw_status(status); |
|||
|
|||
string _dst(dst); |
|||
free(dst); |
|||
return bp::make_tuple(_dst, 0); |
|||
} |
|||
|
|||
static bp::tuple Distribution_encode(string text) { |
|||
char *data = nullptr; |
|||
size_t size = 0; |
|||
::PEP_STATUS status = ::XER_to_PER_Distribution_msg(text.c_str(), &data, &size); |
|||
_throw_status(status); |
|||
|
|||
PyObject * ba = PyBytes_FromStringAndSize(data, size); |
|||
free(data); |
|||
if (!ba) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
return bp::make_tuple(bp::object(bp::handle<>(ba)), 0); |
|||
} |
|||
|
|||
bp::object sync_search(string name) { |
|||
if (name != "pep.sync") { |
|||
return bp::object(); |
|||
} else { |
|||
bp::object codecs = bp::import("codecs"); |
|||
bp::object CodecInfo = codecs.attr("CodecInfo"); |
|||
|
|||
bp::object _sync_decode = make_function(sync_decode); |
|||
bp::object _sync_encode = make_function(sync_encode); |
|||
|
|||
return bp::call<bp::object>(CodecInfo.ptr(), _sync_encode, _sync_decode); |
|||
} |
|||
} |
|||
|
|||
bp::object distribution_search(string name) { |
|||
if (name != "pep.distribution") { |
|||
return bp::object(); |
|||
} else { |
|||
bp::object codecs = bp::import("codecs"); |
|||
bp::object CodecInfo = codecs.attr("CodecInfo"); |
|||
|
|||
bp::object _distribution_decode = make_function(Distribution_decode); |
|||
bp::object _distribution_encode = make_function(Distribution_encode); |
|||
|
|||
return bp::call<bp::object>(CodecInfo.ptr(), _distribution_encode, _distribution_decode); |
|||
} |
|||
} |
|||
|
|||
} // namespace PythonAdapter
|
|||
} // namespace pEp
|
@ -1,26 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#ifndef MESSAGE_API_HH |
|||
#define MESSAGE_API_HH |
|||
|
|||
#include "adapter_main.hh" |
|||
#include "message.hh" |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
Message encrypt_message(Message src, bp::list extra = bp::list(), int enc_format = 4, int flags = 0); |
|||
|
|||
bp::tuple decrypt_message(Message src, int flags = 0); |
|||
|
|||
::PEP_color _color(int rating); |
|||
|
|||
bp::object sync_search(string name); |
|||
|
|||
bp::object distribution_search(string name); |
|||
|
|||
} /* namespace PythonAdapter */ |
|||
} /* namespace pEp */ |
|||
|
|||
#endif /* MESSAGE_API_HH */ |
@ -1,492 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
|
|||
// local
|
|||
#include "adapter_main.hh" |
|||
#include "basic_api.hh" |
|||
#include "message.hh" |
|||
#include "message_api.hh" |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
|
|||
BOOST_PYTHON_MODULE(_pEp) { |
|||
using boost::python::def; |
|||
using boost::python::class_; |
|||
using boost::python::enum_; |
|||
init_before_main_module(); |
|||
|
|||
// Module init function called by pEp.init()
|
|||
def("_init_after_main_module", _init_after_main_module); |
|||
def("testfunc", &testfunc); |
|||
|
|||
bp::docstring_options doc_options(true, false, false); |
|||
bl::generator gen; |
|||
std::locale::global(gen("")); |
|||
|
|||
|
|||
bp::scope().attr("about") = about(); |
|||
bp::scope().attr("per_user_directory") = ::per_user_directory(); |
|||
bp::scope().attr("per_machine_directory") = ::per_machine_directory(); |
|||
bp::scope().attr("engine_version") = ::get_engine_version(); |
|||
bp::scope().attr("protocol_version") = ::get_protocol_version(); |
|||
|
|||
def("passive_mode", config_passive_mode, |
|||
"do not attach pub keys to all messages"); |
|||
|
|||
def("unencrypted_subject", config_unencrypted_subject, |
|||
"do not encrypt the subject of messages"); |
|||
|
|||
def("key_reset", key_reset_user, |
|||
"reset the default database status for the user / keypair provided\n" |
|||
"This will effectively perform key_reset on each identity\n" |
|||
"associated with the key and user_id, if a key is provided, and for\n" |
|||
"each key (and all of their identities) if an fpr is not."); |
|||
|
|||
def("key_reset", key_reset_user2, |
|||
"reset the default database status for the user / keypair provided\n" |
|||
"This will effectively perform key_reset on each identity\n" |
|||
"associated with the key and user_id, if a key is provided, and for\n" |
|||
"each key (and all of their identities) if an fpr is not."); |
|||
|
|||
def("key_reset_all_own_keys", key_reset_all_own_keys, |
|||
"revoke and mistrust all own keys, generate new keys for all\n" |
|||
"own identities, and opportunistically communicate key reset\n" |
|||
"information to people we have recently contacted."); |
|||
|
|||
auto identity_class = class_<Identity>("Identity", |
|||
"Identity(address, username, user_id='', fpr='', comm_type=0, lang='en')\n" |
|||
"\n" |
|||
"represents a p≡p identity\n" |
|||
"\n" |
|||
"an identity is a network address, under which a user is represented in\n" |
|||
"the network\n" |
|||
"\n" |
|||
" address network address, either an SMTP address or a URI\n" |
|||
" username real name or nickname for user\n" |
|||
" user_id ID this user is handled by the application\n" |
|||
" fpr full fingerprint of the key being used as key ID,\n" |
|||
" hex encoded\n" |
|||
" comm_type first rating level of this communication channel\n" |
|||
" lang ISO 639-1 language code for language being preferred\n" |
|||
" on this communication channel\n" |
|||
) |
|||
.def(bp::init<string>()) |
|||
.def(bp::init<string, string>()) |
|||
.def(bp::init<string, string, string>()) |
|||
.def(bp::init<string, string, string, string>()) |
|||
.def(bp::init<string, string, string, string, int>()) |
|||
.def(bp::init<string, string, string, string, int, string>()) |
|||
.def("__repr__", &Identity::_repr) |
|||
.def("__str__", &Identity::_str, |
|||
"string representation of this identity\n" |
|||
"following the pattern 'username < address >'\n" |
|||
) |
|||
.def("key_reset", &Identity::key_reset, |
|||
bp::arg("fpr")=bp::object(""), |
|||
"reset the default database status for the identity / keypair provided. If this\n" |
|||
"corresponds to the own user and a private key, also revoke the key, generate a\n" |
|||
"new one, and communicate the reset to recently contacted pEp partners for this\n" |
|||
"identity. If it does not, remove the key from the keyring; the key's status is\n" |
|||
"completely fresh on next contact from the partner.") |
|||
|
|||
.def("key_mistrusted", &Identity::key_mistrusted, |
|||
bp::arg("fpr")=bp::object(""), |
|||
"If you want updated trust on the identity, you ll have" |
|||
"to call update_identity or myself respectively after this." |
|||
"N.B. If you are calling this on a key that is the identity or user default," |
|||
"it will be removed as the default key for ANY identity and user for which" |
|||
"it is the default. Please keep in mind that the undo in undo_last_mistrust" |
|||
"will only undo the current identity's / it's user's default, not any" |
|||
"other identities which may be impacted (this will not affect most use cases)") |
|||
|
|||
.def("enable_for_sync", &Identity::enable_for_sync, |
|||
"Enable own identity for p≡p sync.\n\n" |
|||
"Only use this on own identities, which are used as accounts.\n") |
|||
.def("disable_for_sync", &Identity::disable_for_sync, |
|||
"Disable own identity for p≡p sync.\n\n" |
|||
"Only use this on own identities, which are used as accounts.\n") |
|||
|
|||
.add_property("address", (string(Identity::*)()) &Identity::address, |
|||
(void(Identity::*)(string)) &Identity::address, |
|||
"email address or URI") |
|||
.add_property("fpr", (string(Identity::*)()) &Identity::fpr, |
|||
(void(Identity::*)(string)) &Identity::fpr, |
|||
"key ID (full fingerprint, hex encoded)") |
|||
.add_property("user_id", (string(Identity::*)()) &Identity::user_id, |
|||
(void(Identity::*)(string)) &Identity::user_id, |
|||
"ID of person associated or 'pEp_own_userId' if own identity") |
|||
.add_property("username", (string(Identity::*)()) &Identity::username, |
|||
(void(Identity::*)(string)) &Identity::username, |
|||
"name in full of person associated") |
|||
.add_property("comm_type", (int(Identity::*)()) |
|||
(PEP_comm_type(Identity::*)()) &Identity::comm_type, |
|||
(void(Identity::*)(int)) |
|||
(void(Identity::*)(::PEP_comm_type)) &Identity::comm_type, |
|||
"communication type, first rating level (p≡p internal)") |
|||
.add_property("lang", (string(Identity::*)()) &Identity::lang, |
|||
(void(Identity::*)(string)) &Identity::lang, |
|||
"ISO 639-1 language code") |
|||
.add_property("flags", (identity_flags_t(Identity::*)()) &Identity::flags, |
|||
(void(Identity::*)(::identity_flags_t)) &Identity::flags, |
|||
"flags (p≡p internal)") |
|||
.add_property("rating", &Identity::rating, "rating of Identity") |
|||
.add_property("color", &Identity::color, "color of Identity as PEP_color") |
|||
.add_property("is_pEp_user", &Identity::is_pEp_user, "True if this is an identity of a pEp user") |
|||
.def("__deepcopy__", &Identity::deepcopy) |
|||
.def("update", &Identity::update, "update Identity") |
|||
.def("__copy__", &Identity::copy); |
|||
|
|||
identity_class.attr("PEP_OWN_USERID") = "pEp_own_userId"; |
|||
|
|||
auto blob_class = class_<Message::Blob>("Blob", |
|||
"Blob(data, mime_type='', filename='')\n" |
|||
"\n" |
|||
"Binary large object\n" |
|||
"\n" |
|||
" data bytes-like object\n" |
|||
" mime_type MIME type for the data\n" |
|||
" filename filename to store the data\n", |
|||
bp::init< bp::object, char const*, char const* >(bp::args("data", "mime_type", "filename"))) |
|||
.def(bp::init<bp::object, string>()) |
|||
.def(bp::init<bp::object>()) |
|||
.def("__repr__", &Message::Blob::_repr) |
|||
.def("__len__", &Message::Blob::size, "size of Blob data in bytes") |
|||
.def("decode", (string(Message::Blob::*)()) &Message::Blob::decode) |
|||
.def("decode", (string(Message::Blob::*)(string)) &Message::Blob::decode, |
|||
"text = blob.decode(encoding='')\n" |
|||
"\n" |
|||
"decode Blob data into string depending on MIME type if encoding=''\n" |
|||
"\n" |
|||
" mime_type='application/pEp.sync' decode as 'pEp.sync'\n" |
|||
" mime_type='application/pEp.keyreset' decode as 'pEp.keyreset'\n" |
|||
" other mime_type decode as 'ascii' by default\n" |
|||
) |
|||
.add_property("mime_type", (string(Message::Blob::*)()) &Message::Blob::mime_type, |
|||
(void(Message::Blob::*)(string)) &Message::Blob::mime_type, |
|||
"MIME type of object in Blob") |
|||
.add_property("filename", (string(Message::Blob::*)()) &Message::Blob::filename, |
|||
(void(Message::Blob::*)(string)) &Message::Blob::filename, |
|||
"filename of object in Blob"); |
|||
|
|||
((PyTypeObject *)(void *)blob_class.ptr())->tp_as_buffer = &Message::Blob::bp; |
|||
|
|||
auto message_class = class_<Message>("Message", |
|||
"Message(dir=1, from=None)\n" |
|||
"\n" |
|||
"new p≡p message\n" |
|||
"\n" |
|||
" dir 1 for outgoing, 2 for incoming\n" |
|||
" from Identity() of sender\n" |
|||
"\n" |
|||
"Message(mime_text)\n" |
|||
"\n" |
|||
"new incoming p≡p message\n" |
|||
"\n" |
|||
" mime_text text in Multipurpose Internet Mail Extensions format\n" |
|||
) |
|||
.def(bp::init<int>()) |
|||
.def(bp::init<int, Identity *>()) |
|||
.def(bp::init<string>()) |
|||
.def("__str__", &Message::_str, |
|||
"the string representation of a Message is it's MIME text" |
|||
) |
|||
.def("__repr__", &Message::_repr) |
|||
.add_property("dir", (int(Message::*)()) |
|||
(PEP_msg_direction(Message::*)()) &Message::dir, |
|||
(void(Message::*)(int)) |
|||
(void(Message::*)(::PEP_msg_direction)) &Message::dir, |
|||
"0: incoming, 1: outgoing message") |
|||
.add_property("id", (string(Message::*)()) &Message::id, |
|||
(void(Message::*)(string)) &Message::id, |
|||
"message ID") |
|||
.add_property("shortmsg", (string(Message::*)()) &Message::shortmsg, |
|||
(void(Message::*)(string)) &Message::shortmsg, |
|||
"subject or short message") |
|||
.add_property("longmsg", (string(Message::*)()) &Message::longmsg, |
|||
(void(Message::*)(string)) &Message::longmsg, |
|||
"body or long version of message") |
|||
.add_property("longmsg_formatted", (string(Message::*)()) &Message::longmsg_formatted, |
|||
(void(Message::*)(string)) &Message::longmsg_formatted, |
|||
"HTML body or fromatted long version of message") |
|||
.add_property("attachments", (bp::tuple(Message::*)()) &Message::attachments, |
|||
(void(Message::*)(bp::list)) &Message::attachments, |
|||
"tuple of Blobs with attachments; setting moves Blobs to attachment tuple") |
|||
.add_property("sent", (time_t(Message::*)()) &Message::sent, |
|||
(void(Message::*)(time_t)) &Message::sent, |
|||
"time when message was sent in UTC seconds since epoch") |
|||
.add_property("recv", (time_t(Message::*)()) &Message::recv, |
|||
(void(Message::*)(time_t)) &Message::recv, |
|||
"time when message was received in UTC seconds since epoch") |
|||
.add_property("from_", (Identity(Message::*)()) &Message::from, |
|||
(void(Message::*)(bp::object)) &Message::from, |
|||
"identity where message is from") |
|||
.add_property("to", (bp::list(Message::*)()) &Message::to, |
|||
(void(Message::*)(bp::list)) &Message::to, |
|||
"list of identities message is going to") |
|||
.add_property("recv_by", (Identity(Message::*)()) &Message::recv_by, |
|||
(void(Message::*)(bp::object)) &Message::recv_by, |
|||
"identity where message was received by") |
|||
.add_property("cc", (bp::list(Message::*)()) &Message::cc, |
|||
(void(Message::*)(bp::list)) &Message::cc, |
|||
"list of identities message is going cc") |
|||
.add_property("bcc", (bp::list(Message::*)()) &Message::bcc, |
|||
(void(Message::*)(bp::list)) &Message::bcc, |
|||
"list of identities message is going bcc") |
|||
.add_property("reply_to", (bp::list(Message::*)()) &Message::reply_to, |
|||
(void(Message::*)(bp::list)) &Message::reply_to, |
|||
"list of identities where message will be replied to") |
|||
.add_property("in_reply_to", (bp::list(Message::*)()) &Message::in_reply_to, |
|||
(void(Message::*)(bp::list)) &Message::in_reply_to, |
|||
"in_reply_to list") |
|||
.add_property("references", (bp::list(Message::*)()) &Message::references, |
|||
(void(Message::*)(bp::list)) &Message::references, |
|||
"message IDs of messages this one is referring to") |
|||
.add_property("keywords", (bp::list(Message::*)()) &Message::keywords, |
|||
(void(Message::*)(bp::list)) &Message::keywords, |
|||
"keywords this message should be stored under") |
|||
.add_property("comments", (string(Message::*)()) &Message::comments, |
|||
(void(Message::*)(string)) &Message::comments, |
|||
"comments added to message") |
|||
.add_property("opt_fields", (bp::dict(Message::*)()) &Message::opt_fields, |
|||
(void(Message::*)(bp::dict)) &Message::opt_fields, |
|||
"opt_fields of message") |
|||
.add_property("enc_format", (int(Message::*)()) |
|||
(PEP_enc_format(Message::*)()) &Message::enc_format, |
|||
(void(Message::*)(int)) |
|||
(void(Message::*)(::PEP_enc_format)) &Message::enc_format, |
|||
"0: unencrypted, 1: inline PGP, 2: S/MIME, 3: PGP/MIME, 4: p≡p format") |
|||
.def("encrypt", (Message(Message::*)())&Message::encrypt) |
|||
.def("encrypt", (Message(Message::*)(bp::list))&Message::_encrypt) |
|||
.def("encrypt", (Message(Message::*)(bp::list, int))&Message::_encrypt) |
|||
.def("encrypt", (Message(Message::*)(bp::list, int, int))&Message::_encrypt, |
|||
"msg2 = msg1.encrypt(extra_keys=[], enc_format='pEp', flags=0)\n" |
|||
"\n" |
|||
"encrypts a p≡p message and returns the encrypted message\n" |
|||
"\n" |
|||
" extra_keys list of strings with fingerprints for extra keys to use\n" |
|||
" for encryption\n" |
|||
" enc_format 0 for none, 1 for partitioned, 2 for S/MIME,\n" |
|||
" 3 for PGP/MIME, 4 for pEp\n" |
|||
" flags 1 is force encryption\n" |
|||
) |
|||
.def("decrypt", &Message::decrypt, bp::arg("flags")=0, |
|||
"msg2, keys, rating, flags = msg1.decrypt()\n" |
|||
"\n" |
|||
"decrypts a p≡p message and returns a tuple with data\n" |
|||
"\n" |
|||
" msg the decrypted p≡p message\n" |
|||
" keys a list of keys being used\n" |
|||
" rating the rating of the message as integer\n" |
|||
" flags flags set while decryption\n" |
|||
) |
|||
.add_property("outgoing_rating", &Message::outgoing_rating, "rating outgoing message will have") |
|||
.add_property("outgoing_color", &Message::outgoing_color, "color outgoing message will have as PEP_color") |
|||
.def("__deepcopy__", &Message::deepcopy) |
|||
.def("__copy__", &Message::copy); |
|||
|
|||
// basic API and key management API
|
|||
|
|||
def("update_identity", &update_identity, |
|||
"update_identity(ident)\n" |
|||
"\n" |
|||
"update identity information\n" |
|||
"call this to complete identity information when you at least have an address\n" |
|||
); |
|||
def("myself", &myself, |
|||
"myself(ident)\n" |
|||
"\n" |
|||
"ensures that the own identity is being complete\n" |
|||
"supply ident.address and ident.username\n" |
|||
); |
|||
def("trust_personal_key", &trust_personal_key, |
|||
"trust_personal_key(ident)\n" |
|||
"\n" |
|||
"mark a key as trusted with a person\n" |
|||
); |
|||
|
|||
enum_<::identity_flags>("identity_flags") |
|||
.value("PEP_idf_not_for_sync", ::PEP_idf_not_for_sync) |
|||
.value("PEP_idf_list", ::PEP_idf_list) |
|||
.value("PEP_idf_devicegroup", ::PEP_idf_devicegroup); |
|||
|
|||
def("set_identity_flags", &set_identity_flags, |
|||
"set_identity_flags(ident, flags)\n" |
|||
"\n" |
|||
"set identity flags\n" |
|||
); |
|||
|
|||
def("unset_identity_flags", &unset_identity_flags, |
|||
"unset_identity_flags(ident, flags)\n" |
|||
"\n" |
|||
"unset identity flags\n" |
|||
); |
|||
|
|||
def("key_reset_trust", &key_reset_trust, |
|||
"key_reset_trust(ident)\n" |
|||
"\n" |
|||
"reset trust bit or explicitly mistrusted status for an identity and " |
|||
"its accompanying key/user_id pair\n" |
|||
); |
|||
|
|||
def("import_key", &import_key, |
|||
"private_key_list = import_key(key_data)\n" |
|||
"\n" |
|||
"import key(s) from key_data\n" |
|||
); |
|||
|
|||
def("export_key", &export_key, |
|||
"key_data = export_key(identity)\n" |
|||
"\n" |
|||
"export key(s) of identity\n" |
|||
); |
|||
|
|||
def("export_secret_key", &export_secret_key, |
|||
"key_data = export_seret_key(identity)\n" |
|||
"\n" |
|||
"export secret key(s) of identity\n" |
|||
); |
|||
|
|||
def("set_own_key", &set_own_key, |
|||
"set_own_key(me, fpr)\n" |
|||
"\n" |
|||
"mark a key as an own key, and make it the default key\n" |
|||
"\n" |
|||
"me Own identity for which to add the existing key\n" |
|||
"fpr The fingerprint of the key to be added\n" |
|||
"\n" |
|||
"me->address, me->user_id and me->username must be set to valid data\n" |
|||
"myself() is called by set_own_key() without key generation\n" |
|||
"me->flags are ignored\n" |
|||
"me->address must not be an alias\n" |
|||
"me->fpr will be ignored and replaced by fpr\n" |
|||
); |
|||
|
|||
// message API
|
|||
|
|||
enum_<::PEP_rating>("rating") |
|||
.value("_undefined", ::PEP_rating_undefined) |
|||
.value("cannot_decrypt", ::PEP_rating_cannot_decrypt) |
|||
.value("have_no_key", ::PEP_rating_have_no_key) |
|||
.value("unencrypted", ::PEP_rating_unencrypted) |
|||
.value("unreliable", ::PEP_rating_unreliable) |
|||
.value("reliable", ::PEP_rating_reliable) |
|||
.value("trusted", ::PEP_rating_trusted) |
|||
.value("trusted_and_anonymized", ::PEP_rating_trusted_and_anonymized) |
|||
.value("fully_anonymous", ::PEP_rating_fully_anonymous) |
|||
.value("mistrust", ::PEP_rating_mistrust) |
|||
.value("b0rken", ::PEP_rating_b0rken) |
|||
.value("under_attack", ::PEP_rating_under_attack); |
|||
|
|||
enum_<::PEP_color>("colorvalue") |
|||
.value("no_color", ::PEP_color_no_color) |
|||
.value("yellow", ::PEP_color_yellow) |
|||
.value("green", ::PEP_color_green) |
|||
.value("red", ::PEP_color_red); |
|||
|
|||
|
|||
def("incoming_message", &incoming_message, |
|||
"msg = incoming_message(mime_text)\n" |
|||
"\n" |
|||
"create an incoming message from a MIME text" |
|||
); |
|||
def("outgoing_message", &outgoing_message, |
|||
"msg = outgoing_message(ident)\n" |
|||
"\n" |
|||
"create an outgoing message using an own identity" |
|||
); |
|||
def("color", &_color, |
|||
"c = color(rating)\n" |
|||
"\n" |
|||
"calculate color value out of rating. Returns PEP_color" |
|||
); |
|||
def("trustwords", &_trustwords, |
|||
"text = trustwords(ident_own, ident_partner)\n" |
|||
"\n" |
|||
"calculate trustwords for two Identities"); |
|||
|
|||
// Sync API
|
|||
|
|||
enum_<::sync_handshake_signal>("sync_handshake_signal") |
|||
.value("SYNC_NOTIFY_UNDEFINED", ::SYNC_NOTIFY_UNDEFINED) |
|||
.value("SYNC_NOTIFY_INIT_ADD_OUR_DEVICE", ::SYNC_NOTIFY_INIT_ADD_OUR_DEVICE) |
|||
.value("SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE", ::SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE) |
|||
.value("SYNC_NOTIFY_INIT_FORM_GROUP", ::SYNC_NOTIFY_INIT_FORM_GROUP) |
|||
.value("SYNC_NOTIFY_TIMEOUT", ::SYNC_NOTIFY_TIMEOUT) |
|||
.value("SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED", ::SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED) |
|||
.value("SYNC_NOTIFY_ACCEPTED_GROUP_CREATED", ::SYNC_NOTIFY_ACCEPTED_GROUP_CREATED) |
|||
.value("SYNC_NOTIFY_ACCEPTED_DEVICE_ACCEPTED", ::SYNC_NOTIFY_ACCEPTED_DEVICE_ACCEPTED) |
|||
.value("SYNC_NOTIFY_SOLE", ::SYNC_NOTIFY_SOLE) |
|||
.value("SYNC_NOTIFY_IN_GROUP", ::SYNC_NOTIFY_IN_GROUP); |
|||
|
|||
// auto user_interface_class = class_<UserInterface, UserInterface_callback, boost::noncopyable>(
|
|||
// "UserInterface",
|
|||
// "class MyUserInterface(UserInterface):\n"
|
|||
// " def notifyHandshake(self, me, partner):\n"
|
|||
// " ...\n"
|
|||
// "\n"
|
|||
// "p≡p User Interface class\n"
|
|||
// "To be used as a mixin\n"
|
|||
// )
|
|||
// .def("notifyHandshake", &UserInterface::notifyHandshake,
|
|||
// "notifyHandshake(self, me, partner)\n"
|
|||
// "\n"
|
|||
// " me own identity\n"
|
|||
// " partner identity of communication partner\n"
|
|||
// "\n"
|
|||
// "overwrite this method with an implementation of a handshake dialog")
|
|||
// .def("deliverHandshakeResult", &UserInterface::deliverHandshakeResult,
|
|||
// bp::arg("identities")=object(),
|
|||
// "deliverHandshakeResult(self, result, identities=None)\n"
|
|||
// "\n"
|
|||
// " result -1: cancel, 0: accepted, 1: rejected\n"
|
|||
// " identities list of identities to share or None for all\n"
|
|||
// "\n"
|
|||
// "call to deliver the handshake result of the handshake dialog"
|
|||
// );
|
|||
|
|||
def("deliver_handshake_result", &deliverHandshakeResult, bp::arg("identities")=bp::object(), |
|||
"deliverHandshakeResult(self, result, identities=None)\n" |
|||
"\n" |
|||
" result -1: cancel, 0: accepted, 1: rejected\n" |
|||
" identities list of identities to share or None for all\n" |
|||
"\n" |
|||
"call to deliver the handshake result of the handshake dialog" |
|||
); |
|||
|
|||
def("start_sync", &start_sync, |
|||
"start_sync()\n" |
|||
"\n" |
|||
"starts the sync thread" |
|||
); |
|||
|
|||
def("shutdown_sync", &shutdown_sync, |
|||
"shutdown_sync()\n" |
|||
"\n" |
|||
"call this from another thread to shut down the sync thread\n" |
|||
); |
|||
|
|||
def("debug_color", &debug_color, |
|||
"for debug builds set ANSI color value"); |
|||
|
|||
def("leave_device_group", &leave_device_group, |
|||
"leave_device_group()\n" |
|||
"\n" |
|||
"call this for a grouped device, which should leave\n" |
|||
); |
|||
|
|||
def("is_sync_active", &is_sync_active, |
|||
"is_sync_active()\n" |
|||
"\n" |
|||
"True if sync is active, False otherwise\n" |
|||
); |
|||
|
|||
|
|||
// codecs
|
|||
bp::call< bp::object >(((bp::object)(bp::import("codecs").attr("register"))).ptr(), make_function(sync_search)); |
|||
bp::call< bp::object >(((bp::object)(bp::import("codecs").attr("register"))).ptr(), make_function(distribution_search)); |
|||
} |
|||
} // namespace PythonAdapter
|
|||
} // namespace pEp
|
@ -1,15 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#ifndef PEPMODULE_HH |
|||
#define PEPMODULE_HH |
|||
|
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
|
|||
} /* namespace PythonAdapter */ |
|||
} /* namespace pEp */ |
|||
|
|||
#endif /* PEPMODULE_HH */ |
@ -1,172 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
// local
|
|||
#include "str_attr.hh" |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
|
|||
bp::object repr(bp::object s) { |
|||
return s.attr("__repr__")(); |
|||
} |
|||
|
|||
string repr(const string &s) { |
|||
bp::str _s = s.c_str(); |
|||
bp::object _r = _s.attr("__repr__")(); |
|||
string r = bp::extract<string>(_r); |
|||
return r; |
|||
} |
|||
|
|||
string str_attr(char *&str) { |
|||
if (!str) { |
|||
return string(""); |
|||
} |
|||
return string(str); |
|||
} |
|||
|
|||
void str_attr(char *&str, const string &value) { |
|||
string normalized = normalize(value, bl::norm_nfc); |
|||
free(str); |
|||
str = strdup(normalized.c_str()); |
|||
if (!str) { |
|||
throw bad_alloc(); |
|||
} |
|||
} |
|||
|
|||
time_t timestamp_attr(::timestamp *&ts) { |
|||
if (!ts) { |
|||
return 0; |
|||
} |
|||
|
|||
return timegm(ts); |
|||
} |
|||
|
|||
void timestamp_attr(::timestamp *&ts, time_t value) { |
|||
free_timestamp(ts); |
|||
ts = ::new_timestamp(value); |
|||
} |
|||
|
|||
bp::list strlist_attr(::stringlist_t *&sl) { |
|||
bp::list result; |
|||
|
|||
for (const ::stringlist_t *_sl = sl; _sl && _sl->value; _sl = _sl->next) { |
|||
string s(_sl->value); |
|||
result.append(bp::object(s)); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
void strlist_attr(::stringlist_t *&sl, bp::list value) { |
|||
::stringlist_t *_sl = ::new_stringlist(NULL); |
|||
if (!_sl) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
::stringlist_t *_s = _sl; |
|||
for (int i = 0; i < len(value); i++) { |
|||
bp::extract<string> extract_string(value[i]); |
|||
if (!extract_string.check()) { |
|||
free_stringlist(_sl); |
|||
} |
|||
string s = extract_string(); |
|||
s = normalize(s, bl::norm_nfc); |
|||
_s = stringlist_add(_s, s.c_str()); |
|||
if (!_s) { |
|||
free_stringlist(_sl); |
|||
throw bad_alloc(); |
|||
} |
|||
} |
|||
|
|||
free_stringlist(sl); |
|||
sl = _sl; |
|||
} |
|||
|
|||
bp::dict strdict_attr(::stringpair_list_t *&spl) { |
|||
bp::dict result; |
|||
|
|||
for (::stringpair_list_t *_spl = spl; _spl && _spl->value; _spl = _spl->next) { |
|||
::stringpair_t *p = _spl->value; |
|||
if (p->key && p->value) { |
|||
string key(p->key); |
|||
string value(p->value); |
|||
|
|||
result[key] = value; |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
void strdict_attr(::stringpair_list_t *&spl, bp::dict value) { |
|||
::stringpair_list_t *_spl = ::new_stringpair_list(nullptr); |
|||
if (!_spl) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
::stringpair_list_t *_s = _spl; |
|||
for (int i = 0; i < len(value); i++) { |
|||
bp::extract<string> extract_key(value.keys()[i]); |
|||
bp::extract<string> extract_value(value.values()[i]); |
|||
|
|||
if (!(extract_key.check() && extract_value.check())) { |
|||
free_stringpair_list(_spl); |
|||
} |
|||
|
|||
string key = extract_key(); |
|||
key = normalize(key, bl::norm_nfc); |
|||
string _value = extract_value(); |
|||
_value = normalize(_value, bl::norm_nfc); |
|||
::stringpair_t *pair = ::new_stringpair(key.c_str(), _value.c_str()); |
|||
if (!pair) { |
|||
free_stringpair_list(_spl); |
|||
throw bad_alloc(); |
|||
} |
|||
_s = stringpair_list_add(_s, pair); |
|||
if (!_s) { |
|||
free_stringpair_list(_spl); |
|||
throw bad_alloc(); |
|||
} |
|||
} |
|||
|
|||
free_stringpair_list(spl); |
|||
spl = _spl; |
|||
} |
|||
|
|||
::stringlist_t *to_stringlist(bp::list l) { |
|||
::stringlist_t *result = ::new_stringlist(nullptr); |
|||
if (!result) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
::stringlist_t *_s = result; |
|||
for (int i = 0; i < len(l); i++) { |
|||
bp::extract<string> extract_string(l[i]); |
|||
if (!extract_string.check()) { |
|||
free_stringlist(result); |
|||
} |
|||
string s = extract_string(); |
|||
_s = stringlist_add(_s, s.c_str()); |
|||
if (!_s) { |
|||
free_stringlist(result); |
|||
throw bad_alloc(); |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
bp::list from_stringlist(const ::stringlist_t *sl) { |
|||
bp::list result; |
|||
for (const ::stringlist_t *_sl = sl; _sl && _sl->value; _sl = _sl->next) { |
|||
string s = _sl->value; |
|||
result.append(s); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
} // namespace PythonAdapter
|
|||
} // namespace pEp {
|
|||
|
@ -1,39 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#ifndef STR_ATTR_HH |
|||
#define STR_ATTR_HH |
|||
|
|||
#include "adapter_main.hh" |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
bp::object repr(bp::object s); |
|||
|
|||
string repr(const string &s); |
|||
|
|||
string str_attr(char *&str); |
|||
|
|||
void str_attr(char *&str, const string &value); |
|||
|
|||
time_t timestamp_attr(::timestamp *&ts); |
|||
|
|||
void timestamp_attr(::timestamp *&ts, time_t value); |
|||
|
|||
bp::list strlist_attr(::stringlist_t *&sl); |
|||
|
|||
void strlist_attr(::stringlist_t *&sl, bp::list value); |
|||
|
|||
bp::dict strdict_attr(::stringpair_list_t *&spl); |
|||
|
|||
void strdict_attr(::stringpair_list_t *&spl, bp::dict value); |
|||
|
|||
::stringlist_t *to_stringlist(bp::list l); |
|||
|
|||
bp::list from_stringlist(const ::stringlist_t *sl); |
|||
|
|||
} /* namespace PythonAdapter */ |
|||
} /* namespace pEp */ |
|||
|
|||
#endif /* STR_ATTR_HH */ |
@ -1,117 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#include "user_interface.hh" |
|||
|
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
UserInterface *UserInterface::_ui = nullptr; |
|||
|
|||
UserInterface::UserInterface() { |
|||
if (_ui) { |
|||
throw runtime_error("only one UserInterface thread allowed"); |
|||
} |
|||
_ui = this; |
|||
} |
|||
|
|||
UserInterface::~UserInterface() { |
|||
_ui = nullptr; |
|||
} |
|||
|
|||
UserInterface_callback::UserInterface_callback(PyObject *self) |
|||
: UserInterface(), |
|||
_self(self) { |
|||
// adapter.ui_object(self);
|
|||
// ::PEP_STATUS status = ::register_sync_callbacks(Adapter::session(),
|
|||
// (void *) this, _notifyHandshake, retrieve_next_sync_event);
|
|||
// assert(status == ::PEP_STATUS_OK);
|
|||
// if (status)
|
|||
// _throw_status(status);
|
|||
} |
|||
|
|||
UserInterface_callback::~UserInterface_callback() { |
|||
// ::unregister_sync_callbacks(Adapter::session());
|
|||
} |
|||
|
|||
::PEP_STATUS UserInterface::_notifyHandshake(::pEp_identity *me, ::pEp_identity *partner, ::sync_handshake_signal signal) { |
|||
if (!(me && partner)) { |
|||
return ::PEP_ILLEGAL_VALUE; |
|||
} |
|||
|
|||
auto that = dynamic_cast< UserInterface_callback * >(_ui); |
|||
that->notifyHandshake(Identity(me), Identity(partner), signal); |
|||
|
|||
return ::PEP_STATUS_OK; |
|||
} |
|||
|
|||
void UserInterface::deliverHandshakeResult(int result, bp::object identities) { |
|||
identity_list *shared_identities = nullptr; |
|||
if (identities != bp::api::object() && bp::len(identities)) { |
|||
shared_identities = new_identity_list(nullptr); |
|||
if (!shared_identities) { |
|||
throw bad_alloc(); |
|||
} |
|||
|
|||
try { |
|||
identity_list *si = shared_identities; |
|||
for (int i = 0; i < bp::len(identities); ++i) { |
|||
Identity ident = bp::extract<Identity>(identities[i]); |
|||
si = identity_list_add(si, ident); |
|||
if (!si) { |
|||
throw bad_alloc(); |
|||
} |
|||
} |
|||
} catch (exception &ex) { |
|||
free_identity_list(shared_identities); |
|||
throw ex; |
|||
} |
|||
} |
|||
|
|||
::PEP_STATUS status = ::deliverHandshakeResult(Adapter::session(), (sync_handshake_result)result, shared_identities); |
|||
free_identity_list(shared_identities); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
//PEP_rating UserInterface::get_key_rating_for_user(string user_id, string fpr)
|
|||
//{
|
|||
// PEP_rating result;
|
|||
// ::PEP_STATUS status =
|
|||
// ::get_key_rating_for_user(Adapter::session(),
|
|||
// user_id.c_str(), fpr.c_str(), &result);
|
|||
// _throw_status(status);
|
|||
// return result;
|
|||
//}
|
|||
|
|||
//SYNC_EVENT UserInterface::retrieve_next_sync_event(void *management, unsigned threshold)
|
|||
//{
|
|||
// time_t started = time(nullptr);
|
|||
// bool timeout = false;
|
|||
//
|
|||
// while (adapter.queue().empty()) {
|
|||
// int i = 0;
|
|||
// ++i;
|
|||
// if (i > 10) {
|
|||
// if (time(nullptr) > started + threshold) {
|
|||
// timeout = true;
|
|||
// break;
|
|||
// }
|
|||
// i = 0;
|
|||
// }
|
|||
// nanosleep((const struct timespec[]){{0, 100000000L}}, nullptr);
|
|||
// }
|
|||
//
|
|||
// if (timeout)
|
|||
// return new_sync_timeout_event();
|
|||
//
|
|||
// return adapter.queue().pop_front();
|
|||
//}
|
|||
|
|||
void UserInterface_callback::notifyHandshake(Identity me, Identity partner, sync_handshake_signal signal) { |
|||
bp::call_method<void>(_self, "notifyHandshake", me, partner, signal); |
|||
} |
|||
|
|||
} // namespace PythonAdapter
|
|||
} // namespace pEp
|
|||
|
@ -1,45 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#ifndef USER_INTERFACE_HH |
|||
#define USER_INTERFACE_HH |
|||
|
|||
#include "adapter_main.hh" |
|||
#include "identity.hh" |
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
class UserInterface { |
|||
static UserInterface *_ui; |
|||
public: |
|||
UserInterface(); |
|||
|
|||
virtual ~UserInterface(); |
|||
|
|||
virtual void notifyHandshake(Identity me, Identity partner, ::sync_handshake_signal signal) { |
|||
throw runtime_error("override this method"); |
|||
} |
|||
|
|||
virtual void deliverHandshakeResult(int result, bp::object identities); |
|||
|
|||
// PEP_rating get_key_rating_for_user(string user_id, string fpr);
|
|||
|
|||
protected: |
|||
static ::PEP_STATUS _notifyHandshake(::pEp_identity *me, ::pEp_identity *partner, ::sync_handshake_signal signal); |
|||
}; |
|||
|
|||
class UserInterface_callback : public UserInterface { |
|||
PyObject *_self; |
|||
public: |
|||
UserInterface_callback(PyObject *self); |
|||
|
|||
~UserInterface_callback(); |
|||
|
|||
void notifyHandshake(Identity me, Identity partner, sync_handshake_signal signal); |
|||
}; |
|||
|
|||
} /* namespace PythonAdapter */ |
|||
} /* namespace pEp */ |
|||
|
|||
#endif /* USER_INTERFACE_HH */ |
|||
|
@ -1,32 +0,0 @@ |
|||
include ../Makefile.conf |
|||
TARGET=$(TARGET_PYBIND) |
|||
|
|||
# Specific Build settings
|
|||
CXXFLAGS+= |
|||
INCLUDES+= |
|||
LIB_DIRS+= |
|||
LIBS+= |
|||
LDFLAGS+= |
|||
|
|||
|
|||
|
|||
# Combine Settings
|
|||
CXXFLAGS+=$(INCLUDES) |
|||
LDFLAGS+=$(LIB_DIRS) |
|||
LDFLAGS+=$(LIBS) |
|||
|
|||
SRCS:=$(wildcard *.cc) |
|||
OBJS:=$(SRCS:.cc=.o) |
|||
|
|||
.PHONY: clean |
|||
|
|||
all: $(TARGET) |
|||
|
|||
# Using implicit compile target
|
|||
# And explicit link taget
|
|||
$(TARGET): $(OBJS) |
|||
$(CXX) $(LDFLAGS) -o $@ $^ |
|||
|
|||
clean: |
|||
rm -rf $(TARGET) |
|||
rm -rf $(OBJS) |
@ -1,88 +0,0 @@ |
|||
#include <string> |
|||
#include <pybind11/pybind11.h> |
|||
#include <pybind11/detail/common.h> |
|||
#include "../_pEp/adapter_main.hh" |
|||
|
|||
using namespace std; |
|||
|
|||
|
|||
namespace pyadpt = pEp::PythonAdapter; |
|||
namespace alib = pEp::Adapter; |
|||
namespace py = pybind11; |
|||
|
|||
struct _datta { |
|||
int great = 3; |
|||
int shit = 1; |
|||
}; |
|||
|
|||
typedef _datta datta; |
|||
typedef datta *DATTA; |
|||
//
|
|||
datta ms; |
|||
|
|||
DATTA dataPointer() { |
|||
return &ms; |
|||
} |
|||
|
|||
struct _pEpSession *getSession() { |
|||
return alib::session.get(); |
|||
} |
|||
|
|||
void *getSessionHandle() { |
|||
void *handle = static_cast<void *>(alib::session()); |
|||
return handle; |
|||
} |
|||
|
|||
PYBIND11_MODULE(_pybind, m) { |
|||
m.doc() = "pybind11 example plugin"; // optional module docstring
|
|||
|
|||
m.def("testfunc", &pyadpt::testfunc, "A function which adds two numbers"); |
|||
|
|||
py::class_<datta>(m, "datta").def(py::init<>()); |
|||
m.def("dataPointer", &dataPointer, py::return_value_policy::reference); |
|||
|
|||
// PEP_SESSION
|
|||
m.def("get_handle", &getSessionHandle); |
|||
|
|||
|
|||
// DYNAMIC_API void set_debug_color(PEP_SESSION session, int ansi_color);
|
|||
m.def("set_debug_color", (void (*)(void *, int))&::set_debug_color); |
|||
|
|||
// typedef struct _pEp_identity {
|
|||
// char *address; // C string with address UTF-8 encoded
|
|||
// char *fpr; // C string with fingerprint UTF-8 encoded
|
|||
// char *user_id; // C string with user ID UTF-8 encoded
|
|||
// // user_id MIGHT be set to "pEp_own_userId"
|
|||
// // (use PEP_OWN_USERID preprocessor define)
|
|||
// // if this is own user's identity.
|
|||
// // But it is not REQUIRED to be.
|
|||
// char *username; // C string with user name UTF-8 encoded
|
|||
// PEP_comm_type comm_type; // type of communication with this ID
|
|||
// char lang[3]; // language of conversation
|
|||
// // ISO 639-1 ALPHA-2, last byte is 0
|
|||
// bool me; // if this is the local user herself/himself
|
|||
// unsigned int major_ver; // highest version of pEp message received, if any
|
|||
// unsigned int minor_ver; // highest version of pEp message received, if any
|
|||
// PEP_enc_format enc_format; // Last specified format we encrypted to for this identity
|
|||
// identity_flags_t flags; // identity_flag1 | identity_flag2 | ...
|
|||
// } pEp_identity;
|
|||
|
|||
py::class_<pEp_identity>(m, "pEp_identity") |
|||
.def_readwrite("address", &::pEp_identity::address) |
|||
.def_readwrite("fpr", &::pEp_identity::fpr) |
|||
.def_readwrite("user_id", &::pEp_identity::user_id) |
|||
.def_readwrite("username", &::pEp_identity::username); |
|||
|
|||
|
|||
// DYNAMIC_API pEp_identity *new_identity(
|
|||
// const char *address, const char *fpr, const char *user_id,
|
|||
// const char *username
|
|||
// );
|
|||
m.def("new_identity", (pEp_identity *(*)(const char *address, const char *fpr, const char *user_id, const char *username))&::new_identity, py::return_value_policy::reference); |
|||
|
|||
// DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity);
|
|||
m.def("myself", (PEP_STATUS(*)(void *, pEp_identity *))&myself); |
|||
|
|||
} |
|||
|
|||
|
@ -1,36 +0,0 @@ |
|||
= Tests in this directory = |
|||
|
|||
$ HOME=$PWD python3 basic_doctest.py -v |
|||
do some basic tests of p≡p |
|||
|
|||
CAVEAT: set environment variable HOME to a test directory before executing |
|||
this test |
|||
|
|||
$ python3 sync_test.py |
|||
start two processes representing two devices and do a sync test |
|||
|
|||
Once started sync_handshake.py is creating a trace of all sent messages in |
|||
TestInbox. There's a file named Laptop or Phone, respectively, which is working |
|||
as a marker; the modification timestamp of this file is showing the mails being |
|||
considered as “already received”. If you delete the file and start i.e. |
|||
|
|||
$ cd Phone |
|||
$ rm ../TestInbox/Phone |
|||
$ HOME=$PWD lldb python3 -- ../sync_handshake.py -e Phone |
|||
|
|||
Then this side is doing a replay in the debugger. Using touch to set a |
|||
different timestamp on the marker will only partly replay. |
|||
|
|||
In order to work with IMAP you need to create a imap_settings.py file with the |
|||
following variables: |
|||
|
|||
IMAP_HOST = 'domain.ch' |
|||
IMAP_PORT = '993' |
|||
IMAP_USER = 'your_username' |
|||
IMAP_PWD = 'password' |
|||
IMAP_EMAIL = 'user@domain.ch' |
|||
|
|||
= Hint = |
|||
|
|||
installing termcolor and lxml will beautify the output |
|||
|
@ -1,23 +0,0 @@ |
|||
#!/usr/bin/env python3 |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
""" |
|||
>>> import pEp |
|||
>>> def message_to_send(msg): |
|||
... m, keys, rating, flags = msg.decrypt() |
|||
... try: |
|||
... m.attachments[0].decode() |
|||
... print("decode successfull") |
|||
... except UnicodeDecodeError as e: |
|||
... print("decode failed") |
|||
>>> pEp.message_to_send = message_to_send |
|||
>>> pEp.myself(pEp.Identity("")) |
|||
>>> pEp.key_reset_all_own_keys() |
|||
decode successfull |
|||
decode successfull |
|||
decode successfull |
|||
""" |
|||
|
|||
if __name__ == "__main__": |
|||
import doctest |
|||
doctest.testmod() |
@ -1,30 +0,0 @@ |
|||
-----BEGIN PGP PUBLIC KEY BLOCK----- |
|||
|
|||
mQENBF6lj68BCAC7dqBN0DIA+gRLHeLV5v96hs+YEOEw4oqjDGTuAbnyJ0omOmKu |
|||
8I3cT6hhGoAx61O5bVogiZ5i5MUa0sJcyJa3ACH5XucHmKCrXS1m6NXtWPDrAKvy |
|||
TaMmItcF5pSR8YvRimdZ+YxcekjDMhH1Afa8SODwpMGOM9OHfNiLtJ2DAbzFXZ7E |
|||
TbNZ1CPc9jTEb7MFVnQx9Q2zsxYIAg/C3TAbMrBm+n4UX1SRhoaNcxepEvGIp0DH |
|||
u+FbG3r520HmIcSJPt0LUf0MfF3AI+t2jVCeI1ht/cyAjKdm+MqHo7vH9yCftYgT |
|||
RlF5/+oyEv1twYfFW3zb5EOeuOsJHkdgOZlFABEBAAG0GWFsaWNlIDxhbGljZUBw |
|||
ZXB0ZXN0Lm9yZz6JAVQEEwEIAD4WIQRyQ/QYAVtywQnCbE0X6rVcaHJFmgUCXqWP |
|||
rwIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAX6rVcaHJFmgrk |
|||
B/wKW2frr+XvXr23fVg85S8S+dGEVRYbLgCehPS02y09dt4knJ7x9aHe1kGRDRYg |
|||
79hYGWcOeMMRn5MnQhUFSZIeWsXtnXzhFLRLALl3A/k+gt8cn7f2Riq2uWNFuUli |
|||
2pn+KjQduh8w+xA42OEW33UfucDWiSdoIx4cfd/SNwsUu1sS3fug62JPTzOeYeEq |
|||
QnKMMw+Cyjtq37oGaMDddWSTGurXDP7E36pkK7S1rmiiZNZZ+GyMtBIF5D0jYdMw |
|||
cwthE1N+v+Qh/1rJu2piDp12+vImDNdKP0jPHh8RDhZJlKqT5Ni+SbBYd1izs29O |
|||
KlqWzxsvmJkOwrfpEJk5XxATuQENBF6lj68BCADG2CblwipT9LtahZMrrO7d/+Vg |
|||
wh+u2ldFPRA7K37BDJkWqq2+czh/wgYEOpXhkgWLqj042+PqQwSb+quwjVv7cETI |
|||
TMW7/IViHr7rOh4JHsC92UJ74DCXYODdAwP6SYbdplgROmrT6LqRbrAwHRIz71ub |
|||
upM9dW1FpMV7MKceIfu4CNRcAiHNb/gz5ws5d+g+PicV4480jQQat1L/r+bDDX7P |
|||
sIiABdaZZgLhqEhyaEaEmARdm1Ken3Ce2faYwI6WkEGQsVmlklUq6coPRTYC2P6Y |
|||
uDNMLfMVAtLi+Qx0Ax1bNxtkJe71p1ysO6h3W+3unZ88zUNsZXB1qBhcnJNZABEB |
|||
AAGJATwEGAEIACYWIQRyQ/QYAVtywQnCbE0X6rVcaHJFmgUCXqWPrwIbDAUJA8Jn |
|||
AAAKCRAX6rVcaHJFmlPsB/wLHi7dzZ601cYIj3XZjCqEptFOZ9BSLXMLzzcfca2A |
|||
9ezoIGV0+LzwfAsTYRqi/AbQnhpoBhaE/tfnJKDFT+2+DBbCdDw7UuZXW4furW17 |
|||
inyXdt9ZAU0L1/5221FNmuNGI20RepX9HsDADeRzulU1DQ7PM0OBNqNxLJE+/59/ |
|||
QfEIgKrSPOQXlNtieXFPqwQGXR6Xa4no+7ma7hKPj2K8HwqAOp4S51Lwr+UnSC2J |
|||
sphDAZ6JhrnCCq12Q6blAONT9tM4uzxJE927VmFuqDIMik9tW310CNiUZWds+gN7 |
|||
Qp3iKQbnleDJMUWTuF8nOphG2ifQh2LG/MoR3LI5Y8Ml |
|||
=tIZY |
|||
-----END PGP PUBLIC KEY BLOCK----- |
@ -1,57 +0,0 @@ |
|||
-----BEGIN PGP PRIVATE KEY BLOCK----- |
|||
|
|||
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 |
|||
=V2ss |
|||
-----END PGP PRIVATE KEY BLOCK----- |
@ -1,51 +0,0 @@ |
|||
-----BEGIN PGP PUBLIC KEY BLOCK----- |
|||
|
|||
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 |
|||
ayrYTuGtZw16aERigF4lvjl4l0y9OSCagOrKzUSZ3KybJ+QO7kzOAJsAEQEAAYkC |
|||
PAQYAQgAJhYhBPgE++F4Hz4vYVj59wn7W9pyvlHBBQJepZF9AhsMBQkSzAMAAAoJ |
|||
EAn7W9pyvlHBeL4P/A0Gj66Xg3t3I3Y7xFzX4GRHR0DeERrN9OHlNfnJ/+gWQpZL |
|||
/mxG+cqvFe5n3UMtc/+LcZirrDPw/ZlzObSoeQXTsyRrZIOcz9W1Ttja3dVPR/i4 |
|||
dFn02CdqB8ibFr2OBbSqdhzkZLabcw7mfhPCW7cCN3gqBqyliIOCgvTJz4m/KkHC |
|||
xm9DhsQaPjHa//9Xmf/LsQuFEhQ0w0fQr0OPYjFHtCu2YxoenpaIGxKsdtIWsMAp |
|||
2T0TyAzpFnBiGVLaBrD1qJKy8hZQd4/3RWatn0oEffYxZTS7LomWFcSdOrpmXTCZ |
|||
KHZQoXFxMSBgFvx1FPjVM3DHUTfuQ41IvcT2hcZde636dJwI0spCaPSDXOKK5CHB |
|||
nRItJzcZLzIRNLWlE6S2kE8j/DZb9HeY+sgcQMNpVYOFwVvruhXM/j0eP5A1WQ0Z |
|||
fUkVjh5nkCgil4NHuFwWUH45/aDLOBjGoS7R1dzsOow+OMKCv45Um9W+PQ+8pZuc |
|||
bCj9uT22WgXOJN1aDKA0puUSaXYnQSN86kKJj6EBnT3aU64UKDV8dm1v5YLQOEqo |
|||
4g06JvosFCtun4pezH/uC5NYstAmZ3O7b5jxC3IQp+6pIXf+fVWwmG4lnsp3biT1 |
|||
7zFa6rwR9i3qsJw8qBQJb2hylt6gd6kWFzpG6vYQEkqt/rMikC3LaZB/vCQN |
|||
=C4RU |
|||
-----END PGP PUBLIC KEY BLOCK----- |
@ -1,105 +0,0 @@ |
|||
-----BEGIN PGP PRIVATE KEY BLOCK----- |
|||
|
|||
lQcYBF6lkX0BEACua4UKu0iBZmz1/JUr3zg3oBldsTspv5CUpcK1YbROa9vrAWsK |
|||
OMBfJBAvdNPN9FQHAtEChxjSkRgI0ug48xuFHwEtEYyAV3G1cQxu9aJfyb3pr1g/ |
|||
TTKzr8CK5wESZVyuDgDt7ZVWE3Z4jXI9zGS4pGbfOP2U0FL6a/nHlUE1FrgNt2dx |
|||
cda/arPX+xuUaLj6u4jMcy4kfs7p1H3TxBq8RO8gy2oEPIl31zIYOGH8a/3l0Mga |
|||
XRRrGQ14m3Ly3WuK4BPzahvtPUXXFxC1X1fxbU717XQVBBGO8z1IEXuoEYeJAKKz |
|||
ALBBUyGVxhcLclyFxm6CzpEMUp+F7xVY8C5yi5iRdSENllCOdtxdzUOay5qhASyK |
|||
BBGAFxkQjjngJW+jfonmZFPlkc+KEQCIkzHL4oOQ2Qvy9+9oWIkCwBQIBwexNMGO |
|||
H5r+HJ5RSBjPfuVNJen3rZ3Ky0KcQ5oJkB/az74CabTLC9Iml+wPrAzabzTKaksI |
|||
4V4zQVJ5SYvYqKuSdylqZ8vWVU8tfJZqcx7Mc4t75tDUO6ODtgXl6RLK2dSBQi1+ |
|||
237+xW+b4r+lx4oXGBM4CD0IAO9D1I2UrVsfxJqCiJimnNXgkoFsjyYK0UntUVra |
|||
brJMSIr8yuvZnt6mvlrG2uQMnz9b+GOkJk3nZpmUD4temZgtJUyofJOooQARAQAB |
|||
AA/8CIkZeHt5d7T9UGe9Hb8C6hygcSiAW9wp5U8GrB1Xwgi0OULCAWeNPnquJ2xh |
|||
BcYBq1rUw09nhGfLqc7hxLuyP+hTBJNvG+7A5p9de5FIvMWg0MP0c8XsMm/qN8Hz |
|||
QvpejTlWi/jhoys4/nr0OW2nC4QmxqDBhBv9G4/XfZANIgh2bFwVKK+TUfMU/FT9 |
|||
C10OmbKTZhHy6EqjsedksE17U3Wk0Cbe4s3a762XytNONENNUwb4a+sx2cXe62U2 |
|||
vFzf65Voqd5U9zNVl3Tjq+86XLBmj1FrVLCfcq6Y8/hrDpVWW9Asph7lVo+3Z97K |
|||
95Pv+YSgRDAmAq4zwU2rGUWeYtwzwmoUXvQILruCoh3EVfX3PfN9k2JsDzTrhSH1 |
|||
fxzD0nMTIcZvyS7Oguiv4zqjIc7nfnOXmZn5dhWUh2PH+aVA9GCb1X1qAAp1pHU0 |
|||
oqSTeo4yse++l68TsSROz+MPsTnVJ/L16VcohXCzauyMqiVjRyEOzZiyue6WWoFX |
|||
cAYCzuT8M5/qvoHoMcrjTn9nbhPgAgdyIv2XzyJ2RyxueUZI8SQdPoyViEtsF1B/ |
|||
dZOLB6lE1G7IH/sFjrBvLjswsWEK8o/CtuakEAh2e0rz2mPeVnxKBq7nEWAsHq6B |
|||
0rbWINtP+QLHw8nZKRuakjdoxkJ3EzzBawsUE7gyApOeNbsIAMDl/ORi0TKc+l1c |
|||
L/ak4rGnAIBMMJWpI0kReDHxp3blEc8QYx8yYoHvPOCM1iZr5YZMKhCMEW60Qk0H |
|||
oVSGinbYQcMmEU8bDbkOmEogSPQzS1CnmWodz6SdWyoaXYFzukL+FlWDm9Zpp+SH |
|||
kkPKiTVlnDGAui1zWgd1D/YstI+QWbJyBFddAvkUmZ5L6AyObbiVeag3dG2RzRlL |
|||
yaWn4aTa5dVI+49AMbdiX8Bhv6ASviIdYpkea+mIyS8SXeu9AZnK/2XhDCDPX2wN |
|||
2TEQ44AyEOb4mXBaid5shTQaV4bs1vDq19XA2pErLPT4p1XNT9+REnl8kjLZyhMB |
|||
pswSG0MIAOd6FY5aMM9Q9wJjzkl5KIugpWg8buBzOKJWB1O0TpXNS7r5yL+7QF0u |
|||
S9fToq9QrGTQH9QcAlmWCKCkcBG2HK6QBZiEQ9eaygZUMiVvWf96NwUQwwr1I0LK |
|||
2/dTWxNSgUBRJdH6bfuCSFnzbSqQP0MI49QI3/2bRQob53DiKj+X9pmNUvo5+gju |
|||
u0RO15fOXbHk+X6W1p0kNrQiiEjfpXilajlxlXiKIqPioaIV5PTnfksTuVdlDsGW |
|||
5oMdh8xpskUgIvzVUu+wdOVGuOpUh+jNR5r3p6LSLtiGgzFnts1/SvHc1lXJw35Z |
|||
+j5kOvvEIkA+txtEXHqcDarn+t4q5EsIAI3HIMAnUSjvdIjj48ZTokC7JCo8y1qK |
|||
J5S3VksBZ/fDLBMKg5fiZ9+uirdUPimVc2C22IVPtq3b63coIfXzoOsx96PWn+8R |
|||
W8cRUk8Bu8mhD1HJMY0nVtpXwldsjl5rv/ERFVfeEDlBPHsHRcT0VpKIhkWR21wW |
|||
2rBvJCStrurdNS5WAFBK9wpP7E2N11tUY/RRzyVfnKQImiHRJvLMbYgR5m+cj8mC |
|||
k7N1KLC+ON6YKgjhwiIg25SDQjXPkhICvthJUdouTmJqPnFKRdfrYPDNhgYUFQTH |
|||
pyybwDPpUqjagIhghrm5bUaZkIcAg6Db6pYPUBiyW7DUMvnsHibWEV2At7QVQm9i |
|||
IDxib2JAcGVwdGVzdC5vcmc+iQJUBBMBCAA+FiEE+AT74XgfPi9hWPn3Cftb2nK+ |
|||
UcEFAl6lkX0CGwMFCRLMAwAFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQCftb |
|||
2nK+UcGg9Q//fqM9bNbMjcYRWNrevCf3h9oY3RxXbHL+HXEEE4U2yd3in1lbw7rY |
|||
AmE+lGDyWA/QGZ7ry4RZc5xHiPdqZs30GKzd0IRgFRaY67yeEoh9o6Dnrl5tvXPz |
|||
MnhPJTTzFbBU9TcWbgUkWXfMKtoIMefYbagbRgQkg+APP5qQGlrbdsviaIp5Kw+K |
|||
sThx8bPvqTPfoZlYb0Q3YnwPOZbe4PJ/S8fDLdOIyhqkM5aStRShHA6k4oV6JAii |
|||
xw8EsLVOG5FqLKcQpOkyratZglP+8a0GKF1cY6KtBwtz5KNDa1xjf+JQvNUmWXQQ |
|||
2XnAyBoXnUeCSGzYXVHpvowm4h2kKZ4I7ORlyWJJO+VI5dH6QqGKnRGgkJMpJr/l |
|||
psQMMNEtWgqzbZChYYpujGw7eltoEiiywIfOx756dRaAjbecQISW2RrhT3mVKf42 |
|||
6DUNUTdKgYJxV0abhDwsxddBdy0+33sZIx7AGT+wVLheCLhGsIf6KnnHP6NVbLKO |
|||
NGRt4WDF67BsPTFQxJxjHe/TRB5OXGhHqGG2NBPqyDNxbS4Wi8UBhk9CQzyf1ZSf |
|||
RB6BrGfW7hY1nRrrC47rd/owCUelHiP/SDdWSAeZIl8wbqWvt4ZDNT7EJXWt+GlV |
|||
ry6APbf3vbKdLgq6UvZeDLY4aw5j63nsvLQFWjejmmfRyswDD64d9E2dBxcEXqWR |
|||
fQEQAL3juiA2Sfj3CYZtwQ3aheOequalb6KrQZyEBwbuE9h8g8M47n4LajURywAw |
|||
PetIhMR7mVUnj3Pfs2H6585VxXkMww5Vhgyo7SsSrBFFEBD1CRIspZGMivSYDwl0 |
|||
qbSwlsjKuMrt4C1NKGBUhfTCAQBuFKJasg3j/+AYXOGxqKoWXnUX8h68A2/k6LpQ |
|||
pgXGP5mFck+OVNko9DBPDwQjj2FAUILZ9KPqlGPWObk24RtEJpkJry4zybU0Fi2/ |
|||
Oi00KOh6nnxI3FcvxzbHFqUMqCusqOdbZrgk5ffIfVRO6Sw/YhlWzEwKRR320lcE |
|||
JipCag+dsh6dfR60a/6+OOWCKO3VRFB7ljUuT7O8he1MWRA/Yxpcz1Gf6CJlU/eK |
|||
CAPZwPC0/k9PdbRkLspWkPjKWnr4/0cSVDZQzBpBLm2UuqUVrSEo4BNh40sqDEw4 |
|||
MrApnLEo1tctxOKVWurf0uewVV4EnwlW3QuwAFPQQ3ouOmEUiKaiY937dgHCE+2S |
|||
zlXfBojZIuzqjSQVBGm/WbjPp0KXWZYc0gqvH++ytSQcd/RuaRLkRdZRtsUvzRPK |
|||
cEI6K4nk9TZ/rEJTLE9as/BFUC8IpPb5dPm0VkoRue/lbZJtmU1OkRJYb2sq2E7h |
|||
rWcNemhEYoBeJb45eJdMvTkgmoDqys1EmdysmyfkDu5MzgCbABEBAAEAD/jZZ8fL |
|||
TMMxYgufXW/3hh/3+2Svrbminj1m28JjEzFyXemw5sqNuFDHceR5n47ehdvistNa |
|||
+Dz47aXAO2qRUjveqKRD3qcbPeayg5Swl3tNiHGNdvbl+k/qVC4WWJUnZKBxdtuC |
|||
R9cVoFrmvEVvDq99TotRVri4Lp9GcwSxYjZshi/SeeTVGDpwyCR5LHaCWSt35mrg |
|||
d8gTpk/tZcnlDNGb04bAsDCBe16c747z/2EhvP7aa7wMED756vV5nipKMIdycPE2 |
|||
WpuE0HvFIfh+ZeW+gaNGcqwOwjAjARuwHkI/GewdSfZqTCSi3Q4oxX25fh1Ww7Xe |
|||
V3GcaShvZyeKA8ijVkrTNzr3hwNL/rKtxaI5RoXbMSLTt1ZtIDuOLPEoY68hd9D2 |
|||
W6uncOar6DchJCFefuxh+CRkzv/vNU3F/yYyVxnHY3k+ODxWBJfNHnH3EN3U+C7T |
|||
wIF3yOSoZlsKlFeE4+PAVJO5/G/V1SrfILyklsge5EGq88VY1KBL9/K2VBQyh9jm |
|||
/CnYE0wKeaXj5mm7n8vopS44Nom+Ne7AS6/bFloIZNpPxHsoLKGiNcCT9/w11Bt0 |
|||
3IRXh8DFATsmiy1Gz8I1QBH+EugkXvMzVP/+X8XYt7GjH3W59e6V5QDacmKypHXG |
|||
LyCXVrw0plJBIHOu3pdsuPjgdazRgGlDXH1RCADKRPWSa9mSSLBU2sGgZf5TOkTj |
|||
NVHvaO5+v/nVk7PI4pWj9psf21n4IvjAbFKiX7F7qY0SrbOzoG5E25fum85S3qH5 |
|||
O363NtvsteZ9ftvE4jSVU412CZ5ue0IK/RKru0fnk+HqrZBaQnN03zcobQSSiA3A |
|||
+3DfGRs9cTbj4VOdiVKCugLgU5rWXaWxu9G2qaHxZTiCH3Rlsd2HDsKjbwRJt9uU |
|||
viwgQVGTXXBk7CaeIqA+ieUvKXOm/Uo8V1fwb8Kr9YAxWhEhdSl+UMLxwnCrMbPs |
|||
B1nGYjrRrcPrl8RkeVLjCKzF0fAWcfybZcx5Q2ztDrIhrPZZ7L+GwQ4a61rLCADw |
|||
VOVts9mBqu71x2eztkiXOOCN9YRREBD+5SX2ZmVv8pn+pa3rcoO5jtIw1nIjYrcf |
|||
+Pzovrx6PUcC10Lp4NTvnZGJjz3auvjYFSLQlbXmwN1R5+i8xMTnD3xhW24CyEqq |
|||
WwkvSH/SUt0QiXdB4t9/n2B7EBJEa1AGtirEBgFnJDAgviGmErsVTXzkwBVvMdRS |
|||
hF037EN99aoadvy+Ft4sXy8l4VxEKAuJwUvX8lgejmPUbulnl63gxKMoUXRIA24I |
|||
G308udV+ndwed2/1gJLj4tIqbc+dO9+2qJ/mdcHih2B4W9Ios+c7ztdSSiUUE2EY |
|||
e9PD/LWO5u/wn+u/gidxB/401GdyBsDJxXXSwZkI9UXBqPWkKRybkoDvyqLmXGQ+ |
|||
v6ehezJ7p/hJzFYYZHAshKEvf17rd0sn4kwX8vrboZJ9W9UYdixBPRdboi39qHY6 |
|||
i8OiYZTIREx7yy02Rk0IJ34VyGX5W7N/NxyEql0JHczITPb9HsFnBE6u5ZLYDIQ0 |
|||
/OLXE4aRhIZ9uhdwFc8J1WDhC4XVggQxIoiTQNQeHLBeXAaQ+PuXGOfNOSrs6I25 |
|||
ZrVJXEecjQlGB3r45c7Z4UrNPsV/m263dDm5RZnEe7bGHqHmBR/Upa18zoR0RyO3 |
|||
D9f4hNuydBgWMZXn/MDyi9v4aOcZiTI+5FVVj18rxjh0oo6JAjwEGAEIACYWIQT4 |
|||
BPvheB8+L2FY+fcJ+1vacr5RwQUCXqWRfQIbDAUJEswDAAAKCRAJ+1vacr5RwXi+ |
|||
D/wNBo+ul4N7dyN2O8Rc1+BkR0dA3hEazfTh5TX5yf/oFkKWS/5sRvnKrxXuZ91D |
|||
LXP/i3GYq6wz8P2Zczm0qHkF07Mka2SDnM/VtU7Y2t3VT0f4uHRZ9NgnagfImxa9 |
|||
jgW0qnYc5GS2m3MO5n4Twlu3Ajd4KgaspYiDgoL0yc+JvypBwsZvQ4bEGj4x2v// |
|||
V5n/y7ELhRIUNMNH0K9Dj2IxR7QrtmMaHp6WiBsSrHbSFrDAKdk9E8gM6RZwYhlS |
|||
2gaw9aiSsvIWUHeP90VmrZ9KBH32MWU0uy6JlhXEnTq6Zl0wmSh2UKFxcTEgYBb8 |
|||
dRT41TNwx1E37kONSL3E9oXGXXut+nScCNLKQmj0g1ziiuQhwZ0SLSc3GS8yETS1 |
|||
pROktpBPI/w2W/R3mPrIHEDDaVWDhcFb67oVzP49Hj+QNVkNGX1JFY4eZ5AoIpeD |
|||
R7hcFlB+Of2gyzgYxqEu0dXc7DqMPjjCgr+OVJvVvj0PvKWbnGwo/bk9tloFziTd |
|||
WgygNKblEml2J0EjfOpCiY+hAZ092lOuFCg1fHZtb+WC0DhKqOINOib6LBQrbp+K |
|||
Xsx/7guTWLLQJmdzu2+Y8QtyEKfuqSF3/n1VsJhuJZ7Kd24k9e8xWuq8EfYt6rCc |
|||
PKgUCW9ocpbeoHepFhc6Rur2EBJKrf6zIpAty2mQf7wkDQ== |
|||
=loxY |
|||
-----END PGP PRIVATE KEY BLOCK----- |
@ -1,53 +0,0 @@ |
|||
#!/usr/bin/env python3 |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
# Regression test against API breakage |
|||
# colors used to be represented as a simple int |
|||
# NEW: colors are represented by colorvalue enum |
|||
# Test for equal resolution of colors using int (OLD) vs using colorvalue (NEW) |
|||
|
|||
print("Running PYADPT-55") |
|||
""" |
|||
>>> resolveOLDvsNEW(pEp.colorvalue.no_color) |
|||
True |
|||
>>> resolveOLDvsNEW(pEp.colorvalue.yellow) |
|||
True |
|||
>>> resolveOLDvsNEW(pEp.colorvalue.green) |
|||
True |
|||
>>> resolveOLDvsNEW(pEp.colorvalue.red) |
|||
True |
|||
""" |
|||
|
|||
|
|||
import pEp |
|||
# resolves a color represented as int, the OLD way, as an int. |
|||
# returns colorvalue |
|||
def resolveColorOLD(col): |
|||
ret = pEp.colorvalue() |
|||
|
|||
c = pEp.colorvalue(col) |
|||
if(c == 0): |
|||
ret = pEp.colorvalue.no_color |
|||
if(c == 1): |
|||
ret = pEp.colorvalue.yellow |
|||
if(c == 2): |
|||
ret = pEp.colorvalue.green |
|||
if(c == -1): |
|||
ret = pEp.colorvalue.red |
|||
|
|||
return ret |
|||
|
|||
# resolves a color represented as colorvalue, the NEW way |
|||
# returns colorvalue |
|||
def resolveColorNEW(col): |
|||
c = pEp.colorvalue(col) |
|||
return c |
|||
|
|||
# Compare color resolution OLD vs NEW way |
|||
# return True if results are equal |
|||
def resolveOLDvsNEW(col): |
|||
return resolveColorOLD(col) == resolveColorNEW(col) |
|||
|
|||
if __name__ == "__main__": |
|||
import doctest |
|||
doctest.testmod() |
@ -1,100 +0,0 @@ |
|||
import imaplib |
|||
import pathlib |
|||
import time |
|||
import os |
|||
from secrets import token_urlsafe |
|||
|
|||
try: |
|||
import imap_settings as settings |
|||
except: |
|||
raise ValueError("Imap settings file not found, please check the readme") |
|||
|
|||
|
|||
def connect(): |
|||
"connect to the IMAP server Inbox" |
|||
server = imaplib.IMAP4_SSL(settings.IMAP_HOST) |
|||
server.login(settings.IMAP_USER, settings.IMAP_PWD) |
|||
tmp, data = server.select('Inbox') |
|||
|
|||
# When you connect to the inbox one of the parameters returned is the |
|||
# current number of messages in it |
|||
if os.environ.get('NUMMESSAGES') is None: |
|||
os.environ["NUMMESSAGES"] = data[0].decode("UTF-8") |
|||
|
|||
return server |
|||
|
|||
def bytesmessage_to_string(msg): |
|||
"converts bytes-like message to string" |
|||
if type(msg) is bytes: |
|||
msg = msg.decode("UTF-8").rstrip() |
|||
return msg |
|||
else: |
|||
return str(msg) |
|||
|
|||
def send(inbox, msg): |
|||
"send msg to inbox in MIME format" |
|||
|
|||
server = connect() |
|||
tmp, data = server.append(inbox, flags='', date_time=time.time(), message=str(msg).encode("UTF-8")) |
|||
server.close() |
|||
|
|||
|
|||
def recv_all(): |
|||
"""receive a list of all MIME messages from inbox newer than the last message when first connected""" |
|||
|
|||
server = connect() |
|||
r = [] |
|||
|
|||
tmp, data = server.search(None, 'ALL') |
|||
|
|||
oldermsgid = os.environ.get('NUMMESSAGES') |
|||
|
|||
for num in data[0].split(): |
|||
if int(num) >= int(oldermsgid): |
|||
tmp, data = server.fetch(num, '(RFC822)') |
|||
msg = bytesmessage_to_string(data[0][1]) |
|||
r.append((num, msg)) |
|||
os.environ["NUMMESSAGES"] = num.decode("UTF-8") |
|||
|
|||
server.close() |
|||
|
|||
return r |
|||
|
|||
|
|||
def clean_inbox(): |
|||
"""clean all messsages from IMAP inbox""" |
|||
print('cleaning IMAP...') |
|||
server = connect() |
|||
tmp, data = server.search(None, 'ALL') |
|||
for num in data[0].split(): |
|||
server.store(num, '+FLAGS', '\\Deleted') |
|||
server.expunge() |
|||
server.close() |
|||
print('IMAP inbox empty.') |
|||
|
|||
|
|||
def backup_inbox(): |
|||
"""copy all messsages from IMAP to local backup folder""" |
|||
server = connect() |
|||
tmp, data = server.search(None, 'ALL') |
|||
for num in data[0].split(): |
|||
tmp, data = server.fetch(num, '(RFC822 BODY[HEADER])') |
|||
device = str(data[0][1]).split('From: "')[1].split(' of')[0] |
|||
name = device + "_" + token_urlsafe(16) + ".eml" |
|||
msg = bytesmessage_to_string(data[0][1]) |
|||
with open(os.path.join('Backup/TestInbox',name), "wb") as f: |
|||
f.write(str(msg).encode()) |
|||
|
|||
server.close() |
|||
|
|||
def restore_inbox(): |
|||
"""copy all the messages from the Backup folder to the IMAP inbox""" |
|||
server = connect() |
|||
backups = pathlib.Path("./Backup/TestInbox") |
|||
emails = backups.glob("*.eml") |
|||
l = [ path for path in emails ] |
|||
for p in l: |
|||
with open(p, "rb") as f: |
|||
tmp, data = server.append("Inbox", flags='', date_time=p.stat().st_ctime, message=f.read(-1)) |
|||
|
|||
server.close() |
@ -1,109 +0,0 @@ |
|||
# vim: set fileencoding=utf-8 : |
|||
|
|||
"""provide a trivial way to send messages between processes |
|||
|
|||
messages are being sent as files to an inbox, which is a path of a directory, |
|||
using a filename as a marker |
|||
|
|||
recv_all() is delivering all messages, which are newer than the marker file |
|||
after completion reading is touching the marker file |
|||
|
|||
to re-read messages touch the marker file with an older timestamp or just |
|||
delete the marker file to re-read all messages |
|||
|
|||
""" |
|||
|
|||
# Minimail 1.2 |
|||
# Copyleft 2019, 2020, p≡p foundation |
|||
|
|||
# this file is under GNU General Public License 3.0 |
|||
|
|||
|
|||
import os |
|||
from secrets import token_urlsafe |
|||
from time import sleep |
|||
from random import random |
|||
|
|||
|
|||
# set timing to None for random timing |
|||
timing = None |
|||
|
|||
|
|||
def snooze(): |
|||
if timing is None: |
|||
sleep(random()/2) |
|||
else: |
|||
sleep(timing) |
|||
|
|||
def unlock(inbox): |
|||
"clear the inbox from lockfile" |
|||
|
|||
lockfile = inbox / "lock" |
|||
try: |
|||
lockfile.unlink() |
|||
except: |
|||
pass |
|||
|
|||
|
|||
class Lock: |
|||
"lock inbox context to be used by with statement" |
|||
|
|||
def __init__(self, inbox): |
|||
self.inbox = inbox |
|||
|
|||
def __exit__(self, *exc): |
|||
unlock(self.inbox) |
|||
|
|||
def __enter__(self): |
|||
lockfile = self.inbox / "lock" |
|||
while lockfile.is_file(): |
|||
snooze() |
|||
lockfile.touch() |
|||
|
|||
|
|||
def send(inbox, msg, marker): |
|||
"send msg to inbox in MIME format" |
|||
|
|||
snooze() |
|||
with Lock(inbox): |
|||
name = marker + "_" + token_urlsafe(16) + ".eml" |
|||
with open(inbox / name, "wb") as f: |
|||
f.write(str(msg).encode()) |
|||
|
|||
|
|||
def newer(file, stamp): |
|||
"return True if file is newer than timestamp stamp" |
|||
|
|||
if not file.is_file(): |
|||
return False |
|||
|
|||
if stamp is None: |
|||
return True |
|||
|
|||
stat = file.stat() |
|||
return stat.st_mtime > stamp.st_mtime |
|||
|
|||
|
|||
def recv_all(inbox, marker): |
|||
"""receive a list of new MIME messages from inbox, which are newer than the |
|||
marker file""" |
|||
|
|||
r = [] |
|||
while not r: |
|||
with Lock(inbox): |
|||
try: |
|||
stamp = (inbox / marker).stat() |
|||
except: |
|||
stamp = None |
|||
l = [ path for path in inbox.glob("*.eml") ] |
|||
(inbox / marker).touch(exist_ok=True) |
|||
for p in reversed(l): |
|||
if newer(p, stamp): |
|||
with open(p, "rb") as f: |
|||
txt = f.read(-1) |
|||
r.append((p, txt)) |
|||
if not r: |
|||
snooze() |
|||
|
|||
return r |
|||
|
@ -1,21 +0,0 @@ |
|||
#!/usr/bin/env python3 |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
# This test is related to jira issue PYADPT-57 - key_mistrusted |
|||
# When key_mistrusted on own key (that has a private), a key revocation is being performed |
|||
# So, this test just proves the revocation by showing fpr before and after key_mistrusted() |
|||
|
|||
""" |
|||
>>> alice = pEp.Identity("alice@peptest.org", "23") |
|||
>>> pEp.myself(alice) |
|||
>>> alice.fpr |
|||
>>> alice.key_mistrusted() |
|||
>>> pEp.myself(alice) |
|||
>>> alice.fpr |
|||
""" |
|||
|
|||
import pEp; |
|||
|
|||
if __name__ == "__main__": |
|||
import doctest |
|||
doctest.testmod() |
@ -1,17 +0,0 @@ |
|||
#!/usr/bin/env python3 |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
# This test is related to jira issue PYADPT-58 - export keys |
|||
|
|||
""" |
|||
>>> alice = pEp.Identity("alice@peptest.org", "23") |
|||
>>> pEp.myself(alice) |
|||
>>> pEp.export_key(alice) |
|||
>>> pEp.export_secret_key(alice) |
|||
""" |
|||
|
|||
import pEp; |
|||
|
|||
if __name__ == "__main__": |
|||
import doctest |
|||
doctest.testmod() |
@ -1,47 +0,0 @@ |
|||
#!/usr/bin/env python3 |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import pEp |
|||
import time |
|||
|
|||
def message_to_send(msg): |
|||
print("User defined message_to_send() called") |
|||
m, keys, rating, flags = msg.decrypt() |
|||
try: |
|||
print(m.attachments[0].decode()) |
|||
except UnicodeDecodeError as e: |
|||
print("decode failed") |
|||
|
|||
def notify_handshake(me, partner, signal): |
|||
print("User defined notify_handshake() called") |
|||
print(me) |
|||
print(partner) |
|||
print(signal) |
|||
|
|||
def start_stop_sync(duration): |
|||
pEp.start_sync() |
|||
time.sleep(duration) |
|||
pEp.shutdown_sync() |
|||
|
|||
|
|||
alice = pEp.Identity("test@alice.com", "alice", "23") |
|||
pEp.myself(alice) |
|||
print(alice.fpr) |
|||
|
|||
dir(pEp) |
|||
|
|||
# test default callback |
|||
start_stop_sync(1) |
|||
|
|||
# test user defined callback |
|||
pEp.message_to_send = message_to_send |
|||
# pEp.notify_handshake = notify_handshake |
|||
|
|||
start_stop_sync(1) |
|||
|
|||
# pEp.start_sync() |
|||
# while(True): |
|||
# print("is_sync_active: {}".format(pEp.is_sync_active())) |
|||
# time.sleep(3) |
|||
# pEp.key_reset_all_own_keys() |
|||
# time.sleep(3) |
@ -1,280 +0,0 @@ |
|||
#!/usr/bin/env python3 |
|||
# -*- coding: utf-8 -*- |
|||
# vim: set fileencoding=utf-8 : |
|||
|
|||
"""start a handshake test for one simulated device |
|||
|
|||
this is being started once per device by sync_test.py |
|||
you can use this manually for debugging purposes |
|||
|
|||
For debugging try: |
|||
|
|||
$ cd $DEV && HOME=$PWD lldb python3 -- ../sync_handshake.py -e $DEV |
|||
|
|||
""" |
|||
|
|||
# Sync test 2.0 |
|||
# Copyleft 2018, 2019, p≡p foundation |
|||
|
|||
# this file is under GNU General Public License 3.0 |
|||
|
|||
|
|||
import pathlib |
|||
import os |
|||
import sys |
|||
import re |
|||
import pEp |
|||
import minimail |
|||
|
|||
from datetime import datetime |
|||
from time import sleep |
|||
|
|||
try: |
|||
from termcolor import colored |
|||
except: |
|||
colored = lambda x, y: x |
|||
|
|||
try: |
|||
from lxml import etree |
|||
from lxml import objectify |
|||
except: |
|||
etree = None |
|||
|
|||
|
|||
inbox = pathlib.Path("..") / "TestInbox" |
|||
device_name = "" |
|||
output = print |
|||
multithreaded = False |
|||
|
|||
DONT_TRIGGER_SYNC = 0x200 |
|||
SYNC_HANDSHAKE_ACCEPTED = 0 |
|||
SYNC_HANDSHAKE_REJECTED = 1 |
|||
|
|||
the_end = False |
|||
end_on = [ |
|||
pEp.sync_handshake_signal.SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED, |
|||
pEp.sync_handshake_signal.SYNC_NOTIFY_ACCEPTED_GROUP_CREATED, |
|||
pEp.sync_handshake_signal.SYNC_NOTIFY_ACCEPTED_DEVICE_ACCEPTED, |
|||
] |
|||
|
|||
|
|||
def print_msg(p): |
|||
if isinstance(p, pathlib.Path): |
|||
if p.name[:5] == "Phone": |
|||
color = "red" |
|||
elif p.name[:6] == "Laptop": |
|||
color = "green" |
|||
else: |
|||
color = "cyan" |
|||
with open(p, "r") as f: |
|||
t = f.read(-1) |
|||
msg = pEp.Message(t) |
|||
print("\n" + colored(p.name, color)) |
|||
print(colored(str(datetime.fromtimestamp(p.stat().st_mtime)), color)) |
|||
elif isinstance(p, pEp.Message): |
|||
msg = p |
|||
else: |
|||
raise TypeError("print_msg(): pathlib.Path and pEp.Message supported, but " |
|||
+ str(type(p)) + " delivered") |
|||
|
|||
m = re.search("<keysync>(.*)</keysync>", msg.opt_fields["pEp.sync"].replace("\n", " ")) |
|||
if m: |
|||
if etree: |
|||
tree = objectify.fromstring(m.group(1).replace("\r", "")) |
|||
text = etree.tostring(tree, pretty_print=True, encoding="unicode") |
|||
else: |
|||
text = m.group(1).replace("\r", "").strip() |
|||
while text.count(" "): |
|||
text = text.replace(" ", " ") |
|||
print(text) |
|||
|
|||
|
|||
def messageToSend(msg): |
|||
msg = add_debug_info(msg) |
|||
minimail.send(inbox, msg, device_name) |
|||
|
|||
def messageImapToSend(msg): |
|||
import miniimap |
|||
msg = add_debug_info(msg) |
|||
miniimap.send('Inbox', msg) |
|||
|
|||
def add_debug_info(msg): |
|||
if msg.enc_format: |
|||
m, keys, rating, flags = msg.decrypt(DONT_TRIGGER_SYNC) |
|||
else: |
|||
m = msg |
|||
try: |
|||
text = "<!-- sending from " + device_name + " -->\n" + m.attachments[0].decode() |
|||
except UnicodeDecodeError as e: |
|||
text = "<!-- sending from " + device_name + " -->\n *** NO DECODER AVAILABLE FOR THIS MESSAGE TYPE ***\n" |
|||
output(text) |
|||
msg.opt_fields = { "pEp.sync": text } |
|||
return msg |
|||
|
|||
|
|||
class UserInterface(pEp.UserInterface): |
|||
def notifyHandshake(self, me, partner, signal): |
|||
print(colored(str(signal), "yellow"), end=" ") |
|||
output("on " + device_name + "" if not me.fpr else |
|||
"for identities " + str(me.fpr) + " " + str(partner.fpr)) |
|||
if me.fpr and partner.fpr: |
|||
assert me.fpr != partner.fpr |
|||
|
|||
if signal in ( |
|||
pEp.sync_handshake_signal.SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE, |
|||
pEp.sync_handshake_signal.SYNC_NOTIFY_INIT_ADD_OUR_DEVICE, |
|||
pEp.sync_handshake_signal.SYNC_NOTIFY_INIT_FORM_GROUP |
|||
): |
|||
if isinstance(end_on, list): |
|||
end_on.extend([ |
|||
pEp.sync_handshake_signal.SYNC_NOTIFY_SOLE, |
|||
pEp.sync_handshake_signal.SYNC_NOTIFY_IN_GROUP, |
|||
]) |
|||
sleep(.5) # user is reading message |
|||
try: |
|||
if not options.noanswer: |
|||
if options.reject: |
|||
self.deliverHandshakeResult(SYNC_HANDSHAKE_REJECTED) |
|||
else: |
|||
self.deliverHandshakeResult(SYNC_HANDSHAKE_ACCEPTED) |
|||
|
|||
except NameError: |
|||
self.deliverHandshakeResult(SYNC_HANDSHAKE_ACCEPTED) |
|||
if signal in end_on: |
|||
global the_end |
|||
the_end = True |
|||
|
|||
|
|||
def shutdown_sync(): |
|||
pEp.shutdown_sync() |
|||
|
|||
|
|||
def run(name, color=None, imap=False, own_ident=1, leave=False): |
|||
|
|||
global device_name |
|||
device_name = name |
|||
|
|||
if color: |
|||
global output |
|||
output = lambda x: print(colored(x, color)) |
|||
if color == "red": |
|||
pEp.debug_color(31) |
|||
elif color == "green": |
|||
pEp.debug_color(32) |
|||
elif color == "cyan": |
|||
pEp.debug_color(36) |
|||
|
|||
if imap: |
|||
import miniimap |
|||
import imap_settings |
|||
|
|||
me = pEp.Identity(imap_settings.IMAP_EMAIL, name + " of " + imap_settings.IMAP_USER, name) |
|||
pEp.myself(me) |
|||
pEp.messageToSend = messageImapToSend |
|||
else: |
|||
me = pEp.Identity("alice@peptest.ch", name + " of Alice Neuman", name) |
|||
pEp.myself(me) |
|||
|
|||
if own_ident >= 2: |
|||
me2 = pEp.Identity("alice@pep.security", name + " of Alice Neuman", name) |
|||
pEp.myself(me2) |
|||
|
|||
if own_ident == 3: |
|||
me3 = pEp.Identity("alice@pep.foundation", name + " of Alice Neuman", name) |
|||
pEp.myself(me3) |
|||
|
|||
pEp.messageToSend = messageToSend |
|||
|
|||
if multithreaded: |
|||
from threading import Thread |
|||
def sync_thread(): |
|||
print(colored("********* ", "yellow") + colored("sync_thread entered", color)) |
|||
ui = UserInterface() |
|||
print(colored("********* ", "yellow") + colored("UserInterface object created", color)) |
|||
pEp.do_sync_protocol() |
|||
print(colored("********* ", "yellow") + colored("leaving sync_thread", color)) |
|||
sync = Thread(target=sync_thread) |
|||
sync.start() |
|||
else: |
|||
pEp.script_is_implementing_sync() |
|||
sync = None |
|||
ui = UserInterface() |
|||
|
|||
try: |
|||
if leave: |
|||
pEp.leave_device_group() |
|||
|
|||
while not the_end: |
|||
if pEp.is_sync_active(): |
|||
pass # we could react on this |
|||
if imap: |
|||
l = miniimap.recv_all() |
|||
else: |
|||
l = minimail.recv_all(inbox, name) |
|||
for n, m in l: |
|||
msg = pEp.Message(m) |
|||
output("*** Reading") |
|||
print_msg(msg) |
|||
msg2, keys, rating, flags = msg.decrypt() |
|||
|
|||
except KeyboardInterrupt: |
|||
shutdown_sync() |
|||
sys.exit() |
|||
|
|||
|
|||
if __name__=="__main__": |
|||
from optparse import OptionParser |
|||
|
|||
optParser = OptionParser() |
|||
optParser.description = __doc__ |
|||
|
|||
optParser.add_option("-e", "--exec-for", action="store", type="string", |
|||
dest="exec_for", help="execute for name of simulated device " + |
|||
"(default: name of actual directory)") |
|||
optParser.add_option("--color", action="store", type="string", |
|||
dest="color", help="print debug output in this color", default=None) |
|||
optParser.add_option("--reject", action="store_true", dest="reject", |
|||
help="reject device group") |
|||
optParser.add_option("--accept", action="store_false", dest="reject", |
|||
help="accept device group (default)") |
|||
optParser.add_option("--no-answer", action="store_true", dest="noanswer", |
|||
help="do not answer device group handshake") |
|||
optParser.add_option("-E", "--end-on", dest="notifications", |
|||
help="end test on these notifications") |
|||
optParser.add_option("-j", "--multi-threaded", action="store_true", |
|||
dest="multithreaded", |
|||
help="use multithreaded instead of single threaded implementation") |
|||
optParser.add_option("-n", "--noend", action="store_true", |
|||
dest="noend", help="do not end") |
|||
optParser.add_option("-i", "--imap", action="store_true", |
|||
dest="imap", |
|||
help="use imap instead of minimail") |
|||
optParser.add_option("-o", "--own-identities", type="int", dest="own_ident", |
|||
help="simulate having OWN_IDENT own identities (1 to 3)", default=1) |
|||
optParser.add_option("-L", "--leave-device-group", action="store_true", |
|||
dest="leave", |
|||
help="after a successful sync run this to make the device leave the " |
|||
"device group again") |
|||
|
|||
options, args = optParser.parse_args() |
|||
|
|||
if not options.exec_for: |
|||
options.exec_for = os.path.basename(os.getcwd()) |
|||
|
|||
if options.own_ident < 1 or options.own_ident > 3: |
|||
raise ValueError("illegal number of own identities (allowed are 1 to 3)") |
|||
|
|||
if options.notifications: |
|||
end_on = eval(options.notifications) |
|||
try: None in end_on |
|||
except TypeError: |
|||
end_on = (end_on,) |
|||
|
|||
if options.noend: |
|||
end_on = (None,) |
|||
|
|||
if options.imap and options.own_ident >1: |
|||
raise ValueError("Multiple own identities not supported for imap mode") |
|||
|
|||
multithreaded = options.multithreaded |
|||
run(options.exec_for, options.color, options.imap, options.own_ident, options.leave) |
@ -1,233 +0,0 @@ |
|||
#!/usr/bin/env python3 |
|||
# -*- coding: utf-8 -*- |
|||
# vim: set fileencoding=utf-8 : |
|||
|
|||
"""test runner for sync tests |
|||
|
|||
Start this with: |
|||
|
|||
$ python3 sync_test.py |
|||
|
|||
""" |
|||
|
|||
# Sync test 2.0 |
|||
# Copyleft 2018, 2019, p≡p foundation |
|||
|
|||
# this file is under GNU General Public License 3.0 |
|||
|
|||
|
|||
import os |
|||
import sys |
|||
import shutil |
|||
import pathlib |
|||
|
|||
|
|||
def test_for(path, color=None, end_on=None, mt=False, imap=False, own_ident=1): |
|||
|
|||
cwd = os.getcwd(); |
|||
os.chdir(path) |
|||
os.environ["HOME"] = os.getcwd() |
|||
|
|||
print("running tests for " + path) |
|||
import sync_handshake |
|||
if end_on: |
|||
sync_handshake.end_on = end_on |
|||
sync_handshake.multithreaded = mt |
|||
|
|||
sync_handshake.run(path, color, imap, own_ident) |
|||
|
|||
os.chdir(cwd) |
|||
|
|||
|
|||
def setup(path): |
|||
cwd = os.getcwd(); |
|||
|
|||
os.makedirs(path, exist_ok=True) |
|||
os.chdir(path) |
|||
lib_path = os.path.join(os.environ["HOME"], "lib") |
|||
Library_path = os.path.join(os.environ["HOME"], "Library") |
|||
|
|||
try: |
|||
os.symlink(lib_path, "lib", True) |
|||
except FileExistsError: |
|||
pass |
|||
|
|||
try: |
|||
os.symlink(Library_path, "Library", True) |
|||
except FileExistsError: |
|||
pass |
|||
|
|||
os.chdir(cwd) |
|||
|
|||
|
|||
def rmrf(path): |
|||
try: |
|||
for p in pathlib.Path(path).iterdir(): |
|||
if p.is_dir() and not p.is_symlink(): |
|||
rmrf(str(p)) |
|||
else: |
|||
p.unlink() |
|||
os.rmdir(path) |
|||
except FileNotFoundError: |
|||
pass |
|||
|
|||
|
|||
EINTR = 4 |
|||
|
|||
|
|||
if __name__ == "__main__": |
|||
from optparse import OptionParser |
|||
|
|||
optParser = OptionParser() |
|||
optParser.description = __doc__ |
|||
optParser.add_option("-c", "--clean", action="store_true", dest="clean", |
|||
help="remove all generated files") |
|||
optParser.add_option("-b", "--backup", action="store_true", dest="backup", |
|||
help="make a backup of all generated files (old backup will be overwritten)") |
|||
optParser.add_option("-r", "--restore", action="store_true", dest="restore", |
|||
help="restore generated files from backup") |
|||
optParser.add_option("-C", "--clean-all", action="store_true", dest="cleanall", |
|||
help="remove all generated files including backup files") |
|||
optParser.add_option("-s", "--setup", action="store_true", dest="setup_only", |
|||
help="setup environment, then stop") |
|||
optParser.add_option("-p", "--print", action="store_true", dest="print", |
|||
help="print sync message trace in inbox") |
|||
optParser.add_option("-n", "--noend", action="store_true", dest="noend", |
|||
help="do not end") |
|||
optParser.add_option("-E", "--end-on", dest="notifications", |
|||
help="end test on these notifications") |
|||
optParser.add_option("-3", "--third-device", action="store_true", dest="third", |
|||
help="start Pad as third device") |
|||
optParser.add_option("-j", "--multi-threaded", action="store_true", |
|||
dest="multithreaded", |
|||
help="use multithreaded instead of single threaded implementation") |
|||
optParser.add_option("-i", "--imap", action="store_true", |
|||
dest="imap", |
|||
help="use imap instead of minimail") |
|||
optParser.add_option("-A", "--add-account-after-sync", action="store_true", |
|||
dest="add_account", |
|||
help="after sync add an account") |
|||
|
|||
options, args = optParser.parse_args() |
|||
|
|||
if options.imap: |
|||
import miniimap |
|||
|
|||
if options.cleanall: |
|||
options.clean = True |
|||
|
|||
if options.clean: |
|||
|
|||
if options.imap: |
|||
miniimap.clean_inbox() |
|||
|
|||
if options.cleanall: |
|||
rmrf("Backup") |
|||
|
|||
else: |
|||
rmrf("TestInbox") |
|||
rmrf("Phone") |
|||
rmrf("Laptop") |
|||
rmrf("Pad") |
|||
|
|||
if options.cleanall: |
|||
rmrf("Backup") |
|||
|
|||
if options.setup_only: |
|||
os.makedirs("TestInbox", exist_ok=True) |
|||
setup("Phone") |
|||
setup("Laptop") |
|||
if options.third: |
|||
setup("Pad") |
|||
|
|||
elif options.backup: |
|||
rmrf("Backup") |
|||
|
|||
try: |
|||
os.mkdir("Backup") |
|||
except FileExistsError: |
|||
pass |
|||
|
|||
if options.imap: |
|||
try: |
|||
os.mkdir("Backup/TestInbox") |
|||
except FileExistsError: |
|||
pass |
|||
|
|||
miniimap.backup_inbox() |
|||
else: |
|||
shutil.copytree("Phone", "Backup/Phone", symlinks=True, copy_function=shutil.copy2) |
|||
shutil.copytree("Laptop", "Backup/Laptop", symlinks=True, copy_function=shutil.copy2) |
|||
shutil.copytree("TestInbox", "Backup/TestInbox", symlinks=True, copy_function=shutil.copy2) |
|||
try: |
|||
shutil.copytree("Pad", "Backup/Pad", symlinks=True, copy_function=shutil.copy2) |
|||
except FileNotFoundError: |
|||
pass |
|||
|
|||
|
|||
elif options.restore: |
|||
if options.imap: |
|||
miniimap.clean_inbox() |
|||
miniimap.restore_inbox() |
|||
else: |
|||
rmrf("TestInbox") |
|||
rmrf("Phone") |
|||
rmrf("Laptop") |
|||
rmrf("Pad") |
|||
|
|||
shutil.copytree("Backup/Phone", "Phone", symlinks=True, copy_function=shutil.copy2) |
|||
shutil.copytree("Backup/Laptop", "Laptop", symlinks=True, copy_function=shutil.copy2) |
|||
shutil.copytree("Backup/TestInbox", "TestInbox", symlinks=True, copy_function=shutil.copy2) |
|||
try: |
|||
shutil.copytree("Backup/Pad", "Pad", symlinks=True, copy_function=shutil.copy2) |
|||
except FileNotFoundError: |
|||
pass |
|||
|
|||
elif options.print: |
|||
from sync_handshake import print_msg |
|||
|
|||
inbox = pathlib.Path("TestInbox") |
|||
l = [ path for path in inbox.glob("*.eml") ] |
|||
l.sort(key=(lambda p: p.stat().st_mtime)) |
|||
for p in l: |
|||
print_msg(p) |
|||
|
|||
else: |
|||
from multiprocessing import Process |
|||
|
|||
os.makedirs("TestInbox", exist_ok=True) |
|||
setup("Phone") |
|||
setup("Laptop") |
|||
if options.third: |
|||
setup("Pad") |
|||
|
|||
if not options.setup_only: |
|||
end_on = None |
|||
if options.notifications: |
|||
end_on = eval(options.notifications) |
|||
try: None in end_on |
|||
except TypeError: |
|||
end_on = (end_on,) |
|||
elif options.noend: |
|||
end_on = (None,) |
|||
|
|||
# Phone runs with own_ident = 2 |
|||
Phone = Process(target=test_for, args=("Phone", "red", end_on, |
|||
options.multithreaded, options.imap, 1)) |
|||
|
|||
# others run with own_ident = 1 |
|||
Laptop = Process(target=test_for, args=("Laptop", "green", end_on, |
|||
options.multithreaded, options.imap)) |
|||
if options.third: |
|||
Pad = Process(target=test_for, args=("Pad", "cyan", end_on, |
|||
options.multithreaded, options.imap)) |
|||
|
|||
Phone.start() |
|||
Laptop.start() |
|||
if options.third: |
|||
Pad.start() |
|||
|
|||
Phone.join() |
|||
Laptop.join() |
|||
if options.third: |
|||
Pad.join() |
@ -1,64 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# This file is under GNU Affero General Public License 3.0 |
|||
# see LICENSE.txt |
|||
|
|||
"""pytest configuration for the unit tests.""" |
|||
|
|||
from .model import * |
|||
|
|||
# Init |
|||
@pytest.fixture() |
|||
def env_init(tmpdir_factory, request): |
|||
"""Create a tmp dir for the tests""" |
|||
base = str(abs(hash(request.node.nodeid)))[:3] |
|||
bn = tmpdir_factory.mktemp(base) |
|||
print(bn) |
|||
import os |
|||
os.environ["PEP_HOME"] = str(bn) |
|||
os.environ["HOME"] = str(bn) |
|||
|
|||
|
|||
@pytest.fixture() |
|||
def pEp(env_init): |
|||
import pEp |
|||
return pEp |
|||
|
|||
|
|||
@pytest.fixture() |
|||
def alice_myself(pEp, model): |
|||
alice = pEp.Identity( |
|||
model.alice.addr, |
|||
model.alice.name, |
|||
model.alice.user_id |
|||
) |
|||
pEp.myself(alice) |
|||
return alice |
|||
|
|||
|
|||
@pytest.fixture() |
|||
def alice_imported(pEp, model): |
|||
pEp.import_key(model.alice.key_sec) |
|||
alice = pEp.Identity( |
|||
model.alice.addr, |
|||
model.alice.name, |
|||
model.alice.user_id |
|||
) |
|||
return alice |
|||
|
|||
|
|||
@pytest.fixture() |
|||
def import_ident_alice_as_own_ident(pEp, model, alice_imported): |
|||
alice = alice_imported |
|||
pEp.set_own_key(alice, model.alice.fpr) |
|||
return alice |
|||
|
|||
|
|||
@pytest.fixture() |
|||
def import_ident_bob(pEp, model): |
|||
pEp.import_key(model.bob.key_pub) |
|||
bob = pEp.Identity( |
|||
model.bob.addr, |
|||
model.bob.name, |
|||
) |
|||
bob.update() |
|||
return bob |
@ -1,12 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# This file is under GNU Affero General Public License 3.0 |
|||
# see LICENSE.txt |
|||
|
|||
"""Constants for unit tests.""" |
|||
DATADIR = "data" |
|||
|
|||
OUTGOING_MSG = 1 |
|||
INCOMING_MSG = 2 |
|||
|
|||
SUBJECT = "This is a subject" |
|||
BODY = "Hi world!\n" |
@ -1,24 +0,0 @@ |
|||
-----BEGIN PGP PUBLIC KEY BLOCK----- |
|||
Comment: 1A97 F263 D831 9D68 85F6 38C5 AA81 E1B5 457A 2B40 |
|||
Comment: bob_work@peptest.org |
|||
|
|||
xjMEXyp4RRYJKwYBBAHaRw8BAQdAdA0qiUaazZJrnWAtqQ+V/XevsZkNHyspsD8M |
|||
jWv69i3ChAQfFgoAFQWCXyp4RQWJBaSPvQIVCgKbAQIeAQAhCRCqgeG1RXorQBYh |
|||
BBqX8mPYMZ1ohfY4xaqB4bVFeitA1j0BAONtcJp4KI4CTjVJps7udMFPRqAPDXU6 |
|||
0YJzHWXK0mspAQCA2kZ2mJKFvMiKl3mY79N08eF2QE4zOVHYQYR+GZrtAc0UYm9i |
|||
X3dvcmtAcGVwdGVzdC5vcmfChAQTFgoAFQWCXyp4RQWJBaSPvQIVCgKbAQIeAQAh |
|||
CRCqgeG1RXorQBYhBBqX8mPYMZ1ohfY4xaqB4bVFeitA0NsA/i+jZZ8jVJVjTN9d |
|||
OPlCSg2rgMoW4CMudbvCeJ05HBGgAQDfpHv0mceDpw0Xb7JvSCZGpcnx7JvnrijO |
|||
o7s0km1fB84zBF8qeEUWCSsGAQQB2kcPAQEHQCqxykiuw5mJk7ulNeeS9ZRmNMh+ |
|||
A5Za3/Mqwr8neCElwsA7BBgWCgAVBYJfKnhFBYkFpI+9AhUKApsCAh4BAJgJEKqB |
|||
4bVFeitAdqAEGRYKAAYFgl8qeEUAIQkQZIW7NIu2E2oWIQQjjCvzjFveMgb5MvZk |
|||
hbs0i7YTav2zAQCDuIDQu3vO31HUiGvSc2/ZYRKUAHJsVfnCovZSFiBaHwD+MNgr |
|||
QYydV0jkx2hyaQV7GGml132sKCVmHW6t+8+B8AYWIQQal/Jj2DGdaIX2OMWqgeG1 |
|||
RXorQI6IAP0RuRRGJV8zg9ax3HSpBYsqQCTjq/Kswiskrzlda77RrwD9EnohAaPF |
|||
0yd5MrZ0H01+RJseLhF20mznjYX4ucKckQrOOARfKnhFEgorBgEEAZdVAQUBAQdA |
|||
/QOYQ28riHwdqlzL1SS89+sK52RUSGJ+z2jMEGZXrg4DAQgJwoQEGBYKABUFgl8q |
|||
eEUFiQWkj70CCwkCmwwCHgEAIQkQqoHhtUV6K0AWIQQal/Jj2DGdaIX2OMWqgeG1 |
|||
RXorQAI/AQCVdZqaCPSHI8KQ75SmjCHOrizFJ5OvRQIxLcgFYnbf4QD/RK8/na7X |
|||
t3H5zFD9yjCeNtTKuBubz8wnlV48V6F8NQk= |
|||
=71Mh |
|||
-----END PGP PUBLIC KEY BLOCK----- |
@ -1,26 +0,0 @@ |
|||
-----BEGIN PGP PRIVATE KEY BLOCK----- |
|||
Comment: 1A97 F263 D831 9D68 85F6 38C5 AA81 E1B5 457A 2B40 |
|||
Comment: bob_work@peptest.org |
|||
|
|||
xVgEXyp4RRYJKwYBBAHaRw8BAQdAdA0qiUaazZJrnWAtqQ+V/XevsZkNHyspsD8M |
|||
jWv69i0AAP9vlqqd0FjnC219hFfUH3NWDyNkE+qLncgL8iauLJJW2xApwoQEHxYK |
|||
ABUFgl8qeEUFiQWkj70CFQoCmwECHgEAIQkQqoHhtUV6K0AWIQQal/Jj2DGdaIX2 |
|||
OMWqgeG1RXorQNY9AQDjbXCaeCiOAk41SabO7nTBT0agDw11OtGCcx1lytJrKQEA |
|||
gNpGdpiShbzIipd5mO/TdPHhdkBOMzlR2EGEfhma7QHNFGJvYl93b3JrQHBlcHRl |
|||
c3Qub3JnwoQEExYKABUFgl8qeEUFiQWkj70CFQoCmwECHgEAIQkQqoHhtUV6K0AW |
|||
IQQal/Jj2DGdaIX2OMWqgeG1RXorQNDbAP4vo2WfI1SVY0zfXTj5QkoNq4DKFuAj |
|||
LnW7wnidORwRoAEA36R79JnHg6cNF2+yb0gmRqXJ8eyb564ozqO7NJJtXwfHWARf |
|||
KnhFFgkrBgEEAdpHDwEBB0AqscpIrsOZiZO7pTXnkvWUZjTIfgOWWt/zKsK/J3gh |
|||
JQABAJW6BesKSs2CgM+fx+SKkv+di6b1aTLirOmVdfbse0R9E5TCwDsEGBYKABUF |
|||
gl8qeEUFiQWkj70CFQoCmwICHgEAmAkQqoHhtUV6K0B2oAQZFgoABgWCXyp4RQAh |
|||
CRBkhbs0i7YTahYhBCOMK/OMW94yBvky9mSFuzSLthNq/bMBAIO4gNC7e87fUdSI |
|||
a9Jzb9lhEpQAcmxV+cKi9lIWIFofAP4w2CtBjJ1XSOTHaHJpBXsYaaXXfawoJWYd |
|||
bq37z4HwBhYhBBqX8mPYMZ1ohfY4xaqB4bVFeitAjogA/RG5FEYlXzOD1rHcdKkF |
|||
iypAJOOr8qzCKySvOV1rvtGvAP0SeiEBo8XTJ3kytnQfTX5Emx4uEXbSbOeNhfi5 |
|||
wpyRCsddBF8qeEUSCisGAQQBl1UBBQEBB0D9A5hDbyuIfB2qXMvVJLz36wrnZFRI |
|||
Yn7PaMwQZleuDgMBCAkAAP99a9Hrl/wNGP8ohfOaTkMYE9zuBEo8FHsCpLT+/Yz9 |
|||
8BIBwoQEGBYKABUFgl8qeEUFiQWkj70CCwkCmwwCHgEAIQkQqoHhtUV6K0AWIQQa |
|||
l/Jj2DGdaIX2OMWqgeG1RXorQAI/AQCVdZqaCPSHI8KQ75SmjCHOrizFJ5OvRQIx |
|||
LcgFYnbf4QD/RK8/na7Xt3H5zFD9yjCeNtTKuBubz8wnlV48V6F8NQk= |
|||
=Yzdu |
|||
-----END PGP PRIVATE KEY BLOCK----- |
@ -1,24 +0,0 @@ |
|||
-----BEGIN PGP PUBLIC KEY BLOCK----- |
|||
Comment: 2D35 731B 9C75 4564 CBAD 15D2 D18F 7444 594F 2283 |
|||
Comment: alice@peptest.org |
|||
|
|||
xjMEXxFT2hYJKwYBBAHaRw8BAQdA/q3RICIqQ4FHd6RfqP6QY1gd2trvJn0DBg/1 |
|||
jIfdpKfChAQfFgoAFQWCXxFT2gWJBaSPvQIVCgKbAQIeAQAhCRDRj3REWU8igxYh |
|||
BC01cxucdUVky60V0tGPdERZTyKDUnYBAMT6z+rJ6HvoAhE531BWhsSU9X0QKLC7 |
|||
UYLQ3/ZGBVAbAQC14aJX1sODCKCPK6eivyhfd8l6W69vCBpPa55TgQ3GD80RYWxp |
|||
Y2VAcGVwdGVzdC5vcmfChAQTFgoAFQWCXxFT2gWJBaSPvQIVCgKbAQIeAQAhCRDR |
|||
j3REWU8igxYhBC01cxucdUVky60V0tGPdERZTyKDQlMBAPhingJLnqAjx+DnEWdu |
|||
nPRwnhxWSgY31GRAD8LG36zlAP94BN2pRvv6sPSCSla+yUvVcYQt927MvI1B3mOI |
|||
2jnlAM4zBF8RU9oWCSsGAQQB2kcPAQEHQCxlXfe9mHyk7Z9Cd+/12i5kYm6ljyKV |
|||
Jsst1oxMj/CnwsA7BBgWCgAVBYJfEVPaBYkFpI+9AhUKApsCAh4BAJgJENGPdERZ |
|||
TyKDdqAEGRYKAAYFgl8RU9oAIQkQYvLo9HBcHrAWIQTnCIjW7qTg/Ju3h6Ni8uj0 |
|||
cFwesAy3AP4uHp91sH/DWv5Ac7jppfEXpg+CW/RoKdJ32N5S6BnWZQEAn5jtnve2 |
|||
cBx2jgUQEKkGZ6AprrrdCnPgH8AOxNOWbAYWIQQtNXMbnHVFZMutFdLRj3REWU8i |
|||
g9JRAQCHR0PJVrsyy91jLA0oAYaEyf743XlrJY8yhM3H4HKKzQEAishD4vi9cpCj |
|||
tx4EXIwoqxy2wfLbwfkGulENJS38DAbOOARfEVPaEgorBgEEAZdVAQUBAQdAo7WR |
|||
Up2ZLQbkUhTB9Aqw3Z6uKGNUUiOp7GsVu3fpAScDAQgJwoQEGBYKABUFgl8RU9oF |
|||
iQWkj70CCwkCmwwCHgEAIQkQ0Y90RFlPIoMWIQQtNXMbnHVFZMutFdLRj3REWU8i |
|||
g1QJAP9l9Xyw8j22fFUa6iKzD68SP7zLb4LbGpHdKXcBd86kigD+O0zwJp7S/Ogq |
|||
LpOoJOD6xX50+0JnlPnIxZWwhgYPrAs= |
|||
=S7O4 |
|||
-----END PGP PUBLIC KEY BLOCK----- |
@ -1,26 +0,0 @@ |
|||
-----BEGIN PGP PRIVATE KEY BLOCK----- |
|||
Comment: 2D35 731B 9C75 4564 CBAD 15D2 D18F 7444 594F 2283 |
|||
Comment: alice@peptest.org |
|||
|
|||
xVgEXxFT2hYJKwYBBAHaRw8BAQdA/q3RICIqQ4FHd6RfqP6QY1gd2trvJn0DBg/1 |
|||
jIfdpKcAAP0W8bWDwzy2kpwqa5gx9T/DWt4kDCoa7tGzMU+dv0FBnBCMwoQEHxYK |
|||
ABUFgl8RU9oFiQWkj70CFQoCmwECHgEAIQkQ0Y90RFlPIoMWIQQtNXMbnHVFZMut |
|||
FdLRj3REWU8ig1J2AQDE+s/qyeh76AIROd9QVobElPV9ECiwu1GC0N/2RgVQGwEA |
|||
teGiV9bDgwigjyunor8oX3fJeluvbwgaT2ueU4ENxg/NEWFsaWNlQHBlcHRlc3Qu |
|||
b3JnwoQEExYKABUFgl8RU9oFiQWkj70CFQoCmwECHgEAIQkQ0Y90RFlPIoMWIQQt |
|||
NXMbnHVFZMutFdLRj3REWU8ig0JTAQD4Yp4CS56gI8fg5xFnbpz0cJ4cVkoGN9Rk |
|||
QA/Cxt+s5QD/eATdqUb7+rD0gkpWvslL1XGELfduzLyNQd5jiNo55QDHWARfEVPa |
|||
FgkrBgEEAdpHDwEBB0AsZV33vZh8pO2fQnfv9douZGJupY8ilSbLLdaMTI/wpwAA |
|||
/RU5lcZzjrlWdEh95e12IjqpCKt1VpwQhT617pSZyYpqELbCwDsEGBYKABUFgl8R |
|||
U9oFiQWkj70CFQoCmwICHgEAmAkQ0Y90RFlPIoN2oAQZFgoABgWCXxFT2gAhCRBi |
|||
8uj0cFwesBYhBOcIiNbupOD8m7eHo2Ly6PRwXB6wDLcA/i4en3Wwf8Na/kBzuOml |
|||
8RemD4Jb9Ggp0nfY3lLoGdZlAQCfmO2e97ZwHHaOBRAQqQZnoCmuut0Kc+AfwA7E |
|||
05ZsBhYhBC01cxucdUVky60V0tGPdERZTyKD0lEBAIdHQ8lWuzLL3WMsDSgBhoTJ |
|||
/vjdeWsljzKEzcfgcorNAQCKyEPi+L1ykKO3HgRcjCirHLbB8tvB+Qa6UQ0lLfwM |
|||
BsddBF8RU9oSCisGAQQBl1UBBQEBB0CjtZFSnZktBuRSFMH0CrDdnq4oY1RSI6ns |
|||
axW7d+kBJwMBCAkAAP9kY8sKTIAbQiR7PVRDPfI49ccZmoDSjNG6nPBeT7JwEA/h |
|||
woQEGBYKABUFgl8RU9oFiQWkj70CCwkCmwwCHgEAIQkQ0Y90RFlPIoMWIQQtNXMb |
|||
nHVFZMutFdLRj3REWU8ig1QJAP9l9Xyw8j22fFUa6iKzD68SP7zLb4LbGpHdKXcB |
|||
d86kigD+O0zwJp7S/OgqLpOoJOD6xX50+0JnlPnIxZWwhgYPrAs= |
|||
=uIGP |
|||
-----END PGP PRIVATE KEY BLOCK----- |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue