Browse Source

Merge branch 'LIB-13' - Define Coding Standards And Project Structure

Define and implement Coding Style using clang-format.
top level .clang-format, supported by nearly all Editors/IDE's and if not, one has to manually run clang-format. Its up to the dev. But everybody can use it, and its enables to use a shared definition of coding style.

I want to avoid the project to end up in an underspecified/inconsistent state after the code base has grown over the years.
So, NOW is the time to do it.

Flat project structure becomes unmanageable.
Create standard project layout, of at least
* src
* test

for now

ALSO: The max. C++ Standard to be used (pEp-wide) has now been raised to C++14 (!!!)
pull/8/head
heck 4 years ago
parent
commit
ca0d30c175
  1. 39
      .clang-format
  2. 41
      Makefile
  3. 3
      Makefile.conf
  4. 0
      README.md
  5. 26
      call_with_lock.hh
  6. 23
      constant_time_algo.cc
  7. 135
      message_cache.hh
  8. 40
      pEpLog.cc
  9. 25
      slurp.cc
  10. 67
      src/Adapter.cc
  11. 32
      src/Adapter.hh
  12. 39
      src/Adapter.hxx
  13. 37
      src/Makefile
  14. 8
      src/Semaphore.hh
  15. 5
      src/call_with_lock.cc
  16. 26
      src/call_with_lock.hh
  17. 34
      src/callback_dispatcher.cc
  18. 14
      src/callback_dispatcher.hh
  19. 21
      src/constant_time_algo.cc
  20. 5
      src/constant_time_algo.hh
  21. 47
      src/locked_queue.hh
  22. 253
      src/message_cache.cc
  23. 128
      src/message_cache.hh
  24. 43
      src/pEpLog.cc
  25. 34
      src/pEpLog.hh
  26. 55
      src/passphrase_cache.cc
  27. 24
      src/passphrase_cache.hh
  28. 9
      src/passphrase_cache.hxx
  29. 0
      src/pc_container.hh
  30. 21
      src/slurp.cc
  31. 3
      src/slurp.hh
  32. 23
      src/status_to_string.cc
  33. 5
      src/status_to_string.hh
  34. 25
      status_to_string.cc
  35. 6
      test/Makefile

39
.clang-format

@ -0,0 +1,39 @@
# Generated from CLion C/C++ Code Style settings
BasedOnStyle: LLVM
Language: Cpp
DerivePointerAlignment: true
SortIncludes: false
ReflowComments: false
PointerAlignment: Left
AlignAfterOpenBracket: AlwaysBreak
AlignOperands: AlignAfterOperator
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

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

67
Adapter.cc → src/Adapter.cc

