Browse Source

Merge in PYADPT-81 (Integrate libpEpAdapter)

build-windows Release_2.1.0-RC1
heck 5 years ago
parent
commit
f366c8329f
  1. 1
      .hgignore
  2. 22
      Makefile
  3. 15
      Makefile.conf
  4. 11
      local.conf.example
  5. 36
      setup.py
  6. 97
      src/adapter.cc
  7. 59
      src/adapter.hh
  8. 161
      src/basic_api.cc
  9. 25
      src/basic_api.hh
  10. 278
      src/identity.cc
  11. 90
      src/identity.hh
  12. 61
      src/locked_queue.hh
  13. 406
      src/message.cc
  14. 145
      src/message.hh
  15. 167
      src/message_api.cc
  16. 17
      src/message_api.hh
  17. 52
      src/pEp/__init__.py
  18. 172
      src/pEp/native_pEp/basic_api.cc
  19. 30
      src/pEp/native_pEp/basic_api.hh
  20. 285
      src/pEp/native_pEp/identity.cc
  21. 102
      src/pEp/native_pEp/identity.hh
  22. 413
      src/pEp/native_pEp/message.cc
  23. 154
      src/pEp/native_pEp/message.hh
  24. 172
      src/pEp/native_pEp/message_api.cc
  25. 27
      src/pEp/native_pEp/message_api.hh
  26. 318
      src/pEp/native_pEp/pEpmodule.cc
  27. 28
      src/pEp/native_pEp/pEpmodule.hh
  28. 184
      src/pEp/native_pEp/str_attr.cc
  29. 43
      src/pEp/native_pEp/str_attr.hh
  30. 130
      src/pEp/native_pEp/user_interface.cc
  31. 60
      src/pEp/native_pEp/user_interface.hh
  32. 23
      src/pEpmodule.hh
  33. 179
      src/str_attr.cc
  34. 36
      src/str_attr.hh
  35. 125
      src/user_interface.cc
  36. 50
      src/user_interface.hh
  37. 5
      test/codec_doctest.py
  38. 47
      test/pyadpt-81.py

1
.hgignore

@ -1,5 +1,6 @@
syntax: glob syntax: glob
local.conf
*.swp *.swp
ws ws
tags tags

22
Makefile

@ -0,0 +1,22 @@
include Makefile.conf
.PHONY: all build clean devenv envtest
all: build_ext
build_ext:
python3 setup.py build_ext $(BUILD_EXT_OPTS)
clean:
rm -r $(BUILD_DIR)
devenv:
LD_LIBRARY_PATH=$(PREFIX)/lib \
DYLD_LIBRARY_PATH=$(PREFIX)/lib \
PYTHONPATH=$PYTHONPATH:`pwd`/build/lib.linux-x86_64-3.7:\
PYTHONPATH=$PYTHONPATH:`pwd`/build/lib.macosx-10.9-x86_64-3.8:\
`pwd`/src \
bash -l
envtest:
python3 -c 'import pEp'

15
Makefile.conf

@ -0,0 +1,15 @@
HERE:=$(dir $(lastword $(MAKEFILE_LIST)))
# Defaults
DEBUG=0
PREFIX?=$(HOME)
BUILD_DIR = ./build
######### Overrides #########
-include $(HERE)local.conf
ifeq ($(DEBUG),1)
BUILD_EXT_OPTS+=--debug
endif
BUILD_EXT_OPTS += --prefix=$(PREFIX)

11
local.conf.example

@ -0,0 +1,11 @@
# This is an Example build config file (local.conf)
# you might not need this file, but if the defaults dont work for you
# You can override them here.
# Tweak the values to your needs and rename it to local.conf
######### C++ Compiler #########
# DEBUG=1
# DEBUG=0
############# DIRS #############
# PREFIX=$(HOME)/local

36
setup.py

