Merge in PYADPT-81 (Integrate libpEpAdapter) Release_2.1.0-RC1
authorheck <heck@pep.foundation>
Thu, 27 Aug 2020 00:15:34 +0200
changeset 39245183a331f2b
parent 378 d5a785f05b44
parent 391 afa50dc3ed51
child 393 2526edfff797
Merge in PYADPT-81 (Integrate libpEpAdapter)
     1.1 --- a/.hgignore	Fri May 15 23:11:13 2020 +0200
     1.2 +++ b/.hgignore	Thu Aug 27 00:15:34 2020 +0200
     1.3 @@ -1,5 +1,6 @@
     1.4  syntax: glob
     1.5  
     1.6 +local.conf
     1.7  *.swp
     1.8  ws
     1.9  tags
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Makefile	Thu Aug 27 00:15:34 2020 +0200
     2.3 @@ -0,0 +1,22 @@
     2.4 +include Makefile.conf
     2.5 +
     2.6 +.PHONY: all build clean devenv envtest
     2.7 +
     2.8 +all: build_ext
     2.9 +
    2.10 +build_ext:
    2.11 +	python3 setup.py build_ext $(BUILD_EXT_OPTS)
    2.12 +
    2.13 +clean:
    2.14 +	rm -r $(BUILD_DIR)
    2.15 +
    2.16 +devenv:
    2.17 +	LD_LIBRARY_PATH=$(PREFIX)/lib \
    2.18 +	DYLD_LIBRARY_PATH=$(PREFIX)/lib \
    2.19 +	PYTHONPATH=$PYTHONPATH:`pwd`/build/lib.linux-x86_64-3.7:\
    2.20 +	PYTHONPATH=$PYTHONPATH:`pwd`/build/lib.macosx-10.9-x86_64-3.8:\
    2.21 +	`pwd`/src \
    2.22 +	bash -l
    2.23 +
    2.24 +envtest:
    2.25 +	python3 -c 'import pEp'
    2.26 \ No newline at end of file
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/Makefile.conf	Thu Aug 27 00:15:34 2020 +0200
     3.3 @@ -0,0 +1,15 @@
     3.4 +HERE:=$(dir $(lastword $(MAKEFILE_LIST)))
     3.5 +
     3.6 +# Defaults
     3.7 +DEBUG=0
     3.8 +PREFIX?=$(HOME)
     3.9 +BUILD_DIR = ./build
    3.10 +
    3.11 +######### Overrides #########
    3.12 +-include $(HERE)local.conf
    3.13 +
    3.14 +ifeq ($(DEBUG),1)
    3.15 +	BUILD_EXT_OPTS+=--debug
    3.16 +endif
    3.17 +
    3.18 +BUILD_EXT_OPTS += --prefix=$(PREFIX)
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/local.conf.example	Thu Aug 27 00:15:34 2020 +0200
     4.3 @@ -0,0 +1,11 @@
     4.4 +# This is an Example build config file (local.conf)
     4.5 +# you might not need this file, but if the defaults dont work for you
     4.6 +# You can override them here.
     4.7 +# Tweak the values to your needs and rename it to local.conf
     4.8 +
     4.9 +######### C++ Compiler #########
    4.10 +# DEBUG=1
    4.11 +# DEBUG=0
    4.12 +
    4.13 +############# DIRS #############
    4.14 +# PREFIX=$(HOME)/local
     5.1 --- a/setup.py	Fri May 15 23:11:13 2020 +0200
     5.2 +++ b/setup.py	Thu Aug 27 00:15:34 2020 +0200
     5.3 @@ -18,18 +18,16 @@
     5.4  
     5.5  from setuptools.command.build_ext import build_ext
     5.6  
     5.7 -verboseLevel = 0
     5.8  
     5.9  def pEpLog(*msg):
    5.10 -    if verboseLevel > 0:
    5.11 -        import inspect
    5.12 -        msgstr = ''
    5.13 -        separator = ' '
    5.14 -        for m in msg:
    5.15 -            msgstr += str(m)
    5.16 -            msgstr += separator
    5.17 -        func = inspect.currentframe().f_back.f_code
    5.18 -        print(func.co_filename + " : " + func.co_name + " : "  + msgstr)
    5.19 +    import inspect
    5.20 +    msgstr = ''
    5.21 +    separator = ' '
    5.22 +    for m in msg:
    5.23 +        msgstr += str(m)
    5.24 +        msgstr += separator
    5.25 +    func = inspect.currentframe().f_back.f_code
    5.26 +    print(func.co_filename + " : " + func.co_name + " : "  + msgstr)
    5.27  
    5.28  class BuildExtCommand(build_ext):
    5.29  
    5.30 @@ -39,13 +37,11 @@
    5.31      ]
    5.32  
    5.33      def initialize_options(self):
    5.34 -        pEpLog("called")
    5.35          build_ext.initialize_options(self)
    5.36          self.local = None != environ.get('PER_USER_DIRECTORY')
    5.37          self.prefix = getattr(self, "prefix=", None)
    5.38  
    5.39      def windowsGetInstallLocation(self):
    5.40 -        pEpLog("called")
    5.41          # Note: should be installed to 'C:\Program Files (x86)' while a 32-bit distro
    5.42          # TODO: Try desktop adapter location first, then COM server
    5.43          # FIXME: This is wrong, we should chase the COM server, not the Outlook Plugin (even if they're in the same place)
    5.44 @@ -90,6 +86,7 @@
    5.45          ]
    5.46          libs = [
    5.47              'pEpEngine',
    5.48 +            'pEpAdapter',
    5.49              'boost_python37-mt',
    5.50              'boost_locale-mt'
    5.51          ]
    5.52 @@ -99,19 +96,14 @@
    5.53          home = environ.get('PER_USER_DIRECTORY') or environ.get('HOME')
    5.54          sys_includes = [
    5.55              '/opt/local/include',
    5.56 -            '/usr/local/include',
    5.57 -            '/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/include',
    5.58 -            '/usr/include',
    5.59          ]
    5.60          sys_libdirs = [
    5.61              '/opt/local/lib',
    5.62 -            '/usr/local/lib',
    5.63 -            '/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/lib',
    5.64 -            '/usr/lib',
    5.65          ]
    5.66          libs = [
    5.67              'pEpEngine',
    5.68 -            'boost_python37-mt',
    5.69 +            'pEpAdapter',
    5.70 +            'boost_python38-mt',
    5.71              'boost_locale-mt'
    5.72          ]
    5.73          return (home, sys_includes, sys_libdirs, libs)
    5.74 @@ -129,23 +121,19 @@
    5.75          ]
    5.76          libs = [
    5.77              'pEpEngine',
    5.78 +            'pEpAdapter',
    5.79              'boost_python3',
    5.80              'boost_locale'
    5.81          ]
    5.82          return (home, sys_includes, sys_libdirs, libs)
    5.83  
    5.84      def finalize_options(self):
    5.85 -        pEpLog("called")
    5.86          build_ext.finalize_options(self)
    5.87  
    5.88 -        pEpLog("verbose: ", self.verbose)
    5.89          pEpLog("local: ", self.local)
    5.90          pEpLog("prefix: ", self.prefix)
    5.91          pEpLog("sys.platform: ", sys.platform)
    5.92  
    5.93 -        global verboseLevel
    5.94 -        verboseLevel = self.verbose
    5.95 -
    5.96          # get build information for platform
    5.97          if sys.platform == 'winnt':
    5.98              build_info = self.get_build_info_winnt()
    5.99 @@ -174,7 +162,6 @@
   5.100  
   5.101          # Append prefix-dir
   5.102          if self.prefix:
   5.103 -            pEpLog("using prefix=",self.prefix)
   5.104              prefix_include=[ join(self.prefix, 'include') ]
   5.105              prefix_libdirs=[ join(self.prefix, 'lib') ]
   5.106              includes += prefix_include
   5.107 @@ -185,7 +172,7 @@
   5.108          libdirs += sys_libdirs
   5.109  
   5.110          # Compile flags
   5.111 -        compile_flags = ['-std=c++14']
   5.112 +        compile_flags = ['-std=c++14', '-fpermissive']
   5.113          if self.debug:
   5.114              pEpLog("debug mode")
   5.115              compile_flags += ['-O0', '-g', '-UNDEBUG']
   5.116 @@ -217,8 +204,16 @@
   5.117  
   5.118  
   5.119  module_pEp = Extension(
   5.120 -    'pEp',
   5.121 -    sources = glob('src/*.cc'),
   5.122 +    'native_pEp',
   5.123 +    sources =   [
   5.124 +                'src/pEp/native_pEp/pEpmodule.cc',
   5.125 +                'src/pEp/native_pEp/basic_api.cc',
   5.126 +                'src/pEp/native_pEp/identity.cc',
   5.127 +                'src/pEp/native_pEp/message.cc',
   5.128 +                'src/pEp/native_pEp/message_api.cc',
   5.129 +                'src/pEp/native_pEp/str_attr.cc',
   5.130 +                # 'src/pEp/native_pEp/user_interface.cc',
   5.131 +                ],
   5.132  )
   5.133  
   5.134  # "MAIN" Function
   5.135 @@ -230,6 +225,7 @@
   5.136      author_email="vb@pep-project.org",
   5.137      maintainer="Heck",
   5.138      maintainer_email="heck@pep.foundation",
   5.139 +    package_dir='src',
   5.140      ext_modules=[module_pEp],
   5.141      cmdclass={
   5.142          'build_ext': BuildExtCommand,
     6.1 --- a/src/adapter.cc	Fri May 15 23:11:13 2020 +0200
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,97 +0,0 @@
     6.4 -// This file is under GNU Affero General Public License 3.0
     6.5 -// see LICENSE.txt
     6.6 -
     6.7 -#include "user_interface.hh"
     6.8 -#include <assert.h>
     6.9 -
    6.10 -namespace pEp {
    6.11 -    namespace PythonAdapter {
    6.12 -        Adapter::Adapter(bool unregister_this)
    6.13 -            : flag_unregister(unregister_this)
    6.14 -        {
    6.15 -            session(init);
    6.16 -        }
    6.17 -
    6.18 -        Adapter::~Adapter()
    6.19 -        {
    6.20 -            session(release);
    6.21 -        }
    6.22 -
    6.23 -        PEP_SESSION Adapter::session(session_action action)
    6.24 -        {
    6.25 -            lock_guard<mutex> lock(mtx());
    6.26 -
    6.27 -            thread_local static PEP_SESSION _session = nullptr;
    6.28 -            thread_local int booked = 0;
    6.29 -            PEP_STATUS status = PEP_STATUS_OK;
    6.30 -
    6.31 -            switch (action) {
    6.32 -                case release:
    6.33 -                    if (booked)
    6.34 -                        --booked;
    6.35 -                    if (!booked && _session) {
    6.36 -                        ::release(_session);
    6.37 -                        _session = nullptr;
    6.38 -                    }
    6.39 -                    break;
    6.40 -
    6.41 -                case none:
    6.42 -                    if (_session)
    6.43 -                        break;
    6.44 -
    6.45 -                case init:
    6.46 -                    ++booked;
    6.47 -                    if (!_session)
    6.48 -                        status = ::init(&_session, _messageToSend, _inject_sync_event);
    6.49 -                    break;
    6.50 -
    6.51 -                default:
    6.52 -                    status = PEP_ILLEGAL_VALUE;
    6.53 -            }
    6.54 -
    6.55 -            if (status)
    6.56 -                _throw_status(status);
    6.57 -
    6.58 -            return _session;
    6.59 -        }
    6.60 -
    6.61 -        ::utility::locked_queue< SYNC_EVENT > * Adapter::q = nullptr;
    6.62 -        bool Adapter::flag_sync_enabled = false;
    6.63 -
    6.64 -        void Adapter::shutdown_sync()
    6.65 -        {
    6.66 -            if (queue_active())
    6.67 -                queue().push_front(nullptr);
    6.68 -            flag_sync_enabled = false;
    6.69 -        }
    6.70 -
    6.71 -        PyObject *Adapter::ui_object(PyObject *value)
    6.72 -        {
    6.73 -            lock_guard<mutex> lock(mtx());
    6.74 -            static PyObject *obj = nullptr;
    6.75 -            if (value)
    6.76 -                obj = value;
    6.77 -            return obj;
    6.78 -        }
    6.79 -
    6.80 -        int Adapter::_inject_sync_event(SYNC_EVENT ev, void *management)
    6.81 -        {
    6.82 -            if (!flag_sync_enabled)
    6.83 -                return 1;
    6.84 -
    6.85 -            if (is_sync_thread(adapter.session())) {
    6.86 -                PEP_STATUS status = do_sync_protocol_step(adapter.session(), adapter.ui_object(), ev);
    6.87 -                return status == PEP_STATUS_OK ? 0 : 1;
    6.88 -            }
    6.89 -
    6.90 -            try {
    6.91 -                queue().push_back(ev);
    6.92 -            }
    6.93 -            catch (exception&) {
    6.94 -                return 1;
    6.95 -            }
    6.96 -            return 0;
    6.97 -        }
    6.98 -    }
    6.99 -}
   6.100 -
     7.1 --- a/src/adapter.hh	Fri May 15 23:11:13 2020 +0200
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,59 +0,0 @@
     7.4 -// This file is under GNU Affero General Public License 3.0
     7.5 -// see LICENSE.txt
     7.6 -
     7.7 -#pragma once
     7.8 -
     7.9 -#include "pEpmodule.hh"
    7.10 -#include "locked_queue.hh"
    7.11 -#include "user_interface.hh"
    7.12 -#include <pEp/sync_api.h>
    7.13 -
    7.14 -namespace pEp {
    7.15 -    namespace PythonAdapter {
    7.16 -        using Message = pEp::PythonAdapter::Message;
    7.17 -
    7.18 -        class Adapter {
    7.19 -                bool flag_unregister;
    7.20 -
    7.21 -            public:
    7.22 -                Adapter(bool unregister_this = false);
    7.23 -                virtual ~Adapter();
    7.24 -
    7.25 -                enum session_action {
    7.26 -                    none = 0,
    7.27 -                    init,
    7.28 -                    release
    7.29 -                };
    7.30 -
    7.31 -                PEP_SESSION session(session_action action = none);
    7.32 -                static ::utility::locked_queue< SYNC_EVENT >& queue()
    7.33 -                {
    7.34 -                    if (!q)
    7.35 -                        q = new ::utility::locked_queue< SYNC_EVENT >();
    7.36 -                    return *q;
    7.37 -                }
    7.38 -                void script_is_implementing_sync() { flag_sync_enabled = true; }
    7.39 -                void shutdown_sync();
    7.40 -                bool is_sync_active() { return flag_sync_enabled; }
    7.41 -
    7.42 -            protected:
    7.43 -                static PyObject *ui_object(PyObject *value = nullptr);
    7.44 -                static int _inject_sync_event(SYNC_EVENT ev, void *management);
    7.45 -
    7.46 -                static ::utility::locked_queue< SYNC_EVENT > *q;
    7.47 -                static bool flag_sync_enabled;
    7.48 -
    7.49 -                bool queue_active() { return !!q; }
    7.50 -
    7.51 -            private:
    7.52 -                static mutex& mtx()
    7.53 -                {
    7.54 -                    static mutex m;
    7.55 -                    return m;
    7.56 -                }
    7.57 -
    7.58 -            friend class UserInterface_callback;
    7.59 -        };
    7.60 -    }
    7.61 -}
    7.62 -
     8.1 --- a/src/basic_api.cc	Fri May 15 23:11:13 2020 +0200
     8.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.3 @@ -1,161 +0,0 @@
     8.4 -// This file is under GNU Affero General Public License 3.0
     8.5 -// see LICENSE.txt
     8.6 -
     8.7 -#include "basic_api.hh"
     8.8 -#include <sstream>
     8.9 -#include <pEp/keymanagement.h>
    8.10 -#include <pEp/message_api.h>
    8.11 -
    8.12 -namespace pEp {
    8.13 -    namespace PythonAdapter {
    8.14 -        void update_identity(Identity& ident)
    8.15 -        {
    8.16 -            if (ident.address() == "")
    8.17 -                throw invalid_argument("address needed");
    8.18 -            if (ident.user_id() == PEP_OWN_USERID)
    8.19 -                throw runtime_error("update_identity: '" PEP_OWN_USERID
    8.20 -                        "' may only be used for own identities");
    8.21 -
    8.22 -            PEP_STATUS status = update_identity(adapter.session(), ident);
    8.23 -            _throw_status(status);
    8.24 -        }
    8.25 -
    8.26 -        void myself(Identity& ident)
    8.27 -        {
    8.28 -            if (ident.address() == "")
    8.29 -                throw invalid_argument("address needed");
    8.30 -            if (ident.username() == "")
    8.31 -                throw invalid_argument("username needed");
    8.32 -
    8.33 -            if (ident.user_id() == "")
    8.34 -                ident.user_id(ident.address());
    8.35 -
    8.36 -            PEP_STATUS status = myself(adapter.session(), ident);
    8.37 -            _throw_status(status);
    8.38 -        }
    8.39 -
    8.40 -        string _trustwords(Identity me, Identity partner, string lang, bool full)
    8.41 -        {
    8.42 -            if (me.fpr() == "" || partner.fpr() == "")
    8.43 -                throw invalid_argument("fingerprint needed in Identities");
    8.44 -
    8.45 -            if (lang == "" && me.lang() == partner.lang())
    8.46 -                lang = me.lang();
    8.47 -
    8.48 -            char *words = NULL;
    8.49 -            size_t size = 0;
    8.50 -            PEP_STATUS status =  get_trustwords(adapter.session(), me, partner,
    8.51 -                                        lang.c_str(),&words, &size, full);
    8.52 -            _throw_status(status);
    8.53 -            return words;
    8.54 -        }
    8.55 -
    8.56 -        void trust_personal_key(Identity ident)
    8.57 -        {
    8.58 -            if (ident.fpr() == "")
    8.59 -                throw invalid_argument("fingerprint needed in Identities");
    8.60 -            if (ident.user_id() == "")
    8.61 -                throw invalid_argument("user_id must be provided");
    8.62 -
    8.63 -            PEP_STATUS status = trust_personal_key(adapter.session(), ident);
    8.64 -            _throw_status(status);
    8.65 -        }
    8.66 -
    8.67 -        void set_identity_flags(Identity ident, identity_flags_t flags)
    8.68 -        {
    8.69 -            if (ident.address() == "")
    8.70 -                throw invalid_argument("address needed");
    8.71 -            if (ident.user_id() == "")
    8.72 -                throw invalid_argument("user_id needed");
    8.73 -
    8.74 -            PEP_STATUS status = set_identity_flags(adapter.session(), ident, flags);
    8.75 -            _throw_status(status);
    8.76 -        }
    8.77 -
    8.78 -        void unset_identity_flags(Identity ident, identity_flags_t flags)
    8.79 -        {
    8.80 -            if (ident.address() == "")
    8.81 -                throw invalid_argument("address needed");
    8.82 -            if (ident.user_id() == "")
    8.83 -                throw invalid_argument("user_id needed");
    8.84 -
    8.85 -            PEP_STATUS status = unset_identity_flags(adapter.session(), ident, flags);
    8.86 -            _throw_status(status);
    8.87 -        }
    8.88 -
    8.89 -        void key_reset_trust(Identity ident)
    8.90 -        {
    8.91 -            if (ident.fpr() == "")
    8.92 -                throw invalid_argument("fpr needed");
    8.93 -            if (ident.address() == "")
    8.94 -                throw invalid_argument("address needed");
    8.95 -            if (ident.user_id() == "")
    8.96 -                throw invalid_argument("user_id needed");
    8.97 -
    8.98 -            PEP_STATUS status = key_reset_trust(adapter.session(), ident);
    8.99 -            _throw_status(status);
   8.100 -        }
   8.101 -
   8.102 -
   8.103 -
   8.104 -        boost::python::list import_key(string key_data)
   8.105 -        {
   8.106 -            ::identity_list *private_keys = NULL;
   8.107 -            PEP_STATUS status = ::import_key(adapter.session(), key_data.c_str(), key_data.size(), &private_keys);
   8.108 -            if (status && status != PEP_KEY_IMPORTED)
   8.109 -                _throw_status(status);
   8.110 -
   8.111 -            auto result = boost::python::list();
   8.112 -            for (::identity_list *il = private_keys; il && il->ident; il=il->next) {
   8.113 -                ::pEp_identity *ident = ::identity_dup(il->ident);
   8.114 -                if (!ident) {
   8.115 -                    free_identity_list(private_keys);
   8.116 -                    throw bad_alloc();
   8.117 -                }
   8.118 -                result.append(Identity(ident));
   8.119 -            }
   8.120 -
   8.121 -            free_identity_list(private_keys);
   8.122 -            return result;
   8.123 -        }
   8.124 -
   8.125 -        string export_key(Identity ident)
   8.126 -        {
   8.127 -            PEP_STATUS status = PEP_STATUS_OK;
   8.128 -            char* key_data = NULL;
   8.129 -            size_t size;
   8.130 -            status = ::export_key(adapter.session(), ident.fpr().c_str(), &key_data, &size);
   8.131 -
   8.132 -            _throw_status(status);
   8.133 -            return key_data;
   8.134 -        }
   8.135 -
   8.136 -        string export_secret_key(Identity ident)
   8.137 -        {
   8.138 -            PEP_STATUS status = PEP_STATUS_OK;
   8.139 -            char* key_data = NULL;
   8.140 -            size_t size;
   8.141 -            status = ::export_secret_key(adapter.session(), ident.fpr().c_str(), &key_data, &size);
   8.142 -
   8.143 -            _throw_status(status);
   8.144 -            return key_data;
   8.145 -        }
   8.146 -
   8.147 -        void set_own_key(Identity& ident, string fpr)
   8.148 -        {
   8.149 -            if (ident.address() == "")
   8.150 -                throw invalid_argument("address needed");
   8.151 -            if (ident.username() == "")
   8.152 -                throw invalid_argument("username needed");
   8.153 -            if (ident.user_id() == "")
   8.154 -                throw invalid_argument("user_id needed");
   8.155 -            if (fpr == "")
   8.156 -                throw invalid_argument("fpr needed");
   8.157 -
   8.158 -
   8.159 -            const char* fpr_c = fpr.c_str();
   8.160 -            PEP_STATUS status = set_own_key(adapter.session(), ident, fpr_c);
   8.161 -            _throw_status(status);
   8.162 -        }
   8.163 -    }
   8.164 -}
     9.1 --- a/src/basic_api.hh	Fri May 15 23:11:13 2020 +0200
     9.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.3 @@ -1,25 +0,0 @@
     9.4 -// This file is under GNU Affero General Public License 3.0
     9.5 -// see LICENSE.txt
     9.6 -
     9.7 -#pragma once
     9.8 -
     9.9 -#include "pEpmodule.hh"
    9.10 -
    9.11 -namespace pEp {
    9.12 -    namespace PythonAdapter {
    9.13 -        void update_identity(Identity& ident);
    9.14 -        void myself(Identity& ident);
    9.15 -        string _trustwords(Identity me, Identity partner, string lang, bool full);
    9.16 -        void trust_personal_key(Identity ident);
    9.17 -
    9.18 -        void set_identity_flags(Identity ident, identity_flags_t flags);
    9.19 -        void unset_identity_flags(Identity ident, identity_flags_t flags);
    9.20 -
    9.21 -        void key_reset_trust(Identity ident);
    9.22 -
    9.23 -        boost::python::list import_key(string key_data);
    9.24 -        string export_key(Identity ident);
    9.25 -        string export_secret_key(Identity ident);
    9.26 -        void set_own_key(Identity& ident, string fpr);
    9.27 -    }
    9.28 -}
    10.1 --- a/src/identity.cc	Fri May 15 23:11:13 2020 +0200
    10.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.3 @@ -1,278 +0,0 @@
    10.4 -// This file is under GNU Affero General Public License 3.0
    10.5 -// see LICENSE.txt
    10.6 -
    10.7 -#include "identity.hh"
    10.8 -#include "pEpmodule.hh"
    10.9 -#include "basic_api.hh"
   10.10 -#include "message_api.hh"
   10.11 -#include <typeinfo>
   10.12 -#include <sstream>
   10.13 -#include <pEp/identity_list.h>
   10.14 -#include <pEp/keymanagement.h>
   10.15 -#include <pEp/key_reset.h>
   10.16 -#include <pEp/message_api.h>
   10.17 -
   10.18 -namespace pEp {
   10.19 -    namespace PythonAdapter {
   10.20 -
   10.21 -        Identity::Identity(string address, string username, string user_id,
   10.22 -                string fpr, int comm_type, string lang, identity_flags_t flags)
   10.23 -            : _ident(new_identity(address.c_str(), fpr.c_str(), user_id.c_str(),
   10.24 -                        username.c_str()), &::free_identity)
   10.25 -        {
   10.26 -            if (!_ident)
   10.27 -                throw bad_alloc();
   10.28 -            _ident->comm_type = (PEP_comm_type) comm_type;
   10.29 -            _ident->flags = (identity_flags_t) flags;
   10.30 -            this->lang(lang);
   10.31 -        }
   10.32 -
   10.33 -        Identity::Identity(const Identity& second)
   10.34 -            : _ident(second._ident)
   10.35 -        {
   10.36 -
   10.37 -        }
   10.38 -
   10.39 -        Identity::Identity(pEp_identity *ident)
   10.40 -            : _ident(ident, &::free_identity)
   10.41 -        {
   10.42 -
   10.43 -        }
   10.44 -
   10.45 -        Identity::~Identity()
   10.46 -        {
   10.47 -
   10.48 -       }
   10.49 -
   10.50 -        Identity::operator pEp_identity *()
   10.51 -        {
   10.52 -            return _ident.get();
   10.53 -        }
   10.54 -
   10.55 -        Identity::operator const pEp_identity *() const
   10.56 -        {
   10.57 -            return _ident.get();
   10.58 -        }
   10.59 -
   10.60 -        string Identity::_repr()
   10.61 -        {
   10.62 -            stringstream build;
   10.63 -            build << "Identity(";
   10.64 -            string address;
   10.65 -            if (_ident->address)
   10.66 -                address = string(_ident->address);
   10.67 -            build << repr(address) << ", ";
   10.68 -            string username;
   10.69 -            if (_ident->username)
   10.70 -                username = string(_ident->username);
   10.71 -            build << repr(username) << ", ";
   10.72 -            string user_id;
   10.73 -            if (_ident->user_id)
   10.74 -                user_id = string(_ident->user_id);
   10.75 -            build << repr(user_id) << ", ";
   10.76 -            string fpr;
   10.77 -            if (_ident->fpr)
   10.78 -                fpr = string(_ident->fpr);
   10.79 -            build << repr(fpr) << ", ";
   10.80 -            build << (int) _ident->comm_type << ", ";
   10.81 -            string lang = _ident->lang;
   10.82 -            build << repr(lang) << ")";
   10.83 -            return build.str();
   10.84 -        }
   10.85 -
   10.86 -        string Identity::_str()
   10.87 -        {
   10.88 -            if (!(_ident->address && _ident->address[0]))
   10.89 -                return "";
   10.90 -            if (!(_ident->username && _ident->username[0]))
   10.91 -                return _ident->address;
   10.92 -            return string(_ident->username) + " <" + _ident->address + ">";
   10.93 -        }
   10.94 -
   10.95 -        void Identity::username(string value)
   10.96 -        {
   10.97 -            if (value.length() && value.length() < 5)
   10.98 -                throw length_error("username must be at least 5 characters");
   10.99 -
  10.100 -            str_attr(_ident->username, value);
  10.101 -        }
  10.102 -
  10.103 -        void Identity::lang(string value)
  10.104 -        {
  10.105 -            if (value == "")
  10.106 -                memset(_ident->lang, 0, 3);
  10.107 -            else if (value.length() != 2)
  10.108 -                throw length_error("length of lang must be 2");
  10.109 -            else
  10.110 -                memcpy(_ident->lang, value.c_str(), 3);
  10.111 -        }
  10.112 -
  10.113 -        string Identity::lang()
  10.114 -        {
  10.115 -            return _ident->lang;
  10.116 -        }
  10.117 -
  10.118 -        int Identity::rating()
  10.119 -        {
  10.120 -            if (!(_ident->address))
  10.121 -                throw invalid_argument("address must be given");
  10.122 -
  10.123 -            PEP_rating rating = PEP_rating_undefined;
  10.124 -            PEP_STATUS status = ::identity_rating(adapter.session(), _ident.get(), &rating);
  10.125 -            _throw_status(status);
  10.126 -
  10.127 -            return (int) rating;
  10.128 -        }
  10.129 -
  10.130 -        PEP_color Identity::color()
  10.131 -        {
  10.132 -            return _color(rating());
  10.133 -        }
  10.134 -
  10.135 -        Identity Identity::copy()
  10.136 -        {
  10.137 -            pEp_identity *dup = ::identity_dup(*this);
  10.138 -            if (!dup)
  10.139 -                throw bad_alloc();
  10.140 -
  10.141 -            return Identity(dup);
  10.142 -        }
  10.143 -
  10.144 -        Identity Identity::deepcopy(dict&)
  10.145 -        {
  10.146 -            return copy();
  10.147 -        }
  10.148 -
  10.149 -        void Identity::update()
  10.150 -        {
  10.151 -            update_identity(*this);
  10.152 -        }
  10.153 -
  10.154 -        void Identity::key_reset(string fpr)
  10.155 -        {
  10.156 -            PEP_STATUS status = ::key_reset_identity(adapter.session(), *this,
  10.157 -                    fpr != "" ? fpr.c_str() : nullptr);
  10.158 -            _throw_status(status);
  10.159 -        }
  10.160 -
  10.161 -        void Identity::key_mistrusted()
  10.162 -        {
  10.163 -            PEP_STATUS status = ::key_mistrusted(adapter.session(), *this);
  10.164 -            _throw_status(status);
  10.165 -        }
  10.166 -
  10.167 -        bool Identity::is_pEp_user()
  10.168 -        {
  10.169 -            bool result;
  10.170 -            PEP_STATUS status = ::is_pEp_user(adapter.session(), *this, &result);
  10.171 -            _throw_status(status);
  10.172 -            return result;
  10.173 -        }
  10.174 -
  10.175 -        void Identity::enable_for_sync()
  10.176 -        {
  10.177 -            PEP_STATUS status = ::enable_identity_for_sync(adapter.session(), *this);
  10.178 -            _throw_status(status);
  10.179 -        }
  10.180 -
  10.181 -        void Identity::disable_for_sync()
  10.182 -        {
  10.183 -            PEP_STATUS status = ::disable_identity_for_sync(adapter.session(), *this);
  10.184 -            _throw_status(status);
  10.185 -        }
  10.186 -
  10.187 -        Myself::Myself(string address, string username, string user_id, string lang)
  10.188 -            : Identity(address, username, user_id, "", 0, lang)
  10.189 -
  10.190 -        {
  10.191 -            if (!(address.length() && username.length()))
  10.192 -                throw invalid_argument("address and username must be set");
  10.193 -            if (lang.length() && lang.length() != 2)
  10.194 -                throw length_error("lang must be an ISO 639-1 language code or empty");
  10.195 -
  10.196 -            // FIXME: should set .me
  10.197 -            // _ident->me = true;
  10.198 -            if (user_id.length())
  10.199 -                throw runtime_error("user_id feature not yet implemented for Myself");
  10.200 -        }
  10.201 -
  10.202 -        void Myself::update()
  10.203 -        {
  10.204 -            pEp::PythonAdapter::myself(*this);
  10.205 -        }
  10.206 -
  10.207 -        Identity identity_attr(pEp_identity *&ident)
  10.208 -        {
  10.209 -            if (!ident)
  10.210 -                throw out_of_range("no identity assigned");
  10.211 -
  10.212 -            pEp_identity *_dup = identity_dup(ident);
  10.213 -            if (!_dup)
  10.214 -                throw bad_alloc();
  10.215 -
  10.216 -            Identity _ident(_dup);
  10.217 -            return _ident;
  10.218 -        }
  10.219 -
  10.220 -        void identity_attr(pEp_identity *&ident, object value)
  10.221 -        {
  10.222 -            Identity& _ident = extract< Identity& >(value);
  10.223 -            pEp_identity *_dup = ::identity_dup(_ident);
  10.224 -            if (!_dup)
  10.225 -                throw bad_alloc();
  10.226 -            PEP_STATUS status = update_identity(adapter.session(), _dup);
  10.227 -            _throw_status(status);
  10.228 -            free_identity(ident);
  10.229 -            ident = _dup;
  10.230 -        }
  10.231 -
  10.232 -        boost::python::list identitylist_attr(identity_list *&il)
  10.233 -        {
  10.234 -            boost::python::list result;
  10.235 -
  10.236 -            for (identity_list *_il = il; _il && _il->ident; _il = _il->next) {
  10.237 -                pEp_identity *ident = ::identity_dup(_il->ident);
  10.238 -                if (!ident)
  10.239 -                    throw bad_alloc();
  10.240 -                result.append(object(Identity(ident)));
  10.241 -            }
  10.242 -
  10.243 -            return result;
  10.244 -        }
  10.245 -
  10.246 -        void identitylist_attr(identity_list *&il, boost::python::list value)
  10.247 -        {
  10.248 -            identity_list *_il = new_identity_list(NULL);
  10.249 -            if (!_il)
  10.250 -                throw bad_alloc();
  10.251 -
  10.252 -            identity_list *_i = _il;
  10.253 -            for (int i=0; i<len(value); i++) {
  10.254 -                extract< Identity& > extract_identity(value[i]);
  10.255 -                if (!extract_identity.check()) {
  10.256 -                    free_identity_list(_il);
  10.257 -                }
  10.258 -                pEp_identity *_ident = extract_identity();
  10.259 -                pEp_identity *_dup = ::identity_dup(_ident);
  10.260 -                if (!_dup) {
  10.261 -                    free_identity_list(_il);
  10.262 -                    throw bad_alloc();
  10.263 -                }
  10.264 -                PEP_STATUS status = update_identity(adapter.session(), _dup);
  10.265 -                if (status != PEP_STATUS_OK) {
  10.266 -                    free_identity_list(_il);
  10.267 -                    _throw_status(status);
  10.268 -                }
  10.269 -                _i = identity_list_add(_i, _dup);
  10.270 -                if (!_i) {
  10.271 -                    free_identity_list(_il);
  10.272 -                    throw bad_alloc();
  10.273 -                }
  10.274 -            }
  10.275 -
  10.276 -            free_identity_list(il);
  10.277 -            il = _il;
  10.278 -        }
  10.279 -    }
  10.280 -}
  10.281 -
    11.1 --- a/src/identity.hh	Fri May 15 23:11:13 2020 +0200
    11.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.3 @@ -1,90 +0,0 @@
    11.4 -// This file is under GNU Affero General Public License 3.0
    11.5 -// see LICENSE.txt
    11.6 -
    11.7 -#pragma once
    11.8 -
    11.9 -#include <boost/python.hpp>
   11.10 -#include <pEp/pEpEngine.h>
   11.11 -#include <pEp/message_api.h>
   11.12 -#include <string>
   11.13 -#include <memory>
   11.14 -#include <cstddef>
   11.15 -#include "str_attr.hh"
   11.16 -
   11.17 -namespace pEp {
   11.18 -    namespace PythonAdapter {
   11.19 -        using namespace utility;
   11.20 -        using namespace std;
   11.21 -
   11.22 -        // Identity is owning a pEp_identity
   11.23 -
   11.24 -        class Identity {
   11.25 -        protected:
   11.26 -            shared_ptr< pEp_identity > _ident;
   11.27 -
   11.28 -        public:
   11.29 -            Identity(string address = "", string username = "",
   11.30 -                    string user_id = "", string fpr = "", int comm_type = 0,
   11.31 -                    string lang = "", identity_flags_t flags = 0);
   11.32 -
   11.33 -            Identity(const Identity& second);
   11.34 -            Identity(pEp_identity *ident);
   11.35 -            virtual ~Identity();
   11.36 -            operator pEp_identity *();
   11.37 -            operator const pEp_identity *() const;
   11.38 -
   11.39 -            string _repr();
   11.40 -            string _str();
   11.41 -
   11.42 -            string address() { return str_attr(_ident->address); }
   11.43 -            void address(string value) { str_attr(_ident->address, value); }
   11.44 -
   11.45 -            string fpr() { return str_attr(_ident->fpr); }
   11.46 -            void fpr(string value) { str_attr(_ident->fpr, value); }
   11.47 -
   11.48 -            string user_id() { return str_attr(_ident->user_id); }
   11.49 -            void user_id(string value) { str_attr(_ident->user_id, value); }
   11.50 -
   11.51 -            string username() { return str_attr(_ident->username); }
   11.52 -            void username(string value);
   11.53 -
   11.54 -            PEP_comm_type comm_type() { return _ident->comm_type; }
   11.55 -            void comm_type(PEP_comm_type value) { _ident->comm_type = value; };
   11.56 -
   11.57 -            std::string lang();
   11.58 -            void lang(std::string value);
   11.59 -
   11.60 -            identity_flags_t flags() { return _ident->flags; }
   11.61 -            void flags(identity_flags_t flags) { _ident->flags = flags; }
   11.62 -
   11.63 -            int rating();
   11.64 -            PEP_color color();
   11.65 -
   11.66 -            Identity copy();
   11.67 -            Identity deepcopy(dict& memo);
   11.68 -
   11.69 -            virtual void update();
   11.70 -
   11.71 -            void key_reset(string fpr="");
   11.72 -            void key_mistrusted();
   11.73 -
   11.74 -            bool is_pEp_user();
   11.75 -
   11.76 -            void enable_for_sync();
   11.77 -            void disable_for_sync();
   11.78 -        };
   11.79 -
   11.80 -        class Myself : public Identity {
   11.81 -        public:
   11.82 -            Myself(string address, string username, string user_id="", string lang="");
   11.83 -            virtual void update();
   11.84 -        };
   11.85 -
   11.86 -        Identity identity_attr(pEp_identity *&ident);
   11.87 -        void identity_attr(pEp_identity *&ident, object value);
   11.88 -
   11.89 -        boost::python::list identitylist_attr(identity_list *&il);
   11.90 -        void identitylist_attr(identity_list *&il, boost::python::list value);
   11.91 -    }
   11.92 -}
   11.93 -
    12.1 --- a/src/locked_queue.hh	Fri May 15 23:11:13 2020 +0200
    12.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.3 @@ -1,61 +0,0 @@
    12.4 -#pragma once
    12.5 -
    12.6 -#include <list>
    12.7 -#include <mutex>
    12.8 -
    12.9 -namespace utility
   12.10 -{
   12.11 -    using namespace std;
   12.12 -
   12.13 -    template<class T> class locked_queue
   12.14 -    {
   12.15 -        mutex _mtx;
   12.16 -        list<T> _q;
   12.17 -
   12.18 -    public:
   12.19 -        T& back()
   12.20 -        {
   12.21 -            lock_guard<mutex> lg(_mtx);
   12.22 -            return _q.back();
   12.23 -        }
   12.24 -        T& front()
   12.25 -        {
   12.26 -            lock_guard<mutex> lg(_mtx);
   12.27 -            return _q.front();
   12.28 -        }
   12.29 -        T pop_back()
   12.30 -        {
   12.31 -            lock_guard<mutex> lg(_mtx);
   12.32 -            T r = _q.back();
   12.33 -            _q.pop_back();
   12.34 -            return r;
   12.35 -        }
   12.36 -        T pop_front()
   12.37 -        {
   12.38 -            lock_guard<mutex> lg(_mtx);
   12.39 -            T r = _q.front();
   12.40 -            _q.pop_front();
   12.41 -            return r;
   12.42 -        }
   12.43 -        void push_back(const T& data)
   12.44 -        {
   12.45 -            lock_guard<mutex> lg(_mtx);
   12.46 -            _q.push_back(data);
   12.47 -        }
   12.48 -        void push_front(const T& data)
   12.49 -        {
   12.50 -            lock_guard<mutex> lg(_mtx);
   12.51 -            _q.push_front(data);
   12.52 -        }
   12.53 -        size_t size()
   12.54 -        {
   12.55 -            lock_guard<mutex> lg(_mtx);
   12.56 -            return _q.size();
   12.57 -        }
   12.58 -        bool empty()
   12.59 -        {
   12.60 -            lock_guard<mutex> lg(_mtx);
   12.61 -            return _q.empty();
   12.62 -        }
   12.63 -    };
   12.64 -};
    13.1 --- a/src/message.cc	Fri May 15 23:11:13 2020 +0200
    13.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.3 @@ -1,406 +0,0 @@
    13.4 -// This file is under GNU Affero General Public License 3.0
    13.5 -// see LICENSE.txt
    13.6 -
    13.7 -#include <Python.h>
    13.8 -#include "message.hh"
    13.9 -#include "message_api.hh"
   13.10 -#include <stdlib.h>
   13.11 -#include <string.h>
   13.12 -#include <stdexcept>
   13.13 -#include <sstream>
   13.14 -#include <vector>
   13.15 -#include <pEp/mime.h>
   13.16 -#include <pEp/keymanagement.h>
   13.17 -#include <pEp/message_api.h>
   13.18 -
   13.19 -namespace pEp {
   13.20 -    namespace PythonAdapter {
   13.21 -        using namespace std;
   13.22 -
   13.23 -        Message::Blob::Blob(bloblist_t *bl, bool chained) :
   13.24 -            _bl(bl), part_of_chain(chained)
   13.25 -        {
   13.26 -            if (!_bl)
   13.27 -                throw bad_alloc();
   13.28 -        }
   13.29 -
   13.30 -        Message::Blob::Blob(object data, string mime_type, string filename) :
   13.31 -            _bl(new_bloblist(NULL, 0, NULL, NULL)), part_of_chain(false)
   13.32 -        {
   13.33 -            if (!_bl)
   13.34 -                throw bad_alloc();
   13.35 -
   13.36 -            Py_buffer src;
   13.37 -            int result = PyObject_GetBuffer(data.ptr(), &src, PyBUF_CONTIG_RO);
   13.38 -            if (result)
   13.39 -                throw invalid_argument("need a contiguous buffer to read");
   13.40 -
   13.41 -            char *mem = (char *)malloc(src.len);
   13.42 -            if (!mem) {
   13.43 -                PyBuffer_Release(&src);
   13.44 -                throw bad_alloc();
   13.45 -            }
   13.46 -
   13.47 -            memcpy(mem, src.buf, src.len);
   13.48 -            free(_bl->value);
   13.49 -            _bl->size = src.len;
   13.50 -            _bl->value = mem;
   13.51 -
   13.52 -            PyBuffer_Release(&src);
   13.53 -
   13.54 -            this->mime_type(mime_type);
   13.55 -            this->filename(filename);
   13.56 -        }
   13.57 -
   13.58 -        Message::Blob::Blob(const Message::Blob& second) :
   13.59 -            _bl(second._bl), part_of_chain(true)
   13.60 -        {
   13.61 -
   13.62 -        }
   13.63 -
   13.64 -        Message::Blob::~Blob()
   13.65 -        {
   13.66 -            if (!part_of_chain) {
   13.67 -                free(_bl->value);
   13.68 -                free(_bl);
   13.69 -            }
   13.70 -        }
   13.71 -
   13.72 -        string Message::Blob::_repr()
   13.73 -        {
   13.74 -            stringstream build;
   13.75 -            build << "Blob(";
   13.76 -            if (!_bl) {
   13.77 -                build << "b'', '', ''";
   13.78 -            }
   13.79 -            else {
   13.80 -                build << "bytes(" << _bl->size << "), ";
   13.81 -                string mime_type;
   13.82 -                if (_bl->mime_type)
   13.83 -                    mime_type = string(_bl->mime_type);
   13.84 -                string filename;
   13.85 -                if (_bl->filename)
   13.86 -                    filename = string(_bl->filename);
   13.87 -                build << repr(mime_type) << ", ";
   13.88 -                build << repr(filename);
   13.89 -            }
   13.90 -            build << ")";
   13.91 -            return build.str();
   13.92 -        }
   13.93 -
   13.94 -        int Message::Blob::getbuffer(PyObject *self, Py_buffer *view, int flags) {
   13.95 -            bloblist_t *bl = NULL;
   13.96 -
   13.97 -            try {
   13.98 -                Message::Blob& blob = extract< Message::Blob& >(self);
   13.99 -                bl = blob._bl;
  13.100 -            }
  13.101 -            catch (exception& e) {
  13.102 -                PyErr_SetString(PyExc_RuntimeError, "extract not possible");
  13.103 -                view->obj = NULL;
  13.104 -                return -1;
  13.105 -            }
  13.106 -
  13.107 -            if (!(bl && bl->value)) {
  13.108 -                PyErr_SetString(PyExc_RuntimeError, "no data available");
  13.109 -                view->obj = NULL;
  13.110 -                return -1;
  13.111 -            }
  13.112 -
  13.113 -            return PyBuffer_FillInfo(view, self, bl->value, bl->size, 0, flags);
  13.114 -        }
  13.115 -
  13.116 -        string Message::Blob::decode(string encoding)
  13.117 -        {
  13.118 -            if (encoding == "") {
  13.119 -                string _mime_type = _bl->mime_type ? _bl->mime_type : "";
  13.120 -                encoding = "ascii";
  13.121 -
  13.122 -                if (_mime_type == "application/pEp.sync")
  13.123 -                    encoding = "pep.sync";
  13.124 -
  13.125 -                if (_mime_type == "application/pEp.keyreset")
  13.126 -                    encoding = "pep.distribution";
  13.127 -
  13.128 -            }
  13.129 -            object codecs = import("codecs");
  13.130 -            object _decode = codecs.attr("decode");
  13.131 -            return call< string >(_decode.ptr(), this, encoding);
  13.132 -        }
  13.133 -
  13.134 -        PyBufferProcs Message::Blob::bp = { getbuffer, NULL };
  13.135 -
  13.136 -        Message::Message(int dir, Identity *from)
  13.137 -            : _msg(new_message((PEP_msg_direction) dir), &free_message)
  13.138 -        {
  13.139 -            if (!_msg)
  13.140 -                throw bad_alloc();
  13.141 -
  13.142 -            if (from) {
  13.143 -                _msg->from = ::identity_dup(*from);
  13.144 -                if (!_msg->from)
  13.145 -                    throw bad_alloc();
  13.146 -                _msg->dir = (PEP_msg_direction) dir;
  13.147 -            }
  13.148 -        }
  13.149 -
  13.150 -        Message::Message(string mimetext)
  13.151 -            : _msg(NULL, &free_message)
  13.152 -        {
  13.153 -            message *_cpy;
  13.154 -            PEP_STATUS status = mime_decode_message(mimetext.c_str(),
  13.155 -                    mimetext.size(), &_cpy, NULL);
  13.156 -            switch (status) {
  13.157 -                case PEP_STATUS_OK:
  13.158 -                    if (_cpy)
  13.159 -                        _cpy->dir = PEP_dir_outgoing;
  13.160 -                    else
  13.161 -                        _cpy = new_message(PEP_dir_outgoing);
  13.162 -
  13.163 -                    if (!_cpy)
  13.164 -                        throw bad_alloc();
  13.165 -
  13.166 -                    _msg = shared_ptr< message >(_cpy);
  13.167 -                    break;
  13.168 -
  13.169 -                case PEP_BUFFER_TOO_SMALL:
  13.170 -                    throw runtime_error("mime_decode_message: buffer too small");
  13.171 -
  13.172 -                case PEP_CANNOT_CREATE_TEMP_FILE:
  13.173 -                    throw runtime_error("mime_decode_message: cannot create temp file");
  13.174 -
  13.175 -                case PEP_OUT_OF_MEMORY:
  13.176 -                    throw bad_alloc();
  13.177 -
  13.178 -                default:
  13.179 -                    stringstream build;
  13.180 -                    build << "mime_decode_message: unknown error (" << (int) status << ")";
  13.181 -                    throw runtime_error(build.str());
  13.182 -            }
  13.183 -        }
  13.184 -
  13.185 -        Message::Message(const Message& second)
  13.186 -            : _msg(second._msg)
  13.187 -        {
  13.188 -            if (!_msg.get())
  13.189 -                throw bad_alloc();
  13.190 -        }
  13.191 -
  13.192 -        Message::Message(message *msg)
  13.193 -            : _msg(::message_dup(msg), &free_message)
  13.194 -        {
  13.195 -
  13.196 -        }
  13.197 -
  13.198 -        Message::~Message()
  13.199 -        {
  13.200 -
  13.201 -        }
  13.202 -
  13.203 -        Message::operator message *()
  13.204 -        {
  13.205 -            return _msg.get();
  13.206 -        }
  13.207 -
  13.208 -        Message::operator const message *() const
  13.209 -        {
  13.210 -            return _msg.get();
  13.211 -        }
  13.212 -
  13.213 -        string Message::_str()
  13.214 -        {
  13.215 -            if (!(_msg->from && _msg->from->address && _msg->from->address[0]))
  13.216 -                throw out_of_range(".from_.address missing");
  13.217 -
  13.218 -            char *mimetext;
  13.219 -            string result;
  13.220 -
  13.221 -            PEP_STATUS status = mime_encode_message(*this, false, &mimetext, false);
  13.222 -            switch (status) {
  13.223 -                case PEP_STATUS_OK:
  13.224 -                    result = mimetext;
  13.225 -                    free(mimetext);
  13.226 -                    break;
  13.227 -
  13.228 -                case PEP_BUFFER_TOO_SMALL:
  13.229 -                    throw runtime_error("mime_encode_message: buffer too small");
  13.230 -
  13.231 -                case PEP_CANNOT_CREATE_TEMP_FILE:
  13.232 -                    throw runtime_error("mime_encode_message: cannot create temp file");
  13.233 -
  13.234 -                case PEP_OUT_OF_MEMORY:
  13.235 -                    throw bad_alloc();
  13.236 -
  13.237 -                default:
  13.238 -                    stringstream build;
  13.239 -                    build << "mime_encode_message: unknown error (" << (int) status << ")";
  13.240 -                    throw runtime_error(build.str());
  13.241 -            }
  13.242 -
  13.243 -            return result;
  13.244 -        }
  13.245 -
  13.246 -        string Message::_repr()
  13.247 -        {
  13.248 -            stringstream build;
  13.249 -            build << "Message(" << repr(_str()) << ")";
  13.250 -            return build.str();
  13.251 -        }
  13.252 -
  13.253 -        boost::python::tuple Message::attachments()
  13.254 -        {
  13.255 -            boost::python::list l;
  13.256 -
  13.257 -            for (bloblist_t *bl = _msg->attachments; bl && bl->value; bl =
  13.258 -                    bl->next) {
  13.259 -                l.append(Blob(bl, true));
  13.260 -            }
  13.261 -
  13.262 -            return boost::python::tuple(l);
  13.263 -        }
  13.264 -
  13.265 -        void Message::attachments(boost::python::list value)
  13.266 -        {
  13.267 -            bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL);
  13.268 -            if (!bl)
  13.269 -                throw bad_alloc();
  13.270 -
  13.271 -            bloblist_t *_l = bl;
  13.272 -            for (int i=0; i<len(value); i++) {
  13.273 -                Message::Blob& blob = extract< Message::Blob& >(value[i]);
  13.274 -                _l = bloblist_add(_l, blob._bl->value, blob._bl->size,
  13.275 -                        blob._bl->mime_type, blob._bl->filename);
  13.276 -                if (!_l) {
  13.277 -                    for (_l = bl; _l && _l->value; ) {
  13.278 -                        free(_l->mime_type);
  13.279 -                        free(_l->filename);
  13.280 -                        bloblist_t *_ll = _l;
  13.281 -                        _l = _l->next;
  13.282 -                        free(_ll);
  13.283 -                    }
  13.284 -                    throw bad_alloc();
  13.285 -                }
  13.286 -            }
  13.287 -
  13.288 -            for (int i=0; i<len(value); i++) {
  13.289 -                Message::Blob& blob = extract< Message::Blob& >(value[i]);
  13.290 -                blob._bl->value = NULL;
  13.291 -                blob._bl->size = 0;
  13.292 -                free(blob._bl->mime_type);
  13.293 -                blob._bl->mime_type = NULL;
  13.294 -                free(blob._bl->filename);
  13.295 -                blob._bl->filename = NULL;
  13.296 -            }
  13.297 -
  13.298 -            free_bloblist(_msg->attachments);
  13.299 -            _msg->attachments = bl;
  13.300 -        }
  13.301 -
  13.302 -        Message Message::encrypt()
  13.303 -        {
  13.304 -            boost::python::list extra;
  13.305 -            return encrypt_message(*this, extra, PEP_enc_PGP_MIME, 0);
  13.306 -        }
  13.307 -
  13.308 -        Message Message::_encrypt(boost::python::list extra, int enc_format, int flags)
  13.309 -        {
  13.310 -            if (!enc_format)
  13.311 -                enc_format = PEP_enc_PGP_MIME;
  13.312 -            return encrypt_message(*this, extra, enc_format, flags);
  13.313 -        }
  13.314 -
  13.315 -        boost::python::tuple Message::decrypt(int flags) {
  13.316 -            return pEp::PythonAdapter::decrypt_message(*this, flags);
  13.317 -        }
  13.318 -
  13.319 -        PEP_rating Message::outgoing_rating()
  13.320 -        {
  13.321 -            if (_msg->dir != PEP_dir_outgoing)
  13.322 -                throw invalid_argument("Message.dir must be outgoing");
  13.323 -
  13.324 -            if (from().address() == "")
  13.325 -                throw invalid_argument("from.address needed");
  13.326 -            if (from().username() == "")
  13.327 -                throw invalid_argument("from.username needed");
  13.328 -
  13.329 -            if (len(to()) + len(cc()) == 0)
  13.330 -                throw invalid_argument("either to or cc needed");
  13.331 -
  13.332 -            PEP_STATUS status = myself(adapter.session(), _msg->from);
  13.333 -            _throw_status(status);
  13.334 -
  13.335 -            PEP_rating rating = PEP_rating_undefined;
  13.336 -            status = outgoing_message_rating(adapter.session(), *this, &rating);
  13.337 -            _throw_status(status);
  13.338 -
  13.339 -            return rating;
  13.340 -        }
  13.341 -
  13.342 -        PEP_color Message::outgoing_color()
  13.343 -        {
  13.344 -            return _color(outgoing_rating());
  13.345 -        }
  13.346 -
  13.347 -        Message Message::copy()
  13.348 -        {
  13.349 -            message *dup = message_dup(*this);
  13.350 -            if (!dup)
  13.351 -                throw bad_alloc();
  13.352 -            return Message(dup);
  13.353 -        }
  13.354 -
  13.355 -        Message Message::deepcopy(dict&)
  13.356 -        {
  13.357 -            return copy();
  13.358 -        }
  13.359 -
  13.360 -        Message outgoing_message(Identity me)
  13.361 -        {
  13.362 -            if (me.address().empty() || me.user_id().empty())
  13.363 -                throw runtime_error("at least address and user_id of own user needed");
  13.364 -
  13.365 -            ::myself(adapter.session(), me);
  13.366 -            auto m = Message(PEP_dir_outgoing, &me);
  13.367 -            return m;
  13.368 -        }
  13.369 -
  13.370 -        static object update(Identity ident)
  13.371 -        {
  13.372 -            if (ident.address().empty())
  13.373 -                throw runtime_error("at least address needed");
  13.374 -            update_identity(adapter.session(), ident);
  13.375 -            return object(ident);
  13.376 -        }
  13.377 -
  13.378 -        static boost::python::list update(boost::python::list il)
  13.379 -        {
  13.380 -            for (int i=0; i<len(il); i++) {
  13.381 -                update(extract< Identity >(il[i]));
  13.382 -            }
  13.383 -
  13.384 -            return il;
  13.385 -        }
  13.386 -
  13.387 -        Message incoming_message(string mime_text)
  13.388 -        {
  13.389 -            auto m = Message(mime_text);
  13.390 -            m.dir(PEP_dir_incoming);
  13.391 -
  13.392 -            try {
  13.393 -                m.from(update(m.from()));
  13.394 -            }
  13.395 -            catch (out_of_range&) { }
  13.396 -
  13.397 -            try {
  13.398 -                m.recv_by(update(m.recv_by()));
  13.399 -            }
  13.400 -            catch (out_of_range&) { }
  13.401 -
  13.402 -            m.to(update(m.to()));
  13.403 -            m.cc(update(m.cc()));
  13.404 -            m.reply_to(update(m.reply_to()));
  13.405 -
  13.406 -            return m;
  13.407 -        }
  13.408 -    }
  13.409 -}
    14.1 --- a/src/message.hh	Fri May 15 23:11:13 2020 +0200
    14.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.3 @@ -1,145 +0,0 @@
    14.4 -// This file is under GNU Affero General Public License 3.0
    14.5 -// see LICENSE.txt
    14.6 -
    14.7 -#pragma once
    14.8 -
    14.9 -#include <boost/python.hpp>
   14.10 -#include <boost/lexical_cast.hpp>
   14.11 -#include <pEp/message.h>
   14.12 -#include <pEp/message_api.h>
   14.13 -#include <string>
   14.14 -#include "str_attr.hh"
   14.15 -#include "identity.hh"
   14.16 -
   14.17 -namespace pEp {
   14.18 -    namespace PythonAdapter {
   14.19 -        using namespace std;
   14.20 -        using namespace boost::python;
   14.21 -        using boost::lexical_cast;
   14.22 -
   14.23 -        // Message is owning a message struct
   14.24 -
   14.25 -        class Message {
   14.26 -            shared_ptr< ::message > _msg;
   14.27 -
   14.28 -        public:
   14.29 -            // Blob is owning a bloblist_t struct - or not and just managing
   14.30 -            // one depending on part_of_chain
   14.31 -
   14.32 -            class Blob {
   14.33 -                bloblist_t *_bl;
   14.34 -                bool part_of_chain;
   14.35 -
   14.36 -            public:
   14.37 -                Blob(bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL),
   14.38 -                        bool chained = false);
   14.39 -                Blob(object data, string mime_type = "", string filename = "");
   14.40 -                Blob(const Blob& second);
   14.41 -                ~Blob();
   14.42 -
   14.43 -                string _repr();
   14.44 -
   14.45 -                string mime_type() { return _bl ? str_attr(_bl->mime_type) : ""; }
   14.46 -                void mime_type(string value) { str_attr(_bl->mime_type, value); }
   14.47 -
   14.48 -                string filename() { return str_attr(_bl->filename); }
   14.49 -                void filename(string value) { str_attr(_bl->filename, value); }
   14.50 -
   14.51 -                size_t size() { return _bl->size; }
   14.52 -                string decode(string encoding);
   14.53 -                string decode() { return decode(""); }
   14.54 -
   14.55 -                static PyBufferProcs bp;
   14.56 -
   14.57 -                friend class Message;
   14.58 -
   14.59 -            protected:
   14.60 -                static int getbuffer(PyObject *self, Py_buffer *view, int flags);
   14.61 -            };
   14.62 -
   14.63 -            Message(int dir = PEP_dir_outgoing, Identity *from = NULL);
   14.64 -            Message(string mimetext);
   14.65 -            Message(const Message& second);
   14.66 -            Message(message *msg);
   14.67 -            ~Message();
   14.68 -            operator message *();
   14.69 -            operator const message *() const;
   14.70 -
   14.71 -            string _str();
   14.72 -            string _repr();
   14.73 -
   14.74 -            PEP_msg_direction dir() { return _msg->dir; }
   14.75 -            void dir(PEP_msg_direction value) { _msg->dir = value; }
   14.76 -
   14.77 -            string id() { return str_attr(_msg->id); }
   14.78 -            void id(string value) { str_attr(_msg->id, value); }
   14.79 -
   14.80 -            string shortmsg() { return str_attr(_msg->shortmsg); }
   14.81 -            void shortmsg(string value) { str_attr(_msg->shortmsg, value); }
   14.82 -
   14.83 -            string longmsg() { return str_attr(_msg->longmsg); }
   14.84 -            void longmsg(string value) { str_attr(_msg->longmsg, value); }
   14.85 -
   14.86 -            string longmsg_formatted() { return str_attr(_msg->longmsg_formatted); }
   14.87 -            void longmsg_formatted(string value) { str_attr(_msg->longmsg_formatted, value); }
   14.88 -
   14.89 -            boost::python::tuple attachments();
   14.90 -            void attachments(boost::python::list value);
   14.91 -
   14.92 -            time_t sent() { return timestamp_attr(_msg->sent); }
   14.93 -            void sent(time_t value) { timestamp_attr(_msg->sent, value); }
   14.94 -
   14.95 -            time_t recv() { return timestamp_attr(_msg->recv); }
   14.96 -            void recv(time_t value) { timestamp_attr(_msg->recv, value); }
   14.97 -
   14.98 -            Identity from() { return identity_attr(_msg->from); }
   14.99 -            void from(object value) { identity_attr(_msg->from, value); }
  14.100 -
  14.101 -            boost::python::list to() { return identitylist_attr(_msg->to); }
  14.102 -            void to(boost::python::list value) { identitylist_attr(_msg->to, value); }
  14.103 -
  14.104 -            Identity recv_by() { return identity_attr(_msg->recv_by); }
  14.105 -            void recv_by(object value) { identity_attr(_msg->recv_by, value); }
  14.106 -
  14.107 -            boost::python::list cc() { return identitylist_attr(_msg->cc); }
  14.108 -            void cc(boost::python::list value) { identitylist_attr(_msg->cc, value); }
  14.109 -
  14.110 -            boost::python::list bcc() { return identitylist_attr(_msg->bcc); }
  14.111 -            void bcc(boost::python::list value) { identitylist_attr(_msg->bcc, value); }
  14.112 -
  14.113 -            boost::python::list reply_to() { return identitylist_attr(_msg->reply_to); }
  14.114 -            void reply_to(boost::python::list value) { identitylist_attr(_msg->reply_to, value); }
  14.115 -
  14.116 -            boost::python::list in_reply_to() { return strlist_attr(_msg->in_reply_to); }
  14.117 -            void in_reply_to(boost::python::list value) { strlist_attr(_msg->in_reply_to, value); }
  14.118 -
  14.119 -            boost::python::list references() { return strlist_attr(_msg->references); }
  14.120 -            void references(boost::python::list value) { strlist_attr(_msg->references, value); }
  14.121 -
  14.122 -            boost::python::list keywords() { return strlist_attr(_msg->keywords); }
  14.123 -            void keywords(boost::python::list value) { strlist_attr(_msg->keywords, value); }
  14.124 -
  14.125 -            string comments() { return str_attr(_msg->comments); }
  14.126 -            void comments(string value) { str_attr(_msg->comments, value); }
  14.127 -
  14.128 -            dict opt_fields() { return strdict_attr(_msg->opt_fields); }
  14.129 -            void opt_fields(dict value) { return strdict_attr(_msg->opt_fields, value); }
  14.130 -
  14.131 -            PEP_enc_format enc_format() { return _msg->enc_format; }
  14.132 -            void enc_format(PEP_enc_format value) { _msg->enc_format = value; }
  14.133 -
  14.134 -            Message encrypt();
  14.135 -            Message _encrypt(boost::python::list extra, int enc_format=4, int flags=0);
  14.136 -
  14.137 -            boost::python::tuple decrypt(int flags=0);
  14.138 -            PEP_rating outgoing_rating();
  14.139 -            PEP_color outgoing_color();
  14.140 -            Message deepcopy(dict& memo);
  14.141 -            Message copy();
  14.142 -        };
  14.143 -
  14.144 -        Message outgoing_message(Identity me);
  14.145 -        Message incoming_message(string mime_text);
  14.146 -    }
  14.147 -}
  14.148 -
    15.1 --- a/src/message_api.cc	Fri May 15 23:11:13 2020 +0200
    15.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.3 @@ -1,167 +0,0 @@
    15.4 -// This file is under GNU Affero General Public License 3.0
    15.5 -// see LICENSE.txt
    15.6 -
    15.7 -#include "message_api.hh"
    15.8 -#include "basic_api.hh"
    15.9 -#include <pEp/pEpEngine.h>
   15.10 -#include <pEp/message_api.h>
   15.11 -#include <pEp/sync_api.h>
   15.12 -#include <pEp/sync_codec.h>
   15.13 -#include <pEp/distribution_codec.h>
   15.14 -
   15.15 -namespace pEp {
   15.16 -    namespace PythonAdapter {
   15.17 -        Message encrypt_message(Message src, boost::python::list extra, int enc_format,
   15.18 -                int flags)
   15.19 -        {
   15.20 -            Identity _from = src.from();
   15.21 -            if (_from.address() == "")
   15.22 -                throw invalid_argument("encrypt_message: src.from_.address empty");
   15.23 -            if (_from.username() == "")
   15.24 -                throw invalid_argument("encrypt_message: src.from_.username empty");
   15.25 -
   15.26 -            if (_from.user_id() == "")
   15.27 -                src.from().user_id(_from.address());
   15.28 -
   15.29 -            stringlist_t *_extra = to_stringlist(extra);
   15.30 -            PEP_enc_format _enc_format = (PEP_enc_format) enc_format;
   15.31 -            PEP_encrypt_flags_t _flags = (PEP_encrypt_flags_t) flags;
   15.32 -            message *_dst = NULL;
   15.33 -
   15.34 -            message *_src = src;
   15.35 -            PEP_STATUS status = encrypt_message(adapter.session(), _src, _extra, &_dst,
   15.36 -                    _enc_format, _flags);
   15.37 -            free_stringlist(_extra);
   15.38 -            _throw_status(status);
   15.39 -
   15.40 -            if (!_dst || _dst == _src)
   15.41 -                return Message(_src);
   15.42 -
   15.43 -            return Message(_dst);
   15.44 -        }
   15.45 -
   15.46 -        boost::python::tuple decrypt_message(Message src, int flags)
   15.47 -        {
   15.48 -            message *_dst = NULL;
   15.49 -            stringlist_t *_keylist = NULL;
   15.50 -            PEP_rating _rating = PEP_rating_undefined;
   15.51 -            PEP_decrypt_flags_t _flags = (PEP_decrypt_flags_t) flags;
   15.52 -            message *_src = src;
   15.53 -
   15.54 -            PEP_STATUS status = ::decrypt_message(adapter.session(), _src, &_dst, &_keylist,
   15.55 -                    &_rating, &_flags);
   15.56 -            _throw_status(status);
   15.57 -
   15.58 -            boost::python::list keylist;
   15.59 -            if (_keylist) {
   15.60 -                keylist = from_stringlist(_keylist);
   15.61 -                free_stringlist(_keylist);
   15.62 -            }
   15.63 -
   15.64 -            Message dst = _dst ? Message(_dst) : Message(src);
   15.65 -            return boost::python::make_tuple(dst, keylist, _rating, _flags);
   15.66 -        }
   15.67 -
   15.68 -        PEP_color _color(int rating)
   15.69 -        {
   15.70 -            return ::color_from_rating((PEP_rating) rating);
   15.71 -        }
   15.72 -
   15.73 -        boost::python::tuple sync_decode(object buffer)
   15.74 -        {
   15.75 -            Py_buffer src;
   15.76 -            int result = PyObject_GetBuffer(buffer.ptr(), &src, PyBUF_CONTIG_RO);
   15.77 -            if (result)
   15.78 -                throw invalid_argument("need a contiguous buffer to read");
   15.79 -
   15.80 -            char *dst = NULL;
   15.81 -            PEP_STATUS status = PER_to_XER_Sync_msg((char *) src.buf, src.len, &dst);
   15.82 -            PyBuffer_Release(&src);
   15.83 -            _throw_status(status);
   15.84 -
   15.85 -            string _dst(dst);
   15.86 -            free(dst);
   15.87 -            return boost::python::make_tuple(_dst, 0);
   15.88 -        }
   15.89 -
   15.90 -        static boost::python::tuple sync_encode(string text)
   15.91 -        {
   15.92 -            char *data = NULL;
   15.93 -            size_t size = 0;
   15.94 -            PEP_STATUS status = XER_to_PER_Sync_msg(text.c_str(), &data, &size);
   15.95 -            _throw_status(status);
   15.96 -
   15.97 -            PyObject *ba = PyBytes_FromStringAndSize(data, size);
   15.98 -            free(data);
   15.99 -            if (!ba)
  15.100 -                throw bad_alloc();
  15.101 -
  15.102 -            return boost::python::make_tuple(object(handle<>(ba)), 0);
  15.103 -        }
  15.104 -
  15.105 -        boost::python::tuple Distribution_decode(object buffer)
  15.106 -        {
  15.107 -            Py_buffer src;
  15.108 -            int result = PyObject_GetBuffer(buffer.ptr(), &src, PyBUF_CONTIG_RO);
  15.109 -            if (result)
  15.110 -                throw invalid_argument("need a contiguous buffer to read");
  15.111 -
  15.112 -            char *dst = NULL;
  15.113 -            PEP_STATUS status = PER_to_XER_Distribution_msg((char *) src.buf, src.len, &dst);
  15.114 -            PyBuffer_Release(&src);
  15.115 -            _throw_status(status);
  15.116 -
  15.117 -            string _dst(dst);
  15.118 -            free(dst);
  15.119 -            return boost::python::make_tuple(_dst, 0);
  15.120 -        }
  15.121 -
  15.122 -        static boost::python::tuple Distribution_encode(string text)
  15.123 -        {
  15.124 -            char *data = NULL;
  15.125 -            size_t size = 0;
  15.126 -            PEP_STATUS status = XER_to_PER_Distribution_msg(text.c_str(), &data, &size);
  15.127 -            _throw_status(status);
  15.128 -
  15.129 -            PyObject *ba = PyBytes_FromStringAndSize(data, size);
  15.130 -            free(data);
  15.131 -            if (!ba)
  15.132 -                throw bad_alloc();
  15.133 -
  15.134 -            return boost::python::make_tuple(object(handle<>(ba)), 0);
  15.135 -        }
  15.136 -
  15.137 -        object sync_search(string name)
  15.138 -        {
  15.139 -            if (name != "pep.sync") {
  15.140 -                return object();
  15.141 -            }
  15.142 -            else {
  15.143 -                object codecs = import("codecs");
  15.144 -                object CodecInfo = codecs.attr("CodecInfo");
  15.145 -
  15.146 -                object _sync_decode = make_function(sync_decode);
  15.147 -                object _sync_encode = make_function(sync_encode);
  15.148 -
  15.149 -                return call< object >(CodecInfo.ptr(), _sync_encode, _sync_decode);
  15.150 -            }
  15.151 -        }
  15.152 -
  15.153 -        object distribution_search(string name)
  15.154 -        {
  15.155 -            if (name != "pep.distribution") {
  15.156 -                return object();
  15.157 -            }
  15.158 -            else {
  15.159 -                object codecs = import("codecs");
  15.160 -                object CodecInfo = codecs.attr("CodecInfo");
  15.161 -
  15.162 -                object _distribution_decode = make_function(Distribution_decode);
  15.163 -                object _distribution_encode = make_function(Distribution_encode);
  15.164 -
  15.165 -                return call< object >(CodecInfo.ptr(), _distribution_encode, _distribution_decode);
  15.166 -            }
  15.167 -        }
  15.168 -
  15.169 -    }
  15.170 -}
    16.1 --- a/src/message_api.hh	Fri May 15 23:11:13 2020 +0200
    16.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.3 @@ -1,17 +0,0 @@
    16.4 -// This file is under GNU Affero General Public License 3.0
    16.5 -// see LICENSE.txt
    16.6 -
    16.7 -#pragma once
    16.8 -
    16.9 -#include "pEpmodule.hh"
   16.10 -
   16.11 -namespace pEp {
   16.12 -    namespace PythonAdapter {
   16.13 -        Message encrypt_message(Message src, boost::python::list extra = boost::python::list(),
   16.14 -                int enc_format = 4, int flags = 0);
   16.15 -        boost::python::tuple decrypt_message(Message src, int flags=0);
   16.16 -        PEP_color _color(int rating);
   16.17 -        object sync_search(string name);
   16.18 -        object distribution_search(string name);
   16.19 -    }
   16.20 -}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/pEp/__init__.py	Thu Aug 27 00:15:34 2020 +0200
    17.3 @@ -0,0 +1,52 @@
    17.4 +# pEp package
    17.5 +# This file is being exectued upon 'import pEp'
    17.6 +#
    17.7 +# __all__ could be used to limit the symbols exported when using from <pkg> import *
    17.8 +
    17.9 +
   17.10 +# Import all symbols EXCEPT the ones beginning with underscore into the current namespace
   17.11 +from native_pEp import *
   17.12 +# TODO: inter-pkg ref to make sure which native_pEp in sys.path gets loaded
   17.13 +# like: pEp.native_pEp
   17.14 +# import the module
   17.15 +import native_pEp
   17.16 +
   17.17 +# Executed on module import
   17.18 +def init():
   17.19 +    print(init, "called")
   17.20 +    native_pEp._init_after_main_module()
   17.21 +
   17.22 +
   17.23 +def message_to_send(msg):
   17.24 +    """
   17.25 +    message_to_send(msg)
   17.26 +    override pEp.message_to_send(msg) with your own implementation
   17.27 +    this callback is being called when a p≡p management message needs to be sent
   17.28 +    GIL CAVEAT
   17.29 +    """
   17.30 +    print("message_to_send() - default callback\n")
   17.31 +    print("overwrite this method")
   17.32 +
   17.33 +
   17.34 +def notify_handshake(me, partner, signal):
   17.35 +    """
   17.36 +    notifyHandshake(self, me, partner)
   17.37 +        me              own identity
   17.38 +        partner         identity of communication partner
   17.39 +        signal          the handshake signal
   17.40 +    overwrite this method with an implementation of a handshake dialog
   17.41 +    GIL CAVEAT
   17.42 +    """
   17.43 +    print("message_to_send() - default callback\n")
   17.44 +    print("overwrite this method")
   17.45 +
   17.46 +
   17.47 +# Executed when run as script
   17.48 +def main():
   17.49 +    print("I am being run as a script")
   17.50 +
   17.51 +# MAIN
   17.52 +if __name__ == "__main__":
   17.53 +    main()
   17.54 +else:
   17.55 +    init()
   17.56 \ No newline at end of file
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/src/pEp/native_pEp/basic_api.cc	Thu Aug 27 00:15:34 2020 +0200
    18.3 @@ -0,0 +1,172 @@
    18.4 +// This file is under GNU Affero General Public License 3.0
    18.5 +// see LICENSE.txt
    18.6 +
    18.7 +// System
    18.8 +#include <sstream>
    18.9 +
   18.10 +// Engine
   18.11 +#include <pEp/keymanagement.h>
   18.12 +#include <pEp/message_api.h>
   18.13 +#include <pEp/Adapter.hh>
   18.14 +
   18.15 +// local
   18.16 +#include "basic_api.hh"
   18.17 +
   18.18 +namespace pEp {
   18.19 +namespace PythonAdapter {
   18.20 +using namespace std;
   18.21 +
   18.22 +void update_identity(Identity& ident)
   18.23 +{
   18.24 +    if (ident.address() == "")
   18.25 +        throw invalid_argument("address needed");
   18.26 +    if (ident.user_id() == PEP_OWN_USERID)
   18.27 +        throw runtime_error("update_identity: '" PEP_OWN_USERID
   18.28 +                "' may only be used for own identities");
   18.29 +
   18.30 +    PEP_STATUS status = update_identity(Adapter::session(), ident);
   18.31 +    _throw_status(status);
   18.32 +}
   18.33 +
   18.34 +void myself(Identity& ident)
   18.35 +{
   18.36 +    if (ident.address() == "")
   18.37 +        throw invalid_argument("address needed");
   18.38 +    if (ident.username() == "")
   18.39 +        throw invalid_argument("username needed");
   18.40 +
   18.41 +    if (ident.user_id() == "")
   18.42 +        ident.user_id(ident.address());
   18.43 +
   18.44 +    PEP_STATUS status = myself(Adapter::session(), ident);
   18.45 +    _throw_status(status);
   18.46 +}
   18.47 +
   18.48 +string _trustwords(Identity me, Identity partner, string lang, bool full)
   18.49 +{
   18.50 +    if (me.fpr() == "" || partner.fpr() == "")
   18.51 +        throw invalid_argument("fingerprint needed in Identities");
   18.52 +
   18.53 +    if (lang == "" && me.lang() == partner.lang())
   18.54 +        lang = me.lang();
   18.55 +
   18.56 +    char *words = NULL;
   18.57 +    size_t size = 0;
   18.58 +    PEP_STATUS status =  get_trustwords(Adapter::session(), me, partner,
   18.59 +                                lang.c_str(),&words, &size, full);
   18.60 +    _throw_status(status);
   18.61 +    return words;
   18.62 +}
   18.63 +
   18.64 +void trust_personal_key(Identity ident)
   18.65 +{
   18.66 +    if (ident.fpr() == "")
   18.67 +        throw invalid_argument("fingerprint needed in Identities");
   18.68 +    if (ident.user_id() == "")
   18.69 +        throw invalid_argument("user_id must be provided");
   18.70 +
   18.71 +    PEP_STATUS status = trust_personal_key(Adapter::session(), ident);
   18.72 +    _throw_status(status);
   18.73 +}
   18.74 +
   18.75 +void set_identity_flags(Identity ident, identity_flags_t flags)
   18.76 +{
   18.77 +    if (ident.address() == "")
   18.78 +        throw invalid_argument("address needed");
   18.79 +    if (ident.user_id() == "")
   18.80 +        throw invalid_argument("user_id needed");
   18.81 +
   18.82 +    PEP_STATUS status = set_identity_flags(Adapter::session(), ident, flags);
   18.83 +    _throw_status(status);
   18.84 +}
   18.85 +
   18.86 +void unset_identity_flags(Identity ident, identity_flags_t flags)
   18.87 +{
   18.88 +    if (ident.address() == "")
   18.89 +        throw invalid_argument("address needed");
   18.90 +    if (ident.user_id() == "")
   18.91 +        throw invalid_argument("user_id needed");
   18.92 +
   18.93 +    PEP_STATUS status = unset_identity_flags(Adapter::session(), ident, flags);
   18.94 +    _throw_status(status);
   18.95 +}
   18.96 +
   18.97 +void key_reset_trust(Identity ident)
   18.98 +{
   18.99 +    if (ident.fpr() == "")
  18.100 +        throw invalid_argument("fpr needed");
  18.101 +    if (ident.address() == "")
  18.102 +        throw invalid_argument("address needed");
  18.103 +    if (ident.user_id() == "")
  18.104 +        throw invalid_argument("user_id needed");
  18.105 +
  18.106 +    PEP_STATUS status = key_reset_trust(Adapter::session(), ident);
  18.107 +    _throw_status(status);
  18.108 +}
  18.109 +
  18.110 +
  18.111 +
  18.112 +boost::python::list import_key(string key_data)
  18.113 +{
  18.114 +    ::identity_list *private_keys = NULL;
  18.115 +    PEP_STATUS status = ::import_key(Adapter::session(), key_data.c_str(), key_data.size(), &private_keys);
  18.116 +    if (status && status != PEP_KEY_IMPORTED)
  18.117 +        _throw_status(status);
  18.118 +
  18.119 +    auto result = boost::python::list();
  18.120 +    for (::identity_list *il = private_keys; il && il->ident; il=il->next) {
  18.121 +        ::pEp_identity *ident = ::identity_dup(il->ident);
  18.122 +        if (!ident) {
  18.123 +            free_identity_list(private_keys);
  18.124 +            throw bad_alloc();
  18.125 +        }
  18.126 +        result.append(Identity(ident));
  18.127 +    }
  18.128 +
  18.129 +    free_identity_list(private_keys);
  18.130 +    return result;
  18.131 +}
  18.132 +
  18.133 +string export_key(Identity ident)
  18.134 +{
  18.135 +    PEP_STATUS status = PEP_STATUS_OK;
  18.136 +    char* key_data = NULL;
  18.137 +    size_t size;
  18.138 +    status = ::export_key(Adapter::session(), ident.fpr().c_str(), &key_data, &size);
  18.139 +
  18.140 +    _throw_status(status);
  18.141 +    return key_data;
  18.142 +}
  18.143 +
  18.144 +string export_secret_key(Identity ident)
  18.145 +{
  18.146 +    PEP_STATUS status = PEP_STATUS_OK;
  18.147 +    char* key_data = NULL;
  18.148 +    size_t size;
  18.149 +    status = ::export_secret_key(Adapter::session(), ident.fpr().c_str(), &key_data, &size);
  18.150 +
  18.151 +    _throw_status(status);
  18.152 +    return key_data;
  18.153 +}
  18.154 +
  18.155 +void set_own_key(Identity& ident, string fpr)
  18.156 +{
  18.157 +    if (ident.address() == "")
  18.158 +        throw invalid_argument("address needed");
  18.159 +    if (ident.username() == "")
  18.160 +        throw invalid_argument("username needed");
  18.161 +    if (ident.user_id() == "")
  18.162 +        throw invalid_argument("user_id needed");
  18.163 +    if (fpr == "")
  18.164 +        throw invalid_argument("fpr needed");
  18.165 +
  18.166 +
  18.167 +    const char* fpr_c = fpr.c_str();
  18.168 +    PEP_STATUS status = set_own_key(Adapter::session(), ident, fpr_c);
  18.169 +    _throw_status(status);
  18.170 +}
  18.171 +
  18.172 +} // namespace PythonAdapter
  18.173 +} // namespace pEp {
  18.174 +
  18.175 +
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/src/pEp/native_pEp/basic_api.hh	Thu Aug 27 00:15:34 2020 +0200
    19.3 @@ -0,0 +1,30 @@
    19.4 +// This file is under GNU Affero General Public License 3.0
    19.5 +// see LICENSE.txt
    19.6 +
    19.7 +#ifndef BASIC_API_HH
    19.8 +#define BASIC_API_HH
    19.9 +
   19.10 +#include "pEpmodule.hh"
   19.11 +
   19.12 +namespace pEp {
   19.13 +namespace PythonAdapter {
   19.14 +
   19.15 +void update_identity(Identity& ident);
   19.16 +void myself(Identity& ident);
   19.17 +string _trustwords(Identity me, Identity partner, string lang, bool full);
   19.18 +void trust_personal_key(Identity ident);
   19.19 +
   19.20 +void set_identity_flags(Identity ident, identity_flags_t flags);
   19.21 +void unset_identity_flags(Identity ident, identity_flags_t flags);
   19.22 +
   19.23 +void key_reset_trust(Identity ident);
   19.24 +
   19.25 +boost::python::list import_key(string key_data);
   19.26 +string export_key(Identity ident);
   19.27 +string export_secret_key(Identity ident);
   19.28 +void set_own_key(Identity& ident, string fpr);
   19.29 +
   19.30 +} /* namespace PythonAdapter */
   19.31 +} /* namespace pEp */
   19.32 +
   19.33 +#endif /* BASIC_API_HH */
   19.34 \ No newline at end of file
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/src/pEp/native_pEp/identity.cc	Thu Aug 27 00:15:34 2020 +0200
    20.3 @@ -0,0 +1,285 @@
    20.4 +// This file is under GNU Affero General Public License 3.0
    20.5 +// see LICENSE.txt
    20.6 +
    20.7 +// System
    20.8 +#include <typeinfo>
    20.9 +#include <sstream>
   20.10 +
   20.11 +// Engine
   20.12 +#include <pEp/identity_list.h>
   20.13 +#include <pEp/keymanagement.h>
   20.14 +#include <pEp/key_reset.h>
   20.15 +
   20.16 +// local
   20.17 +#include "identity.hh"
   20.18 +#include "pEpmodule.hh"
   20.19 +#include "basic_api.hh"
   20.20 +#include "message_api.hh"
   20.21 +
   20.22 +namespace pEp {
   20.23 +namespace PythonAdapter {
   20.24 +using namespace std;
   20.25 +using namespace boost::python;
   20.26 +
   20.27 +Identity::Identity(string address, string username, string user_id,
   20.28 +        string fpr, int comm_type, string lang, identity_flags_t flags)
   20.29 +    : _ident(new_identity(address.c_str(), fpr.c_str(), user_id.c_str(),
   20.30 +                username.c_str()), &::free_identity)
   20.31 +{
   20.32 +    if (!_ident)
   20.33 +        throw bad_alloc();
   20.34 +    _ident->comm_type = (PEP_comm_type) comm_type;
   20.35 +    _ident->flags = (identity_flags_t) flags;
   20.36 +    this->lang(lang);
   20.37 +}
   20.38 +
   20.39 +Identity::Identity(const Identity& second)
   20.40 +    : _ident(second._ident)
   20.41 +{
   20.42 +
   20.43 +}
   20.44 +
   20.45 +Identity::Identity(pEp_identity *ident)
   20.46 +    : _ident(ident, &::free_identity)
   20.47 +{
   20.48 +
   20.49 +}
   20.50 +
   20.51 +Identity::~Identity()
   20.52 +{
   20.53 +
   20.54 +}
   20.55 +
   20.56 +Identity::operator pEp_identity *()
   20.57 +{
   20.58 +    return _ident.get();
   20.59 +}
   20.60 +
   20.61 +Identity::operator const pEp_identity *() const
   20.62 +{
   20.63 +    return _ident.get();
   20.64 +}
   20.65 +
   20.66 +string Identity::_repr()
   20.67 +{
   20.68 +    stringstream build;
   20.69 +    build << "Identity(";
   20.70 +    string address;
   20.71 +    if (_ident->address)
   20.72 +        address = string(_ident->address);
   20.73 +    build << repr(address) << ", ";
   20.74 +    string username;
   20.75 +    if (_ident->username)
   20.76 +        username = string(_ident->username);
   20.77 +    build << repr(username) << ", ";
   20.78 +    string user_id;
   20.79 +    if (_ident->user_id)
   20.80 +        user_id = string(_ident->user_id);
   20.81 +    build << repr(user_id) << ", ";
   20.82 +    string fpr;
   20.83 +    if (_ident->fpr)
   20.84 +        fpr = string(_ident->fpr);
   20.85 +    build << repr(fpr) << ", ";
   20.86 +    build << (int) _ident->comm_type << ", ";
   20.87 +    string lang = _ident->lang;
   20.88 +    build << repr(lang) << ")";
   20.89 +    return build.str();
   20.90 +}
   20.91 +
   20.92 +string Identity::_str()
   20.93 +{
   20.94 +    if (!(_ident->address && _ident->address[0]))
   20.95 +        return "";
   20.96 +    if (!(_ident->username && _ident->username[0]))
   20.97 +        return _ident->address;
   20.98 +    return string(_ident->username) + " <" + _ident->address + ">";
   20.99 +}
  20.100 +
  20.101 +void Identity::username(string value)
  20.102 +{
  20.103 +    if (value.length() && value.length() < 5)
  20.104 +        throw length_error("username must be at least 5 characters");
  20.105 +
  20.106 +    str_attr(_ident->username, value);
  20.107 +}
  20.108 +
  20.109 +void Identity::lang(string value)
  20.110 +{
  20.111 +    if (value == "")
  20.112 +        memset(_ident->lang, 0, 3);
  20.113 +    else if (value.length() != 2)
  20.114 +        throw length_error("length of lang must be 2");
  20.115 +    else
  20.116 +        memcpy(_ident->lang, value.c_str(), 3);
  20.117 +}
  20.118 +
  20.119 +string Identity::lang()
  20.120 +{
  20.121 +    return _ident->lang;
  20.122 +}
  20.123 +
  20.124 +int Identity::rating()
  20.125 +{
  20.126 +    if (!(_ident->address))
  20.127 +        throw invalid_argument("address must be given");
  20.128 +
  20.129 +    PEP_rating rating = PEP_rating_undefined;
  20.130 +    PEP_STATUS status = ::identity_rating(Adapter::session(), _ident.get(), &rating);
  20.131 +    _throw_status(status);
  20.132 +
  20.133 +    return (int) rating;
  20.134 +}
  20.135 +
  20.136 +PEP_color Identity::color()
  20.137 +{
  20.138 +    return _color(rating());
  20.139 +}
  20.140 +
  20.141 +Identity Identity::copy()
  20.142 +{
  20.143 +    pEp_identity *dup = ::identity_dup(*this);
  20.144 +    if (!dup)
  20.145 +        throw bad_alloc();
  20.146 +
  20.147 +    return Identity(dup);
  20.148 +}
  20.149 +
  20.150 +Identity Identity::deepcopy(dict&)
  20.151 +{
  20.152 +    return copy();
  20.153 +}
  20.154 +
  20.155 +void Identity::update()
  20.156 +{
  20.157 +    update_identity(*this);
  20.158 +}
  20.159 +
  20.160 +void Identity::key_reset(string fpr)
  20.161 +{
  20.162 +    PEP_STATUS status = ::key_reset_identity(Adapter::session(), *this,
  20.163 +            fpr != "" ? fpr.c_str() : nullptr);
  20.164 +    _throw_status(status);
  20.165 +}
  20.166 +
  20.167 +void Identity::key_mistrusted()
  20.168 +{
  20.169 +    PEP_STATUS status = ::key_mistrusted(Adapter::session(), *this);
  20.170 +    _throw_status(status);
  20.171 +}
  20.172 +
  20.173 +bool Identity::is_pEp_user()
  20.174 +{
  20.175 +    bool result;
  20.176 +    PEP_STATUS status = ::is_pEp_user(Adapter::session(), *this, &result);
  20.177 +    _throw_status(status);
  20.178 +    return result;
  20.179 +}
  20.180 +
  20.181 +void Identity::enable_for_sync()
  20.182 +{
  20.183 +    PEP_STATUS status = ::enable_identity_for_sync(Adapter::session(), *this);
  20.184 +    _throw_status(status);
  20.185 +}
  20.186 +
  20.187 +void Identity::disable_for_sync()
  20.188 +{
  20.189 +    PEP_STATUS status = ::disable_identity_for_sync(Adapter::session(), *this);
  20.190 +    _throw_status(status);
  20.191 +}
  20.192 +
  20.193 +Myself::Myself(string address, string username, string user_id, string lang)
  20.194 +    : Identity(address, username, user_id, "", 0, lang)
  20.195 +
  20.196 +{
  20.197 +    if (!(address.length() && username.length()))
  20.198 +        throw invalid_argument("address and username must be set");
  20.199 +    if (lang.length() && lang.length() != 2)
  20.200 +        throw length_error("lang must be an ISO 639-1 language code or empty");
  20.201 +
  20.202 +    // FIXME: should set .me
  20.203 +    // _ident->me = true;
  20.204 +    if (user_id.length())
  20.205 +        throw runtime_error("user_id feature not yet implemented for Myself");
  20.206 +}
  20.207 +
  20.208 +void Myself::update()
  20.209 +{
  20.210 +    pEp::PythonAdapter::myself(*this);
  20.211 +}
  20.212 +
  20.213 +Identity identity_attr(pEp_identity *&ident)
  20.214 +{
  20.215 +    if (!ident)
  20.216 +        throw out_of_range("no identity assigned");
  20.217 +
  20.218 +    pEp_identity *_dup = identity_dup(ident);
  20.219 +    if (!_dup)
  20.220 +        throw bad_alloc();
  20.221 +
  20.222 +    Identity _ident(_dup);
  20.223 +    return _ident;
  20.224 +}
  20.225 +
  20.226 +void identity_attr(pEp_identity *&ident, object value)
  20.227 +{
  20.228 +    Identity& _ident = extract< Identity& >(value);
  20.229 +    pEp_identity *_dup = ::identity_dup(_ident);
  20.230 +    if (!_dup)
  20.231 +        throw bad_alloc();
  20.232 +    PEP_STATUS status = update_identity(Adapter::session(), _dup);
  20.233 +    _throw_status(status);
  20.234 +    free_identity(ident);
  20.235 +    ident = _dup;
  20.236 +}
  20.237 +
  20.238 +boost::python::list identitylist_attr(identity_list *&il)
  20.239 +{
  20.240 +    boost::python::list result;
  20.241 +
  20.242 +    for (identity_list *_il = il; _il && _il->ident; _il = _il->next) {
  20.243 +        pEp_identity *ident = ::identity_dup(_il->ident);
  20.244 +        if (!ident)
  20.245 +            throw bad_alloc();
  20.246 +        result.append(object(Identity(ident)));
  20.247 +    }
  20.248 +
  20.249 +    return result;
  20.250 +}
  20.251 +
  20.252 +void identitylist_attr(identity_list *&il, boost::python::list value)
  20.253 +{
  20.254 +    identity_list *_il = new_identity_list(NULL);
  20.255 +    if (!_il)
  20.256 +        throw bad_alloc();
  20.257 +
  20.258 +    identity_list *_i = _il;
  20.259 +    for (int i=0; i<len(value); i++) {
  20.260 +        extract< Identity& > extract_identity(value[i]);
  20.261 +        if (!extract_identity.check()) {
  20.262 +            free_identity_list(_il);
  20.263 +        }
  20.264 +        pEp_identity *_ident = extract_identity();
  20.265 +        pEp_identity *_dup = ::identity_dup(_ident);
  20.266 +        if (!_dup) {
  20.267 +            free_identity_list(_il);
  20.268 +            throw bad_alloc();
  20.269 +        }
  20.270 +        PEP_STATUS status = update_identity(Adapter::session(), _dup);
  20.271 +        if (status != PEP_STATUS_OK) {
  20.272 +            free_identity_list(_il);
  20.273 +            _throw_status(status);
  20.274 +        }
  20.275 +        _i = identity_list_add(_i, _dup);
  20.276 +        if (!_i) {
  20.277 +            free_identity_list(_il);
  20.278 +            throw bad_alloc();
  20.279 +        }
  20.280 +    }
  20.281 +
  20.282 +    free_identity_list(il);
  20.283 +    il = _il;
  20.284 +}
  20.285 +
  20.286 +} // namespace PythonAdapter
  20.287 +} // namespace pEp {
  20.288 +
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/src/pEp/native_pEp/identity.hh	Thu Aug 27 00:15:34 2020 +0200
    21.3 @@ -0,0 +1,102 @@
    21.4 +// This file is under GNU Affero General Public License 3.0
    21.5 +// see LICENSE.txt
    21.6 +
    21.7 +#ifndef IDENTITY_HH
    21.8 +#define IDENTITY_HH
    21.9 +
   21.10 +// System
   21.11 +#include <boost/python.hpp>
   21.12 +#include <string>
   21.13 +#include <memory>
   21.14 +#include <cstddef>
   21.15 +
   21.16 +// Engine
   21.17 +#include <pEp/pEpEngine.h>
   21.18 +#include <pEp/message_api.h>
   21.19 +
   21.20 +//libpEpAdapter
   21.21 +#include "pEp/Adapter.hh"
   21.22 +
   21.23 +// local
   21.24 +#include "str_attr.hh"
   21.25 +
   21.26 +namespace pEp {
   21.27 +namespace PythonAdapter {
   21.28 +
   21.29 +using std::string;
   21.30 +using std::shared_ptr;
   21.31 +
   21.32 +// Identity is owning a pEp_identity
   21.33 +
   21.34 +class Identity {
   21.35 +protected:
   21.36 +    shared_ptr< pEp_identity > _ident;
   21.37 +
   21.38 +public:
   21.39 +    Identity(string address = "", string username = "",
   21.40 +            string user_id = "", string fpr = "", int comm_type = 0,
   21.41 +            string lang = "", identity_flags_t flags = 0);
   21.42 +
   21.43 +    Identity(const Identity& second);
   21.44 +    Identity(pEp_identity *ident);
   21.45 +    virtual ~Identity();
   21.46 +    operator pEp_identity *();
   21.47 +    operator const pEp_identity *() const;
   21.48 +
   21.49 +    string _repr();
   21.50 +    string _str();
   21.51 +
   21.52 +    string address() { return str_attr(_ident->address); }
   21.53 +    void address(string value) { str_attr(_ident->address, value); }
   21.54 +
   21.55 +    string fpr() { return str_attr(_ident->fpr); }
   21.56 +    void fpr(string value) { str_attr(_ident->fpr, value); }
   21.57 +
   21.58 +    string user_id() { return str_attr(_ident->user_id); }
   21.59 +    void user_id(string value) { str_attr(_ident->user_id, value); }
   21.60 +
   21.61 +    string username() { return str_attr(_ident->username); }
   21.62 +    void username(string value);
   21.63 +
   21.64 +    PEP_comm_type comm_type() { return _ident->comm_type; }
   21.65 +    void comm_type(PEP_comm_type value) { _ident->comm_type = value; };
   21.66 +
   21.67 +    std::string lang();
   21.68 +    void lang(std::string value);
   21.69 +
   21.70 +    identity_flags_t flags() { return _ident->flags; }
   21.71 +    void flags(identity_flags_t flags) { _ident->flags = flags; }
   21.72 +
   21.73 +    int rating();
   21.74 +    PEP_color color();
   21.75 +
   21.76 +    Identity copy();
   21.77 +    Identity deepcopy(dict& memo);
   21.78 +
   21.79 +    virtual void update();
   21.80 +
   21.81 +    void key_reset(string fpr="");
   21.82 +    void key_mistrusted();
   21.83 +
   21.84 +    bool is_pEp_user();
   21.85 +
   21.86 +    void enable_for_sync();
   21.87 +    void disable_for_sync();
   21.88 +};
   21.89 +
   21.90 +class Myself : public Identity {
   21.91 +public:
   21.92 +    Myself(string address, string username, string user_id="", string lang="");
   21.93 +    virtual void update();
   21.94 +};
   21.95 +
   21.96 +Identity identity_attr(pEp_identity *&ident);
   21.97 +void identity_attr(pEp_identity *&ident, object value);
   21.98 +
   21.99 +boost::python::list identitylist_attr(identity_list *&il);
  21.100 +void identitylist_attr(identity_list *&il, boost::python::list value);
  21.101 +
  21.102 +} /* namespace PythonAdapter */
  21.103 +} /* namespace pEp */
  21.104 +
  21.105 +#endif /* IDENTITY_HH */
  21.106 \ No newline at end of file
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/src/pEp/native_pEp/message.cc	Thu Aug 27 00:15:34 2020 +0200
    22.3 @@ -0,0 +1,413 @@
    22.4 +// This file is under GNU Affero General Public License 3.0
    22.5 +// see LICENSE.txt
    22.6 +
    22.7 +// System
    22.8 +#include <cstdlib>
    22.9 +#include <cstring>
   22.10 +#include <stdexcept>
   22.11 +#include <sstream>
   22.12 +#include <vector>
   22.13 +#include <Python.h>
   22.14 +
   22.15 +// Engine
   22.16 +#include <pEp/mime.h>
   22.17 +#include <pEp/keymanagement.h>
   22.18 +#include <pEp/message_api.h>
   22.19 +
   22.20 +// local
   22.21 +#include "message.hh"
   22.22 +#include "message_api.hh"
   22.23 +
   22.24 +namespace pEp {
   22.25 +namespace PythonAdapter {
   22.26 +using namespace std;
   22.27 +using namespace boost::python;
   22.28 +
   22.29 +Message::Blob::Blob(bloblist_t *bl, bool chained) :
   22.30 +    _bl(bl), part_of_chain(chained)
   22.31 +{
   22.32 +    if (!_bl)
   22.33 +        throw bad_alloc();
   22.34 +}
   22.35 +
   22.36 +Message::Blob::Blob(object data, string mime_type, string filename) :
   22.37 +    _bl(new_bloblist(NULL, 0, NULL, NULL)), part_of_chain(false)
   22.38 +{
   22.39 +    if (!_bl)
   22.40 +        throw bad_alloc();
   22.41 +
   22.42 +    Py_buffer src;
   22.43 +    int result = PyObject_GetBuffer(data.ptr(), &src, PyBUF_CONTIG_RO);
   22.44 +    if (result)
   22.45 +        throw invalid_argument("need a contiguous buffer to read");
   22.46 +
   22.47 +    char *mem = (char *)malloc(src.len);
   22.48 +    if (!mem) {
   22.49 +        PyBuffer_Release(&src);
   22.50 +        throw bad_alloc();
   22.51 +    }
   22.52 +
   22.53 +    memcpy(mem, src.buf, src.len);
   22.54 +    free(_bl->value);
   22.55 +    _bl->size = src.len;
   22.56 +    _bl->value = mem;
   22.57 +
   22.58 +    PyBuffer_Release(&src);
   22.59 +
   22.60 +    this->mime_type(mime_type);
   22.61 +    this->filename(filename);
   22.62 +}
   22.63 +
   22.64 +Message::Blob::Blob(const Message::Blob& second) :
   22.65 +    _bl(second._bl), part_of_chain(true)
   22.66 +{
   22.67 +
   22.68 +}
   22.69 +
   22.70 +Message::Blob::~Blob()
   22.71 +{
   22.72 +    if (!part_of_chain) {
   22.73 +        free(_bl->value);
   22.74 +        free(_bl);
   22.75 +    }
   22.76 +}
   22.77 +
   22.78 +string Message::Blob::_repr()
   22.79 +{
   22.80 +    stringstream build;
   22.81 +    build << "Blob(";
   22.82 +    if (!_bl) {
   22.83 +        build << "b'', '', ''";
   22.84 +    }
   22.85 +    else {
   22.86 +        build << "bytes(" << _bl->size << "), ";
   22.87 +        string mime_type;
   22.88 +        if (_bl->mime_type)
   22.89 +            mime_type = string(_bl->mime_type);
   22.90 +        string filename;
   22.91 +        if (_bl->filename)
   22.92 +            filename = string(_bl->filename);
   22.93 +        build << repr(mime_type) << ", ";
   22.94 +        build << repr(filename);
   22.95 +    }
   22.96 +    build << ")";
   22.97 +    return build.str();
   22.98 +}
   22.99 +
  22.100 +int Message::Blob::getbuffer(PyObject *self, Py_buffer *view, int flags) {
  22.101 +    bloblist_t *bl = NULL;
  22.102 +
  22.103 +    try {
  22.104 +        Message::Blob& blob = extract< Message::Blob& >(self);
  22.105 +        bl = blob._bl;
  22.106 +    }
  22.107 +    catch (exception& e) {
  22.108 +        PyErr_SetString(PyExc_RuntimeError, "extract not possible");
  22.109 +        view->obj = NULL;
  22.110 +        return -1;
  22.111 +    }
  22.112 +
  22.113 +    if (!(bl && bl->value)) {
  22.114 +        PyErr_SetString(PyExc_RuntimeError, "no data available");
  22.115 +        view->obj = NULL;
  22.116 +        return -1;
  22.117 +    }
  22.118 +
  22.119 +    return PyBuffer_FillInfo(view, self, bl->value, bl->size, 0, flags);
  22.120 +}
  22.121 +
  22.122 +string Message::Blob::decode(string encoding)
  22.123 +{
  22.124 +    if (encoding == "") {
  22.125 +        string _mime_type = _bl->mime_type ? _bl->mime_type : "";
  22.126 +        encoding = "ascii";
  22.127 +
  22.128 +        if (_mime_type == "application/pEp.sync")
  22.129 +            encoding = "pep.sync";
  22.130 +
  22.131 +        if (_mime_type == "application/pEp.keyreset")
  22.132 +            encoding = "pep.distribution";
  22.133 +
  22.134 +    }
  22.135 +    object codecs = import("codecs");
  22.136 +    object _decode = codecs.attr("decode");
  22.137 +    return call< string >(_decode.ptr(), this, encoding);
  22.138 +}
  22.139 +
  22.140 +PyBufferProcs Message::Blob::bp = { getbuffer, NULL };
  22.141 +
  22.142 +Message::Message(int dir, Identity *from)
  22.143 +    : _msg(new_message((PEP_msg_direction) dir), &free_message)
  22.144 +{
  22.145 +    if (!_msg)
  22.146 +        throw bad_alloc();
  22.147 +
  22.148 +    if (from) {
  22.149 +        _msg->from = ::identity_dup(*from);
  22.150 +        if (!_msg->from)
  22.151 +            throw bad_alloc();
  22.152 +        _msg->dir = (PEP_msg_direction) dir;
  22.153 +    }
  22.154 +}
  22.155 +
  22.156 +Message::Message(string mimetext)
  22.157 +    : _msg(NULL, &free_message)
  22.158 +{
  22.159 +    message *_cpy;
  22.160 +    PEP_STATUS status = mime_decode_message(mimetext.c_str(),
  22.161 +            mimetext.size(), &_cpy, NULL);
  22.162 +    switch (status) {
  22.163 +        case PEP_STATUS_OK:
  22.164 +            if (_cpy)
  22.165 +                _cpy->dir = PEP_dir_outgoing;
  22.166 +            else
  22.167 +                _cpy = new_message(PEP_dir_outgoing);
  22.168 +
  22.169 +            if (!_cpy)
  22.170 +                throw bad_alloc();
  22.171 +
  22.172 +            _msg = shared_ptr< message >(_cpy);
  22.173 +            break;
  22.174 +
  22.175 +        case PEP_BUFFER_TOO_SMALL:
  22.176 +            throw runtime_error("mime_decode_message: buffer too small");
  22.177 +
  22.178 +        case PEP_CANNOT_CREATE_TEMP_FILE:
  22.179 +            throw runtime_error("mime_decode_message: cannot create temp file");
  22.180 +
  22.181 +        case PEP_OUT_OF_MEMORY:
  22.182 +            throw bad_alloc();
  22.183 +
  22.184 +        default:
  22.185 +            stringstream build;
  22.186 +            build << "mime_decode_message: unknown error (" << (int) status << ")";
  22.187 +            throw runtime_error(build.str());
  22.188 +    }
  22.189 +}
  22.190 +
  22.191 +Message::Message(const Message& second)
  22.192 +    : _msg(second._msg)
  22.193 +{
  22.194 +    if (!_msg.get())
  22.195 +        throw bad_alloc();
  22.196 +}
  22.197 +
  22.198 +Message::Message(message *msg)
  22.199 +    : _msg(::message_dup(msg), &free_message)
  22.200 +{
  22.201 +
  22.202 +}
  22.203 +
  22.204 +Message::~Message()
  22.205 +{
  22.206 +
  22.207 +}
  22.208 +
  22.209 +Message::operator message *()
  22.210 +{
  22.211 +    return _msg.get();
  22.212 +}
  22.213 +
  22.214 +Message::operator const message *() const
  22.215 +{
  22.216 +    return _msg.get();
  22.217 +}
  22.218 +
  22.219 +string Message::_str()
  22.220 +{
  22.221 +    if (!(_msg->from && _msg->from->address && _msg->from->address[0]))
  22.222 +        throw out_of_range(".from_.address missing");
  22.223 +
  22.224 +    char *mimetext;
  22.225 +    string result;
  22.226 +
  22.227 +    PEP_STATUS status = mime_encode_message(*this, false, &mimetext, false);
  22.228 +    switch (status) {
  22.229 +        case PEP_STATUS_OK:
  22.230 +            result = mimetext;
  22.231 +            free(mimetext);
  22.232 +            break;
  22.233 +
  22.234 +        case PEP_BUFFER_TOO_SMALL:
  22.235 +            throw runtime_error("mime_encode_message: buffer too small");
  22.236 +
  22.237 +        case PEP_CANNOT_CREATE_TEMP_FILE:
  22.238 +            throw runtime_error("mime_encode_message: cannot create temp file");
  22.239 +
  22.240 +        case PEP_OUT_OF_MEMORY:
  22.241 +            throw bad_alloc();
  22.242 +
  22.243 +        default:
  22.244 +            stringstream build;
  22.245 +            build << "mime_encode_message: unknown error (" << (int) status << ")";
  22.246 +            throw runtime_error(build.str());
  22.247 +    }
  22.248 +
  22.249 +    return result;
  22.250 +}
  22.251 +
  22.252 +string Message::_repr()
  22.253 +{
  22.254 +    stringstream build;
  22.255 +    build << "Message(" << repr(_str()) << ")";
  22.256 +    return build.str();
  22.257 +}
  22.258 +
  22.259 +boost::python::tuple Message::attachments()
  22.260 +{
  22.261 +    boost::python::list l;
  22.262 +
  22.263 +    for (bloblist_t *bl = _msg->attachments; bl && bl->value; bl =
  22.264 +            bl->next) {
  22.265 +        l.append(Blob(bl, true));
  22.266 +    }
  22.267 +
  22.268 +    return boost::python::tuple(l);
  22.269 +}
  22.270 +
  22.271 +void Message::attachments(boost::python::list value)
  22.272 +{
  22.273 +    bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL);
  22.274 +    if (!bl)
  22.275 +        throw bad_alloc();
  22.276 +
  22.277 +    bloblist_t *_l = bl;
  22.278 +    for (int i=0; i<len(value); i++) {
  22.279 +        Message::Blob& blob = extract< Message::Blob& >(value[i]);
  22.280 +        _l = bloblist_add(_l, blob._bl->value, blob._bl->size,
  22.281 +                blob._bl->mime_type, blob._bl->filename);
  22.282 +        if (!_l) {
  22.283 +            for (_l = bl; _l && _l->value; ) {
  22.284 +                free(_l->mime_type);
  22.285 +                free(_l->filename);
  22.286 +                bloblist_t *_ll = _l;
  22.287 +                _l = _l->next;
  22.288 +                free(_ll);
  22.289 +            }
  22.290 +            throw bad_alloc();
  22.291 +        }
  22.292 +    }
  22.293 +
  22.294 +    for (int i=0; i<len(value); i++) {
  22.295 +        Message::Blob& blob = extract< Message::Blob& >(value[i]);
  22.296 +        blob._bl->value = NULL;
  22.297 +        blob._bl->size = 0;
  22.298 +        free(blob._bl->mime_type);
  22.299 +        blob._bl->mime_type = NULL;
  22.300 +        free(blob._bl->filename);
  22.301 +        blob._bl->filename = NULL;
  22.302 +    }
  22.303 +
  22.304 +    free_bloblist(_msg->attachments);
  22.305 +    _msg->attachments = bl;
  22.306 +}
  22.307 +
  22.308 +Message Message::encrypt()
  22.309 +{
  22.310 +    boost::python::list extra;
  22.311 +    return encrypt_message(*this, extra, PEP_enc_PGP_MIME, 0);
  22.312 +}
  22.313 +
  22.314 +Message Message::_encrypt(boost::python::list extra, int enc_format, int flags)
  22.315 +{
  22.316 +    if (!enc_format)
  22.317 +        enc_format = PEP_enc_PGP_MIME;
  22.318 +    return encrypt_message(*this, extra, enc_format, flags);
  22.319 +}
  22.320 +
  22.321 +boost::python::tuple Message::decrypt(int flags) {
  22.322 +    return pEp::PythonAdapter::decrypt_message(*this, flags);
  22.323 +}
  22.324 +
  22.325 +PEP_rating Message::outgoing_rating()
  22.326 +{
  22.327 +    if (_msg->dir != PEP_dir_outgoing)
  22.328 +        throw invalid_argument("Message.dir must be outgoing");
  22.329 +
  22.330 +    if (from().address() == "")
  22.331 +        throw invalid_argument("from.address needed");
  22.332 +    if (from().username() == "")
  22.333 +        throw invalid_argument("from.username needed");
  22.334 +
  22.335 +    if (len(to()) + len(cc()) == 0)
  22.336 +        throw invalid_argument("either to or cc needed");
  22.337 +
  22.338 +    PEP_STATUS status = myself(Adapter::session(), _msg->from);
  22.339 +    _throw_status(status);
  22.340 +
  22.341 +    PEP_rating rating = PEP_rating_undefined;
  22.342 +    status = outgoing_message_rating(Adapter::session(), *this, &rating);
  22.343 +    _throw_status(status);
  22.344 +
  22.345 +    return rating;
  22.346 +}
  22.347 +
  22.348 +PEP_color Message::outgoing_color()
  22.349 +{
  22.350 +    return _color(outgoing_rating());
  22.351 +}
  22.352 +
  22.353 +Message Message::copy()
  22.354 +{
  22.355 +    message *dup = message_dup(*this);
  22.356 +    if (!dup)
  22.357 +        throw bad_alloc();
  22.358 +    return Message(dup);
  22.359 +}
  22.360 +
  22.361 +Message Message::deepcopy(dict&)
  22.362 +{
  22.363 +    return copy();
  22.364 +}
  22.365 +
  22.366 +Message outgoing_message(Identity me)
  22.367 +{
  22.368 +    if (me.address().empty() || me.user_id().empty())
  22.369 +        throw runtime_error("at least address and user_id of own user needed");
  22.370 +
  22.371 +    ::myself(Adapter::session(), me);
  22.372 +    auto m = Message(PEP_dir_outgoing, &me);
  22.373 +    return m;
  22.374 +}
  22.375 +
  22.376 +static object update(Identity ident)
  22.377 +{
  22.378 +    if (ident.address().empty())
  22.379 +        throw runtime_error("at least address needed");
  22.380 +    update_identity(Adapter::session(), ident);
  22.381 +    return object(ident);
  22.382 +}
  22.383 +
  22.384 +static boost::python::list update(boost::python::list il)
  22.385 +{
  22.386 +    for (int i=0; i<len(il); i++) {
  22.387 +        update(extract< Identity >(il[i]));
  22.388 +    }
  22.389 +
  22.390 +    return il;
  22.391 +}
  22.392 +
  22.393 +Message incoming_message(string mime_text)
  22.394 +{
  22.395 +    auto m = Message(mime_text);
  22.396 +    m.dir(PEP_dir_incoming);
  22.397 +
  22.398 +    try {
  22.399 +        m.from(update(m.from()));
  22.400 +    }
  22.401 +    catch (out_of_range&) { }
  22.402 +
  22.403 +    try {
  22.404 +        m.recv_by(update(m.recv_by()));
  22.405 +    }
  22.406 +    catch (out_of_range&) { }
  22.407 +
  22.408 +    m.to(update(m.to()));
  22.409 +    m.cc(update(m.cc()));
  22.410 +    m.reply_to(update(m.reply_to()));
  22.411 +
  22.412 +    return m;
  22.413 +}
  22.414 +
  22.415 +} // namespace PythonAdapter
  22.416 +} // namespace pEp {
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/src/pEp/native_pEp/message.hh	Thu Aug 27 00:15:34 2020 +0200
    23.3 @@ -0,0 +1,154 @@
    23.4 +// This file is under GNU Affero General Public License 3.0
    23.5 +// see LICENSE.txt
    23.6 +
    23.7 +#ifndef MESSAGE_HH
    23.8 +#define MESSAGE_HH
    23.9 +
   23.10 +// System
   23.11 +#include <string>
   23.12 +#include <boost/python.hpp>
   23.13 +#include <boost/lexical_cast.hpp>
   23.14 +
   23.15 +// Engine
   23.16 +#include <pEp/message.h>
   23.17 +#include <pEp/message_api.h>
   23.18 +
   23.19 +// local
   23.20 +#include "str_attr.hh"
   23.21 +#include "identity.hh"
   23.22 +
   23.23 +namespace pEp {
   23.24 +namespace PythonAdapter {
   23.25 +using std::string;
   23.26 +using std::runtime_error;
   23.27 +using std::invalid_argument;
   23.28 +using boost::lexical_cast;
   23.29 +
   23.30 +// Message is owning a message struct
   23.31 +
   23.32 +class Message {
   23.33 +    shared_ptr< ::message > _msg;
   23.34 +
   23.35 +public:
   23.36 +    // Blob is owning a bloblist_t struct - or not and just managing
   23.37 +    // one depending on part_of_chain
   23.38 +
   23.39 +    class Blob {
   23.40 +        bloblist_t *_bl;
   23.41 +        bool part_of_chain;
   23.42 +
   23.43 +    public:
   23.44 +        Blob(bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL),
   23.45 +                bool chained = false);
   23.46 +        Blob(object data, string mime_type = "", string filename = "");
   23.47 +        Blob(const Blob& second);
   23.48 +        ~Blob();
   23.49 +
   23.50 +        string _repr();
   23.51 +
   23.52 +        string mime_type() { return _bl ? str_attr(_bl->mime_type) : ""; }
   23.53 +        void mime_type(string value) { str_attr(_bl->mime_type, value); }
   23.54 +
   23.55 +        string filename() { return str_attr(_bl->filename); }
   23.56 +        void filename(string value) { str_attr(_bl->filename, value); }
   23.57 +
   23.58 +        size_t size() { return _bl->size; }
   23.59 +        string decode(string encoding);
   23.60 +        string decode() { return decode(""); }
   23.61 +
   23.62 +        static PyBufferProcs bp;
   23.63 +
   23.64 +        friend class Message;
   23.65 +
   23.66 +    protected:
   23.67 +        static int getbuffer(PyObject *self, Py_buffer *view, int flags);
   23.68 +    };
   23.69 +
   23.70 +    Message(int dir = PEP_dir_outgoing, Identity *from = NULL);
   23.71 +    Message(string mimetext);
   23.72 +    Message(const Message& second);
   23.73 +    Message(message *msg);
   23.74 +    ~Message();
   23.75 +    operator message *();
   23.76 +    operator const message *() const;
   23.77 +
   23.78 +    string _str();
   23.79 +    string _repr();
   23.80 +
   23.81 +    PEP_msg_direction dir() { return _msg->dir; }
   23.82 +    void dir(PEP_msg_direction value) { _msg->dir = value; }
   23.83 +
   23.84 +    string id() { return str_attr(_msg->id); }
   23.85 +    void id(string value) { str_attr(_msg->id, value); }
   23.86 +
   23.87 +    string shortmsg() { return str_attr(_msg->shortmsg); }
   23.88 +    void shortmsg(string value) { str_attr(_msg->shortmsg, value); }
   23.89 +
   23.90 +    string longmsg() { return str_attr(_msg->longmsg); }
   23.91 +    void longmsg(string value) { str_attr(_msg->longmsg, value); }
   23.92 +
   23.93 +    string longmsg_formatted() { return str_attr(_msg->longmsg_formatted); }
   23.94 +    void longmsg_formatted(string value) { str_attr(_msg->longmsg_formatted, value); }
   23.95 +
   23.96 +    boost::python::tuple attachments();
   23.97 +    void attachments(boost::python::list value);
   23.98 +
   23.99 +    time_t sent() { return timestamp_attr(_msg->sent); }
  23.100 +    void sent(time_t value) { timestamp_attr(_msg->sent, value); }
  23.101 +
  23.102 +    time_t recv() { return timestamp_attr(_msg->recv); }
  23.103 +    void recv(time_t value) { timestamp_attr(_msg->recv, value); }
  23.104 +
  23.105 +    Identity from() { return identity_attr(_msg->from); }
  23.106 +    void from(object value) { identity_attr(_msg->from, value); }
  23.107 +
  23.108 +    boost::python::list to() { return identitylist_attr(_msg->to); }
  23.109 +    void to(boost::python::list value) { identitylist_attr(_msg->to, value); }
  23.110 +
  23.111 +    Identity recv_by() { return identity_attr(_msg->recv_by); }
  23.112 +    void recv_by(object value) { identity_attr(_msg->recv_by, value); }
  23.113 +
  23.114 +    boost::python::list cc() { return identitylist_attr(_msg->cc); }
  23.115 +    void cc(boost::python::list value) { identitylist_attr(_msg->cc, value); }
  23.116 +
  23.117 +    boost::python::list bcc() { return identitylist_attr(_msg->bcc); }
  23.118 +    void bcc(boost::python::list value) { identitylist_attr(_msg->bcc, value); }
  23.119 +
  23.120 +    boost::python::list reply_to() { return identitylist_attr(_msg->reply_to); }
  23.121 +    void reply_to(boost::python::list value) { identitylist_attr(_msg->reply_to, value); }
  23.122 +
  23.123 +    boost::python::list in_reply_to() { return strlist_attr(_msg->in_reply_to); }
  23.124 +    void in_reply_to(boost::python::list value) { strlist_attr(_msg->in_reply_to, value); }
  23.125 +
  23.126 +    boost::python::list references() { return strlist_attr(_msg->references); }
  23.127 +    void references(boost::python::list value) { strlist_attr(_msg->references, value); }
  23.128 +
  23.129 +    boost::python::list keywords() { return strlist_attr(_msg->keywords); }
  23.130 +    void keywords(boost::python::list value) { strlist_attr(_msg->keywords, value); }
  23.131 +
  23.132 +    string comments() { return str_attr(_msg->comments); }
  23.133 +    void comments(string value) { str_attr(_msg->comments, value); }
  23.134 +
  23.135 +    dict opt_fields() { return strdict_attr(_msg->opt_fields); }
  23.136 +    void opt_fields(dict value) { return strdict_attr(_msg->opt_fields, value); }
  23.137 +
  23.138 +    PEP_enc_format enc_format() { return _msg->enc_format; }
  23.139 +    void enc_format(PEP_enc_format value) { _msg->enc_format = value; }
  23.140 +
  23.141 +    Message encrypt();
  23.142 +    Message _encrypt(boost::python::list extra, int enc_format=4, int flags=0);
  23.143 +
  23.144 +    boost::python::tuple decrypt(int flags=0);
  23.145 +    PEP_rating outgoing_rating();
  23.146 +    PEP_color outgoing_color();
  23.147 +    Message deepcopy(dict& memo);
  23.148 +    Message copy();
  23.149 +};
  23.150 +
  23.151 +Message outgoing_message(Identity me);
  23.152 +Message incoming_message(string mime_text);
  23.153 +
  23.154 +} /* namespace PythonAdapter */
  23.155 +} /* namespace pEp */
  23.156 +
  23.157 +#endif /* MESSAGE_HH */
  23.158 \ No newline at end of file
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/src/pEp/native_pEp/message_api.cc	Thu Aug 27 00:15:34 2020 +0200
    24.3 @@ -0,0 +1,172 @@
    24.4 +// This file is under GNU Affero General Public License 3.0
    24.5 +// see LICENSE.txt
    24.6 +
    24.7 +// Engine
    24.8 +#include <pEp/pEpEngine.h>
    24.9 +#include <pEp/message_api.h>
   24.10 +#include <pEp/sync_api.h>
   24.11 +#include <pEp/sync_codec.h>
   24.12 +#include <pEp/distribution_codec.h>
   24.13 +
   24.14 +// local
   24.15 +#include "message_api.hh"
   24.16 +#include "basic_api.hh"
   24.17 +
   24.18 +namespace pEp {
   24.19 +namespace PythonAdapter {
   24.20 +using namespace std;
   24.21 +using namespace boost::python;
   24.22 +
   24.23 +Message encrypt_message(Message src, boost::python::list extra, int enc_format, int flags)
   24.24 +{
   24.25 +    Identity _from = src.from();
   24.26 +    if (_from.address() == "")
   24.27 +        throw invalid_argument("encrypt_message: src.from_.address empty");
   24.28 +    if (_from.username() == "")
   24.29 +        throw invalid_argument("encrypt_message: src.from_.username empty");
   24.30 +
   24.31 +    if (_from.user_id() == "")
   24.32 +        src.from().user_id(_from.address());
   24.33 +
   24.34 +    stringlist_t *_extra = to_stringlist(extra);
   24.35 +    PEP_enc_format _enc_format = (PEP_enc_format) enc_format;
   24.36 +    PEP_encrypt_flags_t _flags = (PEP_encrypt_flags_t) flags;
   24.37 +    message *_dst = NULL;
   24.38 +
   24.39 +    message *_src = src;
   24.40 +    PEP_STATUS status = encrypt_message(Adapter::session(), _src, _extra, &_dst,
   24.41 +            _enc_format, _flags);
   24.42 +    free_stringlist(_extra);
   24.43 +    _throw_status(status);
   24.44 +
   24.45 +    if (!_dst || _dst == _src)
   24.46 +        return Message(_src);
   24.47 +
   24.48 +    return Message(_dst);
   24.49 +}
   24.50 +
   24.51 +boost::python::tuple decrypt_message(Message src, int flags)
   24.52 +{
   24.53 +    message *_dst = NULL;
   24.54 +    stringlist_t *_keylist = NULL;
   24.55 +    PEP_rating _rating = PEP_rating_undefined;
   24.56 +    PEP_decrypt_flags_t _flags = (PEP_decrypt_flags_t) flags;
   24.57 +    message *_src = src;
   24.58 +
   24.59 +    PEP_STATUS status = ::decrypt_message(Adapter::session(), _src, &_dst, &_keylist,
   24.60 +            &_rating, &_flags);
   24.61 +    _throw_status(status);
   24.62 +
   24.63 +    boost::python::list keylist;
   24.64 +    if (_keylist) {
   24.65 +        keylist = from_stringlist(_keylist);
   24.66 +        free_stringlist(_keylist);
   24.67 +    }
   24.68 +
   24.69 +    Message dst = _dst ? Message(_dst) : Message(src);
   24.70 +    return boost::python::make_tuple(dst, keylist, _rating, _flags);
   24.71 +}
   24.72 +
   24.73 +PEP_color _color(int rating)
   24.74 +{
   24.75 +    return ::color_from_rating((PEP_rating) rating);
   24.76 +}
   24.77 +
   24.78 +boost::python::tuple sync_decode(object buffer)
   24.79 +{
   24.80 +    Py_buffer src;
   24.81 +    int result = PyObject_GetBuffer(buffer.ptr(), &src, PyBUF_CONTIG_RO);
   24.82 +    if (result)
   24.83 +        throw invalid_argument("need a contiguous buffer to read");
   24.84 +
   24.85 +    char *dst = NULL;
   24.86 +    PEP_STATUS status = PER_to_XER_Sync_msg((char *) src.buf, src.len, &dst);
   24.87 +    PyBuffer_Release(&src);
   24.88 +    _throw_status(status);
   24.89 +
   24.90 +    string _dst(dst);
   24.91 +    free(dst);
   24.92 +    return boost::python::make_tuple(_dst, 0);
   24.93 +}
   24.94 +
   24.95 +static boost::python::tuple sync_encode(string text)
   24.96 +{
   24.97 +    char *data = NULL;
   24.98 +    size_t size = 0;
   24.99 +    PEP_STATUS status = XER_to_PER_Sync_msg(text.c_str(), &data, &size);
  24.100 +    _throw_status(status);
  24.101 +
  24.102 +    PyObject *ba = PyBytes_FromStringAndSize(data, size);
  24.103 +    free(data);
  24.104 +    if (!ba)
  24.105 +        throw bad_alloc();
  24.106 +
  24.107 +    return boost::python::make_tuple(object(handle<>(ba)), 0);
  24.108 +}
  24.109 +
  24.110 +boost::python::tuple Distribution_decode(object buffer)
  24.111 +{
  24.112 +    Py_buffer src;
  24.113 +    int result = PyObject_GetBuffer(buffer.ptr(), &src, PyBUF_CONTIG_RO);
  24.114 +    if (result)
  24.115 +        throw invalid_argument("need a contiguous buffer to read");
  24.116 +
  24.117 +    char *dst = NULL;
  24.118 +    PEP_STATUS status = PER_to_XER_Distribution_msg((char *) src.buf, src.len, &dst);
  24.119 +    PyBuffer_Release(&src);
  24.120 +    _throw_status(status);
  24.121 +
  24.122 +    string _dst(dst);
  24.123 +    free(dst);
  24.124 +    return boost::python::make_tuple(_dst, 0);
  24.125 +}
  24.126 +
  24.127 +static boost::python::tuple Distribution_encode(string text)
  24.128 +{
  24.129 +    char *data = NULL;
  24.130 +    size_t size = 0;
  24.131 +    PEP_STATUS status = XER_to_PER_Distribution_msg(text.c_str(), &data, &size);
  24.132 +    _throw_status(status);
  24.133 +
  24.134 +    PyObject *ba = PyBytes_FromStringAndSize(data, size);
  24.135 +    free(data);
  24.136 +    if (!ba)
  24.137 +        throw bad_alloc();
  24.138 +
  24.139 +    return boost::python::make_tuple(object(handle<>(ba)), 0);
  24.140 +}
  24.141 +
  24.142 +object sync_search(string name)
  24.143 +{
  24.144 +    if (name != "pep.sync") {
  24.145 +        return object();
  24.146 +    }
  24.147 +    else {
  24.148 +        object codecs = import("codecs");
  24.149 +        object CodecInfo = codecs.attr("CodecInfo");
  24.150 +
  24.151 +        object _sync_decode = make_function(sync_decode);
  24.152 +        object _sync_encode = make_function(sync_encode);
  24.153 +
  24.154 +        return call< object >(CodecInfo.ptr(), _sync_encode, _sync_decode);
  24.155 +    }
  24.156 +}
  24.157 +
  24.158 +object distribution_search(string name)
  24.159 +{
  24.160 +    if (name != "pep.distribution") {
  24.161 +        return object();
  24.162 +    }
  24.163 +    else {
  24.164 +        object codecs = import("codecs");
  24.165 +        object CodecInfo = codecs.attr("CodecInfo");
  24.166 +
  24.167 +        object _distribution_decode = make_function(Distribution_decode);
  24.168 +        object _distribution_encode = make_function(Distribution_encode);
  24.169 +
  24.170 +        return call< object >(CodecInfo.ptr(), _distribution_encode, _distribution_decode);
  24.171 +    }
  24.172 +}
  24.173 +
  24.174 +} // namespace PythonAdapter
  24.175 +} // namespace pEp {
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/src/pEp/native_pEp/message_api.hh	Thu Aug 27 00:15:34 2020 +0200
    25.3 @@ -0,0 +1,27 @@
    25.4 +// This file is under GNU Affero General Public License 3.0
    25.5 +// see LICENSE.txt
    25.6 +
    25.7 +#ifndef MESSAGE_API_HH
    25.8 +#define MESSAGE_API_HH
    25.9 +
   25.10 +#include "pEpmodule.hh"
   25.11 +
   25.12 +namespace pEp {
   25.13 +namespace PythonAdapter {
   25.14 +
   25.15 +Message encrypt_message(
   25.16 +    Message src,
   25.17 +    boost::python::list extra = boost::python::list(),
   25.18 +    int enc_format = 4,
   25.19 +    int flags = 0
   25.20 +);
   25.21 +
   25.22 +boost::python::tuple decrypt_message(Message src, int flags=0);
   25.23 +PEP_color _color(int rating);
   25.24 +object sync_search(string name);
   25.25 +object distribution_search(string name);
   25.26 +
   25.27 +} /* namespace PythonAdapter */
   25.28 +} /* namespace pEp */
   25.29 +
   25.30 +#endif /* MESSAGE_API_HH */
   25.31 \ No newline at end of file
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/pEp/native_pEp/pEpmodule.cc	Thu Aug 27 00:15:34 2020 +0200
    26.3 @@ -0,0 +1,673 @@
    26.4 +// This file is under GNU Affero General Public License 3.0
    26.5 +// see LICENSE.txt
    26.6 +
    26.7 +// System
    26.8 +#include <boost/python.hpp>
    26.9 +#include <boost/locale.hpp>
   26.10 +#include <string>
   26.11 +#include <sstream>
   26.12 +#include <iomanip>
   26.13 +#include <mutex>
   26.14 +
   26.15 +// Engine
   26.16 +#include <pEp/key_reset.h>
   26.17 +#include <pEp/message_api.h>
   26.18 +#include <pEp/sync_api.h>
   26.19 +#include <pEp/status_to_string.h>
   26.20 +
   26.21 +// libpEpAdapter
   26.22 +#include <pEp/Adapter.hh>
   26.23 +#include <pEp/callback_dispatcher.hh>
   26.24 +#include <pEp/pEpLog.hh>
   26.25 +
   26.26 +// local
   26.27 +#include "pEpmodule.hh"
   26.28 +#include "basic_api.hh"
   26.29 +#include "message_api.hh"
   26.30 +//#include "user_interface.hh"
   26.31 +
   26.32 +namespace pEp {
   26.33 +namespace PythonAdapter {
   26.34 +using namespace std;
   26.35 +using namespace boost::python;
   26.36 +
   26.37 +static const char *version_string = "p≡p Python adapter version 0.3";
   26.38 +
   26.39 +void init_before_main_module() {
   26.40 +    pEpLog("called");
   26.41 +}
   26.42 +
   26.43 +// hidden init function, wrapped by hello_world.init()
   26.44 +void _init_after_main_module() {
   26.45 +    pEpLog("called");
   26.46 +    callback_dispatcher.add(_messageToSend, notifyHandshake, nullptr, nullptr);
   26.47 +    Adapter::_messageToSend = CallbackDispatcher::messageToSend;
   26.48 +}
   26.49 +
   26.50 +
   26.51 +void config_passive_mode(bool enable)
   26.52 +{
   26.53 +    ::config_passive_mode(Adapter::session(), enable);
   26.54 +}
   26.55 +
   26.56 +void config_unencrypted_subject(bool enable)
   26.57 +{
   26.58 +    ::config_unencrypted_subject(Adapter::session(), enable);
   26.59 +}
   26.60 +
   26.61 +void key_reset_user(string user_id, string fpr)
   26.62 +{
   26.63 +    if (user_id == "")
   26.64 +        throw invalid_argument("user_id required");
   26.65 +
   26.66 +    PEP_STATUS status = ::key_reset_user(Adapter::session(),
   26.67 +            user_id.c_str(), fpr != "" ?  fpr.c_str() : nullptr);
   26.68 +    _throw_status(status);
   26.69 +}
   26.70 +
   26.71 +void key_reset_user2(string user_id)
   26.72 +{
   26.73 +    key_reset_user(user_id, "");
   26.74 +}
   26.75 +
   26.76 +void key_reset_all_own_keys()
   26.77 +{
   26.78 +    PEP_STATUS status = ::key_reset_all_own_keys(Adapter::session());
   26.79 +    _throw_status(status);
   26.80 +}
   26.81 +
   26.82 +static string about()
   26.83 +{
   26.84 +    string version = string(version_string) + "\np≡p version "
   26.85 +        + PEP_VERSION + "\n";
   26.86 +    return version;
   26.87 +}
   26.88 +
   26.89 +void _throw_status(PEP_STATUS status)
   26.90 +{
   26.91 +    if (status == PEP_STATUS_OK)
   26.92 +        return;
   26.93 +    if (status >= 0x400 && status <= 0x4ff)
   26.94 +        return;
   26.95 +    if (status == PEP_OUT_OF_MEMORY)
   26.96 +        throw bad_alloc();
   26.97 +    if (status == PEP_ILLEGAL_VALUE)
   26.98 +        throw invalid_argument("illegal value");
   26.99 +
  26.100 +    if (string(pEp_status_to_string(status)) == "unknown status code") {
  26.101 +        stringstream build;
  26.102 +        build << setfill('0') << "p≡p 0x" << setw(4) << hex << status;
  26.103 +        throw runtime_error(build.str());
  26.104 +    }
  26.105 +    else {
  26.106 +        throw runtime_error(pEp_status_to_string(status));
  26.107 +    }
  26.108 +}
  26.109 +
  26.110 +PEP_STATUS _messageToSend(::message *msg)
  26.111 +{
  26.112 +    pEpLog("called");
  26.113 +    try {
  26.114 +        PyGILState_STATE gil = PyGILState_Ensure();
  26.115 +        pEpLog("GIL Aquired");
  26.116 +        object modref = import("pEp");
  26.117 +        object funcref = modref.attr("message_to_send");
  26.118 +        call<void>(funcref.ptr(), Message());
  26.119 +        PyGILState_Release(gil);
  26.120 +        pEpLog("GIL released");
  26.121 +    } catch (exception& e) { }
  26.122 +
  26.123 +    return PEP_STATUS_OK;
  26.124 +}
  26.125 +
  26.126 +PEP_STATUS notifyHandshake(pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal)
  26.127 +{
  26.128 +    pEpLog("called");
  26.129 +    try {
  26.130 +        PyGILState_STATE gil = PyGILState_Ensure();
  26.131 +        pEpLog("GIL Aquired");
  26.132 +        object modref = import("pEp");
  26.133 +        object funcref = modref.attr("notify_handshake");
  26.134 +        call<void>(funcref.ptr(), me, partner, signal);
  26.135 +        PyGILState_Release(gil);
  26.136 +        pEpLog("GIL released");
  26.137 +    } catch (exception& e) { }
  26.138 +
  26.139 +    return PEP_STATUS_OK;
  26.140 +}
  26.141 +
  26.142 +
  26.143 +void start_sync()
  26.144 +{
  26.145 +    CallbackDispatcher::start_sync();
  26.146 +}
  26.147 +
  26.148 +void shutdown_sync()
  26.149 +{
  26.150 +    CallbackDispatcher::stop_sync();
  26.151 +}
  26.152 +
  26.153 +void debug_color(int ansi_color)
  26.154 +{
  26.155 +    ::set_debug_color(Adapter::session(), ansi_color);
  26.156 +}
  26.157 +
  26.158 +void leave_device_group()
  26.159 +{
  26.160 +    ::leave_device_group(Adapter::session());
  26.161 +}
  26.162 +
  26.163 +bool is_sync_active()
  26.164 +{
  26.165 +    return Adapter::is_sync_running();
  26.166 +}
  26.167 +
  26.168 +void testfunc() {
  26.169 +    _messageToSend(NULL);
  26.170 +}
  26.171 +
  26.172 +void deliverHandshakeResult(int result, object identities)
  26.173 +{
  26.174 +    identity_list *shared_identities = nullptr;
  26.175 +    if (identities != boost::python::api::object() && boost::python::len(identities)) {
  26.176 +        shared_identities = new_identity_list(nullptr);
  26.177 +        if (!shared_identities)
  26.178 +            throw bad_alloc();
  26.179 +
  26.180 +        try {
  26.181 +            identity_list *si = shared_identities;
  26.182 +            for (int i=0; i < boost::python::len(identities); ++i) {
  26.183 +                Identity ident = extract< Identity >(identities[i]);
  26.184 +                si = identity_list_add(si, ident);
  26.185 +                if (!si)
  26.186 +                    throw bad_alloc();
  26.187 +            }
  26.188 +        }
  26.189 +        catch (exception& ex) {
  26.190 +            free_identity_list(shared_identities);
  26.191 +            throw ex;
  26.192 +        }
  26.193 +    }
  26.194 +
  26.195 +    PEP_STATUS status = ::deliverHandshakeResult(Adapter::session(), (sync_handshake_result) result, shared_identities);
  26.196 +    free_identity_list(shared_identities);
  26.197 +    _throw_status(status);
  26.198 +}
  26.199 +
  26.200 +BOOST_PYTHON_MODULE(native_pEp)
  26.201 +{
  26.202 +    init_before_main_module();
  26.203 +
  26.204 +    // Module init function called by pEp.init()
  26.205 +    def("_init_after_main_module", _init_after_main_module);
  26.206 +    def("testfunc", &testfunc);
  26.207 +
  26.208 +    docstring_options doc_options(true, false, false);
  26.209 +    boost::locale::generator gen;
  26.210 +    std::locale::global(gen(""));
  26.211 +
  26.212 +//    _scope = new scope();
  26.213 +    scope().attr("about") = about();
  26.214 +    scope().attr("per_user_directory") = per_user_directory();
  26.215 +    scope().attr("per_machine_directory") = per_machine_directory();
  26.216 +    scope().attr("engine_version") = get_engine_version();
  26.217 +    scope().attr("protocol_version") = get_protocol_version();
  26.218 +
  26.219 +    def("passive_mode", config_passive_mode,
  26.220 +            "do not attach pub keys to all messages");
  26.221 +
  26.222 +    def("unencrypted_subject", config_unencrypted_subject,
  26.223 +            "do not encrypt the subject of messages");
  26.224 +
  26.225 +    def("key_reset", key_reset_user,
  26.226 +            "reset the default database status for the user / keypair provided\n"
  26.227 +            "This will effectively perform key_reset on each identity\n"
  26.228 +            "associated with the key and user_id, if a key is provided, and for\n"
  26.229 +            "each key (and all of their identities) if an fpr is not.");
  26.230 +
  26.231 +    def("key_reset", key_reset_user2,
  26.232 +            "reset the default database status for the user / keypair provided\n"
  26.233 +            "This will effectively perform key_reset on each identity\n"
  26.234 +            "associated with the key and user_id, if a key is provided, and for\n"
  26.235 +            "each key (and all of their identities) if an fpr is not.");
  26.236 +
  26.237 +    def("key_reset_all_own_keys", key_reset_all_own_keys,
  26.238 +            "revoke and mistrust all own keys, generate new keys for all\n"
  26.239 +            "own identities, and opportunistically communicate key reset\n"
  26.240 +            "information to people we have recently contacted.");
  26.241 +
  26.242 +    auto identity_class = class_<Identity>("Identity",
  26.243 +    "Identity(address, username, user_id='', fpr='', comm_type=0, lang='en')\n"
  26.244 +    "\n"
  26.245 +    "represents a p≡p identity\n"
  26.246 +    "\n"
  26.247 +    "an identity is a network address, under which a user is represented in\n"
  26.248 +    "the network\n"
  26.249 +    "\n"
  26.250 +    "   address     network address, either an SMTP address or a URI\n"
  26.251 +    "   username    real name or nickname for user\n"
  26.252 +    "   user_id     ID this user is handled by the application\n"
  26.253 +    "   fpr         full fingerprint of the key being used as key ID,\n"
  26.254 +    "               hex encoded\n"
  26.255 +    "   comm_type   first rating level of this communication channel\n"
  26.256 +    "   lang        ISO 639-1 language code for language being preferred\n"
  26.257 +    "               on this communication channel\n"
  26.258 +        )
  26.259 +        .def(boost::python::init<string>())
  26.260 +        .def(boost::python::init<string, string>())
  26.261 +        .def(boost::python::init<string, string, string>())
  26.262 +        .def(boost::python::init<string, string, string, string>())
  26.263 +        .def(boost::python::init<string, string, string, string, int>())
  26.264 +        .def(boost::python::init<string, string, string, string, int, string>())
  26.265 +        .def("__repr__", &Identity::_repr)
  26.266 +        .def("__str__", &Identity::_str,
  26.267 +            "string representation of this identity\n"
  26.268 +            "following the pattern 'username < address >'\n"
  26.269 +                )
  26.270 +        .def("key_reset", &Identity::key_reset,
  26.271 +                boost::python::arg("fpr")=object(""),
  26.272 +            "reset the default database status for the identity / keypair provided. If this\n"
  26.273 +            "corresponds to the own user and a private key, also revoke the key, generate a\n"
  26.274 +            "new one, and communicate the reset to recently contacted pEp partners for this\n"
  26.275 +            "identity. If it does not, remove the key from the keyring; the key's status is\n"
  26.276 +            "completely fresh on next contact from the partner.")
  26.277 +
  26.278 +        .def("key_mistrusted", &Identity::key_mistrusted,
  26.279 +                boost::python::arg("fpr")=object(""),
  26.280 +            "If you want updated trust on the identity, you ll have"
  26.281 +            "to call update_identity or myself respectively after this."
  26.282 +            "N.B. If you are calling this on a key that is the identity or user default,"
  26.283 +            "it will be removed as the default key for ANY identity and user for which"
  26.284 +            "it is the default. Please keep in mind that the undo in undo_last_mistrust"
  26.285 +            "will only undo the current identity's / it's user's default, not any"
  26.286 +            "other identities which may be impacted (this will not affect most use cases)")
  26.287 +
  26.288 +        .def("enable_for_sync", &Identity::enable_for_sync,
  26.289 +                "Enable own identity for p≡p sync.\n\n"
  26.290 +                "Only use this on own identities, which are used as accounts.\n")
  26.291 +        .def("disable_for_sync", &Identity::disable_for_sync,
  26.292 +                "Disable own identity for p≡p sync.\n\n"
  26.293 +                "Only use this on own identities, which are used as accounts.\n")
  26.294 +
  26.295 +        .add_property("address", (string(Identity::*)()) &Identity::address,
  26.296 +                (void(Identity::*)(string)) &Identity::address,
  26.297 +                "email address or URI")
  26.298 +        .add_property("fpr", (string(Identity::*)()) &Identity::fpr,
  26.299 +                (void(Identity::*)(string)) &Identity::fpr,
  26.300 +                "key ID (full fingerprint, hex encoded)")
  26.301 +        .add_property("user_id", (string(Identity::*)()) &Identity::user_id,
  26.302 +                (void(Identity::*)(string)) &Identity::user_id,
  26.303 +                "ID of person associated or 'pEp_own_userId' if own identity")
  26.304 +        .add_property("username", (string(Identity::*)()) &Identity::username,
  26.305 +                (void(Identity::*)(string)) &Identity::username,
  26.306 +                "name in full of person associated")
  26.307 +        .add_property("comm_type", (int(Identity::*)())
  26.308 +                (PEP_comm_type(Identity::*)()) &Identity::comm_type,
  26.309 +                (void(Identity::*)(int))
  26.310 +                (void(Identity::*)(PEP_comm_type)) &Identity::comm_type,
  26.311 +                 "communication type, first rating level (p≡p internal)")
  26.312 +        .add_property("lang", (string(Identity::*)()) &Identity::lang,
  26.313 +                (void(Identity::*)(string)) &Identity::lang,
  26.314 +                "ISO 639-1 language code")
  26.315 +        .add_property("flags", (identity_flags_t(Identity::*)()) &Identity::flags,
  26.316 +                (void(Identity::*)(identity_flags_t)) &Identity::flags,
  26.317 +                "flags (p≡p internal)")
  26.318 +        .add_property("rating", &Identity::rating, "rating of Identity")
  26.319 +        .add_property("color", &Identity::color, "color of Identity as PEP_color")
  26.320 +        .add_property("is_pEp_user", &Identity::is_pEp_user, "True if this is an identity of a pEp user")
  26.321 +        .def("__deepcopy__", &Identity::deepcopy)
  26.322 +        .def("update", &Identity::update, "update Identity")
  26.323 +        .def("__copy__", &Identity::copy);
  26.324 +
  26.325 +    identity_class.attr("PEP_OWN_USERID") = "pEp_own_userId";
  26.326 +
  26.327 +    auto blob_class = class_<Message::Blob>("Blob",
  26.328 +    "Blob(data, mime_type='', filename='')\n"
  26.329 +    "\n"
  26.330 +    "Binary large object\n"
  26.331 +    "\n"
  26.332 +    "   data            bytes-like object\n"
  26.333 +    "   mime_type       MIME type for the data\n"
  26.334 +    "   filename        filename to store the data\n" ,
  26.335 +            boost::python::init< object, char const*, char const* >(args("data", "mime_type", "filename")))
  26.336 +        .def(boost::python::init<object, string>())
  26.337 +        .def(boost::python::init<object>())
  26.338 +        .def("__repr__", &Message::Blob::_repr)
  26.339 +        .def("__len__", &Message::Blob::size, "size of Blob data in bytes")
  26.340 +        .def("decode", (string(Message::Blob::*)()) &Message::Blob::decode)
  26.341 +        .def("decode", (string(Message::Blob::*)(string)) &Message::Blob::decode,
  26.342 +    "text = blob.decode(encoding='')\n"
  26.343 +    "\n"
  26.344 +    "decode Blob data into string depending on MIME type if encoding=''\n"
  26.345 +    "\n"
  26.346 +    "   mime_type='application/pEp.sync'      decode as 'pEp.sync'\n"
  26.347 +    "   mime_type='application/pEp.keyreset'  decode as 'pEp.keyreset'\n"
  26.348 +    "   other mime_type                       decode as 'ascii' by default\n"
  26.349 +                )
  26.350 +        .add_property("mime_type", (string(Message::Blob::*)()) &Message::Blob::mime_type,
  26.351 +                (void(Message::Blob::*)(string)) &Message::Blob::mime_type,
  26.352 +                "MIME type of object in Blob")
  26.353 +        .add_property("filename", (string(Message::Blob::*)()) &Message::Blob::filename,
  26.354 +                (void(Message::Blob::*)(string)) &Message::Blob::filename,
  26.355 +                "filename of object in Blob");
  26.356 +
  26.357 +    ((PyTypeObject *)(void *)blob_class.ptr())->tp_as_buffer = &Message::Blob::bp;
  26.358 +
  26.359 +    auto message_class = class_<Message>("Message",
  26.360 +    "Message(dir=1, from=None)\n"
  26.361 +    "\n"
  26.362 +    "new p≡p message\n"
  26.363 +    "\n"
  26.364 +    "   dir         1 for outgoing, 2 for incoming\n"
  26.365 +    "   from        Identity() of sender\n"
  26.366 +    "\n"
  26.367 +    "Message(mime_text)\n"
  26.368 +    "\n"
  26.369 +    "new incoming p≡p message\n"
  26.370 +    "\n"
  26.371 +    "   mime_text       text in Multipurpose Internet Mail Extensions format\n"
  26.372 +                )
  26.373 +        .def(boost::python::init<int>())
  26.374 +        .def(boost::python::init<int, Identity *>())
  26.375 +        .def(boost::python::init<string>())
  26.376 +        .def("__str__", &Message::_str,
  26.377 +    "the string representation of a Message is it's MIME text"
  26.378 +                )
  26.379 +        .def("__repr__", &Message::_repr)
  26.380 +        .add_property("dir", (int(Message::*)())
  26.381 +                (PEP_msg_direction(Message::*)()) &Message::dir,
  26.382 +                (void(Message::*)(int))
  26.383 +                (void(Message::*)(PEP_msg_direction)) &Message::dir,
  26.384 +                "0: incoming, 1: outgoing message")
  26.385 +        .add_property("id", (string(Message::*)()) &Message::id,
  26.386 +                (void(Message::*)(string)) &Message::id,
  26.387 +                "message ID")
  26.388 +        .add_property("shortmsg", (string(Message::*)()) &Message::shortmsg,
  26.389 +                (void(Message::*)(string)) &Message::shortmsg,
  26.390 +                "subject or short message")
  26.391 +        .add_property("longmsg", (string(Message::*)()) &Message::longmsg,
  26.392 +                (void(Message::*)(string)) &Message::longmsg,
  26.393 +                "body or long version of message")
  26.394 +        .add_property("longmsg_formatted", (string(Message::*)()) &Message::longmsg_formatted,
  26.395 +                (void(Message::*)(string)) &Message::longmsg_formatted,
  26.396 +                "HTML body or fromatted long version of message")
  26.397 +        .add_property("attachments", (boost::python::tuple(Message::*)()) &Message::attachments,
  26.398 +                (void(Message::*)(boost::python::list)) &Message::attachments,
  26.399 +                "tuple of Blobs with attachments; setting moves Blobs to attachment tuple")
  26.400 +        .add_property("sent", (time_t(Message::*)()) &Message::sent,
  26.401 +                (void(Message::*)(time_t)) &Message::sent,
  26.402 +                "time when message was sent in UTC seconds since epoch")
  26.403 +        .add_property("recv", (time_t(Message::*)()) &Message::recv,
  26.404 +                (void(Message::*)(time_t)) &Message::recv,
  26.405 +                "time when message was received in UTC seconds since epoch")
  26.406 +        .add_property("from_", (Identity(Message::*)()) &Message::from,
  26.407 +                (void(Message::*)(object)) &Message::from,
  26.408 +                "identity where message is from")
  26.409 +        .add_property("to", (boost::python::list(Message::*)()) &Message::to,
  26.410 +                (void(Message::*)(boost::python::list)) &Message::to,
  26.411 +                "list of identities message is going to")
  26.412 +        .add_property("recv_by", (Identity(Message::*)()) &Message::recv_by,
  26.413 +                (void(Message::*)(object)) &Message::recv_by,
  26.414 +                "identity where message was received by")
  26.415 +        .add_property("cc", (boost::python::list(Message::*)()) &Message::cc,
  26.416 +                (void(Message::*)(boost::python::list)) &Message::cc,
  26.417 +                "list of identities message is going cc")
  26.418 +        .add_property("bcc", (boost::python::list(Message::*)()) &Message::bcc,
  26.419 +                (void(Message::*)(boost::python::list)) &Message::bcc,
  26.420 +                "list of identities message is going bcc")
  26.421 +        .add_property("reply_to", (boost::python::list(Message::*)()) &Message::reply_to,
  26.422 +                (void(Message::*)(boost::python::list)) &Message::reply_to,
  26.423 +                "list of identities where message will be replied to")
  26.424 +        .add_property("in_reply_to", (boost::python::list(Message::*)()) &Message::in_reply_to,
  26.425 +                (void(Message::*)(boost::python::list)) &Message::in_reply_to,
  26.426 +                "in_reply_to list")
  26.427 +        .add_property("references", (boost::python::list(Message::*)()) &Message::references,
  26.428 +                (void(Message::*)(boost::python::list)) &Message::references,
  26.429 +                "message IDs of messages this one is referring to")
  26.430 +        .add_property("keywords", (boost::python::list(Message::*)()) &Message::keywords,
  26.431 +                (void(Message::*)(boost::python::list)) &Message::keywords,
  26.432 +                "keywords this message should be stored under")
  26.433 +        .add_property("comments", (string(Message::*)()) &Message::comments,
  26.434 +                (void(Message::*)(string)) &Message::comments,
  26.435 +                "comments added to message")
  26.436 +        .add_property("opt_fields", (dict(Message::*)()) &Message::opt_fields,
  26.437 +                (void(Message::*)(dict)) &Message::opt_fields,
  26.438 +                "opt_fields of message")
  26.439 +        .add_property("enc_format", (int(Message::*)())
  26.440 +                (PEP_enc_format(Message::*)()) &Message::enc_format,
  26.441 +                (void(Message::*)(int))
  26.442 +                (void(Message::*)(PEP_enc_format)) &Message::enc_format,
  26.443 +                "0: unencrypted, 1: inline PGP, 2: S/MIME, 3: PGP/MIME, 4: p≡p format")
  26.444 +        .def("encrypt", (Message(Message::*)())&Message::encrypt)
  26.445 +        .def("encrypt", (Message(Message::*)(boost::python::list))&Message::_encrypt)
  26.446 +        .def("encrypt", (Message(Message::*)(boost::python::list,int))&Message::_encrypt)
  26.447 +        .def("encrypt", (Message(Message::*)(boost::python::list,int,int))&Message::_encrypt,
  26.448 +    "msg2 = msg1.encrypt(extra_keys=[], enc_format='pEp', flags=0)\n"
  26.449 +    "\n"
  26.450 +    "encrypts a p≡p message and returns the encrypted message\n"
  26.451 +    "\n"
  26.452 +    "   extra_keys      list of strings with fingerprints for extra keys to use\n"
  26.453 +    "                   for encryption\n"
  26.454 +    "   enc_format      0 for none, 1 for partitioned, 2 for S/MIME,\n"
  26.455 +    "                   3 for PGP/MIME, 4 for pEp\n"
  26.456 +    "   flags           1 is force encryption\n"
  26.457 +                )
  26.458 +        .def("decrypt", &Message::decrypt, boost::python::arg("flags")=0,
  26.459 +    "msg2, keys, rating, flags = msg1.decrypt()\n"
  26.460 +    "\n"
  26.461 +    "decrypts a p≡p message and returns a tuple with data\n"
  26.462 +    "\n"
  26.463 +    "   msg             the decrypted p≡p message\n"
  26.464 +    "   keys            a list of keys being used\n"
  26.465 +    "   rating          the rating of the message as integer\n"
  26.466 +    "   flags           flags set while decryption\n"
  26.467 +                )
  26.468 +        .add_property("outgoing_rating", &Message::outgoing_rating, "rating outgoing message will have")
  26.469 +        .add_property("outgoing_color", &Message::outgoing_color, "color outgoing message will have as PEP_color")
  26.470 +        .def("__deepcopy__", &Message::deepcopy)
  26.471 +        .def("__copy__", &Message::copy);
  26.472 +
  26.473 +    // basic API and key management API
  26.474 +
  26.475 +    def("update_identity", &update_identity,
  26.476 +    "update_identity(ident)\n"
  26.477 +    "\n"
  26.478 +    "update identity information\n"
  26.479 +    "call this to complete identity information when you at least have an address\n"
  26.480 +            );
  26.481 +    def("myself", &myself,
  26.482 +    "myself(ident)\n"
  26.483 +    "\n"
  26.484 +    "ensures that the own identity is being complete\n"
  26.485 +    "supply ident.address and ident.username\n"
  26.486 +            );
  26.487 +    def("trust_personal_key", &trust_personal_key,
  26.488 +    "trust_personal_key(ident)\n"
  26.489 +    "\n"
  26.490 +    "mark a key as trusted with a person\n"
  26.491 +            );
  26.492 +
  26.493 +    enum_<identity_flags>("identity_flags")
  26.494 +        .value("PEP_idf_not_for_sync", PEP_idf_not_for_sync)
  26.495 +        .value("PEP_idf_list", PEP_idf_list)
  26.496 +        .value("PEP_idf_devicegroup", PEP_idf_devicegroup);
  26.497 +
  26.498 +    def("set_identity_flags", &set_identity_flags,
  26.499 +    "set_identity_flags(ident, flags)\n"
  26.500 +    "\n"
  26.501 +    "set identity flags\n"
  26.502 +            );
  26.503 +
  26.504 +    def("unset_identity_flags", &unset_identity_flags,
  26.505 +    "unset_identity_flags(ident, flags)\n"
  26.506 +    "\n"
  26.507 +    "unset identity flags\n"
  26.508 +            );
  26.509 +
  26.510 +    def("key_reset_trust", &key_reset_trust,
  26.511 +            "key_reset_trust(ident)\n"
  26.512 +            "\n"
  26.513 +            "reset trust bit or explicitly mistrusted status for an identity and "
  26.514 +            "its accompanying key/user_id pair\n"
  26.515 +        );
  26.516 +
  26.517 +    def("import_key", &import_key,
  26.518 +            "private_key_list = import_key(key_data)\n"
  26.519 +            "\n"
  26.520 +            "import key(s) from key_data\n"
  26.521 +        );
  26.522 +
  26.523 +    def("export_key", &export_key,
  26.524 +            "key_data = export_key(identity)\n"
  26.525 +            "\n"
  26.526 +            "export key(s) of identity\n"
  26.527 +        );
  26.528 +
  26.529 +    def("export_secret_key", &export_secret_key,
  26.530 +            "key_data = export_seret_key(identity)\n"
  26.531 +            "\n"
  26.532 +            "export secret key(s) of identity\n"
  26.533 +        );
  26.534 +
  26.535 +    def("set_own_key", &set_own_key,
  26.536 +            "set_own_key(me, fpr)\n"
  26.537 +            "\n"
  26.538 +            "mark a key as an own key, and make it the default key\n"
  26.539 +            "\n"
  26.540 +            "me         Own identity for which to add the existing key\n"
  26.541 +            "fpr        The fingerprint of the key to be added\n"
  26.542 +            "\n"
  26.543 +            "me->address, me->user_id and me->username must be set to valid data\n"
  26.544 +            "myself() is called by set_own_key() without key generation\n"
  26.545 +            "me->flags are ignored\n"
  26.546 +            "me->address must not be an alias\n"
  26.547 +            "me->fpr will be ignored and replaced by fpr\n"
  26.548 +        );
  26.549 +
  26.550 +    // message API
  26.551 +
  26.552 +    enum_<PEP_rating>("rating")
  26.553 +        .value("_undefined", PEP_rating_undefined)
  26.554 +        .value("cannot_decrypt", PEP_rating_cannot_decrypt)
  26.555 +        .value("have_no_key", PEP_rating_have_no_key)
  26.556 +        .value("unencrypted", PEP_rating_unencrypted)
  26.557 +        .value("unreliable", PEP_rating_unreliable)
  26.558 +        .value("reliable", PEP_rating_reliable)
  26.559 +        .value("trusted", PEP_rating_trusted)
  26.560 +        .value("trusted_and_anonymized", PEP_rating_trusted_and_anonymized)
  26.561 +        .value("fully_anonymous", PEP_rating_fully_anonymous)
  26.562 +        .value("mistrust", PEP_rating_mistrust)
  26.563 +        .value("b0rken", PEP_rating_b0rken)
  26.564 +        .value("under_attack", PEP_rating_under_attack);
  26.565 +
  26.566 +    enum_<PEP_color>("colorvalue")
  26.567 +        .value("no_color", PEP_color_no_color)
  26.568 +        .value("yellow", PEP_color_yellow)
  26.569 +        .value("green", PEP_color_green)
  26.570 +        .value("red", PEP_color_red);
  26.571 +
  26.572 +
  26.573 +    def("incoming_message", &incoming_message,
  26.574 +    "msg = incoming_message(mime_text)\n"
  26.575 +    "\n"
  26.576 +    "create an incoming message from a MIME text"
  26.577 +            );
  26.578 +    def("outgoing_message", &outgoing_message,
  26.579 +    "msg = outgoing_message(ident)\n"
  26.580 +    "\n"
  26.581 +    "create an outgoing message using an own identity"
  26.582 +            );
  26.583 +    def("color", &_color,
  26.584 +    "c = color(rating)\n"
  26.585 +    "\n"
  26.586 +    "calculate color value out of rating. Returns PEP_color"
  26.587 +            );
  26.588 +    def("trustwords", &_trustwords,
  26.589 +    "text = trustwords(ident_own, ident_partner)\n"
  26.590 +    "\n"
  26.591 +    "calculate trustwords for two Identities");
  26.592 +
  26.593 +    // Sync API
  26.594 +
  26.595 +    enum_<sync_handshake_signal>("sync_handshake_signal")
  26.596 +        .value("SYNC_NOTIFY_UNDEFINED"             , SYNC_NOTIFY_UNDEFINED)
  26.597 +        .value("SYNC_NOTIFY_INIT_ADD_OUR_DEVICE"   , SYNC_NOTIFY_INIT_ADD_OUR_DEVICE)
  26.598 +        .value("SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE" , SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE)
  26.599 +        .value("SYNC_NOTIFY_INIT_FORM_GROUP"       , SYNC_NOTIFY_INIT_FORM_GROUP)
  26.600 +        .value("SYNC_NOTIFY_TIMEOUT"               , SYNC_NOTIFY_TIMEOUT)
  26.601 +        .value("SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED" , SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED)
  26.602 +        .value("SYNC_NOTIFY_ACCEPTED_GROUP_CREATED", SYNC_NOTIFY_ACCEPTED_GROUP_CREATED)
  26.603 +        .value("SYNC_NOTIFY_ACCEPTED_DEVICE_ACCEPTED", SYNC_NOTIFY_ACCEPTED_DEVICE_ACCEPTED)
  26.604 +        .value("SYNC_NOTIFY_SOLE"                  , SYNC_NOTIFY_SOLE)
  26.605 +        .value("SYNC_NOTIFY_IN_GROUP"              , SYNC_NOTIFY_IN_GROUP);
  26.606 +
  26.607 +//    auto user_interface_class = class_<UserInterface, UserInterface_callback, boost::noncopyable>(
  26.608 +//            "UserInterface",
  26.609 +//    "class MyUserInterface(UserInterface):\n"
  26.610 +//    "   def notifyHandshake(self, me, partner):\n"
  26.611 +//    "       ...\n"
  26.612 +//    "\n"
  26.613 +//    "p≡p User Interface class\n"
  26.614 +//    "To be used as a mixin\n"
  26.615 +//    )
  26.616 +//        .def("notifyHandshake", &UserInterface::notifyHandshake,
  26.617 +//    "notifyHandshake(self, me, partner)\n"
  26.618 +//    "\n"
  26.619 +//    "   me              own identity\n"
  26.620 +//    "   partner         identity of communication partner\n"
  26.621 +//    "\n"
  26.622 +//    "overwrite this method with an implementation of a handshake dialog")
  26.623 +//        .def("deliverHandshakeResult", &UserInterface::deliverHandshakeResult,
  26.624 +//                boost::python::arg("identities")=object(),
  26.625 +//    "deliverHandshakeResult(self, result, identities=None)\n"
  26.626 +//    "\n"
  26.627 +//    "   result          -1: cancel, 0: accepted, 1: rejected\n"
  26.628 +//    "   identities      list of identities to share or None for all\n"
  26.629 +//    "\n"
  26.630 +//    "call to deliver the handshake result of the handshake dialog"
  26.631 +//    );
  26.632 +
  26.633 +    def("deliver_handshake_result", &deliverHandshakeResult, boost::python::arg("identities")=object(),
  26.634 +        "deliverHandshakeResult(self, result, identities=None)\n"
  26.635 +        "\n"
  26.636 +        "   result          -1: cancel, 0: accepted, 1: rejected\n"
  26.637 +        "   identities      list of identities to share or None for all\n"
  26.638 +        "\n"
  26.639 +        "call to deliver the handshake result of the handshake dialog"
  26.640 +        );
  26.641 +
  26.642 +    def("start_sync", &start_sync,
  26.643 +        "start_sync()\n"
  26.644 +        "\n"
  26.645 +        "starts the sync thread"
  26.646 +       );
  26.647 +
  26.648 +    def("shutdown_sync", &shutdown_sync,
  26.649 +            "shutdown_sync()\n"
  26.650 +            "\n"
  26.651 +            "call this from another thread to shut down the sync thread\n"
  26.652 +       );
  26.653 +
  26.654 +    def("debug_color", &debug_color,
  26.655 +            "for debug builds set ANSI color value");
  26.656 +
  26.657 +    def("leave_device_group", &leave_device_group,
  26.658 +            "leave_device_group()\n"
  26.659 +            "\n"
  26.660 +            "call this for a grouped device, which should leave\n"
  26.661 +       );
  26.662 +
  26.663 +    def("is_sync_active", &is_sync_active,
  26.664 +            "is_sync_active()\n"
  26.665 +            "\n"
  26.666 +            "True if sync is active, False otherwise\n"
  26.667 +       );
  26.668 +
  26.669 +
  26.670 +    // codecs
  26.671 +    call< object >(((object)(import("codecs").attr("register"))).ptr(), make_function(sync_search));
  26.672 +    call< object >(((object)(import("codecs").attr("register"))).ptr(), make_function(distribution_search));
  26.673 +}
  26.674 +
  26.675 +} // namespace PythonAdapter
  26.676 +} // namespace pEp
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/src/pEp/native_pEp/pEpmodule.hh	Thu Aug 27 00:15:34 2020 +0200
    27.3 @@ -0,0 +1,28 @@
    27.4 +// This file is under GNU Affero General Public License 3.0
    27.5 +// see LICENSE.txt
    27.6 +
    27.7 +#ifndef PEPMODULE_HH
    27.8 +#define PEPMODULE_HH
    27.9 +
   27.10 +// Engine
   27.11 +#include <pEp/pEpEngine.h>
   27.12 +
   27.13 +// local
   27.14 +#include "message.hh"
   27.15 +
   27.16 +namespace pEp {
   27.17 +namespace PythonAdapter {
   27.18 +
   27.19 +extern string device_name;
   27.20 +void config_passive_mode(bool enable);
   27.21 +void config_unencrypted_subject(bool enable);
   27.22 +void key_reset_user(string user_id, string fpr);
   27.23 +void key_reset_all_own_keys();
   27.24 +void _throw_status(PEP_STATUS status);
   27.25 +PEP_STATUS _messageToSend(::message *msg);
   27.26 +PEP_STATUS notifyHandshake(pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal);
   27.27 +
   27.28 +} /* namespace PythonAdapter */
   27.29 +} /* namespace pEp */
   27.30 +
   27.31 +#endif /* PEPMODULE_HH */
   27.32 \ No newline at end of file
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/src/pEp/native_pEp/str_attr.cc	Thu Aug 27 00:15:34 2020 +0200
    28.3 @@ -0,0 +1,184 @@
    28.4 +// This file is under GNU Affero General Public License 3.0
    28.5 +// see LICENSE.txt
    28.6 +
    28.7 +// System
    28.8 +#include <cstdlib>
    28.9 +#include <boost/python.hpp>
   28.10 +#include <boost/locale.hpp>
   28.11 +
   28.12 +// local
   28.13 +#include "str_attr.hh"
   28.14 +
   28.15 +namespace pEp {
   28.16 +namespace PythonAdapter {
   28.17 +using namespace std;
   28.18 +using namespace boost::python;
   28.19 +using namespace boost::locale;
   28.20 +
   28.21 +object repr(object s)
   28.22 +{
   28.23 +    return s.attr("__repr__")();
   28.24 +}
   28.25 +
   28.26 +string repr(string s)
   28.27 +{
   28.28 +    str _s = s.c_str();
   28.29 +    object _r = _s.attr("__repr__")();
   28.30 +    string r = extract< string >(_r);
   28.31 +    return r;
   28.32 +}
   28.33 +
   28.34 +string str_attr(char *&str)
   28.35 +{
   28.36 +    if (!str)
   28.37 +        return string("");
   28.38 +    return string(str);
   28.39 +}
   28.40 +
   28.41 +void str_attr(char *&str, string value)
   28.42 +{
   28.43 +    string normalized = normalize(value, norm_nfc);
   28.44 +    free(str);
   28.45 +    str = strdup(normalized.c_str());
   28.46 +    if (!str)
   28.47 +        throw bad_alloc();
   28.48 +}
   28.49 +
   28.50 +time_t timestamp_attr(timestamp *&ts)
   28.51 +{
   28.52 +    if (!ts)
   28.53 +        return 0;
   28.54 +
   28.55 +    return timegm(ts);
   28.56 +}
   28.57 +
   28.58 +void timestamp_attr(timestamp *&ts, time_t value)
   28.59 +{
   28.60 +    free_timestamp(ts);
   28.61 +    ts = new_timestamp(value);
   28.62 +}
   28.63 +
   28.64 +boost::python::list strlist_attr(stringlist_t *&sl)
   28.65 +{
   28.66 +    boost::python::list result;
   28.67 +
   28.68 +    for (stringlist_t *_sl = sl; _sl && _sl->value; _sl = _sl->next) {
   28.69 +        string s(_sl->value);
   28.70 +        result.append(object(s));
   28.71 +    }
   28.72 +
   28.73 +    return result;
   28.74 +}
   28.75 +
   28.76 +void strlist_attr(stringlist_t *&sl, boost::python::list value)
   28.77 +{
   28.78 +    stringlist_t *_sl = new_stringlist(NULL);
   28.79 +    if (!_sl)
   28.80 +        throw bad_alloc();
   28.81 +
   28.82 +    stringlist_t *_s = _sl;
   28.83 +    for (int i=0; i<len(value); i++) {
   28.84 +        extract< string > extract_string(value[i]);
   28.85 +        if (!extract_string.check()) {
   28.86 +            free_stringlist(_sl);
   28.87 +        }
   28.88 +        string s = extract_string();
   28.89 +        s = normalize(s, norm_nfc);
   28.90 +        _s = stringlist_add(_s, s.c_str());
   28.91 +        if (!_s) {
   28.92 +            free_stringlist(_sl);
   28.93 +            throw bad_alloc();
   28.94 +        }
   28.95 +    }
   28.96 +
   28.97 +    free_stringlist(sl);
   28.98 +    sl = _sl;
   28.99 +}
  28.100 +
  28.101 +dict strdict_attr(stringpair_list_t *&spl)
  28.102 +{
  28.103 +    dict result;
  28.104 +
  28.105 +    for (stringpair_list_t *_spl = spl; _spl && _spl->value; _spl =
  28.106 +            _spl->next) {
  28.107 +        stringpair_t *p = _spl->value;
  28.108 +        if (p->key && p->value) {
  28.109 +            string key(p->key);
  28.110 +            string value(p->value);
  28.111 +
  28.112 +            result[key] = value;
  28.113 +        }
  28.114 +    }
  28.115 +
  28.116 +    return result;
  28.117 +}
  28.118 +
  28.119 +void strdict_attr(stringpair_list_t *&spl, dict value)
  28.120 +{
  28.121 +    stringpair_list_t *_spl = new_stringpair_list(NULL);
  28.122 +    if (!_spl)
  28.123 +        throw bad_alloc();
  28.124 +
  28.125 +    stringpair_list_t *_s = _spl;
  28.126 +    for (int i=0; i<len(value); i++) {
  28.127 +        extract< string > extract_key(value.keys()[i]);
  28.128 +        extract< string > extract_value(value.values()[i]);
  28.129 +
  28.130 +        if (!(extract_key.check() && extract_value.check()))
  28.131 +            free_stringpair_list(_spl);
  28.132 +
  28.133 +        string key = extract_key();
  28.134 +        key = normalize(key, norm_nfc);
  28.135 +        string _value = extract_value();
  28.136 +        _value = normalize(_value, norm_nfc);
  28.137 +        stringpair_t *pair = new_stringpair(key.c_str(), _value.c_str());
  28.138 +        if (!pair) {
  28.139 +            free_stringpair_list(_spl);
  28.140 +            throw bad_alloc();
  28.141 +        }
  28.142 +        _s = stringpair_list_add(_s, pair);
  28.143 +        if (!_s) {
  28.144 +            free_stringpair_list(_spl);
  28.145 +            throw bad_alloc();
  28.146 +        }
  28.147 +    }
  28.148 +
  28.149 +    free_stringpair_list(spl);
  28.150 +    spl = _spl;
  28.151 +}
  28.152 +
  28.153 +stringlist_t *to_stringlist(boost::python::list l)
  28.154 +{
  28.155 +    stringlist_t *result = new_stringlist(NULL);
  28.156 +    if (!result)
  28.157 +        throw bad_alloc();
  28.158 +
  28.159 +    stringlist_t *_s = result;
  28.160 +    for (int i=0; i<len(l); i++) {
  28.161 +        extract< string > extract_string(l[i]);
  28.162 +        if (!extract_string.check())
  28.163 +            free_stringlist(result);
  28.164 +        string s = extract_string();
  28.165 +        _s = stringlist_add(_s, s.c_str());
  28.166 +        if (!_s) {
  28.167 +            free_stringlist(result);
  28.168 +            throw bad_alloc();
  28.169 +        }
  28.170 +    }
  28.171 +
  28.172 +    return result;
  28.173 +}
  28.174 +
  28.175 +boost::python::list from_stringlist(const stringlist_t *sl)
  28.176 +{
  28.177 +    boost::python::list result;
  28.178 +    for (const stringlist_t *_sl = sl; _sl && _sl->value; _sl = _sl->next) {
  28.179 +        string s = _sl->value;
  28.180 +        result.append(s);
  28.181 +    }
  28.182 +    return result;
  28.183 +}
  28.184 +
  28.185 +} // namespace PythonAdapter
  28.186 +} // namespace pEp {
  28.187 +
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/src/pEp/native_pEp/str_attr.hh	Thu Aug 27 00:15:34 2020 +0200
    29.3 @@ -0,0 +1,43 @@
    29.4 +// This file is under GNU Affero General Public License 3.0
    29.5 +// see LICENSE.txt
    29.6 +
    29.7 +#ifndef STR_ATTR_HH
    29.8 +#define STR_ATTR_HH
    29.9 +
   29.10 +// System
   29.11 +#include <string>
   29.12 +
   29.13 +// Engine
   29.14 +#include <pEp/pEpEngine.h>
   29.15 +#include <pEp/timestamp.h>
   29.16 +#include <pEp/stringlist.h>
   29.17 +#include <pEp/stringpair.h>
   29.18 +
   29.19 +namespace pEp {
   29.20 +namespace PythonAdapter {
   29.21 +using std::string;
   29.22 +using boost::python::object;
   29.23 +using boost::python::dict;
   29.24 +
   29.25 +object repr(object s);
   29.26 +string repr(string s);
   29.27 +
   29.28 +string str_attr(char *&str);
   29.29 +void str_attr(char *&str, string value);
   29.30 +
   29.31 +time_t timestamp_attr(timestamp *&ts);
   29.32 +void timestamp_attr(timestamp *&ts, time_t value);
   29.33 +
   29.34 +boost::python::list strlist_attr(stringlist_t *&sl);
   29.35 +void strlist_attr(stringlist_t *&sl, boost::python::list value);
   29.36 +
   29.37 +dict strdict_attr(stringpair_list_t *&spl);
   29.38 +void strdict_attr(stringpair_list_t *&spl, dict value);
   29.39 +
   29.40 +stringlist_t *to_stringlist(boost::python::list l);
   29.41 +boost::python::list from_stringlist(const stringlist_t *sl);
   29.42 +
   29.43 +} /* namespace PythonAdapter */
   29.44 +} /* namespace pEp */
   29.45 +
   29.46 +#endif /* STR_ATTR_HH */
   29.47 \ No newline at end of file
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/src/pEp/native_pEp/user_interface.cc	Thu Aug 27 00:15:34 2020 +0200
    30.3 @@ -0,0 +1,130 @@
    30.4 +// This file is under GNU Affero General Public License 3.0
    30.5 +// see LICENSE.txt
    30.6 +
    30.7 +// System
    30.8 +#include <cassert>
    30.9 +
   30.10 +// local
   30.11 +#include "user_interface.hh"
   30.12 +
   30.13 +namespace pEp {
   30.14 +namespace PythonAdapter {
   30.15 +using namespace std;
   30.16 +using namespace boost::python;
   30.17 +
   30.18 +UserInterface *UserInterface::_ui = nullptr;
   30.19 +
   30.20 +UserInterface::UserInterface()
   30.21 +{
   30.22 +    if (_ui)
   30.23 +        throw runtime_error("only one UserInterface thread allowed");
   30.24 +    _ui = this;
   30.25 +}
   30.26 +
   30.27 +UserInterface::~UserInterface()
   30.28 +{
   30.29 +    _ui = nullptr;
   30.30 +}
   30.31 +
   30.32 +UserInterface_callback::UserInterface_callback(PyObject *self) :
   30.33 +    UserInterface(), _self(self)
   30.34 +{
   30.35 +//    adapter.ui_object(self);
   30.36 +//    PEP_STATUS status = ::register_sync_callbacks(Adapter::session(),
   30.37 +//            (void *) this, _notifyHandshake, retrieve_next_sync_event);
   30.38 +//    assert(status == PEP_STATUS_OK);
   30.39 +//    if (status)
   30.40 +//        _throw_status(status);
   30.41 +}
   30.42 +
   30.43 +UserInterface_callback::~UserInterface_callback()
   30.44 +{
   30.45 +//    ::unregister_sync_callbacks(Adapter::session());
   30.46 +}
   30.47 +
   30.48 +PEP_STATUS UserInterface::_notifyHandshake(
   30.49 +        pEp_identity *me, pEp_identity *partner,
   30.50 +        sync_handshake_signal signal
   30.51 +    )
   30.52 +{
   30.53 +    if (!(me && partner))
   30.54 +        return PEP_ILLEGAL_VALUE;
   30.55 +
   30.56 +    auto that = dynamic_cast< UserInterface_callback * >(_ui);
   30.57 +    that->notifyHandshake(Identity(me), Identity(partner), signal);
   30.58 +
   30.59 +    return PEP_STATUS_OK;
   30.60 +}
   30.61 +
   30.62 +void UserInterface::deliverHandshakeResult(int result, object identities)
   30.63 +{
   30.64 +    identity_list *shared_identities = nullptr;
   30.65 +    if (identities != boost::python::api::object() && boost::python::len(identities)) {
   30.66 +        shared_identities = new_identity_list(nullptr);
   30.67 +        if (!shared_identities)
   30.68 +            throw bad_alloc();
   30.69 +
   30.70 +        try {
   30.71 +            identity_list *si = shared_identities;
   30.72 +            for (int i=0; i < boost::python::len(identities); ++i) {
   30.73 +                Identity ident = extract< Identity >(identities[i]);
   30.74 +                si = identity_list_add(si, ident);
   30.75 +                if (!si)
   30.76 +                    throw bad_alloc();
   30.77 +            }
   30.78 +        }
   30.79 +        catch (exception& ex) {
   30.80 +            free_identity_list(shared_identities);
   30.81 +            throw ex;
   30.82 +        }
   30.83 +    }
   30.84 +
   30.85 +    PEP_STATUS status = ::deliverHandshakeResult(Adapter::session(),
   30.86 +            (sync_handshake_result) result, shared_identities);
   30.87 +    free_identity_list(shared_identities);
   30.88 +    _throw_status(status);
   30.89 +}
   30.90 +
   30.91 +//PEP_rating UserInterface::get_key_rating_for_user(string user_id, string fpr)
   30.92 +//{
   30.93 +//    PEP_rating result;
   30.94 +//    PEP_STATUS status =
   30.95 +//        ::get_key_rating_for_user(Adapter::session(),
   30.96 +//                user_id.c_str(), fpr.c_str(), &result);
   30.97 +//    _throw_status(status);
   30.98 +//    return result;
   30.99 +//}
  30.100 +
  30.101 +//SYNC_EVENT UserInterface::retrieve_next_sync_event(void *management, unsigned threshold)
  30.102 +//{
  30.103 +//    time_t started = time(nullptr);
  30.104 +//    bool timeout = false;
  30.105 +//
  30.106 +//    while (adapter.queue().empty()) {
  30.107 +//        int i = 0;
  30.108 +//        ++i;
  30.109 +//        if (i > 10) {
  30.110 +//            if (time(nullptr) > started + threshold) {
  30.111 +//                timeout = true;
  30.112 +//                break;
  30.113 +//            }
  30.114 +//            i = 0;
  30.115 +//        }
  30.116 +//        nanosleep((const struct timespec[]){{0, 100000000L}}, NULL);
  30.117 +//    }
  30.118 +//
  30.119 +//    if (timeout)
  30.120 +//        return new_sync_timeout_event();
  30.121 +//
  30.122 +//    return adapter.queue().pop_front();
  30.123 +//}
  30.124 +
  30.125 +void UserInterface_callback::notifyHandshake(
  30.126 +    Identity me, Identity partner, sync_handshake_signal signal)
  30.127 +{
  30.128 +    call_method< void >(_self, "notifyHandshake", me, partner, signal);
  30.129 +}
  30.130 +
  30.131 +} // namespace PythonAdapter
  30.132 +} // namespace pEp {
  30.133 +
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/src/pEp/native_pEp/user_interface.hh	Thu Aug 27 00:15:34 2020 +0200
    31.3 @@ -0,0 +1,60 @@
    31.4 +// This file is under GNU Affero General Public License 3.0
    31.5 +// see LICENSE.txt
    31.6 +
    31.7 +#ifndef USER_INTERFACE_HH
    31.8 +#define USER_INTERFACE_HH
    31.9 +
   31.10 +// System
   31.11 +#include <csetjmp>
   31.12 +
   31.13 +// Engine
   31.14 +#include <pEp/sync_api.h>
   31.15 +#include <pEp/message_api.h>
   31.16 +
   31.17 +// local
   31.18 +#include "pEpmodule.hh"
   31.19 +
   31.20 +
   31.21 +namespace pEp {
   31.22 +namespace PythonAdapter {
   31.23 +
   31.24 +class UserInterface {
   31.25 +    static UserInterface *_ui;
   31.26 +public:
   31.27 +    UserInterface();
   31.28 +    virtual ~UserInterface();
   31.29 +
   31.30 +    virtual void notifyHandshake(
   31.31 +        Identity me,
   31.32 +        Identity partner,
   31.33 +        sync_handshake_signal signal)
   31.34 +    {
   31.35 +        throw runtime_error("override this method");
   31.36 +    }
   31.37 +
   31.38 +    virtual void deliverHandshakeResult(int result, object identities);
   31.39 +
   31.40 +//     PEP_rating get_key_rating_for_user(string user_id, string fpr);
   31.41 +
   31.42 +protected:
   31.43 +    static PEP_STATUS _notifyHandshake(pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal);
   31.44 +};
   31.45 +
   31.46 +class UserInterface_callback : public UserInterface {
   31.47 +    PyObject *_self;
   31.48 +public:
   31.49 +    UserInterface_callback(PyObject *self);
   31.50 +    ~UserInterface_callback();
   31.51 +
   31.52 +    void notifyHandshake(
   31.53 +        Identity me,
   31.54 +        Identity partner,
   31.55 +        sync_handshake_signal signal
   31.56 +    );
   31.57 +};
   31.58 +
   31.59 +} /* namespace PythonAdapter */
   31.60 +} /* namespace pEp */
   31.61 +
   31.62 +#endif /* USER_INTERFACE_HH */
   31.63 +
    32.1 --- a/src/pEpmodule.cc	Fri May 15 23:11:13 2020 +0200
    32.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.3 @@ -1,615 +0,0 @@
    32.4 -// This file is under GNU Affero General Public License 3.0
    32.5 -// see LICENSE.txt
    32.6 -
    32.7 -#include "pEpmodule.hh"
    32.8 -#include <boost/locale.hpp>
    32.9 -#include <string>
   32.10 -#include <sstream>
   32.11 -#include <iomanip>
   32.12 -#include "basic_api.hh"
   32.13 -#include "message_api.hh"
   32.14 -#include "user_interface.hh"
   32.15 -#include "adapter.hh"
   32.16 -
   32.17 -#include <mutex>
   32.18 -
   32.19 -#include <pEp/key_reset.h>
   32.20 -#include <pEp/message_api.h>
   32.21 -#include <pEp/sync_api.h>
   32.22 -#include <pEp/status_to_string.h>
   32.23 -
   32.24 -namespace pEp {
   32.25 -    namespace PythonAdapter {
   32.26 -        using namespace std;
   32.27 -
   32.28 -        Adapter adapter(true);
   32.29 -
   32.30 -        void config_passive_mode(bool enable)
   32.31 -        {
   32.32 -            ::config_passive_mode(adapter.session(), enable);
   32.33 -        }
   32.34 -
   32.35 -        void config_unencrypted_subject(bool enable)
   32.36 -        {
   32.37 -            ::config_unencrypted_subject(adapter.session(), enable);
   32.38 -        }
   32.39 -
   32.40 -        void key_reset_user(string user_id, string fpr)
   32.41 -        {
   32.42 -            if (user_id == "")
   32.43 -                throw invalid_argument("user_id required");
   32.44 -
   32.45 -            PEP_STATUS status = ::key_reset_user(adapter.session(),
   32.46 -                    user_id.c_str(), fpr != "" ?  fpr.c_str() : nullptr);
   32.47 -            _throw_status(status);
   32.48 -        }
   32.49 -
   32.50 -        void key_reset_user2(string user_id)
   32.51 -        {
   32.52 -            key_reset_user(user_id, "");
   32.53 -        }
   32.54 -
   32.55 -        void key_reset_all_own_keys()
   32.56 -        {
   32.57 -            PEP_STATUS status = ::key_reset_all_own_keys(adapter.session());
   32.58 -            _throw_status(status);
   32.59 -        }
   32.60 -
   32.61 -        scope *_scope = NULL;
   32.62 -
   32.63 -        static const char *version_string = "p≡p Python adapter version 0.3";
   32.64 -        static string about()
   32.65 -        {
   32.66 -            string version = string(version_string) + "\np≡p version "
   32.67 -                + PEP_VERSION + "\n";
   32.68 -            return version;
   32.69 -        }
   32.70 -
   32.71 -        void _throw_status(PEP_STATUS status)
   32.72 -        {
   32.73 -            if (status == PEP_STATUS_OK)
   32.74 -                return;
   32.75 -            if (status >= 0x400 && status <= 0x4ff)
   32.76 -                return;
   32.77 -            if (status == PEP_OUT_OF_MEMORY)
   32.78 -                throw bad_alloc();
   32.79 -            if (status == PEP_ILLEGAL_VALUE)
   32.80 -                throw invalid_argument("illegal value");
   32.81 -
   32.82 -            if (string(pEp_status_to_string(status)) == "unknown status code") {
   32.83 -                stringstream build;
   32.84 -                build << setfill('0') << "p≡p 0x" << setw(4) << hex << status;
   32.85 -                throw runtime_error(build.str());
   32.86 -            }
   32.87 -            else {
   32.88 -                throw runtime_error(pEp_status_to_string(status));
   32.89 -            }
   32.90 -        }
   32.91 -
   32.92 -        PEP_STATUS _messageToSend(::message *msg)
   32.93 -        {
   32.94 -            if (!_scope)
   32.95 -                return PEP_SEND_FUNCTION_NOT_REGISTERED;
   32.96 -
   32.97 -            try {
   32.98 -                object m = _scope->attr("messageToSend");
   32.99 -                call< void >(m.ptr(), Message(msg));
  32.100 -            }
  32.101 -            catch (exception& e) { }
  32.102 -
  32.103 -            return PEP_STATUS_OK;
  32.104 -        }
  32.105 -
  32.106 -        void messageToSend(Message msg) {
  32.107 -            throw runtime_error("implement pEp.messageToSend(msg)");
  32.108 -        }
  32.109 -
  32.110 -        void do_sync_protocol()
  32.111 -        {
  32.112 -            ::do_sync_protocol(adapter.session(), nullptr);
  32.113 -        }
  32.114 -
  32.115 -        void shutdown_sync()
  32.116 -        {
  32.117 -            adapter.shutdown_sync();
  32.118 -        }
  32.119 -
  32.120 -        void debug_color(int ansi_color)
  32.121 -        {
  32.122 -            ::set_debug_color(adapter.session(), ansi_color);
  32.123 -        }
  32.124 -
  32.125 -        void leave_device_group() {
  32.126 -            ::leave_device_group(adapter.session());
  32.127 -        }
  32.128 -
  32.129 -        void script_is_implementing_sync() {
  32.130 -            adapter.script_is_implementing_sync();
  32.131 -        }
  32.132 -
  32.133 -        bool is_sync_active() {
  32.134 -            return adapter.is_sync_active();
  32.135 -        }
  32.136 -    }
  32.137 -}
  32.138 -
  32.139 -BOOST_PYTHON_MODULE(pEp)
  32.140 -{
  32.141 -    using namespace boost::python;
  32.142 -    using namespace boost::locale;
  32.143 -    using namespace pEp::PythonAdapter;
  32.144 -
  32.145 -    docstring_options doc_options(true, false, false);
  32.146 -
  32.147 -    generator gen;
  32.148 -    std::locale::global(gen(""));
  32.149 -    _scope = new scope();
  32.150 -
  32.151 -    scope().attr("about") = about();
  32.152 -    scope().attr("per_user_directory") = per_user_directory();
  32.153 -    scope().attr("per_machine_directory") = per_machine_directory();
  32.154 -    scope().attr("engine_version") = get_engine_version();
  32.155 -    scope().attr("protocol_version") = get_protocol_version();
  32.156 -
  32.157 -    def("passive_mode", pEp::PythonAdapter::config_passive_mode,
  32.158 -            "do not attach pub keys to all messages");
  32.159 -
  32.160 -    def("unencrypted_subject", pEp::PythonAdapter::config_unencrypted_subject,
  32.161 -            "do not encrypt the subject of messages");
  32.162 -
  32.163 -    def("key_reset", pEp::PythonAdapter::key_reset_user,
  32.164 -            "reset the default database status for the user / keypair provided\n"
  32.165 -            "This will effectively perform key_reset on each identity\n"
  32.166 -            "associated with the key and user_id, if a key is provided, and for\n"
  32.167 -            "each key (and all of their identities) if an fpr is not.");
  32.168 -
  32.169 -    def("key_reset", pEp::PythonAdapter::key_reset_user2,
  32.170 -            "reset the default database status for the user / keypair provided\n"
  32.171 -            "This will effectively perform key_reset on each identity\n"
  32.172 -            "associated with the key and user_id, if a key is provided, and for\n"
  32.173 -            "each key (and all of their identities) if an fpr is not.");
  32.174 -
  32.175 -    def("key_reset_all_own_keys", pEp::PythonAdapter::key_reset_all_own_keys,
  32.176 -            "revoke and mistrust all own keys, generate new keys for all\n"
  32.177 -            "own identities, and opportunistically communicate key reset\n"
  32.178 -            "information to people we have recently contacted.");
  32.179 -
  32.180 -    auto identity_class = class_<pEp::PythonAdapter::Identity>("Identity",
  32.181 -    "Identity(address, username, user_id='', fpr='', comm_type=0, lang='en')\n"
  32.182 -    "\n"
  32.183 -    "represents a p≡p identity\n"
  32.184 -    "\n"
  32.185 -    "an identity is a network address, under which a user is represented in\n"
  32.186 -    "the network\n"
  32.187 -    "\n"
  32.188 -    "   address     network address, either an SMTP address or a URI\n"
  32.189 -    "   username    real name or nickname for user\n"
  32.190 -    "   user_id     ID this user is handled by the application\n"
  32.191 -    "   fpr         full fingerprint of the key being used as key ID,\n"
  32.192 -    "               hex encoded\n"
  32.193 -    "   comm_type   first rating level of this communication channel\n"
  32.194 -    "   lang        ISO 639-1 language code for language being preferred\n"
  32.195 -    "               on this communication channel\n"
  32.196 -        )
  32.197 -        .def(boost::python::init<string>())
  32.198 -        .def(boost::python::init<string, string>())
  32.199 -        .def(boost::python::init<string, string, string>())
  32.200 -        .def(boost::python::init<string, string, string, string>())
  32.201 -        .def(boost::python::init<string, string, string, string, int>())
  32.202 -        .def(boost::python::init<string, string, string, string, int, string>())
  32.203 -        .def("__repr__", &pEp::PythonAdapter::Identity::_repr)
  32.204 -        .def("__str__", &pEp::PythonAdapter::Identity::_str,
  32.205 -            "string representation of this identity\n"
  32.206 -            "following the pattern 'username < address >'\n"
  32.207 -                )
  32.208 -        .def("key_reset", &pEp::PythonAdapter::Identity::key_reset,
  32.209 -                boost::python::arg("fpr")=object(""),
  32.210 -            "reset the default database status for the identity / keypair provided. If this\n"
  32.211 -            "corresponds to the own user and a private key, also revoke the key, generate a\n"
  32.212 -            "new one, and communicate the reset to recently contacted pEp partners for this\n"
  32.213 -            "identity. If it does not, remove the key from the keyring; the key's status is\n"
  32.214 -            "completely fresh on next contact from the partner.")
  32.215 -
  32.216 -        .def("key_mistrusted", &pEp::PythonAdapter::Identity::key_mistrusted,
  32.217 -                boost::python::arg("fpr")=object(""),
  32.218 -            "If you want updated trust on the identity, you ll have"
  32.219 -            "to call update_identity or myself respectively after this."
  32.220 -            "N.B. If you are calling this on a key that is the identity or user default,"
  32.221 -            "it will be removed as the default key for ANY identity and user for which"
  32.222 -            "it is the default. Please keep in mind that the undo in undo_last_mistrust"
  32.223 -            "will only undo the current identity's / it's user's default, not any"
  32.224 -            "other identities which may be impacted (this will not affect most use cases)")
  32.225 -
  32.226 -        .def("enable_for_sync", &pEp::PythonAdapter::Identity::enable_for_sync,
  32.227 -                "Enable own identity for p≡p sync.\n\n"
  32.228 -                "Only use this on own identities, which are used as accounts.\n")
  32.229 -        .def("disable_for_sync", &pEp::PythonAdapter::Identity::disable_for_sync,
  32.230 -                "Disable own identity for p≡p sync.\n\n"
  32.231 -                "Only use this on own identities, which are used as accounts.\n")
  32.232 -
  32.233 -        .add_property("address", (string(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::address,
  32.234 -                (void(pEp::PythonAdapter::Identity::*)(string)) &pEp::PythonAdapter::Identity::address,
  32.235 -                "email address or URI")
  32.236 -        .add_property("fpr", (string(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::fpr,
  32.237 -                (void(pEp::PythonAdapter::Identity::*)(string)) &pEp::PythonAdapter::Identity::fpr,
  32.238 -                "key ID (full fingerprint, hex encoded)")
  32.239 -        .add_property("user_id", (string(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::user_id,
  32.240 -                (void(pEp::PythonAdapter::Identity::*)(string)) &pEp::PythonAdapter::Identity::user_id,
  32.241 -                "ID of person associated or 'pEp_own_userId' if own identity")
  32.242 -        .add_property("username", (string(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::username,
  32.243 -                (void(pEp::PythonAdapter::Identity::*)(string)) &pEp::PythonAdapter::Identity::username,
  32.244 -                "name in full of person associated")
  32.245 -        .add_property("comm_type", (int(pEp::PythonAdapter::Identity::*)())
  32.246 -                (PEP_comm_type(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::comm_type,
  32.247 -                (void(pEp::PythonAdapter::Identity::*)(int))
  32.248 -                (void(pEp::PythonAdapter::Identity::*)(PEP_comm_type)) &pEp::PythonAdapter::Identity::comm_type,
  32.249 -                 "communication type, first rating level (p≡p internal)")
  32.250 -        .add_property("lang", (string(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::lang,
  32.251 -                (void(pEp::PythonAdapter::Identity::*)(string)) &pEp::PythonAdapter::Identity::lang,
  32.252 -                "ISO 639-1 language code")
  32.253 -        .add_property("flags", (identity_flags_t(pEp::PythonAdapter::Identity::*)()) &pEp::PythonAdapter::Identity::flags,
  32.254 -                (void(pEp::PythonAdapter::Identity::*)(identity_flags_t)) &pEp::PythonAdapter::Identity::flags,
  32.255 -                "flags (p≡p internal)")
  32.256 -        .add_property("rating", &pEp::PythonAdapter::Identity::rating, "rating of Identity")
  32.257 -        .add_property("color", &pEp::PythonAdapter::Identity::color, "color of Identity as PEP_color")
  32.258 -        .add_property("is_pEp_user", &pEp::PythonAdapter::Identity::is_pEp_user, "True if this is an identity of a pEp user")
  32.259 -        .def("__deepcopy__", &pEp::PythonAdapter::Identity::deepcopy)
  32.260 -        .def("update", &pEp::PythonAdapter::Identity::update, "update Identity")
  32.261 -        .def("__copy__", &pEp::PythonAdapter::Identity::copy);
  32.262 -
  32.263 -    identity_class.attr("PEP_OWN_USERID") = "pEp_own_userId";
  32.264 -
  32.265 -    auto blob_class = class_<Message::Blob>("Blob",
  32.266 -    "Blob(data, mime_type='', filename='')\n"
  32.267 -    "\n"
  32.268 -    "Binary large object\n"
  32.269 -    "\n"
  32.270 -    "   data            bytes-like object\n"
  32.271 -    "   mime_type       MIME type for the data\n"
  32.272 -    "   filename        filename to store the data\n" ,
  32.273 -            boost::python::init< object, char const*, char const* >(args("data", "mime_type", "filename")))
  32.274 -        .def(boost::python::init<object, string>())
  32.275 -        .def(boost::python::init<object>())
  32.276 -        .def("__repr__", &Message::Blob::_repr)
  32.277 -        .def("__len__", &Message::Blob::size, "size of Blob data in bytes")
  32.278 -        .def("decode", (string(Message::Blob::*)()) &Message::Blob::decode)
  32.279 -        .def("decode", (string(Message::Blob::*)(string)) &Message::Blob::decode,
  32.280 -    "text = blob.decode(encoding='')\n"
  32.281 -    "\n"
  32.282 -    "decode Blob data into string depending on MIME type if encoding=''\n"
  32.283 -    "\n"
  32.284 -    "   mime_type='application/pEp.sync'      decode as 'pEp.sync'\n"
  32.285 -    "   mime_type='application/pEp.keyreset'  decode as 'pEp.keyreset'\n"
  32.286 -    "   other mime_type                       decode as 'ascii' by default\n"
  32.287 -                )
  32.288 -        .add_property("mime_type", (string(Message::Blob::*)()) &Message::Blob::mime_type,
  32.289 -                (void(Message::Blob::*)(string)) &Message::Blob::mime_type,
  32.290 -                "MIME type of object in Blob")
  32.291 -        .add_property("filename", (string(Message::Blob::*)()) &Message::Blob::filename,
  32.292 -                (void(Message::Blob::*)(string)) &Message::Blob::filename,
  32.293 -                "filename of object in Blob");
  32.294 -
  32.295 -    ((PyTypeObject *)(void *)blob_class.ptr())->tp_as_buffer = &Message::Blob::bp;
  32.296 -
  32.297 -    auto message_class = class_<Message>("Message",
  32.298 -    "Message(dir=1, from=None)\n"
  32.299 -    "\n"
  32.300 -    "new p≡p message\n"
  32.301 -    "\n"
  32.302 -    "   dir         1 for outgoing, 2 for incoming\n"
  32.303 -    "   from        Identity() of sender\n"
  32.304 -    "\n"
  32.305 -    "Message(mime_text)\n"
  32.306 -    "\n"
  32.307 -    "new incoming p≡p message\n"
  32.308 -    "\n"
  32.309 -    "   mime_text       text in Multipurpose Internet Mail Extensions format\n"
  32.310 -                )
  32.311 -        .def(boost::python::init<int>())
  32.312 -        .def(boost::python::init<int, pEp::PythonAdapter::Identity *>())
  32.313 -        .def(boost::python::init<string>())
  32.314 -        .def("__str__", &Message::_str,
  32.315 -    "the string representation of a Message is it's MIME text"
  32.316 -                )
  32.317 -        .def("__repr__", &Message::_repr)
  32.318 -        .add_property("dir", (int(Message::*)())
  32.319 -                (PEP_msg_direction(Message::*)()) &Message::dir,
  32.320 -                (void(Message::*)(int))
  32.321 -                (void(Message::*)(PEP_msg_direction)) &Message::dir,
  32.322 -                "0: incoming, 1: outgoing message")
  32.323 -        .add_property("id", (string(Message::*)()) &Message::id,
  32.324 -                (void(Message::*)(string)) &Message::id,
  32.325 -                "message ID")
  32.326 -        .add_property("shortmsg", (string(Message::*)()) &Message::shortmsg,
  32.327 -                (void(Message::*)(string)) &Message::shortmsg,
  32.328 -                "subject or short message")
  32.329 -        .add_property("longmsg", (string(Message::*)()) &Message::longmsg,
  32.330 -                (void(Message::*)(string)) &Message::longmsg,
  32.331 -                "body or long version of message")
  32.332 -        .add_property("longmsg_formatted", (string(Message::*)()) &Message::longmsg_formatted,
  32.333 -                (void(Message::*)(string)) &Message::longmsg_formatted,
  32.334 -                "HTML body or fromatted long version of message")
  32.335 -        .add_property("attachments", (boost::python::tuple(Message::*)()) &Message::attachments,
  32.336 -                (void(Message::*)(boost::python::list)) &Message::attachments,
  32.337 -                "tuple of Blobs with attachments; setting moves Blobs to attachment tuple")
  32.338 -        .add_property("sent", (time_t(Message::*)()) &Message::sent,
  32.339 -                (void(Message::*)(time_t)) &Message::sent,
  32.340 -                "time when message was sent in UTC seconds since epoch")
  32.341 -        .add_property("recv", (time_t(Message::*)()) &Message::recv,
  32.342 -                (void(Message::*)(time_t)) &Message::recv,
  32.343 -                "time when message was received in UTC seconds since epoch")
  32.344 -        .add_property("from_", (pEp::PythonAdapter::Identity(Message::*)()) &Message::from,
  32.345 -                (void(Message::*)(object)) &Message::from,
  32.346 -                "identity where message is from")
  32.347 -        .add_property("to", (boost::python::list(Message::*)()) &Message::to,
  32.348 -                (void(Message::*)(boost::python::list)) &Message::to,
  32.349 -                "list of identities message is going to")
  32.350 -        .add_property("recv_by", (pEp::PythonAdapter::Identity(Message::*)()) &Message::recv_by,
  32.351 -                (void(Message::*)(object)) &Message::recv_by,
  32.352 -                "identity where message was received by")
  32.353 -        .add_property("cc", (boost::python::list(Message::*)()) &Message::cc,
  32.354 -                (void(Message::*)(boost::python::list)) &Message::cc,
  32.355 -                "list of identities message is going cc")
  32.356 -        .add_property("bcc", (boost::python::list(Message::*)()) &Message::bcc,
  32.357 -                (void(Message::*)(boost::python::list)) &Message::bcc,
  32.358 -                "list of identities message is going bcc")
  32.359 -        .add_property("reply_to", (boost::python::list(Message::*)()) &Message::reply_to,
  32.360 -                (void(Message::*)(boost::python::list)) &Message::reply_to,
  32.361 -                "list of identities where message will be replied to")
  32.362 -        .add_property("in_reply_to", (boost::python::list(Message::*)()) &Message::in_reply_to,
  32.363 -                (void(Message::*)(boost::python::list)) &Message::in_reply_to,
  32.364 -                "in_reply_to list")
  32.365 -        .add_property("references", (boost::python::list(Message::*)()) &Message::references,
  32.366 -                (void(Message::*)(boost::python::list)) &Message::references,
  32.367 -                "message IDs of messages this one is referring to")
  32.368 -        .add_property("keywords", (boost::python::list(Message::*)()) &Message::keywords,
  32.369 -                (void(Message::*)(boost::python::list)) &Message::keywords,
  32.370 -                "keywords this message should be stored under")
  32.371 -        .add_property("comments", (string(Message::*)()) &Message::comments,
  32.372 -                (void(Message::*)(string)) &Message::comments,
  32.373 -                "comments added to message")
  32.374 -        .add_property("opt_fields", (dict(Message::*)()) &Message::opt_fields,
  32.375 -                (void(Message::*)(dict)) &Message::opt_fields,
  32.376 -                "opt_fields of message")
  32.377 -        .add_property("enc_format", (int(Message::*)())
  32.378 -                (PEP_enc_format(Message::*)()) &Message::enc_format,
  32.379 -                (void(Message::*)(int))
  32.380 -                (void(Message::*)(PEP_enc_format)) &Message::enc_format,
  32.381 -                "0: unencrypted, 1: inline PGP, 2: S/MIME, 3: PGP/MIME, 4: p≡p format")
  32.382 -        .def("encrypt", (Message(Message::*)())&Message::encrypt)
  32.383 -        .def("encrypt", (Message(Message::*)(boost::python::list))&Message::_encrypt)
  32.384 -        .def("encrypt", (Message(Message::*)(boost::python::list,int))&Message::_encrypt)
  32.385 -        .def("encrypt", (Message(Message::*)(boost::python::list,int,int))&Message::_encrypt,
  32.386 -    "msg2 = msg1.encrypt(extra_keys=[], enc_format='pEp', flags=0)\n"
  32.387 -    "\n"
  32.388 -    "encrypts a p≡p message and returns the encrypted message\n"
  32.389 -    "\n"
  32.390 -    "   extra_keys      list of strings with fingerprints for extra keys to use\n"
  32.391 -    "                   for encryption\n"
  32.392 -    "   enc_format      0 for none, 1 for partitioned, 2 for S/MIME,\n"
  32.393 -    "                   3 for PGP/MIME, 4 for pEp\n"
  32.394 -    "   flags           1 is force encryption\n"
  32.395 -                )
  32.396 -        .def("decrypt", &Message::decrypt, boost::python::arg("flags")=0,
  32.397 -    "msg2, keys, rating, flags = msg1.decrypt()\n"
  32.398 -    "\n"
  32.399 -    "decrypts a p≡p message and returns a tuple with data\n"
  32.400 -    "\n"
  32.401 -    "   msg             the decrypted p≡p message\n"
  32.402 -    "   keys            a list of keys being used\n"
  32.403 -    "   rating          the rating of the message as integer\n"
  32.404 -    "   flags           flags set while decryption\n"
  32.405 -                )
  32.406 -        .add_property("outgoing_rating", &Message::outgoing_rating, "rating outgoing message will have")
  32.407 -        .add_property("outgoing_color", &Message::outgoing_color, "color outgoing message will have as PEP_color")
  32.408 -        .def("__deepcopy__", &Message::deepcopy)
  32.409 -        .def("__copy__", &Message::copy);
  32.410 -
  32.411 -    // basic API and key management API
  32.412 -
  32.413 -    def("update_identity", &pEp::PythonAdapter::update_identity,
  32.414 -    "update_identity(ident)\n"
  32.415 -    "\n"
  32.416 -    "update identity information\n"
  32.417 -    "call this to complete identity information when you at least have an address\n"
  32.418 -            );
  32.419 -    def("myself", &pEp::PythonAdapter::myself,
  32.420 -    "myself(ident)\n"
  32.421 -    "\n"
  32.422 -    "ensures that the own identity is being complete\n"
  32.423 -    "supply ident.address and ident.username\n"
  32.424 -            );
  32.425 -    def("trust_personal_key", &pEp::PythonAdapter::trust_personal_key,
  32.426 -    "trust_personal_key(ident)\n"
  32.427 -    "\n"
  32.428 -    "mark a key as trusted with a person\n"
  32.429 -            );
  32.430 -
  32.431 -    enum_<identity_flags>("identity_flags")
  32.432 -        .value("PEP_idf_not_for_sync", PEP_idf_not_for_sync)
  32.433 -        .value("PEP_idf_list", PEP_idf_list)
  32.434 -        .value("PEP_idf_devicegroup", PEP_idf_devicegroup);
  32.435 -
  32.436 -    def("set_identity_flags", &pEp::PythonAdapter::set_identity_flags,
  32.437 -    "set_identity_flags(ident, flags)\n"
  32.438 -    "\n"
  32.439 -    "set identity flags\n"
  32.440 -            );
  32.441 -
  32.442 -    def("unset_identity_flags", &pEp::PythonAdapter::unset_identity_flags,
  32.443 -    "unset_identity_flags(ident, flags)\n"
  32.444 -    "\n"
  32.445 -    "unset identity flags\n"
  32.446 -            );
  32.447 -
  32.448 -    def("key_reset_trust", &pEp::PythonAdapter::key_reset_trust,
  32.449 -            "key_reset_trust(ident)\n"
  32.450 -            "\n"
  32.451 -            "reset trust bit or explicitly mistrusted status for an identity and "
  32.452 -            "its accompanying key/user_id pair\n"
  32.453 -        );
  32.454 -
  32.455 -    def("import_key", &pEp::PythonAdapter::import_key,
  32.456 -            "private_key_list = import_key(key_data)\n"
  32.457 -            "\n"
  32.458 -            "import key(s) from key_data\n"
  32.459 -        );
  32.460 -
  32.461 -    def("export_key", &pEp::PythonAdapter::export_key,
  32.462 -            "key_data = export_key(identity)\n"
  32.463 -            "\n"
  32.464 -            "export key(s) of identity\n"
  32.465 -        );
  32.466 -
  32.467 -    def("export_secret_key", &pEp::PythonAdapter::export_secret_key,
  32.468 -            "key_data = export_seret_key(identity)\n"
  32.469 -            "\n"
  32.470 -            "export secret key(s) of identity\n"
  32.471 -        );
  32.472 -
  32.473 -    def("set_own_key", &pEp::PythonAdapter::set_own_key,
  32.474 -            "set_own_key(me, fpr)\n"
  32.475 -            "\n"
  32.476 -            "mark a key as an own key, and make it the default key\n"
  32.477 -            "\n"
  32.478 -            "me         Own identity for which to add the existing key\n"
  32.479 -            "fpr        The fingerprint of the key to be added\n"
  32.480 -            "\n"
  32.481 -            "me->address, me->user_id and me->username must be set to valid data\n"
  32.482 -            "myself() is called by set_own_key() without key generation\n"
  32.483 -            "me->flags are ignored\n"
  32.484 -            "me->address must not be an alias\n"
  32.485 -            "me->fpr will be ignored and replaced by fpr\n"
  32.486 -        );
  32.487 -
  32.488 -    // message API
  32.489 -
  32.490 -    enum_<PEP_rating>("rating")
  32.491 -        .value("_undefined", PEP_rating_undefined)
  32.492 -        .value("cannot_decrypt", PEP_rating_cannot_decrypt)
  32.493 -        .value("have_no_key", PEP_rating_have_no_key)
  32.494 -        .value("unencrypted", PEP_rating_unencrypted)
  32.495 -        .value("unreliable", PEP_rating_unreliable)
  32.496 -        .value("reliable", PEP_rating_reliable)
  32.497 -        .value("trusted", PEP_rating_trusted)
  32.498 -        .value("trusted_and_anonymized", PEP_rating_trusted_and_anonymized)
  32.499 -        .value("fully_anonymous", PEP_rating_fully_anonymous)
  32.500 -        .value("mistrust", PEP_rating_mistrust)
  32.501 -        .value("b0rken", PEP_rating_b0rken)
  32.502 -        .value("under_attack", PEP_rating_under_attack);
  32.503 -
  32.504 -    enum_<PEP_color>("colorvalue")
  32.505 -        .value("no_color", PEP_color_no_color)
  32.506 -        .value("yellow", PEP_color_yellow)
  32.507 -        .value("green", PEP_color_green)
  32.508 -        .value("red", PEP_color_red);
  32.509 -
  32.510 -
  32.511 -    def("incoming_message", &incoming_message,
  32.512 -    "msg = incoming_message(mime_text)\n"
  32.513 -    "\n"
  32.514 -    "create an incoming message from a MIME text"
  32.515 -            );
  32.516 -    def("outgoing_message", &outgoing_message,
  32.517 -    "msg = outgoing_message(ident)\n"
  32.518 -    "\n"
  32.519 -    "create an outgoing message using an own identity"
  32.520 -            );
  32.521 -    def("color", &_color,
  32.522 -    "c = color(rating)\n"
  32.523 -    "\n"
  32.524 -    "calculate color value out of rating. Returns PEP_color"
  32.525 -            );
  32.526 -    def("trustwords", &_trustwords,
  32.527 -    "text = trustwords(ident_own, ident_partner)\n"
  32.528 -    "\n"
  32.529 -    "calculate trustwords for two Identities");
  32.530 -
  32.531 -    // messageToSend()
  32.532 -
  32.533 -    def("messageToSend", &pEp::PythonAdapter::messageToSend,
  32.534 -    "messageToSend(msg)\n"
  32.535 -    "\n"
  32.536 -    "override pEp.messageToSend(msg) with your own implementation\n"
  32.537 -    "this callback is being called when a p≡p management message needs to be sent");
  32.538 -
  32.539 -    // Sync API
  32.540 -
  32.541 -    enum_<sync_handshake_signal>("sync_handshake_signal")
  32.542 -        .value("SYNC_NOTIFY_UNDEFINED"             , SYNC_NOTIFY_UNDEFINED)
  32.543 -        .value("SYNC_NOTIFY_INIT_ADD_OUR_DEVICE"   , SYNC_NOTIFY_INIT_ADD_OUR_DEVICE)
  32.544 -        .value("SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE" , SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE)
  32.545 -        .value("SYNC_NOTIFY_INIT_FORM_GROUP"       , SYNC_NOTIFY_INIT_FORM_GROUP)
  32.546 -        .value("SYNC_NOTIFY_TIMEOUT"               , SYNC_NOTIFY_TIMEOUT)
  32.547 -        .value("SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED" , SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED)
  32.548 -        .value("SYNC_NOTIFY_ACCEPTED_GROUP_CREATED", SYNC_NOTIFY_ACCEPTED_GROUP_CREATED)
  32.549 -        .value("SYNC_NOTIFY_ACCEPTED_DEVICE_ACCEPTED", SYNC_NOTIFY_ACCEPTED_DEVICE_ACCEPTED)
  32.550 -        .value("SYNC_NOTIFY_SOLE"                  , SYNC_NOTIFY_SOLE)
  32.551 -        .value("SYNC_NOTIFY_IN_GROUP"              , SYNC_NOTIFY_IN_GROUP);
  32.552 -
  32.553 -    auto user_interface_class = class_<UserInterface, UserInterface_callback, boost::noncopyable>(
  32.554 -            "UserInterface",
  32.555 -    "class MyUserInterface(UserInterface):\n"
  32.556 -    "   def notifyHandshake(self, me, partner):\n"
  32.557 -    "       ...\n"
  32.558 -    "\n"
  32.559 -    "p≡p User Interface class\n"
  32.560 -    "To be used as a mixin\n"
  32.561 -    )
  32.562 -        .def("notifyHandshake", &UserInterface::notifyHandshake,
  32.563 -    "notifyHandshake(self, me, partner)\n"
  32.564 -    "\n"
  32.565 -    "   me              own identity\n"
  32.566 -    "   partner         identity of communication partner\n"
  32.567 -    "\n"
  32.568 -    "overwrite this method with an implementation of a handshake dialog")
  32.569 -        .def("deliverHandshakeResult", &UserInterface::deliverHandshakeResult,
  32.570 -                boost::python::arg("identities")=object(),
  32.571 -    "deliverHandshakeResult(self, result, identities=None)\n"
  32.572 -    "\n"
  32.573 -    "   result          -1: cancel, 0: accepted, 1: rejected\n"
  32.574 -    "   identities      list of identities to share or None for all\n"
  32.575 -    "\n"
  32.576 -    "call to deliver the handshake result of the handshake dialog")
  32.577 -    ;
  32.578 -
  32.579 -    def("do_sync_protocol", &pEp::PythonAdapter::do_sync_protocol,
  32.580 -        "do_sync_protocol()\n"
  32.581 -        "\n"
  32.582 -        "in case of an explicit sync thread instead of a single threaded\n"
  32.583 -        "implementation call this function in your sync thread\n"
  32.584 -    );
  32.585 -
  32.586 -    def("shutdown_sync", &pEp::PythonAdapter::shutdown_sync,
  32.587 -            "shutdown_sync()\n"
  32.588 -            "\n"
  32.589 -            "call this from another thread to shut down the sync thread\n"
  32.590 -       );
  32.591 -
  32.592 -    def("debug_color", &pEp::PythonAdapter::debug_color,
  32.593 -            "for debug builds set ANSI color value");
  32.594 -
  32.595 -    def("leave_device_group", &pEp::PythonAdapter::leave_device_group,
  32.596 -            "leave_device_group()\n"
  32.597 -            "\n"
  32.598 -            "call this for a grouped device, which should leave\n"
  32.599 -       );
  32.600 -    
  32.601 -    def("script_is_implementing_sync", &pEp::PythonAdapter::script_is_implementing_sync,
  32.602 -            "script_is_implementing_sync()\n"
  32.603 -            "\n"
  32.604 -            "call this in case the Python script is implementing sync to make\n"
  32.605 -            "is_sync_active() working\n"
  32.606 -       );
  32.607 -
  32.608 -    def("is_sync_active", &pEp::PythonAdapter::is_sync_active,
  32.609 -            "is_sync_active()\n"
  32.610 -            "\n"
  32.611 -            "True if sync is active, False otherwise\n"
  32.612 -       );
  32.613 -
  32.614 -
  32.615 -    // codecs
  32.616 -    call< object >(((object)(import("codecs").attr("register"))).ptr(), make_function(sync_search));
  32.617 -    call< object >(((object)(import("codecs").attr("register"))).ptr(), make_function(distribution_search));
  32.618 -}
    33.1 --- a/src/pEpmodule.hh	Fri May 15 23:11:13 2020 +0200
    33.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.3 @@ -1,23 +0,0 @@
    33.4 -#pragma once
    33.5 -
    33.6 -#include <boost/python.hpp>
    33.7 -#include "identity.hh"
    33.8 -#include "message.hh"
    33.9 -#include "adapter.hh"
   33.10 -#include <pEp/pEpEngine.h>
   33.11 -
   33.12 -namespace pEp {
   33.13 -    namespace PythonAdapter {
   33.14 -        extern string device_name;
   33.15 -        void config_passive_mode(bool enable);
   33.16 -        void config_unencrypted_subject(bool enable);
   33.17 -        void key_reset_user(string user_id, string fpr);
   33.18 -        void key_reset_all_own_keys();
   33.19 -        void _throw_status(PEP_STATUS status);
   33.20 -        void messageToSend(Message msg);
   33.21 -        PEP_STATUS _messageToSend(::message *msg);
   33.22 -        void do_sync_protocol();
   33.23 -        extern Adapter adapter;
   33.24 -    }
   33.25 -}
   33.26 -
    34.1 --- a/src/str_attr.cc	Fri May 15 23:11:13 2020 +0200
    34.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.3 @@ -1,179 +0,0 @@
    34.4 -// This file is under GNU Affero General Public License 3.0
    34.5 -// see LICENSE.txt
    34.6 -
    34.7 -#include <boost/python.hpp>
    34.8 -#include <boost/locale.hpp>
    34.9 -#include "str_attr.hh"
   34.10 -#include <stdlib.h>
   34.11 -
   34.12 -namespace pEp {
   34.13 -    namespace utility {
   34.14 -        using namespace std;
   34.15 -        using namespace boost::locale;
   34.16 -
   34.17 -        object repr(object s)
   34.18 -        {
   34.19 -            return s.attr("__repr__")();
   34.20 -        }
   34.21 -
   34.22 -        string repr(string s)
   34.23 -        {
   34.24 -            str _s = s.c_str();
   34.25 -            object _r = _s.attr("__repr__")();
   34.26 -            string r = extract< string >(_r);
   34.27 -            return r;
   34.28 -        }
   34.29 -
   34.30 -        string str_attr(char *&str)
   34.31 -        {
   34.32 -            if (!str)
   34.33 -                return string("");
   34.34 -            return string(str);
   34.35 -        }
   34.36 -
   34.37 -        void str_attr(char *&str, string value)
   34.38 -        {
   34.39 -            string normalized = normalize(value, norm_nfc);
   34.40 -            free(str);
   34.41 -            str = strdup(normalized.c_str());
   34.42 -            if (!str)
   34.43 -                throw bad_alloc();
   34.44 -        }
   34.45 -
   34.46 -        time_t timestamp_attr(timestamp *&ts)
   34.47 -        {
   34.48 -            if (!ts)
   34.49 -                return 0;
   34.50 -
   34.51 -            return timegm(ts);
   34.52 -        }
   34.53 -
   34.54 -        void timestamp_attr(timestamp *&ts, time_t value)
   34.55 -        {
   34.56 -            free_timestamp(ts);
   34.57 -            ts = new_timestamp(value);
   34.58 -        }
   34.59 -
   34.60 -        boost::python::list strlist_attr(stringlist_t *&sl)
   34.61 -        {
   34.62 -            boost::python::list result;
   34.63 -
   34.64 -            for (stringlist_t *_sl = sl; _sl && _sl->value; _sl = _sl->next) {
   34.65 -                string s(_sl->value);
   34.66 -                result.append(object(s));
   34.67 -            }
   34.68 -
   34.69 -            return result;
   34.70 -        }
   34.71 -
   34.72 -        void strlist_attr(stringlist_t *&sl, boost::python::list value)
   34.73 -        {
   34.74 -            stringlist_t *_sl = new_stringlist(NULL);
   34.75 -            if (!_sl)
   34.76 -                throw bad_alloc();
   34.77 -
   34.78 -            stringlist_t *_s = _sl;
   34.79 -            for (int i=0; i<len(value); i++) {
   34.80 -                extract< string > extract_string(value[i]);
   34.81 -                if (!extract_string.check()) {
   34.82 -                    free_stringlist(_sl);
   34.83 -                }
   34.84 -                string s = extract_string();
   34.85 -                s = normalize(s, norm_nfc);
   34.86 -                _s = stringlist_add(_s, s.c_str());
   34.87 -                if (!_s) {
   34.88 -                    free_stringlist(_sl);
   34.89 -                    throw bad_alloc();
   34.90 -                }
   34.91 -            }
   34.92 -
   34.93 -            free_stringlist(sl);
   34.94 -            sl = _sl;
   34.95 -        }
   34.96 -
   34.97 -        dict strdict_attr(stringpair_list_t *&spl)
   34.98 -        {
   34.99 -            dict result;
  34.100 -
  34.101 -            for (stringpair_list_t *_spl = spl; _spl && _spl->value; _spl =
  34.102 -                    _spl->next) {
  34.103 -                stringpair_t *p = _spl->value;
  34.104 -                if (p->key && p->value) {
  34.105 -                    string key(p->key);
  34.106 -                    string value(p->value);
  34.107 -
  34.108 -                    result[key] = value;
  34.109 -                }
  34.110 -            }
  34.111 -
  34.112 -            return result;
  34.113 -        }
  34.114 -
  34.115 -        void strdict_attr(stringpair_list_t *&spl, dict value)
  34.116 -        {
  34.117 -            stringpair_list_t *_spl = new_stringpair_list(NULL);
  34.118 -            if (!_spl)
  34.119 -                throw bad_alloc();
  34.120 -
  34.121 -            stringpair_list_t *_s = _spl;
  34.122 -            for (int i=0; i<len(value); i++) {
  34.123 -                extract< string > extract_key(value.keys()[i]);
  34.124 -                extract< string > extract_value(value.values()[i]);
  34.125 -
  34.126 -                if (!(extract_key.check() && extract_value.check()))
  34.127 -                    free_stringpair_list(_spl);
  34.128 -
  34.129 -                string key = extract_key();
  34.130 -                key = normalize(key, norm_nfc);
  34.131 -                string _value = extract_value();
  34.132 -                _value = normalize(_value, norm_nfc);
  34.133 -                stringpair_t *pair = new_stringpair(key.c_str(), _value.c_str());
  34.134 -                if (!pair) {
  34.135 -                    free_stringpair_list(_spl);
  34.136 -                    throw bad_alloc();
  34.137 -                }
  34.138 -                _s = stringpair_list_add(_s, pair);
  34.139 -                if (!_s) {
  34.140 -                    free_stringpair_list(_spl);
  34.141 -                    throw bad_alloc();
  34.142 -                }
  34.143 -            }
  34.144 -
  34.145 -            free_stringpair_list(spl);
  34.146 -            spl = _spl;
  34.147 -        }
  34.148 -
  34.149 -        stringlist_t *to_stringlist(boost::python::list l)
  34.150 -        {
  34.151 -            stringlist_t *result = new_stringlist(NULL);
  34.152 -            if (!result)
  34.153 -                throw bad_alloc();
  34.154 -
  34.155 -            stringlist_t *_s = result;
  34.156 -            for (int i=0; i<len(l); i++) {
  34.157 -                extract< string > extract_string(l[i]);
  34.158 -                if (!extract_string.check())
  34.159 -                    free_stringlist(result);
  34.160 -                string s = extract_string();
  34.161 -                _s = stringlist_add(_s, s.c_str());
  34.162 -                if (!_s) {
  34.163 -                    free_stringlist(result);
  34.164 -                    throw bad_alloc();
  34.165 -                }
  34.166 -            }
  34.167 -
  34.168 -            return result;
  34.169 -        }
  34.170 -
  34.171 -        boost::python::list from_stringlist(const stringlist_t *sl)
  34.172 -        {
  34.173 -            boost::python::list result;
  34.174 -            for (const stringlist_t *_sl = sl; _sl && _sl->value; _sl = _sl->next) {
  34.175 -                string s = _sl->value;
  34.176 -                result.append(s);
  34.177 -            }
  34.178 -            return result;
  34.179 -        }
  34.180 -    }
  34.181 -}
  34.182 -
    35.1 --- a/src/str_attr.hh	Fri May 15 23:11:13 2020 +0200
    35.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.3 @@ -1,36 +0,0 @@
    35.4 -// This file is under GNU Affero General Public License 3.0
    35.5 -// see LICENSE.txt
    35.6 -
    35.7 -#pragma once
    35.8 -
    35.9 -#include <string>
   35.10 -#include <pEp/pEpEngine.h>
   35.11 -#include <pEp/timestamp.h>
   35.12 -#include <pEp/stringlist.h>
   35.13 -#include <pEp/stringpair.h>
   35.14 -
   35.15 -namespace pEp {
   35.16 -    namespace utility {
   35.17 -        using namespace std;
   35.18 -        using namespace boost::python;
   35.19 -
   35.20 -        object repr(object s);
   35.21 -        string repr(string s);
   35.22 -
   35.23 -        string str_attr(char *&str);
   35.24 -        void str_attr(char *&str, string value);
   35.25 -
   35.26 -        time_t timestamp_attr(timestamp *&ts);
   35.27 -        void timestamp_attr(timestamp *&ts, time_t value);
   35.28 -
   35.29 -        boost::python::list strlist_attr(stringlist_t *&sl);
   35.30 -        void strlist_attr(stringlist_t *&sl, boost::python::list value);
   35.31 -
   35.32 -        dict strdict_attr(stringpair_list_t *&spl);
   35.33 -        void strdict_attr(stringpair_list_t *&spl, dict value);
   35.34 -
   35.35 -        stringlist_t *to_stringlist(boost::python::list l);
   35.36 -        boost::python::list from_stringlist(const stringlist_t *sl);
   35.37 -    }
   35.38 -}
   35.39 -
    36.1 --- a/src/user_interface.cc	Fri May 15 23:11:13 2020 +0200
    36.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.3 @@ -1,125 +0,0 @@
    36.4 -// This file is under GNU Affero General Public License 3.0
    36.5 -// see LICENSE.txt
    36.6 -
    36.7 -#include "user_interface.hh"
    36.8 -#include <assert.h>
    36.9 -#include <time.h>
   36.10 -
   36.11 -namespace pEp {
   36.12 -    namespace PythonAdapter {
   36.13 -        UserInterface *UserInterface::_ui = nullptr;
   36.14 -        
   36.15 -        UserInterface::UserInterface()
   36.16 -        {
   36.17 -            if (_ui)
   36.18 -                throw runtime_error("only one UserInterface thread allowed");
   36.19 -            _ui = this;
   36.20 -        }
   36.21 -
   36.22 -        UserInterface::~UserInterface()
   36.23 -        {
   36.24 -            _ui = nullptr;
   36.25 -        }
   36.26 -
   36.27 -        UserInterface_callback::UserInterface_callback(PyObject *self) :
   36.28 -            UserInterface(), _self(self)
   36.29 -        {
   36.30 -            adapter.ui_object(self);
   36.31 -            PEP_STATUS status = ::register_sync_callbacks(adapter.session(),
   36.32 -                    (void *) this, _notifyHandshake, retrieve_next_sync_event);
   36.33 -            assert(status == PEP_STATUS_OK);
   36.34 -            if (status)
   36.35 -                _throw_status(status);
   36.36 -        }
   36.37 -
   36.38 -        UserInterface_callback::~UserInterface_callback()
   36.39 -        {
   36.40 -            ::unregister_sync_callbacks(adapter.session());
   36.41 -        }
   36.42 -
   36.43 -        PEP_STATUS UserInterface::_notifyHandshake(
   36.44 -                pEp_identity *me, pEp_identity *partner,
   36.45 -                sync_handshake_signal signal
   36.46 -            )
   36.47 -        {
   36.48 -            if (!(me && partner))
   36.49 -                return PEP_ILLEGAL_VALUE;
   36.50 -
   36.51 -            auto that = dynamic_cast< UserInterface_callback * >(_ui);
   36.52 -            that->notifyHandshake(Identity(me), Identity(partner), signal);
   36.53 -
   36.54 -            return PEP_STATUS_OK;
   36.55 -        }
   36.56 -
   36.57 -        void UserInterface::deliverHandshakeResult(int result, object identities)
   36.58 -        {
   36.59 -            identity_list *shared_identities = nullptr;
   36.60 -            if (identities != boost::python::api::object() &&
   36.61 -                    boost::python::len(identities)) {
   36.62 -                shared_identities = new_identity_list(nullptr);
   36.63 -                if (!shared_identities)
   36.64 -                    throw bad_alloc();
   36.65 -
   36.66 -                try {
   36.67 -                    identity_list *si = shared_identities;
   36.68 -                    for (int i=0; i < boost::python::len(identities); ++i) {
   36.69 -                        Identity ident = extract< Identity >(identities[i]);
   36.70 -                        si = identity_list_add(si, ident);
   36.71 -                        if (!si)
   36.72 -                            throw bad_alloc();
   36.73 -                    }
   36.74 -                }
   36.75 -                catch (exception& ex) {
   36.76 -                    free_identity_list(shared_identities);
   36.77 -                    throw ex;
   36.78 -                }
   36.79 -            }
   36.80 -
   36.81 -            PEP_STATUS status = ::deliverHandshakeResult(adapter.session(),
   36.82 -                    (sync_handshake_result) result, shared_identities);
   36.83 -            free_identity_list(shared_identities);
   36.84 -            _throw_status(status);
   36.85 -        }
   36.86 -
   36.87 -        PEP_rating UserInterface::get_key_rating_for_user(string user_id, string fpr)
   36.88 -        {
   36.89 -            PEP_rating result;
   36.90 -            PEP_STATUS status =
   36.91 -                ::get_key_rating_for_user(adapter.session(),
   36.92 -                        user_id.c_str(), fpr.c_str(), &result);
   36.93 -            _throw_status(status);
   36.94 -            return result;
   36.95 -        }
   36.96 -
   36.97 -        SYNC_EVENT UserInterface::retrieve_next_sync_event(void *management, unsigned threshold)
   36.98 -        {
   36.99 -            time_t started = time(nullptr);
  36.100 -            bool timeout = false;
  36.101 -
  36.102 -            while (adapter.queue().empty()) {
  36.103 -                int i = 0;
  36.104 -                ++i;
  36.105 -                if (i > 10) {
  36.106 -                    if (time(nullptr) > started + threshold) {
  36.107 -                        timeout = true;
  36.108 -                        break;
  36.109 -                    }
  36.110 -                    i = 0;
  36.111 -                }
  36.112 -                nanosleep((const struct timespec[]){{0, 100000000L}}, NULL);
  36.113 -            }
  36.114 -
  36.115 -            if (timeout)
  36.116 -                return new_sync_timeout_event();
  36.117 -
  36.118 -            return adapter.queue().pop_front();
  36.119 -        }
  36.120 -
  36.121 -        void UserInterface_callback::notifyHandshake(
  36.122 -            Identity me, Identity partner, sync_handshake_signal signal)
  36.123 -        {
  36.124 -            call_method< void >(_self, "notifyHandshake", me, partner, signal);
  36.125 -        }
  36.126 -    }
  36.127 -}
  36.128 -
    37.1 --- a/src/user_interface.hh	Fri May 15 23:11:13 2020 +0200
    37.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.3 @@ -1,50 +0,0 @@
    37.4 -// This file is under GNU Affero General Public License 3.0
    37.5 -// see LICENSE.txt
    37.6 -
    37.7 -#pragma once
    37.8 -
    37.9 -#include "pEpmodule.hh"
   37.10 -#include <setjmp.h> 
   37.11 -#include <pEp/sync_api.h>
   37.12 -#include <pEp/message_api.h>
   37.13 -
   37.14 -namespace pEp {
   37.15 -    namespace PythonAdapter {
   37.16 -        class UserInterface {
   37.17 -                static UserInterface *_ui;
   37.18 -            public:
   37.19 -                UserInterface();
   37.20 -                virtual ~UserInterface();
   37.21 -
   37.22 -                virtual void notifyHandshake(
   37.23 -                    pEp::PythonAdapter::Identity me,
   37.24 -                    pEp::PythonAdapter::Identity partner, 
   37.25 -                    sync_handshake_signal signal)
   37.26 -                {
   37.27 -                    throw runtime_error("override this method");
   37.28 -                }
   37.29 -
   37.30 -                virtual void deliverHandshakeResult(int result, object identities);
   37.31 -
   37.32 -                PEP_rating get_key_rating_for_user(string user_id, string fpr);
   37.33 -
   37.34 -            protected:
   37.35 -                static PEP_STATUS _notifyHandshake(pEp_identity *me,
   37.36 -                        pEp_identity *partner, sync_handshake_signal signal);
   37.37 -                static SYNC_EVENT retrieve_next_sync_event(void *management, unsigned threshold);
   37.38 -        };
   37.39 -
   37.40 -        class UserInterface_callback : public UserInterface {
   37.41 -                PyObject *_self;
   37.42 -            public:
   37.43 -                UserInterface_callback(PyObject *self);
   37.44 -                ~UserInterface_callback();
   37.45 -
   37.46 -                void notifyHandshake(
   37.47 -                    pEp::PythonAdapter::Identity me,
   37.48 -                    pEp::PythonAdapter::Identity partner, 
   37.49 -                    sync_handshake_signal signal);
   37.50 -        };
   37.51 -    }
   37.52 -}
   37.53 -
    38.1 --- a/test/codec_doctest.py	Fri May 15 23:11:13 2020 +0200
    38.2 +++ b/test/codec_doctest.py	Thu Aug 27 00:15:34 2020 +0200
    38.3 @@ -3,14 +3,15 @@
    38.4  
    38.5  """
    38.6  >>> import pEp
    38.7 ->>> def messageToSend(msg):
    38.8 +>>> def message_to_send(msg):
    38.9  ...   m, keys, rating, flags = msg.decrypt()
   38.10  ...   try:
   38.11  ...     m.attachments[0].decode()
   38.12  ...     print("decode successfull")
   38.13  ...   except UnicodeDecodeError as e:
   38.14  ...     print("decode failed")
   38.15 ->>> pEp.messageToSend = messageToSend
   38.16 +>>> pEp.message_to_send = message_to_send
   38.17 +>>> pEp.myself(pEp.Identity(""))
   38.18  >>> pEp.key_reset_all_own_keys()
   38.19  decode successfull
   38.20  decode successfull
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/test/pyadpt-81.py	Thu Aug 27 00:15:34 2020 +0200
    39.3 @@ -0,0 +1,47 @@
    39.4 +#!/usr/bin/env python3
    39.5 +# -*- coding: utf-8 -*-
    39.6 +
    39.7 +import pEp
    39.8 +import time
    39.9 +
   39.10 +def message_to_send(msg):
   39.11 +    print("User defined message_to_send() called")
   39.12 +    m, keys, rating, flags = msg.decrypt()
   39.13 +    try:
   39.14 +        print(m.attachments[0].decode())
   39.15 +    except UnicodeDecodeError as e:
   39.16 +        print("decode failed")
   39.17 +
   39.18 +def notify_handshake(me, partner, signal):
   39.19 +    print("User defined notify_handshake() called")
   39.20 +    print(me)
   39.21 +    print(partner)
   39.22 +    print(signal)
   39.23 +
   39.24 +def start_stop_sync(duration):
   39.25 +    pEp.start_sync()
   39.26 +    time.sleep(duration)
   39.27 +    pEp.shutdown_sync()
   39.28 +
   39.29 +
   39.30 +alice = pEp.Identity("test@alice.com", "alice", "23")
   39.31 +pEp.myself(alice)
   39.32 +print(alice.fpr)
   39.33 +
   39.34 +dir(pEp)
   39.35 +
   39.36 +# test default callback
   39.37 +start_stop_sync(1)
   39.38 +
   39.39 +# test user defined callback
   39.40 +pEp.message_to_send = message_to_send
   39.41 +# pEp.notify_handshake = notify_handshake
   39.42 +
   39.43 +start_stop_sync(1)
   39.44 +
   39.45 +# pEp.start_sync()
   39.46 +# while(True):
   39.47 +#     print("is_sync_active: {}".format(pEp.is_sync_active()))
   39.48 +#     time.sleep(3)
   39.49 +#     pEp.key_reset_all_own_keys()
   39.50 +#     time.sleep(3)
   39.51 \ No newline at end of file