@ -14,35 +14,39 @@ using namespace std;
thread_local pEp::Adapter::Session pEp::Adapter::session; thread_local pEp::Adapter::Session pEp::Adapter::session;
namespace pEp { namespace pEp {
void throw_status(PEP_STATUS status) void throw_status(::PEP_STATUS status)
{ {
if (status == PEP_STATUS_OK) if (status == ::PEP_STATUS_OK) {
return; return;
if (status >= 0x400 && status <= 0x4ff) }
if (status >= 0x400 && status <= 0x4ff) {
return; return;
if (status == PEP_STATEMACHINE_CANNOT_SEND) }
if (status == ::PEP_STATEMACHINE_CANNOT_SEND) {
return; return;
if (status == PEP_OUT_OF_MEMORY) }
if (status == ::PEP_OUT_OF_MEMORY) {
throw bad_alloc(); throw bad_alloc();
if (status == PEP_ILLEGAL_VALUE) }
if (status == ::PEP_ILLEGAL_VALUE) {
throw invalid_argument("illegal value"); throw invalid_argument("illegal value");
}
string _status = status_to_string(status); string _status = status_to_string(status);
throw RuntimeError(_status, status); throw RuntimeError(_status, status);
} }
RuntimeError::RuntimeError(const std::string& _text, PEP_STATUS _status) RuntimeError::RuntimeError(const std::string &_text, ::PEP_STATUS _status)
: std::runtime_error(_text.c_str()), text(_text), status(_status) : std::runtime_error(_text.c_str()), text(_text), status(_status)
{ {
} }
namespace Adapter { namespace Adapter {
messageToSend_t _messageToSend = nullptr; ::messageToSend_t _messageToSend = nullptr;
notifyHandshake_t _notifyHandshake = nullptr; ::notifyHandshake_t _notifyHandshake = nullptr;
std::thread _sync_thread; std::thread _sync_thread;
::utility::locked_queue< SYNC_EVENT, ::free_Sync_event > sync_evt_q; ::utility::locked_queue<SYNC_EVENT, ::free_Sync_event> sync_evt_q;
std::mutex m; std::mutex m;
std::thread::id sync_thread_id() std::thread::id sync_thread_id()
@ -50,36 +54,34 @@ namespace pEp {
return _sync_thread.get_id(); return _sync_thread.get_id();
} }
int _inject_sync_event(SYNC_EVENT ev, void *management) int _inject_sync_event(::SYNC_EVENT ev, void *management)
{ {
try { try {
if (ev == nullptr) { if (ev == nullptr) {
sync_evt_q.clear(); sync_evt_q.clear();
sync_evt_q.push_back(ev); sync_evt_q.push_back(ev);
} } else {
else {
sync_evt_q.push_front(ev); sync_evt_q.push_front(ev);
} }
} } catch (exception &) {
catch (exception&) {
return 1; return 1;
} }
return 0; return 0;
} }
PEP_STATUS _ensure_passphrase(PEP_SESSION session, const char *fpr) PEP_STATUS _ensure_passphrase(::PEP_SESSION session, const char *fpr)
{ {
return passphrase_cache.ensure_passphrase(session, fpr); return passphrase_cache.ensure_passphrase(session, fpr);
} }
// threshold: max waiting time in seconds // threshold: max waiting time in seconds
SYNC_EVENT _retrieve_next_sync_event(void *management, unsigned threshold) ::SYNC_EVENT _retrieve_next_sync_event(void *management, unsigned threshold)
{ {
SYNC_EVENT syncEvent = nullptr; ::SYNC_EVENT syncEvent = nullptr;
const bool success = sync_evt_q.try_pop_front(syncEvent, std::chrono::seconds(threshold)); const bool success = sync_evt_q.try_pop_front(syncEvent, std::chrono::seconds(threshold));
if (!success) { if (!success) {
return new_sync_timeout_event(); return ::new_sync_timeout_event();
} }
return syncEvent; return syncEvent;
@ -90,11 +92,11 @@ namespace pEp {
return _sync_thread.get_id() == this_thread::get_id(); return _sync_thread.get_id() == this_thread::get_id();
} }
PEP_SESSION Session::operator()(session_action action) ::PEP_SESSION Session::operator()(session_action action)
{ {
std::lock_guard<mutex> lock(m); std::lock_guard<mutex> lock(m);
PEP_STATUS status = PEP_STATUS_OK; ::PEP_STATUS status = ::PEP_STATUS_OK;
switch (action) { switch (action) {
case release: case release:
@ -105,7 +107,7 @@ namespace pEp {
case init: case init:
if (!_session.get()) { if (!_session.get()) {
PEP_SESSION session_; ::PEP_SESSION session_;
status = ::init(&session_, _messageToSend, _inject_sync_event, _ensure_passphrase); status = ::init(&session_, _messageToSend, _inject_sync_event, _ensure_passphrase);
throw_status(status); throw_status(status);
_session = SessionPtr{session_, ::release}; _session = SessionPtr{session_, ::release};
@ -113,7 +115,7 @@ namespace pEp {
break; break;
default: default:
status = PEP_ILLEGAL_VALUE; status = ::PEP_ILLEGAL_VALUE;
} }
throw_status(status); throw_status(status);
@ -122,9 +124,9 @@ namespace pEp {
void shutdown() void shutdown()
{ {
pEpLog("called"); pEpLog("called");
if (_sync_thread.joinable()) { if (_sync_thread.joinable()) {
pEpLog("sync_is_running - injecting null event"); pEpLog("sync_is_running - injecting null event");
_inject_sync_event(nullptr, nullptr); _inject_sync_event(nullptr, nullptr);
_sync_thread.join(); _sync_thread.join();
} }
@ -140,8 +142,7 @@ namespace pEp {
SYNC_EVENT ev; SYNC_EVENT ev;
try { try {
ev = sync_evt_q.back(); ev = sync_evt_q.back();
} } catch (std::underflow_error &) {
catch (std::underflow_error&) {
return false; return false;
} }
if (ev) { if (ev) {
@ -149,6 +150,6 @@ namespace pEp {
} else { } else {
return true; return true;
} }
} }
} } // namespace Adapter
} } // namespace pEp

32
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,26 +17,25 @@ 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); int _inject_sync_event(::SYNC_EVENT ev, void *management);
PEP_STATUS _ensure_passphrase(PEP_SESSION session, const char *fpr); ::PEP_STATUS _ensure_passphrase(::PEP_SESSION session, const char *fpr);
template<class T = void> template<class T = void>
void startup( void startup(
messageToSend_t messageToSend, messageToSend_t messageToSend,
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,7 +43,8 @@ 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
}; };
@ -59,15 +59,15 @@ 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"
#endif //LIBPEPADAPTER_ADAPTER_HH #endif // LIBPEPADAPTER_ADAPTER_HH

39
Adapter.hxx → src/Adapter.hxx

@ -14,20 +14,20 @@ namespace pEp {
namespace Adapter { namespace Adapter {
using std::function; using std::function;
extern messageToSend_t _messageToSend; extern ::messageToSend_t _messageToSend;
extern notifyHandshake_t _notifyHandshake; extern ::notifyHandshake_t _notifyHandshake;
extern std::thread _sync_thread; extern std::thread _sync_thread;
extern ::utility::locked_queue< SYNC_EVENT, ::free_Sync_event > sync_evt_q; extern ::utility::locked_queue<::SYNC_EVENT, ::free_Sync_event> sync_evt_q;
extern std::mutex m; extern std::mutex m;
SYNC_EVENT _retrieve_next_sync_event(void *management, unsigned threshold); ::SYNC_EVENT _retrieve_next_sync_event(void *management, unsigned threshold);
static std::exception_ptr _ex; static std::exception_ptr _ex;
static std::atomic_bool register_done{false}; static std::atomic_bool register_done{false};
template< class T > template<class T>
void sync_thread(T *obj, function< void(T *) > _startup, function< void(T *) > _shutdown) void sync_thread(T *obj, function<void(T *)> _startup, function<void(T *)> _shutdown)
{ {
pEpLog("called"); pEpLog("called");
_ex = nullptr; _ex = nullptr;
@ -41,16 +41,19 @@ namespace pEp {
session(); session();
{ {
//TODO: Do we need to use a passphraseWrap here??? // TODO: Do we need to use a passphraseWrap here???
pEpLog("register_sync_callbacks()"); pEpLog("register_sync_callbacks()");
PEP_STATUS status = register_sync_callbacks(session(), nullptr, ::PEP_STATUS status = ::register_sync_callbacks(
_notifyHandshake, _retrieve_next_sync_event); session(),
nullptr,
_notifyHandshake,
_retrieve_next_sync_event);
pEpLog("register_sync_callbacks() return:" << status); pEpLog("register_sync_callbacks() return:" << status);
try { try {
throw_status(status); throw_status(status);
register_done.store(true); register_done.store(true);
} } catch (...) {
catch (...) {
_ex = std::current_exception(); _ex = std::current_exception();
register_done.store(true); register_done.store(true);
return; return;
@ -58,7 +61,7 @@ namespace pEp {
} }
pEpLog("sync protocol loop started"); pEpLog("sync protocol loop started");
do_sync_protocol(session(), (void *)obj); ::do_sync_protocol(session(), (void *)obj);
pEpLog("sync protocol loop ended"); pEpLog("sync protocol loop ended");
unregister_sync_callbacks(session()); unregister_sync_callbacks(session());
@ -69,13 +72,13 @@ namespace pEp {
} }
} }
template< class T > template<class T>
void startup( void startup(
messageToSend_t messageToSend, messageToSend_t messageToSend,
notifyHandshake_t notifyHandshake, notifyHandshake_t notifyHandshake,
T *obj, T *obj,
function< void(T *) > _startup, function<void(T *)> _startup,
function< void(T *) > _shutdown) function<void(T *)> _shutdown)
{ {
pEpLog("called"); pEpLog("called");
if (messageToSend) { if (messageToSend) {
@ -104,7 +107,7 @@ namespace pEp {
} }
} }
} }
} } // namespace Adapter
} } // namespace pEp
#endif //LIBPEPADAPTER_ADAPTER_HXX #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)

8
Semaphore.hh → src/Semaphore.hh

@ -19,7 +19,7 @@ namespace pEp {
std::atomic_bool _stop; std::atomic_bool _stop;
public: public:
Semaphore() : _stop(false) { } Semaphore() : _stop(false) {}
void stop() void stop()
{ {
@ -34,7 +34,7 @@ namespace pEp {
return; return;
} }
while(_stop.load()) { while (_stop.load()) {
cv.wait(lock); cv.wait(lock);
} }
} }
@ -46,8 +46,6 @@ namespace pEp {
cv.notify_all(); cv.notify_all();
} }
}; };
} } // namespace pEp
#endif // LIBPEPADAPTER_SEMAPHORE_HH #endif // LIBPEPADAPTER_SEMAPHORE_HH

5
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

34
callback_dispatcher.cc → src/callback_dispatcher.cc

@ -14,18 +14,19 @@ 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);
} }
void CallbackDispatcher::add( void CallbackDispatcher::add(
::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,10 +78,12 @@ 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::on_startup, CallbackDispatcher::notifyHandshake,
&CallbackDispatcher::on_shutdown); &callback_dispatcher,
&CallbackDispatcher::on_startup,
&CallbackDispatcher::on_shutdown);
pEpLog("all targets signal: SYNC_NOTIFY_START"); pEpLog("all targets signal: SYNC_NOTIFY_START");
for (auto target : callback_dispatcher.targets) { for (auto target : callback_dispatcher.targets) {
@ -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

14
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

5
constant_time_algo.hh → src/constant_time_algo.hh

@ -6,14 +6,13 @@
#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.
// Use this function instead of operator== if timing sidechannel attack // Use this function instead of operator== if timing sidechannel attack
// might be a security problem. // might be a security problem.
bool constant_time_equal(const std::string& a, const std::string& b); bool constant_time_equal(const std::string &a, const std::string &b);
} // end of namespace pEp } // end of namespace pEp

47
locked_queue.hh → src/locked_queue.hh

@ -8,17 +8,15 @@
#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::unique_lock<Mutex> Lock;
typedef std::recursive_mutex Mutex;
typedef std::unique_lock<Mutex> Lock; int _waiting = 0;
Mutex _mtx;
int _waiting = 0; std::condition_variable_any _cv;
Mutex _mtx;
std::condition_variable_any _cv;
std::deque<T> _q; std::deque<T> _q;
public: public:
@ -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);
} }
} }
@ -63,7 +59,7 @@ namespace utility
T pop_back() T pop_back()
{ {
Lock L(_mtx); Lock L(_mtx);
_cv.wait(L, [&]{ return !_q.empty(); } ); _cv.wait(L, [&] { return !_q.empty(); });
T r{std::move(_q.back())}; T r{std::move(_q.back())};
_q.pop_back(); _q.pop_back();
return r; return r;
@ -74,7 +70,7 @@ namespace utility
T pop_front() T pop_front()
{ {
Lock L(_mtx); Lock L(_mtx);
_cv.wait(L, [&]{ return !_q.empty(); } ); _cv.wait(L, [&] { return !_q.empty(); });
T r{std::move(_q.front())}; T r{std::move(_q.front())};
_q.pop_front(); _q.pop_front();
return r; return r;
@ -86,30 +82,28 @@ 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;
} }
--_waiting; --_waiting;
out = std::move(_q.back()); out = std::move(_q.back());
_q.pop_back(); _q.pop_back();
return true; return true;
} }
// returns true and set a copy of the first element and pop it from queue if there is any // returns true and set a copy of the first element and pop it from queue if there is any
// returns false and leaves 'out' untouched if queue is empty even after 'end_time' // returns false and leaves 'out' untouched if queue is empty even after 'end_time'
bool try_pop_front(T& out, std::chrono::steady_clock::time_point end_time) bool try_pop_front(T& out, std::chrono::steady_clock::time_point end_time)
{ {
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;
} }
--_waiting; --_waiting;
out = std::move(_q.front()); out = std::move(_q.front());
_q.pop_front(); _q.pop_front();
@ -122,12 +116,11 @@ 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;
} }
--_waiting; --_waiting;
out = std::move(_q.front()); out = std::move(_q.front());
_q.pop_front(); _q.pop_front();

