CpEpEngine.cpp
author Volker Birk <vb@pep-project.org>
Wed, 23 Nov 2016 20:22:17 +0100
changeset 219 03531c4d3fda
parent 218 ef80732697e6
child 220 92489901bb81
permissions -rw-r--r--
switch to pEpIdentityFlags data type
vb@0
     1
// CpEpEngine.cpp : Implementation of CpEpEngine
vb@0
     2
vb@0
     3
#include "stdafx.h"
vb@0
     4
#include "CpEpEngine.h"
vb@0
     5
vb@10
     6
using namespace std;
vb@10
     7
using namespace pEp::utility;
vb@0
     8
vb@0
     9
// CpEpEngine
vb@0
    10
vb@0
    11
STDMETHODIMP CpEpEngine::InterfaceSupportsErrorInfo(REFIID riid)
vb@0
    12
{
markus@165
    13
	static const IID* const arr[] =
vb@0
    14
	{
vb@0
    15
		&IID_IpEpEngine
vb@0
    16
	};
vb@0
    17
markus@165
    18
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
vb@0
    19
	{
markus@165
    20
		if (InlineIsEqualGUID(*arr[i], riid))
vb@0
    21
			return S_OK;
vb@0
    22
	}
vb@0
    23
	return S_FALSE;
vb@0
    24
}
vb@0
    25
markus@189
    26
// The second argument is optional, and currently supports PEP_STATUS.
markus@189
    27
#define FAIL(msg, ...) error(msg, __VA_ARGS__)
vb@0
    28
markus@172
    29
STDMETHODIMP CpEpEngine::VerboseLogging(VARIANT_BOOL enable)
vb@51
    30
{
markus@165
    31
	verbose_mode = enable != VARIANT_FALSE;
markus@165
    32
	return S_OK;
vb@60
    33
}
vb@60
    34
markus@172
    35
STDMETHODIMP CpEpEngine::PassiveMode(VARIANT_BOOL enable)
vb@60
    36
{
markus@165
    37
	::config_passive_mode(get_session(), enable != VARIANT_FALSE);
markus@165
    38
	return S_OK;
vb@60
    39
}
vb@60
    40
markus@172
    41
STDMETHODIMP CpEpEngine::UnencryptedSubject(VARIANT_BOOL enable)
vb@60
    42
{
markus@165
    43
	::config_unencrypted_subject(get_session(), enable != VARIANT_FALSE);
markus@165
    44
	return S_OK;
vb@51
    45
}
vb@0
    46
Dean@184
    47
STDMETHODIMP CpEpEngine::ExportKey(BSTR fpr, BSTR * keyData)
Dean@183
    48
{
Dean@183
    49
    assert(fpr);
Dean@185
    50
    assert(keyData);
Dean@183
    51
markus@192
    52
    if (!(fpr && keyData))
Dean@183
    53
        return E_INVALIDARG;
Dean@183
    54
Dean@183
    55
    string _fpr = utf8_string(fpr);
Dean@183
    56
    char *_key_data = NULL;
Dean@183
    57
    size_t _size = 0;
Dean@183
    58
Dean@183
    59
    ::PEP_STATUS status = ::export_key(get_session(), _fpr.c_str(), &_key_data, &_size);
Dean@183
    60
    assert(status != ::PEP_OUT_OF_MEMORY);
Dean@183
    61
    if (status == ::PEP_OUT_OF_MEMORY)
Dean@183
    62
        return E_OUTOFMEMORY;
Dean@183
    63
Dean@183
    64
    if (status != ::PEP_STATUS_OK)
markus@189
    65
        return FAIL(L"export_key", status);
Dean@183
    66
Dean@183
    67
    _bstr_t b_key_data(utf16_string(_key_data).c_str());
Dean@183
    68
    pEp_free(_key_data);
Dean@184
    69
    * keyData = b_key_data.Detach();
Dean@183
    70
Dean@183
    71
    return S_OK;
Dean@183
    72
}
Dean@183
    73
markus@177
    74
STDMETHODIMP CpEpEngine::Log(BSTR title, BSTR entity, BSTR description, BSTR comment)
vb@0
    75
{
markus@165
    76
	string _title;
markus@165
    77
	string _entity;
markus@165
    78
	string _description;
markus@165
    79
	string _comment;
markus@165
    80
	HRESULT result = S_OK;
vb@0
    81
markus@165
    82
	assert(title);
markus@165
    83
	if (title)
markus@165
    84
		_title = utf8_string(title);
markus@165
    85
	else
markus@165
    86
		result = E_INVALIDARG;
vb@0
    87
markus@165
    88
	assert(entity);
markus@165
    89
	if (entity)
markus@165
    90
		_entity = utf8_string(entity);
markus@165
    91
	else
markus@165
    92
		result = E_INVALIDARG;
vb@0
    93
markus@165
    94
	if (description)
markus@165
    95
		_description = utf8_string(description);
vb@0
    96
markus@165
    97
	if (comment)
markus@165
    98
		_comment = utf8_string(comment);
vb@0
    99
markus@165
   100
	if (result != S_OK)
markus@165
   101
		return result;
vb@0
   102
markus@165
   103
	PEP_STATUS _status = ::log_event(get_session(), _title.c_str(), _entity.c_str(), _description.c_str(), _comment.c_str());
markus@165
   104
	assert(_status == PEP_STATUS_OK);
markus@165
   105
	if (_status != PEP_STATUS_OK)
markus@189
   106
		return FAIL(L"log_event", _status);
markus@165
   107
	else
markus@165
   108
		return S_OK;
vb@0
   109
}
vb@0
   110
Dean@202
   111
STDMETHODIMP CpEpEngine::Trustwords(BSTR fpr, BSTR lang, LONG max_words, BSTR * words)
vb@0
   112
{
markus@165
   113
	assert(fpr);
markus@165
   114
	assert(max_words >= 0);
markus@165
   115
	assert(words);
vb@0
   116
markus@165
   117
	HRESULT result = S_OK;
vb@0
   118
markus@165
   119
	string _fpr;
markus@165
   120
	if (fpr)
markus@165
   121
		_fpr = utf8_string(fpr);
markus@165
   122
	else
markus@165
   123
		result = E_INVALIDARG;
vb@0
   124
markus@165
   125
	string _lang;
markus@165
   126
	if (lang) {
markus@165
   127
		_lang = utf8_string(lang);
markus@165
   128
		if (_lang.length()) {
markus@165
   129
			if (_lang.length() != 2)
markus@165
   130
				result = E_INVALIDARG;
markus@165
   131
		}
markus@165
   132
		else
markus@165
   133
			_lang = "en";
markus@165
   134
	}
markus@165
   135
	else
markus@165
   136
		_lang = "en";
vb@0
   137
markus@165
   138
	if (max_words < 0)
markus@165
   139
		result = E_INVALIDARG;
vb@0
   140
markus@165
   141
	if (words == NULL)
markus@165
   142
		result = E_INVALIDARG;
vb@0
   143
markus@165
   144
	if (result != S_OK)
markus@165
   145
		return result;
vb@0
   146
markus@165
   147
	char *_words = NULL;
markus@165
   148
	size_t _wsize = 0;
vb@0
   149
markus@165
   150
	PEP_STATUS status = ::trustwords(get_session(), _fpr.c_str(), _lang.c_str(), &_words, &_wsize, max_words);
markus@165
   151
	assert(status != PEP_OUT_OF_MEMORY);
markus@165
   152
	if (status == PEP_OUT_OF_MEMORY)
markus@165
   153
		return E_OUTOFMEMORY;
vb@0
   154
markus@165
   155
	if (_words == NULL) {
markus@165
   156
		*words = NULL;
Dean@202
   157
		return FAIL(L"Trustwords: _words == NULL", status);
markus@165
   158
	}
markus@165
   159
	else {
markus@165
   160
		*words = utf16_bstr(_words);
markus@165
   161
		pEp_free(_words);
markus@165
   162
		return S_OK;
markus@165
   163
	}
vb@0
   164
}
vb@0
   165