@ -18,10 +18,8 @@ from glob import glob
from setuptools.command.build_ext import build_ext from setuptools.command.build_ext import build_ext
verboseLevel = 0
def pEpLog(*msg): def pEpLog(*msg):
if verboseLevel > 0:
import inspect import inspect
msgstr = '' msgstr = ''
separator = ' ' separator = ' '
@ -39,13 +37,11 @@ class BuildExtCommand(build_ext):
] ]
def initialize_options(self): def initialize_options(self):
pEpLog("called")
build_ext.initialize_options(self) build_ext.initialize_options(self)
self.local = None != environ.get('PER_USER_DIRECTORY') self.local = None != environ.get('PER_USER_DIRECTORY')
self.prefix = getattr(self, "prefix=", None) self.prefix = getattr(self, "prefix=", None)
def windowsGetInstallLocation(self): def windowsGetInstallLocation(self):
pEpLog("called")
# Note: should be installed to 'C:\Program Files (x86)' while a 32-bit distro # Note: should be installed to 'C:\Program Files (x86)' while a 32-bit distro
# TODO: Try desktop adapter location first, then COM server # TODO: Try desktop adapter location first, then COM server
# FIXME: This is wrong, we should chase the COM server, not the Outlook Plugin (even if they're in the same place) # FIXME: This is wrong, we should chase the COM server, not the Outlook Plugin (even if they're in the same place)
@ -90,6 +86,7 @@ class BuildExtCommand(build_ext):
] ]
libs = [ libs = [
'pEpEngine', 'pEpEngine',
'pEpAdapter',
'boost_python37-mt', 'boost_python37-mt',
'boost_locale-mt' 'boost_locale-mt'
] ]
@ -99,19 +96,14 @@ class BuildExtCommand(build_ext):
home = environ.get('PER_USER_DIRECTORY') or environ.get('HOME') home = environ.get('PER_USER_DIRECTORY') or environ.get('HOME')
sys_includes = [ sys_includes = [
'/opt/local/include', '/opt/local/include',
'/usr/local/include',
'/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/include',
'/usr/include',
] ]
sys_libdirs = [ sys_libdirs = [
'/opt/local/lib', '/opt/local/lib',
'/usr/local/lib',
'/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/lib',
'/usr/lib',
] ]
libs = [ libs = [
'pEpEngine', 'pEpEngine',
'boost_python37-mt', 'pEpAdapter',
'boost_python38-mt',
'boost_locale-mt' 'boost_locale-mt'
] ]
return (home, sys_includes, sys_libdirs, libs) return (home, sys_includes, sys_libdirs, libs)
@ -129,23 +121,19 @@ class BuildExtCommand(build_ext):
] ]
libs = [ libs = [
'pEpEngine', 'pEpEngine',
'pEpAdapter',
'boost_python3', 'boost_python3',
'boost_locale' 'boost_locale'
] ]
return (home, sys_includes, sys_libdirs, libs) return (home, sys_includes, sys_libdirs, libs)
def finalize_options(self): def finalize_options(self):
pEpLog("called")
build_ext.finalize_options(self) build_ext.finalize_options(self)
pEpLog("verbose: ", self.verbose)
pEpLog("local: ", self.local) pEpLog("local: ", self.local)
pEpLog("prefix: ", self.prefix) pEpLog("prefix: ", self.prefix)
pEpLog("sys.platform: ", sys.platform) pEpLog("sys.platform: ", sys.platform)
global verboseLevel
verboseLevel = self.verbose
# get build information for platform # get build information for platform
if sys.platform == 'winnt': if sys.platform == 'winnt':
build_info = self.get_build_info_winnt() build_info = self.get_build_info_winnt()
@ -174,7 +162,6 @@ class BuildExtCommand(build_ext):
# Append prefix-dir # Append prefix-dir
if self.prefix: if self.prefix:
pEpLog("using prefix=",self.prefix)
prefix_include=[ join(self.prefix, 'include') ] prefix_include=[ join(self.prefix, 'include') ]
prefix_libdirs=[ join(self.prefix, 'lib') ] prefix_libdirs=[ join(self.prefix, 'lib') ]
includes += prefix_include includes += prefix_include
@ -185,7 +172,7 @@ class BuildExtCommand(build_ext):
libdirs += sys_libdirs libdirs += sys_libdirs
# Compile flags # Compile flags
compile_flags = ['-std=c++14'] compile_flags = ['-std=c++14', '-fpermissive']
if self.debug: if self.debug:
pEpLog("debug mode") pEpLog("debug mode")
compile_flags += ['-O0', '-g', '-UNDEBUG'] compile_flags += ['-O0', '-g', '-UNDEBUG']
@ -217,8 +204,16 @@ if sys.version_info[0] < 3:
module_pEp = Extension( module_pEp = Extension(
'pEp', 'native_pEp',
sources = glob('src/*.cc'), sources = [
'src/pEp/native_pEp/pEpmodule.cc',
'src/pEp/native_pEp/basic_api.cc',
'src/pEp/native_pEp/identity.cc',
'src/pEp/native_pEp/message.cc',
'src/pEp/native_pEp/message_api.cc',
'src/pEp/native_pEp/str_attr.cc',
# 'src/pEp/native_pEp/user_interface.cc',
],
) )
# "MAIN" Function # "MAIN" Function
@ -230,6 +225,7 @@ setup(
author_email="vb@pep-project.org", author_email="vb@pep-project.org",
maintainer="Heck", maintainer="Heck",
maintainer_email="heck@pep.foundation", maintainer_email="heck@pep.foundation",
package_dir='src',
ext_modules=[module_pEp], ext_modules=[module_pEp],
cmdclass={ cmdclass={
'build_ext': BuildExtCommand, 'build_ext': BuildExtCommand,

97
src/adapter.cc

@ -1,97 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#include "user_interface.hh"
#include <assert.h>
namespace pEp {
namespace PythonAdapter {
Adapter::Adapter(bool unregister_this)
: flag_unregister(unregister_this)
{
session(init);
}
Adapter::~Adapter()
{
session(release);
}
PEP_SESSION Adapter::session(session_action action)
{
lock_guard<mutex> lock(mtx());
thread_local static PEP_SESSION _session = nullptr;
thread_local int booked = 0;
PEP_STATUS status = PEP_STATUS_OK;
switch (action) {
case release:
if (booked)
--booked;
if (!booked && _session) {
::release(_session);
_session = nullptr;
}
break;
case none:
if (_session)
break;
case init:
++booked;
if (!_session)
status = ::init(&_session, _messageToSend, _inject_sync_event);
break;
default:
status = PEP_ILLEGAL_VALUE;
}
if (status)
_throw_status(status);
return _session;
}
::utility::locked_queue< SYNC_EVENT > * Adapter::q = nullptr;
bool Adapter::flag_sync_enabled = false;
void Adapter::shutdown_sync()
{
if (queue_active())
queue().push_front(nullptr);
flag_sync_enabled = false;
}
PyObject *Adapter::ui_object(PyObject *value)
{
lock_guard<mutex> lock(mtx());
static PyObject *obj = nullptr;
if (value)
obj = value;
return obj;
}
int Adapter::_inject_sync_event(SYNC_EVENT ev, void *management)
{
if (!flag_sync_enabled)
return 1;
if (is_sync_thread(adapter.session())) {
PEP_STATUS status = do_sync_protocol_step(adapter.session(), adapter.ui_object(), ev);
return status == PEP_STATUS_OK ? 0 : 1;
}
try {
queue().push_back(ev);
}
catch (exception&) {
return 1;
}
return 0;
}
}
}

59
src/adapter.hh

@ -1,59 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#pragma once
#include "pEpmodule.hh"
#include "locked_queue.hh"
#include "user_interface.hh"
#include <pEp/sync_api.h>
namespace pEp {
namespace PythonAdapter {
using Message = pEp::PythonAdapter::Message;
class Adapter {
bool flag_unregister;
public:
Adapter(bool unregister_this = false);
virtual ~Adapter();
enum session_action {
none = 0,
init,
release
};
PEP_SESSION session(session_action action = none);
static ::utility::locked_queue< SYNC_EVENT >& queue()
{
if (!q)
q = new ::utility::locked_queue< SYNC_EVENT >();
return *q;
}
void script_is_implementing_sync() { flag_sync_enabled = true; }
void shutdown_sync();
bool is_sync_active() { return flag_sync_enabled; }
protected:
static PyObject *ui_object(PyObject *value = nullptr);
static int _inject_sync_event(SYNC_EVENT ev, void *management);
static ::utility::locked_queue< SYNC_EVENT > *q;
static bool flag_sync_enabled;
bool queue_active() { return !!q; }
private:
static mutex& mtx()
{
static mutex m;
return m;
}
friend class UserInterface_callback;
};
}
}

161
src/basic_api.cc

@ -1,161 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#include "basic_api.hh"
#include <sstream>
#include <pEp/keymanagement.h>
#include <pEp/message_api.h>
namespace pEp {
namespace PythonAdapter {
void update_identity(Identity& ident)
{
if (ident.address() == "")
throw invalid_argument("address needed");
if (ident.user_id() == PEP_OWN_USERID)
throw runtime_error("update_identity: '" PEP_OWN_USERID
"' may only be used for own identities");
PEP_STATUS status = update_identity(adapter.session(), ident);
_throw_status(status);
}
void myself(Identity& ident)
{
if (ident.address() == "")
throw invalid_argument("address needed");
if (ident.username() == "")
throw invalid_argument("username needed");
if (ident.user_id() == "")
ident.user_id(ident.address());
PEP_STATUS status = myself(adapter.session(), ident);
_throw_status(status);
}
string _trustwords(Identity me, Identity partner, string lang, bool full)
{
if (me.fpr() == "" || partner.fpr() == "")
throw invalid_argument("fingerprint needed in Identities");
if (lang == "" && me.lang() == partner.lang())
lang = me.lang();
char *words = 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);
}
}
}

25
src/basic_api.hh

@ -1,25 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#pragma once
#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);
}
}

