Browse Source

Merge branch 'master' into Release_2.1

android-build
heck 4 years ago
parent
commit
ba3f8d141d
  1. 41
      .clang-format
  2. 154
      Adapter.cc
  3. 110
      Adapter.hxx
  4. 41
      Makefile
  5. 3
      Makefile.conf
  6. 0
      README.md
  7. 26
      call_with_lock.hh
  8. 23
      constant_time_algo.cc
  9. 135
      message_cache.hh
  10. 40
      pEpLog.cc
  11. 25
      slurp.cc
  12. 242
      src/Adapter.cc
  13. 48
      src/Adapter.hh
  14. 148
      src/Adapter.hxx
  15. 37
      src/Makefile
  16. 4
      src/Semaphore.hh
  17. 3
      src/call_with_lock.cc
  18. 26
      src/call_with_lock.hh
  19. 24
      src/callback_dispatcher.cc
  20. 12
      src/callback_dispatcher.hh
  21. 21
      src/constant_time_algo.cc
  22. 3
      src/constant_time_algo.hh
  23. 21
      src/locked_queue.hh
  24. 131
      src/message_cache.cc
  25. 128
      src/message_cache.hh
  26. 43
      src/pEpLog.cc
  27. 11
      src/pEpLog.hh
  28. 35
      src/passphrase_cache.cc
  29. 6
      src/passphrase_cache.hh
  30. 9
      src/passphrase_cache.hxx
  31. 0
      src/pc_container.hh
  32. 21
      src/slurp.cc
  33. 3
      src/slurp.hh
  34. 23
      src/status_to_string.cc
  35. 3
      src/status_to_string.hh
  36. 25
      status_to_string.cc
  37. 5
      test/Makefile
  38. 45
      test/framework.cc
  39. 7
      test/framework.hh
  40. 22
      test/test_adapter.cc
  41. 40
      test/test_adapter_cxx.cc
  42. 23
      test/test_ensure_passphrase.cc
  43. 61
      test/test_leave_device_group.cc
  44. 47
      test/test_library.cc
  45. 53
      test/test_message_cache.cc
  46. 64
      test/test_passphrase_cache.cc
  47. 4
      test/test_semaphore.cc

41
.clang-format

@ -0,0 +1,41 @@
BasedOnStyle: LLVM
Language: Cpp
Standard: c++14
DerivePointerAlignment: true
SortIncludes: false
ReflowComments: false
PointerAlignment: Left
AlignAfterOpenBracket: AlwaysBreak
AlignOperands: AlignAfterOperator
BreakConstructorInitializers: AfterColon
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
ExperimentalAutoDetectBinPacking: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: true
ColumnLimit: 100
AllowAllConstructorInitializersOnNextLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
PenaltyBreakBeforeFirstCallParameter: 0
PenaltyReturnTypeOnItsOwnLine: 1000000
PenaltyBreakAssignment: 1000000
PenaltyExcessCharacter: 10
IndentCaseLabels: true
IndentWidth: 4
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
SpaceAfterTemplateKeyword: false
AccessModifierOffset: -4
AllowShortBlocksOnASingleLine: Always
IndentPPDirectives: BeforeHash
Cpp11BracedListStyle: false

154
Adapter.cc

@ -1,154 +0,0 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "Adapter.hh"
#include <sstream>
#include <iomanip>
#include <assert.h>
#include "status_to_string.hh"
#include "pEpLog.hh"
#include "passphrase_cache.hh"
using namespace std;
thread_local pEp::Adapter::Session pEp::Adapter::session;
namespace pEp {
void throw_status(PEP_STATUS status)
{
if (status == PEP_STATUS_OK)
return;
if (status >= 0x400 && status <= 0x4ff)
return;
if (status == PEP_STATEMACHINE_CANNOT_SEND)
return;
if (status == PEP_OUT_OF_MEMORY)
throw bad_alloc();
if (status == PEP_ILLEGAL_VALUE)
throw invalid_argument("illegal value");
string _status = status_to_string(status);
throw RuntimeError(_status, status);
}
RuntimeError::RuntimeError(const std::string& _text, PEP_STATUS _status)
: std::runtime_error(_text.c_str()), text(_text), status(_status)
{
}
namespace Adapter {
messageToSend_t _messageToSend = nullptr;
notifyHandshake_t _notifyHandshake = nullptr;
std::thread _sync_thread;
::utility::locked_queue< SYNC_EVENT, ::free_Sync_event > sync_evt_q;
std::mutex m;
std::thread::id sync_thread_id()
{
return _sync_thread.get_id();
}
int _inject_sync_event(SYNC_EVENT ev, void *management)
{
try {
if (ev == nullptr) {
sync_evt_q.clear();
sync_evt_q.push_back(ev);
}
else {
sync_evt_q.push_front(ev);
}
}
catch (exception&) {
return 1;
}
return 0;
}
PEP_STATUS _ensure_passphrase(PEP_SESSION session, const char *fpr)
{
return passphrase_cache.ensure_passphrase(session, fpr);
}
// threshold: max waiting time in seconds
SYNC_EVENT _retrieve_next_sync_event(void *management, unsigned threshold)
{
SYNC_EVENT syncEvent = nullptr;
const bool success = sync_evt_q.try_pop_front(syncEvent, std::chrono::seconds(threshold));
if (!success) {
return new_sync_timeout_event();
}
return syncEvent;
}
bool on_sync_thread()
{
return _sync_thread.get_id() == this_thread::get_id();
}
PEP_SESSION Session::operator()(session_action action)
{
std::lock_guard<mutex> lock(m);
PEP_STATUS status = PEP_STATUS_OK;
switch (action) {
case release:
if (_session.get()) {
_session = nullptr;
}
break;
case init:
if (!_session.get()) {
PEP_SESSION session_;
status = ::init(&session_, _messageToSend, _inject_sync_event, _ensure_passphrase);
throw_status(status);
_session = SessionPtr{session_, ::release};
}
break;
default:
status = PEP_ILLEGAL_VALUE;
}
throw_status(status);
return _session.get();
}
void shutdown()
{
pEpLog("called");
if (_sync_thread.joinable()) {
pEpLog("sync_is_running - injecting null event");
_inject_sync_event(nullptr, nullptr);
_sync_thread.join();
}
}
bool is_sync_running()
{
return _sync_thread.joinable();
}
bool in_shutdown()
{
SYNC_EVENT ev;
try {
ev = sync_evt_q.back();
}
catch (std::underflow_error&) {
return false;
}
if (ev) {
return false;
} else {
return true;
}
}
}
}

110
Adapter.hxx

@ -1,110 +0,0 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef LIBPEPADAPTER_ADAPTER_HXX
#define LIBPEPADAPTER_ADAPTER_HXX
#include <thread>
#include "locked_queue.hh"
#include <cassert>
#include "pEpLog.hh"
#include <atomic>
namespace pEp {
namespace Adapter {
using std::function;
extern messageToSend_t _messageToSend;
extern notifyHandshake_t _notifyHandshake;
extern std::thread _sync_thread;
extern ::utility::locked_queue< SYNC_EVENT, ::free_Sync_event > sync_evt_q;
extern std::mutex m;
SYNC_EVENT _retrieve_next_sync_event(void *management, unsigned threshold);
static std::exception_ptr _ex;
static std::atomic_bool register_done{false};
template< class T >
void sync_thread(T *obj, function< void(T *) > _startup, function< void(T *) > _shutdown)
{
pEpLog("called");
_ex = nullptr;
assert(_messageToSend);
assert(_notifyHandshake);
if (obj && _startup) {
_startup(obj);
}
pEpLog("creating session");
session();
{
//TODO: Do we need to use a passphraseWrap here???
pEpLog("register_sync_callbacks()");
PEP_STATUS status = register_sync_callbacks(session(), nullptr,
_notifyHandshake, _retrieve_next_sync_event);
pEpLog("register_sync_callbacks() return:" << status);
try {
throw_status(status);
register_done.store(true);
}
catch (...) {
_ex = std::current_exception();
register_done.store(true);
return;
}
}
pEpLog("sync protocol loop started");
do_sync_protocol(session(), (void *)obj);
pEpLog("sync protocol loop ended");
unregister_sync_callbacks(session());
session(release);
if (obj && _shutdown) {
_shutdown(obj);
}
}
template< class T >
void startup(
messageToSend_t messageToSend,
notifyHandshake_t notifyHandshake,
T *obj,
function< void(T *) > _startup,
function< void(T *) > _shutdown)
{
pEpLog("called");
if (messageToSend) {
_messageToSend = messageToSend;
}
if (notifyHandshake) {
_notifyHandshake = notifyHandshake;
}
pEpLog("creating session");
session();
if (!_sync_thread.joinable()) {
register_done.store(false);
pEpLog("creating sync-thread");
_sync_thread = std::thread(sync_thread<T>, obj, _startup, _shutdown);
while (register_done.load() == false) {
pEpLog("waiting for sync-thread to init...");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
if (_ex) {
pEpLog("exception pending, rethrowing");
std::rethrow_exception(_ex);
}
}
}
}
}
#endif //LIBPEPADAPTER_ADAPTER_HXX

41
Makefile

@ -3,45 +3,22 @@
# This file may be used under the terms of the GNU General Public License version 3 # This file may be used under the terms of the GNU General Public License version 3
# see LICENSE.txt # see LICENSE.txt
include Makefile.conf .PHONY: src test install uninstall clean
TARGET=libpEpAdapter.a all: src
.PHONY: install uninstall clean src:
$(MAKE) -C src
SOURCE=$(wildcard *.cc) test: src
HEADERS=$(wildcard *.hh *.hxx)
OBJECTS=$(subst .cc,.o,$(SOURCE))
DEPENDS=$(subst .cc,.d,$(SOURCE))
CXXFLAGS+= -MMD -MP
all: $(TARGET)
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPENDS)
endif
lib: $(TARGET)
all: lib
test: lib
$(MAKE) -C test $(MAKE) -C test
$(TARGET): $(OBJECTS)
$(AR) -rc $@ $^
clean: clean:
rm -vf $(TARGET) $(OBJECTS) $(DEPENDS) $(MAKE) -C src clean
rm -f *.d.*
$(MAKE) -C test clean $(MAKE) -C test clean
install: $(TARGET) install:
mkdir -p $(PREFIX)/include/pEp $(MAKE) -C src install
mkdir -p $(PREFIX)/lib
cp -v $(HEADERS) $(PREFIX)/include/pEp/
cp -v $(TARGET) $(PREFIX)/lib/
uninstall: uninstall:
cd $(PREFIX)/include/pEp && rm -vf $(HEADERS) $(MAKE) -C src uninstall
cd $(PREFIX)/lib && rm -vf $(TARGET)

3
Makefile.conf

@ -5,6 +5,7 @@
HERE:=$(dir $(lastword $(MAKEFILE_LIST))) HERE:=$(dir $(lastword $(MAKEFILE_LIST)))
TARGET=libpEpAdapter.a
# Defaults # Defaults
DEBUG=1 DEBUG=1
@ -12,7 +13,7 @@ PREFIX?=$(HOME)
ENGINE_LIB_PATH=$(PREFIX)/lib ENGINE_LIB_PATH=$(PREFIX)/lib
ENGINE_INC_PATH=$(PREFIX)/include ENGINE_INC_PATH=$(PREFIX)/include
CXXFLAGS+=-std=c++11 -fPIC CXXFLAGS+=-std=c++14 -fPIC
# Build target # Build target
BUILD_FOR:=$(shell uname) BUILD_FOR:=$(shell uname)

0
readme.md → README.md

26
call_with_lock.hh

@ -1,26 +0,0 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef LIBPEPADAPTER_CALL_WITH_LOCK_HH
#define LIBPEPADAPTER_CALL_WITH_LOCK_HH
#include <mutex>
namespace pEp
{
extern std::mutex call_with_lock_mutex;
// TODO: use && and std::forward<> to avoid copying of the arguments.
// It is not relevant, yet, because at the moment we use this function template only
// for init() and release() which have cheap-to-copy pointer parameters only
template<class R, class... Args>
R call_with_lock( R(*fn)(Args...), Args... args)
{
std::lock_guard<std::mutex> L(call_with_lock_mutex);
return fn(args...);
}
}
#endif // LIBPEPADAPTER_CALL_WITH_LOCK_HH

23
constant_time_algo.cc

