
65 changed files with 3880 additions and 2615 deletions
@ -0,0 +1,30 @@ |
|||||
|
root = true |
||||
|
|
||||
|
[*] |
||||
|
charset = utf-8 |
||||
|
end_of_line = lf |
||||
|
indent_size = 4 |
||||
|
indent_style = space |
||||
|
insert_final_newline = true |
||||
|
max_line_length = 300 |
||||
|
tab_width = 4 |
||||
|
|
||||
|
# C++ Coding style |
||||
|
# I know these keys are unknown, regard it as documentation |
||||
|
[*.{cc,hh}] |
||||
|
indent_brace_style = K&R |
||||
|
curly_bracket_next_line = false |
||||
|
spaces_around_operators = true |
||||
|
spaces_around_brackets = true |
||||
|
|
||||
|
[*.py] |
||||
|
indent_size = 4 |
||||
|
|
||||
|
[Makefile] |
||||
|
indent_style = tab |
||||
|
|
||||
|
[*.ini] |
||||
|
indent_size = 2 |
||||
|
|
||||
|
[*.cfg] |
||||
|
indent_size = 2 |
@ -1,28 +0,0 @@ |
|||||
syntax: glob |
|
||||
|
|
||||
local.conf |
|
||||
*.swp |
|
||||
ws |
|
||||
tags |
|
||||
.DS_Store |
|
||||
pEp.egg-info |
|
||||
dist |
|
||||
build |
|
||||
.pythonhist |
|
||||
.gnupg |
|
||||
.lldb |
|
||||
.pEp_management.db* |
|
||||
.python_history |
|
||||
__pycache__ |
|
||||
test/Laptop |
|
||||
test/Library |
|
||||
test/Phone |
|
||||
test/TestInbox |
|
||||
test/Backup |
|
||||
test/lib |
|
||||
test/imap_settings.py |
|
||||
venv |
|
||||
launch.json |
|
||||
settings.json |
|
||||
# Default ignored files |
|
||||
.idea/ |
|
@ -0,0 +1,9 @@ |
|||||
|
# This is the list of pEpPythonAdapter's significant contributors. |
||||
|
# |
||||
|
# This does not necessarily list everyone who has contributed code |
||||
|
# To see the full list of contributors, see the revision history in |
||||
|
# source control. |
||||
|
Volker Birk <vb@pep-project.org> (original author and maintainer) |
||||
|
Heck <heck@pep.foundation> (current maintainer and author) |
||||
|
Hartmut Goebel <h.goebel@crazy-compilers.com> (contributions) |
||||
|
juga <juga@pep.foundation> (contributions) |
@ -1,42 +0,0 @@ |
|||||
# pEpPythonAdapter |
|
||||
|
|
||||
## Build Insttructions |
|
||||
|
|
||||
These build instructions should work on: |
|
||||
* Linux (Verified 26.4.20 - heck) |
|
||||
* MacOS (Verified 26.4.20 - heck) |
|
||||
* Windows |
|
||||
|
|
||||
### Build |
|
||||
To build against system wide pEp installation (libs/includes) |
|
||||
```bash |
|
||||
python3 setup.py build_ext |
|
||||
``` |
|
||||
|
|
||||
To build against a pEp installation in your home dir (libs/includes): |
|
||||
```bash |
|
||||
python3 setup.py build_ext --local |
|
||||
``` |
|
||||
|
|
||||
To build against a pEp installation in a custom installation root (libs/includes) |
|
||||
```bash |
|
||||
python3 setup.py build_ext --prefix=<path_to_your_install_root> |
|
||||
``` |
|
||||
|
|
||||
### Install |
|
||||
|
|
||||
To install the extension module system wide, as root, run: |
|
||||
```bash |
|
||||
python3 setup.py install |
|
||||
``` |
|
||||
|
|
||||
To install the extension module into you home dir |
|
||||
```bash |
|
||||
python3 setup.py install --user |
|
||||
``` |
|
||||
|
|
||||
To install the extension module into a custom destination |
|
||||
```bash |
|
||||
python3 setup.py install --prefix=<custom_destination_root> |
|
||||
``` |
|
||||
Attention: The ~ (tilde) does not get expanded, but env vars work ($HOME). |
|
@ -0,0 +1,22 @@ |
|||||
|
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 |
@ -0,0 +1,19 @@ |
|||||
|
# 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) |
@ -0,0 +1,35 @@ |
|||||
|
@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 |
@ -0,0 +1,12 @@ |
|||||
|
pEp package |
||||
|
=========== |
||||
|
|
||||
|
Module contents |
||||
|
--------------- |
||||
|
|
||||
|
.. automodule:: pEp |
||||
|
:members: |
||||
|
:imported-members: |
||||
|
:undoc-members: |
||||
|
:show-inheritance: |
||||
|
|
@ -0,0 +1,206 @@ |
|||||
|
# -*- 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 |
@ -0,0 +1,21 @@ |
|||||
|
.. 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` |
@ -0,0 +1,143 @@ |
|||||
|
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. |
@ -0,0 +1,7 @@ |
|||||
|
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???>`_ |
@ -0,0 +1,18 @@ |
|||||
|
|
||||
|
[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", |
||||
|
] |
||||
|
|
@ -0,0 +1,161 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
// System
|
||||
|
#include <sstream> |
||||
|
|
||||
|
// Engine
|
||||
|
#include <pEp/keymanagement.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
#include <pEp/Adapter.hh> |
||||
|
|
||||
|
// local
|
||||
|
#include "basic_api.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
using namespace std; |
||||
|
|
||||
|
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 = NULL; |
||||
|
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, 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, 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); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
boost::python::list import_key(string key_data) { |
||||
|
::identity_list *private_keys = NULL; |
||||
|
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 = boost::python::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 = NULL; |
||||
|
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, 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
|
||||
|
|
||||
|
|
@ -0,0 +1,37 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef BASIC_API_HH |
||||
|
#define BASIC_API_HH |
||||
|
|
||||
|
#include "pEpmodule.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, identity_flags_t flags); |
||||
|
|
||||
|
void unset_identity_flags(Identity ident, identity_flags_t flags); |
||||
|
|
||||
|
void key_reset_trust(Identity ident); |
||||
|
|
||||
|
boost::python::list import_key(string key_data); |
||||
|
|
||||
|
string export_key(Identity ident); |
||||
|
|
||||
|
string export_secret_key(Identity ident); |
||||
|
|
||||
|
void set_own_key(Identity &ident, string fpr); |
||||
|
|
||||
|
} /* namespace PythonAdapter */ |
||||
|
} /* namespace pEp */ |
||||
|
|
||||
|
#endif /* BASIC_API_HH */ |
@ -0,0 +1,257 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
// System
|
||||
|
#include <typeinfo> |
||||
|
#include <sstream> |
||||
|
|
||||
|
// Engine
|
||||
|
#include <pEp/identity_list.h> |
||||
|
#include <pEp/keymanagement.h> |
||||
|
#include <pEp/key_reset.h> |
||||
|
|
||||
|
// local
|
||||
|
#include "identity.hh" |
||||
|
#include "pEpmodule.hh" |
||||
|
#include "basic_api.hh" |
||||
|
#include "message_api.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
using namespace std; |
||||
|
using namespace boost::python; |
||||
|
|
||||
|
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(dict &) { |
||||
|
return copy(); |
||||
|
} |
||||
|
|
||||
|
void Identity::update() { |
||||
|
update_identity(*this); |
||||
|
} |
||||
|
|
||||
|
void Identity::key_reset(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, object value) { |
||||
|
Identity &_ident = 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; |
||||
|
} |
||||
|
|
||||
|
boost::python::list identitylist_attr(identity_list *&il) { |
||||
|
boost::python::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(object(Identity(ident))); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
void identitylist_attr(identity_list *&il, boost::python::list value) { |
||||
|
identity_list *_il = ::new_identity_list(NULL); |
||||
|
if (!_il) |
||||
|
throw bad_alloc(); |
||||
|
|
||||
|
identity_list *_i = _il; |
||||
|
for (int i = 0; i < len(value); i++) { |
||||
|
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
|
||||
|
|
@ -0,0 +1,121 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef IDENTITY_HH |
||||
|
#define IDENTITY_HH |
||||
|
|
||||
|
// System
|
||||
|
#include <boost/python.hpp> |
||||
|
#include <string> |
||||
|
#include <memory> |
||||
|
#include <cstddef> |
||||
|
|
||||
|
// Engine
|
||||
|
#include <pEp/pEpEngine.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
|
||||
|
//libpEpAdapter
|
||||
|
#include "pEp/Adapter.hh" |
||||
|
|
||||
|
// local
|
||||
|
#include "str_attr.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
|
||||
|
using std::string; |
||||
|
using std::shared_ptr; |
||||
|
|
||||
|
// 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(dict &memo); |
||||
|
|
||||
|
virtual void update(); |
||||
|
|
||||
|
void key_reset(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, object value); |
||||
|
|
||||
|
boost::python::list identitylist_attr(identity_list *&il); |
||||
|
|
||||
|
void identitylist_attr(identity_list *&il, boost::python::list value); |
||||
|
|
||||
|
} // namespace PythonAdapter
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
#endif /* IDENTITY_HH */ |
@ -0,0 +1,385 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
// System
|
||||
|
#include <cstdlib> |
||||
|
#include <cstring> |
||||
|
#include <stdexcept> |
||||
|
#include <sstream> |
||||
|
#include <vector> |
||||
|
#include <Python.h> |
||||
|
|
||||
|
// Engine
|
||||
|
#include <pEp/mime.h> |
||||
|
#include <pEp/keymanagement.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
|
||||
|
// local
|
||||
|
#include "message.hh" |
||||
|
#include "message_api.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
using namespace std; |
||||
|
using namespace boost::python; |
||||
|
|
||||
|
Message::Blob::Blob(bloblist_t *bl, bool chained) : |
||||
|
_bl(bl), part_of_chain(chained) { |
||||
|
if (!_bl) |
||||
|
throw bad_alloc(); |
||||
|
} |
||||
|
|
||||
|
Message::Blob::Blob(object data, string mime_type, string filename) : |
||||
|
_bl(new_bloblist(NULL, 0, NULL, NULL)), 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 = NULL; |
||||
|
|
||||
|
try { |
||||
|
Message::Blob &blob = extract<Message::Blob &>(self); |
||||
|
bl = blob._bl; |
||||
|
} |
||||
|
catch (exception &e) { |
||||
|
PyErr_SetString(PyExc_RuntimeError, "extract not possible"); |
||||
|
view->obj = NULL; |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
if (!(bl && bl->value)) { |
||||
|
PyErr_SetString(PyExc_RuntimeError, "no data available"); |
||||
|
view->obj = NULL; |
||||
|
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"; |
||||
|
|
||||
|
} |
||||
|
object codecs = import("codecs"); |
||||
|
object _decode = codecs.attr("decode"); |
||||
|
return call<string>(_decode.ptr(), this, encoding); |
||||
|
} |
||||
|
|
||||
|
PyBufferProcs Message::Blob::bp = {getbuffer, NULL}; |
||||
|
|
||||
|
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(NULL, &free_message) { |
||||
|
message *_cpy; |
||||
|
PEP_STATUS status = mime_decode_message(mimetext.c_str(), |
||||
|
mimetext.size(), &_cpy, NULL); |
||||
|
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(); |
||||
|
} |
||||
|
|
||||
|
boost::python::tuple Message::attachments() { |
||||
|
boost::python::list l; |
||||
|
|
||||
|
for (bloblist_t *bl = _msg->attachments; bl && bl->value; bl = |
||||
|
bl->next) { |
||||
|
l.append(Blob(bl, true)); |
||||
|
} |
||||
|
|
||||
|
return boost::python::tuple(l); |
||||
|
} |
||||
|
|
||||
|
void Message::attachments(boost::python::list value) { |
||||
|
bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL); |
||||
|
if (!bl) |
||||
|
throw bad_alloc(); |
||||
|
|
||||
|
bloblist_t *_l = bl; |
||||
|
for (int i = 0; i < len(value); i++) { |
||||
|
Message::Blob &blob = 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 = extract<Message::Blob &>(value[i]); |
||||
|
blob._bl->value = NULL; |
||||
|
blob._bl->size = 0; |
||||
|
free(blob._bl->mime_type); |
||||
|
blob._bl->mime_type = NULL; |
||||
|
free(blob._bl->filename); |
||||
|
blob._bl->filename = NULL; |
||||
|
} |
||||
|
|
||||
|
free_bloblist(_msg->attachments); |
||||
|
_msg->attachments = bl; |
||||
|
} |
||||
|
|
||||
|
Message Message::encrypt() { |
||||
|
boost::python::list extra; |
||||
|
return encrypt_message(*this, extra, PEP_enc_PGP_MIME, 0); |
||||
|
} |
||||
|
|
||||
|
Message Message::_encrypt(boost::python::list extra, int enc_format, int flags) { |
||||
|
if (!enc_format) |
||||
|
enc_format = PEP_enc_PGP_MIME; |
||||
|
return encrypt_message(*this, extra, enc_format, flags); |
||||
|
} |
||||
|
|
||||
|
boost::python::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(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 object update(Identity ident) { |
||||
|
if (ident.address().empty()) |
||||
|
throw runtime_error("at least address needed"); |
||||
|
update_identity(Adapter::session(), ident); |
||||
|
return object(ident); |
||||
|
} |
||||
|
|
||||
|
static boost::python::list update(boost::python::list il) { |
||||
|
for (int i = 0; i < len(il); i++) { |
||||
|
update(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
|
@ -0,0 +1,194 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef MESSAGE_HH |
||||
|
#define MESSAGE_HH |
||||
|
|
||||
|
// System
|
||||
|
#include <string> |
||||
|
#include <boost/python.hpp> |
||||
|
#include <boost/lexical_cast.hpp> |
||||
|
|
||||
|
// Engine
|
||||
|
#include <pEp/message.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
|
||||
|
// local
|
||||
|
#include "str_attr.hh" |
||||
|
#include "identity.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
using std::string; |
||||
|
using std::runtime_error; |
||||
|
using std::invalid_argument; |
||||
|
using boost::lexical_cast; |
||||
|
|
||||
|
// 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(NULL, 0, NULL, NULL), |
||||
|
bool chained = false); |
||||
|
|
||||
|
Blob(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 = NULL); |
||||
|
|
||||
|
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); } |
||||
|
|
||||
|
boost::python::tuple attachments(); |
||||
|
|
||||
|
void attachments(boost::python::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(object value) { identity_attr(_msg->from, value); } |
||||
|
|
||||
|
boost::python::list to() { return identitylist_attr(_msg->to); } |
||||
|
|
||||
|
void to(boost::python::list value) { identitylist_attr(_msg->to, value); } |
||||
|
|
||||
|
Identity recv_by() { return identity_attr(_msg->recv_by); } |
||||
|
|
||||
|
void recv_by(object value) { identity_attr(_msg->recv_by, value); } |
||||
|
|
||||
|
boost::python::list cc() { return identitylist_attr(_msg->cc); } |
||||
|
|
||||
|
void cc(boost::python::list value) { identitylist_attr(_msg->cc, value); } |
||||
|
|
||||
|
boost::python::list bcc() { return identitylist_attr(_msg->bcc); } |
||||
|
|
||||
|
void bcc(boost::python::list value) { identitylist_attr(_msg->bcc, value); } |
||||
|
|
||||
|
boost::python::list reply_to() { return identitylist_attr(_msg->reply_to); } |
||||
|
|
||||
|
void reply_to(boost::python::list value) { identitylist_attr(_msg->reply_to, value); } |
||||
|
|
||||
|
boost::python::list in_reply_to() { return strlist_attr(_msg->in_reply_to); } |
||||
|
|
||||
|
void in_reply_to(boost::python::list value) { strlist_attr(_msg->in_reply_to, value); } |
||||
|
|
||||
|
boost::python::list references() { return strlist_attr(_msg->references); } |
||||
|
|
||||
|
void references(boost::python::list value) { strlist_attr(_msg->references, value); } |
||||
|
|
||||
|
boost::python::list keywords() { return strlist_attr(_msg->keywords); } |
||||
|
|
||||
|
void keywords(boost::python::list value) { strlist_attr(_msg->keywords, value); } |
||||
|
|
||||
|
string comments() { return str_attr(_msg->comments); } |
||||
|
|
||||
|
void comments(string value) { str_attr(_msg->comments, value); } |
||||
|
|
||||
|
dict opt_fields() { return strdict_attr(_msg->opt_fields); } |
||||
|
|
||||
|
void opt_fields(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(boost::python::list extra, int enc_format = 4, int flags = 0); |
||||
|
|
||||
|
boost::python::tuple decrypt(int flags = 0); |
||||
|
|
||||
|
PEP_rating outgoing_rating(); |
||||
|
|
||||
|
PEP_color outgoing_color(); |
||||
|
|
||||
|
Message deepcopy(dict &memo); |
||||
|
|
||||
|
Message copy(); |
||||
|
}; |
||||
|
|
||||
|
Message outgoing_message(Identity me); |
||||
|
|
||||
|
Message incoming_message(string mime_text); |
||||
|
|
||||
|
} /* namespace PythonAdapter */ |
||||
|
} /* namespace pEp */ |
||||
|
|
||||
|
#endif /* MESSAGE_HH */ |
@ -0,0 +1,161 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
// Engine
|
||||
|
#include <pEp/pEpEngine.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
#include <pEp/sync_api.h> |
||||
|
#include <pEp/sync_codec.h> |
||||
|
#include <pEp/distribution_codec.h> |
||||
|
|
||||
|
// local
|
||||
|
#include "message_api.hh" |
||||
|
#include "basic_api.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
using namespace std; |
||||
|
using namespace boost::python; |
||||
|
|
||||
|
Message encrypt_message(Message src, boost::python::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 = NULL; |
||||
|
|
||||
|
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); |
||||
|
} |
||||
|
|
||||
|
boost::python::tuple decrypt_message(Message src, int flags) { |
||||
|
message *_dst = NULL; |
||||
|
stringlist_t *_keylist = NULL; |
||||
|
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); |
||||
|
|
||||
|
boost::python::list keylist; |
||||
|
if (_keylist) { |
||||
|
keylist = from_stringlist(_keylist); |
||||
|
free_stringlist(_keylist); |
||||
|
} |
||||
|
|
||||
|
Message dst = _dst ? Message(_dst) : Message(src); |
||||
|
return boost::python::make_tuple(dst, keylist, _rating, _flags); |
||||
|
} |
||||
|
|
||||
|
PEP_color _color(int rating) { |
||||
|
return ::color_from_rating((PEP_rating) rating); |
||||
|
} |
||||
|
|
||||
|
boost::python::tuple sync_decode(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 = NULL; |
||||
|
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 boost::python::make_tuple(_dst, 0); |
||||
|
} |
||||
|
|
||||
|
static boost::python::tuple sync_encode(string text) { |
||||
|
char *data = NULL; |
||||
|
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 boost::python::make_tuple(object(handle<>(ba)), 0); |
||||
|
} |
||||
|
|
||||
|
boost::python::tuple Distribution_decode(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 = NULL; |
||||
|
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 boost::python::make_tuple(_dst, 0); |
||||
|
} |
||||
|
|
||||
|
static boost::python::tuple Distribution_encode(string text) { |
||||
|
char *data = NULL; |
||||
|
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 boost::python::make_tuple(object(handle<>(ba)), 0); |
||||
|
} |
||||
|
|
||||
|
object sync_search(string name) { |
||||
|
if (name != "pep.sync") { |
||||
|
return object(); |
||||
|
} else { |
||||
|
object codecs = import("codecs"); |
||||
|
object CodecInfo = codecs.attr("CodecInfo"); |
||||
|
|
||||
|
object _sync_decode = make_function(sync_decode); |
||||
|
object _sync_encode = make_function(sync_encode); |
||||
|
|
||||
|
return call<object>(CodecInfo.ptr(), _sync_encode, _sync_decode); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
object distribution_search(string name) { |
||||
|
if (name != "pep.distribution") { |
||||
|
return object(); |
||||
|
} else { |
||||
|
object codecs = import("codecs"); |
||||
|
object CodecInfo = codecs.attr("CodecInfo"); |
||||
|
|
||||
|
object _distribution_decode = make_function(Distribution_decode); |
||||
|
object _distribution_encode = make_function(Distribution_encode); |
||||
|
|
||||
|
return call<object>(CodecInfo.ptr(), _distribution_encode, _distribution_decode); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} // namespace PythonAdapter
|
||||
|
} // namespace pEp {
|
@ -0,0 +1,30 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef MESSAGE_API_HH |
||||
|
#define MESSAGE_API_HH |
||||
|
|
||||
|
#include "pEpmodule.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
|
||||
|
Message encrypt_message( |
||||
|
Message src, |
||||
|
boost::python::list extra = boost::python::list(), |
||||
|
int enc_format = 4, |
||||
|
int flags = 0 |
||||
|
); |
||||
|
|
||||
|
boost::python::tuple decrypt_message(Message src, int flags = 0); |
||||
|
|
||||
|
PEP_color _color(int rating); |
||||
|
|
||||
|
object sync_search(string name); |
||||
|
|
||||
|
object distribution_search(string name); |
||||
|
|
||||
|
} /* namespace PythonAdapter */ |
||||
|
} /* namespace pEp */ |
||||
|
|
||||
|
#endif /* MESSAGE_API_HH */ |
@ -0,0 +1,656 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
// System
|
||||
|
#include <boost/python.hpp> |
||||
|
#include <boost/locale.hpp> |
||||
|
#include <string> |
||||
|
#include <sstream> |
||||
|
#include <iomanip> |
||||
|
#include <mutex> |
||||
|
|
||||
|
// Engine
|
||||
|
#include <pEp/key_reset.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
#include <pEp/sync_api.h> |
||||
|
#include <pEp/status_to_string.h> |
||||
|
|
||||
|
// libpEpAdapter
|
||||
|
#include <pEp/Adapter.hh> |
||||
|
#include <pEp/callback_dispatcher.hh> |
||||
|
#include <pEp/pEpLog.hh> |
||||
|
|
||||
|
// local
|
||||
|
#include "pEpmodule.hh" |
||||
|
#include "basic_api.hh" |
||||
|
#include "message_api.hh" |
||||
|
//#include "user_interface.hh"
|
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
using namespace std; |
||||
|
using namespace boost::python; |
||||
|
|
||||
|
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(string user_id, 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(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); |
||||
|
} |
||||
|
|
||||
|
static 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 (string(pEp_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(pEp_status_to_string(status)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
PEP_STATUS _messageToSend(::message *msg) { |
||||
|
pEpLog("called"); |
||||
|
try { |
||||
|
PyGILState_STATE gil = PyGILState_Ensure(); |
||||
|
pEpLog("GIL Aquired"); |
||||
|
object modref = import("pEp"); |
||||
|
object funcref = modref.attr("message_to_send"); |
||||
|
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"); |
||||
|
object modref = import("pEp"); |
||||
|
object funcref = modref.attr("notify_handshake"); |
||||
|
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(NULL); |
||||
|
} |
||||
|
|
||||
|
void deliverHandshakeResult(int result, object identities) { |
||||
|
identity_list *shared_identities = nullptr; |
||||
|
if (identities != boost::python::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 < boost::python::len(identities); ++i) { |
||||
|
Identity ident = 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); |
||||
|
} |
||||
|
|
||||
|
BOOST_PYTHON_MODULE(_pEp) { |
||||
|
init_before_main_module(); |
||||
|
|
||||
|
// Module init function called by pEp.init()
|
||||
|
def("_init_after_main_module", _init_after_main_module); |
||||
|
def("testfunc", &testfunc); |
||||
|
|
||||
|
docstring_options doc_options(true, false, false); |
||||
|
boost::locale::generator gen; |
||||
|
std::locale::global(gen("")); |
||||
|
|
||||
|
|
||||
|
scope().attr("about") = about(); |
||||
|
scope().attr("per_user_directory") = per_user_directory(); |
||||
|
scope().attr("per_machine_directory") = per_machine_directory(); |
||||
|
scope().attr("engine_version") = get_engine_version(); |
||||
|
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(boost::python::init<string>()) |
||||
|
.def(boost::python::init<string, string>()) |
||||
|
.def(boost::python::init<string, string, string>()) |
||||
|
.def(boost::python::init<string, string, string, string>()) |
||||
|
.def(boost::python::init<string, string, string, string, int>()) |
||||
|
.def(boost::python::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, |
||||
|
boost::python::arg("fpr")=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, |
||||
|
boost::python::arg("fpr")=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", |
||||
|
boost::python::init< object, char const*, char const* >(args("data", "mime_type", "filename"))) |
||||
|
.def(boost::python::init<object, string>()) |
||||
|
.def(boost::python::init<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(boost::python::init<int>()) |
||||
|
.def(boost::python::init<int, Identity *>()) |
||||
|
.def(boost::python::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", (boost::python::tuple(Message::*)()) &Message::attachments, |
||||
|
(void(Message::*)(boost::python::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::*)(object)) &Message::from, |
||||
|
"identity where message is from") |
||||
|
.add_property("to", (boost::python::list(Message::*)()) &Message::to, |
||||
|
(void(Message::*)(boost::python::list)) &Message::to, |
||||
|
"list of identities message is going to") |
||||
|
.add_property("recv_by", (Identity(Message::*)()) &Message::recv_by, |
||||
|
(void(Message::*)(object)) &Message::recv_by, |
||||
|
"identity where message was received by") |
||||
|
.add_property("cc", (boost::python::list(Message::*)()) &Message::cc, |
||||
|
(void(Message::*)(boost::python::list)) &Message::cc, |
||||
|
"list of identities message is going cc") |
||||
|
.add_property("bcc", (boost::python::list(Message::*)()) &Message::bcc, |
||||
|
(void(Message::*)(boost::python::list)) &Message::bcc, |
||||
|
"list of identities message is going bcc") |
||||
|
.add_property("reply_to", (boost::python::list(Message::*)()) &Message::reply_to, |
||||
|
(void(Message::*)(boost::python::list)) &Message::reply_to, |
||||
|
"list of identities where message will be replied to") |
||||
|
.add_property("in_reply_to", (boost::python::list(Message::*)()) &Message::in_reply_to, |
||||
|
(void(Message::*)(boost::python::list)) &Message::in_reply_to, |
||||
|
"in_reply_to list") |
||||
|
.add_property("references", (boost::python::list(Message::*)()) &Message::references, |
||||
|
(void(Message::*)(boost::python::list)) &Message::references, |
||||
|
"message IDs of messages this one is referring to") |
||||
|
.add_property("keywords", (boost::python::list(Message::*)()) &Message::keywords, |
||||
|
(void(Message::*)(boost::python::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", (dict(Message::*)()) &Message::opt_fields, |
||||
|
(void(Message::*)(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::*)(boost::python::list))&Message::_encrypt) |
||||
|
.def("encrypt", (Message(Message::*)(boost::python::list, int))&Message::_encrypt) |
||||
|
.def("encrypt", (Message(Message::*)(boost::python::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, boost::python::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,
|
||||
|
// boost::python::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, boost::python::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("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
|
||||
|
call< object >(((object)(import("codecs").attr("register"))).ptr(), make_function(sync_search)); |
||||
|
call< object >(((object)(import("codecs").attr("register"))).ptr(), make_function(distribution_search)); |
||||
|
} |
||||
|
|
||||
|
} // namespace PythonAdapter
|
||||
|
} // namespace pEp
|
@ -0,0 +1,35 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef PEPMODULE_HH |
||||
|
#define PEPMODULE_HH |
||||
|
|
||||
|
// Engine
|
||||
|
#include <pEp/pEpEngine.h> |
||||
|
|
||||
|
// local
|
||||
|
#include "message.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
|
||||
|
extern string device_name; |
||||
|
|
||||
|
void config_passive_mode(bool enable); |
||||
|
|
||||
|
void config_unencrypted_subject(bool enable); |
||||
|
|
||||
|
void key_reset_user(string user_id, string fpr); |
||||
|
|
||||
|
void key_reset_all_own_keys(); |
||||
|
|
||||
|
void _throw_status(PEP_STATUS status); |
||||
|
|
||||
|
PEP_STATUS _messageToSend(::message *msg); |
||||
|
|
||||
|
PEP_STATUS notifyHandshake(pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal); |
||||
|
|
||||
|
} /* namespace PythonAdapter */ |
||||
|
} /* namespace pEp */ |
||||
|
|
||||
|
#endif /* PEPMODULE_HH */ |
@ -0,0 +1,172 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
// System
|
||||
|
#include <cstdlib> |
||||
|
#include <boost/python.hpp> |
||||
|
#include <boost/locale.hpp> |
||||
|
|
||||
|
// local
|
||||
|
#include "str_attr.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
using namespace std; |
||||
|
using namespace boost::python; |
||||
|
using namespace boost::locale; |
||||
|
|
||||
|
object repr(object s) { |
||||
|
return s.attr("__repr__")(); |
||||
|
} |
||||
|
|
||||
|
string repr(string s) { |
||||
|
str _s = s.c_str(); |
||||
|
object _r = _s.attr("__repr__")(); |
||||
|
string r = extract<string>(_r); |
||||
|
return r; |
||||
|
} |
||||
|
|
||||
|
string str_attr(char *&str) { |
||||
|
if (!str) |
||||
|
return string(""); |
||||
|
return string(str); |
||||
|
} |
||||
|
|
||||
|
void str_attr(char *&str, string value) { |
||||
|
string normalized = normalize(value, 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); |
||||
|
} |
||||
|
|
||||
|
boost::python::list strlist_attr(stringlist_t *&sl) { |
||||
|
boost::python::list result; |
||||
|
|
||||
|
for (stringlist_t *_sl = sl; _sl && _sl->value; _sl = _sl->next) { |
||||
|
string s(_sl->value); |
||||
|
result.append(object(s)); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
void strlist_attr(stringlist_t *&sl, boost::python::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++) { |
||||
|
extract <string> extract_string(value[i]); |
||||
|
if (!extract_string.check()) { |
||||
|
free_stringlist(_sl); |
||||
|
} |
||||
|
string s = extract_string(); |
||||
|
s = normalize(s, norm_nfc); |
||||
|
_s = stringlist_add(_s, s.c_str()); |
||||
|
if (!_s) { |
||||
|
free_stringlist(_sl); |
||||
|
throw bad_alloc(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
free_stringlist(sl); |
||||
|
sl = _sl; |
||||
|
} |
||||
|
|
||||
|
dict strdict_attr(stringpair_list_t *&spl) { |
||||
|
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, dict value) { |
||||
|
stringpair_list_t *_spl = new_stringpair_list(NULL); |
||||
|
if (!_spl) |
||||
|
throw bad_alloc(); |
||||
|
|
||||
|
stringpair_list_t *_s = _spl; |
||||
|
for (int i = 0; i < len(value); i++) { |
||||
|
extract <string> extract_key(value.keys()[i]); |
||||
|
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, norm_nfc); |
||||
|
string _value = extract_value(); |
||||
|
_value = normalize(_value, 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(boost::python::list l) { |
||||
|
stringlist_t *result = new_stringlist(NULL); |
||||
|
if (!result) |
||||
|
throw bad_alloc(); |
||||
|
|
||||
|
stringlist_t *_s = result; |
||||
|
for (int i = 0; i < len(l); i++) { |
||||
|
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; |
||||
|
} |
||||
|
|
||||
|
boost::python::list from_stringlist(const stringlist_t *sl) { |
||||
|
boost::python::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 {
|
||||
|
|
@ -0,0 +1,123 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
// System
|
||||
|
#include <cassert> |
||||
|
|
||||
|
// local
|
||||
|
#include "user_interface.hh" |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace PythonAdapter { |
||||
|
using namespace std; |
||||
|
using namespace boost::python; |
||||
|
|
||||
|
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, object identities) { |
||||
|
identity_list *shared_identities = nullptr; |
||||
|
if (identities != boost::python::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 < boost::python::len(identities); ++i) { |
||||
|
Identity ident = 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}}, NULL);
|
||||
|
// }
|
||||
|
//
|
||||
|
// if (timeout)
|
||||
|
// return new_sync_timeout_event();
|
||||
|
//
|
||||
|
// return adapter.queue().pop_front();
|
||||
|
//}
|
||||
|
|
||||
|
void UserInterface_callback::notifyHandshake( |
||||
|
Identity me, Identity partner, sync_handshake_signal signal) { |
||||
|
call_method<void>(_self, "notifyHandshake", me, partner, signal); |
||||
|
} |
||||
|
|
||||
|
} // namespace PythonAdapter
|
||||
|
} // namespace pEp {
|
||||
|
|
@ -0,0 +1,61 @@ |
|||||
|
// This file is under GNU Affero General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef USER_INTERFACE_HH |
||||
|
#define USER_INTERFACE_HH |
||||
|
|
||||
|
// System
|
||||
|
#include <csetjmp> |
||||
|
|
||||
|
// Engine
|
||||
|
#include <pEp/sync_api.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
|
||||
|
// local
|
||||
|
#include "pEpmodule.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, 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,172 +0,0 @@ |
|||||
// This file is under GNU Affero General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
// System
|
|
||||
#include <sstream> |
|
||||
|
|
||||
// Engine
|
|
||||
#include <pEp/keymanagement.h> |
|
||||
#include <pEp/message_api.h> |
|
||||
#include <pEp/Adapter.hh> |
|
||||
|
|
||||
// local
|
|
||||
#include "basic_api.hh" |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace PythonAdapter { |
|
||||
using namespace std; |
|
||||
|
|
||||
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 = NULL; |
|
||||
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, 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, 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); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
boost::python::list import_key(string key_data) |
|
||||
{ |
|
||||
::identity_list *private_keys = NULL; |
|
||||
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 = boost::python::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 = NULL; |
|
||||
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, 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,30 +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 "pEpmodule.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, identity_flags_t flags); |
|
||||
void unset_identity_flags(Identity ident, identity_flags_t flags); |
|
||||
|
|
||||
void key_reset_trust(Identity ident); |
|
||||
|
|
||||
boost::python::list import_key(string key_data); |
|
||||
string export_key(Identity ident); |
|
||||
string export_secret_key(Identity ident); |
|
||||
void set_own_key(Identity& ident, string fpr); |
|
||||
|
|
||||
} /* namespace PythonAdapter */ |
|
||||
} /* namespace pEp */ |
|
||||
|
|
||||
#endif /* BASIC_API_HH */ |
|
@ -1,285 +0,0 @@ |
|||||
// This file is under GNU Affero General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
// System
|
|
||||
#include <typeinfo> |
|
||||
#include <sstream> |
|
||||
|
|
||||
// Engine
|
|
||||
#include <pEp/identity_list.h> |
|
||||
#include <pEp/keymanagement.h> |
|
||||
#include <pEp/key_reset.h> |
|
||||
|
|
||||
// local
|
|
||||
#include "identity.hh" |
|
||||
#include "pEpmodule.hh" |
|
||||
#include "basic_api.hh" |
|
||||
#include "message_api.hh" |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace PythonAdapter { |
|
||||
using namespace std; |
|
||||
using namespace boost::python; |
|
||||
|
|
||||
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(dict&) |
|
||||
{ |
|
||||
return copy(); |
|
||||
} |
|
||||
|
|
||||
void Identity::update() |
|
||||
{ |
|
||||
update_identity(*this); |
|
||||
} |
|
||||
|
|
||||
void Identity::key_reset(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, object value) |
|
||||
{ |
|
||||
Identity& _ident = 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; |
|
||||
} |
|
||||
|
|
||||
boost::python::list identitylist_attr(identity_list *&il) |
|
||||
{ |
|
||||
boost::python::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(object(Identity(ident))); |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
void identitylist_attr(identity_list *&il, boost::python::list value) |
|
||||
{ |
|
||||
identity_list *_il = new_identity_list(NULL); |
|
||||
if (!_il) |
|
||||
throw bad_alloc(); |
|
||||
|
|
||||
identity_list *_i = _il; |
|
||||
for (int i=0; i<len(value); i++) { |
|
||||
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,102 +0,0 @@ |
|||||
// This file is under GNU Affero General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#ifndef IDENTITY_HH |
|
||||
#define IDENTITY_HH |
|
||||
|
|
||||
// System
|
|
||||
#include <boost/python.hpp> |
|
||||
#include <string> |
|
||||
#include <memory> |
|
||||
#include <cstddef> |
|
||||
|
|
||||
// Engine
|
|
||||
#include <pEp/pEpEngine.h> |
|
||||
#include <pEp/message_api.h> |
|
||||
|
|
||||
//libpEpAdapter
|
|
||||
#include "pEp/Adapter.hh" |
|
||||
|
|
||||
// local
|
|
||||
#include "str_attr.hh" |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace PythonAdapter { |
|
||||
|
|
||||
using std::string; |
|
||||
using std::shared_ptr; |
|
||||
|
|
||||
// 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(dict& memo); |
|
||||
|
|
||||
virtual void update(); |
|
||||
|
|
||||
void key_reset(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, object value); |
|
||||
|
|
||||
boost::python::list identitylist_attr(identity_list *&il); |
|
||||
void identitylist_attr(identity_list *&il, boost::python::list value); |
|
||||
|
|
||||
} /* namespace PythonAdapter */ |
|
||||
} /* namespace pEp */ |
|
||||
|
|
||||
#endif /* IDENTITY_HH */ |
|
@ -1,413 +0,0 @@ |
|||||
// This file is under GNU Affero General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
// System
|
|
||||
#include <cstdlib> |
|
||||
#include <cstring> |
|
||||
#include <stdexcept> |
|
||||
#include <sstream> |
|
||||
#include <vector> |
|
||||
#include <Python.h> |
|
||||
|
|
||||
// Engine
|
|
||||
#include <pEp/mime.h> |
|
||||
#include <pEp/keymanagement.h> |
|
||||
#include <pEp/message_api.h> |
|
||||
|
|
||||
// local
|
|
||||
#include "message.hh" |
|
||||
#include "message_api.hh" |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace PythonAdapter { |
|
||||
using namespace std; |
|
||||
using namespace boost::python; |
|
||||
|
|
||||
Message::Blob::Blob(bloblist_t *bl, bool chained) : |
|
||||
_bl(bl), part_of_chain(chained) |
|
||||
{ |
|
||||
if (!_bl) |
|
||||
throw bad_alloc(); |
|
||||
} |
|
||||
|
|
||||
Message::Blob::Blob(object data, string mime_type, string filename) : |
|
||||
_bl(new_bloblist(NULL, 0, NULL, NULL)), 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 = NULL; |
|
||||
|
|
||||
try { |
|
||||
Message::Blob& blob = extract< Message::Blob& >(self); |
|
||||
bl = blob._bl; |
|
||||
} |
|
||||
catch (exception& e) { |
|
||||
PyErr_SetString(PyExc_RuntimeError, "extract not possible"); |
|
||||
view->obj = NULL; |
|
||||
return -1; |
|
||||
} |
|
||||
|
|
||||
if (!(bl && bl->value)) { |
|
||||
PyErr_SetString(PyExc_RuntimeError, "no data available"); |
|
||||
view->obj = NULL; |
|
||||
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"; |
|
||||
|
|
||||
} |
|
||||
object codecs = import("codecs"); |
|
||||
object _decode = codecs.attr("decode"); |
|
||||
return call< string >(_decode.ptr(), this, encoding); |
|
||||
} |
|
||||
|
|
||||
PyBufferProcs Message::Blob::bp = { getbuffer, NULL }; |
|
||||
|
|
||||
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(NULL, &free_message) |
|
||||
{ |
|
||||
message *_cpy; |
|
||||
PEP_STATUS status = mime_decode_message(mimetext.c_str(), |
|
||||
mimetext.size(), &_cpy, NULL); |
|
||||
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(); |
|
||||
} |
|
||||
|
|
||||
boost::python::tuple Message::attachments() |
|
||||
{ |
|
||||
boost::python::list l; |
|
||||
|
|
||||
for (bloblist_t *bl = _msg->attachments; bl && bl->value; bl = |
|
||||
bl->next) { |
|
||||
l.append(Blob(bl, true)); |
|
||||
} |
|
||||
|
|
||||
return boost::python::tuple(l); |
|
||||
} |
|
||||
|
|
||||
void Message::attachments(boost::python::list value) |
|
||||
{ |
|
||||
bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL); |
|
||||
if (!bl) |
|
||||
throw bad_alloc(); |
|
||||
|
|
||||
bloblist_t *_l = bl; |
|
||||
for (int i=0; i<len(value); i++) { |
|
||||
Message::Blob& blob = 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 = extract< Message::Blob& >(value[i]); |
|
||||
blob._bl->value = NULL; |
|
||||
blob._bl->size = 0; |
|
||||
free(blob._bl->mime_type); |
|
||||
blob._bl->mime_type = NULL; |
|
||||
free(blob._bl->filename); |
|
||||
blob._bl->filename = NULL; |
|
||||
} |
|
||||
|
|
||||
free_bloblist(_msg->attachments); |
|
||||
_msg->attachments = bl; |
|
||||
} |
|
||||
|
|
||||
Message Message::encrypt() |
|
||||
{ |
|
||||
boost::python::list extra; |
|
||||
return encrypt_message(*this, extra, PEP_enc_PGP_MIME, 0); |
|
||||
} |
|
||||
|
|
||||
Message Message::_encrypt(boost::python::list extra, int enc_format, int flags) |
|
||||
{ |
|
||||
if (!enc_format) |
|
||||
enc_format = PEP_enc_PGP_MIME; |
|
||||
return encrypt_message(*this, extra, enc_format, flags); |
|
||||
} |
|
||||
|
|
||||
boost::python::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(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 object update(Identity ident) |
|
||||
{ |
|
||||
if (ident.address().empty()) |
|
||||
throw runtime_error("at least address needed"); |
|
||||
update_identity(Adapter::session(), ident); |
|
||||
return object(ident); |
|
||||
} |
|
||||
|
|
||||
static boost::python::list update(boost::python::list il) |
|
||||
{ |
|
||||
for (int i=0; i<len(il); i++) { |
|
||||
update(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,154 +0,0 @@ |
|||||
// This file is under GNU Affero General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#ifndef MESSAGE_HH |
|
||||
#define MESSAGE_HH |
|
||||
|
|
||||
// System
|
|
||||
#include <string> |
|
||||
#include <boost/python.hpp> |
|
||||
#include <boost/lexical_cast.hpp> |
|
||||
|
|
||||
// Engine
|
|
||||
#include <pEp/message.h> |
|
||||
#include <pEp/message_api.h> |
|
||||
|
|
||||
// local
|
|
||||
#include "str_attr.hh" |
|
||||
#include "identity.hh" |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace PythonAdapter { |
|
||||
using std::string; |
|
||||
using std::runtime_error; |
|
||||
using std::invalid_argument; |
|
||||
using boost::lexical_cast; |
|
||||
|
|
||||
// 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(NULL, 0, NULL, NULL), |
|
||||
bool chained = false); |
|
||||
Blob(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 = NULL); |
|
||||
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); } |
|
||||
|
|
||||
boost::python::tuple attachments(); |
|
||||
void attachments(boost::python::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(object value) { identity_attr(_msg->from, value); } |
|
||||
|
|
||||
boost::python::list to() { return identitylist_attr(_msg->to); } |
|
||||
void to(boost::python::list value) { identitylist_attr(_msg->to, value); } |
|
||||
|
|
||||
Identity recv_by() { return identity_attr(_msg->recv_by); } |
|
||||
void recv_by(object value) { identity_attr(_msg->recv_by, value); } |
|
||||
|
|
||||
boost::python::list cc() { return identitylist_attr(_msg->cc); } |
|
||||
void cc(boost::python::list value) { identitylist_attr(_msg->cc, value); } |
|
||||
|
|
||||
boost::python::list bcc() { return identitylist_attr(_msg->bcc); } |
|
||||
void bcc(boost::python::list value) { identitylist_attr(_msg->bcc, value); } |
|
||||
|
|
||||
boost::python::list reply_to() { return identitylist_attr(_msg->reply_to); } |
|
||||
void reply_to(boost::python::list value) { identitylist_attr(_msg->reply_to, value); } |
|
||||
|
|
||||
boost::python::list in_reply_to() { return strlist_attr(_msg->in_reply_to); } |
|
||||
void in_reply_to(boost::python::list value) { strlist_attr(_msg->in_reply_to, value); } |
|
||||
|
|
||||
boost::python::list references() { return strlist_attr(_msg->references); } |
|
||||
void references(boost::python::list value) { strlist_attr(_msg->references, value); } |
|
||||
|
|
||||
boost::python::list keywords() { return strlist_attr(_msg->keywords); } |
|
||||
void keywords(boost::python::list value) { strlist_attr(_msg->keywords, value); } |
|
||||
|
|
||||
string comments() { return str_attr(_msg->comments); } |
|
||||
void comments(string value) { str_attr(_msg->comments, value); } |
|
||||
|
|
||||
dict opt_fields() { return strdict_attr(_msg->opt_fields); } |
|
||||
void opt_fields(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(boost::python::list extra, int enc_format=4, int flags=0); |
|
||||
|
|
||||
boost::python::tuple decrypt(int flags=0); |
|
||||
PEP_rating outgoing_rating(); |
|
||||
PEP_color outgoing_color(); |
|
||||
Message deepcopy(dict& memo); |
|
||||
Message copy(); |
|
||||
}; |
|
||||
|
|
||||
Message outgoing_message(Identity me); |
|
||||
Message incoming_message(string mime_text); |
|
||||
|
|
||||
} /* namespace PythonAdapter */ |
|
||||
} /* namespace pEp */ |
|
||||
|
|
||||
#endif /* MESSAGE_HH */ |
|
@ -1,172 +0,0 @@ |
|||||
// This file is under GNU Affero General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
// Engine
|
|
||||
#include <pEp/pEpEngine.h> |
|
||||
#include <pEp/message_api.h> |
|
||||
#include <pEp/sync_api.h> |
|
||||
#include <pEp/sync_codec.h> |
|
||||
#include <pEp/distribution_codec.h> |
|
||||
|
|
||||
// local
|
|
||||
#include "message_api.hh" |
|
||||
#include "basic_api.hh" |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace PythonAdapter { |
|
||||
using namespace std; |
|
||||
using namespace boost::python; |
|
||||
|
|
||||
Message encrypt_message(Message src, boost::python::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 = NULL; |
|
||||
|
|
||||
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); |
|
||||
} |
|
||||
|
|
||||
boost::python::tuple decrypt_message(Message src, int flags) |
|
||||
{ |
|
||||
message *_dst = NULL; |
|
||||
stringlist_t *_keylist = NULL; |
|
||||
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); |
|
||||
|
|
||||
boost::python::list keylist; |
|
||||
if (_keylist) { |
|
||||
keylist = from_stringlist(_keylist); |
|
||||
free_stringlist(_keylist); |
|
||||
} |
|
||||
|
|
||||
Message dst = _dst ? Message(_dst) : Message(src); |
|
||||
return boost::python::make_tuple(dst, keylist, _rating, _flags); |
|
||||
} |
|
||||
|
|
||||
PEP_color _color(int rating) |
|
||||
{ |
|
||||
return ::color_from_rating((PEP_rating) rating); |
|
||||
} |
|
||||
|
|
||||
boost::python::tuple sync_decode(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 = NULL; |
|
||||
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 boost::python::make_tuple(_dst, 0); |
|
||||
} |
|
||||
|
|
||||
static boost::python::tuple sync_encode(string text) |
|
||||
{ |
|
||||
char *data = NULL; |
|
||||
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 boost::python::make_tuple(object(handle<>(ba)), 0); |
|
||||
} |
|
||||
|
|
||||
boost::python::tuple Distribution_decode(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 = NULL; |
|
||||
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 boost::python::make_tuple(_dst, 0); |
|
||||
} |
|
||||
|
|
||||
static boost::python::tuple Distribution_encode(string text) |
|
||||
{ |
|
||||
char *data = NULL; |
|
||||
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 boost::python::make_tuple(object(handle<>(ba)), 0); |
|
||||
} |
|
||||
|
|
||||
object sync_search(string name) |
|
||||
{ |
|
||||
if (name != "pep.sync") { |
|
||||
return object(); |
|
||||
} |
|
||||
else { |
|
||||
object codecs = import("codecs"); |
|
||||
object CodecInfo = codecs.attr("CodecInfo"); |
|
||||
|
|
||||
object _sync_decode = make_function(sync_decode); |
|
||||
object _sync_encode = make_function(sync_encode); |
|
||||
|
|
||||
return call< object >(CodecInfo.ptr(), _sync_encode, _sync_decode); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
object distribution_search(string name) |
|
||||
{ |
|
||||
if (name != "pep.distribution") { |
|
||||
return object(); |
|
||||
} |
|
||||
else { |
|
||||
object codecs = import("codecs"); |
|
||||
object CodecInfo = codecs.attr("CodecInfo"); |
|
||||
|
|
||||
object _distribution_decode = make_function(Distribution_decode); |
|
||||
object _distribution_encode = make_function(Distribution_encode); |
|
||||
|
|
||||
return call< object >(CodecInfo.ptr(), _distribution_encode, _distribution_decode); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} // namespace PythonAdapter
|
|
||||
} // namespace pEp {
|
|
@ -1,27 +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 "pEpmodule.hh" |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace PythonAdapter { |
|
||||
|
|
||||
Message encrypt_message( |
|
||||
Message src, |
|
||||
boost::python::list extra = boost::python::list(), |
|
||||
int enc_format = 4, |
|
||||
int flags = 0 |
|
||||
); |
|
||||
|
|
||||
boost::python::tuple decrypt_message(Message src, int flags=0); |
|
||||
PEP_color _color(int rating); |
|
||||
object sync_search(string name); |
|
||||
object distribution_search(string name); |
|
||||
|
|
||||
} /* namespace PythonAdapter */ |
|
||||
} /* namespace pEp */ |
|
||||
|
|
||||
#endif /* MESSAGE_API_HH */ |
|
@ -1,673 +0,0 @@ |
|||||
// This file is under GNU Affero General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
// System
|
|
||||
#include <boost/python.hpp> |
|
||||
#include <boost/locale.hpp> |
|
||||
#include <string> |
|
||||
#include <sstream> |
|
||||
#include <iomanip> |
|
||||
#include <mutex> |
|
||||
|
|
||||
// Engine
|
|
||||
#include <pEp/key_reset.h> |
|
||||
#include <pEp/message_api.h> |
|
||||
#include <pEp/sync_api.h> |
|
||||
#include <pEp/status_to_string.h> |
|
||||
|
|
||||
// libpEpAdapter
|
|
||||
#include <pEp/Adapter.hh> |
|
||||
#include <pEp/callback_dispatcher.hh> |
|
||||
#include <pEp/pEpLog.hh> |
|
||||
|
|
||||
// local
|
|
||||
#include "pEpmodule.hh" |
|
||||
#include "basic_api.hh" |
|
||||
#include "message_api.hh" |
|
||||
//#include "user_interface.hh"
|
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace PythonAdapter { |
|
||||
using namespace std; |
|
||||
using namespace boost::python; |
|
||||
|
|
||||
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(string user_id, 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(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); |
|
||||
} |
|
||||
|
|
||||
static 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 (string(pEp_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(pEp_status_to_string(status)); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
PEP_STATUS _messageToSend(::message *msg) |
|
||||
{ |
|
||||
pEpLog("called"); |
|
||||
try { |
|
||||
PyGILState_STATE gil = PyGILState_Ensure(); |
|
||||
pEpLog("GIL Aquired"); |
|
||||
object modref = import("pEp"); |
|
||||
object funcref = modref.attr("message_to_send"); |
|
||||
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"); |
|
||||
object modref = import("pEp"); |
|
||||
object funcref = modref.attr("notify_handshake"); |
|
||||
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(NULL); |
|
||||
} |
|
||||
|
|
||||
void deliverHandshakeResult(int result, object identities) |
|
||||
{ |
|
||||
identity_list *shared_identities = nullptr; |
|
||||
if (identities != boost::python::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 < boost::python::len(identities); ++i) { |
|
||||
Identity ident = 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); |
|
||||
} |
|
||||
|
|
||||
BOOST_PYTHON_MODULE(native_pEp) |
|
||||
{ |
|
||||
init_before_main_module(); |
|
||||
|
|
||||
// Module init function called by pEp.init()
|
|
||||
def("_init_after_main_module", _init_after_main_module); |
|
||||
def("testfunc", &testfunc); |
|
||||
|
|
||||
docstring_options doc_options(true, false, false); |
|
||||
boost::locale::generator gen; |
|
||||
std::locale::global(gen("")); |
|
||||
|
|
||||
// _scope = new scope();
|
|
||||
scope().attr("about") = about(); |
|
||||
scope().attr("per_user_directory") = per_user_directory(); |
|
||||
scope().attr("per_machine_directory") = per_machine_directory(); |
|
||||
scope().attr("engine_version") = get_engine_version(); |
|
||||
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(boost::python::init<string>()) |
|
||||
.def(boost::python::init<string, string>()) |
|
||||
.def(boost::python::init<string, string, string>()) |
|
||||
.def(boost::python::init<string, string, string, string>()) |
|
||||
.def(boost::python::init<string, string, string, string, int>()) |
|
||||
.def(boost::python::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, |
|
||||
boost::python::arg("fpr")=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, |
|
||||
boost::python::arg("fpr")=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" , |
|
||||
boost::python::init< object, char const*, char const* >(args("data", "mime_type", "filename"))) |
|
||||
.def(boost::python::init<object, string>()) |
|
||||
.def(boost::python::init<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(boost::python::init<int>()) |
|
||||
.def(boost::python::init<int, Identity *>()) |
|
||||
.def(boost::python::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", (boost::python::tuple(Message::*)()) &Message::attachments, |
|
||||
(void(Message::*)(boost::python::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::*)(object)) &Message::from, |
|
||||
"identity where message is from") |
|
||||
.add_property("to", (boost::python::list(Message::*)()) &Message::to, |
|
||||
(void(Message::*)(boost::python::list)) &Message::to, |
|
||||
"list of identities message is going to") |
|
||||
.add_property("recv_by", (Identity(Message::*)()) &Message::recv_by, |
|
||||
(void(Message::*)(object)) &Message::recv_by, |
|
||||
"identity where message was received by") |
|
||||
.add_property("cc", (boost::python::list(Message::*)()) &Message::cc, |
|
||||
(void(Message::*)(boost::python::list)) &Message::cc, |
|
||||
"list of identities message is going cc") |
|
||||
.add_property("bcc", (boost::python::list(Message::*)()) &Message::bcc, |
|
||||
(void(Message::*)(boost::python::list)) &Message::bcc, |
|
||||
"list of identities message is going bcc") |
|
||||
.add_property("reply_to", (boost::python::list(Message::*)()) &Message::reply_to, |
|
||||
(void(Message::*)(boost::python::list)) &Message::reply_to, |
|
||||
"list of identities where message will be replied to") |
|
||||
.add_property("in_reply_to", (boost::python::list(Message::*)()) &Message::in_reply_to, |
|
||||
(void(Message::*)(boost::python::list)) &Message::in_reply_to, |
|
||||
"in_reply_to list") |
|
||||
.add_property("references", (boost::python::list(Message::*)()) &Message::references, |
|
||||
(void(Message::*)(boost::python::list)) &Message::references, |
|
||||
"message IDs of messages this one is referring to") |
|
||||
.add_property("keywords", (boost::python::list(Message::*)()) &Message::keywords, |
|
||||
(void(Message::*)(boost::python::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", (dict(Message::*)()) &Message::opt_fields, |
|
||||
(void(Message::*)(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::*)(boost::python::list))&Message::_encrypt) |
|
||||
.def("encrypt", (Message(Message::*)(boost::python::list,int))&Message::_encrypt) |
|
||||
.def("encrypt", (Message(Message::*)(boost::python::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, boost::python::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,
|
|
||||
// boost::python::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, boost::python::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("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
|
|
||||
call< object >(((object)(import("codecs").attr("register"))).ptr(), make_function(sync_search)); |
|
||||
call< object >(((object)(import("codecs").attr("register"))).ptr(), make_function(distribution_search)); |
|
||||
} |
|
||||
|
|
||||
} // namespace PythonAdapter
|
|
||||
} // namespace pEp
|
|
@ -1,28 +0,0 @@ |
|||||
// This file is under GNU Affero General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#ifndef PEPMODULE_HH |
|
||||
#define PEPMODULE_HH |
|
||||
|
|
||||
// Engine
|
|
||||
#include <pEp/pEpEngine.h> |
|
||||
|
|
||||
// local
|
|
||||
#include "message.hh" |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace PythonAdapter { |
|
||||
|
|
||||
extern string device_name; |
|
||||
void config_passive_mode(bool enable); |
|
||||
void config_unencrypted_subject(bool enable); |
|
||||
void key_reset_user(string user_id, string fpr); |
|
||||
void key_reset_all_own_keys(); |
|
||||
void _throw_status(PEP_STATUS status); |
|
||||
PEP_STATUS _messageToSend(::message *msg); |
|
||||
PEP_STATUS notifyHandshake(pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal); |
|
||||
|
|
||||
} /* namespace PythonAdapter */ |
|
||||
} /* namespace pEp */ |
|
||||
|
|
||||
#endif /* PEPMODULE_HH */ |
|
@ -1,184 +0,0 @@ |
|||||
// This file is under GNU Affero General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
// System
|
|
||||
#include <cstdlib> |
|
||||
#include <boost/python.hpp> |
|
||||
#include <boost/locale.hpp> |
|
||||
|
|
||||
// local
|
|
||||
#include "str_attr.hh" |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace PythonAdapter { |
|
||||
using namespace std; |
|
||||
using namespace boost::python; |
|
||||
using namespace boost::locale; |
|
||||
|
|
||||
object repr(object s) |
|
||||
{ |
|
||||
return s.attr("__repr__")(); |
|
||||
} |
|
||||
|
|
||||
string repr(string s) |
|
||||
{ |
|
||||
str _s = s.c_str(); |
|
||||
object _r = _s.attr("__repr__")(); |
|
||||
string r = extract< string >(_r); |
|
||||
return r; |
|
||||
} |
|
||||
|
|
||||
string str_attr(char *&str) |
|
||||
{ |
|
||||
if (!str) |
|
||||
return string(""); |
|
||||
return string(str); |
|
||||
} |
|
||||
|
|
||||
void str_attr(char *&str, string value) |
|
||||
{ |
|
||||
string normalized = normalize(value, 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); |
|
||||
} |
|
||||
|
|
||||
boost::python::list strlist_attr(stringlist_t *&sl) |
|
||||
{ |
|
||||
boost::python::list result; |
|
||||
|
|
||||
for (stringlist_t *_sl = sl; _sl && _sl->value; _sl = _sl->next) { |
|
||||
string s(_sl->value); |
|
||||
result.append(object(s)); |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
void strlist_attr(stringlist_t *&sl, boost::python::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++) { |
|
||||
extract< string > extract_string(value[i]); |
|
||||
if (!extract_string.check()) { |
|
||||
free_stringlist(_sl); |
|
||||
} |
|
||||
string s = extract_string(); |
|
||||
s = normalize(s, norm_nfc); |
|
||||
_s = stringlist_add(_s, s.c_str()); |
|
||||
if (!_s) { |
|
||||
free_stringlist(_sl); |
|
||||
throw bad_alloc(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
free_stringlist(sl); |
|
||||
sl = _sl; |
|
||||
} |
|
||||
|
|
||||
dict strdict_attr(stringpair_list_t *&spl) |
|
||||
{ |
|
||||
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, dict value) |
|
||||
{ |
|
||||
stringpair_list_t *_spl = new_stringpair_list(NULL); |
|
||||
if (!_spl) |
|
||||
throw bad_alloc(); |
|
||||
|
|
||||
stringpair_list_t *_s = _spl; |
|
||||
for (int i=0; i<len(value); i++) { |
|
||||
extract< string > extract_key(value.keys()[i]); |
|
||||
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, norm_nfc); |
|
||||
string _value = extract_value(); |
|
||||
_value = normalize(_value, 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(boost::python::list l) |
|
||||
{ |
|
||||
stringlist_t *result = new_stringlist(NULL); |
|
||||
if (!result) |
|
||||
throw bad_alloc(); |
|
||||
|
|
||||
stringlist_t *_s = result; |
|
||||
for (int i=0; i<len(l); i++) { |
|
||||
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; |
|
||||
} |
|
||||
|
|
||||
boost::python::list from_stringlist(const stringlist_t *sl) |
|
||||
{ |
|
||||
boost::python::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,130 +0,0 @@ |
|||||
// This file is under GNU Affero General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
// System
|
|
||||
#include <cassert> |
|
||||
|
|
||||
// local
|
|
||||
#include "user_interface.hh" |
|
||||
|
|
||||
namespace pEp { |
|
||||
namespace PythonAdapter { |
|
||||
using namespace std; |
|
||||
using namespace boost::python; |
|
||||
|
|
||||
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, object identities) |
|
||||
{ |
|
||||
identity_list *shared_identities = nullptr; |
|
||||
if (identities != boost::python::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 < boost::python::len(identities); ++i) { |
|
||||
Identity ident = 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}}, NULL);
|
|
||||
// }
|
|
||||
//
|
|
||||
// if (timeout)
|
|
||||
// return new_sync_timeout_event();
|
|
||||
//
|
|
||||
// return adapter.queue().pop_front();
|
|
||||
//}
|
|
||||
|
|
||||
void UserInterface_callback::notifyHandshake( |
|
||||
Identity me, Identity partner, sync_handshake_signal signal) |
|
||||
{ |
|
||||
call_method< void >(_self, "notifyHandshake", me, partner, signal); |
|
||||
} |
|
||||
|
|
||||
} // namespace PythonAdapter
|
|
||||
} // namespace pEp {
|
|
||||
|
|
@ -1,60 +0,0 @@ |
|||||
// This file is under GNU Affero General Public License 3.0
|
|
||||
// see LICENSE.txt
|
|
||||
|
|
||||
#ifndef USER_INTERFACE_HH |
|
||||
#define USER_INTERFACE_HH |
|
||||
|
|
||||
// System
|
|
||||
#include <csetjmp> |
|
||||
|
|
||||
// Engine
|
|
||||
#include <pEp/sync_api.h> |
|
||||
#include <pEp/message_api.h> |
|
||||
|
|
||||
// local
|
|
||||
#include "pEpmodule.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, 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,27 +0,0 @@ |
|||||
#!/usr/bin/env python3 |
|
||||
# -*- coding: utf-8 -*- |
|
||||
|
|
||||
""" |
|
||||
>>> import pEp |
|
||||
>>> me = pEp.Identity("alice.smith@peptest.ch", "Alice Smith", "23") |
|
||||
>>> me.username |
|
||||
'Alice Smith' |
|
||||
>>> print(me) |
|
||||
Alice Smith <alice.smith@peptest.ch> |
|
||||
>>> you = pEp.Identity("bob.bourne@peptest.ch", "Bob Bourne", "42") |
|
||||
>>> print(you) |
|
||||
Bob Bourne <bob.bourne@peptest.ch> |
|
||||
>>> m = pEp.outgoing_message(me) |
|
||||
>>> m.to = [you] |
|
||||
>>> m.shortmsg = "let's meet next week" |
|
||||
>>> m.longmsg = "Please call me back" |
|
||||
>>> m2 = m.encrypt() |
|
||||
>>> print(m2) |
|
||||
>>> m3, keys, rating, flags = m2.decrypt() |
|
||||
>>> rating |
|
||||
pEp.rating.reliable |
|
||||
""" |
|
||||
|
|
||||
if __name__ == "__main__": |
|
||||
import doctest |
|
||||
doctest.testmod() |
|
@ -0,0 +1,3 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# This file is under GNU Affero General Public License 3.0 |
||||
|
# see LICENSE.txt |
@ -0,0 +1,64 @@ |
|||||
|
# -*- 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 |
@ -0,0 +1,12 @@ |
|||||
|
# -*- 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" |
@ -0,0 +1,24 @@ |
|||||
|
-----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----- |
@ -0,0 +1,26 @@ |
|||||
|
-----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----- |
@ -0,0 +1,24 @@ |
|||||
|
-----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----- |
@ -0,0 +1,26 @@ |
|||||
|
-----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----- |
@ -0,0 +1,24 @@ |
|||||
|
-----BEGIN PGP PUBLIC KEY BLOCK----- |
||||
|
Comment: 3E45 175E E953 EBBE B948 F11A 6A03 DB2A 17FB 9D15 |
||||
|
Comment: alice_work@peptest.org |
||||
|
|
||||
|
xjMEXxFT7BYJKwYBBAHaRw8BAQdAToI/CRX5M3LjPpSCfmJtOngHTos502W02e4e |
||||
|
I1CyNE/ChAQfFgoAFQWCXxFT7AWJBaSPvQIVCgKbAQIeAQAhCRBqA9sqF/udFRYh |
||||
|
BD5FF17pU+u+uUjxGmoD2yoX+50VV9cA/1HmBlEd6SVkhAK7dP46yGQtEJLix5x+ |
||||
|
Z14COnk/EKETAP9Roz7sJakpqC/VejESHekpt5DterDWAXc4hjf1ADutDc0WYWxp |
||||
|
Y2Vfd29ya0BwZXB0ZXN0Lm9yZ8KEBBMWCgAVBYJfEVPsBYkFpI+9AhUKApsBAh4B |
||||
|
ACEJEGoD2yoX+50VFiEEPkUXXulT6765SPEaagPbKhf7nRVc2wD/Q7ISeG3cDbji |
||||
|
W+17gSnlYEYtG5EjIzGavYMr2tPhAlcA/RpuaaYkB+9FGYapXpKEZfOa9gRfg4sY |
||||
|
l2jIK5QNWYcDzjMEXxFT7BYJKwYBBAHaRw8BAQdAnljLgkOQD0jx8eoIbV0rUN1o |
||||
|
m5mux0+pLHZ6sIt+yD7CwDsEGBYKABUFgl8RU+wFiQWkj70CFQoCmwICHgEAmAkQ |
||||
|
agPbKhf7nRV2oAQZFgoABgWCXxFT7AAhCRBLlptQp2yWJxYhBMqF7w4SDl18JRD6 |
||||
|
akuWm1CnbJYnUBEBAM55LvWxQ7Mi65AJEGhRlqGzCexUDheuXgVZYbqboc2wAQDc |
||||
|
SUxqP5Jbq66pAWSpHBTgT1rrZW9RbsA+yOA9B6DpBxYhBD5FF17pU+u+uUjxGmoD |
||||
|
2yoX+50VAjgBANay4I3jqeDBCkUlxPQZr0wlcxhiZW4m6NSamTqQvsLCAPwPivrv |
||||
|
YXaMc4zGSAesvk0Mwo5+2eX984EiHzsW+1mUAM44BF8RU+wSCisGAQQBl1UBBQEB |
||||
|
B0C0Ix+Z8q+NmQ7W64bAZwf1lYbDIykmtmh4pOCu9/XGdQMBCAnChAQYFgoAFQWC |
||||
|
XxFT7AWJBaSPvQILCQKbDAIeAQAhCRBqA9sqF/udFRYhBD5FF17pU+u+uUjxGmoD |
||||
|
2yoX+50VvKMBAOHyhqD60oJJpA1G116lL7LjKjnFuJG/6tG4xfvFi2fPAQCxPM+N |
||||
|
Pm5OZkyuDqsmY1RkrsbPCMOer3nrCNaKWYBcCg== |
||||
|
=FGLu |
||||
|
-----END PGP PUBLIC KEY BLOCK----- |
@ -0,0 +1,26 @@ |
|||||
|
-----BEGIN PGP PRIVATE KEY BLOCK----- |
||||
|
Comment: 3E45 175E E953 EBBE B948 F11A 6A03 DB2A 17FB 9D15 |
||||
|
Comment: alice_work@peptest.org |
||||
|
|
||||
|
xVgEXxFT7BYJKwYBBAHaRw8BAQdAToI/CRX5M3LjPpSCfmJtOngHTos502W02e4e |
||||
|
I1CyNE8AAP9nsNGRiCaR0Rd9A0zQ8olYfdApaEGAtlI7Ke5AjnRGvRBMwoQEHxYK |
||||
|
ABUFgl8RU+wFiQWkj70CFQoCmwECHgEAIQkQagPbKhf7nRUWIQQ+RRde6VPrvrlI |
||||
|
8RpqA9sqF/udFVfXAP9R5gZRHeklZIQCu3T+OshkLRCS4secfmdeAjp5PxChEwD/ |
||||
|
UaM+7CWpKagv1XoxEh3pKbeQ7Xqw1gF3OIY39QA7rQ3NFmFsaWNlX3dvcmtAcGVw |
||||
|
dGVzdC5vcmfChAQTFgoAFQWCXxFT7AWJBaSPvQIVCgKbAQIeAQAhCRBqA9sqF/ud |
||||
|
FRYhBD5FF17pU+u+uUjxGmoD2yoX+50VXNsA/0OyEnht3A244lvte4Ep5WBGLRuR |
||||
|
IyMxmr2DK9rT4QJXAP0abmmmJAfvRRmGqV6ShGXzmvYEX4OLGJdoyCuUDVmHA8dY |
||||
|
BF8RU+wWCSsGAQQB2kcPAQEHQJ5Yy4JDkA9I8fHqCG1dK1DdaJuZrsdPqSx2erCL |
||||
|
fsg+AAEA9dzB32gcqp1IQ3GXFZ7gu6ay46pdfrlUNNvnyzUxW8wSOcLAOwQYFgoA |
||||
|
FQWCXxFT7AWJBaSPvQIVCgKbAgIeAQCYCRBqA9sqF/udFXagBBkWCgAGBYJfEVPs |
||||
|
ACEJEEuWm1CnbJYnFiEEyoXvDhIOXXwlEPpqS5abUKdslidQEQEAznku9bFDsyLr |
||||
|
kAkQaFGWobMJ7FQOF65eBVlhupuhzbABANxJTGo/klurrqkBZKkcFOBPWutlb1Fu |
||||
|
wD7I4D0HoOkHFiEEPkUXXulT6765SPEaagPbKhf7nRUCOAEA1rLgjeOp4MEKRSXE |
||||
|
9BmvTCVzGGJlbibo1JqZOpC+wsIA/A+K+u9hdoxzjMZIB6y+TQzCjn7Z5f3zgSIf |
||||
|
Oxb7WZQAx10EXxFT7BIKKwYBBAGXVQEFAQEHQLQjH5nyr42ZDtbrhsBnB/WVhsMj |
||||
|
KSa2aHik4K739cZ1AwEICQAA/2iRtG/26b2MEAaxszNxbwdaeE39GU5HvdLmnuVQ |
||||
|
kTwgENbChAQYFgoAFQWCXxFT7AWJBaSPvQILCQKbDAIeAQAhCRBqA9sqF/udFRYh |
||||
|
BD5FF17pU+u+uUjxGmoD2yoX+50VvKMBAOHyhqD60oJJpA1G116lL7LjKjnFuJG/ |
||||
|
6tG4xfvFi2fPAQCxPM+NPm5OZkyuDqsmY1RkrsbPCMOer3nrCNaKWYBcCg== |
||||
|
=Vrqy |
||||
|
-----END PGP PRIVATE KEY BLOCK----- |
@ -0,0 +1,24 @@ |
|||||
|
-----BEGIN PGP PUBLIC KEY BLOCK----- |
||||
|
Comment: 6A98 3569 9EF1 215F 1558 A496 D9C1 D4B0 9840 94E5 |
||||
|
Comment: bob@peptest.org |
||||
|
|
||||
|
xjMEXxFT+xYJKwYBBAHaRw8BAQdAAYt8QUG+i4GQyfwaUQL+cmGKUcWHkcWX87IC |
||||
|
qmNpm//ChAQfFgoAFQWCXxFT+wWJBaSPvQIVCgKbAQIeAQAhCRDZwdSwmECU5RYh |
||||
|
BGqYNWme8SFfFVikltnB1LCYQJTlle4A/3Xl+WA2cHvE5pYsuhxZGqwABxaOmIx8 |
||||
|
AMxj0TBpuObXAP9y/flFpkK15Et/wl/T7iwAn2HAbQWRaPMoX694iQGjB80PYm9i |
||||
|
QHBlcHRlc3Qub3JnwoQEExYKABUFgl8RU/sFiQWkj70CFQoCmwECHgEAIQkQ2cHU |
||||
|
sJhAlOUWIQRqmDVpnvEhXxVYpJbZwdSwmECU5cmFAQDNarwFonE0e3rmjt1eI6CK |
||||
|
e8VjWgMpOYRa05xPdONVsQD/cejxjE+vsMlw3xVprNbKeJeXN+ZPJjNI4LIcw1B/ |
||||
|
igrOMwRfEVP7FgkrBgEEAdpHDwEBB0DdURvGONC+G8dZa0Q1vFGp5WVnrtahfJ0T |
||||
|
PRx5LPdvC8LAOwQYFgoAFQWCXxFT+wWJBaSPvQIVCgKbAgIeAQCYCRDZwdSwmECU |
||||
|
5XagBBkWCgAGBYJfEVP7ACEJENwMujbE/mf1FiEEvRHaDz+iRkPLimpN3Ay6NsT+ |
||||
|
Z/VX8QD/eKyJ/O2yF4jaNDDjzNrEzOZg7pvqiKZolV2WMlA4msUBANdN8PkKCH5G |
||||
|
HPo/T3mWl+xYkOVqZuw90Ay6npS6++wJFiEEapg1aZ7xIV8VWKSW2cHUsJhAlOUQ |
||||
|
UwEAhWLV69mEyxA1FrixumNan7vulofahcc7ox5cfZAANbEA/jBNmTPtROEaSeuU |
||||
|
IPyQ0lO+DS+Gmh9FYIfa35uAaQYKzjgEXxFT+xIKKwYBBAGXVQEFAQEHQL3nDAFV |
||||
|
lgBfUmw5C9OEv0txcP98NUgtADUmr5p9MdswAwEICcKEBBgWCgAVBYJfEVP7BYkF |
||||
|
pI+9AgsJApsMAh4BACEJENnB1LCYQJTlFiEEapg1aZ7xIV8VWKSW2cHUsJhAlOWl |
||||
|
CQD+O3xgfil6wkuenJEEWOWRHm0ft2u50DeP3/mJiRRdefoBAOwurevk+Ky1ZGqo |
||||
|
gpTmsS/1vAf/fz2DLWWN61hIyOEM |
||||
|
=/DS+ |
||||
|
-----END PGP PUBLIC KEY BLOCK----- |
@ -0,0 +1,26 @@ |
|||||
|
-----BEGIN PGP PRIVATE KEY BLOCK----- |
||||
|
Comment: 6A98 3569 9EF1 215F 1558 A496 D9C1 D4B0 9840 94E5 |
||||
|
Comment: bob@peptest.org |
||||
|
|
||||
|
xVgEXxFT+xYJKwYBBAHaRw8BAQdAAYt8QUG+i4GQyfwaUQL+cmGKUcWHkcWX87IC |
||||
|
qmNpm/8AAQCrGsb0A0+Vfxn13bwcs9cotQzf4f8gP4AN6oX3wiMgQxB1woQEHxYK |
||||
|
ABUFgl8RU/sFiQWkj70CFQoCmwECHgEAIQkQ2cHUsJhAlOUWIQRqmDVpnvEhXxVY |
||||
|
pJbZwdSwmECU5ZXuAP915flgNnB7xOaWLLocWRqsAAcWjpiMfADMY9Ewabjm1wD/ |
||||
|
cv35RaZCteRLf8Jf0+4sAJ9hwG0FkWjzKF+veIkBowfND2JvYkBwZXB0ZXN0Lm9y |
||||
|
Z8KEBBMWCgAVBYJfEVP7BYkFpI+9AhUKApsBAh4BACEJENnB1LCYQJTlFiEEapg1 |
||||
|
aZ7xIV8VWKSW2cHUsJhAlOXJhQEAzWq8BaJxNHt65o7dXiOginvFY1oDKTmEWtOc |
||||
|
T3TjVbEA/3Ho8YxPr7DJcN8VaazWyniXlzfmTyYzSOCyHMNQf4oKx1gEXxFT+xYJ |
||||
|
KwYBBAHaRw8BAQdA3VEbxjjQvhvHWWtENbxRqeVlZ67WoXydEz0ceSz3bwsAAPsF |
||||
|
YmCVyg8ega1rLrOGVRhphlUGpGwiAvUd8C56L/ZGlg3kwsA7BBgWCgAVBYJfEVP7 |
||||
|
BYkFpI+9AhUKApsCAh4BAJgJENnB1LCYQJTldqAEGRYKAAYFgl8RU/sAIQkQ3Ay6 |
||||
|
NsT+Z/UWIQS9EdoPP6JGQ8uKak3cDLo2xP5n9VfxAP94rIn87bIXiNo0MOPM2sTM |
||||
|
5mDum+qIpmiVXZYyUDiaxQEA103w+QoIfkYc+j9PeZaX7FiQ5Wpm7D3QDLqelLr7 |
||||
|
7AkWIQRqmDVpnvEhXxVYpJbZwdSwmECU5RBTAQCFYtXr2YTLEDUWuLG6Y1qfu+6W |
||||
|
h9qFxzujHlx9kAA1sQD+ME2ZM+1E4RpJ65Qg/JDSU74NL4aaH0Vgh9rfm4BpBgrH |
||||
|
XQRfEVP7EgorBgEEAZdVAQUBAQdAvecMAVWWAF9SbDkL04S/S3Fw/3w1SC0ANSav |
||||
|
mn0x2zADAQgJAAD/cLLc4Gss5eq6v0PO/sCLyyA69hsz5FAyDFX7F3nMBygRzMKE |
||||
|
BBgWCgAVBYJfEVP7BYkFpI+9AgsJApsMAh4BACEJENnB1LCYQJTlFiEEapg1aZ7x |
||||
|
IV8VWKSW2cHUsJhAlOWlCQD+O3xgfil6wkuenJEEWOWRHm0ft2u50DeP3/mJiRRd |
||||
|
efoBAOwurevk+Ky1ZGqogpTmsS/1vAf/fz2DLWWN61hIyOEM |
||||
|
=4nOw |
||||
|
-----END PGP PRIVATE KEY BLOCK----- |
@ -0,0 +1,126 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# This file is under GNU Affero General Public License 3.0 |
||||
|
# see LICENSE.txt |
||||
|
|
||||
|
from . import utils |
||||
|
|
||||
|
import pytest |
||||
|
|
||||
|
@pytest.fixture() |
||||
|
def model(): |
||||
|
"Returns the whole data model" |
||||
|
return Model() |
||||
|
|
||||
|
identities = \ |
||||
|
{ |
||||
|
"alice": { |
||||
|
"name": "alice", |
||||
|
"user_id": "23", |
||||
|
"accounts": |
||||
|
{ |
||||
|
"work": { |
||||
|
"addr": "alice_work@peptest.org", |
||||
|
"fpr": "3E45175EE953EBBEB948F11A6A03DB2A17FB9D15" |
||||
|
}, |
||||
|
"home": { |
||||
|
"addr": "alice@peptest.org", |
||||
|
"fpr": "2D35731B9C754564CBAD15D2D18F7444594F2283" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
"bob": { |
||||
|
"name": "bob", |
||||
|
"user_id": "uuid:1-2-3-4", |
||||
|
"accounts": \ |
||||
|
{ |
||||
|
"work": { |
||||
|
"addr": "bob_work@peptest.org", |
||||
|
"fpr": "1A97F263D8319D6885F638C5AA81E1B5457A2B40" |
||||
|
}, |
||||
|
"home": { |
||||
|
"addr": "bob@peptest.org", |
||||
|
"fpr": "6A9835699EF1215F1558A496D9C1D4B0984094E5" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class Identity: |
||||
|
""" |
||||
|
An Identity class that is: |
||||
|
- can represent pEp.Identity |
||||
|
- is read-only (const) |
||||
|
""" |
||||
|
|
||||
|
def __init__(self, name="", user_id="", addr="", fpr="", key_sec="", key_pub=""): |
||||
|
self.__name = name |
||||
|
self.__user_id = user_id |
||||
|
self.__addr = addr |
||||
|
self.__fpr = fpr |
||||
|
self.__key_sec = key_sec |
||||
|
self.__key_pub = key_pub |
||||
|
|
||||
|
@property |
||||
|
def name(self): |
||||
|
return self.__name |
||||
|
|
||||
|
@property |
||||
|
def user_id(self): |
||||
|
return self.__user_id |
||||
|
|
||||
|
@property |
||||
|
def addr(self): |
||||
|
return self.__addr |
||||
|
|
||||
|
@property |
||||
|
def fpr(self): |
||||
|
return self.__fpr |
||||
|
|
||||
|
@property |
||||
|
def key_sec(self): |
||||
|
return self.__key_sec |
||||
|
|
||||
|
@property |
||||
|
def key_pub(self): |
||||
|
return self.__key_pub |
||||
|
|
||||
|
def debug(self) -> str: |
||||
|
ret = "name:" + self.__name |
||||
|
ret +="user_id:" + self.__user_id |
||||
|
ret +="addr:" + self.__addr |
||||
|
ret +="fpr:" + self.__fpr |
||||
|
ret +="key_sec:" + self.__key_sec[0:255] |
||||
|
ret +="key_pub:" + self.__key_pub[0:255] |
||||
|
return ret |
||||
|
|
||||
|
def __str__(self): |
||||
|
return "{} {}".format(self.name, "<{}>".format(self.addr)) |
||||
|
|
||||
|
|
||||
|
|
||||
|
# The Data Model |
||||
|
class Model: |
||||
|
alice = None |
||||
|
alice_work = None |
||||
|
bob = None |
||||
|
bob_work = None |
||||
|
|
||||
|
def getIdentity(self, name, account) -> Identity: |
||||
|
# fetch keys for ident from data folder |
||||
|
key_sec = utils.data_file_contents(identities[name]['accounts'][account]['fpr'] + ".sec.asc") |
||||
|
key_pub = utils.data_file_contents(identities[name]['accounts'][account]['fpr'] + ".pub.asc") |
||||
|
ident = Identity(name=identities[name]['name'], |
||||
|
user_id=identities[name]['user_id'], |
||||
|
addr=identities[name]['accounts'][account]['addr'], |
||||
|
fpr=identities[name]['accounts'][account]['fpr'], |
||||
|
key_pub=key_pub, |
||||
|
key_sec=key_sec |
||||
|
) |
||||
|
return ident |
||||
|
|
||||
|
def __init__(self): |
||||
|
self.alice = self.getIdentity("alice", "home") |
||||
|
self.alice_work = self.getIdentity("alice", "work") |
||||
|
|
||||
|
self.bob = self.getIdentity("bob", "home") |
||||
|
self.bob_work = self.getIdentity("bob", "work") |
@ -0,0 +1,55 @@ |
|||||
|
#!/usr/bin/env python3 |
||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from . import constants |
||||
|
import pytest |
||||
|
|
||||
|
# """ |
||||
|
# >>> import pEp |
||||
|
# >>> me = pEp.Identity("alice.smith@peptest.ch", "Alice Smith", "23") |
||||
|
# >>> me.username |
||||
|
# 'Alice Smith' |
||||
|
# >>> print(me) |
||||
|
# Alice Smith <alice.smith@peptest.ch> |
||||
|
# >>> you = pEp.Identity("bob.bourne@peptest.ch", "Bob Bourne", "42") |
||||
|
# >>> print(you) |
||||
|
# Bob Bourne <bob.bourne@peptest.ch> |
||||
|
# >>> m = pEp.outgoing_message(me) |
||||
|
# >>> m.to = [you] |
||||
|
# >>> m.shortmsg = "let's meet next week" |
||||
|
# >>> m.longmsg = "Please call me back" |
||||
|
# >>> m2 = m.encrypt() |
||||
|
# >>> print(m2) |
||||
|
# >>> m3, keys, rating, flags = m2.decrypt() |
||||
|
# >>> rating |
||||
|
# pEp.rating.reliable |
||||
|
# """ |
||||
|
# |
||||
|
# if __name__ == "__main__": |
||||
|
# import doctest |
||||
|
# doctest.testmod() |
||||
|
|
||||
|
def test_basic(pEp, model): |
||||
|
me = pEp.Identity( |
||||
|
model.alice.addr, |
||||
|
model.alice.name, |
||||
|
model.alice.user_id |
||||
|
) |
||||
|
assert me.username == model.alice.name |
||||
|
assert str(me) == str(model.alice) |
||||
|
you = pEp.Identity( |
||||
|
model.bob.addr, |
||||
|
model.bob.name, |
||||
|
model.bob.user_id |
||||
|
) |
||||
|
assert str(you) == str(model.bob) |
||||
|
#TODO: pEp.outgoing_message() needs to return type pEp.Message not None |
||||
|
m = pEp.outgoing_message(me) |
||||
|
m.to = [you] |
||||
|
m.shortmsg = constants.SUBJECT |
||||
|
m.longmsg = constants.BODY |
||||
|
#TODO: encrypt needs to return message type |
||||
|
m2 = m.encrypt() |
||||
|
m3, keys, rating, flags = m2.decrypt() |
||||
|
#TODO: fix pEp.rating |
||||
|
# assert rating == pEp. |
@ -0,0 +1,107 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# This file is under GNU Affero General Public License 3.0 |
||||
|
# see LICENSE.txt |
||||
|
|
||||
|
"""Identity unit tests.""" |
||||
|
|
||||
|
import pytest |
||||
|
|
||||
|
from . import constants |
||||
|
from . import model |
||||
|
|
||||
|
|
||||
|
# TODO: test_get_identity_by_{name,addr,etc..} |
||||
|
# def test_create_ident_myself(pEp, alice_myself): |
||||
|
# def test_create_ident_import(pEp, alice_myself): |
||||
|
# def test_create_ident_nokey(pEp, alice_myself): |
||||
|
|
||||
|
|
||||
|
def test_identity_constructor(pEp, model): |
||||
|
alice = pEp.Identity( |
||||
|
model.alice.addr, |
||||
|
model.alice.name, |
||||
|
model.alice.user_id |
||||
|
) |
||||
|
|
||||
|
assert alice.address == model.alice.addr |
||||
|
assert alice.username == model.alice.name |
||||
|
assert alice.user_id == model.alice.user_id |
||||
|
assert str(alice) == str(model.alice) |
||||
|
|
||||
|
|
||||
|
# TODO: |
||||
|
# These here are actually plenty of individual tests |
||||
|
# Identity.update |
||||
|
# key_import |
||||
|
# set_own_key |
||||
|
|
||||
|
@pytest.mark.skip(reason="needs to be decomposed and migrated to new data model") |
||||
|
def test_two_identities_succeed(pEp, model): |
||||
|
alice = pEp.Identity( |
||||
|
constants.ALICE_ADDRESS, constants.ALICE_USERNAME, '', |
||||
|
constants.ALICE_FPR, 0, '' |
||||
|
) |
||||
|
assert alice.address == constants.ALICE_ADDRESS |
||||
|
assert alice.username == constants.ALICE_USERNAME |
||||
|
assert alice.fpr == constants.ALICE_FPR |
||||
|
assert alice.user_id == "" |
||||
|
assert alice.comm_type == 0 |
||||
|
assert alice.flags == 0 |
||||
|
|
||||
|
pEp.import_key(model.bob.key_pub) |
||||
|
|
||||
|
bob = pEp.Identity() |
||||
|
bob.address = constants.BOB_ADDRESS |
||||
|
bob.username = constants.BOB_USERNAME |
||||
|
bob.fpr = constants.BOB_FPR |
||||
|
expected_bob = pEp.Identity( |
||||
|
constants.BOB_ADDRESS, constants.BOB_USERNAME, '', |
||||
|
constants.BOB_FPR, 56, '' |
||||
|
) |
||||
|
|
||||
|
assert str(bob) == constants.BOB_NAME_ADDR |
||||
|
assert bob.address == expected_bob.address |
||||
|
assert bob.username == expected_bob.username |
||||
|
assert bob.fpr == expected_bob.fpr |
||||
|
assert bob.user_id == "" |
||||
|
assert bob.comm_type == 0 |
||||
|
assert bob.flags == 0 |
||||
|
|
||||
|
# Test that data after updating. |
||||
|
bob.update() |
||||
|
assert str(bob) == constants.BOB_NAME_ADDR |
||||
|
assert bob.address == expected_bob.address |
||||
|
assert bob.username == expected_bob.username |
||||
|
assert bob.fpr == expected_bob.fpr |
||||
|
assert bob.user_id == "TOFU_bob@openpgp.example" |
||||
|
assert bob.comm_type == 56 |
||||
|
assert bob.flags == 0 |
||||
|
|
||||
|
|
||||
|
@pytest.mark.skip(reason="needs to be decomposed and migrated to new data model") |
||||
|
def test_set_own_key(pEp, alice_key_sec): |
||||
|
pEp.import_key(alice_key_sec) |
||||
|
alice = pEp.Identity() |
||||
|
alice.address = constants.ALICE_ADDRESS |
||||
|
alice.username = constants.ALICE_USERNAME |
||||
|
alice.fpr = constants.ALICE_FPR |
||||
|
alice.user_id = constants.ALICE_NAME_ADDR |
||||
|
|
||||
|
expected_alice = pEp.Identity( |
||||
|
constants.ALICE_ADDRESS, constants.ALICE_USERNAME, '', |
||||
|
constants.ALICE_FPR, 0, '' |
||||
|
) |
||||
|
|
||||
|
pEp.set_own_key(alice, alice.fpr) |
||||
|
# assert str(alice) == constants.ALICE_NAME_ADDR |
||||
|
assert str(alice) == str(expected_alice) |
||||
|
assert alice.address == expected_alice.address |
||||
|
assert alice.username == expected_alice.username |
||||
|
# assert alice.user_id == constants.ALICE_NAME_ADDR |
||||
|
assert alice.user_id == str(expected_alice) |
||||
|
assert alice.fpr == expected_alice.fpr |
||||
|
assert alice.comm_type == 255 |
||||
|
assert alice.flags == 0 |
||||
|
|
||||
|
# After setting own key this would give ValueError: illegal value |
||||
|
# alice.update() |
@ -0,0 +1,169 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# This file is under GNU Affero General Public License 3.0 |
||||
|
# see LICENSE.txt |
||||
|
|
||||
|
"""Message unit tests.""" |
||||
|
|
||||
|
from . import constants |
||||
|
|
||||
|
|
||||
|
def test_msg_enc_dec_roundtrip(pEp, model, import_ident_alice_as_own_ident, import_ident_bob): |
||||
|
alice = import_ident_alice_as_own_ident |
||||
|
bob = import_ident_bob |
||||
|
|
||||
|
msg = pEp.Message(constants.OUTGOING_MSG, alice) |
||||
|
msg.to = [bob] |
||||
|
msg.shortmsg = constants.SUBJECT |
||||
|
msg.longmsg = constants.BODY |
||||
|
assert msg.enc_format == 0 |
||||
|
# XXX: No way to check MIME so far. |
||||
|
|
||||
|
# Test that creating the `Message` with `outgoing_message` is the same. |
||||
|
msg2 = pEp.outgoing_message(alice) |
||||
|
msg2.to = [bob] |
||||
|
msg2.shortmsg = constants.SUBJECT |
||||
|
msg2.longmsg = constants.BODY |
||||
|
assert str(msg2) == str(msg) |
||||
|
|
||||
|
# Encrypt Message |
||||
|
enc_msg = msg.encrypt() |
||||
|
|
||||
|
assert enc_msg.enc_format == 3 |
||||
|
assert str(enc_msg.from_) == str(model.alice) |
||||
|
assert str(enc_msg.to[0]) == str(model.bob) |
||||
|
assert enc_msg.shortmsg == "p≡p" |
||||
|
assert enc_msg.longmsg == "this message was encrypted with p≡p https://pEp-project.org" |
||||
|
|
||||
|
# Decrypt message. |
||||
|
dec_msg, key_list, rating, r = enc_msg.decrypt() |
||||
|
assert r == 0 |
||||
|
# pEp version 2.2 throws this error: |
||||
|
# AttributeError: module 'pEp' has no attribute 'PEP_rating' |
||||
|
# assert rating == pEp.PEP_rating.PEP_rating_reliable |
||||
|
# It seems to have changed to the following. |
||||
|
assert rating == pEp._pEp.rating.reliable |
||||
|
|
||||
|
# The first 2 keys are Alice's ones, the last is Bob's one. |
||||
|
assert key_list[0] == key_list[1] == model.alice.fpr |
||||
|
assert key_list[-1] == model.bob.fpr |
||||
|
assert dec_msg.shortmsg == constants.SUBJECT |
||||
|
assert dec_msg.longmsg.replace("\r", "") == msg.longmsg |
||||
|
dec_lines = str(dec_msg).replace("\r", "").split("\n") |
||||
|
# pEp version 2.2 seems to have fixed some of the replaced characters. |
||||
|
# and changed also: |
||||
|
# Content-Type: doesn't pring `; charset="utf-8"` anymore. |
||||
|
# Content-Transfer-Encoding: doesn't print `quoted-printable` anymore. |
||||
|
# Content-Disposition: is not present anymore. |
||||
|
# `!` is not replaced by `=21` anymore. |
||||
|
expected_dec_lines = \ |
||||
|
"""From: alice <alice@peptest.org> |
||||
|
To: bob <bob@peptest.org> |
||||
|
Subject: This is a subject |
||||
|
X-pEp-Version: 2.1 |
||||
|
X-EncStatus: reliable |
||||
|
X-KeyList: |
||||
|
X,X,6A9835699EF1215F1558A496D9C1D4B0984094E5 |
||||
|
MIME-Version: 1.0 |
||||
|
Content-Type: text/plain |
||||
|
Content-Transfer-Encoding: 7bit |
||||
|
|
||||
|
Hi world! |
||||
|
""".split("\n") |
||||
|
assert dec_lines[:5] == expected_dec_lines[:5] |
||||
|
assert dec_lines[7:] == expected_dec_lines[7:] |
||||
|
|
||||
|
|
||||
|
def test_msg_len_changes(pEp, import_ident_alice_as_own_ident, import_ident_bob): |
||||
|
"""Test that the original message is modified after encryption. |
||||
|
|
||||
|
Headers are added and therefore the modified unencrypted message length |
||||
|
is different to the original. |
||||
|
XXX: The original message should be left unchanged. |
||||
|
There could be another method previous to `encrypt` that adds the |
||||
|
extra headers and modify the subject returning a new message. |
||||
|
|
||||
|
""" |
||||
|
alice = import_ident_alice_as_own_ident |
||||
|
bob = import_ident_bob |
||||
|
|
||||
|
msg = pEp.outgoing_message(alice) |
||||
|
msg.to = [bob] |
||||
|
msg.shortmsg = constants.SUBJECT |
||||
|
msg.longmsg = constants.BODY |
||||
|
msg_len = len(str(msg)) |
||||
|
# Encrypt Message |
||||
|
msg.encrypt() |
||||
|
|
||||
|
# After encryption, the original message is modified!! |
||||
|
# It contains one more header and the alice's public key, if it's the first |
||||
|
# msg to bob. |
||||
|
# XXX: if/when this is fixed, change the following `!=` to `==` |
||||
|
msg_after_encrypt_len = len(str(msg)) |
||||
|
assert msg.shortmsg != constants.SUBJECT |
||||
|
assert msg.longmsg == constants.BODY |
||||
|
assert msg_after_encrypt_len != msg_len |
||||
|
|
||||
|
|
||||
|
def test_dec_msg_len(pEp, import_ident_alice_as_own_ident, import_ident_bob): |
||||
|
""" |
||||
|
Test that the decrypted message length is different from the original. |
||||
|
|
||||
|
Because it adds extra headers. |
||||
|
|
||||
|
""" |
||||
|
alice = import_ident_alice_as_own_ident |
||||
|
bob = import_ident_bob |
||||
|
|
||||
|
msg = pEp.outgoing_message(alice) |
||||
|
msg.to = [bob] |
||||
|
msg.shortmsg = constants.SUBJECT |
||||
|
msg.longmsg = constants.BODY |
||||
|
msg_len = len(str(msg)) |
||||
|
# Encrypt Message |
||||
|
enc_msg = msg.encrypt() |
||||
|
|
||||
|
# Decrypt message. |
||||
|
dec_msg, _key_list, _rating, _r = enc_msg.decrypt() |
||||
|
dec_msg_len = len(str(dec_msg)) |
||||
|
|
||||
|
assert dec_msg.longmsg.replace("\r", "") == constants.BODY # msg.longmsg |
||||
|
expected_dec_msg = \ |
||||
|
"""From: alice <alice@peptest.org>\r |
||||
|
To: bob <bob@peptest.org>\r |
||||
|
Subject: This is a subject\r |
||||
|
X-pEp-Version: 2.1\r |
||||
|
X-EncStatus: reliable\r |
||||
|
X-KeyList: \r |
||||
|
2D35731B9C754564CBAD15D2D18F7444594F2283,2D35731B9C754564CBAD15D2D18F7444594F2283,6A9835699EF1215F1558A496D9C1D4B0984094E5\r |
||||
|
MIME-Version: 1.0\r |
||||
|
Content-Type: text/plain\r |
||||
|
Content-Transfer-Encoding: 7bit\r |
||||
|
\r |
||||
|
Hi world!\r |
||||
|
""" |
||||
|
assert expected_dec_msg == str(dec_msg) |
||||
|
# The decrypted message length should then be equal to the original message |
||||
|
# minus the extra headers added. |
||||
|
dec_lines = str(dec_msg).split("\n") |
||||
|
extra_headers_lines = dec_lines[3:7] |
||||
|
extra_headers = "\n".join(extra_headers_lines) + "\n" |
||||
|
len_extra_headers = len(extra_headers) |
||||
|
print("len_extra_headers", len_extra_headers) |
||||
|
assert dec_msg_len - len_extra_headers == msg_len |
||||
|
|
||||
|
#@pytest.mark.skip(reason="PYADAPT-91") |
||||
|
def test_null_char_rmed(pEp, import_ident_alice_as_own_ident, import_ident_bob): |
||||
|
"""Test that null characters and anything after them are not removed.""" |
||||
|
alice = import_ident_alice_as_own_ident |
||||
|
bob = import_ident_bob |
||||
|
|
||||
|
msg = pEp.outgoing_message(alice) |
||||
|
msg.to = [bob] |
||||
|
msg.shortmsg = constants.SUBJECT |
||||
|
|
||||
|
# Message with null chars, potentially for padding. |
||||
|
body = "Hi Bob,\n" + "\0" * 255 + "\nBye,\nAlice." |
||||
|
msg.longmsg = body |
||||
|
# PYADAPT-91: The null characters and anything after them is removed. |
||||
|
# If/when this is fixed, change the following assertion. |
||||
|
assert msg.longmsg != body |
@ -0,0 +1,15 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# This file is under GNU Affero General Public License 3.0 |
||||
|
# see LICENSE.txt |
||||
|
|
||||
|
"""Unit test for pEp package, not for subpackages or modules.""" |
||||
|
|
||||
|
|
||||
|
|
||||
|
def test_pep_version(): |
||||
|
""" Test that __version__ is not None or empty and is not 0.0.0.""" |
||||
|
from pEp import __version__ |
||||
|
# We could also test that match the regex, but that is already a test in |
||||
|
# setuptools_scm itself. |
||||
|
assert __version__ |
||||
|
assert __version__ != "0.0.0" |
@ -0,0 +1,13 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# This file is under GNU Affero General Public License 3.0 |
||||
|
# see LICENSE.txt |
||||
|
|
||||
|
from . import constants |
||||
|
|
||||
|
import pathlib |
||||
|
|
||||
|
def data_file_contents(name) -> str: |
||||
|
"""grab the contents of a file in the data folder""" |
||||
|
path = pathlib.Path(__file__).parent / constants.DATADIR / name |
||||
|
with path.open(mode='r') as fid: |
||||
|
return fid.read() |
Loading…
Reference in new issue