From af81820c13087d7b7e3e5bc4fbf6e29e4245ad1b Mon Sep 17 00:00:00 2001 From: Volker Birk Date: Thu, 8 Aug 2019 19:11:42 +0200 Subject: [PATCH 1/5] adding README --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..77cc090 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +There's a setup.py in pEpPythonAdapter/ + +In Python we've setup tools, so it's: + +python3 setup.py build +python3 setup.py install + +That is a Python concept. You can find more about it here: + +https://docs.python.org/3/extending/building.html#building-c-and-c-extensions-with-distutils + From 6305c9fbd58413053a561d2700db0c198ec34abb Mon Sep 17 00:00:00 2001 From: Volker Birk Date: Wed, 21 Aug 2019 21:12:50 +0200 Subject: [PATCH 2/5] ... --- setup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 1b7baf9..39d4cda 100644 --- a/setup.py +++ b/setup.py @@ -6,9 +6,9 @@ from setuptools import setup, Extension from glob import glob -from os import environ, uname -from os.path import dirname, exists, join -from sys import argv +from os import environ +from os.path import dirname, exists, join, abspath +from sys import argv, platform compile_args = ['-O0', '-g', '-UNDEBUG', '-std=c++14'] \ @@ -43,7 +43,7 @@ libraries = [ ] -libext = '.dylib' if uname().sysname == 'Darwin' else '.so' +libext = '.dll' if platform == 'win32' else '.dylib' if platform == 'darwin' else '.so' search_for_includes = 'pEp', 'boost', 'asn1c/asn_system.h' From 9205d16623198a81c52bd65b40451eecfe861591 Mon Sep 17 00:00:00 2001 From: Volker Birk Date: Wed, 21 Aug 2019 23:03:55 +0200 Subject: [PATCH 3/5] merge in Claudio's setup.py --- setup.py | 287 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 250 insertions(+), 37 deletions(-) diff --git a/setup.py b/setup.py index 39d4cda..4c3db47 100644 --- a/setup.py +++ b/setup.py @@ -3,61 +3,272 @@ # This file is under GNU Affero General Public License 3.0 # see LICENSE.txt +from __future__ import print_function + +import sys +from sys import argv + +import os +from os import environ, uname +from os.path import dirname, exists, join from setuptools import setup, Extension from glob import glob -from os import environ -from os.path import dirname, exists, join, abspath -from sys import argv, platform +import sysconfig + +if sys.platform == 'winnt': + if sys.version_info[0] >= 3: + import winreg + else: + import _winreg as winreg + +from setuptools.command.build_ext import build_ext -compile_args = ['-O0', '-g', '-UNDEBUG', '-std=c++14'] \ - if '--debug' in argv or '-g' in argv else ['-std=c++14'] +if sys.version_info[0] < 3: + FileNotFoundError = EnvironmentError -def find(file, pathlist): +def find(fname, pathlist): for path in pathlist: - _file = join(path, file) - if exists(_file): - return dirname(_file) - raise FileNotFoundError(file) - - -includes = [ - join(environ['HOME'], 'include'), - '/usr/include', - '/usr/local/include', - '/opt/local/include', - join(environ['HOME'], 'share'), - '/usr/share', - '/usr/local/share', - '/opt/local/share', - ] + cand_fname = join(path, fname) + if exists(cand_fname): + return path + raise FileNotFoundError(fname) + +def append_once(lst, element): + if element not in lst: + lst.append(element) +def extend_once(lst, elements): + for element in elements: + if element not in lst: + lst.append(element) -libraries = [ - join(environ['HOME'], 'lib'), - '/usr/lib', - '/usr/local/lib', - '/opt/local/lib', +def getPythonLibver(): + g = sysconfig.get_config_vars() + sent = [] + for template in ( + '{cmd}{py_version_nodot}{abiflags}', + '{cmd}{py_version_nodot}', + '{cmd}{py_version_major}', + '{cmd}{py_version_major}{abiflags}', + '{cmd}' + ): + val = template.format( + cmd = g['PYTHON'], + py_version_nodot = g['py_version_nodot'], + py_version_major = sys.version_info[0], + abiflags = g.get('ABIFLAGS', ''), + ) + if val not in sent: + yield val + sent.append(val) + + +class BuildExtCommand(build_ext): + + # default_pyver = next( getPythonLibver() ) + user_options = build_ext.user_options + [ + # ('boost-python=', None, 'Boost Python version to use (e.g. \'python34\')'), + ('local', None, 'Use local pEp install in HOME/USERPROFILE'), + ('with-pEp-engine=', None, 'Path to pEp Engine source'), + ('with-pEp-libadapter=', None, 'Path to pEp C++ Adapter Library source'), + ('with-boost=', None, 'Path to Boost install prefix'), + ('with-asn1c-share=', None, 'Path to installed ASN1C share directory'), ] + def windowsGetInstallLocation(): + # Note: should be installed to 'C:\Program Files (x86)' while a 32-bit distro + # TODO: Try desktop adapter location first, then COM server + # FIXME: This is wrong, we should chase the COM server, not the Outlook Plugin (even if they're in the same place) + REG_PATH = "Software\\Microsoft\\Office\\Outlook\\Addins\\pEp" + regKey = None + try: + regKey = winreg.OpenKey( + winreg.HKEY_LOCAL_MACHINE, REG_PATH, 0, winreg.KEY_READ) + # Keys: Description, FileName, FriendlyName, LoadBehavior + com_server, regtype = winreg.QueryValueEx(regKey, 'FileName') + winreg.CloseKey(regKey) + except WindowsError: + com_server = None + finally: + if winreg: + winreg.CloseKey(regKey) + # \\bin\\COM_Server.exe + dirname = os.path.dirname + return dirname( dirname( com_server ) ) + + def initialize_options(self): + build_ext.initialize_options(self) + # self.boost_python = BuildExtCommand.default_pyver + self.local = None != environ.get('PER_USER_DIRECTORY') + self.with_pEp_engine = None + self.with_pEp_libadapter = None + self.with_boost = None + self.with_asn1c_share = None + + def finalize_options(self): + build_ext.finalize_options(self) + + # normalize paths given by user (expand tilde etc.) + for with_option in ('pEp_engine', 'pEp_libadapter', 'boost', 'asn1c_share'): + w_opt = 'with_' + with_option + w_val = getattr(self, w_opt) + if w_val != None: + setattr(self, w_opt, os.path.normpath(w_val)) -libext = '.dll' if platform == 'win32' else '.dylib' if platform == 'darwin' else '.so' + if sys.platform == 'darwin': + HOME = environ.get('PER_USER_DIRECTORY') or environ.get('HOME') + PEPLIBNAME = 'libpEpEngine.dylib' + LIBPEPA = 'libpEpAdapter.a' + BOOSTLIBNAME = 'libboost_{boost_python:s}-mt.dylib' + SYS_INCLUDES = [ + '/opt/local/include', # we prefer MacPorts over Homebrew (but support both) + '/usr/local/include', + '/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/include', + join(environ["HOME"], 'include'), + '/usr/include', + ] + SYS_SHARES = [ + '/opt/local/share', + '/usr/local/share', + '/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/share', + join(environ["HOME"], 'share'), + '/usr/share', + ] + SYS_LIB_PREFIXES = [ + '/opt/local/lib', + '/usr/local/lib', + '/Library/Frameworks/PrettyEasyPrivacy.framework/Versions/A/lib', + join(environ["HOME"], 'lib'), + '/usr/lib', + ] + elif sys.platform == 'winnt': + HOME = environ.get('PER_USER_DIRECTORY') or environ.get('USERPROFILE') + SYS_ROOT = environ.get('SystemRoot') + PROFILE_ROOT = environ.get('AppData') + LOCAL_ROOT = environ.get('LocalAppData') + INST_PREFIX = windowsGetInstallLocation() + PEPLIBNAME = 'pEpEngine.dll' + LIBPEPA = 'libpEpAdapter.a' + BOOSTLIBNAME = 'boost_{boost_python:s}-mt.dll' + SYS_INCLUDES = [ + join(INST_PREFIX, 'include'), + join(PROFILE_ROOT, 'pEp', 'include'), + join(LOCAL_ROOT, 'pEp', 'include'), + join(SYS_ROOT, 'pEp', 'include'), + ] + SYS_SHARES = [ + join(INST_PREFIX, 'share'), + join(PROFILE_ROOT, 'pEp', 'share'), + join(LOCAL_ROOT, 'pEp', 'share'), + join(SYS_ROOT, 'pEp', 'share'), + ] + SYS_LIB_PREFIXES = [ + join(INST_PREFIX, 'bin'), + join(PROFILE_ROOT, 'pEp', 'bin'), + join(LOCAL_ROOT, 'pEp', 'bin'), + join(SYS_ROOT, 'pEp', 'bin'), + ] + else: + HOME = environ.get('PER_USER_DIRECTORY') or environ.get('HOME') + PEPLIBNAME = 'pEpEngine.so' + LIBPEPA = 'libpEpAdapter.a' + BOOSTLIBNAME = 'boost_{boost_python:s}-mt.so' + SYS_INCLUDES = ['/usr/local/pEp/include', '/usr/local/include', '/usr/include'] + SYS_SHARES = ['/usr/local/pEp/share', '/usr/local/share', '/usr/share'] + SYS_LIB_PREFIXES = ['/usr/local/pEp/bin', '/usr/local/bin', '/usr/bin'] + use_local_incl = (self.local or os.path.isfile( + join(HOME, 'include', 'pEp', 'pEpEngine.h')) ) + use_local_lib = (self.local or os.path.isfile( + join(HOME, 'lib', PEPLIBNAME)) ) -search_for_includes = 'pEp', 'boost', 'asn1c/asn_system.h' -search_for_libraries = 'libpEpengine' + libext, 'libboost_python3-mt' + libext + INCLUDES = [ join(HOME, 'include') ] if use_local_incl else [] + INCLUDES.extend(SYS_INCLUDES) + SHARES = [ join(HOME, 'share') ] if use_local_incl else [] + SHARES.extend(SYS_SHARES) + LIBS = [ join(HOME, 'lib') ] if use_local_lib else [] + LIBS.extend(SYS_LIB_PREFIXES) + if not self.with_pEp_engine: + ENGINE_INC = find( join('pEp', 'pEpEngine.h'), INCLUDES ) + ENGINE_LIB = find( PEPLIBNAME, LIBS ) + else: + if exists( join(self.with_pEp_engine, 'include', 'pEp') ): + ENGINE_INC = find( join('pEp', 'pEpEngine.h'), (join(self.with_pEp_engine, 'include'),) ) + ENGINE_LIB = find( PEPLIBNAME, (join(self.with_pEp_engine, 'lib'),) ) + else: + ENGINE_INC = find( 'pEpEngine.h', (join(self.with_pEp_engine, 'src'),) ) + ENGINE_LIB = find( PEPLIBNAME, (join(self.with_pEp_engine, 'src'),) ) + if not self.with_pEp_libadapter: + LIBPEPA_INC = find( join('pEp', 'Adapter.hh'), INCLUDES ) + LIBPEPA_LIB = find( LIBPEPA, LIBS ) + else: + if exists( join(self.with_pEp_libadapter, 'include', 'pEp') ): + LIBPEPA_INC = find( join('pEp', 'Adapter.hh'), (join(self.with_pEp_libadapter, 'include'),) ) + LIBPEPA_LIB = find( LIBPEPA, (join(self.with_pEp_libadapter, 'lib'),) ) + else: + LIBPEPA_INC = find( 'Adapter.hh', (join(self.with_pEp_libadapter, 'src'),) ) + LIBPEPA_LIB = find( LIBPEPA, (join(self.with_pEp_libadapter, 'src'),) ) + + if not self.with_boost: + BOOST_INC = find( join('boost', 'system', 'config.hpp'), INCLUDES ) + BOOST_LIB = None + e_ = None + for py in getPythonLibver(): + f = BOOSTLIBNAME.format(boost_python=py) + try: + BOOST_LIB = find( f, LIBS ) + break + except Exception as e: + if self.verbose: + print("Not found: " + f) + e_ = e if e_ is None else e_ + if BOOST_LIB is None: + raise e_ + else: + raise NotImplementedError("Building from Boost source not implemented yet") # FIXME + # BOOST_INC = find( join('boost', 'system', 'config.hpp'), (self.with_boost,) ) + # BOOST_LIB = find( BOOSTLIBNAME, (self.with_boost,) ) + + if not self.with_asn1c_share: + ASN1C_INC = find( join('asn1c', 'asn_system.h'), SHARES ) + else: + ASN1C_INC = find( join('asn1c', 'asn_system.h'), (self.with_asn1c_share,) ) + + if self.verbose: + print('ENGINE_INC=%s' % ENGINE_INC) + print('ENGINE_LIB=%s' % ENGINE_LIB) + print('LIBPEPA_INC=%s' % LIBPEPA_INC) + print('LIBPEPA_LIB=%s' % LIBPEPA_LIB) + print('BOOST_INC=%s' % BOOST_INC) + print('BOOST_LIB=%s' % BOOST_LIB) + print('ASN1C_INC=%s' % ASN1C_INC) + + global module_pEp + extend_once( module_pEp.include_dirs, [ENGINE_INC, LIBPEPA_INC, BOOST_INC, ASN1C_INC] ) + extend_once( module_pEp.library_dirs, [ENGINE_LIB, LIBPEPA_LIB, BOOST_LIB] ) + extend_once( module_pEp.libraries, ['pEpEngine', 'boost_python3-mt', 'boost_locale-mt'] ) + + if self.debug: + module_pEp.extra_compile_args = ['-O0', '-g', '-UNDEBUG', '-std=c++14'] + else: + module_pEp.extra_compile_args = ['-std=c++14'] # FIXME + + def run(self): + build_ext.run(self) + + +# module_pEp global is referenced in BuildExtCommand module_pEp = Extension('pEp', sources = glob('src/*.cc'), - libraries = ['pEpEngine', 'boost_python3-mt', 'boost_locale-mt',], - extra_compile_args = compile_args, - include_dirs = list(set( [ find(file, includes) for file in - search_for_includes ] )), - library_dirs = list(set( [ find(file, libraries) for file in - search_for_libraries ] )), + libraries = ['pEpEngine'], + # extra_compile_args = compile_args, + # include_dirs = [ENGINE_INC, BOOST_INC, ASN1C_INC], + # library_dirs = [ENGINE_LIB, BOOST_LIB], ) @@ -68,5 +279,7 @@ setup( author="Volker Birk", author_email="vb@pep-project.org", ext_modules=[module_pEp,], + cmdclass={ + 'build_ext': BuildExtCommand, + }, ) - From 1c880644c780b25d4b6e12edd9b9b9b8645bd82f Mon Sep 17 00:00:00 2001 From: Volker Birk Date: Thu, 5 Sep 2019 13:20:19 +0200 Subject: [PATCH 4/5] informational attributes --- src/pEpmodule.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pEpmodule.cc b/src/pEpmodule.cc index d1db2f5..d261192 100644 --- a/src/pEpmodule.cc +++ b/src/pEpmodule.cc @@ -129,6 +129,10 @@ BOOST_PYTHON_MODULE(pEp) _scope = new scope(); scope().attr("about") = about(); + scope().attr("per_user_directory") = per_user_directory(); + scope().attr("per_machine_directory") = per_machine_directory(); + scope().attr("engine_version") = get_engine_version(); + scope().attr("protocol_version") = get_protocol_version(); def("passive_mode", pEp::PythonAdapter::config_passive_mode, "do not attach pub keys to all messages"); From 2f4d103cac3d0fb637d735f20d1772e4d5357990 Mon Sep 17 00:00:00 2001 From: Volker Birk Date: Thu, 5 Sep 2019 13:27:35 +0200 Subject: [PATCH 5/5] add is_pEp_user --- src/identity.cc | 8 ++++++++ src/identity.hh | 2 ++ src/pEpmodule.cc | 1 + 3 files changed, 11 insertions(+) diff --git a/src/identity.cc b/src/identity.cc index 1ec6961..6b7f6ac 100644 --- a/src/identity.cc +++ b/src/identity.cc @@ -156,6 +156,14 @@ namespace pEp { _throw_status(status); } + bool Identity::is_pEp_user() + { + bool result; + PEP_STATUS status = ::is_pEp_user(adapter.session(), *this, &result); + _throw_status(status); + return result; + } + Myself::Myself(string address, string username, string user_id, string lang) : Identity(address, username, user_id, "", 0, lang) diff --git a/src/identity.hh b/src/identity.hh index 9301172..ddb0baa 100644 --- a/src/identity.hh +++ b/src/identity.hh @@ -65,6 +65,8 @@ namespace pEp { virtual void update(); void key_reset(string fpr=""); + + bool is_pEp_user(); }; class Myself : public Identity { diff --git a/src/pEpmodule.cc b/src/pEpmodule.cc index d261192..8b0cab8 100644 --- a/src/pEpmodule.cc +++ b/src/pEpmodule.cc @@ -218,6 +218,7 @@ BOOST_PYTHON_MODULE(pEp) "flags (p≡p internal)") .add_property("rating", &pEp::PythonAdapter::Identity::rating, "rating of Identity") .add_property("color", &pEp::PythonAdapter::Identity::color, "color of Identity") + .add_property("is_pEp_user", &pEp::PythonAdapter::Identity::is_pEp_user, "True if this is an identity of a pEp user") .def("__deepcopy__", &pEp::PythonAdapter::Identity::deepcopy) .def("update", &pEp::PythonAdapter::Identity::update, "update Identity") .def("__copy__", &pEp::PythonAdapter::Identity::copy);