@ -1,23 +0,0 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "constant_time_algo.hh"
namespace pEp
{
bool constant_time_equal(const std::string& a, const std::string& b)
{
if(a.size() != b.size())
return false;
unsigned d = 0;
for(std::size_t idx = 0; idx<a.size(); ++idx)
{
d |= ( static_cast<unsigned>(a[idx]) ^ static_cast<unsigned>(b[idx]) );
}
// if d is still 0, the strings are equal.
return d == 0;
}
} // end of namespace pEp

135
message_cache.hh

@ -1,135 +0,0 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef LIBPEPADAPTER_MESSAGE_CACHE_HH
#define LIBPEPADAPTER_MESSAGE_CACHE_HH
#include <string>
#include <unordered_map>
#include <mutex>
#include <pEp/message_api.h>
#include <pEp/mime.h>
namespace pEp {
class MessageCache {
struct cache_entry {
cache_entry(::message *s, ::message *d)
: src(s), dst(d) { }
::message *src;
::message *dst;
};
using cache = std::unordered_map<std::string, cache_entry>;
cache _cache;
std::mutex _mtx;
long long id_range = 42;
long long next_id = 23;
public:
MessageCache();
enum which { msg_src = 0, msg_dst = 1 };
static PEP_STATUS cache_mime_decode_message(
const char *mimetext,
size_t size,
message **msg,
bool* has_possible_pEp_msg
);
static PEP_STATUS cache_mime_encode_message(
int one,
const message * msg,
bool omit_fields,
char **mimetext,
bool has_pEp_msg_attachment
);
static PEP_STATUS cache_decrypt_message(
PEP_SESSION session,
message *src,
message **dst,
stringlist_t **keylist,
PEP_rating *rating,
PEP_decrypt_flags_t *flags
);
static PEP_STATUS cache_encrypt_message(
PEP_SESSION session,
message *src,
stringlist_t *extra,
message **dst,
PEP_enc_format enc_format,
PEP_encrypt_flags_t flags
);
static PEP_STATUS cache_encrypt_message_for_self(
PEP_SESSION session,
pEp_identity* target_id,
message *src,
stringlist_t* extra,
message **dst,
PEP_enc_format enc_format,
PEP_encrypt_flags_t flags
);
static PEP_STATUS cache_release(std::string id);
static void removeCacheID(::message* msg);
protected:
void release(std::string id);
PEP_STATUS mime_decode_message(
const char *mimetext,
size_t size,
message **msg,
bool* has_possible_pEp_msg
);
PEP_STATUS mime_encode_message(
which one,
const message * src,
bool omit_fields,
char **mimetext,
bool has_pEp_msg_attachment
);
PEP_STATUS decrypt_message(
PEP_SESSION session,
message *src,
message **dst,
stringlist_t **keylist,
PEP_rating *rating,
PEP_decrypt_flags_t *flags
);
PEP_STATUS encrypt_message(
PEP_SESSION session,
message *src,
stringlist_t *extra,
message **dst,
PEP_enc_format enc_format,
PEP_encrypt_flags_t flags
);
PEP_STATUS encrypt_message_for_self(
PEP_SESSION session,
pEp_identity* target_id,
message *src,
stringlist_t* extra,
message **dst,
PEP_enc_format enc_format,
PEP_encrypt_flags_t flags
);
void generateCacheID(::message* msg);
static std::string cacheID(const ::message* msg);
};
extern MessageCache message_cache;
};
#endif // LIBPEPADAPTER_MESSAGE_CACHE_HH

40
pEpLog.cc

@ -1,40 +0,0 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "pEpLog.hh"
#include <iostream>
#include <sstream>
#include <mutex>
#include <atomic>
namespace pEp {
namespace Adapter {
namespace pEpLog {
std::mutex mtx;
std::atomic_bool is_enabled{false};
void set_enabled(bool enabled) {
is_enabled.store(enabled);
}
bool get_enabled() {
return is_enabled.load();
}
void log(std::string msg) {
if (is_enabled.load()) {
std::lock_guard<std::mutex> l(mtx);
#ifdef ANDROID
__android_log_print(ANDROID_LOG_DEBUG, "pEpDebugLog", "%s", msg.c_str());
#else
std::cout << msg << std::endl; //std::endl also flushes
#endif
}
}
} // pEpLog
} // Adapter
} // pEp

25
slurp.cc

@ -1,25 +0,0 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "slurp.hh"
#include <fstream>
#include <sstream>
#include <stdexcept>
namespace pEp
{
std::string slurp(const std::string& filename)
{
std::ifstream input(filename.c_str(), std::ios_base::binary);
if(!input)
{
throw std::runtime_error("Cannot read file \"" + filename + "\"! ");
}
std::stringstream sstr;
sstr << input.rdbuf();
return sstr.str();
}
} // end of namespace pEp

242
src/Adapter.cc

@ -0,0 +1,242 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "Adapter.hh"
#include <sstream>
#include <iomanip>
#include <assert.h>
#include "status_to_string.hh"
#include "pEpLog.hh"
#include "passphrase_cache.hh"
using namespace std;
thread_local pEp::Adapter::Session pEp::Adapter::session;
namespace pEp {
void throw_status(::PEP_STATUS status)
{
if (status == ::PEP_STATUS_OK) {
return;
}
if (status >= 0x400 && status <= 0x4ff) {
return;
}
if (status == ::PEP_STATEMACHINE_CANNOT_SEND) {
return;
}
if (status == ::PEP_OUT_OF_MEMORY) {
throw bad_alloc();
}
if (status == ::PEP_ILLEGAL_VALUE) {
throw invalid_argument("illegal value");
}
string _status = status_to_string(status);
throw RuntimeError(_status, status);
}
RuntimeError::RuntimeError(const std::string &_text, ::PEP_STATUS _status)
: std::runtime_error(_text.c_str()), text(_text), status(_status)
{
}
namespace Adapter {
// private
SyncModes _sync_mode = SyncModes::Async;
::messageToSend_t _messageToSend = nullptr;
::notifyHandshake_t _notifyHandshake = nullptr;
bool _adapter_manages_sync_thread = false;
::inject_sync_event_t _inject_action = _queue_sync_event;
std::thread _sync_thread;
::utility::locked_queue<SYNC_EVENT, ::free_Sync_event> sync_evt_q;
std::mutex mut;
// private
std::thread::id sync_thread_id()
{
return _sync_thread.get_id();
}
// public
void sync_initialize(
SyncModes mode,
::messageToSend_t messageToSend,
::notifyHandshake_t notifyHandshake,
bool adapter_manages_sync_thread)
{
_messageToSend = messageToSend;
_notifyHandshake = notifyHandshake;
_adapter_manages_sync_thread = adapter_manages_sync_thread;
set_sync_mode(mode);
return;
}
// public
void set_sync_mode(SyncModes mode)
{
// std::lock_guard<mutex> lock(mut);
_sync_mode = mode;
if (_sync_mode == SyncModes::Sync) {
// init sesssion with inject_sync = process
// stop sync
session(release);
_inject_action = _process_sync_event;
session(init);
::register_sync_callbacks(session(), nullptr, _notifyHandshake, _retrieve_next_sync_event);
if(!_adapter_manages_sync_thread) {
shutdown();
} else {
// The adapter need to shutdown sync thread
}
}
if (_sync_mode == SyncModes::Async) {
// init session with inject_sync = queue
// start sync thread
session(release);
_inject_action = _queue_sync_event;
session(init);
if(!_adapter_manages_sync_thread) {
if (!is_sync_running()) {
startup<void>(_messageToSend, _notifyHandshake, nullptr, nullptr);
}
} else {
// The adapter need to do sync thread start up
}
}
if (_sync_mode == SyncModes::Off) {
// init sesssion with inject_sync = null
// stop sync thread
if(!_adapter_manages_sync_thread) {
shutdown();
} else {
// Adapter needs to shutdown sync thread
}
session(release);
_inject_action = _queue_sync_event;
session(init);
}
return;
}
// private
int _process_sync_event(::SYNC_EVENT ev, void *management)
{
if (ev != nullptr) {
::do_sync_protocol_step(session(), nullptr, ev);
return 0;
} else {
return 0;
}
}
// private
int _queue_sync_event(::SYNC_EVENT ev, void *management)
{
try {
if (ev == nullptr) {
sync_evt_q.clear();
sync_evt_q.push_back(ev);
} else {
sync_evt_q.push_front(ev);
}
} catch (exception &) {
return 1;
}
return 0;
}
// private
PEP_STATUS _ensure_passphrase(::PEP_SESSION session, const char *fpr)
{
return passphrase_cache.ensure_passphrase(session, fpr);
}
// public
::SYNC_EVENT _retrieve_next_sync_event(void *management, unsigned threshold)
{
::SYNC_EVENT syncEvent = nullptr;
const bool success = sync_evt_q.try_pop_front(syncEvent, std::chrono::seconds(threshold));
if (!success) {
return ::new_sync_timeout_event();
}
return syncEvent;
}
// public
bool on_sync_thread()
{
return _sync_thread.get_id() == this_thread::get_id();
}
// public
::PEP_SESSION Session::operator()(session_action action)
{
std::lock_guard<mutex> lock(mut);
::PEP_STATUS status = ::PEP_STATUS_OK;
switch (action) {
case release:
if (_session.get()) {
_session = nullptr;
}
break;
case init:
if (!_session.get()) {
::PEP_SESSION session_;
status = ::init(&session_, _messageToSend, _inject_action, _ensure_passphrase);
throw_status(status);
_session = SessionPtr{session_, ::release};
}
break;
default:
status = ::PEP_ILLEGAL_VALUE;
}
throw_status(status);
return _session.get();
}
// public
void shutdown()
{
pEpLog("called");
if (_sync_thread.joinable()) {
pEpLog("sync_is_running - injecting null event");
_queue_sync_event(nullptr, nullptr);
_sync_thread.join();
}
}
// public
bool is_sync_running()
{
if(!_adapter_manages_sync_thread) {
return _sync_thread.joinable();
} else {
return false;
}
}
// public
// Works even if adapter is managing sync thread, BUT must be using this queue
bool in_shutdown()
{
SYNC_EVENT ev;
try {
ev = sync_evt_q.back();
} catch (std::underflow_error &) {
return false;
}
if (ev) {
return false;
} else {
return true;
}
}
} // namespace Adapter
} // namespace pEp

48
Adapter.hh → src/Adapter.hh