Dean@202
   166
STDMETHODIMP CpEpEngine::GetTrustwords(struct pEpIdentity *id1, struct pEpIdentity *id2, BSTR lang, VARIANT_BOOL full, BSTR *words)
markus@190
   167
{
markus@190
   168
    assert(id1);
markus@190
   169
    assert(id2);
markus@190
   170
    assert(words);
markus@190
   171
markus@192
   172
    if (!(id1 && id2 && words))
markus@190
   173
    {
markus@190
   174
        return E_INVALIDARG;
markus@190
   175
    }
markus@190
   176
markus@190
   177
    HRESULT result = S_OK;
markus@190
   178
markus@190
   179
    pEp_identity* _id1 = NULL;
markus@190
   180
    pEp_identity* _id2 = NULL;
markus@190
   181
    string _lang;
markus@190
   182
    *words = NULL;
markus@190
   183
markus@190
   184
    try {
markus@190
   185
        _id1 = new_identity(id1);
markus@190
   186
        _id2 = new_identity(id2);
markus@190
   187
markus@190
   188
        if (!lang) {
markus@190
   189
            _lang = utf8_string(lang);
markus@190
   190
            if (_lang.length() == 0) {
markus@190
   191
                _lang = "en";
markus@190
   192
            } else if (_lang.length() != 2) {
markus@190
   193
                result = E_INVALIDARG;
markus@190
   194
            }
markus@190
   195
        } else {
markus@190
   196
            _lang = "en";
markus@190
   197
        }
markus@190
   198
    } catch (bad_alloc&) {
markus@190
   199
        result = E_OUTOFMEMORY;
markus@190
   200
    } catch (exception& ex) {
markus@190
   201
        result = FAIL(ex.what());
markus@190
   202
    }
markus@190
   203
markus@190
   204
    char* _words;
markus@190
   205
    size_t _size;
Dean@203
   206
    if (result == S_OK) {
markus@190
   207
        auto status = ::get_trustwords(get_session(), _id1, _id2, _lang.c_str(), &_words, &_size, full != 0 /* convert variant bool to C bool */);
markus@190
   208
markus@190
   209
        if (status == PEP_OUT_OF_MEMORY) {
markus@190
   210
            result = E_OUTOFMEMORY;
markus@190
   211
        }
markus@190
   212
        else if (status == PEP_TRUSTWORD_NOT_FOUND) {
Dean@202
   213
            result = FAIL(L"GetTrustwords: Trustword not found", status);
markus@190
   214
        }
markus@190
   215
        else if (!words) {
Dean@202
   216
            result = FAIL(L"GetTrustwords: _words == NULL", status);
markus@190
   217
        }
markus@190
   218
        else {
markus@190
   219
            *words = utf16_bstr(_words);
markus@190
   220
            pEp_free(_words);
markus@190
   221
        }
markus@190
   222
    }
markus@190
   223
markus@190
   224
    free_identity(_id1);
markus@190
   225
    free_identity(_id2);
markus@190
   226
markus@190
   227
    return result;
markus@190
   228
}
markus@190
   229
markus@190
   230
markus@172
   231
STDMETHODIMP CpEpEngine::GetCrashdumpLog(LONG maxlines, BSTR * log)
vb@57
   232
{
markus@194
   233
	// COM-18: Currently, long == int on windows, so the check
markus@194
   234
	// for INT_MAX is not strictly necessary. However, the code
markus@194
   235
	// might get copy-pasted to other adapters in the future,
markus@194
   236
	// so safety first...
markus@194
   237
	assert(maxlines >= 0 && maxlines <= INT_MAX);
markus@165
   238
	assert(log);
vb@57
   239
markus@194
   240
	if (!(maxlines >= 0 && maxlines <= INT_MAX && log))
markus@165
   241
		return E_INVALIDARG;
vb@57
   242
markus@165
   243
	char *_log;
markus@165
   244
	PEP_STATUS status = ::get_crashdump_log(get_session(), (int)maxlines, &_log);
markus@165
   245
	assert(status == PEP_STATUS_OK);
markus@165
   246
	if (status == PEP_OUT_OF_MEMORY)
markus@165
   247
		return E_OUTOFMEMORY;
markus@189
   248
	if (status != PEP_STATUS_OK)
markus@189
   249
		return FAIL(L"GetCrashdumpLog", status);
markus@189
   250
    if (_log == NULL)
markus@189
   251
        return FAIL(L"GetCrashdumpLog: _log == NULL");
vb@57
   252
markus@165
   253
	*log = utf16_bstr(_log);
markus@165
   254
	pEp_free(_log);
markus@165
   255
	return S_OK;
vb@57
   256
}
vb@57
   257
markus@172
   258
STDMETHODIMP CpEpEngine::GetEngineVersion(BSTR * engine_version)
Dean@151
   259
{
markus@165
   260
	assert(engine_version);
Dean@151
   261
markus@165
   262
	if (!engine_version)
markus@165
   263
		return E_INVALIDARG;
Dean@151
   264
Dean@174
   265
	const char *_engine_version = ::get_engine_version();
Dean@151
   266
Dean@174
   267
	if (_engine_version == NULL)
markus@189
   268
		return FAIL(L"GetEngineVersion: _engine_version == NULL");
Dean@151
   269
Dean@174
   270
	*engine_version = utf16_bstr(_engine_version);
Dean@151
   271
markus@165
   272
	return S_OK;
Dean@151
   273
}
Dean@151
   274
markus@177
   275
STDMETHODIMP CpEpEngine::GetLanguageList(BSTR * languages)
vb@59
   276
{
markus@165
   277
	assert(languages);
vb@59
   278
markus@165
   279
	if (!languages)
markus@165
   280
		return E_INVALIDARG;
vb@59
   281
markus@165
   282
	char *_languages;
markus@165
   283
	PEP_STATUS status = ::get_languagelist(get_session(), &_languages);
markus@165
   284
	assert(status == PEP_STATUS_OK);
markus@165
   285
	if (status == PEP_OUT_OF_MEMORY)
markus@165
   286
		return E_OUTOFMEMORY;
markus@189
   287
    if (status != PEP_STATUS_OK)
markus@189
   288
        return FAIL(L"GetLanguageList", status);
markus@189
   289
	if (_languages == NULL)
markus@189
   290
		return FAIL(L"GetLanguageList: _languages == NULL");
vb@59
   291
markus@165
   292
	*languages = utf16_bstr(_languages);
markus@165
   293
	pEp_free(_languages);
markus@165
   294
	return S_OK;
vb@59
   295
}
vb@59
   296
vb@219
   297
