Browse Source

Merge branch 'LIB-11'

# Conflicts:
#	test/Makefile
master
heck 7 months ago
parent
commit
ce136d408d
79 changed files with 254556 additions and 716 deletions
  1. +3
    -2
      .clang-format
  2. +31
    -0
      .gitignore
  3. +108
    -93
      src/Adapter.cc
  4. +48
    -21
      src/Adapter.hh
  5. +20
    -49
      src/Adapter.hxx
  6. +6
    -3
      src/Makefile
  7. +0
    -96
      src/adapter_group.cc
  8. +2
    -34
      src/callback_dispatcher.cc
  9. +3
    -6
      src/callback_dispatcher.hh
  10. +146
    -0
      src/group_manager_api.cc
  11. +34
    -81
      src/group_manager_api.h
  12. +383
    -0
      src/grp_driver_dummy.cc
  13. +69
    -0
      src/grp_driver_dummy.hh
  14. +63
    -0
      src/grp_driver_engine.cc
  15. +52
    -0
      src/grp_driver_engine.hh
  16. +267
    -0
      src/grp_driver_replicator.cc
  17. +83
    -0
      src/grp_driver_replicator.hh
  18. +66
    -0
      src/grp_manager_interface.hh
  19. +12264
    -0
      src/internal/sqlite3.h
  20. +367
    -0
      src/listmanager_dummy.cc
  21. +63
    -0
      src/listmanager_dummy.hh
  22. +120
    -9
      src/pEpLog.cc
  23. +192
    -19
      src/pEpLog.hh
  24. +167
    -0
      src/pEpSQLite.cc
  25. +64
    -0
      src/pEpSQLite.hh
  26. +234229
    -0
      src/sqlite3.c
  27. +297
    -0
      src/std_utils.cc
  28. +94
    -0
      src/std_utils.hh
  29. +22
    -0
      src/std_utils.hxx
  30. +259
    -0
      src/utils.cc
  31. +35
    -0
      src/utils.hh
  32. +10
    -6
      test/Makefile
  33. +11
    -6
      test/framework/framework.cc
  34. +1
    -1
      test/framework/framework.hh
  35. +236
    -131
      test/framework/utils.cc
  36. +121
    -16
      test/framework/utils.hh
  37. +39
    -0
      test/pitytest11/Makefile
  38. +456
    -0
      test/pitytest11/src/AbstractPityUnit.cc
  39. +135
    -0
      test/pitytest11/src/AbstractPityUnit.hh
  40. +32
    -0
      test/pitytest11/src/PityModel.cc
  41. +53
    -0
      test/pitytest11/src/PityModel.hh
  42. +63
    -0
      test/pitytest11/src/PityNode.cc
  43. +55
    -0
      test/pitytest11/src/PityNode.hh
  44. +48
    -0
      test/pitytest11/src/PityPerspective.cc
  45. +59
    -0
      test/pitytest11/src/PityPerspective.hh
  46. +146
    -0
      test/pitytest11/src/PitySwarm.cc
  47. +59
    -0
      test/pitytest11/src/PitySwarm.hh
  48. +32
    -0
      test/pitytest11/src/PityTest.hh
  49. +97
    -0
      test/pitytest11/src/PityTransport.cc
  50. +45
    -0
      test/pitytest11/src/PityTransport.hh
  51. +88
    -0
      test/pitytest11/src/PityTree.hh
  52. +220
    -0
      test/pitytest11/src/PityTree.hxx
  53. +75
    -0
      test/pitytest11/src/PityUnit.hh
  54. +136
    -0
      test/pitytest11/src/PityUnit.hxx
  55. +41
    -0
      test/pitytest11/src/fs_mutex.cc
  56. +25
    -0
      test/pitytest11/src/fs_mutex.hh
  57. +32
    -0
      test/pitytest11/test/test_assert.cc
  58. +94
    -0
      test/pitytest11/test/test_execmodes.cc
  59. +68
    -0
      test/pitytest11/test/test_linear.cc
  60. +161
    -0
      test/pitytest11/test/test_pitytree.cc
  61. +98
    -0
      test/pitytest11/test/test_processdirs.cc
  62. +88
    -0
      test/pitytest11/test/test_swarm.cc
  63. +14
    -15
      test/test_adapter.cc
  64. +21
    -26
      test/test_adapter_cxx.cc
  65. +2
    -12
      test/test_ensure_passphrase.cc
  66. +109
    -76
      test/test_group.cc
  67. +6
    -6
      test/test_leave_device_group.cc
  68. +307
    -0
      test/test_listmanager_dummy.cc
  69. +3
    -2
      test/test_message_cache.cc
  70. +642
    -0
      test/test_pEpSQLite.cc
  71. +115
    -0
      test/test_pEpSQLite.hh
  72. +2
    -3
      test/test_passphrase_cache.cc
  73. +2
    -3
      test/test_semaphore.cc
  74. +492
    -0
      test/test_swarm_group.cc
  75. +135
    -0
      test/test_swarm_tofu.cc
  76. +53
    -0
      test/test_sync_init.cc
  77. +65
    -0
      test/test_template_swarm_multi.cc
  78. +55
    -0
      test/test_template_swarm_single.cc
  79. +152
    -0
      test/test_tofu.cc

+ 3
- 2
.clang-format View File