@ -5,10 +5,10 @@
#define LIBPEPADAPTER_ADAPTER_HH #define LIBPEPADAPTER_ADAPTER_HH
#include <functional> #include <functional>
#include <memory>
#include <stdexcept>
#include <string> #include <string>
#include <thread> #include <thread>
#include <stdexcept>
#include <memory>
#include <pEp/sync_api.h> #include <pEp/sync_api.h>
@ -17,17 +17,35 @@ namespace pEp {
// throws std::bad_alloc if status==PEP_OUT_OF_MEMORY, // throws std::bad_alloc if status==PEP_OUT_OF_MEMORY,
// throws std::invalid_argument if status==PEP_ILLEGAL_VALUE, // throws std::invalid_argument if status==PEP_ILLEGAL_VALUE,
// throws RuntimeError when 'status' represents another exceptional value. // throws RuntimeError when 'status' represents another exceptional value.
void throw_status(PEP_STATUS status); void throw_status(::PEP_STATUS status);
struct RuntimeError : std::runtime_error { struct RuntimeError : std::runtime_error {
RuntimeError(const std::string& _text, PEP_STATUS _status); RuntimeError(const std::string &_text, ::PEP_STATUS _status);
std::string text; std::string text;
PEP_STATUS status; ::PEP_STATUS status;
}; };
namespace Adapter { namespace Adapter {
int _inject_sync_event(SYNC_EVENT ev, void *management); // public
PEP_STATUS _ensure_passphrase(PEP_SESSION session, const char *fpr); enum class SyncModes
{
Off,
Sync,
Async
};
void sync_initialize(
SyncModes mode,
::messageToSend_t messageToSend,
::notifyHandshake_t notifyHandshake,
bool adapter_manages_sync_thread);
void set_sync_mode(SyncModes mode);
int _queue_sync_event(::SYNC_EVENT ev, void *management);
int _process_sync_event(::SYNC_EVENT ev, void *management);
::PEP_STATUS _ensure_passphrase(::PEP_SESSION session, const char *fpr);
template<class T = void> template<class T = void>
void startup( void startup(
@ -35,8 +53,7 @@ namespace pEp {
notifyHandshake_t notifyHandshake, notifyHandshake_t notifyHandshake,
T *obj = nullptr, T *obj = nullptr,
std::function<void(T *)> _startup = nullptr, std::function<void(T *)> _startup = nullptr,
std::function< void (T *) > _shutdown = nullptr std::function<void(T *)> _shutdown = nullptr);
);
// returns 'true' when called from the "sync" thread, 'false' otherwise. // returns 'true' when called from the "sync" thread, 'false' otherwise.
bool on_sync_thread(); bool on_sync_thread();
@ -44,9 +61,10 @@ namespace pEp {
// returns the thread id of the sync thread // returns the thread id of the sync thread
std::thread::id sync_thread_id(); std::thread::id sync_thread_id();
enum session_action { enum session_action
{
init, init,
release release,
}; };
class Session { class Session {
@ -59,14 +77,14 @@ namespace pEp {
extern thread_local Session session; extern thread_local Session session;
// injects a NULL event into sync_event_queue to denote sync thread to shutdown, // injects a NULL event into sync_event_queue to denote sync thread to
// and joins & removes the sync thread // shutdown, and joins & removes the sync thread
void shutdown(); void shutdown();
bool is_sync_running(); bool is_sync_running();
bool in_shutdown(); bool in_shutdown();
} } // namespace Adapter
} } // namespace pEp
#include "Adapter.hxx" #include "Adapter.hxx"

148
src/Adapter.hxx

@ -0,0 +1,148 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef LIBPEPADAPTER_ADAPTER_HXX
#define LIBPEPADAPTER_ADAPTER_HXX
#include <thread>
#include "locked_queue.hh"
#include <cassert>
#include "pEpLog.hh"
#include <atomic>
namespace pEp {
namespace Adapter {
using std::function;
extern ::messageToSend_t _messageToSend;
extern ::notifyHandshake_t _notifyHandshake;
extern std::thread _sync_thread;
extern ::utility::locked_queue<::SYNC_EVENT, ::free_Sync_event> sync_evt_q;
extern std::mutex mut;
::SYNC_EVENT _retrieve_next_sync_event(void *management, unsigned threshold);
static std::exception_ptr _ex;
static std::atomic_bool register_done{false};
/*
* Sync Thread
* 1. Execute registered startup function
* 2. Create session for the sync thread (registers: messageToSend, inject_sync_event, ensure_passphrase)
* 3. register_sync_callbacks() (registers: _notifyHandshake, _retrieve_next_sync_event)
* 4. Enter Sync Event Dispatching Loop (do_sync_protocol())
* 5. unregister_sync_callbacks()
* 6. Release the session
* 7. Execute registered shutdown function
*/
// private
template<class T>
void sync_thread(T *obj, function<void(T *)> _startup, function<void(T *)> _shutdown)
{
pEpLog("called");
_ex = nullptr;
assert(_messageToSend);
assert(_notifyHandshake);
// 1. Execute registered startup function
if (obj && _startup) {
_startup(obj);
}
pEpLog("creating session for the sync thread");
// 2. Create session for the sync thread
session();
// 3. register_sync_callbacks()
{
// TODO: Do we need to use a passphraseWrap here???
pEpLog("register_sync_callbacks()");
::PEP_STATUS status = ::register_sync_callbacks(
session(),
nullptr,
_notifyHandshake,
_retrieve_next_sync_event);
pEpLog("register_sync_callbacks() return:" << status);
// Convert status into exception and store it
// set register_done AFTER that
try {
throw_status(status);
register_done.store(true);
} catch (...) {
_ex = std::current_exception();
register_done.store(true);
return;
}
}
pEpLog("sync protocol loop started");
// 4. Enter Sync Event Dispatching Loop (do_sync_protocol())
::do_sync_protocol(session(), (void *)obj);
pEpLog("sync protocol loop ended");
// 5. unregister_sync_callbacks()
unregister_sync_callbacks(session());
// 6. Release the session
// TODO: Maybe do that AFTER shutdown?
session(release);
// 7. Execute registered shutdown function
if (obj && _shutdown) {
_shutdown(obj);
}
}
/*
* Sync Thread Startup
* 1. ensure session for the main thread (registers: messageToSend, _queue_sync_event, _ensure_passphrase)
* 2. Start the sync thread
* 3. Defer execution until sync thread register_sync_callbacks() has returned
* 4. Throw pending exception from the sync thread
*/
// private
template<class T>
void startup(
::messageToSend_t messageToSend,
::notifyHandshake_t notifyHandshake,
T *obj,
function<void(T *)> _startup,
function<void(T *)> _shutdown)
{
pEpLog("called");
if (messageToSend) {
_messageToSend = messageToSend;
}
if (notifyHandshake) {
_notifyHandshake = notifyHandshake;
}
pEpLog("ensure session for the main thread");
// 1. re-initialize session for the main thread (registers: messageToSend, _queue_sync_event, _ensure_passphrase)
session(release);
session(init);
if (!_sync_thread.joinable()) {
register_done.store(false);
pEpLog("creating sync-thread");
// 2. Start the sync thread
_sync_thread = std::thread(sync_thread<T>, obj, _startup, _shutdown);
// 3. Defer execution until sync thread register_sync_callbacks() has returned
while (register_done.load() == false) {
pEpLog("waiting for sync-thread to init...");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// 4. Throw pending exception from the sync thread
if (_ex) {
pEpLog("exception pending, rethrowing");
std::rethrow_exception(_ex);
}
}
}
} // namespace Adapter
} // namespace pEp
#endif //LIBPEPADAPTER_ADAPTER_HXX

37
src/Makefile

@ -0,0 +1,37 @@
# Copyright 2018, pEp Foundation
# This file is part of lib pEp Adapter
# This file may be used under the terms of the GNU General Public License version 3
# see LICENSE.txt
include ../Makefile.conf
SOURCE=$(wildcard *.cc)
HEADERS=$(wildcard *.hh *.hxx)
OBJECTS=$(subst .cc,.o,$(SOURCE))
DEPENDS=$(subst .cc,.d,$(SOURCE))
CXXFLAGS+= -MMD -MP
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPENDS)
endif
.PHONY: install uninstall clean
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(AR) -rc $@ $^
clean:
rm -vf $(TARGET) $(OBJECTS) $(DEPENDS)
rm -f *.d.*
install: $(TARGET)
mkdir -p $(PREFIX)/include/pEp
mkdir -p $(PREFIX)/lib
cp -v $(HEADERS) $(PREFIX)/include/pEp/
cp -v $(TARGET) $(PREFIX)/lib/
uninstall:
cd $(PREFIX)/include/pEp && rm -vf $(HEADERS)
cd $(PREFIX)/lib && rm -vf $(TARGET)

4
Semaphore.hh → src/Semaphore.hh

@ -46,8 +46,6 @@ namespace pEp {
cv.notify_all(); cv.notify_all();
} }
}; };
} } // namespace pEp
#endif // LIBPEPADAPTER_SEMAPHORE_HH #endif // LIBPEPADAPTER_SEMAPHORE_HH

3
call_with_lock.cc → src/call_with_lock.cc

@ -3,7 +3,6 @@
#include "call_with_lock.hh" #include "call_with_lock.hh"
namespace pEp namespace pEp {
{
std::mutex call_with_lock_mutex; std::mutex call_with_lock_mutex;
} }

26
src/call_with_lock.hh

@ -0,0 +1,26 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef LIBPEPADAPTER_CALL_WITH_LOCK_HH
#define LIBPEPADAPTER_CALL_WITH_LOCK_HH
#include <mutex>
namespace pEp {
extern std::mutex call_with_lock_mutex;
// TODO: use && and std::forward<> to avoid copying of the arguments.
// It is not relevant, yet, because at the moment we use this function
// template only for init() and release() which have cheap-to-copy pointer
// parameters only
template<class R, class... Args>
R call_with_lock(R (*fn)(Args...), Args... args)
{
std::lock_guard<std::mutex> L(call_with_lock_mutex);
return fn(args...);
}
} // namespace pEp
#endif // LIBPEPADAPTER_CALL_WITH_LOCK_HH

24
callback_dispatcher.cc → src/callback_dispatcher.cc