253
message_cache.cc → src/message_cache.cc

@ -20,67 +20,58 @@ namespace pEp {
} }
PEP_STATUS MessageCache::cache_decrypt_message( PEP_STATUS MessageCache::cache_decrypt_message(
PEP_SESSION session, PEP_SESSION session,
message *src, message *src,
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(
int one, int one,
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(
PEP_SESSION session, PEP_SESSION session,
message *src, message *src,
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(
PEP_SESSION session, PEP_SESSION session,
pEp_identity* target_id, pEp_identity *target_id,
message *src, message *src,
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)
@ -105,7 +96,7 @@ namespace pEp {
if (!src) if (!src)
return nullptr; return nullptr;
char * dst = ::strdup(src); char *dst = ::strdup(src);
assert(dst); assert(dst);
if (!dst) if (!dst)
throw std::bad_alloc(); throw std::bad_alloc();
@ -118,7 +109,7 @@ namespace pEp {
if (!src) if (!src)
return nullptr; return nullptr;
::timestamp * dst = ::timestamp_dup(src); ::timestamp *dst = ::timestamp_dup(src);
if (!dst) if (!dst)
throw std::bad_alloc(); throw std::bad_alloc();
@ -130,7 +121,7 @@ namespace pEp {
if (!src) if (!src)
return nullptr; return nullptr;
::pEp_identity * dst = ::identity_dup(src); ::pEp_identity *dst = ::identity_dup(src);
if (!dst) if (!dst)
throw std::bad_alloc(); throw std::bad_alloc();
@ -142,7 +133,7 @@ namespace pEp {
if (!src) if (!src)
return nullptr; return nullptr;
::identity_list * dst = ::identity_list_dup(src); ::identity_list *dst = ::identity_list_dup(src);
if (!dst) if (!dst)
throw std::bad_alloc(); throw std::bad_alloc();
@ -154,7 +145,7 @@ namespace pEp {
if (!src) if (!src)
return nullptr; return nullptr;
::stringlist_t * dst = ::stringlist_dup(src); ::stringlist_t *dst = ::stringlist_dup(src);
if (!dst) if (!dst)
throw std::bad_alloc(); throw std::bad_alloc();
@ -166,19 +157,19 @@ namespace pEp {
if (!src) if (!src)
return nullptr; return nullptr;
::stringpair_list_t * dst = ::stringpair_list_dup(src); ::stringpair_list_t *dst = ::stringpair_list_dup(src);
if (!dst) if (!dst)
throw std::bad_alloc(); throw std::bad_alloc();
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();
@ -223,7 +213,7 @@ namespace pEp {
dst->longmsg = dup("pEp"); dst->longmsg = dup("pEp");
else if (!emptystr(src->longmsg_formatted)) else if (!emptystr(src->longmsg_formatted))
dst->longmsg_formatted = dup("<pEp/>"); dst->longmsg_formatted = dup("<pEp/>");
// attachments are never copied // attachments are never copied
dst->rawmsg_ref = src->rawmsg_ref; dst->rawmsg_ref = src->rawmsg_ref;
@ -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);
@ -262,20 +252,19 @@ namespace pEp {
return dst; return dst;
} }
static void correctAttachmentsOrder(bloblist_t*& bl) static void correctAttachmentsOrder(bloblist_t *&bl)
{ {
// only execute if there are exactly two attachments, both with // only execute if there are exactly two attachments, both with
// a non-empty MIME type // a non-empty MIME type
if (bl && bl->next && !bl->next->next && !emptystr(bl->mime_type) && if (bl && bl->next && !bl->next->next && !emptystr(bl->mime_type) &&
!emptystr(bl->next->mime_type)) { !emptystr(bl->next->mime_type)) {
// if this is most likely an PGP/MIME compliant format then correct // if this is most likely an PGP/MIME compliant format then correct
// 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;
@ -285,7 +274,7 @@ namespace pEp {
} }
} }
static void swapContent(::message*& part, ::message*& full) static void swapContent(::message *&part, ::message *&full)
{ {
free(part->longmsg); free(part->longmsg);
part->longmsg = full->longmsg; part->longmsg = full->longmsg;
@ -301,13 +290,12 @@ namespace pEp {
} }
PEP_STATUS MessageCache::decrypt_message( PEP_STATUS MessageCache::decrypt_message(
PEP_SESSION session, PEP_SESSION session,
message *src, message *src,
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);
{ {
@ -338,12 +325,11 @@ namespace pEp {
} }
PEP_STATUS MessageCache::mime_encode_message( PEP_STATUS MessageCache::mime_encode_message(
which one, which one,
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));
@ -374,7 +358,7 @@ namespace pEp {
return status; return status;
} }
void MessageCache::generateCacheID(::message* msg) void MessageCache::generateCacheID(::message *msg)
{ {
std::string _range = std::to_string(id_range); std::string _range = std::to_string(id_range);
std::string _id = std::to_string(next_id++); std::string _id = std::to_string(next_id++);
@ -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();
@ -403,12 +384,11 @@ namespace pEp {
} }
} }
std::string MessageCache::cacheID(const ::message* msg) std::string MessageCache::cacheID(const ::message *msg)
{ {
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;
@ -418,27 +398,22 @@ namespace pEp {
} }
return ""; return "";
} }
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);
@ -451,37 +426,34 @@ namespace pEp {
} }
PEP_STATUS MessageCache::mime_decode_message( PEP_STATUS MessageCache::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)
)
{ {
::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;
} }
PEP_STATUS MessageCache::encrypt_message( PEP_STATUS MessageCache::encrypt_message(
PEP_SESSION session, PEP_SESSION session,
message *src, message *src,
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);
{ {
@ -507,14 +478,13 @@ namespace pEp {
} }
PEP_STATUS MessageCache::encrypt_message_for_self( PEP_STATUS MessageCache::encrypt_message_for_self(
PEP_SESSION session, PEP_SESSION session,
pEp_identity* target_id, pEp_identity *target_id,
message *src, message *src,
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

34
pEpLog.hh → src/pEpLog.hh

@ -29,34 +29,36 @@
// 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
#ifdef ANDROID #ifdef ANDROID
#include <android/log.h> #include <android/log.h>
#endif #endif
#define pEpLog(msg) \ #define pEpLog(msg) \
do { \ do { \
std::stringstream msg_ss; \ std::stringstream msg_ss; \
msg_ss << std::this_thread::get_id() << " - " << __FILE__ << "::" << __FUNCTION__ << " - " << msg; \ msg_ss << std::this_thread::get_id() << " - " << __FILE__ << "::" << __FUNCTION__ \
pEp::Adapter::pEpLog::log(msg_ss.str()); \ << " - " << msg; \
} while(0) pEp::Adapter::pEpLog::log(msg_ss.str()); \
} while (0)
#endif // NDEBUG #endif // NDEBUG
namespace pEp { namespace pEp {
namespace Adapter { namespace Adapter {
namespace pEpLog { namespace pEpLog {
void log(std::string msg); void log(std::string msg);
void set_enabled(bool is_enabled); 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

55
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();
} }
@ -36,16 +36,16 @@ namespace pEp {
return *this; return *this;
} }
const char *PassphraseCache::add(const std::string& passphrase) const char* PassphraseCache::add(const std::string& passphrase)
{ {
if (!passphrase.empty()) { if (!passphrase.empty()) {
const char *result = nullptr; const char* result = nullptr;
{ {
std::lock_guard<std::mutex> lock(_mtx); std::lock_guard<std::mutex> lock(_mtx);
while (_cache.size() >= _max_size) while (_cache.size() >= _max_size)
_cache.pop_front(); _cache.pop_front();
_cache.push_back({passphrase, clock::now()}); _cache.push_back({passphrase, clock::now()});
auto back = _cache.end(); auto back = _cache.end();
assert(!_cache.empty()); assert(!_cache.empty());
@ -55,11 +55,11 @@ namespace pEp {
return result; return result;
} }
static const char *empty = ""; static const char* empty = "";
return empty; return empty;
} }
const char *PassphraseCache::add_stored(const std::string& passphrase) const char* PassphraseCache::add_stored(const std::string& passphrase)
{ {
std::lock_guard<std::mutex> lock(_stored_mtx); std::lock_guard<std::mutex> lock(_stored_mtx);
_stored = passphrase; _stored = passphrase;
@ -81,7 +81,7 @@ namespace pEp {
std::lock_guard<std::mutex> lock(_mtx); std::lock_guard<std::mutex> lock(_mtx);
cleanup(); cleanup();
for (auto entry=_cache.begin(); entry!=_cache.end(); ++entry) { for (auto entry = _cache.begin(); entry != _cache.end(); ++entry) {
if (callee(entry->passphrase)) { if (callee(entry->passphrase)) {
refresh(entry); refresh(entry);
return true; return true;
@ -104,7 +104,7 @@ namespace pEp {
_cache.splice(_cache.end(), _cache, entry); _cache.splice(_cache.end(), _cache, entry);
} }
const char *PassphraseCache::latest_passphrase(PassphraseCache& c) const char* PassphraseCache::latest_passphrase(PassphraseCache& c)
{ {
if (c.first_time) { if (c.first_time) {
c.cleanup(); c.cleanup();
@ -128,8 +128,8 @@ namespace pEp {
return c._which->passphrase.c_str(); return c._which->passphrase.c_str();
} }
PEP_STATUS PassphraseCache::config_next_passphrase(bool reset, PEP_SESSION session) PEP_STATUS PassphraseCache::config_next_passphrase(bool reset, PEP_SESSION session)
{ {
static pEp::PassphraseCache _copy; static pEp::PassphraseCache _copy;
static bool new_copy = true; static bool new_copy = true;
@ -146,16 +146,14 @@ 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;
} }
} }
PEP_STATUS PassphraseCache::ensure_passphrase(PEP_SESSION session, std::string fpr) PEP_STATUS PassphraseCache::ensure_passphrase(PEP_SESSION session, std::string fpr)
{ {
@ -172,5 +170,4 @@ namespace pEp {
return status; return status;
} }
}; }; // namespace pEp

24
passphrase_cache.hh → src/passphrase_cache.hh

@ -20,7 +20,7 @@ namespace pEp {
struct cache_entry { struct cache_entry {
static const size_t max_len = 250 * 4; static const size_t max_len = 250 * 4;
cache_entry(const std::string& p, time_point t); cache_entry(const std::string& p, time_point t);
std::string passphrase; std::string passphrase;
time_point tp; time_point tp;
@ -39,30 +39,30 @@ namespace pEp {
public: public:
struct Empty : public std::underflow_error { struct Empty : public std::underflow_error {
Empty() : std::underflow_error("passphrase cache empty") { } Empty() : std::underflow_error("passphrase cache empty") {}
}; };
struct Exhausted : public std::underflow_error { struct Exhausted : public std::underflow_error {
Exhausted() : std::underflow_error("out of passphrases") { } Exhausted() : std::underflow_error("out of passphrases") {}
}; };
PassphraseCache(size_t max_size=20, duration timeout = std::chrono::minutes(10)); PassphraseCache(size_t max_size = 20, duration timeout = std::chrono::minutes(10));
~PassphraseCache() { } ~PassphraseCache() {}
PassphraseCache(const PassphraseCache& second); PassphraseCache(const PassphraseCache& second);
PassphraseCache& operator=(const PassphraseCache& second); PassphraseCache& operator=(const PassphraseCache& second);
// adds the passphrase to the cache, which will timeout // adds the passphrase to the cache, which will timeout
// returns a ptr to the passsword entry in the cache. Don't free() it! // returns a ptr to the passsword entry in the cache. Don't free() it!
const char *add(const std::string& passphrase); const char* add(const std::string& passphrase);
// adds the stored passphrase to the cache, which will not timeout // adds the stored passphrase to the cache, which will not timeout
const char *add_stored(const std::string& passphrase); const char* add_stored(const std::string& passphrase);
// call this function inside the messageToSend() implementation of the adapter // call this function inside the messageToSend() implementation of the adapter
// this function is using latest_passphrase() to test one passphrase after the // this function is using latest_passphrase() to test one passphrase after the
// other until the cache is exhausted // other until the cache is exhausted
// call with reset = true to reset the iterator // call with reset = true to reset the iterator
static PEP_STATUS config_next_passphrase(bool reset=false, PEP_SESSION session = NULL); static PEP_STATUS config_next_passphrase(bool reset = false, PEP_SESSION session = NULL);
// convenience functions // convenience functions
// i.e. // i.e.
@ -71,10 +71,10 @@ 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)>;
bool for_each_passphrase(const passphrase_callee& callee); bool for_each_passphrase(const passphrase_callee& callee);
PEP_STATUS ensure_passphrase(PEP_SESSION session, std::string fpr); PEP_STATUS ensure_passphrase(PEP_SESSION session, std::string fpr);
@ -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

5
status_to_string.hh → src/status_to_string.hh

@ -8,12 +8,11 @@
#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);
} // end of namespace pEp } // end of namespace pEp
#endif // LIBPEPADAPTER_STATUS_TO_STRING_HH #endif // LIBPEPADAPTER_STATUS_TO_STRING_HH

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

6
test/Makefile

@ -1,8 +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 $(ENGINE_INC) -std=c++11 -DENGINE_TEST=$(ENGINE_TEST)
SRC=$(wildcard test_*.cc) SRC=$(wildcard test_*.cc)
TST=$(subst .cc,,$(SRC)) TST=$(subst .cc,,$(SRC))
@ -13,7 +13,7 @@ $(TST): framework.o
.PHONY: clean rmtestdata .PHONY: clean rmtestdata
clean: clean:
rm -f $(TST) rm -f $(TST)
rm -Rf *.dSYM rm -Rf *.dSYM
rm -f *.o rm -f *.o

Loading…
Cancel
Save