@ -1,6 +1,6 @@
BasedOnStyle: LLVM
Language: Cpp
Standard: c++14
Standard: c++11
DerivePointerAlignment: true
SortIncludes: false
ReflowComments: false
@ -38,4 +38,5 @@ SpaceAfterTemplateKeyword: false
AccessModifierOffset: -4
AllowShortBlocksOnASingleLine: Always
IndentPPDirectives: BeforeHash
Cpp11BracedListStyle: false
Cpp11BracedListStyle: false
BreakStringLiterals: false

+ 31
- 0
.gitignore View File

@ -2,6 +2,7 @@
*.a
*.d
*.swp
.DS_Store
ws
test_adapter
.gnupg
@ -24,3 +25,33 @@ test_library
test_message_cache
test_passphrase_cache
test_semaphore
test_lm_dummy
test_sqlite3
test_pEpsqlite
test_listmanager_dummy
test_tofu_react
test_pEpLog_basic
/test/pitytest_data
*.db
/test/pitytest11/test/test_transport
/test/pitytest11/test/test_processdirs
/test/pitytest11/test/test_execmodes
/test/pitytest11/test/test_linear
/test/pitytest11/test/test_model
/test/pitytest11/pitytest_data/*
/test/pitytest11/test/test_swarm
/test/test_update_ident
/test/test_template_swarm_single
/test/test_template_swarm_multi
/test/pitytest11/test/test_copy
/test/pitytest11/test/test_pitytree
/test/test_suite_all
/test/test_sync_init
/test/test_tofu2
/test/pitytest11/test/test_assert
/test/test_tofu
/test/test_tofu_one2many
/test/test_swarm_group
/test/pitytest11/test/pitytest_data/

+ 108
- 93
src/Adapter.cc View File

@ -8,6 +8,9 @@
#include "status_to_string.hh"
#include "pEpLog.hh"
#include "passphrase_cache.hh"
#include "callback_dispatcher.hh"
#include "group_manager_api.h"
#include <iostream>
using namespace std;
@ -36,18 +39,12 @@ namespace pEp {
throw RuntimeError(_status, status);
}
RuntimeError::RuntimeError(const std::string &_text, ::PEP_STATUS _status)
: std::runtime_error(_text.c_str()), text(_text), 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 = _inject_sync_event;
std::thread _sync_thread;
::utility::locked_queue<SYNC_EVENT, ::free_Sync_event> sync_evt_q;
std::mutex mut;
@ -58,67 +55,6 @@ namespace pEp {
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 session 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 = _inject_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 = _inject_sync_event;
session(init);
}
return;
}
// private
int _process_sync_event(::SYNC_EVENT ev, void *management)
{
@ -171,34 +107,104 @@ namespace pEp {
return _sync_thread.get_id() == this_thread::get_id();
}
// public
::PEP_SESSION Session::operator()(session_action action)
// ---------------------------------------------------------------------------------------
Session::Session() :
_messageToSend{ nullptr }, _notifyHandshake{ nullptr }, _sync_mode{ SyncModes::Async },
_adapter_manages_sync_thread{ false }
{
}
void Session::initialize(SyncModes sync_mode, bool adapter_manages_sync_thread)
{
pEpLog("Initializing session with CallbackDispatcher...");
_init(
pEp::CallbackDispatcher::messageToSend,
pEp::CallbackDispatcher::notifyHandshake,
sync_mode,
adapter_manages_sync_thread);
}
void Session::initialize(
SyncModes sync_mode,
bool adapter_manages_sync_thread,
::messageToSend_t messageToSend,
::notifyHandshake_t notifyHandshake)
{
pEpLog("Initializing session...");
_init(messageToSend, notifyHandshake, sync_mode, adapter_manages_sync_thread);
}
void Session::_init(
::messageToSend_t messageToSend,
::notifyHandshake_t notifyHandshake,
SyncModes sync_mode,
bool adapter_manages_sync_thread)
{
// cache the values for sync-thread session creation
_messageToSend = messageToSend;
_notifyHandshake = notifyHandshake;
_sync_mode = sync_mode;
_adapter_manages_sync_thread = adapter_manages_sync_thread;
refresh();
::adapter_group_init();
}
void Session::refresh()
{
std::lock_guard<mutex> lock(mut);
release();
::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;
// Switch to mode "Sync" ensures the sync thread to be shutdown
if (_sync_mode == SyncModes::Sync) {
// process the event directly
_inject_action = _process_sync_event;
if (!_adapter_manages_sync_thread) {
stop_sync();
} else {
// The adapter needs to shutdown sync thread
}
}
// Switch to mode "ASync", sync thread needs to be started using start_sync
if (_sync_mode == SyncModes::Async) {
// put the event on queue
_inject_action = _inject_sync_event;
}
// create
::PEP_SESSION session_;
::PEP_STATUS status;
status = ::init(&session_, _messageToSend, _inject_action, _ensure_passphrase);
throw_status(status);
return _session.get();
status = ::register_sync_callbacks(
session_,
nullptr,
_notifyHandshake,
_retrieve_next_sync_event);
if (status != PEP_STATUS_OK) {
pEpLog("libpEpAdapter: WARNING - session is initialized but without sync/callbacks. "
"This is normal if there are no own identities yet. Call session.init() again to "
"re-initialize the session after creating an own identity.");
}
// store
_session = SessionPtr{ session_, ::release };
}
void Session::release()
{
if (_session.get()) {
_session = nullptr;
}
}
// public
::PEP_SESSION Session::operator()()
{
if (!_session.get()) {
throw std::runtime_error(
"libpEpAdapter: No session! Before use, call session.initialize() for each thread");
} else {
return _session.get();
}
}
// public
@ -207,21 +213,30 @@ namespace pEp {
_inject_sync_event(nullptr, nullptr);
}
void start_sync()
{
startup<pEp::CallbackDispatcher>(
&callback_dispatcher,
&::pEp::CallbackDispatcher::on_startup,
&::pEp::CallbackDispatcher::on_shutdown);
}
// public
void shutdown()
void stop_sync()
{
pEpLog("called");
if (_sync_thread.joinable()) {
pEpLog("sync_is_running - injecting null event");
inject_sync_shutdown();
_sync_thread.join();
pEp::callback_dispatcher.notifyHandshake(nullptr, nullptr, SYNC_NOTIFY_STOP);
}
}
// public
bool is_sync_running()
{
if(!_adapter_manages_sync_thread) {
if (!session._adapter_manages_sync_thread) {
return _sync_thread.joinable();
} else {
return false;


+ 48
- 21
src/Adapter.hh View File

@ -11,6 +11,7 @@
#include <thread>
#include <pEp/sync_api.h>
#include "callback_dispatcher.hh"
namespace pEp {
@ -29,28 +30,19 @@ namespace pEp {
// public
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 _inject_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);
void start_sync();
template<class T = void>
void startup(
messageToSend_t messageToSend,
notifyHandshake_t notifyHandshake,
T *obj = nullptr,
std::function<void(T *)> _startup = nullptr,
std::function<void(T *)> _shutdown = nullptr);
@ -61,18 +53,53 @@ namespace pEp {
// returns the thread id of the sync thread
std::thread::id sync_thread_id();
enum session_action
{
init,
release,
};
class Session {
public:
// TODO: needed because libpEpAdapter provides a static instance
// the session needs to be initialized in order to be usable.
Session();
// Init using CallbackDispatcher
// CAUTION: This may result in a partially initialized session.
// If there are any problem with register_sync_callbacks(), it will still
// succeed. (e.g. due to no own identities yet)
// BUT
// * Sync will not work
// * Group Encryption will not work
// TODO: This needs to be resolved in the engine, new func register_callbacks()
// that is not sync specific, and move the sync-checks to "start-sync()"
void initialize(SyncModes sync_mode = SyncModes::Async, bool adapter_manages_sync_thread = false);
// Arbitrary callbacks
void initialize(
SyncModes sync_mode,
bool adapter_manages_sync_thread,
::messageToSend_t messageToSend,
::notifyHandshake_t notifyHandshake);
// re-creates the session using same values
void refresh();
// Not copyable
Session(const Session &) = delete;
Session operator=(const Session&) = delete;
void release();
PEP_SESSION operator()();
SyncModes _sync_mode;
::messageToSend_t _messageToSend;
::notifyHandshake_t _notifyHandshake;
bool _adapter_manages_sync_thread;
::inject_sync_event_t _inject_action;
private:
void _init(
::messageToSend_t messageToSend,
::notifyHandshake_t notifyHandshake,
SyncModes sync_mode,
bool adapter_manages_sync_thread);
using SessionPtr = std::unique_ptr<_pEpSession, std::function<void(PEP_SESSION)>>;
SessionPtr _session = nullptr;
public:
PEP_SESSION operator()(session_action action = init);
};
extern thread_local Session session;
@ -84,7 +111,7 @@ namespace pEp {
// injects a NULL event into sync_event_queue to denote sync thread to
// shutdown, and joins & removes the sync thread
void shutdown();
void stop_sync();
bool is_sync_running();
bool in_shutdown();


+ 20
- 49
src/Adapter.hxx View File

@ -14,8 +14,6 @@ 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;
@ -38,12 +36,10 @@ namespace pEp {
*/
// private
template<class T>
void sync_thread(T *obj, function<void(T *)> _startup, function<void(T *)> _shutdown)
void sync_thread(Session *rhs, 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) {
@ -52,29 +48,18 @@ namespace pEp {
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;
}
// 3. register_sync_callbacks() (in session.initialize())
try {
session.initialize(
rhs->_sync_mode,
rhs->_adapter_manages_sync_thread,
rhs->_messageToSend,
rhs->_notifyHandshake);
register_done.store(true);
} catch (...) {
_ex = std::current_exception();
register_done.store(true);
return;
}
pEpLog("sync protocol loop started");
@ -86,8 +71,7 @@ namespace pEp {
unregister_sync_callbacks(session());
// 6. Release the session
// TODO: Maybe do that AFTER shutdown?
session(release);
session.release();
// 7. Execute registered shutdown function
if (obj && _shutdown) {
@ -97,38 +81,25 @@ namespace pEp {
/*
* Sync Thread Startup
* 1. ensure session for the main thread (registers: messageToSend, _inject_sync_event, _ensure_passphrase)
* 1. throw if main thread session is not initialized
* 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)
void startup(T *obj, std::function<void(T *)> _startup, std::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, _inject_sync_event, _ensure_passphrase)
session(release);
session(init);
// refresh the session
// due to partially initialized session, see session.initialize()
session.refresh();
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);
_sync_thread = std::thread(sync_thread<T>, &session, 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...");


+ 6
- 3
src/Makefile View File

@ -5,10 +5,13 @@
include ../Makefile.conf
SOURCE=$(wildcard *.cc)
SRC_CXX=$(wildcard *.cc)
SRC_C=$(wildcard *.c)
HEADERS=$(wildcard *.hh *.hxx *.h)
OBJECTS=$(subst .cc,.o,$(SOURCE))
DEPENDS=$(subst .cc,.d,$(SOURCE))
OBJ_CXX=$(subst .cc,.o,$(SRC_CXX))
OBJ_C=$(subst .c,.o,$(SRC_C))
OBJECTS=$(OBJ_CXX) $(OBJ_C)
DEPENDS=$(subst .cc,.d,$(SRC_CXX))
CXXFLAGS+= -MMD -MP
ifneq ($(MAKECMDGOALS),clean)


+ 0
- 96
src/adapter_group.cc View File

@ -1,96 +0,0 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include <pEp/group.h>
#include "adapter_group.h"
#include "pEpLog.hh"
#ifdef __cplusplus
extern "C" {
#endif
/*************************************************************************************************
* Group management functions
*************************************************************************************************/
DYNAMIC_API PEP_STATUS adapter_group_create(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *manager,
identity_list *memberlist,
pEp_group **group)
{
pEpLog("called");
return ::group_create(session, group_identity, manager, memberlist, group);
}
DYNAMIC_API PEP_STATUS
adapter_group_join(PEP_SESSION session, pEp_identity *group_identity, pEp_identity *as_member)
{
pEpLog("called");
return ::group_join(session, group_identity, as_member);
}
DYNAMIC_API PEP_STATUS
adapter_group_dissolve(PEP_SESSION session, pEp_identity *group_identity, pEp_identity *manager)
{
pEpLog("called");
return ::group_dissolve(session, group_identity, manager);
}
DYNAMIC_API PEP_STATUS adapter_group_invite_member(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *group_member)
{
pEpLog("called");
return ::group_invite_member(session, group_identity, group_member);
}
PEP_STATUS adapter_group_remove_member(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *group_member)
{
pEpLog("called");
return ::group_remove_member(session, group_identity, group_member);
}
DYNAMIC_API PEP_STATUS adapter_group_rating(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *manager,
PEP_rating *rating)
{
pEpLog("called");
return ::group_rating(session, group_identity, manager, rating);
}
/*************************************************************************************************
* Group query functions
*************************************************************************************************/
//DYNAMIC_API PEP_STATUS group_query_groups(PEP_SESSION session, identity_list **groups)
//{
// pEpLog("called");
// return PEP_STATUS_OK;
//}
//
//DYNAMIC_API PEP_STATUS
//group_query_manager(PEP_SESSION session, const pEp_identity *const group, pEp_identity **manager)
//{
// pEpLog("called");
// return PEP_STATUS_OK;
//}
//
//DYNAMIC_API PEP_STATUS
//group_query_members(PEP_SESSION session, const pEp_identity *const group, identity_list **members)
//{
// pEpLog("called");
// return PEP_STATUS_OK;
//}
#ifdef __cplusplus
}
#endif

+ 2
- 34
src/callback_dispatcher.cc View File

@ -5,6 +5,7 @@
#include "passphrase_cache.hh"
#include <stdexcept>
#include <cassert>
#include "Adapter.hh"
pEp::CallbackDispatcher pEp::callback_dispatcher;
@ -51,7 +52,7 @@ namespace pEp {
}
if (targets.empty()) {
stop_sync();
Adapter::stop_sync();
}
}
@ -73,39 +74,6 @@ namespace pEp {
}
}
void CallbackDispatcher::start_sync()
{
pEpLog("called");
callback_dispatcher.semaphore.go();
pEp::Adapter::startup<CallbackDispatcher>(
CallbackDispatcher::messageToSend,
CallbackDispatcher::notifyHandshake,
&callback_dispatcher,
&CallbackDispatcher::on_startup,
&CallbackDispatcher::on_shutdown);
pEpLog("all targets signal: SYNC_NOTIFY_START");
for (auto target : callback_dispatcher.targets) {
if (target.notifyHandshake) {
target.notifyHandshake(nullptr, nullptr, SYNC_NOTIFY_START);
}
}
}
void CallbackDispatcher::stop_sync()
{
callback_dispatcher.semaphore.stop();
Adapter::shutdown();
callback_dispatcher.semaphore.go();
for (auto target : callback_dispatcher.targets) {
if (target.notifyHandshake) {
target.notifyHandshake(nullptr, nullptr, SYNC_NOTIFY_STOP);
}
}
}
PEP_STATUS CallbackDispatcher::_messageToSend(::message *msg)
{
if (Adapter::on_sync_thread() && !msg) {


+ 3
- 6
src/callback_dispatcher.hh View File

@ -7,10 +7,10 @@
#include <vector>
#include <functional>
#include <mutex>
#include "Adapter.hh"
#include "Semaphore.hh"
#include "passphrase_cache.hh"
#include <pEp/sync_api.h>
namespace pEp {
// use this class when implementing a desktop adapter
// register different interfaces with add()
@ -37,18 +37,15 @@ namespace pEp {
proc on_shutdown = nullptr);
void remove(::messageToSend_t messageToSend);
static void start_sync();
static void stop_sync();
static PEP_STATUS messageToSend(::message *msg);
static PEP_STATUS notifyHandshake(
::pEp_identity *me,
::pEp_identity *partner,
::sync_handshake_signal signal);
protected:
void on_startup();
void on_shutdown();
protected:
PEP_STATUS _messageToSend(::message *msg);
PEP_STATUS _notifyHandshake(


+ 146
- 0
src/group_manager_api.cc View File

@ -0,0 +1,146 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
//#include <pEp/group.h>
// clang-format off
#include "group_manager_api.h"
#include "grp_driver_replicator.hh"
#include "pEpLog.hh"
#include "grp_driver_dummy.hh"
#include "grp_driver_engine.hh"
#ifdef __cplusplus
extern "C" {
#endif
using namespace std;
using namespace pEp;
Adapter::GroupDriverReplicator adapter_grp_manager{};
shared_ptr<Adapter::GroupDriverDummy> grp_drv_dummy;
shared_ptr<Adapter::GroupDriverEngine> grp_drv_engine;
DYNAMIC_API PEP_STATUS adapter_group_init()
{
PEP_STATUS status;
try {
const string lm_dummy_db_filename = "groups.db";
#ifdef WIN32
const string lm_dummy_db_path = string(::per_user_directory()) + "\\" + lm_dummy_db_filename;
#else
const string lm_dummy_db_path = string(::per_user_directory()) + "/" + lm_dummy_db_filename;
#endif
if(!grp_drv_dummy) {
grp_drv_dummy = make_shared<Adapter::GroupDriverDummy>(lm_dummy_db_path);
}
if(!grp_drv_engine) {
grp_drv_engine = make_shared<Adapter::GroupDriverEngine>();
}
adapter_grp_manager.set_replication_source(*grp_drv_dummy.get());
adapter_grp_manager.set_replication_destination(*grp_drv_engine.get());
} catch (const std::exception &e) {
pEpLog(Utils::nested_exception_to_string(e));
status = PEP_UNKNOWN_ERROR;
} catch (...) {
pEpLog("unknown exception");
status = PEP_UNKNOWN_ERROR;
}
return status;
}
/*************************************************************************************************
* Group management functions
*************************************************************************************************/
DYNAMIC_API PEP_STATUS adapter_group_create(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *manager,
identity_list *memberlist)
{
pEpLog("called");
PEP_STATUS status = adapter_grp_manager.adapter_group_create(
session,
group_identity,
manager,
memberlist);
return status;
}
DYNAMIC_API PEP_STATUS adapter_group_dissolve(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *manager)
{
pEpLog("called");
PEP_STATUS status = adapter_grp_manager.adapter_group_dissolve(session, group_identity, manager);
return status;
}
DYNAMIC_API PEP_STATUS adapter_group_invite_member(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *group_member)
{
pEpLog("called");
PEP_STATUS status = adapter_grp_manager.adapter_group_invite_member(
session,
group_identity,
group_member);
return status;
}
DYNAMIC_API PEP_STATUS adapter_group_remove_member(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *group_member)
{
pEpLog("called");
PEP_STATUS status = adapter_grp_manager.adapter_group_remove_member(
session,
group_identity,
group_member);
return status;
}
DYNAMIC_API PEP_STATUS adapter_group_join(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *as_member)
{
pEpLog("called");
PEP_STATUS status = adapter_grp_manager.adapter_group_join(session, group_identity, as_member);
return status;
}
/*************************************************************************************************
* Group query functions
*************************************************************************************************/
DYNAMIC_API PEP_STATUS adapter_group_query_groups(PEP_SESSION session, identity_list **groups)
{
pEpLog("called");
PEP_STATUS status = adapter_grp_manager.group_query_groups(session, groups);
return status;
}
DYNAMIC_API PEP_STATUS
adapter_group_query_manager(PEP_SESSION session, const pEp_identity *const group, pEp_identity **manager)
{
pEpLog("called");
PEP_STATUS status = adapter_grp_manager.group_query_manager(session, group, manager);
return status;
}
DYNAMIC_API PEP_STATUS adapter_group_query_members(
PEP_SESSION session,
const pEp_identity *const group,
identity_list **members)
{
pEpLog("called");
PEP_STATUS status = adapter_grp_manager.group_query_members(session, group, members);
return status;
}
#ifdef __cplusplus
}
#endif

src/adapter_group.h → src/group_manager_api.h View File


+ 383
- 0
src/grp_driver_dummy.cc View File

@ -0,0 +1,383 @@
#include "grp_driver_dummy.hh"
#include "pEpLog.hh"
#include "utils.hh"
#include "std_utils.hh"
#include <pEp/message_api.h>
#include "listmanager_dummy.hh"
using namespace std;
namespace pEp {
namespace Adapter {
bool GroupDriverDummy::log_enabled = false;
GroupDriverDummy::GroupDriverDummy(const std::string &db_path) :
lmd(ListManagerDummy(db_path))
{
pEpLogClass("called");
}
PEP_STATUS GroupDriverDummy::adapter_group_create(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *manager,
identity_list *memberlist) noexcept
{
pEpLogClass("called");
PEP_STATUS status = PEP_UNKNOWN_ERROR;
if (!group_identity || !manager) {
status = PEP_ILLEGAL_VALUE;
} else {
if (Utils::is_c_str_empty(group_identity->address) ||
Utils::is_c_str_empty(manager->address)) {
status = PEP_ILLEGAL_VALUE;
} else {
const string addr_list{ group_identity->address };
const string addr_manager{ manager->address };
try {
lmd.list_add(addr_list, addr_manager);
status = PEP_STATUS_OK;
} catch (const AlreadyExistsException &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_GROUP_EXISTS;
} catch (const exception &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_UNKNOWN_ERROR;
} catch (...) {
pEpLogClass("unknown exception");
status = PEP_UNKNOWN_ERROR;
}
if (status == PEP_STATUS_OK) {
// Add the memberlist (if given)
// Fail totally on the first member_invite() that fails
const vector<pEp_identity *> cxx_memberlist = Utils::to_cxx(*memberlist);
for (pEp_identity *const member : cxx_memberlist) {
status = this->adapter_group_invite_member(session, group_identity, member);
if (status != PEP_STATUS_OK) {
status = status;
break;
}
}
}
}
}
return status;
}
// The engine checks if the manager is correct for the group given
// But the list manager does not require that
// So, we verify that first, too. using moderator()
PEP_STATUS GroupDriverDummy::adapter_group_dissolve(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *manager) noexcept
{
pEpLogClass("called");
PEP_STATUS status = PEP_UNKNOWN_ERROR;
if (!group_identity || !manager) {
status = PEP_ILLEGAL_VALUE;
} else {
if (Utils::is_c_str_empty(group_identity->address) ||
Utils::is_c_str_empty(manager->address)) {
status = PEP_ILLEGAL_VALUE;
} else {
const string addr_list{ group_identity->address };
const string addr_manager{ manager->address };
// Check if given manager is correct for the given group
string addr_manager_queried;
try {
addr_manager_queried = lmd.moderator(addr_list);
status = PEP_STATUS_OK;
} catch (const ListDoesNotExistException &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_GROUP_NOT_FOUND;
} catch (const exception &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_UNKNOWN_ERROR;
} catch (...) {
pEpLogClass("unknown exception");
status = PEP_UNKNOWN_ERROR;
}
if (status == PEP_STATUS_OK) {
if (addr_manager_queried != addr_manager) {
status = PEP_CANNOT_DISABLE_GROUP;
} else {
try {
lmd.list_delete(addr_list);
status = PEP_STATUS_OK;
} catch (const MemberDoesNotExistException &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
// TODO: Silently succeed???
status = PEP_STATUS_OK;
} catch (const ListDoesNotExistException &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_GROUP_NOT_FOUND;
} catch (const exception &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_UNKNOWN_ERROR;
} catch (...) {
pEpLogClass("unknown exception");
status = PEP_UNKNOWN_ERROR;
}
}
}
}
}
return status;
}
PEP_STATUS GroupDriverDummy::adapter_group_invite_member(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *group_member) noexcept
{
pEpLogClass("called");
PEP_STATUS status = PEP_UNKNOWN_ERROR;
if (!group_identity || !group_member) {
status = PEP_ILLEGAL_VALUE;
} else {
if (Utils::is_c_str_empty(group_identity->address) ||
Utils::is_c_str_empty(group_member->address)) {
status = PEP_ILLEGAL_VALUE;
} else {
const string addr_list{ group_identity->address };
const string addr_member{ group_member->address };
try {
lmd.member_add(addr_list, addr_member);
status = PEP_STATUS_OK;
} catch (const AlreadyExistsException &e) {
// TODO: Silently succeed???
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_STATUS_OK;
} catch (const ListDoesNotExistException &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
return PEP_GROUP_NOT_FOUND;
} catch (const exception &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_UNKNOWN_ERROR;
} catch (...) {
pEpLogClass("unknown exception");
status = PEP_UNKNOWN_ERROR;
}
}
}
return status;
}
PEP_STATUS GroupDriverDummy::adapter_group_remove_member(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *group_member) noexcept
{
pEpLogClass("called");
PEP_STATUS status = PEP_UNKNOWN_ERROR;
if (!group_identity || !group_member) {
status = PEP_ILLEGAL_VALUE;
} else {
if (Utils::is_c_str_empty(group_identity->address) ||
Utils::is_c_str_empty(group_member->address)) {
status = PEP_ILLEGAL_VALUE;
} else {
const string addr_list{ group_identity->address };
const string addr_member{ group_member->address };
try {
lmd.member_remove(addr_list, addr_member);
status = PEP_STATUS_OK;
} catch (const MemberDoesNotExistException &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
// TODO: Silently succeed???
status = PEP_STATUS_OK;
} catch (const ListDoesNotExistException &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_GROUP_NOT_FOUND;
} catch (const exception &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_UNKNOWN_ERROR;
} catch (...) {
pEpLogClass("unknown exception");
status = PEP_UNKNOWN_ERROR;
}
}
}
return status;
}
PEP_STATUS GroupDriverDummy::adapter_group_join(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *as_member) noexcept
{
pEpLogClass("called");
// TODO: listmanager member db list_join()
// PEP_STATUS status = PEP_UNKNOWN_ERROR;
// if (!group_identity || !group_member) {
// status = PEP_ILLEGAL_VALUE;
// } else {
// if (Utils::is_c_str_empty(group_identity->address) ||
// Utils::is_c_str_empty(group_member->address)) {
// status = PEP_ILLEGAL_VALUE;
// } else {
// const string addr_list{ group_identity->address };
// const string addr_member{ group_member->address };
//
// try {
// lmd.member_remove(addr_list, addr_member);
// status = PEP_STATUS_OK;
// } catch (const MemberDoesNotExistException &e) {
// pEpLogClass(Utils::nested_exception_to_string(e));
// // TODO: Silently succeed???
// status = PEP_STATUS_OK;
// } catch (const ListDoesNotExistException &e) {
// pEpLogClass(Utils::nested_exception_to_string(e));
// status = PEP_GROUP_NOT_FOUND;
// } catch (const exception &e) {
// pEpLogClass(Utils::nested_exception_to_string(e));
// status = PEP_UNKNOWN_ERROR;
// } catch (...) {
// pEpLogClass("unknown exception");
// status = PEP_UNKNOWN_ERROR;
// }
// }
// }
return PEP_STATUS_OK;
}
PEP_STATUS GroupDriverDummy::group_query_groups(PEP_SESSION session, identity_list **groups) noexcept
{
pEpLogClass("called");
PEP_STATUS status = PEP_UNKNOWN_ERROR;
if (!session) {
status = PEP_ILLEGAL_VALUE;
} else {
vector<string> lists_queried;
try {
lists_queried = lmd.lists();
status = PEP_STATUS_OK;
} catch (const exception &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_UNKNOWN_ERROR;
} catch (...) {
pEpLogClass("unknown exception");
status = PEP_UNKNOWN_ERROR;
}
if (status == PEP_STATUS_OK) {
::identity_list *idl_groups = ::new_identity_list(nullptr);
for (const string &addr_list : lists_queried) {
::pEp_identity *grp_ident = ::new_identity(
addr_list.c_str(),
nullptr,
nullptr,
nullptr);
::update_identity(session, grp_ident);
identity_list_add(idl_groups, grp_ident);
}
*groups = idl_groups;
}
}
return status;
}
PEP_STATUS GroupDriverDummy::group_query_manager(
PEP_SESSION session,
const pEp_identity *const group,
pEp_identity **manager) noexcept
{
pEpLogClass("called");
PEP_STATUS status = PEP_UNKNOWN_ERROR;
if (!session || !group) {
status = PEP_ILLEGAL_VALUE;
} else {
const string addr_list{ group->address };
string addr_manager{};
try {
addr_manager = lmd.moderator(addr_list);
status = PEP_STATUS_OK;
} catch (const ListDoesNotExistException &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_GROUP_NOT_FOUND;
} catch (const exception &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_UNKNOWN_ERROR;
} catch (...) {
pEpLogClass("unknown exception");
status = PEP_UNKNOWN_ERROR;
}
if (status == PEP_STATUS_OK) {
::pEp_identity *manager_queried = ::new_identity(
addr_manager.c_str(),
nullptr,
nullptr,
nullptr);
::update_identity(session, manager_queried);
*manager = manager_queried;
}
}
return status;
}
PEP_STATUS GroupDriverDummy::group_query_members(
PEP_SESSION session,
const pEp_identity *const group,
identity_list **members) noexcept
{
pEpLogClass("called");
PEP_STATUS status = PEP_UNKNOWN_ERROR;
if (!session || !group) {
status = PEP_ILLEGAL_VALUE;
} else {
if (Utils::is_c_str_empty(group->address)) {
status = PEP_ILLEGAL_VALUE;
} else {
const string addr_grp{ group->address };
vector<string> members_queried;
try {
members_queried = lmd.members(addr_grp);
status = PEP_STATUS_OK;
} catch (const ListDoesNotExistException &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_GROUP_NOT_FOUND;
} catch (const exception &e) {
pEpLogClass(Utils::nested_exception_to_string(e));
status = PEP_UNKNOWN_ERROR;
} catch (...) {
pEpLogClass("unknown exception");
status = PEP_UNKNOWN_ERROR;
}
if (status == PEP_STATUS_OK) {
::identity_list *idl_members = ::new_identity_list(nullptr);
for (const string &addr_member : members_queried) {
::pEp_identity *member_ident = ::new_identity(
addr_member.c_str(),
nullptr,
nullptr,
nullptr);
::update_identity(session, member_ident);
identity_list_add(idl_members, member_ident);
}
*members = idl_members;
}
}
}
return status;
}
} // namespace Adapter
} // namespace pEp

+ 69
- 0
src/grp_driver_dummy.hh View File

@ -0,0 +1,69 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef LIBPEPADAPTER_GRP_DRIVER_DUMMY_HH
#define LIBPEPADAPTER_GRP_DRIVER_DUMMY_HH
#include "grp_manager_interface.hh"
#include "pEpLog.hh"
#include "listmanager_dummy.hh"
#include <pEp/message_api.h>
namespace pEp {
namespace Adapter {
class GroupDriverDummy : public GroupManagerInterface {
public:
GroupDriverDummy() = delete;
explicit GroupDriverDummy(const std::string &db_path);
// GroupUpdateInterface
PEP_STATUS adapter_group_create(
::PEP_SESSION session,
::pEp_identity *group_identity,
::pEp_identity *manager,
::identity_list *memberlist) noexcept override;
PEP_STATUS adapter_group_dissolve(
::PEP_SESSION session,
::pEp_identity *group_identity,
::pEp_identity *manager) noexcept override;
PEP_STATUS adapter_group_invite_member(
::PEP_SESSION session,
::pEp_identity *group_identity,
::pEp_identity *group_member) noexcept override;
PEP_STATUS adapter_group_remove_member(
::PEP_SESSION session,
::pEp_identity *group_identity,
::pEp_identity *group_member) noexcept override;
PEP_STATUS adapter_group_join(
::PEP_SESSION session,
::pEp_identity *group_identity,
::pEp_identity *as_member) noexcept override;
// GroupQueryInterface
PEP_STATUS group_query_groups(::PEP_SESSION session, ::identity_list **groups) noexcept override;
PEP_STATUS group_query_manager(
::PEP_SESSION session,
const ::pEp_identity *const group,
::pEp_identity **manager) noexcept override;
PEP_STATUS group_query_members(
::PEP_SESSION session,
const ::pEp_identity *const group,
::identity_list **members) noexcept override;
// Logging
static bool log_enabled;
Adapter::pEpLog::pEpLogger logger{ "GroupDriverDummy", log_enabled };
private:
ListManagerDummy lmd;
Adapter::pEpLog::pEpLogger &m4gic_logger_n4me = logger;
};
} // namespace Adapter
} // namespace pEp
#endif // LIBPEPADAPTER_GRP_DRIVER_DUMMY_HH

+ 63
- 0
src/grp_driver_engine.cc View File

@ -0,0 +1,63 @@
#include "grp_driver_engine.hh"
#include "pEpLog.hh"
#include <pEp/message_api.h>
#include <pEp/group.h>
using namespace std;
namespace pEp {
namespace Adapter {
bool GroupDriverEngine::log_enabled = false;
GroupDriverEngine::GroupDriverEngine()
{
pEpLogClass("called");
}
PEP_STATUS GroupDriverEngine::adapter_group_create(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *manager,
identity_list *memberlist) noexcept
{
pEpLogClass("called");
return ::group_create(session, group_identity, manager, memberlist, nullptr);
}
PEP_STATUS GroupDriverEngine::adapter_group_dissolve(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *manager) noexcept
{
pEpLogClass("called");
return ::group_dissolve(session, group_identity, manager);
}
PEP_STATUS GroupDriverEngine::adapter_group_invite_member(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *group_member) noexcept
{
pEpLogClass("called");
return ::group_invite_member(session, group_identity, group_member);
}
PEP_STATUS GroupDriverEngine::adapter_group_remove_member(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *group_member) noexcept
{
pEpLogClass("called");
return ::group_remove_member(session, group_identity, group_member);
}
PEP_STATUS GroupDriverEngine::adapter_group_join(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *as_member) noexcept
{
pEpLogClass("called");
return ::group_join(session, group_identity, as_member);
}
} // namespace Adapter
} // namespace pEp

+ 52
- 0
src/grp_driver_engine.hh View File

@ -0,0 +1,52 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef LIBPEPADAPTER_GRP_DRIVER_ENGINE_HH
#define LIBPEPADAPTER_GRP_DRIVER_ENGINE_HH
#include "grp_manager_interface.hh"
#include "pEpLog.hh"
#include <pEp/message_api.h>
namespace pEp {
namespace Adapter {
class GroupDriverEngine : public GroupUpdateInterface {
public:
GroupDriverEngine();
PEP_STATUS adapter_group_create(
::PEP_SESSION session,
::pEp_identity *group_identity,
::pEp_identity *manager,
::identity_list *memberlist) noexcept override;
PEP_STATUS adapter_group_dissolve(
::PEP_SESSION session,
::pEp_identity *group_identity,
::pEp_identity *manager) noexcept override;
PEP_STATUS adapter_group_invite_member(
::PEP_SESSION session,
::pEp_identity *group_identity,
::pEp_identity *group_member) noexcept override;
PEP_STATUS adapter_group_remove_member(
::PEP_SESSION session,
::pEp_identity *group_identity,
::pEp_identity *group_member) noexcept override;
PEP_STATUS adapter_group_join(
::PEP_SESSION session,
::pEp_identity *group_identity,
::pEp_identity *as_member) noexcept override;
// Logging
static bool log_enabled;
Adapter::pEpLog::pEpLogger logger{ "GroupDriverEngine", log_enabled };
private:
Adapter::pEpLog::pEpLogger &m4gic_logger_n4me = logger;
};
} // namespace Adapter
} // namespace pEp
#endif // LIBPEPADAPTER_GRP_DRIVER_ENGINE_HH

+ 267
- 0
src/grp_driver_replicator.cc View File

@ -0,0 +1,267 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "grp_driver_replicator.hh"
using namespace std;
namespace pEp {
namespace Adapter {
bool GroupDriverReplicator::log_enabled = false;
GroupDriverReplicator::GroupDriverReplicator()
{
pEpLogClass("called");
/* const string lm_dummy_db_filename = "listman_dummy.db";
#ifdef WIN32
const string lm_dummy_db_path = string(::per_user_directory()) + "\\" +
lm_dummy_db_filename;
#else
const string lm_dummy_db_path = string(::per_user_directory()) + "/" +
lm_dummy_db_filename;
#endif
default_repl_src = make_shared<GroupDriverDummy>(lm_dummy_db_path);
set_replication_source(*default_repl_src);
default_repl_dst = make_shared<GroupDriverEngine>();
set_replication_destination(*default_repl_dst);
*/
}
void GroupDriverReplicator::set_replication_source(GroupManagerInterface &src)
{
pEpLogClass("called");
repl_src = &src;
}
void GroupDriverReplicator::set_replication_destination(GroupUpdateInterface &dst)
{
pEpLogClass("called");
repl_dst = &dst;
}
// GroupUpdateInterface
PEP_STATUS GroupDriverReplicator::adapter_group_create(
PEP_SESSION session,
pEp_identity *group_identity,
pEp_identity *manager,
identity_list *memberlist) noexcept
{
pEpLogClass("called");
if (!has_repl_src_and_dst()) {
return PEP_UNKNOWN_ERROR;
}
// Do listmanager
PEP_STATUS status = repl_src->adapter_group_create(
session,
group_identity,
manager,
memberlist);
if (status != PEP_STATUS_OK) {
return status;
}
// Do engine
status = repl_dst->adapter_group_create(session, group_identity, manager, memberlist);
if (status != PEP_STATUS_OK) {
// Rollback listman
PEP_STATUS rb_stat = repl_src->adapter_group_dissolve(session, group_identity, manager);
if (rb_stat != PEP_STATUS_OK) {
//FATAL ERROR ON ROLLBACK
status = (PEP_STATUS)-9999;
}
}
return status;
}
PEP_STATUS GroupDriverReplicator::adapter_group_dissolve(