@ -14,8 +14,10 @@ namespace pEp {
return callback_dispatcher._messageToSend(msg); return callback_dispatcher._messageToSend(msg);
} }
PEP_STATUS CallbackDispatcher::notifyHandshake(::pEp_identity *me, PEP_STATUS CallbackDispatcher::notifyHandshake(
::pEp_identity *partner, ::sync_handshake_signal signal) ::pEp_identity *me,
::pEp_identity *partner,
::sync_handshake_signal signal)
{ {
return callback_dispatcher._notifyHandshake(me, partner, signal); return callback_dispatcher._notifyHandshake(me, partner, signal);
} }
@ -24,8 +26,7 @@ namespace pEp {
::messageToSend_t messageToSend, ::messageToSend_t messageToSend,
::notifyHandshake_t notifyHandshake, ::notifyHandshake_t notifyHandshake,
proc on_startup, proc on_startup,
proc shutdown proc shutdown)
)
{ {
assert(messageToSend); assert(messageToSend);
if (!messageToSend) { if (!messageToSend) {
@ -77,8 +78,10 @@ namespace pEp {
pEpLog("called"); pEpLog("called");
callback_dispatcher.semaphore.go(); callback_dispatcher.semaphore.go();
pEp::Adapter::startup<CallbackDispatcher>(CallbackDispatcher::messageToSend, pEp::Adapter::startup<CallbackDispatcher>(
CallbackDispatcher::notifyHandshake, &callback_dispatcher, CallbackDispatcher::messageToSend,
CallbackDispatcher::notifyHandshake,
&callback_dispatcher,
&CallbackDispatcher::on_startup, &CallbackDispatcher::on_startup,
&CallbackDispatcher::on_shutdown); &CallbackDispatcher::on_shutdown);
@ -143,8 +146,10 @@ namespace pEp {
return PEP_STATUS_OK; return PEP_STATUS_OK;
} }
PEP_STATUS CallbackDispatcher::_notifyHandshake(::pEp_identity *me, PEP_STATUS CallbackDispatcher::_notifyHandshake(
::pEp_identity *partner, ::sync_handshake_signal signal) ::pEp_identity *me,
::pEp_identity *partner,
::sync_handshake_signal signal)
{ {
for (auto target : targets) { for (auto target : targets) {
if (target.notifyHandshake) { if (target.notifyHandshake) {
@ -169,5 +174,4 @@ namespace pEp {
return PEP_STATUS_OK; return PEP_STATUS_OK;
} }
}; }; // namespace pEp

12
callback_dispatcher.hh → src/callback_dispatcher.hh

@ -34,8 +34,7 @@ namespace pEp {
::messageToSend_t messageToSend, ::messageToSend_t messageToSend,
::notifyHandshake_t notifyHandshake, ::notifyHandshake_t notifyHandshake,
proc on_startup = nullptr, proc on_startup = nullptr,
proc on_shutdown = nullptr proc on_shutdown = nullptr);
);
void remove(::messageToSend_t messageToSend); void remove(::messageToSend_t messageToSend);
static void start_sync(); static void start_sync();
@ -45,8 +44,8 @@ namespace pEp {
static PEP_STATUS notifyHandshake( static PEP_STATUS notifyHandshake(
::pEp_identity *me, ::pEp_identity *me,
::pEp_identity *partner, ::pEp_identity *partner,
::sync_handshake_signal signal ::sync_handshake_signal signal);
);
protected: protected:
void on_startup(); void on_startup();
void on_shutdown(); void on_shutdown();
@ -55,13 +54,12 @@ namespace pEp {
PEP_STATUS _notifyHandshake( PEP_STATUS _notifyHandshake(
::pEp_identity *me, ::pEp_identity *me,
::pEp_identity *partner, ::pEp_identity *partner,
::sync_handshake_signal signal ::sync_handshake_signal signal);
);
friend const char *PassphraseCache::add(const std::string &passphrase); friend const char *PassphraseCache::add(const std::string &passphrase);
}; };
extern CallbackDispatcher callback_dispatcher; extern CallbackDispatcher callback_dispatcher;
} } // namespace pEp
#endif // LIBPEPADAPTER_CALLBACK_DISPATCHER_HH #endif // LIBPEPADAPTER_CALLBACK_DISPATCHER_HH

21
src/constant_time_algo.cc

@ -0,0 +1,21 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "constant_time_algo.hh"
namespace pEp {
bool constant_time_equal(const std::string &a, const std::string &b)
{
if (a.size() != b.size())
return false;
unsigned d = 0;
for (std::size_t idx = 0; idx < a.size(); ++idx) {
d |= (static_cast<unsigned>(a[idx]) ^ static_cast<unsigned>(b[idx]));
}
// if d is still 0, the strings are equal.
return d == 0;
}
} // end of namespace pEp

3
constant_time_algo.hh → src/constant_time_algo.hh

@ -6,8 +6,7 @@
#include <string> #include <string>
namespace pEp namespace pEp {
{
// Returns false if a.size() != b.size(). // Returns false if a.size() != b.size().
// Compares always _all_ characters of 'a' and 'b' so runtime does not // Compares always _all_ characters of 'a' and 'b' so runtime does not
// depends on the character position where the strings differ. // depends on the character position where the strings differ.

21
locked_queue.hh → src/locked_queue.hh

@ -8,11 +8,9 @@
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
namespace utility namespace utility {
{
template<class T, void (*Deleter)(T) = nullptr> template<class T, void (*Deleter)(T) = nullptr>
class locked_queue class locked_queue {
{
typedef std::recursive_mutex Mutex; typedef std::recursive_mutex Mutex;
typedef std::unique_lock<Mutex> Lock; typedef std::unique_lock<Mutex> Lock;
@ -30,10 +28,8 @@ namespace utility
void clear() void clear()
{ {
Lock L(_mtx); Lock L(_mtx);
if(Deleter != nullptr) if (Deleter != nullptr) {
{ for (auto q : _q) {
for(auto q : _q)
{
Deleter(q); Deleter(q);
} }
} }
@ -86,8 +82,7 @@ namespace utility
{ {
Lock L(_mtx); Lock L(_mtx);
++_waiting; ++_waiting;
if(! _cv.wait_until(L, end_time, [this]{ return !_q.empty(); } ) ) if (!_cv.wait_until(L, end_time, [this] { return !_q.empty(); })) {
{
--_waiting; --_waiting;
return false; return false;
} }
@ -104,8 +99,7 @@ namespace utility
{ {
Lock L(_mtx); Lock L(_mtx);
++_waiting; ++_waiting;
if(! _cv.wait_until(L, end_time, [this]{ return !_q.empty(); } ) ) if (!_cv.wait_until(L, end_time, [this] { return !_q.empty(); })) {
{
--_waiting; --_waiting;
return false; return false;
} }
@ -122,8 +116,7 @@ namespace utility
{ {
Lock L(_mtx); Lock L(_mtx);
++_waiting; ++_waiting;
if(! _cv.wait_for(L, duration, [this]{ return !_q.empty(); } ) ) if (!_cv.wait_for(L, duration, [this] { return !_q.empty(); })) {
{
--_waiting; --_waiting;
return false; return false;
} }

131
message_cache.cc → src/message_cache.cc

@ -25,11 +25,9 @@ namespace pEp {
message **dst, message **dst,
stringlist_t **keylist, stringlist_t **keylist,
PEP_rating *rating, PEP_rating *rating,
PEP_decrypt_flags_t *flags PEP_decrypt_flags_t *flags)
)
{ {
return message_cache.decrypt_message(session, src, dst, keylist, return message_cache.decrypt_message(session, src, dst, keylist, rating, flags);
rating, flags);
} }
PEP_STATUS MessageCache::cache_mime_encode_message( PEP_STATUS MessageCache::cache_mime_encode_message(
@ -37,23 +35,19 @@ namespace pEp {
const message *msg, const message *msg,
bool omit_fields, bool omit_fields,
char **mimetext, char **mimetext,
bool has_pEp_msg_attachment bool has_pEp_msg_attachment)
)
{ {
which _one = (which)one; which _one = (which)one;
return message_cache.mime_encode_message(_one, msg, omit_fields, return message_cache.mime_encode_message(_one, msg, omit_fields, mimetext, has_pEp_msg_attachment);
mimetext, has_pEp_msg_attachment);
} }
PEP_STATUS MessageCache::cache_mime_decode_message( PEP_STATUS MessageCache::cache_mime_decode_message(
const char *mimetext, const char *mimetext,
size_t size, size_t size,
message **msg, message **msg,
bool* has_possible_pEp_msg bool *has_possible_pEp_msg)
)
{ {
return message_cache.mime_decode_message(mimetext, size, msg, return message_cache.mime_decode_message(mimetext, size, msg, has_possible_pEp_msg);
has_possible_pEp_msg);
} }
PEP_STATUS MessageCache::cache_encrypt_message( PEP_STATUS MessageCache::cache_encrypt_message(
@ -62,11 +56,9 @@ namespace pEp {
stringlist_t *extra, stringlist_t *extra,
message **dst, message **dst,
PEP_enc_format enc_format, PEP_enc_format enc_format,
PEP_encrypt_flags_t flags PEP_encrypt_flags_t flags)
)
{ {
return message_cache.encrypt_message(session, src, extra, dst, return message_cache.encrypt_message(session, src, extra, dst, enc_format, flags);
enc_format, flags);
} }
PEP_STATUS MessageCache::cache_encrypt_message_for_self( PEP_STATUS MessageCache::cache_encrypt_message_for_self(
@ -76,11 +68,10 @@ namespace pEp {
stringlist_t *extra, stringlist_t *extra,
message **dst, message **dst,
PEP_enc_format enc_format, PEP_enc_format enc_format,
PEP_encrypt_flags_t flags PEP_encrypt_flags_t flags)
)
{ {
return message_cache.encrypt_message_for_self(session, target_id, src, return message_cache
extra, dst, enc_format, flags); .encrypt_message_for_self(session, target_id, src, extra, dst, enc_format, flags);
} }
PEP_STATUS MessageCache::cache_release(std::string id) PEP_STATUS MessageCache::cache_release(std::string id)
@ -96,8 +87,8 @@ namespace pEp {
::free_message(_cache.at(id).src); ::free_message(_cache.at(id).src);
::free_message(_cache.at(id).dst); ::free_message(_cache.at(id).dst);
_cache.erase(id); _cache.erase(id);
} catch (...) {
} }
catch (...) { }
} }
static char *dup(const char *src) static char *dup(const char *src)
@ -173,12 +164,12 @@ namespace pEp {
return dst; return dst;
} }
static ::message_ref_list *dup(const ::message_ref_list *src) { static ::message_ref_list *dup(const ::message_ref_list *src)
{
if (!src) if (!src)
return nullptr; return nullptr;
::message_ref_list *dst = (::message_ref_list *) ::calloc(1, ::message_ref_list *dst = (::message_ref_list *)::calloc(1, sizeof(::message_ref_list));
sizeof(::message_ref_list));
assert(dst); assert(dst);
if (!dst) if (!dst)
throw std::bad_alloc(); throw std::bad_alloc();
@ -187,8 +178,7 @@ namespace pEp {
for (const message_ref_list *s = src; s; s = s->next) { for (const message_ref_list *s = src; s; s = s->next) {
d->msg_ref = s->msg_ref; d->msg_ref = s->msg_ref;
if (s->next) { if (s->next) {
d->next = (::message_ref_list *) ::calloc(1, d->next = (::message_ref_list *)::calloc(1, sizeof(::message_ref_list));
sizeof(::message_ref_list));
assert(d); assert(d);
if (!d) if (!d)
throw std::bad_alloc(); throw std::bad_alloc();
@ -251,9 +241,9 @@ namespace pEp {
if (_id == "") { if (_id == "") {
dst->opt_fields = dup(src->opt_fields); dst->opt_fields = dup(src->opt_fields);
} } else {
else { dst->opt_fields = ::new_stringpair_list(
dst->opt_fields = ::new_stringpair_list(::new_stringpair("X-pEp-Adapter-Cache-ID", _id.c_str())); ::new_stringpair("X-pEp-Adapter-Cache-ID", _id.c_str()));
if (!dst->opt_fields) if (!dst->opt_fields)
throw std::bad_alloc(); throw std::bad_alloc();
dst->opt_fields->next = dup(src->opt_fields); dst->opt_fields->next = dup(src->opt_fields);
@ -274,8 +264,7 @@ namespace pEp {
// order of attachments // order of attachments
if (std::string(bl->mime_type) == "application/octet-stream" && if (std::string(bl->mime_type) == "application/octet-stream" &&
std::string(bl->next->mime_type) == std::string(bl->next->mime_type) == "application/pgp-encrypted") {
"application/pgp-encrypted") {
bloblist_t *one = bl->next; bloblist_t *one = bl->next;
bloblist_t *two = bl; bloblist_t *two = bl;
bl = one; bl = one;
@ -306,8 +295,7 @@ namespace pEp {
message **dst, message **dst,
stringlist_t **keylist, stringlist_t **keylist,
PEP_rating *rating, PEP_rating *rating,
PEP_decrypt_flags_t *flags PEP_decrypt_flags_t *flags)
)
{ {
if (!src || cacheID(src) == "") if (!src || cacheID(src) == "")
return PEP_ILLEGAL_VALUE; return PEP_ILLEGAL_VALUE;
@ -324,8 +312,7 @@ namespace pEp {
correctAttachmentsOrder(src->attachments); correctAttachmentsOrder(src->attachments);
::message *_dst = nullptr; ::message *_dst = nullptr;
PEP_STATUS status = ::decrypt_message(session, src, &_dst, keylist, PEP_STATUS status = ::decrypt_message(session, src, &_dst, keylist, rating, flags);
rating, flags);
*dst = empty_message_copy(_dst, _id); *dst = empty_message_copy(_dst, _id);
{ {
@ -342,8 +329,7 @@ namespace pEp {
const message *msg, const message *msg,
bool omit_fields, bool omit_fields,
char **mimetext, char **mimetext,
bool has_pEp_msg_attachment bool has_pEp_msg_attachment)
)
{ {
if (!msg || cacheID(msg) == "") if (!msg || cacheID(msg) == "")
return PEP_ILLEGAL_VALUE; return PEP_ILLEGAL_VALUE;
@ -357,16 +343,14 @@ namespace pEp {
std::lock_guard<std::mutex> l(_mtx); std::lock_guard<std::mutex> l(_mtx);
::message *_src = _cache.at(cacheID(msg)).src; ::message *_src = _cache.at(cacheID(msg)).src;
swapContent(_msg, _src); swapContent(_msg, _src);
} } else /* msg_dst */ {
else /* msg_dst */ {
std::lock_guard<std::mutex> l(_mtx); std::lock_guard<std::mutex> l(_mtx);
::message *_dst = _cache.at(cacheID(msg)).dst; ::message *_dst = _cache.at(cacheID(msg)).dst;
swapContent(_msg, _dst); swapContent(_msg, _dst);
} }
removeCacheID(_msg); removeCacheID(_msg);
PEP_STATUS status = ::mime_encode_message(_msg, omit_fields, mimetext, PEP_STATUS status = ::mime_encode_message(_msg, omit_fields, mimetext, has_pEp_msg_attachment);
has_pEp_msg_attachment);
::free_message(_msg); ::free_message(_msg);
cache_release(cacheID(msg)); cache_release(cacheID(msg));
@ -383,18 +367,15 @@ namespace pEp {
// if opt_fields is an empty list generate a new list // if opt_fields is an empty list generate a new list
if (!msg->opt_fields || !msg->opt_fields->value) { if (!msg->opt_fields || !msg->opt_fields->value) {
free_stringpair_list(msg->opt_fields); free_stringpair_list(msg->opt_fields);
msg->opt_fields = msg->opt_fields = ::new_stringpair_list(
::new_stringpair_list(::new_stringpair("X-pEp-Adapter-Cache-ID", ::new_stringpair("X-pEp-Adapter-Cache-ID", cid.c_str()));
cid.c_str()));
if (!msg->opt_fields) if (!msg->opt_fields)
throw std::bad_alloc(); throw std::bad_alloc();
} } else {
else {
// add the cache ID as first field to an existing list // add the cache ID as first field to an existing list
auto spl = msg->opt_fields; auto spl = msg->opt_fields;
msg->opt_fields = msg->opt_fields = ::new_stringpair_list(
::new_stringpair_list(::new_stringpair("X-pEp-Adapter-Cache-ID", ::new_stringpair("X-pEp-Adapter-Cache-ID", cid.c_str()));
cid.c_str()));
if (!msg->opt_fields) { if (!msg->opt_fields) {
msg->opt_fields = spl; msg->opt_fields = spl;
throw std::bad_alloc(); throw std::bad_alloc();
@ -407,8 +388,7 @@ namespace pEp {
{ {
for (auto spl = msg->opt_fields; spl && spl->value; spl = spl->next) { for (auto spl = msg->opt_fields; spl && spl->value; spl = spl->next) {
assert(spl->value->key); assert(spl->value->key);
if (spl->value->key && std::string(spl->value->key) == if (spl->value->key && std::string(spl->value->key) == "X-pEp-Adapter-Cache-ID") {
"X-pEp-Adapter-Cache-ID") {
assert(spl->value->value); assert(spl->value->value);
if (spl->value->value) if (spl->value->value)
return spl->value->value; return spl->value->value;
@ -422,23 +402,18 @@ namespace pEp {
void MessageCache::removeCacheID(::message *msg) void MessageCache::removeCacheID(::message *msg)
{ {
// if the first element in the list is the cache ID then skip // if the first element in the list is the cache ID then skip
if (msg->opt_fields && msg->opt_fields->value && if (msg->opt_fields && msg->opt_fields->value && msg->opt_fields->value->key &&
msg->opt_fields->value->key && std::string(msg->opt_fields->value->key) == "X-pEp-Adapter-Cache-ID") {
std::string(msg->opt_fields->value->key) ==
"X-pEp-Adapter-Cache-ID") {
auto n = msg->opt_fields->next; auto n = msg->opt_fields->next;
msg->opt_fields->next = nullptr; msg->opt_fields->next = nullptr;
::free_stringpair_list(msg->opt_fields); ::free_stringpair_list(msg->opt_fields);
msg->opt_fields = n; msg->opt_fields = n;
} } else {
else {
// go through the list and remove // go through the list and remove
::stringpair_list_t *prev = nullptr; ::stringpair_list_t *prev = nullptr;
for (auto spl = msg->opt_fields; spl && spl->value; spl = for (auto spl = msg->opt_fields; spl && spl->value; spl = spl->next) {
spl->next) {
assert(spl->value->key); assert(spl->value->key);
if (spl->value->key && if (spl->value->key && std::string(spl->value->key) == "X-pEp-Adapter-Cache-ID") {
std::string(spl->value->key) == "X-pEp-Adapter-Cache-ID") {
auto next = spl->next; auto next = spl->next;
spl->next = nullptr; spl->next = nullptr;
::free_stringpair_list(spl); ::free_stringpair_list(spl);
@ -454,21 +429,19 @@ namespace pEp {
const char *mimetext, const char *mimetext,
size_t size, size_t size,
message **msg, message **msg,
bool* has_possible_pEp_msg bool *has_possible_pEp_msg)
)
{ {
::message *_msg = nullptr; ::message *_msg = nullptr;
PEP_STATUS status = ::mime_decode_message(mimetext, size, &_msg, PEP_STATUS status = ::mime_decode_message(mimetext, size, &_msg, has_possible_pEp_msg);
has_possible_pEp_msg);
if (status) if (status)
return status; return status;
generateCacheID(_msg); *msg = empty_message_copy(_msg); generateCacheID(_msg);
*msg = empty_message_copy(_msg);
{ {
std::lock_guard<std::mutex> l(_mtx); std::lock_guard<std::mutex> l(_mtx);
message_cache._cache.emplace(std::make_pair(cacheID(_msg), message_cache._cache.emplace(std::make_pair(cacheID(_msg), cache_entry(_msg, nullptr)));
cache_entry(_msg, nullptr)));
} }
return status; return status;
@ -480,8 +453,7 @@ namespace pEp {
stringlist_t *extra, stringlist_t *extra,
message **dst, message **dst,
PEP_enc_format enc_format, PEP_enc_format enc_format,
PEP_encrypt_flags_t flags PEP_encrypt_flags_t flags)
)
{ {
::message *_msg; ::message *_msg;
std::string _id = cacheID(src); std::string _id = cacheID(src);
@ -492,8 +464,7 @@ namespace pEp {
} }
::message *_dst = nullptr; ::message *_dst = nullptr;
PEP_STATUS status = ::encrypt_message(session, src, extra, &_dst, PEP_STATUS status = ::encrypt_message(session, src, extra, &_dst, enc_format, flags);
enc_format, flags);
*dst = empty_message_copy(_dst, _id); *dst = empty_message_copy(_dst, _id);
{ {
@ -513,8 +484,7 @@ namespace pEp {
stringlist_t *extra, stringlist_t *extra,
message **dst, message **dst,
PEP_enc_format enc_format, PEP_enc_format enc_format,
PEP_encrypt_flags_t flags PEP_encrypt_flags_t flags)
)
{ {
::message *_msg; ::message *_msg;
std::string _id = cacheID(src); std::string _id = cacheID(src);
@ -525,8 +495,14 @@ namespace pEp {
} }
::message *_dst = nullptr; ::message *_dst = nullptr;
PEP_STATUS status = ::encrypt_message_for_self(session, target_id, src, PEP_STATUS status = ::encrypt_message_for_self(
extra, &_dst, enc_format, flags); session,
target_id,
src,
extra,
&_dst,
enc_format,
flags);
*dst = empty_message_copy(_dst, _id); *dst = empty_message_copy(_dst, _id);
{ {
@ -538,5 +514,4 @@ namespace pEp {
return status; return status;
} }
}; }; // namespace pEp

128
src/message_cache.hh

@ -0,0 +1,128 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef LIBPEPADAPTER_MESSAGE_CACHE_HH
#define LIBPEPADAPTER_MESSAGE_CACHE_HH
#include <string>
#include <unordered_map>
#include <mutex>
#include <pEp/message_api.h>
#include <pEp/mime.h>
namespace pEp {
class MessageCache {
struct cache_entry {
cache_entry(::message *s, ::message *d) : src(s), dst(d) {}
::message *src;
::message *dst;
};
using cache = std::unordered_map<std::string, cache_entry>;
cache _cache;
std::mutex _mtx;
long long id_range = 42;
long long next_id = 23;
public:
MessageCache();
enum which
{
msg_src = 0,
msg_dst = 1
};
static PEP_STATUS cache_mime_decode_message(
const char *mimetext,
size_t size,
message **msg,
bool *has_possible_pEp_msg);
static PEP_STATUS cache_mime_encode_message(
int one,
const message *msg,
bool omit_fields,
char **mimetext,
bool has_pEp_msg_attachment);
static PEP_STATUS cache_decrypt_message(
PEP_SESSION session,
message *src,
message **dst,
stringlist_t **keylist,
PEP_rating *rating,
PEP_decrypt_flags_t *flags);
static PEP_STATUS cache_encrypt_message(
PEP_SESSION session,
message *src,
stringlist_t *extra,
message **dst,
PEP_enc_format enc_format,
PEP_encrypt_flags_t flags);
static PEP_STATUS cache_encrypt_message_for_self(
PEP_SESSION session,
pEp_identity *target_id,
message *src,
stringlist_t *extra,
message **dst,
PEP_enc_format enc_format,
PEP_encrypt_flags_t flags);
static PEP_STATUS cache_release(std::string id);
static void removeCacheID(::message *msg);
protected:
void release(std::string id);
PEP_STATUS mime_decode_message(
const char *mimetext,
size_t size,
message **msg,
bool *has_possible_pEp_msg);
PEP_STATUS mime_encode_message(
which one,
const message *src,
bool omit_fields,
char **mimetext,
bool has_pEp_msg_attachment);
PEP_STATUS decrypt_message(
PEP_SESSION session,
message *src,
message **dst,
stringlist_t **keylist,
PEP_rating *rating,
PEP_decrypt_flags_t *flags);
PEP_STATUS encrypt_message(
PEP_SESSION session,
message *src,
stringlist_t *extra,
message **dst,
PEP_enc_format enc_format,
PEP_encrypt_flags_t flags);
PEP_STATUS encrypt_message_for_self(
PEP_SESSION session,
pEp_identity *target_id,
message *src,
stringlist_t *extra,
message **dst,
PEP_enc_format enc_format,
PEP_encrypt_flags_t flags);
void generateCacheID(::message *msg);
static std::string cacheID(const ::message *msg);
};
extern MessageCache message_cache;
}; // namespace pEp
#endif // LIBPEPADAPTER_MESSAGE_CACHE_HH

43
src/pEpLog.cc

@ -0,0 +1,43 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "pEpLog.hh"
#include <iostream>
#include <sstream>
#include <mutex>
#include <atomic>
namespace pEp {
namespace Adapter {
namespace pEpLog {
std::mutex mtx;
std::atomic_bool is_enabled{false};
void set_enabled(bool enabled)
{
is_enabled.store(enabled);
}
bool get_enabled()
{
return is_enabled.load();
}
void log(std::string msg)
{
if (is_enabled.load()) {
std::lock_guard<std::mutex> l(mtx);
#ifdef ANDROID
__android_log_print(ANDROID_LOG_DEBUG, "pEpDebugLog", "%s", msg.c_str());
#else
std::cout << msg << std::endl; //std::endl also flushes
#endif
}
}
} // namespace pEpLog
} // namespace Adapter
} // namespace pEp

11
pEpLog.hh → src/pEpLog.hh

@ -32,7 +32,9 @@
// use set_enabled_<backend>(bool) to turn logging on/off per backend // use set_enabled_<backend>(bool) to turn logging on/off per backend
#ifdef NDEBUG #ifdef NDEBUG
#define pEpLog(msg) do{}while(0) #define pEpLog(msg) \
do { \
} while (0)
#else #else
#define pEpLog(msg) \ #define pEpLog(msg) \
do { \ do { \
@ -52,10 +54,9 @@ void set_enabled(bool is_enabled);
bool get_enabled(); bool get_enabled();
} // pEpLog } // namespace pEpLog
} // Adapter } // namespace Adapter
} // pEp } // namespace pEp
#endif // LIBPEPADAPTER_PEPLOG_HH #endif // LIBPEPADAPTER_PEPLOG_HH

35
passphrase_cache.cc → src/passphrase_cache.cc

@ -9,19 +9,19 @@
pEp::PassphraseCache pEp::passphrase_cache; pEp::PassphraseCache pEp::passphrase_cache;
namespace pEp { namespace pEp {
PassphraseCache::cache_entry::cache_entry(const std::string& p, time_point t) : PassphraseCache::cache_entry::cache_entry(const std::string& p, time_point t)
passphrase{p, 0, PassphraseCache::cache_entry::max_len}, tp{t} : passphrase{p, 0, PassphraseCache::cache_entry::max_len}, tp{t}
{ } {
}
PassphraseCache::PassphraseCache(size_t max_size, duration timeout) :
_max_size{max_size}, _timeout{timeout}, _which(_cache.end()), PassphraseCache::PassphraseCache(size_t max_size, duration timeout)
first_time(true) : _max_size{max_size}, _timeout{timeout}, _which(_cache.end()), first_time(true)
{ } {
}
PassphraseCache::PassphraseCache(const PassphraseCache& second) :
_cache{second._cache}, _max_size{second._max_size}, PassphraseCache::PassphraseCache(const PassphraseCache& second)
_timeout{second._timeout}, _stored{second._stored}, : _cache{second._cache}, _max_size{second._max_size}, _timeout{second._timeout},
_which(_cache.end()), first_time(true) _stored{second._stored}, _which(_cache.end()), first_time(true)
{ {
cleanup(); cleanup();
} }
@ -146,12 +146,10 @@ namespace pEp {
try { try {
::config_passphrase(session ? session : Adapter::session(), latest_passphrase(_copy)); ::config_passphrase(session ? session : Adapter::session(), latest_passphrase(_copy));
return PEP_STATUS_OK; return PEP_STATUS_OK;
} } catch (pEp::PassphraseCache::Empty&) {
catch (pEp::PassphraseCache::Empty&) {
new_copy = true; new_copy = true;
return PEP_PASSPHRASE_REQUIRED; return PEP_PASSPHRASE_REQUIRED;
} } catch (pEp::PassphraseCache::Exhausted&) {
catch (pEp::PassphraseCache::Exhausted&) {
new_copy = true; new_copy = true;
return PEP_WRONG_PASSPHRASE; return PEP_WRONG_PASSPHRASE;
} }
@ -172,5 +170,4 @@ namespace pEp {
return status; return status;
} }
}; }; // namespace pEp

6
passphrase_cache.hh → src/passphrase_cache.hh

@ -71,8 +71,8 @@ namespace pEp {
// status = ::encrypt_message(session, src, extra, dst, enc_format, flags) // status = ::encrypt_message(session, src, extra, dst, enc_format, flags)
// using for_each_passphrase() // using for_each_passphrase()
template<typename... A> PEP_STATUS api(PEP_STATUS f(PEP_SESSION, A...), template<typename... A>
PEP_SESSION session, A... a); PEP_STATUS api(PEP_STATUS f(PEP_SESSION, A...), PEP_SESSION session, A... a);
static const char* latest_passphrase(PassphraseCache& _cache); static const char* latest_passphrase(PassphraseCache& _cache);
using passphrase_callee = std::function<bool(std::string)>; using passphrase_callee = std::function<bool(std::string)>;
@ -85,7 +85,7 @@ namespace pEp {
}; };
extern PassphraseCache passphrase_cache; extern PassphraseCache passphrase_cache;
}; }; // namespace pEp
#include "passphrase_cache.hxx" #include "passphrase_cache.hxx"

9
passphrase_cache.hxx → src/passphrase_cache.hxx

@ -7,8 +7,8 @@
#include "passphrase_cache.hh" #include "passphrase_cache.hh"
namespace pEp { namespace pEp {
template<typename... A> PEP_STATUS PassphraseCache::api( template<typename... A>
PEP_STATUS f(PEP_SESSION, A...), PEP_SESSION session, A... a) PEP_STATUS PassphraseCache::api(PEP_STATUS f(PEP_SESSION, A...), PEP_SESSION session, A... a)
{ {
PEP_STATUS status; PEP_STATUS status;
@ -18,12 +18,11 @@ namespace pEp {
return true; return true;
status = f(session, a...); status = f(session, a...);
return status != PEP_PASSPHRASE_REQUIRED && return status != PEP_PASSPHRASE_REQUIRED && status != PEP_WRONG_PASSPHRASE;
status != PEP_WRONG_PASSPHRASE;
}); });
return status; return status;
} }
}; }; // namespace pEp
#endif // LIBPEPADAPTER_PASSPHRASE_CACHE_HXX #endif // LIBPEPADAPTER_PASSPHRASE_CACHE_HXX

0
pc_container.hh → src/pc_container.hh

21
src/slurp.cc

@ -0,0 +1,21 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "slurp.hh"
#include <fstream>
#include <sstream>
#include <stdexcept>
namespace pEp {
std::string slurp(const std::string& filename)
{
std::ifstream input(filename.c_str(), std::ios_base::binary);
if (!input) {
throw std::runtime_error("Cannot read file \"" + filename + "\"! ");
}
std::stringstream sstr;
sstr << input.rdbuf();
return sstr.str();
}
} // end of namespace pEp

3
slurp.hh → src/slurp.hh

@ -6,8 +6,7 @@
#include <string> #include <string>
namespace pEp namespace pEp {
{
// reads a whole file and returns it as std::string // reads a whole file and returns it as std::string
// throws std::runtime_error() if the file cannot be read. Empty file is not an error. // throws std::runtime_error() if the file cannot be read. Empty file is not an error.
std::string slurp(const std::string& filename); std::string slurp(const std::string& filename);

23
src/status_to_string.cc

@ -0,0 +1,23 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "status_to_string.hh"
#include <sstream>
namespace pEp {
// in pEpEngine.h positive values are hex, negative are decimal. :-o
// TODO: the code should be generated!
std::string status_to_string(PEP_STATUS status)
{
std::stringstream ss;
if (status > 0) {
ss << "0x" << std::hex << status;
} else {
ss << status;
}
return ss.str() + " \"" + pEp_status_to_string(status) + '"';
}
} // end of namespace pEp

3
status_to_string.hh → src/status_to_string.hh

@ -8,8 +8,7 @@
#include <pEp/status_to_string.h> #include <pEp/status_to_string.h>
#include <string> #include <string>
namespace pEp namespace pEp {
{
// creates a textual string (returned by pep_status_to_string() ) and the numerical status value. // creates a textual string (returned by pep_status_to_string() ) and the numerical status value.
// in pEpEngine.h positive values are in hex value, negatives in decimal. So we follow this. // in pEpEngine.h positive values are in hex value, negatives in decimal. So we follow this.
std::string status_to_string(PEP_STATUS status); std::string status_to_string(PEP_STATUS status);

25
status_to_string.cc

@ -1,25 +0,0 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "status_to_string.hh"
#include <sstream>
namespace pEp
{
// in pEpEngine.h positive values are hex, negative are decimal. :-o
// TODO: the code should be generated!
std::string status_to_string(PEP_STATUS status)
{
std::stringstream ss;
if(status>0)
{
ss << "0x" << std::hex << status;
}else{
ss << status;
}
return ss.str() + " \"" + pEp_status_to_string(status) + '"';
}
} // end of namespace pEp

5
test/Makefile

@ -1,9 +1,8 @@
include ../Makefile.conf include ../Makefile.conf
LDFLAGS=-L../ $(ENGINE_LIB) LDFLAGS=-L../src $(ENGINE_LIB)
LDLIBS=-lstdc++ -lpEpEngine -lpEpAdapter LDLIBS=-lstdc++ -lpEpEngine -lpEpAdapter
CXXFLAGS+=-I../ $(ENGINE_INC) -std=c++11 -DENGINE_TEST=$(ENGINE_TEST) CXXFLAGS:=-I../src -DENGINE_TEST=$(ENGINE_TEST) $(CXXFLAGS)
SRC=$(wildcard test_*.cc) SRC=$(wildcard test_*.cc)
TST=$(subst .cc,,$(SRC)) TST=$(subst .cc,,$(SRC))

45
test/framework.cc

@ -1,5 +1,7 @@
#include "framework.hh" // This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "framework.hh"
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
@ -20,6 +22,8 @@
#include <pEp/sync_codec.h> #include <pEp/sync_codec.h>
#include <pEp/distribution_codec.h> #include <pEp/distribution_codec.h>
#include <Adapter.hh>
pEp::Test::Transport pEp::Test::transport; pEp::Test::Transport pEp::Test::transport;
std::string pEp::Test::path; std::string pEp::Test::path;
extern std::thread pEp::Adapter::_sync_thread; extern std::thread pEp::Adapter::_sync_thread;
@ -45,11 +49,9 @@ namespace pEp {
cout << "usage: " << args[0] << " [--dir HOME]" << endl; cout << "usage: " << args[0] << " [--dir HOME]" << endl;
#endif #endif
exit(0); exit(0);
} } else if (args[1] == "--dir" && args.size() == 3) {
else if (args[1] == "--dir" && args.size() == 3) {
dir = args[2]; dir = args[2];
} } else {
else {
cerr << "illegal parameter" << endl; cerr << "illegal parameter" << endl;
exit(1); exit(1);
} }
@ -83,7 +85,10 @@ namespace pEp {
ifstream f(filename, ifstream::in); ifstream f(filename, ifstream::in);
string key{ istreambuf_iterator<char>(f), istreambuf_iterator<char>() }; string key{ istreambuf_iterator<char>(f), istreambuf_iterator<char>() };
::identity_list *il = NULL; ::identity_list *il = NULL;
PEP_STATUS status = ::import_key(session(), key.c_str(), key.length(), &il); cout << key.c_str() << endl;
cout << key.length() << endl;
::PEP_STATUS status = ::import_key(session(), key.c_str(), key.length(), &il);
throw_status(status);
assert(status == PEP_KEY_IMPORTED); assert(status == PEP_KEY_IMPORTED);
::free_identity_list(il); ::free_identity_list(il);
} }
@ -102,7 +107,11 @@ namespace pEp {
{ {
::message *msg; ::message *msg;
bool has_possible_pEp_msg; bool has_possible_pEp_msg;
PEP_STATUS status = ::mime_decode_message(text.c_str(), text.length(), &msg, &has_possible_pEp_msg); ::PEP_STATUS status = ::mime_decode_message(
text.c_str(),
text.length(),
&msg,
&has_possible_pEp_msg);
throw_status(status); throw_status(status);
return make_message(msg); return make_message(msg);
} }
@ -123,9 +132,9 @@ namespace pEp {
::message *_dst; ::message *_dst;
stringlist_t *keylist; stringlist_t *keylist;
PEP_rating rating; ::PEP_rating rating;
PEP_decrypt_flags_t flags = 0; ::PEP_decrypt_flags_t flags = 0;
PEP_STATUS status = ::decrypt_message(session(), msg.get(), &_dst, &keylist, &rating, &flags); ::PEP_STATUS status = ::decrypt_message(session(), msg.get(), &_dst, &keylist, &rating, &flags);
throw_status(status); throw_status(status);
Message dst; Message dst;
@ -138,18 +147,17 @@ namespace pEp {
for (auto a = dst.get()->attachments; a && a->value; a = a->next) { for (auto a = dst.get()->attachments; a && a->value; a = a->next) {
if (string("application/pEp.sync") == a->mime_type) { if (string("application/pEp.sync") == a->mime_type) {
char *_text; char *_text;
status = PER_to_XER_Sync_msg(a->value, a->size, &_text); status = ::PER_to_XER_Sync_msg(a->value, a->size, &_text);
throw_status(status); throw_status(status);
text += _text; text += _text;
pEp_free(_text); ::pEp_free(_text);
return text; return text;
} } else if (string("application/pEp.distribution") == a->mime_type) {
else if (string("application/pEp.distribution") == a->mime_type) {
char *_text; char *_text;
status = PER_to_XER_Distribution_msg(a->value, a->size, &_text); status = ::PER_to_XER_Distribution_msg(a->value, a->size, &_text);
throw_status(status); throw_status(status);
text += _text; text += _text;
pEp_free(_text); ::pEp_free(_text);
return text; return text;
} }
} }
@ -175,7 +183,6 @@ namespace pEp {
void Transport::send(Message msg) void Transport::send(Message msg)
{ {
mkdir(outbox_path.c_str(), 0770); mkdir(outbox_path.c_str(), 0770);
} }
}; }; // namespace Test
}; }; // namespace pEp

7
test/framework.hh

@ -1,5 +1,6 @@
// This file is under GNU General Public License 3.0 // This file is under GNU General Public License 3.0
// see LICENSE.txt // see LICENSE.txt
#ifndef LIBPEPADAPTER_FRAMEWORK_HH #ifndef LIBPEPADAPTER_FRAMEWORK_HH
#define LIBPEPADAPTER_FRAMEWORK_HH #define LIBPEPADAPTER_FRAMEWORK_HH
@ -7,7 +8,7 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include "Adapter.hh" #include <pEp/message.h>
namespace pEp { namespace pEp {
namespace Test { namespace Test {
@ -57,7 +58,7 @@ namespace pEp {
extern Transport transport; extern Transport transport;
extern string path; extern string path;
}; }; // namespace Test
}; }; // namespace pEp
#endif // LIBPEPADAPTER_FRAMEWORK_HH #endif // LIBPEPADAPTER_FRAMEWORK_HH

22
test/test_adapter.cc

@ -6,11 +6,15 @@
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <sys/param.h> #include <sys/param.h>
#include <pEpLog.hh>
#include <Adapter.hh>
#include <pEp/sync_api.h>
#include <pEp/keymanagement.h> #include <pEp/keymanagement.h>
#include "pEpLog.hh" #include <pEp/message_api.h>
using namespace std; using namespace std;
using namespace pEp::Adapter; using namespace pEp;
PEP_STATUS messageToSend(struct _message *msg) PEP_STATUS messageToSend(struct _message *msg)
{ {
@ -18,7 +22,7 @@ PEP_STATUS messageToSend(struct _message *msg)
return PEP_STATUS_OK; return PEP_STATUS_OK;
} }
PEP_STATUS notifyHandshake(pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal) PEP_STATUS notifyHandshake(::pEp_identity *me, ::pEp_identity *partner, ::sync_handshake_signal signal)
{ {
pEpLog("called()"); pEpLog("called()");
return PEP_STATUS_OK; return PEP_STATUS_OK;
@ -26,14 +30,14 @@ PEP_STATUS notifyHandshake(pEp_identity *me, pEp_identity *partner, sync_handsha
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
pEp::Test::setup(argc, argv); Test::setup(argc, argv);
// Create new identity // Create new identity
pEpLog("updating or creating identity for me"); pEpLog("updating or creating identity for me");
pEp_identity *me = new_identity("alice@peptest.ch", NULL, "23", "Who the F* is Alice"); ::pEp_identity *me = new_identity("alice@peptest.ch", NULL, "23", "Who the F* is Alice");
assert(me); assert(me);
PEP_STATUS status = myself(session(), me); ::PEP_STATUS status = ::myself(Adapter::session(), me);
free_identity(me); ::free_identity(me);
pEp::throw_status(status); pEp::throw_status(status);
// start and stop sync repeatedly // start and stop sync repeatedly
@ -44,10 +48,10 @@ int main(int argc, char **argv)
pEpLog(i); pEpLog(i);
pEpLog("SYNC START"); pEpLog("SYNC START");
pEpLog("starting the adapter including sync"); pEpLog("starting the adapter including sync");
startup(messageToSend, notifyHandshake); Adapter::startup(messageToSend, notifyHandshake);
pEpLog("SYNC STOP"); pEpLog("SYNC STOP");
usleep(sleepuSec); usleep(sleepuSec);
shutdown(); Adapter::shutdown();
} }
return 0; return 0;
} }

40
test/test_adapter_cxx.cc

@ -5,42 +5,51 @@
#include <iostream> #include <iostream>
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <pEp/keymanagement.h> #include <pEp/keymanagement.h>
#include "pEpLog.hh" #include <pEpLog.hh>
#include <pEp/sync_api.h>
#include <Adapter.hh>
using namespace pEp::Adapter; using namespace pEp;
PEP_STATUS messageToSend(struct _message *msg) { PEP_STATUS messageToSend(struct _message *msg)
{
pEpLog("called"); pEpLog("called");
return PEP_STATUS_OK; return PEP_STATUS_OK;
} }
PEP_STATUS notifyHandshake(pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal) { PEP_STATUS notifyHandshake(pEp_identity *me, pEp_identity *partner, ::sync_handshake_signal signal)
{
pEpLog("called"); pEpLog("called");
return PEP_STATUS_OK; return PEP_STATUS_OK;
} }
class JNISync { class JNISync {
public: public:
void onSyncStartup() { void onSyncStartup()
{
pEpLog("called"); pEpLog("called");
} }
void onSyncShutdown() { void onSyncShutdown()
{
pEpLog("called"); pEpLog("called");
} }
} o; } o;
int main(int argc, char **argv) { int main(int argc, char **argv)
{
pEp::Test::setup(argc, argv); pEp::Test::setup(argc, argv);
// Create new identity // Create new identity
pEpLog("updating or creating identity for me"); pEpLog("updating or creating identity for me");
pEp_identity *me = new_identity("alice@peptest.ch", NULL, "23", "Who the F* is Alice"); ::pEp_identity *me = ::new_identity("alice@peptest.ch", NULL, "23", "Who the F* is Alice");
assert(me); assert(me);
PEP_STATUS status = myself(session(), me); ::PEP_STATUS status = ::myself(Adapter::session(), me);
free_identity(me); ::free_identity(me);
pEp::throw_status(status); throw_status(status);
// start and stop sync repeatedly // start and stop sync repeatedly
useconds_t sleepuSec = 1000 * 100; useconds_t sleepuSec = 1000 * 100;
@ -50,10 +59,15 @@ int main(int argc, char **argv) {
pEpLog(i); pEpLog(i);
pEpLog("SYNC START"); pEpLog("SYNC START");
pEpLog("starting the adapter including sync"); pEpLog("starting the adapter including sync");
startup<JNISync>(messageToSend, notifyHandshake, &o, &JNISync::onSyncStartup, &JNISync::onSyncShutdown); Adapter::startup<JNISync>(
messageToSend,
notifyHandshake,
&o,
&JNISync::onSyncStartup,
&JNISync::onSyncShutdown);
pEpLog("SYNC STOP"); pEpLog("SYNC STOP");
usleep(sleepuSec); usleep(sleepuSec);
shutdown(); Adapter::shutdown();
} }
return 0; return 0;
} }

23
test/test_ensure_passphrase.cc

@ -1,3 +1,6 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
@ -9,15 +12,15 @@
#include "framework.hh" #include "framework.hh"
#include "passphrase_cache.hh" #include <passphrase_cache.hh>
#include "status_to_string.hh" #include <status_to_string.hh>
#include <Adapter.hh>
#include <pEp/message_api.h> #include <pEp/message_api.h>
#include <pEp/keymanagement.h> #include <pEp/keymanagement.h>
#include <pEp/key_reset.h> #include <pEp/key_reset.h>
using namespace pEp; using namespace pEp;
using namespace pEp::Adapter;
using namespace std; using namespace std;
int main(int argc, char** argv) int main(int argc, char** argv)
@ -28,7 +31,8 @@ int main(int argc, char **argv)
passphrase_cache.add("cathy"); passphrase_cache.add("cathy");
passphrase_cache.add("bob"); passphrase_cache.add("bob");
const char* bob_filename = ENGINE_TEST "/test_keys/bob-primary-with-password-bob-subkey-without.pgp"; const char* bob_filename = ENGINE_TEST
"/test_keys/bob-primary-with-password-bob-subkey-without.pgp";
const char* bob_fpr = "5C76378A62B04CF3F41BEC8D4940FC9FA1878736"; const char* bob_fpr = "5C76378A62B04CF3F41BEC8D4940FC9FA1878736";
const char* erwin_filename = ENGINE_TEST "/test_keys/erwin_normal_encrypted.pgp"; const char* erwin_filename = ENGINE_TEST "/test_keys/erwin_normal_encrypted.pgp";
@ -37,15 +41,15 @@ int main(int argc, char **argv)
Test::import_key_from_file(bob_filename); Test::import_key_from_file(bob_filename);
Test::import_key_from_file(erwin_filename); Test::import_key_from_file(erwin_filename);
pEp_identity* bob = ::new_identity("bob@example.org", bob_fpr, "BOB", "Bob Dog"); ::pEp_identity* bob = ::new_identity("bob@example.org", bob_fpr, "BOB", "Bob Dog");
PEP_STATUS status = ::set_own_key(session(), bob, bob_fpr); ::PEP_STATUS status = ::set_own_key(Adapter::session(), bob, bob_fpr);
assert(status == PEP_STATUS_OK); assert(status == PEP_STATUS_OK);
pEp_identity* erwin = ::new_identity("erwin@example.org", erwin_fpr, "BOB", "Bob is Erwin"); ::pEp_identity* erwin = ::new_identity("erwin@example.org", erwin_fpr, "BOB", "Bob is Erwin");
status = ::set_own_key(session(), erwin, erwin_fpr); status = ::set_own_key(Adapter::session(), erwin, erwin_fpr);
assert(status == PEP_STATUS_OK); assert(status == PEP_STATUS_OK);
status = ::key_reset_all_own_keys(session()); status = ::key_reset_all_own_keys(Adapter::session());
assert(status == PEP_STATUS_OK); assert(status == PEP_STATUS_OK);
::free_identity(bob); ::free_identity(bob);
@ -55,4 +59,3 @@ int main(int argc, char **argv)
return 0; return 0;
} }

61
test/test_leave_device_group.cc

@ -1,34 +1,32 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <unistd.h> #include <unistd.h>
#include "framework.hh" #include "framework.hh"
#include "passphrase_cache.hh" #include <passphrase_cache.hh>
#include "callback_dispatcher.hh" #include <callback_dispatcher.hh>
#include <pEp/sync_api.h> #include <pEp/sync_api.h>
using namespace pEp;
using namespace pEp::Adapter;
using namespace std; using namespace std;
using namespace pEp;
vector<string> expected_msg = { vector<string> expected_msg = { "synchronizeGroupKeys",
"synchronizeGroupKeys",
"groupKeysUpdate", "groupKeysUpdate",
"initUnledGroupKeyReset", "initUnledGroupKeyReset",
"beacon", "beacon",
"beacon" "beacon" };
};
vector<::sync_handshake_signal> expected_notification = { vector<::sync_handshake_signal> expected_notification = { SYNC_NOTIFY_IN_GROUP,
SYNC_NOTIFY_IN_GROUP,
SYNC_NOTIFY_START, SYNC_NOTIFY_START,
SYNC_NOTIFY_SOLE, SYNC_NOTIFY_SOLE,
SYNC_NOTIFY_START, SYNC_NOTIFY_START,
SYNC_NOTIFY_STOP SYNC_NOTIFY_STOP };
};
PEP_STATUS test_messageToSend(::message *_msg) ::PEP_STATUS test_messageToSend(::message* _msg)
{ {
static auto actual = expected_msg.begin(); static auto actual = expected_msg.begin();
@ -41,7 +39,7 @@ PEP_STATUS test_messageToSend(::message *_msg)
} }
PEP_STATUS test_notifyHandshake(pEp_identity *_me, pEp_identity *_partner, sync_handshake_signal signal) ::PEP_STATUS test_notifyHandshake(::pEp_identity* _me, ::pEp_identity* _partner, sync_handshake_signal signal)
{ {
static auto actual = expected_notification.begin(); static auto actual = expected_notification.begin();
@ -56,14 +54,15 @@ PEP_STATUS test_notifyHandshake(pEp_identity *_me, pEp_identity *_partner, sync_
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
Test::setup(argc, argv); Test::setup(argc, argv);
session(); Adapter::session();
// set up two own identites for sync // set up two own identites for sync
passphrase_cache.add("erwin"); passphrase_cache.add("erwin");
passphrase_cache.add("bob"); passphrase_cache.add("bob");
const char* bob_filename = ENGINE_TEST "/test_keys/bob-primary-with-password-bob-subkey-without.pgp"; const char* bob_filename = ENGINE_TEST
"/test_keys/bob-primary-with-password-bob-subkey-without.pgp";
const char* bob_fpr = "5C76378A62B04CF3F41BEC8D4940FC9FA1878736"; const char* bob_fpr = "5C76378A62B04CF3F41BEC8D4940FC9FA1878736";
const char* erwin_filename = ENGINE_TEST "/test_keys/erwin_normal_encrypted.pgp"; const char* erwin_filename = ENGINE_TEST "/test_keys/erwin_normal_encrypted.pgp";
@ -72,24 +71,26 @@ int main(int argc, char **argv)
Test::import_key_from_file(bob_filename); Test::import_key_from_file(bob_filename);
Test::import_key_from_file(erwin_filename); Test::import_key_from_file(erwin_filename);
Test::Identity bob = Test::make_identity(::new_identity("bob@example.org", bob_fpr, "BOB", "Bob Dog")); Test::Identity bob = Test::make_identity(
PEP_STATUS status = ::set_own_key(session(), bob.get(), bob_fpr); ::new_identity("bob@example.org", bob_fpr, "BOB", "Bob Dog"));
PEP_STATUS status = ::set_own_key(Adapter::session(), bob.get(), bob_fpr);
assert(status == PEP_STATUS_OK); assert(status == PEP_STATUS_OK);
status = ::enable_identity_for_sync(session(), bob.get()); status = ::enable_identity_for_sync(Adapter::session(), bob.get());
assert(status == PEP_STATUS_OK); assert(status == PEP_STATUS_OK);
Test::Identity erwin = Test::make_identity(::new_identity("erwin@example.org", erwin_fpr, "BOB", "Bob is Erwin")); Test::Identity erwin = Test::make_identity(
status = ::set_own_key(session(), erwin.get(), erwin_fpr); ::new_identity("erwin@example.org", erwin_fpr, "BOB", "Bob is Erwin"));
status = ::set_own_key(Adapter::session(), erwin.get(), erwin_fpr);
assert(status == PEP_STATUS_OK); assert(status == PEP_STATUS_OK);
status = ::enable_identity_for_sync(session(), erwin.get()); status = ::enable_identity_for_sync(Adapter::session(), erwin.get());
assert(status == PEP_STATUS_OK); assert(status == PEP_STATUS_OK);
// simulate a device group by setting the identities to in sync // simulate a device group by setting the identities to in sync
status = set_identity_flags(session(), bob.get(), PEP_idf_devicegroup); status = ::set_identity_flags(Adapter::session(), bob.get(), PEP_idf_devicegroup);
status = set_identity_flags(session(), erwin.get(), PEP_idf_devicegroup); status = ::set_identity_flags(Adapter::session(), erwin.get(), PEP_idf_devicegroup);
// register at callback_dispatcher and start sync // register at callback_dispatcher and start sync
@ -98,24 +99,24 @@ int main(int argc, char **argv)
// leave device group // leave device group
status = ::leave_device_group(session());
status = ::leave_device_group(Adapter::session());
// wait for sync shutdown and release first session // wait for sync shutdown and release first session
Test::join_sync_thread(); Test::join_sync_thread();
assert(!is_sync_running()); assert(!Adapter::is_sync_running());
// switch off and on again // switch off and on again
CallbackDispatcher::start_sync(); CallbackDispatcher::start_sync();
sleep(2); sleep(2);
assert(is_sync_running()); assert(Adapter::is_sync_running());
CallbackDispatcher::stop_sync(); CallbackDispatcher::stop_sync();
Test::join_sync_thread(); Test::join_sync_thread();
assert(!is_sync_running()); assert(!Adapter::is_sync_running());
session(Adapter::release); Adapter::session(Adapter::release);
return 0; return 0;
} }

47
test/test_library.cc

@ -1,19 +1,18 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "pc_container.hh" #include "pc_container.hh"
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#include <thread> #include <thread>
using namespace pEp; using namespace pEp;
// Producer's data: // Producer's data:
class P class P {
{
public: public:
P(int i) P(int i) : data{ new char[64] }
: data{new char[64]}
{ {
snprintf(data, 63, "%i", i); snprintf(data, 63, "%i", i);
} }
@ -32,8 +31,7 @@ public:
// Consumer's data: // Consumer's data:
class C class C {
{
public: public:
C(int _i) : i(_i) {} C(int _i) : i(_i) {}
int i; int i;
@ -45,17 +43,12 @@ void consumer_thread()
{ {
bool keep_running = true; bool keep_running = true;
int sum = 0; int sum = 0;
while(keep_running) while (keep_running) {
{ for (auto& q : pc) {
for(auto& q : pc) switch (q.state()) {
{ case PC_State::Created: {
switch(q.state())
{
case PC_State::Created:
{
const int value = atoi(q.pdata->data); const int value = atoi(q.pdata->data);
if(value<0) if (value < 0) {
{
std::cerr << "Q\n"; std::cerr << "Q\n";
keep_running = false; keep_running = false;
} else { } else {
@ -65,15 +58,13 @@ void consumer_thread()
} }
break; break;
} }
case PC_State::Deleted: case PC_State::Deleted: {
{
std::cerr << "D"; std::cerr << "D";
sum -= q.cdata->i; sum -= q.cdata->i;
delete q.cdata; delete q.cdata;
break; break;
} }
case PC_State::Changed: case PC_State::Changed: {
{
std::cerr << "X"; std::cerr << "X";
sum -= q.cdata->i; sum -= q.cdata->i;
delete q.cdata; delete q.cdata;
@ -81,7 +72,8 @@ void consumer_thread()
sum += q.cdata->i; sum += q.cdata->i;
break; break;
} }
default: throw "Illegal state"; default:
throw "Illegal state";
} }
} }
} }
@ -91,20 +83,17 @@ void consumer_thread()
int main() int main()
{ {
for(int i=0; i<10; ++i) for (int i = 0; i < 10; ++i) {
{
pc.insert(new P(i)); pc.insert(new P(i));
} }
std::thread t{ &consumer_thread }; std::thread t{ &consumer_thread };
for(int i=10; i<100; ++i) for (int i = 10; i < 100; ++i) {
{
pc.insert(new P(i)); pc.insert(new P(i));
} }
while( !pc.empty() ) while (!pc.empty()) {
{
auto q = pc.begin(); auto q = pc.begin();
delete q->pdata; delete q->pdata;
pc.erase(q); pc.erase(q);

53
test/test_message_cache.cc

@ -1,9 +1,13 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "framework.hh"
#include <iostream> #include <iostream>
#include <cassert> #include <cassert>
#include <sys/param.h> #include <sys/param.h>
#include <unistd.h> #include <unistd.h>
#include "message_cache.hh" #include <message_cache.hh>
#include "framework.hh" #include <Adapter.hh>
using namespace std; using namespace std;
using namespace pEp; using namespace pEp;
@ -12,8 +16,8 @@ int main(int argc, char **argv)
{ {
Test::setup(argc, argv); Test::setup(argc, argv);
pEp_identity *alice = ::new_identity("alice@mail.com", nullptr, PEP_OWN_USERID, "Alice"); ::pEp_identity *alice = ::new_identity("alice@mail.com", nullptr, PEP_OWN_USERID, "Alice");
::myself(pEp::Adapter::session(), alice); ::myself(Adapter::session(), alice);
char *mime = strdup("From: Alice <alice@mail.com>\n" char *mime = strdup("From: Alice <alice@mail.com>\n"
"To: Bob <bob@mail.com>\n" "To: Bob <bob@mail.com>\n"
@ -25,20 +29,30 @@ int main(int argc, char **argv)
::message *src = nullptr; ::message *src = nullptr;
bool has_possible_pEp_msg; bool has_possible_pEp_msg;
PEP_STATUS status = MessageCache::cache_mime_decode_message(mime, strlen(mime), &src, &has_possible_pEp_msg); ::PEP_STATUS status = MessageCache::cache_mime_decode_message(
mime,
strlen(mime),
&src,
&has_possible_pEp_msg);
assert(status == PEP_STATUS_OK); assert(status == PEP_STATUS_OK);
status = ::myself(pEp::Adapter::session(), src->from); status = ::myself(Adapter::session(), src->from);
assert(status == PEP_STATUS_OK); assert(status == PEP_STATUS_OK);
::update_identity(pEp::Adapter::session(), src->to->ident); ::update_identity(Adapter::session(), src->to->ident);
assert(status == PEP_STATUS_OK); assert(status == PEP_STATUS_OK);
pEp_identity *bob = identity_dup(src->to->ident); ::pEp_identity *bob = identity_dup(src->to->ident);
src->dir = PEP_dir_outgoing; src->dir = ::PEP_dir_outgoing;
::message *dst = nullptr; ::message *dst = nullptr;
status = MessageCache::cache_encrypt_message(pEp::Adapter::session(), src, nullptr, &dst, PEP_enc_PEP, 0); status = MessageCache::cache_encrypt_message(
Adapter::session(),
src,
nullptr,
&dst,
PEP_enc_PEP,
0);
assert(status != PEP_ILLEGAL_VALUE); assert(status != PEP_ILLEGAL_VALUE);
assert(src->longmsg == nullptr); assert(src->longmsg == nullptr);
@ -65,11 +79,17 @@ int main(int argc, char **argv)
assert(src->longmsg == nullptr); assert(src->longmsg == nullptr);
assert(src->attachments == nullptr); assert(src->attachments == nullptr);
PEP_rating rating; ::PEP_rating rating;
PEP_decrypt_flags_t flags = 0; ::PEP_decrypt_flags_t flags = 0;
stringlist_t *keylist = nullptr; ::stringlist_t *keylist = nullptr;
status = MessageCache::cache_decrypt_message(pEp::Adapter::session(), src, &dst, &keylist, &rating, &flags); status = MessageCache::cache_decrypt_message(
Adapter::session(),
src,
&dst,
&keylist,
&rating,
&flags);
assert(status != PEP_ILLEGAL_VALUE); assert(status != PEP_ILLEGAL_VALUE);
assert(src->longmsg == nullptr); assert(src->longmsg == nullptr);
@ -92,7 +112,6 @@ int main(int argc, char **argv)
::free_identity(bob); ::free_identity(bob);
::free_identity(alice); ::free_identity(alice);
pEp::Adapter::session(pEp::Adapter::release); Adapter::session(Adapter::release);
return 0; return 0;
} }

64
test/test_passphrase_cache.cc

@ -1,20 +1,27 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "framework.hh"
#include <iostream> #include <iostream>
#include <unistd.h> #include <unistd.h>
#include <assert.h> #include <assert.h>
#include <sys/param.h> #include <sys/param.h>
#include <passphrase_cache.hh>
#include <status_to_string.hh>
#include <Adapter.hh>
#include "framework.hh" using namespace pEp;
#include "passphrase_cache.hh"
#include "status_to_string.hh"
extern "C" { extern "C" {
PEP_STATUS api_test1(PEP_SESSION session, const char *str, char *bytes, int n, ::stringlist_t *sl) ::PEP_STATUS api_test1(::PEP_SESSION session, const char *str, char *bytes, int n, ::stringlist_t *sl)
{ {
std::cout << "called api_test1\n"; std::cout << "called api_test1\n";
return PEP_WRONG_PASSPHRASE; return PEP_WRONG_PASSPHRASE;
} }
PEP_STATUS api_test2(PEP_SESSION session, int n, const char *str, char *bytes, ::stringlist_t *sl) ::PEP_STATUS api_test2(::PEP_SESSION session, int n, const char *str, char *bytes, ::stringlist_t *sl)
{ {
std::cout << "called api_test2\n"; std::cout << "called api_test2\n";
return PEP_STATUS_OK; return PEP_STATUS_OK;
@ -23,62 +30,73 @@ extern "C" {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
pEp::Test::setup(argc, argv); Test::setup(argc, argv);
const char *str = "23"; const char *str = "23";
char *bytes = NULL; char *bytes = NULL;
int n = 42; int n = 42;
::stringlist_t *sl = NULL; ::stringlist_t *sl = NULL;
pEp::PassphraseCache cache{2, std::chrono::seconds(1)}; PassphraseCache cache{ 2, std::chrono::seconds(1) };
cache.add("say"); cache.add("say");
cache.add("hello"); cache.add("hello");
cache.add("world"); cache.add("world");
std::cout << "expected: two passphrases\n"; std::cout << "expected: two passphrases\n";
cache.for_each_passphrase([&](std::string passphrase){std::cout << "'" << passphrase << "'\n"; return false;}); cache.for_each_passphrase([&](std::string passphrase) {
std::cout << "'" << passphrase << "'\n";
return false;
});
std::cout << "expected: one passphrase\n"; std::cout << "expected: one passphrase\n";
cache.for_each_passphrase([&](std::string passphrase){std::cout << "'" << passphrase << "'\n"; return passphrase != "";}); cache.for_each_passphrase([&](std::string passphrase) {
std::cout << "'" << passphrase << "'\n";
return passphrase != "";
});
std::cout << "expected: two passphrases but reverse order\n"; std::cout << "expected: two passphrases but reverse order\n";
cache.for_each_passphrase([&](std::string passphrase){std::cout << "'" << passphrase << "'\n"; return false;}); cache.for_each_passphrase([&](std::string passphrase) {
std::cout << "'" << passphrase << "'\n";
return false;
});
PEP_STATUS status = cache.api(api_test1, pEp::Adapter::session(), "23", bytes, n, (::stringlist_t *) NULL); ::PEP_STATUS status = cache.api(api_test1, Adapter::session(), "23", bytes, n, (::stringlist_t *)NULL);
assert(status == PEP_WRONG_PASSPHRASE); assert(status == PEP_WRONG_PASSPHRASE);
status = cache.api(api_test2, pEp::Adapter::session(), n, str, bytes, sl); status = cache.api(api_test2, Adapter::session(), n, str, bytes, sl);
assert(status == PEP_STATUS_OK); assert(status == PEP_STATUS_OK);
cache.add("hello"); cache.add("hello");
cache.add("world"); cache.add("world");
std::cout << "expected: two passphrases in reverse order\n"; std::cout << "expected: two passphrases in reverse order\n";
pEp::PassphraseCache _cache = cache; PassphraseCache _cache = cache;
try { try {
while (1) { while (1) {
std::cout << "'" << _cache.latest_passphrase(_cache) << "'\n"; std::cout << "'" << _cache.latest_passphrase(_cache) << "'\n";
} }
} catch (std::underflow_error &) {
} }
catch (std::underflow_error&) { }
pEp::passphrase_cache.add("hello"); passphrase_cache.add("hello");
pEp::passphrase_cache.add("world"); passphrase_cache.add("world");
std::cout << "two times PEP_STATUS_OK (0), one time PEP_WRONG_PASSPHRASE (2561)\n"; std::cout << "two times PEP_STATUS_OK (0), one time PEP_WRONG_PASSPHRASE (2561)\n";
do { do {
status = pEp::PassphraseCache::config_next_passphrase(); status = PassphraseCache::config_next_passphrase();
std::cout << pEp::status_to_string(status) << " (" << status << ")\n"; std::cout << status_to_string(status) << " (" << status << ")\n";
} while (status == PEP_STATUS_OK); } while (status == PEP_STATUS_OK);
sleep(2); sleep(2);
std::cout << "expected: no passphrase\n"; std::cout << "expected: no passphrase\n";
cache.for_each_passphrase([&](std::string passphrase){std::cout << "'" << passphrase << "'\n"; return false;}); cache.for_each_passphrase([&](std::string passphrase) {
std::cout << "'" << passphrase << "'\n";
return false;
});
status = cache.api(api_test1, pEp::Adapter::session(), str, bytes, n, sl); status = cache.api(api_test1, Adapter::session(), str, bytes, n, sl);
assert(status == PEP_WRONG_PASSPHRASE); assert(status == PEP_WRONG_PASSPHRASE);
status = cache.api(api_test2, pEp::Adapter::session(), 23, str, bytes, sl); status = cache.api(api_test2, Adapter::session(), 23, str, bytes, sl);
assert(status == PEP_STATUS_OK); assert(status == PEP_STATUS_OK);
pEp::Adapter::session(pEp::Adapter::release); Adapter::session(Adapter::release);
return 0; return 0;
} }

4
test/test_semaphore.cc

@ -1,3 +1,6 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#include <unistd.h> #include <unistd.h>
@ -32,4 +35,3 @@ int main()
return 0; return 0;
} }

Loading…
Cancel
Save