278
src/identity.cc

@ -1,278 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#include "identity.hh"
#include "pEpmodule.hh"
#include "basic_api.hh"
#include "message_api.hh"
#include <typeinfo>
#include <sstream>
#include <pEp/identity_list.h>
#include <pEp/keymanagement.h>
#include <pEp/key_reset.h>
#include <pEp/message_api.h>
namespace pEp {
namespace PythonAdapter {
Identity::Identity(string address, string username, string user_id,
string fpr, int comm_type, string lang, identity_flags_t flags)
: _ident(new_identity(address.c_str(), fpr.c_str(), user_id.c_str(),
username.c_str()), &::free_identity)
{
if (!_ident)
throw bad_alloc();
_ident->comm_type = (PEP_comm_type) comm_type;
_ident->flags = (identity_flags_t) flags;
this->lang(lang);
}
Identity::Identity(const Identity& second)
: _ident(second._ident)
{
}
Identity::Identity(pEp_identity *ident)
: _ident(ident, &::free_identity)
{
}
Identity::~Identity()
{
}
Identity::operator pEp_identity *()
{
return _ident.get();
}
Identity::operator const pEp_identity *() const
{
return _ident.get();
}
string Identity::_repr()
{
stringstream build;
build << "Identity(";
string address;
if (_ident->address)
address = string(_ident->address);
build << repr(address) << ", ";
string username;
if (_ident->username)
username = string(_ident->username);
build << repr(username) << ", ";
string user_id;
if (_ident->user_id)
user_id = string(_ident->user_id);
build << repr(user_id) << ", ";
string fpr;
if (_ident->fpr)
fpr = string(_ident->fpr);
build << repr(fpr) << ", ";
build << (int) _ident->comm_type << ", ";
string lang = _ident->lang;
build << repr(lang) << ")";
return build.str();
}
string Identity::_str()
{
if (!(_ident->address && _ident->address[0]))
return "";
if (!(_ident->username && _ident->username[0]))
return _ident->address;
return string(_ident->username) + " <" + _ident->address + ">";
}
void Identity::username(string value)
{
if (value.length() && value.length() < 5)
throw length_error("username must be at least 5 characters");
str_attr(_ident->username, value);
}
void Identity::lang(string value)
{
if (value == "")
memset(_ident->lang, 0, 3);
else if (value.length() != 2)
throw length_error("length of lang must be 2");
else
memcpy(_ident->lang, value.c_str(), 3);
}
string Identity::lang()
{
return _ident->lang;
}
int Identity::rating()
{
if (!(_ident->address))
throw invalid_argument("address must be given");
PEP_rating rating = PEP_rating_undefined;
PEP_STATUS status = ::identity_rating(adapter.session(), _ident.get(), &rating);
_throw_status(status);
return (int) rating;
}
PEP_color Identity::color()
{
return _color(rating());
}
Identity Identity::copy()
{
pEp_identity *dup = ::identity_dup(*this);
if (!dup)
throw bad_alloc();
return Identity(dup);
}
Identity Identity::deepcopy(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;
}
}
}

90
src/identity.hh

@ -1,90 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#pragma once
#include <boost/python.hpp>
#include <pEp/pEpEngine.h>
#include <pEp/message_api.h>
#include <string>
#include <memory>
#include <cstddef>
#include "str_attr.hh"
namespace pEp {
namespace PythonAdapter {
using namespace utility;
using namespace std;
// 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);
}
}

61
src/locked_queue.hh

@ -1,61 +0,0 @@
#pragma once
#include <list>
#include <mutex>
namespace utility
{
using namespace std;
template<class T> class locked_queue
{
mutex _mtx;
list<T> _q;
public:
T& back()
{
lock_guard<mutex> lg(_mtx);
return _q.back();
}
T& front()
{
lock_guard<mutex> lg(_mtx);
return _q.front();
}
T pop_back()
{
lock_guard<mutex> lg(_mtx);
T r = _q.back();
_q.pop_back();
return r;
}
T pop_front()
{
lock_guard<mutex> lg(_mtx);
T r = _q.front();
_q.pop_front();
return r;
}
void push_back(const T& data)
{
lock_guard<mutex> lg(_mtx);
_q.push_back(data);
}
void push_front(const T& data)
{
lock_guard<mutex> lg(_mtx);
_q.push_front(data);
}
size_t size()
{
lock_guard<mutex> lg(_mtx);
return _q.size();
}
bool empty()
{
lock_guard<mutex> lg(_mtx);
return _q.empty();
}
};
};

406
src/message.cc

@ -1,406 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#include <Python.h>
#include "message.hh"
#include "message_api.hh"
#include <stdlib.h>
#include <string.h>
#include <stdexcept>
#include <sstream>
#include <vector>
#include <pEp/mime.h>
#include <pEp/keymanagement.h>
#include <pEp/message_api.h>
namespace pEp {
namespace PythonAdapter {
using namespace std;
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;
}
}
}

145
src/message.hh

@ -1,145 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#pragma once
#include <boost/python.hpp>
#include <boost/lexical_cast.hpp>
#include <pEp/message.h>
#include <pEp/message_api.h>
#include <string>
#include "str_attr.hh"
#include "identity.hh"
namespace pEp {
namespace PythonAdapter {
using namespace std;
using namespace boost::python;
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);
}
}

167
src/message_api.cc

@ -1,167 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#include "message_api.hh"
#include "basic_api.hh"
#include <pEp/pEpEngine.h>
#include <pEp/message_api.h>
#include <pEp/sync_api.h>
#include <pEp/sync_codec.h>
#include <pEp/distribution_codec.h>
namespace pEp {
namespace PythonAdapter {
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);
}
}
}
}

17
src/message_api.hh

@ -1,17 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#pragma once
#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);
}
}

52
src/pEp/__init__.py