STDMETHODIMP CpEpEngine::SetIdentityFlags(struct pEpIdentity *identity, pEpIdentityFlags flags)
vb@218
   298
{
vb@219
   299
	assert(identity);
vb@219
   300
	if (!identity)
vb@219
   301
		return E_INVALIDARG;
vb@219
   302
vb@218
   303
	::pEp_identity *_ident = nullptr;
vb@218
   304
vb@218
   305
	try {
vb@218
   306
		_ident = new_identity(identity);
vb@218
   307
		assert(_ident);
vb@218
   308
		if (_ident == NULL)
vb@218
   309
			return E_OUTOFMEMORY;
vb@218
   310
	}
vb@218
   311
	catch (bad_alloc&) {
vb@218
   312
		return E_OUTOFMEMORY;
vb@218
   313
	}
vb@218
   314
	catch (exception& ex) {
vb@218
   315
		return FAIL(ex.what());;
vb@218
   316
	}
vb@218
   317
vb@218
   318
	PEP_STATUS status = ::set_identity_flags(get_session(), _ident, (identity_flags_t)flags);
vb@218
   319
	::free_identity(_ident);
vb@218
   320
	if (status != PEP_STATUS_OK)
vb@218
   321
		return FAIL(_T("SetIdentityFlags"), status);
vb@218
   322
vb@218
   323
	return S_OK;
vb@218
   324
}
vb@218
   325
vb@219
   326
STDMETHODIMP CpEpEngine::UnsetIdentityFlags(struct pEpIdentity *identity, pEpIdentityFlags flags)
vb@218
   327
{
vb@219
   328
	assert(identity);
vb@219
   329
	if (!identity)
vb@219
   330
		return E_INVALIDARG;
vb@219
   331
vb@218
   332
	::pEp_identity *_ident = nullptr;
vb@218
   333
vb@218
   334
	try {
vb@218
   335
		_ident = new_identity(identity);
vb@218
   336
		assert(_ident);
vb@218
   337
		if (_ident == NULL)
vb@218
   338
			return E_OUTOFMEMORY;
vb@218
   339
	}
vb@218
   340
	catch (bad_alloc&) {
vb@218
   341
		return E_OUTOFMEMORY;
vb@218
   342
	}
vb@218
   343
	catch (exception& ex) {
vb@218
   344
		return FAIL(ex.what());;
vb@218
   345
	}
vb@218
   346
vb@218
   347
	PEP_STATUS status = ::unset_identity_flags(get_session(), _ident, (identity_flags_t)flags);
vb@218
   348
	::free_identity(_ident);
vb@218
   349
	if (status != PEP_STATUS_OK)
vb@218
   350
		return FAIL(_T("UnsetIdentityFlags"), status);
vb@218
   351
vb@218
   352
	return S_OK;
vb@218
   353
}
vb@218
   354
markus@172
   355
STDMETHODIMP CpEpEngine::StartKeyserverLookup()
vb@24
   356
{
markus@165
   357
	if (identity_queue.load())
markus@165
   358
		return S_OK;
vb@24
   359
markus@165
   360
	identity_queue.store(new identity_queue_t());
markus@165
   361
	keymanagement_thread = new thread(::do_keymanagement, retrieve_next_identity, (void *)identity_queue.load());
markus@165
   362
markus@165
   363
	return S_OK;
vb@24
   364
}
vb@24
   365
markus@172
   366
STDMETHODIMP CpEpEngine::StopKeyserverLookup()
vb@24
   367
{
markus@165
   368
	if (identity_queue.load() == NULL)
markus@165
   369
		return S_OK;
vb@24
   370
markus@165
   371
	identity_queue_t *_iq = identity_queue.load();
markus@165
   372
	identity_queue.store(NULL);
vb@25
   373
markus@165
   374
	pEp_identity_cpp shutdown;
markus@165
   375
	_iq->push_front(shutdown);
vb@24
   376
markus@165
   377
	keymanagement_thread->join();
markus@165
   378
	delete keymanagement_thread;
markus@165
   379
	keymanagement_thread = NULL;
vb@24
   380
markus@165
   381
	delete _iq;
vb@24
   382
markus@165
   383
	return S_OK;
vb@24
   384
}
vb@24
   385
markus@172
   386
STDMETHODIMP CpEpEngine::Myself(struct pEpIdentity *ident, struct pEpIdentity *result)
vb@0
   387
{
markus@165
   388
	assert(ident);
markus@165
   389
	assert(result);
vb@0
   390
markus@192
   391
	if (!(ident && result))
markus@165
   392
		return E_INVALIDARG;
vb@0
   393
markus@196
   394
	::pEp_identity *_ident = 0;
markus@196
   395
	
markus@196
   396
	try {
markus@196
   397
		_ident = new_identity(ident);
markus@196
   398
		assert(_ident);
markus@196
   399
		if (_ident == NULL)
markus@196
   400
			return E_OUTOFMEMORY;
markus@196
   401
	}
markus@196
   402
	catch (bad_alloc&) {
markus@165
   403
		return E_OUTOFMEMORY;
markus@196
   404
	}
markus@196
   405
	catch (exception& ex) {
markus@196
   406
		return FAIL(ex.what());;
markus@196
   407
	}
markus@196
   408
vb@0
   409
markus@84
   410
	// DEBUG CODE - REMOVE BEFORE RELEASE!
markus@172
   411
	// SyncHandshakeResult handshakeResult;
markus@84
   412
	//
markus@85
   413
	// HRESULT res = Fire_ShowHandshake(ident, result, &handshakeResult);
markus@85
   414
	// 
markus@85
   415
	// HRESULT res2 = Fire_TestEvent(15, _bstr_t( "hallo"));
markus@84
   416
markus@165
   417
	PEP_STATUS status = ::myself(get_session(), _ident);
vb@0
   418
markus@165
   419
	if (status == PEP_STATUS_OK) {
markus@165
   420
		assert(_ident->fpr);
markus@165
   421
		copy_identity(result, _ident);
markus@165
   422
		::free_identity(_ident);
markus@165
   423
		return S_OK;
markus@165
   424
	}
markus@165
   425
	else {
markus@165
   426
		::free_identity(_ident);
markus@165
   427
		if (status == PEP_OUT_OF_MEMORY)
markus@165
   428
			return E_OUTOFMEMORY;
markus@165
   429
		else
markus@189
   430
			return FAIL(L"myself", status);
markus@165
   431
	}
vb@0
   432
}
vb@0
   433
markus@172
   434
STDMETHODIMP CpEpEngine::UpdateIdentity(struct pEpIdentity *ident, struct pEpIdentity *result)
vb@0
   435
{
markus@165
   436
	assert(ident);
markus@165
   437
	assert(result);
vb@0
   438
markus@192
   439
	if (!(ident && result))
markus@165
   440
		return E_INVALIDARG;
vb@0
   441
markus@196
   442
	::pEp_identity *_ident;
markus@196
   443
	try {
markus@196
   444
		_ident = new_identity(ident);
markus@196
   445
	}
markus@196
   446
	catch (bad_alloc&) {
markus@196
   447
		return E_OUTOFMEMORY;
markus@196
   448
	}
markus@196
   449
	catch (exception& ex) {
markus@196
   450
		return FAIL(ex.what());
markus@196
   451
	}
markus@196
   452
markus@165
   453
	assert(_ident);
markus@165
   454
	if (_ident == NULL)
markus@165
   455
		return E_OUTOFMEMORY;
vb@0
   456
markus@165
   457
	PEP_STATUS status = ::update_identity(get_session(), _ident);
vb@0
   458
markus@165
   459
	if (status == PEP_STATUS_OK) {
markus@201
   460
		assert(_ident->fpr); // Guaranteed not NULL, but possibly empty string.
markus@165
   461
		copy_identity(result, _ident);
markus@165
   462
		::free_identity(_ident);
markus@165
   463
		return S_OK;
markus@165
   464
	}
vb@216
   465
	else if (status == PEP_GET_KEY_FAILED) {
vb@216
   466
		if (_ident->fpr) {
vb@216
   467
			pEp_free(_ident->fpr);
vb@216
   468
			_ident->fpr = NULL;
vb@216
   469
		}
vb@216
   470
		copy_identity(result, _ident);
vb@216
   471
		result->Fpr = NULL;
vb@216
   472
		::free_identity(_ident);
vb@216
   473
		return S_OK;
vb@216
   474
	}
markus@165
   475
	else {
markus@165
   476
		::free_identity(_ident);
markus@165
   477
		if (status == PEP_OUT_OF_MEMORY)
markus@165
   478
			return E_OUTOFMEMORY;
markus@165
   479
		else
markus@189
   480
			return FAIL(L"UpdateIdentity", status);
markus@165
   481
	}
vb@0
   482
}
vb@0
   483
markus@172
   484
STDMETHODIMP CpEpEngine::KeyMistrusted(struct pEpIdentity *ident)
vb@4
   485
{
markus@165
   486
	::pEp_identity *_ident;
vb@4
   487
markus@165
   488
	assert(ident);
markus@192
   489
	if (!ident)
markus@192
   490
		return E_INVALIDARG;
vb@4
   491
markus@165
   492
	try {
markus@165
   493
		_ident = new_identity(ident);
markus@165
   494
	}
markus@165
   495
	catch (bad_alloc&) {
markus@165
   496
		return E_OUTOFMEMORY;
markus@165
   497
	}
markus@196
   498
	catch (exception& ex) {
markus@196
   499
		return FAIL(ex.what());;
markus@165
   500
	}
vb@4
   501
markus@165
   502
	PEP_STATUS status = ::key_mistrusted(get_session(), _ident);
markus@165
   503
	free_identity(_ident);
vb@49
   504
markus@165
   505
	if (status == PEP_OUT_OF_MEMORY)
markus@165
   506
		return E_OUTOFMEMORY;
vb@4
   507
markus@165
   508
	if (status == PEP_KEY_NOT_FOUND)
markus@165
   509
		return FAIL(L"key not found");
vb@4
   510
markus@165
   511
	if (status != ::PEP_STATUS_OK)
markus@189
   512
		return FAIL(L"cannot revoke compromized key", status);
vb@4
   513
markus@165
   514
	return S_OK;
vb@4
   515
}
vb@4
   516
markus@172
   517
STDMETHODIMP CpEpEngine::KeyResetTrust(struct pEpIdentity *ident)
Edouard@53
   518
{
markus@165
   519
	::pEp_identity *_ident;
Edouard@53
   520
markus@192
   521
	assert(ident); 
markus@192
   522
	
markus@192
   523
	if (!ident)
markus@192
   524
		return E_INVALIDARG;
Edouard@53
   525
markus@165
   526
	try {
markus@165
   527
		_ident = new_identity(ident);
markus@165
   528
	}
markus@165
   529
	catch (bad_alloc&) {
markus@165
   530
		return E_OUTOFMEMORY;
markus@165
   531
	}
markus@196
   532
	catch (exception& ex) {
markus@196
   533
		return FAIL(ex.what());;
markus@165
   534
	}
Edouard@53
   535
markus@165
   536
	PEP_STATUS status = ::key_reset_trust(get_session(), _ident);
markus@165
   537
	free_identity(_ident);
Edouard@53
   538
markus@165
   539
	if (status == PEP_OUT_OF_MEMORY)
markus@165
   540
		return E_OUTOFMEMORY;
Edouard@53
   541
markus@165
   542
	if (status == PEP_KEY_NOT_FOUND)
markus@165
   543
		return FAIL(L"key not found");
Edouard@53
   544
markus@165
   545
	if (status != ::PEP_STATUS_OK)
markus@189
   546
		return FAIL(L"cannot reset trust", status);
Edouard@53
   547
markus@165
   548
	return S_OK;
Edouard@53
   549
}
Edouard@53
   550
vb@28
   551
int CpEpEngine::examine_identity(pEp_identity *ident, void *management)
vb@28
   552
{
markus@165
   553
	assert(ident);
markus@165
   554
	assert(management);
markus@165
   555
	if (!(ident && management))
markus@165
   556
		return -1;
vb@28
   557
markus@165
   558
	CpEpEngine *me = (CpEpEngine *)management;
vb@28
   559
markus@165
   560
	if (me->identity_queue.load() == NULL)
markus@165
   561
		return 0;
vb@28
   562
markus@165
   563
	try {
markus@165
   564
		me->identity_queue.load()->push_back(ident);
markus@165
   565
	}
markus@165
   566
	catch (exception&) {
markus@165
   567
		return -1;
markus@165
   568
	}
vb@28
   569
markus@165
   570
	return 0;
vb@28
   571
}
vb@28
   572
vb@0
   573
::pEp_identity * CpEpEngine::retrieve_next_identity(void *management)
vb@0
   574
{
markus@165
   575
	assert(management);
markus@192
   576
	if (!management)
markus@192
   577
		return NULL;
markus@192
   578
markus@165
   579
	identity_queue_t *iq = (identity_queue_t *)management;
vb@0
   580
markus@165
   581
	do /* poll queue */ {
markus@165
   582
		if (iq->size())
markus@165
   583
			break;
markus@165
   584
		::Sleep(100);
markus@165
   585
	} while (true);
vb@0
   586
markus@165
   587
	::pEp_identity *_ident;
markus@165
   588
	pEp_identity_cpp& ident = iq->front();
vb@0
   589
markus@165
   590
	if (ident.address.size() == 0)
markus@165
   591
		return NULL;
vb@0
   592
markus@165
   593
	_ident = ident.to_pEp_identity();
markus@165
   594
	iq->pop_front();
vb@0
   595
markus@165
   596
	return _ident;
vb@0
   597
}
vb@0
   598
markus@164
   599
PEP_STATUS CpEpEngine::messageToSend(void * obj, message *msg)
vb@74
   600
{
markus@165
   601
	assert(msg);
markus@192
   602
	assert(obj);
markus@192
   603
	if (!(msg && obj))
markus@165
   604
		return PEP_ILLEGAL_VALUE;
vb@75
   605
markus@172
   606
	TextMessage _msg;
markus@172
   607
	memset(&_msg, 0, sizeof(TextMessage));
vb@82
   608
markus@165
   609
	text_message_from_C(&_msg, msg);
markus@165
   610
	CpEpEngine *me = (CpEpEngine *)obj;
markus@165
   611
	HRESULT r = me->Fire_MessageToSend(&_msg);
markus@165
   612
	assert(r == S_OK);
markus@165
   613
	clear_text_message(&_msg);
markus@165
   614
	if (r == E_OUTOFMEMORY)
markus@165
   615
		return PEP_OUT_OF_MEMORY;
markus@165
   616
	if (r != S_OK)
markus@165
   617
		return PEP_UNKNOWN_ERROR;
vb@75
   618
markus@165
   619
	return PEP_STATUS_OK;
vb@74
   620
}
vb@74
   621
markus@164
   622