@ -0,0 +1,52 @@
# pEp package
# This file is being exectued upon 'import pEp'
#
# __all__ could be used to limit the symbols exported when using from <pkg> import *
# Import all symbols EXCEPT the ones beginning with underscore into the current namespace
from native_pEp import *
# TODO: inter-pkg ref to make sure which native_pEp in sys.path gets loaded
# like: pEp.native_pEp
# import the module
import native_pEp
# Executed on module import
def init():
print(init, "called")
native_pEp._init_after_main_module()
def message_to_send(msg):
"""
message_to_send(msg)
override pEp.message_to_send(msg) with your own implementation
this callback is being called when a pp management message needs to be sent
GIL CAVEAT
"""
print("message_to_send() - default callback\n")
print("overwrite this method")
def notify_handshake(me, partner, signal):
"""
notifyHandshake(self, me, partner)
me own identity
partner identity of communication partner
signal the handshake signal
overwrite this method with an implementation of a handshake dialog
GIL CAVEAT
"""
print("message_to_send() - default callback\n")
print("overwrite this method")
# Executed when run as script
def main():
print("I am being run as a script")
# MAIN
if __name__ == "__main__":
main()
else:
init()

172
src/pEp/native_pEp/basic_api.cc

@ -0,0 +1,172 @@
// 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 {

30
src/pEp/native_pEp/basic_api.hh

@ -0,0 +1,30 @@
// 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 */

285
src/pEp/native_pEp/identity.cc

@ -0,0 +1,285 @@
// 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 {

102
src/pEp/native_pEp/identity.hh

@ -0,0 +1,102 @@
// 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 */

413
src/pEp/native_pEp/message.cc

@ -0,0 +1,413 @@
// 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 {

154
src/pEp/native_pEp/message.hh

@ -0,0 +1,154 @@
// 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 */

172
src/pEp/native_pEp/message_api.cc

@ -0,0 +1,172 @@
// 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 {

27
src/pEp/native_pEp/message_api.hh

@ -0,0 +1,27 @@
// 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 */

318
src/pEpmodule.cc → src/pEp/native_pEp/pEpmodule.cc

@ -1,37 +1,58 @@
// This file is under GNU Affero General Public License 3.0 // This file is under GNU Affero General Public License 3.0
// see LICENSE.txt // see LICENSE.txt
#include "pEpmodule.hh" // System
#include <boost/python.hpp>
#include <boost/locale.hpp> #include <boost/locale.hpp>
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include "basic_api.hh"
#include "message_api.hh"
#include "user_interface.hh"
#include "adapter.hh"
#include <mutex> #include <mutex>
// Engine
#include <pEp/key_reset.h> #include <pEp/key_reset.h>
#include <pEp/message_api.h> #include <pEp/message_api.h>
#include <pEp/sync_api.h> #include <pEp/sync_api.h>
#include <pEp/status_to_string.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 pEp {
namespace PythonAdapter { namespace PythonAdapter {
using namespace std; 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;
}
Adapter adapter(true);
void config_passive_mode(bool enable) void config_passive_mode(bool enable)
{ {
::config_passive_mode(adapter.session(), enable); ::config_passive_mode(Adapter::session(), enable);
} }
void config_unencrypted_subject(bool enable) void config_unencrypted_subject(bool enable)
{ {
::config_unencrypted_subject(adapter.session(), enable); ::config_unencrypted_subject(Adapter::session(), enable);
} }
void key_reset_user(string user_id, string fpr) void key_reset_user(string user_id, string fpr)
@ -39,7 +60,7 @@ namespace pEp {
if (user_id == "") if (user_id == "")
throw invalid_argument("user_id required"); throw invalid_argument("user_id required");
PEP_STATUS status = ::key_reset_user(adapter.session(), PEP_STATUS status = ::key_reset_user(Adapter::session(),
user_id.c_str(), fpr != "" ? fpr.c_str() : nullptr); user_id.c_str(), fpr != "" ? fpr.c_str() : nullptr);
_throw_status(status); _throw_status(status);
} }
@ -51,13 +72,10 @@ namespace pEp {
void key_reset_all_own_keys() void key_reset_all_own_keys()
{ {
PEP_STATUS status = ::key_reset_all_own_keys(adapter.session()); PEP_STATUS status = ::key_reset_all_own_keys(Adapter::session());
_throw_status(status); _throw_status(status);
} }
scope *_scope = NULL;
static const char *version_string = "p≡p Python adapter version 0.3";
static string about() static string about()
{ {
string version = string(version_string) + "\np≡p version " string version = string(version_string) + "\np≡p version "
@ -88,93 +106,137 @@ namespace pEp {
PEP_STATUS _messageToSend(::message *msg) PEP_STATUS _messageToSend(::message *msg)
{ {
if (!_scope) pEpLog("called");
return PEP_SEND_FUNCTION_NOT_REGISTERED;
try { try {
object m = _scope->attr("messageToSend"); PyGILState_STATE gil = PyGILState_Ensure();
call< void >(m.ptr(), Message(msg)); pEpLog("GIL Aquired");
} object modref = import("pEp");
catch (exception& e) { } 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; return PEP_STATUS_OK;
} }
void messageToSend(Message msg) { PEP_STATUS notifyHandshake(pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal)
throw runtime_error("implement pEp.messageToSend(msg)"); {
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 do_sync_protocol()
void start_sync()
{ {
::do_sync_protocol(adapter.session(), nullptr); CallbackDispatcher::start_sync();
} }
void shutdown_sync() void shutdown_sync()
{ {
adapter.shutdown_sync(); CallbackDispatcher::stop_sync();
} }
void debug_color(int ansi_color) void debug_color(int ansi_color)
{ {
::set_debug_color(adapter.session(), ansi_color); ::set_debug_color(Adapter::session(), ansi_color);
} }
void leave_device_group() { void leave_device_group()
::leave_device_group(adapter.session()); {
::leave_device_group(Adapter::session());
} }
void script_is_implementing_sync() { bool is_sync_active()
adapter.script_is_implementing_sync(); {
return Adapter::is_sync_running();
} }
bool is_sync_active() { void testfunc() {
return adapter.is_sync_active(); _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) BOOST_PYTHON_MODULE(native_pEp)
{ {
using namespace boost::python; init_before_main_module();
using namespace boost::locale;
using namespace pEp::PythonAdapter;
docstring_options doc_options(true, false, false); // Module init function called by pEp.init()
def("_init_after_main_module", _init_after_main_module);
def("testfunc", &testfunc);
generator gen; docstring_options doc_options(true, false, false);
boost::locale::generator gen;
std::locale::global(gen("")); std::locale::global(gen(""));
_scope = new scope();
// _scope = new scope();
scope().attr("about") = about(); scope().attr("about") = about();
scope().attr("per_user_directory") = per_user_directory(); scope().attr("per_user_directory") = per_user_directory();
scope().attr("per_machine_directory") = per_machine_directory(); scope().attr("per_machine_directory") = per_machine_directory();
scope().attr("engine_version") = get_engine_version(); scope().attr("engine_version") = get_engine_version();
scope().attr("protocol_version") = get_protocol_version(); scope().attr("protocol_version") = get_protocol_version();
def("passive_mode", pEp::PythonAdapter::config_passive_mode, def("passive_mode", config_passive_mode,
"do not attach pub keys to all messages"); "do not attach pub keys to all messages");
def("unencrypted_subject", pEp::PythonAdapter::config_unencrypted_subject, def("unencrypted_subject", config_unencrypted_subject,
"do not encrypt the subject of messages"); "do not encrypt the subject of messages");
def("key_reset", pEp::PythonAdapter::key_reset_user, def("key_reset", key_reset_user,
"reset the default database status for the user / keypair provided\n" "reset the default database status for the user / keypair provided\n"
"This will effectively perform key_reset on each identity\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" "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."); "each key (and all of their identities) if an fpr is not.");
def("key_reset", pEp::PythonAdapter::key_reset_user2, def("key_reset", key_reset_user2,
"reset the default database status for the user / keypair provided\n" "reset the default database status for the user / keypair provided\n"
"This will effectively perform key_reset on each identity\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" "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."); "each key (and all of their identities) if an fpr is not.");
def("key_reset_all_own_keys", pEp::PythonAdapter::key_reset_all_own_keys, def("key_reset_all_own_keys", key_reset_all_own_keys,
"revoke and mistrust all own keys, generate new keys for all\n" "revoke and mistrust all own keys, generate new keys for all\n"
"own identities, and opportunistically communicate key reset\n" "own identities, and opportunistically communicate key reset\n"
"information to people we have recently contacted."); "information to people we have recently contacted.");
auto identity_class = class_<pEp::PythonAdapter::Identity>("Identity", auto identity_class = class_<Identity>("Identity",
"Identity(address, username, user_id='', fpr='', comm_type=0, lang='en')\n" "Identity(address, username, user_id='', fpr='', comm_type=0, lang='en')\n"
"\n" "\n"
"represents a p≡p identity\n" "represents a p≡p identity\n"
@ -197,12 +259,12 @@ BOOST_PYTHON_MODULE(pEp)
.def(boost::python::init<string, 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>())
.def(boost::python::init<string, string, string, string, int, string>()) .def(boost::python::init<string, string, string, string, int, string>())
.def("__repr__", &pEp::PythonAdapter::Identity::_repr) .def("__repr__", &Identity::_repr)
.def("__str__", &pEp::PythonAdapter::Identity::_str, .def("__str__", &Identity::_str,
"string representation of this identity\n" "string representation of this identity\n"
"following the pattern 'username < address >'\n" "following the pattern 'username < address >'\n"
) )
.def("key_reset", &pEp::PythonAdapter::Identity::key_reset, .def("key_reset", &Identity::key_reset,
boost::python::arg("fpr")=object(""), boost::python::arg("fpr")=object(""),
"reset the default database status for the identity / keypair provided. If this\n" "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" "corresponds to the own user and a private key, also revoke the key, generate a\n"
@ -210,7 +272,7 @@ BOOST_PYTHON_MODULE(pEp)
"identity. If it does not, remove the key from the keyring; the key's status is\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.") "completely fresh on next contact from the partner.")
.def("key_mistrusted", &pEp::PythonAdapter::Identity::key_mistrusted, .def("key_mistrusted", &Identity::key_mistrusted,
boost::python::arg("fpr")=object(""), boost::python::arg("fpr")=object(""),
"If you want updated trust on the identity, you ll have" "If you want updated trust on the identity, you ll have"
"to call update_identity or myself respectively after this." "to call update_identity or myself respectively after this."
@ -220,42 +282,42 @@ BOOST_PYTHON_MODULE(pEp)
"will only undo the current identity's / it's user's default, not any" "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)") "other identities which may be impacted (this will not affect most use cases)")
.def("enable_for_sync", &pEp::PythonAdapter::Identity::enable_for_sync, .def("enable_for_sync", &Identity::enable_for_sync,
"Enable own identity for p≡p sync.\n\n" "Enable own identity for p≡p sync.\n\n"
"Only use this on own identities, which are used as accounts.\n") "Only use this on own identities, which are used as accounts.\n")
.def("disable_for_sync", &pEp::PythonAdapter::Identity::disable_for_sync, .def("disable_for_sync", &Identity::disable_for_sync,
"Disable own identity for p≡p sync.\n\n" "Disable own identity for p≡p sync.\n\n"
"Only use this on own identities, which are used as accounts.\n") "Only use this on own identities, which are used as accounts.\n")
.add_property("address", (string(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::address, .add_property("address", (string(Identity::*)()) &Identity::address,
(void(pEp::PythonAdapter::Identity::*)(string)) &pEp::PythonAdapter::Identity::address, (void(Identity::*)(string)) &Identity::address,
"email address or URI") "email address or URI")
.add_property("fpr", (string(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::fpr, .add_property("fpr", (string(Identity::*)()) &Identity::fpr,
(void(pEp::PythonAdapter::Identity::*)(string)) &pEp::PythonAdapter::Identity::fpr, (void(Identity::*)(string)) &Identity::fpr,
"key ID (full fingerprint, hex encoded)") "key ID (full fingerprint, hex encoded)")
.add_property("user_id", (string(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::user_id, .add_property("user_id", (string(Identity::*)()) &Identity::user_id,
(void(pEp::PythonAdapter::Identity::*)(string)) &pEp::PythonAdapter::Identity::user_id, (void(Identity::*)(string)) &Identity::user_id,
"ID of person associated or 'pEp_own_userId' if own identity") "ID of person associated or 'pEp_own_userId' if own identity")
.add_property("username", (string(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::username, .add_property("username", (string(Identity::*)()) &Identity::username,
(void(pEp::PythonAdapter::Identity::*)(string)) &pEp::PythonAdapter::Identity::username, (void(Identity::*)(string)) &Identity::username,
"name in full of person associated") "name in full of person associated")
.add_property("comm_type", (int(pEp::PythonAdapter::Identity::*)()) .add_property("comm_type", (int(Identity::*)())
(PEP_comm_type(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::comm_type, (PEP_comm_type(Identity::*)()) &Identity::comm_type,
(void(pEp::PythonAdapter::Identity::*)(int)) (void(Identity::*)(int))
(void(pEp::PythonAdapter::Identity::*)(PEP_comm_type)) &pEp::PythonAdapter::Identity::comm_type, (void(Identity::*)(PEP_comm_type)) &Identity::comm_type,
"communication type, first rating level (p≡p internal)") "communication type, first rating level (p≡p internal)")
.add_property("lang", (string(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::lang, .add_property("lang", (string(Identity::*)()) &Identity::lang,
(void(pEp::PythonAdapter::Identity::*)(string)) &pEp::PythonAdapter::Identity::lang, (void(Identity::*)(string)) &Identity::lang,
"ISO 639-1 language code") "ISO 639-1 language code")
.add_property("flags", (identity_flags_t(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::flags, .add_property("flags", (identity_flags_t(Identity::*)()) &Identity::flags,
(void(pEp::PythonAdapter::Identity::*)(identity_flags_t)) &pEp::PythonAdapter::Identity::flags, (void(Identity::*)(identity_flags_t)) &Identity::flags,
"flags (p≡p internal)") "flags (p≡p internal)")
.add_property("rating", &pEp::PythonAdapter::Identity::rating, "rating of Identity") .add_property("rating", &Identity::rating, "rating of Identity")
.add_property("color", &pEp::PythonAdapter::Identity::color, "color of Identity as PEP_color") .add_property("color", &Identity::color, "color of Identity as PEP_color")
.add_property("is_pEp_user", &pEp::PythonAdapter::Identity::is_pEp_user, "True if this is an identity of a pEp user") .add_property("is_pEp_user", &Identity::is_pEp_user, "True if this is an identity of a pEp user")
.def("__deepcopy__", &pEp::PythonAdapter::Identity::deepcopy) .def("__deepcopy__", &Identity::deepcopy)
.def("update", &pEp::PythonAdapter::Identity::update, "update Identity") .def("update", &Identity::update, "update Identity")
.def("__copy__", &pEp::PythonAdapter::Identity::copy); .def("__copy__", &Identity::copy);
identity_class.attr("PEP_OWN_USERID") = "pEp_own_userId"; identity_class.attr("PEP_OWN_USERID") = "pEp_own_userId";
@ -306,7 +368,7 @@ BOOST_PYTHON_MODULE(pEp)
" mime_text text in Multipurpose Internet Mail Extensions format\n" " mime_text text in Multipurpose Internet Mail Extensions format\n"
) )
.def(boost::python::init<int>()) .def(boost::python::init<int>())
.def(boost::python::init<int, pEp::PythonAdapter::Identity *>()) .def(boost::python::init<int, Identity *>())
.def(boost::python::init<string>()) .def(boost::python::init<string>())
.def("__str__", &Message::_str, .def("__str__", &Message::_str,
"the string representation of a Message is it's MIME text" "the string representation of a Message is it's MIME text"
@ -338,13 +400,13 @@ BOOST_PYTHON_MODULE(pEp)
.add_property("recv", (time_t(Message::*)()) &Message::recv, .add_property("recv", (time_t(Message::*)()) &Message::recv,
(void(Message::*)(time_t)) &Message::recv, (void(Message::*)(time_t)) &Message::recv,
"time when message was received in UTC seconds since epoch") "time when message was received in UTC seconds since epoch")
.add_property("from_", (pEp::PythonAdapter::Identity(Message::*)()) &Message::from, .add_property("from_", (Identity(Message::*)()) &Message::from,
(void(Message::*)(object)) &Message::from, (void(Message::*)(object)) &Message::from,
"identity where message is from") "identity where message is from")
.add_property("to", (boost::python::list(Message::*)()) &Message::to, .add_property("to", (boost::python::list(Message::*)()) &Message::to,
(void(Message::*)(boost::python::list)) &Message::to, (void(Message::*)(boost::python::list)) &Message::to,
"list of identities message is going to") "list of identities message is going to")
.add_property("recv_by", (pEp::PythonAdapter::Identity(Message::*)()) &Message::recv_by, .add_property("recv_by", (Identity(Message::*)()) &Message::recv_by,
(void(Message::*)(object)) &Message::recv_by, (void(Message::*)(object)) &Message::recv_by,
"identity where message was received by") "identity where message was received by")
.add_property("cc", (boost::python::list(Message::*)()) &Message::cc, .add_property("cc", (boost::python::list(Message::*)()) &Message::cc,
@ -407,19 +469,19 @@ BOOST_PYTHON_MODULE(pEp)
// basic API and key management API // basic API and key management API
def("update_identity", &pEp::PythonAdapter::update_identity, def("update_identity", &update_identity,
"update_identity(ident)\n" "update_identity(ident)\n"
"\n" "\n"
"update identity information\n" "update identity information\n"
"call this to complete identity information when you at least have an address\n" "call this to complete identity information when you at least have an address\n"
); );
def("myself", &pEp::PythonAdapter::myself, def("myself", &myself,
"myself(ident)\n" "myself(ident)\n"
"\n" "\n"
"ensures that the own identity is being complete\n" "ensures that the own identity is being complete\n"
"supply ident.address and ident.username\n" "supply ident.address and ident.username\n"
); );
def("trust_personal_key", &pEp::PythonAdapter::trust_personal_key, def("trust_personal_key", &trust_personal_key,
"trust_personal_key(ident)\n" "trust_personal_key(ident)\n"
"\n" "\n"
"mark a key as trusted with a person\n" "mark a key as trusted with a person\n"
@ -430,44 +492,44 @@ BOOST_PYTHON_MODULE(pEp)
.value("PEP_idf_list", PEP_idf_list) .value("PEP_idf_list", PEP_idf_list)
.value("PEP_idf_devicegroup", PEP_idf_devicegroup); .value("PEP_idf_devicegroup", PEP_idf_devicegroup);
def("set_identity_flags", &pEp::PythonAdapter::set_identity_flags, def("set_identity_flags", &set_identity_flags,
"set_identity_flags(ident, flags)\n" "set_identity_flags(ident, flags)\n"
"\n" "\n"
"set identity flags\n" "set identity flags\n"
); );
def("unset_identity_flags", &pEp::PythonAdapter::unset_identity_flags, def("unset_identity_flags", &unset_identity_flags,
"unset_identity_flags(ident, flags)\n" "unset_identity_flags(ident, flags)\n"
"\n" "\n"
"unset identity flags\n" "unset identity flags\n"
); );
def("key_reset_trust", &pEp::PythonAdapter::key_reset_trust, def("key_reset_trust", &key_reset_trust,
"key_reset_trust(ident)\n" "key_reset_trust(ident)\n"
"\n" "\n"
"reset trust bit or explicitly mistrusted status for an identity and " "reset trust bit or explicitly mistrusted status for an identity and "
"its accompanying key/user_id pair\n" "its accompanying key/user_id pair\n"
); );
def("import_key", &pEp::PythonAdapter::import_key, def("import_key", &import_key,
"private_key_list = import_key(key_data)\n" "private_key_list = import_key(key_data)\n"
"\n" "\n"
"import key(s) from key_data\n" "import key(s) from key_data\n"
); );
def("export_key", &pEp::PythonAdapter::export_key, def("export_key", &export_key,
"key_data = export_key(identity)\n" "key_data = export_key(identity)\n"
"\n" "\n"
"export key(s) of identity\n" "export key(s) of identity\n"
); );
def("export_secret_key", &pEp::PythonAdapter::export_secret_key, def("export_secret_key", &export_secret_key,
"key_data = export_seret_key(identity)\n" "key_data = export_seret_key(identity)\n"
"\n" "\n"
"export secret key(s) of identity\n" "export secret key(s) of identity\n"
); );
def("set_own_key", &pEp::PythonAdapter::set_own_key, def("set_own_key", &set_own_key,
"set_own_key(me, fpr)\n" "set_own_key(me, fpr)\n"
"\n" "\n"
"mark a key as an own key, and make it the default key\n" "mark a key as an own key, and make it the default key\n"
@ -525,14 +587,6 @@ BOOST_PYTHON_MODULE(pEp)
"\n" "\n"
"calculate trustwords for two Identities"); "calculate trustwords for two Identities");
// messageToSend()
def("messageToSend", &pEp::PythonAdapter::messageToSend,
"messageToSend(msg)\n"
"\n"
"override pEp.messageToSend(msg) with your own implementation\n"
"this callback is being called when a p≡p management message needs to be sent");
// Sync API // Sync API
enum_<sync_handshake_signal>("sync_handshake_signal") enum_<sync_handshake_signal>("sync_handshake_signal")
@ -547,62 +601,63 @@ BOOST_PYTHON_MODULE(pEp)
.value("SYNC_NOTIFY_SOLE" , SYNC_NOTIFY_SOLE) .value("SYNC_NOTIFY_SOLE" , SYNC_NOTIFY_SOLE)
.value("SYNC_NOTIFY_IN_GROUP" , SYNC_NOTIFY_IN_GROUP); .value("SYNC_NOTIFY_IN_GROUP" , SYNC_NOTIFY_IN_GROUP);
auto user_interface_class = class_<UserInterface, UserInterface_callback, boost::noncopyable>( // auto user_interface_class = class_<UserInterface, UserInterface_callback, boost::noncopyable>(
"UserInterface", // "UserInterface",
"class MyUserInterface(UserInterface):\n" // "class MyUserInterface(UserInterface):\n"
" def notifyHandshake(self, me, partner):\n" // " def notifyHandshake(self, me, partner):\n"
" ...\n" // " ...\n"
"\n" // "\n"
"p≡p User Interface class\n" // "p≡p User Interface class\n"
"To be used as a mixin\n" // "To be used as a mixin\n"
) // )
.def("notifyHandshake", &UserInterface::notifyHandshake, // .def("notifyHandshake", &UserInterface::notifyHandshake,
"notifyHandshake(self, me, partner)\n" // "notifyHandshake(self, me, partner)\n"
"\n" // "\n"
" me own identity\n" // " me own identity\n"
" partner identity of communication partner\n" // " partner identity of communication partner\n"
"\n" // "\n"
"overwrite this method with an implementation of a handshake dialog") // "overwrite this method with an implementation of a handshake dialog")
.def("deliverHandshakeResult", &UserInterface::deliverHandshakeResult, // .def("deliverHandshakeResult", &UserInterface::deliverHandshakeResult,
boost::python::arg("identities")=object(), // 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" "deliverHandshakeResult(self, result, identities=None)\n"
"\n" "\n"
" result -1: cancel, 0: accepted, 1: rejected\n" " result -1: cancel, 0: accepted, 1: rejected\n"
" identities list of identities to share or None for all\n" " identities list of identities to share or None for all\n"
"\n" "\n"
"call to deliver the handshake result of the handshake dialog") "call to deliver the handshake result of the handshake dialog"
; );
def("do_sync_protocol", &pEp::PythonAdapter::do_sync_protocol, def("start_sync", &start_sync,
"do_sync_protocol()\n" "start_sync()\n"
"\n" "\n"
"in case of an explicit sync thread instead of a single threaded\n" "starts the sync thread"
"implementation call this function in your sync thread\n"
); );
def("shutdown_sync", &pEp::PythonAdapter::shutdown_sync, def("shutdown_sync", &shutdown_sync,
"shutdown_sync()\n" "shutdown_sync()\n"
"\n" "\n"
"call this from another thread to shut down the sync thread\n" "call this from another thread to shut down the sync thread\n"
); );
def("debug_color", &pEp::PythonAdapter::debug_color, def("debug_color", &debug_color,
"for debug builds set ANSI color value"); "for debug builds set ANSI color value");
def("leave_device_group", &pEp::PythonAdapter::leave_device_group, def("leave_device_group", &leave_device_group,
"leave_device_group()\n" "leave_device_group()\n"
"\n" "\n"
"call this for a grouped device, which should leave\n" "call this for a grouped device, which should leave\n"
); );
def("script_is_implementing_sync", &pEp::PythonAdapter::script_is_implementing_sync, def("is_sync_active", &is_sync_active,
"script_is_implementing_sync()\n"
"\n"
"call this in case the Python script is implementing sync to make\n"
"is_sync_active() working\n"
);
def("is_sync_active", &pEp::PythonAdapter::is_sync_active,
"is_sync_active()\n" "is_sync_active()\n"
"\n" "\n"
"True if sync is active, False otherwise\n" "True if sync is active, False otherwise\n"
@ -613,3 +668,6 @@ BOOST_PYTHON_MODULE(pEp)
call< object >(((object)(import("codecs").attr("register"))).ptr(), make_function(sync_search)); call< object >(((object)(import("codecs").attr("register"))).ptr(), make_function(sync_search));
call< object >(((object)(import("codecs").attr("register"))).ptr(), make_function(distribution_search)); call< object >(((object)(import("codecs").attr("register"))).ptr(), make_function(distribution_search));
} }
} // namespace PythonAdapter
} // namespace pEp

28
src/pEp/native_pEp/pEpmodule.hh

@ -0,0 +1,28 @@
// 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 */

184
src/pEp/native_pEp/str_attr.cc

@ -0,0 +1,184 @@
// 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 {

43
src/pEp/native_pEp/str_attr.hh

@ -0,0 +1,43 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#ifndef STR_ATTR_HH
#define STR_ATTR_HH
// System
#include <string>
// Engine
#include <pEp/pEpEngine.h>
#include <pEp/timestamp.h>
#include <pEp/stringlist.h>
#include <pEp/stringpair.h>
namespace pEp {
namespace PythonAdapter {
using std::string;
using boost::python::object;
using boost::python::dict;
object repr(object s);
string repr(string s);
string str_attr(char *&str);
void str_attr(char *&str, string value);
time_t timestamp_attr(timestamp *&ts);
void timestamp_attr(timestamp *&ts, time_t value);
boost::python::list strlist_attr(stringlist_t *&sl);
void strlist_attr(stringlist_t *&sl, boost::python::list value);
dict strdict_attr(stringpair_list_t *&spl);
void strdict_attr(stringpair_list_t *&spl, dict value);
stringlist_t *to_stringlist(boost::python::list l);
boost::python::list from_stringlist(const stringlist_t *sl);
} /* namespace PythonAdapter */
} /* namespace pEp */
#endif /* STR_ATTR_HH */

130
src/pEp/native_pEp/user_interface.cc

@ -0,0 +1,130 @@
// 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 {

60
src/pEp/native_pEp/user_interface.hh

@ -0,0 +1,60 @@
// 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 */

23
src/pEpmodule.hh

@ -1,23 +0,0 @@
#pragma once
#include <boost/python.hpp>
#include "identity.hh"
#include "message.hh"
#include "adapter.hh"
#include <pEp/pEpEngine.h>
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);
void messageToSend(Message msg);
PEP_STATUS _messageToSend(::message *msg);
void do_sync_protocol();
extern Adapter adapter;
}
}

179
src/str_attr.cc

@ -1,179 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#include <boost/python.hpp>
#include <boost/locale.hpp>
#include "str_attr.hh"
#include <stdlib.h>
namespace pEp {
namespace utility {
using namespace std;
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;
}
}
}

36
src/str_attr.hh

@ -1,36 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#pragma once
#include <string>
#include <pEp/pEpEngine.h>
#include <pEp/timestamp.h>
#include <pEp/stringlist.h>
#include <pEp/stringpair.h>
namespace pEp {
namespace utility {
using namespace std;
using namespace boost::python;
object repr(object s);
string repr(string s);
string str_attr(char *&str);
void str_attr(char *&str, string value);
time_t timestamp_attr(timestamp *&ts);
void timestamp_attr(timestamp *&ts, time_t value);
boost::python::list strlist_attr(stringlist_t *&sl);
void strlist_attr(stringlist_t *&sl, boost::python::list value);
dict strdict_attr(stringpair_list_t *&spl);
void strdict_attr(stringpair_list_t *&spl, dict value);
stringlist_t *to_stringlist(boost::python::list l);
boost::python::list from_stringlist(const stringlist_t *sl);
}
}

125
src/user_interface.cc

@ -1,125 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#include "user_interface.hh"
#include <assert.h>
#include <time.h>
namespace pEp {
namespace PythonAdapter {
UserInterface *UserInterface::_ui = nullptr;
UserInterface::UserInterface()
{
if (_ui)
throw runtime_error("only one UserInterface thread allowed");
_ui = this;
}
UserInterface::~UserInterface()
{
_ui = nullptr;
}
UserInterface_callback::UserInterface_callback(PyObject *self) :
UserInterface(), _self(self)
{
adapter.ui_object(self);
PEP_STATUS status = ::register_sync_callbacks(adapter.session(),
(void *) this, _notifyHandshake, retrieve_next_sync_event);
assert(status == PEP_STATUS_OK);
if (status)
_throw_status(status);
}
UserInterface_callback::~UserInterface_callback()
{
::unregister_sync_callbacks(adapter.session());
}
PEP_STATUS UserInterface::_notifyHandshake(
pEp_identity *me, pEp_identity *partner,
sync_handshake_signal signal
)
{
if (!(me && partner))
return PEP_ILLEGAL_VALUE;
auto that = dynamic_cast< UserInterface_callback * >(_ui);
that->notifyHandshake(Identity(me), Identity(partner), signal);
return PEP_STATUS_OK;
}
void UserInterface::deliverHandshakeResult(int result, 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);
}
}
}

50
src/user_interface.hh

@ -1,50 +0,0 @@
// This file is under GNU Affero General Public License 3.0
// see LICENSE.txt
#pragma once
#include "pEpmodule.hh"
#include <setjmp.h>
#include <pEp/sync_api.h>
#include <pEp/message_api.h>
namespace pEp {
namespace PythonAdapter {
class UserInterface {
static UserInterface *_ui;
public:
UserInterface();
virtual ~UserInterface();
virtual void notifyHandshake(
pEp::PythonAdapter::Identity me,
pEp::PythonAdapter::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);
static SYNC_EVENT retrieve_next_sync_event(void *management, unsigned threshold);
};
class UserInterface_callback : public UserInterface {
PyObject *_self;
public:
UserInterface_callback(PyObject *self);
~UserInterface_callback();
void notifyHandshake(
pEp::PythonAdapter::Identity me,
pEp::PythonAdapter::Identity partner,
sync_handshake_signal signal);
};
}
}

5
test/codec_doctest.py

@ -3,14 +3,15 @@
""" """
>>> import pEp >>> import pEp
>>> def messageToSend(msg): >>> def message_to_send(msg):
... m, keys, rating, flags = msg.decrypt() ... m, keys, rating, flags = msg.decrypt()
... try: ... try:
... m.attachments[0].decode() ... m.attachments[0].decode()
... print("decode successfull") ... print("decode successfull")
... except UnicodeDecodeError as e: ... except UnicodeDecodeError as e:
... print("decode failed") ... print("decode failed")
>>> pEp.messageToSend = messageToSend >>> pEp.message_to_send = message_to_send
>>> pEp.myself(pEp.Identity(""))
>>> pEp.key_reset_all_own_keys() >>> pEp.key_reset_all_own_keys()
decode successfull decode successfull
decode successfull decode successfull

47
test/pyadpt-81.py

@ -0,0 +1,47 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pEp
import time
def message_to_send(msg):
print("User defined message_to_send() called")
m, keys, rating, flags = msg.decrypt()
try:
print(m.attachments[0].decode())
except UnicodeDecodeError as e:
print("decode failed")
def notify_handshake(me, partner, signal):
print("User defined notify_handshake() called")
print(me)
print(partner)
print(signal)
def start_stop_sync(duration):
pEp.start_sync()
time.sleep(duration)
pEp.shutdown_sync()
alice = pEp.Identity("test@alice.com", "alice", "23")
pEp.myself(alice)
print(alice.fpr)
dir(pEp)
# test default callback
start_stop_sync(1)
# test user defined callback
pEp.message_to_send = message_to_send
# pEp.notify_handshake = notify_handshake
start_stop_sync(1)
# pEp.start_sync()
# while(True):
# print("is_sync_active: {}".format(pEp.is_sync_active()))
# time.sleep(3)
# pEp.key_reset_all_own_keys()
# time.sleep(3)
Loading…
Cancel
Save