PEP_STATUS CpEpEngine::showHandshake(void * obj, pEp_identity *self, pEp_identity *partner)
vb@74
   623
{
markus@165
   624
	assert(self && partner);
markus@165
   625
	if (!(self && partner))
markus@165
   626
		return PEP_ILLEGAL_VALUE;
vb@80
   627
markus@172
   628
	pEpIdentity _self;
markus@165
   629
	copy_identity(&_self, self);
markus@172
   630
	pEpIdentity _partner;
markus@165
   631
	copy_identity(&_partner, partner);
markus@165
   632
	CpEpEngine *me = (CpEpEngine *)obj;
markus@172
   633
	SyncHandshakeResult _result;
markus@165
   634
	HRESULT r = me->Fire_ShowHandshake(&_self, &_partner, &_result);
markus@165
   635
	assert(r == S_OK);
markus@165
   636
	clear_identity_s(_self);
markus@165
   637
	clear_identity_s(_partner);
markus@165
   638
	if (r == E_OUTOFMEMORY)
markus@165
   639
		return PEP_OUT_OF_MEMORY;
markus@165
   640
	if (r != S_OK)
markus@165
   641
		return PEP_UNKNOWN_ERROR;
vb@75
   642
markus@165
   643
	PEP_STATUS status = deliverHandshakeResult(me->get_session(), partner, (sync_handshake_result)(int)_result);
markus@165
   644
	return status;
vb@74
   645
}
vb@74
   646
markus@172
   647
STDMETHODIMP CpEpEngine::BlacklistAdd(BSTR fpr)
vb@65
   648
{
markus@165
   649
	assert(fpr);
markus@192
   650
	if (!fpr)
markus@192
   651
		return E_INVALIDARG;
vb@65
   652
markus@165
   653
	string _fpr = utf8_string(fpr);
markus@165
   654
	PEP_STATUS status = ::blacklist_add(get_session(), _fpr.c_str());
markus@165
   655
	assert(status == PEP_STATUS_OK);
markus@165
   656
	if (status != PEP_STATUS_OK)
markus@189
   657
		return FAIL(L"blacklist_add failed in pEp engine", status);
vb@65
   658
markus@165
   659
	return S_OK;
vb@65
   660
}
vb@65
   661
markus@172
   662
STDMETHODIMP CpEpEngine::BlacklistDelete(BSTR fpr)
vb@65
   663
{
markus@165
   664
	assert(fpr);
markus@192
   665
	if (!fpr)
markus@192
   666
		return E_INVALIDARG;
vb@65
   667
markus@165
   668
	string _fpr = utf8_string(fpr);
markus@165
   669
	PEP_STATUS status = ::blacklist_delete(get_session(), _fpr.c_str());
markus@165
   670
	assert(status == PEP_STATUS_OK);
markus@165
   671
	if (status != PEP_STATUS_OK)
markus@189
   672
		return FAIL(L"blacklist_delete failed in pEp engine", status);
vb@65
   673
markus@165
   674
	return S_OK;
vb@65
   675
}
vb@65
   676
markus@172
   677
STDMETHODIMP CpEpEngine::BlacklistIsListed(BSTR fpr, VARIANT_BOOL *listed)
vb@65
   678
{
markus@165
   679
	assert(fpr);
markus@165
   680
	assert(listed);
vb@65
   681
markus@192
   682
	if (!(fpr && listed))
markus@192
   683
		return E_INVALIDARG;
markus@192
   684
markus@165
   685
	string _fpr = utf8_string(fpr);
markus@165
   686
	bool result;
markus@165
   687
	PEP_STATUS status = ::blacklist_is_listed(get_session(), _fpr.c_str(), &result);
markus@165
   688
	assert(status == PEP_STATUS_OK);
markus@165
   689
	if (status != PEP_STATUS_OK)
markus@189
   690
		return FAIL(L"blacklist_is_listed failed in pEp engine", status);
vb@65
   691
markus@165
   692
	*listed = result ? VARIANT_TRUE : VARIANT_FALSE;
markus@165
   693
	return S_OK;
vb@65
   694
}
vb@65
   695
Dean@187
   696
STDMETHODIMP CpEpEngine::BlacklistRetrieve(SAFEARRAY **blacklist)
vb@65
   697
{
markus@165
   698
	assert(blacklist);
vb@65
   699
markus@192
   700
	if (!blacklist)
markus@192
   701
		return E_INVALIDARG;
markus@192
   702
markus@165
   703
	::stringlist_t *_blacklist = NULL;
markus@165
   704
	PEP_STATUS status = ::blacklist_retrieve(get_session(), &_blacklist);
markus@165
   705
	assert(status == PEP_STATUS_OK);
markus@165
   706
	if (status != PEP_STATUS_OK)
markus@189
   707
		return FAIL(L"blacklist_retrieve failed in pEp engine", status);
markus@165
   708
	assert(_blacklist);
vb@65
   709
markus@165
   710
	*blacklist = string_array(_blacklist);
markus@193
   711
	::free_stringlist(_blacklist);
markus@165
   712
	return S_OK;
vb@65
   713
}
vb@65
   714
vb@0
   715
HRESULT CpEpEngine::error(_bstr_t msg)
vb@0
   716
{
markus@165
   717
	_bstr_t helpFile = L"";
markus@165
   718
	_bstr_t source = L"pEp COM Adapter";
vb@0
   719
markus@165
   720
	ICreateErrorInfo *cei;
markus@165
   721
	if (SUCCEEDED(CreateErrorInfo(&cei))) {
markus@165
   722
		cei->SetDescription(msg);
markus@165
   723
		cei->SetGUID(__uuidof(IpEpEngine));
markus@165
   724
		cei->SetHelpContext(0);
markus@165
   725
		cei->SetHelpFile(helpFile);
markus@165
   726
		cei->SetSource(source);
vb@0
   727
markus@165
   728
		IErrorInfo *errinfo;
markus@165
   729
		if (SUCCEEDED(cei->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &errinfo))) {
markus@165
   730
			SetErrorInfo(0, errinfo);
markus@165
   731
			errinfo->Release();
markus@165
   732
		}
markus@165
   733
		cei->Release();
markus@165
   734
	}
markus@165
   735
	return E_FAIL;
vb@0
   736
}
vb@15
   737
markus@189
   738
HRESULT CpEpEngine::error(_bstr_t msg, PEP_STATUS status)
markus@189
   739
{
markus@189
   740
    std::stringstream stream;
markus@189
   741
    stream << msg;
markus@189
   742
    stream << ": ";
markus@189
   743
    stream << std::hex << status;
markus@189
   744
    
markus@189
   745
    error(stream.str().c_str());
markus@189
   746
markus@189
   747
    if (status == ::PEP_OUT_OF_MEMORY)
markus@189
   748
        return E_OUTOFMEMORY;
markus@189
   749
markus@189
   750
    return E_FAIL;
markus@189
   751
}
markus@189
   752
markus@172
   753
STDMETHODIMP CpEpEngine::EncryptMessage(TextMessage * src, TextMessage * dst, SAFEARRAY * extra, pEpEncryptFlags flags)
vb@15
   754
{
markus@165
   755
	assert(src);
markus@165
   756
	assert(dst);
vb@15
   757
markus@192
   758
	if (!(src && dst))
markus@192
   759
		return E_INVALIDARG;
markus@192
   760
markus@165
   761
	::message *_src = text_message_to_C(src);
markus@191
   762
markus@191
   763
	// COM-19: Initialize msg_dst to NULL, or we end up calling
markus@191
   764
	// free_message() below with a pointer to random garbage in
markus@191
   765
	// case of an error in encrypt_message().
markus@191
   766
	::message *msg_dst = NULL;
markus@192
   767
	::stringlist_t *_extra = new_stringlist(extra); // can cope with NULL
vb@16
   768
markus@167
   769
	// _PEP_enc_format is intentionally hardcoded to PEP_enc_PEP:
markus@167
   770
	// 2016-10-02 14:10 < fdik> schabi: actually, all adapters now must use PEP_enc_PEP
markus@167
   771
	PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t) flags;
markus@167
   772
	PEP_STATUS status = ::encrypt_message(get_session(), _src, _extra, &msg_dst, PEP_enc_PEP, engineFlags);
markus@165
   773
	::free_stringlist(_extra);
vb@16
   774
markus@165
   775
	if (status == PEP_STATUS_OK)
markus@165
   776
		text_message_from_C(dst, msg_dst);
markus@165
   777
	else
markus@165
   778
		text_message_from_C(dst, _src);
vb@38
   779
markus@165
   780
	::free_message(msg_dst);
markus@165
   781
	::free_message(_src);
vb@16
   782
markus@165
   783
	if (status == PEP_OUT_OF_MEMORY)
markus@165
   784
		return E_OUTOFMEMORY;
vb@46
   785
markus@204
   786
	// COM-41: Enhanced PEP status handling
markus@204
   787
	if ((status > PEP_STATUS_OK && status < PEP_UNENCRYPTED) ||
markus@204
   788
		status < PEP_STATUS_OK ||
markus@204
   789
		status >= PEP_TRUSTWORD_NOT_FOUND)
markus@204
   790
		return FAIL("Failure to encrypt message", status);
markus@204
   791
markus@204
   792
	// Statii like PEP_UNENCRYPTED due to no private key
markus@204
   793
	// should not be a catastrophic failure here. Using S_FALSE
markus@204
   794
	// still allows clients to differentiate with S_OK,
markus@204
   795
	// although this does not work out of the box with
markus@204
   796
	// the standard .NET mapping of COM.
markus@197
   797
	if (status != PEP_STATUS_OK)
markus@204
   798
		return S_FALSE;
markus@197
   799
markus@165
   800
	return S_OK;
vb@15
   801
}
vb@15
   802
markus@172
   803
STDMETHODIMP CpEpEngine::DecryptMessage(TextMessage * src, TextMessage * dst, SAFEARRAY ** keylist, pEpDecryptFlags *flags, pEpRating *rating)
vb@15
   804
{
markus@165
   805
	assert(src);
markus@165
   806
	assert(dst);
markus@165
   807
	assert(keylist);
markus@192
   808
	assert(flags);
markus@165
   809
	assert(rating);
vb@15
   810
markus@192
   811
	if (!(src && dst && keylist && flags && rating))
markus@192
   812
		return E_INVALIDARG;
markus@192
   813
markus@165
   814
	*keylist = NULL;
markus@172
   815
	*rating = pEpRatingUndefined;
vb@40
   816
markus@165
   817
	::message *_src = text_message_to_C(src);
markus@165
   818
	::message *msg_dst = NULL;
markus@195
   819
	::stringlist_t *_keylist = NULL;
markus@165
   820
	::PEP_rating _rating;
vb@16
   821
markus@167
   822
	PEP_decrypt_flags_t engineflags = 0;
markus@167
   823
	PEP_STATUS status = ::decrypt_message(get_session(), _src, &msg_dst, &_keylist, &_rating, &engineflags);
markus@167
   824
markus@167
   825
	*flags = (pEpDecryptFlags)engineflags;
vb@42
   826
markus@165
   827
	if (msg_dst)
markus@165
   828
		text_message_from_C(dst, msg_dst);
vb@42
   829
markus@165
   830
	::free_message(_src);
markus@165
   831
	::free_message(msg_dst);
vb@16
   832
markus@165
   833
	if (_keylist) {
markus@165
   834
		*keylist = string_array(_keylist);
markus@165
   835
		free_stringlist(_keylist);
markus@165
   836
	}
vb@18
   837
markus@172
   838
	*rating = (pEpRating)_rating;
vb@18
   839
markus@165
   840
	return S_OK;
vb@15
   841
}
vb@15
   842
markus@172
   843
STDMETHODIMP CpEpEngine::OutgoingMessageRating(TextMessage *msg, pEpRating * pVal)
vb@15
   844
{
markus@165
   845
	assert(msg);
markus@165
   846
	assert(pVal);
vb@15
   847
markus@192
   848
	if (!(msg  && pVal))
markus@192
   849
		return E_INVALIDARG;
markus@192
   850
markus@165
   851
	::message *_msg = text_message_to_C(msg);
vb@19
   852
markus@165
   853
	PEP_rating _rating;
markus@165
   854
	PEP_STATUS status = ::outgoing_message_rating(get_session(), _msg, &_rating);
markus@165
   855
	if (status != PEP_STATUS_OK)
markus@189
   856
		return FAIL(L"cannot get message rating", status);
vb@16
   857
markus@172
   858
	*pVal = (pEpRating)_rating;
markus@165
   859
	return S_OK;
vb@15
   860
}
vb@18
   861
markus@172
   862
STDMETHODIMP CpEpEngine::IdentityRating(struct pEpIdentity *ident, pEpRating * pVal)
vb@18
   863
{
markus@165
   864
	::pEp_identity *_ident;
vb@18
   865
markus@165
   866
	assert(ident);
markus@165
   867
	assert(pVal);
vb@18
   868
markus@192
   869
	if (!(ident  && pVal))
markus@192
   870
		return E_INVALIDARG;
markus@192
   871
markus@165
   872
	try {
markus@165
   873
		_ident = new_identity(ident);
markus@165
   874
	}
markus@165
   875
	catch (bad_alloc&) {
markus@165
   876
		return E_OUTOFMEMORY;
markus@165
   877
	}
markus@196
   878
	catch (exception& ex) {
markus@196
   879
		return FAIL(ex.what());;
markus@165
   880
	}
vb@18
   881
markus@165
   882
	PEP_rating _rating;
markus@165
   883
	PEP_STATUS status = ::identity_rating(get_session(), _ident, &_rating);
markus@165
   884
	free_identity(_ident);
markus@192
   885
markus@165
   886
	if (status != PEP_STATUS_OK)
markus@189
   887
		return FAIL(L"cannot get message color", status);
vb@18
   888
markus@172
   889
	*pVal = (pEpRating)_rating;
markus@165
   890
	return S_OK;
vb@18
   891
}
vb@48
   892
markus@172
   893
STDMETHODIMP CpEpEngine::ColorFromRating(pEpRating rating, pEpColor * pVal)
markus@164
   894
{
markus@164
   895
	assert(pVal);
markus@164
   896
markus@192
   897
	if (!pVal)
markus@192
   898
		return E_INVALIDARG;
markus@192
   899
markus@164
   900
	PEP_rating engineRating = (PEP_rating)rating;
markus@164
   901
	PEP_color _color = ::color_from_rating(engineRating);
markus@164
   902
markus@172
   903
	*pVal = (pEpColor)_color;
markus@164
   904
markus@164
   905
	return S_OK;
markus@164
   906
}
markus@164
   907
vb@219
   908
STDMETHODIMP CpEpEngine::OwnIdentitiesRetrieve(LPSAFEARRAY* own_identities)
vb@219
   909
{
vb@219
   910
	assert(own_identities);
vb@219
   911
	if (!own_identities)
vb@219
   912
		return E_INVALIDARG;
vb@219
   913
vb@219
   914
vb@219
   915
	return S_OK;
vb@219
   916
}
vb@219
   917
markus@172
   918
STDMETHODIMP CpEpEngine::TrustPersonalKey(struct pEpIdentity *ident, struct pEpIdentity *result)
vb@48
   919
{
markus@165
   920
	::pEp_identity *_ident;
vb@48
   921
markus@165
   922
	assert(ident);
markus@165
   923
	assert(result);
vb@48
   924
markus@192
   925
	if (!ident || !result)
markus@192
   926
		return E_INVALIDARG;
markus@192
   927
markus@165
   928
	try {
markus@165
   929
		_ident = new_identity(ident);
markus@165
   930
	}
markus@165
   931
	catch (bad_alloc&) {
markus@165
   932
		return E_OUTOFMEMORY;
markus@165
   933
	}
markus@196
   934
	catch (exception& ex) {
markus@196
   935
		return FAIL(ex.what());;
markus@165
   936
	}
vb@48
   937
markus@165
   938
	if (verbose_mode) {
markus@165
   939
		stringstream ss;
markus@172
   940
		ss << "TrustPersonalKey called with ";
markus@180
   941
		ss << utf8_string(ident->Address);
markus@165
   942
		ss << L": ";
markus@180
   943
		ss << ident->CommType;
markus@165
   944
		verbose(ss.str());
markus@165
   945
	}
vb@52
   946
markus@165
   947
	PEP_STATUS status = ::trust_personal_key(get_session(), _ident);
vb@52
   948
markus@165
   949
	if (verbose_mode) {
markus@165
   950
		stringstream ss;
markus@165
   951
		ss << "result ";
markus@165
   952
		ss << status;
markus@165
   953
		ss << " for ";
markus@165
   954
		ss << _ident->address;
markus@165
   955
		ss << L": ";
markus@165
   956
		ss << _ident->comm_type;
markus@165
   957
		verbose(ss.str());
markus@165
   958
	}
vb@52
   959
markus@165
   960
	if (status == PEP_STATUS_OK)
markus@165
   961
		copy_identity(result, _ident);
vb@50
   962
markus@165
   963
	free_identity(_ident);
markus@165
   964
	if (status == PEP_OUT_OF_MEMORY)
markus@165
   965
		return E_OUTOFMEMORY;
markus@165
   966
	else if (status != PEP_STATUS_OK)
markus@189
   967
		return FAIL(L"failure while executing TrustPersonalKey()", status);
vb@48
   968
markus@165
   969
	return S_OK;
markus@165
   970
}
markus@165
   971
markus@165
   972
// keysync api
markus@165
   973
markus@169
   974
void CpEpEngine::start_keysync()
markus@165
   975
{
markus@165
   976
	// acquire the lock
markus@165
   977
	std::unique_lock<std::mutex> lock(keysync_mutex);
markus@165
   978
markus@188
   979
	// Assert if we're not already running.
markus@188
   980
    assert(!this->keysync_thread);
markus@165
   981
markus@169
   982
	// Ensure we are not aborting the new thread due to a
markus@169
   983
	// left over flag.
markus@169
   984
	keysync_abort_requested = false;
markus@165
   985
markus@169
   986
	// Init our keysync session
markus@165
   987
	PEP_STATUS status = ::init(&keysync_session);
Dean@187
   988
	::register_sync_callbacks(keysync_session, (void*)this, messageToSend, showHandshake, inject_sync_msg, retrieve_next_sync_msg);
markus@176
   989
	assert(status == PEP_STATUS_OK);
markus@175
   990
markus@175
   991
    attach_sync_session(get_session(), keysync_session);
markus@165
   992
markus@188
   993
    // We need to marshal the callbacks to the keysync thread
markus@188
   994
    LPSTREAM marshaled_callbacks;
markus@188
   995
markus@188
   996
    auto result = CoMarshalInterThreadInterfaceInStream(IID_IpEpEngineCallbacks, client_callbacks, &marshaled_callbacks);
markus@188
   997
    assert(result == S_OK);
markus@188
   998
markus@169
   999
	// Star the keysync thread
markus@188
  1000
	keysync_thread = new thread(do_keysync_in_thread, this, marshaled_callbacks);
markus@188
  1001
}
markus@165
  1002
markus@188
  1003
void CpEpEngine::do_keysync_in_thread(CpEpEngine* self, LPSTREAM marshaled_callbacks) 
markus@188
  1004
{
markus@188
  1005
    assert(self);
markus@192
  1006
	assert(marshaled_callbacks);
markus@192
  1007
markus@188
  1008
    // We need to initialize COM here for successfull delivery of the callbacks.
markus@188
  1009
    // As we don't create any COM instances in our thread, the COMINIT value is
markus@188
  1010
    // currently irrelevant, so we go with the safest value.
markus@188
  1011
    auto res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
markus@188
  1012
    assert(res == S_OK);
markus@188
  1013
markus@188
  1014
    LPVOID vp;
markus@188
  1015
markus@188
  1016
    res = CoGetInterfaceAndReleaseStream(marshaled_callbacks, IID_IpEpEngineCallbacks, &vp);
markus@188
  1017
    assert(SUCCEEDED(res));
markus@188
  1018
markus@188
  1019
    self->client_callbacks_on_sync_thread = static_cast<IpEpEngineCallbacks*>(vp);
markus@188
  1020
markus@188
  1021
    ::do_sync_protocol(self->keysync_session, self);
markus@188
  1022
markus@188
  1023
    self->client_callbacks_on_sync_thread->Release();
markus@188
  1024
markus@188
  1025
    self->client_callbacks_on_sync_thread = NULL;
markus@188
  1026
markus@188
  1027
    CoUninitialize();
markus@165
  1028
}
markus@165
  1029
markus@169
  1030
void CpEpEngine::stop_keysync()
markus@165
  1031
{
markus@165
  1032
	// acquire the lock
markus@165
  1033
	std::unique_lock<std::mutex> lock(keysync_mutex);
markus@165
  1034
markus@188
  1035
    // Do nothing if keysync is not running.
markus@188
  1036
    if (!keysync_thread)
markus@188
  1037
        return;
markus@165
  1038
markus@188
  1039
    assert(!keysync_abort_requested);
markus@165
  1040
	// signal that we're gonna abort
markus@165
  1041
	keysync_abort_requested = true;
markus@165
  1042
markus@165
  1043
	// Notify the keysync thread
markus@165
  1044
	keysync_condition.notify_all();
markus@165
  1045
markus@165
  1046
	// Wait for the other thread to finish and clean up
markus@188
  1047
	while (keysync_abort_requested)
markus@165
  1048
		keysync_condition.wait(lock);
markus@165
  1049
markus@188
  1050
	// collect the child thread for the thread to end
markus@165
  1051
	keysync_thread->join();
markus@165
  1052
markus@165
  1053
	// clean up
markus@165
  1054
	delete keysync_thread;
markus@165
  1055
	keysync_thread = NULL;
markus@188
  1056
markus@188
  1057
    ::detach_sync_session(get_session());
markus@169
  1058
	::unregister_sync_callbacks(keysync_session);
markus@165
  1059
	release(keysync_session);
markus@180
  1060
    keysync_session = NULL;
markus@165
  1061
}
markus@165
  1062
markus@165
  1063
int CpEpEngine::inject_sync_msg(void * msg, void * management)
markus@165
  1064
{
markus@192
  1065
	assert(msg);
markus@192
  1066
	assert(management);
markus@165
  1067
	// check argument
markus@165
  1068
	if (!msg)
markus@165
  1069
		return E_INVALIDARG;
markus@169
  1070
	if (!management)
markus@165
  1071
		return ERROR_INVALID_HANDLE;
markus@165
  1072
markus@169
  1073
	CpEpEngine* me = (CpEpEngine*)management;
markus@169
  1074
markus@165
  1075
	// acquire the lock
markus@169
  1076
	std::unique_lock<std::mutex> lock(me->keysync_mutex);
markus@165
  1077
markus@188
  1078
	// check whether we're in a valid state running:
markus@188
  1079
	if (!me->keysync_thread)
markus@165
  1080
		return E_ASYNC_OPERATION_NOT_STARTED;
markus@165
  1081
markus@165
  1082
	// queue the message
markus@169
  1083
	me->keysync_queue.push(msg);
markus@165
  1084
markus@165
  1085
	// notify the receivers
markus@169
  1086
	me->keysync_condition.notify_all();
markus@170
  1087
markus@170
  1088
    return S_OK;
markus@165
  1089
}
markus@165
  1090
Dean@187
  1091
void * CpEpEngine::retrieve_next_sync_msg(void * management)
markus@165
  1092
{
markus@165
  1093
	// sanity check
markus@169
  1094
	assert(management);
markus@192
  1095
	if (!management)
markus@192
  1096
		return NULL;
markus@169
  1097
markus@169
  1098
	CpEpEngine* me = (CpEpEngine*)management;
markus@165
  1099
markus@165
  1100
	// acquire the lock
markus@169
  1101
	std::unique_lock<std::mutex> lock(me->keysync_mutex);
markus@165
  1102
markus@165
  1103
	// as long as we're supposed to be active 
markus@165
  1104
	// (we won't wait for the queue to empty currently...)
markus@169
  1105
	while (!me->keysync_abort_requested)
markus@165
  1106
	{
markus@165
  1107
		// If the queue is empty, wait for a signal, and try again.
markus@169
  1108
		if (me->keysync_queue.empty())
markus@165
  1109
		{
markus@169
  1110
			me->keysync_condition.wait(lock);
markus@165
  1111
			continue;
markus@165
  1112
		}
markus@165
  1113
markus@165
  1114
		// Pop the message and return it.
markus@169
  1115
		void* msg = me->keysync_queue.front();
markus@165
  1116
		assert(msg);
markus@165
  1117
markus@169
  1118
		me->keysync_queue.pop();
markus@169
  1119
markus@165
  1120
		return msg;
markus@165
  1121
	}
markus@165
  1122
markus@165
  1123
	// we acknowledge that we're quitting...
markus@188
  1124
	me->keysync_abort_requested = false;
markus@165
  1125
markus@165
  1126
	// We signal the main thread that we got his signal
markus@165
  1127
	// so it can gain the mutex again and call join() on us.
markus@169
  1128
	me->keysync_condition.notify_all();
markus@165
  1129
markus@165
  1130
	// and tell the pep engine we're done.
markus@165
  1131
	return NULL;
vb@48
  1132
}
markus@84
  1133
markus@84
  1134
markus@84
  1135
// Event callbacks
markus@84
  1136
markus@172
  1137
STDMETHODIMP CpEpEngine::RegisterCallbacks(IpEpEngineCallbacks* new_callbacks)
markus@84
  1138
{
markus@188
  1139
    // check for valid parameter
markus@188
  1140
    if (!new_callbacks)
markus@188
  1141
        return E_INVALIDARG;
markus@84
  1142
markus@188
  1143
    // don't allow double registration.
markus@188
  1144
    if (this->client_callbacks)
markus@188
  1145
        return E_ILLEGAL_STATE_CHANGE;
markus@188
  1146
markus@188
  1147
    this->client_callbacks = new_callbacks;
markus@188
  1148
    new_callbacks->AddRef();
markus@188
  1149
markus@169
  1150
	start_keysync();
markus@84
  1151
markus@84
  1152
	return S_OK;
markus@84
  1153
}
markus@84
  1154
markus@188
  1155
STDMETHODIMP CpEpEngine::UnregisterCallbacks()
markus@84
  1156
{
markus@188
  1157
    // don't allow double deregistration.
markus@188
  1158
    // S_FALSE still is no error (as double deregistration is not fatal).
markus@188
  1159
    if (!this->client_callbacks)
markus@188
  1160
        return S_FALSE;
markus@84
  1161
markus@188
  1162
    stop_keysync();
markus@169
  1163
markus@188
  1164
    this->client_callbacks->Release();
markus@84
  1165
markus@188
  1166
    this->client_callbacks = NULL;
markus@188
  1167
markus@188
  1168
    return S_OK;
markus@84
  1169
}
markus@84
  1170
markus@177
  1171
STDMETHODIMP CpEpEngine::OpenPGPListKeyinfo(BSTR search_pattern, LPSAFEARRAY* keyinfo_list) {
markus@165
  1172
	assert(keyinfo_list);
krista@154
  1173
markus@165
  1174
	if (keyinfo_list == NULL)
markus@165
  1175
		return E_INVALIDARG;
krista@154
  1176
markus@165
  1177
	string _pattern = "";
markus@165
  1178
	if (search_pattern)
markus@165
  1179
		_pattern = utf8_string(search_pattern);
markus@165
  1180
	::stringpair_list_t* _keyinfo_list = NULL;
krista@154
  1181
markus@165
  1182
	PEP_STATUS status = ::OpenPGP_list_keyinfo(get_session(), _pattern.c_str(), &_keyinfo_list);
markus@165
  1183
	assert(status != PEP_OUT_OF_MEMORY);
markus@165
  1184
	if (status == PEP_OUT_OF_MEMORY)
markus@165
  1185
		return E_OUTOFMEMORY;
krista@154
  1186
markus@165
  1187
	if (status != ::PEP_STATUS_OK)
markus@189
  1188
		return FAIL(L"OpenPGP_list_keyinfo", status);
krista@154
  1189
markus@165
  1190
	if (_keyinfo_list && _keyinfo_list->value) {
markus@165
  1191
		::opt_field_array_from_C(_keyinfo_list, keyinfo_list);
markus@165
  1192
	}
markus@165
  1193
	else {
markus@165
  1194
		::free_stringpair_list(_keyinfo_list);
markus@165
  1195
		return FAIL(L"OpenPGP_list_keyinfo: no keys found");
markus@165
  1196
	}
markus@165
  1197
markus@165
  1198
	::free_stringpair_list(_keyinfo_list);
markus@165
  1199
	return S_OK;
markus@165
  1200
krista@154
  1201
}
krista@154
  1202
markus@172
  1203
HRESULT CpEpEngine::Fire_MessageToSend(TextMessage * msg)
markus@84
  1204
{
markus@188
  1205
	assert(msg);
markus@188
  1206
    assert(this->client_callbacks_on_sync_thread);
markus@84
  1207
markus@192
  1208
	if (!msg)
markus@192
  1209
		return E_INVALIDARG;
markus@192
  1210
markus@192
  1211
	if (!this->client_callbacks_on_sync_thread)
markus@192
  1212
		return E_ILLEGAL_METHOD_CALL;
markus@192
  1213
markus@188
  1214
    auto result = this->client_callbacks_on_sync_thread->MessageToSend(msg);
markus@84
  1215
markus@188
  1216
	return result;
markus@84
  1217
}
markus@84
  1218
markus@172
  1219
HRESULT CpEpEngine::Fire_ShowHandshake(pEpIdentity * self, pEpIdentity * partner, SyncHandshakeResult * result)
markus@84
  1220
{
markus@84
  1221
	assert(self);
markus@84
  1222
	assert(partner);
markus@84
  1223
	assert(result);
markus@188
  1224
    assert(this->client_callbacks_on_sync_thread);
markus@192
  1225
markus@192
  1226
	if (!(self && partner && result))
markus@192
  1227
		return E_INVALIDARG;
markus@192
  1228
	if (!this->client_callbacks_on_sync_thread)
markus@192
  1229
		return E_ILLEGAL_METHOD_CALL;
markus@188
  1230
    	
markus@188
  1231
	auto res = this->client_callbacks_on_sync_thread->ShowHandshake(self, partner, result);
markus@188
  1232
		
markus@188
  1233
	return res;	
markus@84
  1234
}