CpEpEngine.cpp
author Volker Birk <vb@pep-project.org>
Sun, 13 Nov 2016 08:45:29 +0100
changeset 208 35eb7b0492ac
parent 204 21b7749b5beb
child 216 6a08f0334e8a
permissions -rw-r--r--
delete lock file on startup
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
markus@172
   297
STDMETHODIMP CpEpEngine::StartKeyserverLookup()
vb@24
   298
{
markus@165
   299
	if (identity_queue.load())
markus@165
   300
		return S_OK;
vb@24
   301
markus@165
   302
	identity_queue.store(new identity_queue_t());
markus@165
   303
	keymanagement_thread = new thread(::do_keymanagement, retrieve_next_identity, (void *)identity_queue.load());
markus@165
   304
markus@165
   305
	return S_OK;
vb@24
   306
}
vb@24
   307
markus@172
   308
STDMETHODIMP CpEpEngine::StopKeyserverLookup()
vb@24
   309
{
markus@165
   310
	if (identity_queue.load() == NULL)
markus@165
   311
		return S_OK;
vb@24
   312
markus@165
   313
	identity_queue_t *_iq = identity_queue.load();
markus@165
   314
	identity_queue.store(NULL);
vb@25
   315
markus@165
   316
	pEp_identity_cpp shutdown;
markus@165
   317
	_iq->push_front(shutdown);
vb@24
   318
markus@165
   319
	keymanagement_thread->join();
markus@165
   320
	delete keymanagement_thread;
markus@165
   321
	keymanagement_thread = NULL;
vb@24
   322
markus@165
   323
	delete _iq;
vb@24
   324
markus@165
   325
	return S_OK;
vb@24
   326
}
vb@24
   327
markus@172
   328
STDMETHODIMP CpEpEngine::Myself(struct pEpIdentity *ident, struct pEpIdentity *result)
vb@0
   329
{
markus@165
   330
	assert(ident);
markus@165
   331
	assert(result);
vb@0
   332
markus@192
   333
	if (!(ident && result))
markus@165
   334
		return E_INVALIDARG;
vb@0
   335
markus@196
   336
	::pEp_identity *_ident = 0;
markus@196
   337
	
markus@196
   338
	try {
markus@196
   339
		_ident = new_identity(ident);
markus@196
   340
		assert(_ident);
markus@196
   341
		if (_ident == NULL)
markus@196
   342
			return E_OUTOFMEMORY;
markus@196
   343
	}
markus@196
   344
	catch (bad_alloc&) {
markus@165
   345
		return E_OUTOFMEMORY;
markus@196
   346
	}
markus@196
   347
	catch (exception& ex) {
markus@196
   348
		return FAIL(ex.what());;
markus@196
   349
	}
markus@196
   350
vb@0
   351
markus@84
   352
	// DEBUG CODE - REMOVE BEFORE RELEASE!
markus@172
   353
	// SyncHandshakeResult handshakeResult;
markus@84
   354
	//
markus@85
   355
	// HRESULT res = Fire_ShowHandshake(ident, result, &handshakeResult);
markus@85
   356
	// 
markus@85
   357
	// HRESULT res2 = Fire_TestEvent(15, _bstr_t( "hallo"));
markus@84
   358
markus@165
   359
	PEP_STATUS status = ::myself(get_session(), _ident);
vb@0
   360
markus@165
   361
	if (status == PEP_STATUS_OK) {
markus@165
   362
		assert(_ident->fpr);
markus@165
   363
		copy_identity(result, _ident);
markus@165
   364
		::free_identity(_ident);
markus@165
   365
		return S_OK;
markus@165
   366
	}
markus@165
   367
	else {
markus@165
   368
		::free_identity(_ident);
markus@165
   369
		if (status == PEP_OUT_OF_MEMORY)
markus@165
   370
			return E_OUTOFMEMORY;
markus@165
   371
		else
markus@189
   372
			return FAIL(L"myself", status);
markus@165
   373
	}
vb@0
   374
}
vb@0
   375
markus@172
   376
STDMETHODIMP CpEpEngine::UpdateIdentity(struct pEpIdentity *ident, struct pEpIdentity *result)
vb@0
   377
{
markus@165
   378
	assert(ident);
markus@165
   379
	assert(result);
vb@0
   380
markus@192
   381
	if (!(ident && result))
markus@165
   382
		return E_INVALIDARG;
vb@0
   383
markus@196
   384
	::pEp_identity *_ident;
markus@196
   385
	try {
markus@196
   386
		_ident = new_identity(ident);
markus@196
   387
	}
markus@196
   388
	catch (bad_alloc&) {
markus@196
   389
		return E_OUTOFMEMORY;
markus@196
   390
	}
markus@196
   391
	catch (exception& ex) {
markus@196
   392
		return FAIL(ex.what());
markus@196
   393
	}
markus@196
   394
markus@165
   395
	assert(_ident);
markus@165
   396
	if (_ident == NULL)
markus@165
   397
		return E_OUTOFMEMORY;
vb@0
   398
markus@165
   399
	PEP_STATUS status = ::update_identity(get_session(), _ident);
vb@0
   400
markus@165
   401
	if (status == PEP_STATUS_OK) {
markus@201
   402
		assert(_ident->fpr); // Guaranteed not NULL, but possibly empty string.
markus@165
   403
		copy_identity(result, _ident);
markus@165
   404
		::free_identity(_ident);
markus@165
   405
		return S_OK;
markus@165
   406
	}
markus@165
   407
	else {
markus@165
   408
		::free_identity(_ident);
markus@165
   409
		if (status == PEP_OUT_OF_MEMORY)
markus@165
   410
			return E_OUTOFMEMORY;
markus@165
   411
		else
markus@189
   412
			return FAIL(L"UpdateIdentity", status);
markus@165
   413
	}
vb@0
   414
}
vb@0
   415
markus@172
   416
STDMETHODIMP CpEpEngine::KeyMistrusted(struct pEpIdentity *ident)
vb@4
   417
{
markus@165
   418
	::pEp_identity *_ident;
vb@4
   419
markus@165
   420
	assert(ident);
markus@192
   421
	if (!ident)
markus@192
   422
		return E_INVALIDARG;
vb@4
   423
markus@165
   424
	try {
markus@165
   425
		_ident = new_identity(ident);
markus@165
   426
	}
markus@165
   427
	catch (bad_alloc&) {
markus@165
   428
		return E_OUTOFMEMORY;
markus@165
   429
	}
markus@196
   430
	catch (exception& ex) {
markus@196
   431
		return FAIL(ex.what());;
markus@165
   432
	}
vb@4
   433
markus@165
   434
	PEP_STATUS status = ::key_mistrusted(get_session(), _ident);
markus@165
   435
	free_identity(_ident);
vb@49
   436
markus@165
   437
	if (status == PEP_OUT_OF_MEMORY)
markus@165
   438
		return E_OUTOFMEMORY;
vb@4
   439
markus@165
   440
	if (status == PEP_KEY_NOT_FOUND)
markus@165
   441
		return FAIL(L"key not found");
vb@4
   442
markus@165
   443
	if (status != ::PEP_STATUS_OK)
markus@189
   444
		return FAIL(L"cannot revoke compromized key", status);
vb@4
   445
markus@165
   446
	return S_OK;
vb@4
   447
}
vb@4
   448
markus@172
   449
STDMETHODIMP CpEpEngine::KeyResetTrust(struct pEpIdentity *ident)
Edouard@53
   450
{
markus@165
   451
	::pEp_identity *_ident;
Edouard@53
   452
markus@192
   453
	assert(ident); 
markus@192
   454
	
markus@192
   455
	if (!ident)
markus@192
   456
		return E_INVALIDARG;
Edouard@53
   457
markus@165
   458
	try {
markus@165
   459
		_ident = new_identity(ident);
markus@165
   460
	}
markus@165
   461
	catch (bad_alloc&) {
markus@165
   462
		return E_OUTOFMEMORY;
markus@165
   463
	}
markus@196
   464
	catch (exception& ex) {
markus@196
   465
		return FAIL(ex.what());;
markus@165
   466
	}
Edouard@53
   467
markus@165
   468
	PEP_STATUS status = ::key_reset_trust(get_session(), _ident);
markus@165
   469
	free_identity(_ident);
Edouard@53
   470
markus@165
   471
	if (status == PEP_OUT_OF_MEMORY)
markus@165
   472
		return E_OUTOFMEMORY;
Edouard@53
   473
markus@165
   474
	if (status == PEP_KEY_NOT_FOUND)
markus@165
   475
		return FAIL(L"key not found");
Edouard@53
   476
markus@165
   477
	if (status != ::PEP_STATUS_OK)
markus@189
   478
		return FAIL(L"cannot reset trust", status);
Edouard@53
   479
markus@165
   480
	return S_OK;
Edouard@53
   481
}
Edouard@53
   482
vb@28
   483
int CpEpEngine::examine_identity(pEp_identity *ident, void *management)
vb@28
   484
{
markus@165
   485
	assert(ident);
markus@165
   486
	assert(management);
markus@165
   487
	if (!(ident && management))
markus@165
   488
		return -1;
vb@28
   489
markus@165
   490
	CpEpEngine *me = (CpEpEngine *)management;
vb@28
   491
markus@165
   492
	if (me->identity_queue.load() == NULL)
markus@165
   493
		return 0;
vb@28
   494
markus@165
   495
	try {
markus@165
   496
		me->identity_queue.load()->push_back(ident);
markus@165
   497
	}
markus@165
   498
	catch (exception&) {
markus@165
   499
		return -1;
markus@165
   500
	}
vb@28
   501
markus@165
   502
	return 0;
vb@28
   503
}
vb@28
   504
vb@0
   505
::pEp_identity * CpEpEngine::retrieve_next_identity(void *management)
vb@0
   506
{
markus@165
   507
	assert(management);
markus@192
   508
	if (!management)
markus@192
   509
		return NULL;
markus@192
   510
markus@165
   511
	identity_queue_t *iq = (identity_queue_t *)management;
vb@0
   512
markus@165
   513
	do /* poll queue */ {
markus@165
   514
		if (iq->size())
markus@165
   515
			break;
markus@165
   516
		::Sleep(100);
markus@165
   517
	} while (true);
vb@0
   518
markus@165
   519
	::pEp_identity *_ident;
markus@165
   520
	pEp_identity_cpp& ident = iq->front();
vb@0
   521
markus@165
   522
	if (ident.address.size() == 0)
markus@165
   523
		return NULL;
vb@0
   524
markus@165
   525
	_ident = ident.to_pEp_identity();
markus@165
   526
	iq->pop_front();
vb@0
   527
markus@165
   528
	return _ident;
vb@0
   529
}
vb@0
   530
markus@164
   531
PEP_STATUS CpEpEngine::messageToSend(void * obj, message *msg)
vb@74
   532
{
markus@165
   533
	assert(msg);
markus@192
   534
	assert(obj);
markus@192
   535
	if (!(msg && obj))
markus@165
   536
		return PEP_ILLEGAL_VALUE;
vb@75
   537
markus@172
   538
	TextMessage _msg;
markus@172
   539
	memset(&_msg, 0, sizeof(TextMessage));
vb@82
   540
markus@165
   541
	text_message_from_C(&_msg, msg);
markus@165
   542
	CpEpEngine *me = (CpEpEngine *)obj;
markus@165
   543
	HRESULT r = me->Fire_MessageToSend(&_msg);
markus@165
   544
	assert(r == S_OK);
markus@165
   545
	clear_text_message(&_msg);
markus@165
   546
	if (r == E_OUTOFMEMORY)
markus@165
   547
		return PEP_OUT_OF_MEMORY;
markus@165
   548
	if (r != S_OK)
markus@165
   549
		return PEP_UNKNOWN_ERROR;
vb@75
   550
markus@165
   551
	return PEP_STATUS_OK;
vb@74
   552
}
vb@74
   553
markus@164
   554
PEP_STATUS CpEpEngine::showHandshake(void * obj, pEp_identity *self, pEp_identity *partner)
vb@74
   555
{
markus@165
   556
	assert(self && partner);
markus@165
   557
	if (!(self && partner))
markus@165
   558
		return PEP_ILLEGAL_VALUE;
vb@80
   559
markus@172
   560
	pEpIdentity _self;
markus@165
   561
	copy_identity(&_self, self);
markus@172
   562
	pEpIdentity _partner;
markus@165
   563
	copy_identity(&_partner, partner);
markus@165
   564
	CpEpEngine *me = (CpEpEngine *)obj;
markus@172
   565
	SyncHandshakeResult _result;
markus@165
   566
	HRESULT r = me->Fire_ShowHandshake(&_self, &_partner, &_result);
markus@165
   567
	assert(r == S_OK);
markus@165
   568
	clear_identity_s(_self);
markus@165
   569
	clear_identity_s(_partner);
markus@165
   570
	if (r == E_OUTOFMEMORY)
markus@165
   571
		return PEP_OUT_OF_MEMORY;
markus@165
   572
	if (r != S_OK)
markus@165
   573
		return PEP_UNKNOWN_ERROR;
vb@75
   574
markus@165
   575
	PEP_STATUS status = deliverHandshakeResult(me->get_session(), partner, (sync_handshake_result)(int)_result);
markus@165
   576
	return status;
vb@74
   577
}
vb@74
   578
markus@172
   579
STDMETHODIMP CpEpEngine::BlacklistAdd(BSTR fpr)
vb@65
   580
{
markus@165
   581
	assert(fpr);
markus@192
   582
	if (!fpr)
markus@192
   583
		return E_INVALIDARG;
vb@65
   584
markus@165
   585
	string _fpr = utf8_string(fpr);
markus@165
   586
	PEP_STATUS status = ::blacklist_add(get_session(), _fpr.c_str());
markus@165
   587
	assert(status == PEP_STATUS_OK);
markus@165
   588
	if (status != PEP_STATUS_OK)
markus@189
   589
		return FAIL(L"blacklist_add failed in pEp engine", status);
vb@65
   590
markus@165
   591
	return S_OK;
vb@65
   592
}
vb@65
   593
markus@172
   594
STDMETHODIMP CpEpEngine::BlacklistDelete(BSTR fpr)
vb@65
   595
{
markus@165
   596
	assert(fpr);
markus@192
   597
	if (!fpr)
markus@192
   598
		return E_INVALIDARG;
vb@65
   599
markus@165
   600
	string _fpr = utf8_string(fpr);
markus@165
   601
	PEP_STATUS status = ::blacklist_delete(get_session(), _fpr.c_str());
markus@165
   602
	assert(status == PEP_STATUS_OK);
markus@165
   603
	if (status != PEP_STATUS_OK)
markus@189
   604
		return FAIL(L"blacklist_delete failed in pEp engine", status);
vb@65
   605
markus@165
   606
	return S_OK;
vb@65
   607
}
vb@65
   608
markus@172
   609
STDMETHODIMP CpEpEngine::BlacklistIsListed(BSTR fpr, VARIANT_BOOL *listed)
vb@65
   610
{
markus@165
   611
	assert(fpr);
markus@165
   612
	assert(listed);
vb@65
   613
markus@192
   614
	if (!(fpr && listed))
markus@192
   615
		return E_INVALIDARG;
markus@192
   616
markus@165
   617
	string _fpr = utf8_string(fpr);
markus@165
   618
	bool result;
markus@165
   619
	PEP_STATUS status = ::blacklist_is_listed(get_session(), _fpr.c_str(), &result);
markus@165
   620
	assert(status == PEP_STATUS_OK);
markus@165
   621
	if (status != PEP_STATUS_OK)
markus@189
   622
		return FAIL(L"blacklist_is_listed failed in pEp engine", status);
vb@65
   623
markus@165
   624
	*listed = result ? VARIANT_TRUE : VARIANT_FALSE;
markus@165
   625
	return S_OK;
vb@65
   626
}
vb@65
   627
Dean@187
   628
STDMETHODIMP CpEpEngine::BlacklistRetrieve(SAFEARRAY **blacklist)
vb@65
   629
{
markus@165
   630
	assert(blacklist);
vb@65
   631
markus@192
   632
	if (!blacklist)
markus@192
   633
		return E_INVALIDARG;
markus@192
   634
markus@165
   635
	::stringlist_t *_blacklist = NULL;
markus@165
   636
	PEP_STATUS status = ::blacklist_retrieve(get_session(), &_blacklist);
markus@165
   637
	assert(status == PEP_STATUS_OK);
markus@165
   638
	if (status != PEP_STATUS_OK)
markus@189
   639
		return FAIL(L"blacklist_retrieve failed in pEp engine", status);
markus@165
   640
	assert(_blacklist);
vb@65
   641
markus@165
   642
	*blacklist = string_array(_blacklist);
markus@193
   643
	::free_stringlist(_blacklist);
markus@165
   644
	return S_OK;
vb@65
   645
}
vb@65
   646
vb@0
   647
HRESULT CpEpEngine::error(_bstr_t msg)
vb@0
   648
{
markus@165
   649
	_bstr_t helpFile = L"";
markus@165
   650
	_bstr_t source = L"pEp COM Adapter";
vb@0
   651
markus@165
   652
	ICreateErrorInfo *cei;
markus@165
   653
	if (SUCCEEDED(CreateErrorInfo(&cei))) {
markus@165
   654
		cei->SetDescription(msg);
markus@165
   655
		cei->SetGUID(__uuidof(IpEpEngine));
markus@165
   656
		cei->SetHelpContext(0);
markus@165
   657
		cei->SetHelpFile(helpFile);
markus@165
   658
		cei->SetSource(source);
vb@0
   659
markus@165
   660
		IErrorInfo *errinfo;
markus@165
   661
		if (SUCCEEDED(cei->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &errinfo))) {
markus@165
   662
			SetErrorInfo(0, errinfo);
markus@165
   663
			errinfo->Release();
markus@165
   664
		}
markus@165
   665
		cei->Release();
markus@165
   666
	}
markus@165
   667
	return E_FAIL;
vb@0
   668
}
vb@15
   669
markus@189
   670
HRESULT CpEpEngine::error(_bstr_t msg, PEP_STATUS status)
markus@189
   671
{
markus@189
   672
    std::stringstream stream;
markus@189
   673
    stream << msg;
markus@189
   674
    stream << ": ";
markus@189
   675
    stream << std::hex << status;
markus@189
   676
    
markus@189
   677
    error(stream.str().c_str());
markus@189
   678
markus@189
   679
    if (status == ::PEP_OUT_OF_MEMORY)
markus@189
   680
        return E_OUTOFMEMORY;
markus@189
   681
markus@189
   682
    return E_FAIL;
markus@189
   683
}
markus@189
   684
markus@172
   685
STDMETHODIMP CpEpEngine::EncryptMessage(TextMessage * src, TextMessage * dst, SAFEARRAY * extra, pEpEncryptFlags flags)
vb@15
   686
{
markus@165
   687
	assert(src);
markus@165
   688
	assert(dst);
vb@15
   689
markus@192
   690
	if (!(src && dst))
markus@192
   691
		return E_INVALIDARG;
markus@192
   692
markus@165
   693
	::message *_src = text_message_to_C(src);
markus@191
   694
markus@191
   695
	// COM-19: Initialize msg_dst to NULL, or we end up calling
markus@191
   696
	// free_message() below with a pointer to random garbage in
markus@191
   697
	// case of an error in encrypt_message().
markus@191
   698
	::message *msg_dst = NULL;
markus@192
   699
	::stringlist_t *_extra = new_stringlist(extra); // can cope with NULL
vb@16
   700
markus@167
   701
	// _PEP_enc_format is intentionally hardcoded to PEP_enc_PEP:
markus@167
   702
	// 2016-10-02 14:10 < fdik> schabi: actually, all adapters now must use PEP_enc_PEP
markus@167
   703
	PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t) flags;
markus@167
   704
	PEP_STATUS status = ::encrypt_message(get_session(), _src, _extra, &msg_dst, PEP_enc_PEP, engineFlags);
markus@165
   705
	::free_stringlist(_extra);
vb@16
   706
markus@165
   707
	if (status == PEP_STATUS_OK)
markus@165
   708
		text_message_from_C(dst, msg_dst);
markus@165
   709
	else
markus@165
   710
		text_message_from_C(dst, _src);
vb@38
   711
markus@165
   712
	::free_message(msg_dst);
markus@165
   713
	::free_message(_src);
vb@16
   714
markus@165
   715
	if (status == PEP_OUT_OF_MEMORY)
markus@165
   716
		return E_OUTOFMEMORY;
vb@46
   717
markus@204
   718
	// COM-41: Enhanced PEP status handling
markus@204
   719
	if ((status > PEP_STATUS_OK && status < PEP_UNENCRYPTED) ||
markus@204
   720
		status < PEP_STATUS_OK ||
markus@204
   721
		status >= PEP_TRUSTWORD_NOT_FOUND)
markus@204
   722
		return FAIL("Failure to encrypt message", status);
markus@204
   723
markus@204
   724
	// Statii like PEP_UNENCRYPTED due to no private key
markus@204
   725
	// should not be a catastrophic failure here. Using S_FALSE
markus@204
   726
	// still allows clients to differentiate with S_OK,
markus@204
   727
	// although this does not work out of the box with
markus@204
   728
	// the standard .NET mapping of COM.
markus@197
   729
	if (status != PEP_STATUS_OK)
markus@204
   730
		return S_FALSE;
markus@197
   731
markus@165
   732
	return S_OK;
vb@15
   733
}
vb@15
   734
markus@172
   735
STDMETHODIMP CpEpEngine::DecryptMessage(TextMessage * src, TextMessage * dst, SAFEARRAY ** keylist, pEpDecryptFlags *flags, pEpRating *rating)
vb@15
   736
{
markus@165
   737
	assert(src);
markus@165
   738
	assert(dst);
markus@165
   739
	assert(keylist);
markus@192
   740
	assert(flags);
markus@165
   741
	assert(rating);
vb@15
   742
markus@192
   743
	if (!(src && dst && keylist && flags && rating))
markus@192
   744
		return E_INVALIDARG;
markus@192
   745
markus@165
   746
	*keylist = NULL;
markus@172
   747
	*rating = pEpRatingUndefined;
vb@40
   748
markus@165
   749
	::message *_src = text_message_to_C(src);
markus@165
   750
	::message *msg_dst = NULL;
markus@195
   751
	::stringlist_t *_keylist = NULL;
markus@165
   752
	::PEP_rating _rating;
vb@16
   753
markus@167
   754
	PEP_decrypt_flags_t engineflags = 0;
markus@167
   755
	PEP_STATUS status = ::decrypt_message(get_session(), _src, &msg_dst, &_keylist, &_rating, &engineflags);
markus@167
   756
markus@167
   757
	*flags = (pEpDecryptFlags)engineflags;
vb@42
   758
markus@165
   759
	if (msg_dst)
markus@165
   760
		text_message_from_C(dst, msg_dst);
vb@42
   761
markus@165
   762
	::free_message(_src);
markus@165
   763
	::free_message(msg_dst);
vb@16
   764
markus@165
   765
	if (_keylist) {
markus@165
   766
		*keylist = string_array(_keylist);
markus@165
   767
		free_stringlist(_keylist);
markus@165
   768
	}
vb@18
   769
markus@172
   770
	*rating = (pEpRating)_rating;
vb@18
   771
markus@165
   772
	return S_OK;
vb@15
   773
}
vb@15
   774
markus@172
   775
STDMETHODIMP CpEpEngine::OutgoingMessageRating(TextMessage *msg, pEpRating * pVal)
vb@15
   776
{
markus@165
   777
	assert(msg);
markus@165
   778
	assert(pVal);
vb@15
   779
markus@192
   780
	if (!(msg  && pVal))
markus@192
   781
		return E_INVALIDARG;
markus@192
   782
markus@165
   783
	::message *_msg = text_message_to_C(msg);
vb@19
   784
markus@165
   785
	PEP_rating _rating;
markus@165
   786
	PEP_STATUS status = ::outgoing_message_rating(get_session(), _msg, &_rating);
markus@165
   787
	if (status != PEP_STATUS_OK)
markus@189
   788
		return FAIL(L"cannot get message rating", status);
vb@16
   789
markus@172
   790
	*pVal = (pEpRating)_rating;
markus@165
   791
	return S_OK;
vb@15
   792
}
vb@18
   793
markus@172
   794
STDMETHODIMP CpEpEngine::IdentityRating(struct pEpIdentity *ident, pEpRating * pVal)
vb@18
   795
{
markus@165
   796
	::pEp_identity *_ident;
vb@18
   797
markus@165
   798
	assert(ident);
markus@165
   799
	assert(pVal);
vb@18
   800
markus@192
   801
	if (!(ident  && pVal))
markus@192
   802
		return E_INVALIDARG;
markus@192
   803
markus@165
   804
	try {
markus@165
   805
		_ident = new_identity(ident);
markus@165
   806
	}
markus@165
   807
	catch (bad_alloc&) {
markus@165
   808
		return E_OUTOFMEMORY;
markus@165
   809
	}
markus@196
   810
	catch (exception& ex) {
markus@196
   811
		return FAIL(ex.what());;
markus@165
   812
	}
vb@18
   813
markus@165
   814
	PEP_rating _rating;
markus@165
   815
	PEP_STATUS status = ::identity_rating(get_session(), _ident, &_rating);
markus@165
   816
	free_identity(_ident);
markus@192
   817
markus@165
   818
	if (status != PEP_STATUS_OK)
markus@189
   819
		return FAIL(L"cannot get message color", status);
vb@18
   820
markus@172
   821
	*pVal = (pEpRating)_rating;
markus@165
   822
	return S_OK;
vb@18
   823
}
vb@48
   824
markus@172
   825
STDMETHODIMP CpEpEngine::ColorFromRating(pEpRating rating, pEpColor * pVal)
markus@164
   826
{
markus@164
   827
	assert(pVal);
markus@164
   828
markus@192
   829
	if (!pVal)
markus@192
   830
		return E_INVALIDARG;
markus@192
   831
markus@164
   832
	PEP_rating engineRating = (PEP_rating)rating;
markus@164
   833
	PEP_color _color = ::color_from_rating(engineRating);
markus@164
   834
markus@172
   835
	*pVal = (pEpColor)_color;
markus@164
   836
markus@164
   837
	return S_OK;
markus@164
   838
}
markus@164
   839
markus@172
   840
STDMETHODIMP CpEpEngine::TrustPersonalKey(struct pEpIdentity *ident, struct pEpIdentity *result)
vb@48
   841
{
markus@165
   842
	::pEp_identity *_ident;
vb@48
   843
markus@165
   844
	assert(ident);
markus@165
   845
	assert(result);
vb@48
   846
markus@192
   847
	if (!ident || !result)
markus@192
   848
		return E_INVALIDARG;
markus@192
   849
markus@165
   850
	try {
markus@165
   851
		_ident = new_identity(ident);
markus@165
   852
	}
markus@165
   853
	catch (bad_alloc&) {
markus@165
   854
		return E_OUTOFMEMORY;
markus@165
   855
	}
markus@196
   856
	catch (exception& ex) {
markus@196
   857
		return FAIL(ex.what());;
markus@165
   858
	}
vb@48
   859
markus@165
   860
	if (verbose_mode) {
markus@165
   861
		stringstream ss;
markus@172
   862
		ss << "TrustPersonalKey called with ";
markus@180
   863
		ss << utf8_string(ident->Address);
markus@165
   864
		ss << L": ";
markus@180
   865
		ss << ident->CommType;
markus@165
   866
		verbose(ss.str());
markus@165
   867
	}
vb@52
   868
markus@165
   869
	PEP_STATUS status = ::trust_personal_key(get_session(), _ident);
vb@52
   870
markus@165
   871
	if (verbose_mode) {
markus@165
   872
		stringstream ss;
markus@165
   873
		ss << "result ";
markus@165
   874
		ss << status;
markus@165
   875
		ss << " for ";
markus@165
   876
		ss << _ident->address;
markus@165
   877
		ss << L": ";
markus@165
   878
		ss << _ident->comm_type;
markus@165
   879
		verbose(ss.str());
markus@165
   880
	}
vb@52
   881
markus@165
   882
	if (status == PEP_STATUS_OK)
markus@165
   883
		copy_identity(result, _ident);
vb@50
   884
markus@165
   885
	free_identity(_ident);
markus@165
   886
	if (status == PEP_OUT_OF_MEMORY)
markus@165
   887
		return E_OUTOFMEMORY;
markus@165
   888
	else if (status != PEP_STATUS_OK)
markus@189
   889
		return FAIL(L"failure while executing TrustPersonalKey()", status);
vb@48
   890
markus@165
   891
	return S_OK;
markus@165
   892
}
markus@165
   893
markus@165
   894
// keysync api
markus@165
   895
markus@169
   896
void CpEpEngine::start_keysync()
markus@165
   897
{
markus@165
   898
	// acquire the lock
markus@165
   899
	std::unique_lock<std::mutex> lock(keysync_mutex);
markus@165
   900
markus@188
   901
	// Assert if we're not already running.
markus@188
   902
    assert(!this->keysync_thread);
markus@165
   903
markus@169
   904
	// Ensure we are not aborting the new thread due to a
markus@169
   905
	// left over flag.
markus@169
   906
	keysync_abort_requested = false;
markus@165
   907
markus@169
   908
	// Init our keysync session
markus@165
   909
	PEP_STATUS status = ::init(&keysync_session);
Dean@187
   910
	::register_sync_callbacks(keysync_session, (void*)this, messageToSend, showHandshake, inject_sync_msg, retrieve_next_sync_msg);
markus@176
   911
	assert(status == PEP_STATUS_OK);
markus@175
   912
markus@175
   913
    attach_sync_session(get_session(), keysync_session);
markus@165
   914
markus@188
   915
    // We need to marshal the callbacks to the keysync thread
markus@188
   916
    LPSTREAM marshaled_callbacks;
markus@188
   917
markus@188
   918
    auto result = CoMarshalInterThreadInterfaceInStream(IID_IpEpEngineCallbacks, client_callbacks, &marshaled_callbacks);
markus@188
   919
    assert(result == S_OK);
markus@188
   920
markus@169
   921
	// Star the keysync thread
markus@188
   922
	keysync_thread = new thread(do_keysync_in_thread, this, marshaled_callbacks);
markus@188
   923
}
markus@165
   924
markus@188
   925
void CpEpEngine::do_keysync_in_thread(CpEpEngine* self, LPSTREAM marshaled_callbacks) 
markus@188
   926
{
markus@188
   927
    assert(self);
markus@192
   928
	assert(marshaled_callbacks);
markus@192
   929
markus@188
   930
    // We need to initialize COM here for successfull delivery of the callbacks.
markus@188
   931
    // As we don't create any COM instances in our thread, the COMINIT value is
markus@188
   932
    // currently irrelevant, so we go with the safest value.
markus@188
   933
    auto res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
markus@188
   934
    assert(res == S_OK);
markus@188
   935
markus@188
   936
    LPVOID vp;
markus@188
   937
markus@188
   938
    res = CoGetInterfaceAndReleaseStream(marshaled_callbacks, IID_IpEpEngineCallbacks, &vp);
markus@188
   939
    assert(SUCCEEDED(res));
markus@188
   940
markus@188
   941
    self->client_callbacks_on_sync_thread = static_cast<IpEpEngineCallbacks*>(vp);
markus@188
   942
markus@188
   943
    ::do_sync_protocol(self->keysync_session, self);
markus@188
   944
markus@188
   945
    self->client_callbacks_on_sync_thread->Release();
markus@188
   946
markus@188
   947
    self->client_callbacks_on_sync_thread = NULL;
markus@188
   948
markus@188
   949
    CoUninitialize();
markus@165
   950
}
markus@165
   951
markus@169
   952
void CpEpEngine::stop_keysync()
markus@165
   953
{
markus@165
   954
	// acquire the lock
markus@165
   955
	std::unique_lock<std::mutex> lock(keysync_mutex);
markus@165
   956
markus@188
   957
    // Do nothing if keysync is not running.
markus@188
   958
    if (!keysync_thread)
markus@188
   959
        return;
markus@165
   960
markus@188
   961
    assert(!keysync_abort_requested);
markus@165
   962
	// signal that we're gonna abort
markus@165
   963
	keysync_abort_requested = true;
markus@165
   964
markus@165
   965
	// Notify the keysync thread
markus@165
   966
	keysync_condition.notify_all();
markus@165
   967
markus@165
   968
	// Wait for the other thread to finish and clean up
markus@188
   969
	while (keysync_abort_requested)
markus@165
   970
		keysync_condition.wait(lock);
markus@165
   971
markus@188
   972
	// collect the child thread for the thread to end
markus@165
   973
	keysync_thread->join();
markus@165
   974
markus@165
   975
	// clean up
markus@165
   976
	delete keysync_thread;
markus@165
   977
	keysync_thread = NULL;
markus@188
   978
markus@188
   979
    ::detach_sync_session(get_session());
markus@169
   980
	::unregister_sync_callbacks(keysync_session);
markus@165
   981
	release(keysync_session);
markus@180
   982
    keysync_session = NULL;
markus@165
   983
}
markus@165
   984
markus@165
   985
int CpEpEngine::inject_sync_msg(void * msg, void * management)
markus@165
   986
{
markus@192
   987
	assert(msg);
markus@192
   988
	assert(management);
markus@165
   989
	// check argument
markus@165
   990
	if (!msg)
markus@165
   991
		return E_INVALIDARG;
markus@169
   992
	if (!management)
markus@165
   993
		return ERROR_INVALID_HANDLE;
markus@165
   994
markus@169
   995
	CpEpEngine* me = (CpEpEngine*)management;
markus@169
   996
markus@165
   997
	// acquire the lock
markus@169
   998
	std::unique_lock<std::mutex> lock(me->keysync_mutex);
markus@165
   999
markus@188
  1000
	// check whether we're in a valid state running:
markus@188
  1001
	if (!me->keysync_thread)
markus@165
  1002
		return E_ASYNC_OPERATION_NOT_STARTED;
markus@165
  1003
markus@165
  1004
	// queue the message
markus@169
  1005
	me->keysync_queue.push(msg);
markus@165
  1006
markus@165
  1007
	// notify the receivers
markus@169
  1008
	me->keysync_condition.notify_all();
markus@170
  1009
markus@170
  1010
    return S_OK;
markus@165
  1011
}
markus@165
  1012
Dean@187
  1013
void * CpEpEngine::retrieve_next_sync_msg(void * management)
markus@165
  1014
{
markus@165
  1015
	// sanity check
markus@169
  1016
	assert(management);
markus@192
  1017
	if (!management)
markus@192
  1018
		return NULL;
markus@169
  1019
markus@169
  1020
	CpEpEngine* me = (CpEpEngine*)management;
markus@165
  1021
markus@165
  1022
	// acquire the lock
markus@169
  1023
	std::unique_lock<std::mutex> lock(me->keysync_mutex);
markus@165
  1024
markus@165
  1025
	// as long as we're supposed to be active 
markus@165
  1026
	// (we won't wait for the queue to empty currently...)
markus@169
  1027
	while (!me->keysync_abort_requested)
markus@165
  1028
	{
markus@165
  1029
		// If the queue is empty, wait for a signal, and try again.
markus@169
  1030
		if (me->keysync_queue.empty())
markus@165
  1031
		{
markus@169
  1032
			me->keysync_condition.wait(lock);
markus@165
  1033
			continue;
markus@165
  1034
		}
markus@165
  1035
markus@165
  1036
		// Pop the message and return it.
markus@169
  1037
		void* msg = me->keysync_queue.front();
markus@165
  1038
		assert(msg);
markus@165
  1039
markus@169
  1040
		me->keysync_queue.pop();
markus@169
  1041
markus@165
  1042
		return msg;
markus@165
  1043
	}
markus@165
  1044
markus@165
  1045
	// we acknowledge that we're quitting...
markus@188
  1046
	me->keysync_abort_requested = false;
markus@165
  1047
markus@165
  1048
	// We signal the main thread that we got his signal
markus@165
  1049
	// so it can gain the mutex again and call join() on us.
markus@169
  1050
	me->keysync_condition.notify_all();
markus@165
  1051
markus@165
  1052
	// and tell the pep engine we're done.
markus@165
  1053
	return NULL;
vb@48
  1054
}
markus@84
  1055
markus@84
  1056
markus@84
  1057
// Event callbacks
markus@84
  1058
markus@172
  1059
STDMETHODIMP CpEpEngine::RegisterCallbacks(IpEpEngineCallbacks* new_callbacks)
markus@84
  1060
{
markus@188
  1061
    // check for valid parameter
markus@188
  1062
    if (!new_callbacks)
markus@188
  1063
        return E_INVALIDARG;
markus@84
  1064
markus@188
  1065
    // don't allow double registration.
markus@188
  1066
    if (this->client_callbacks)
markus@188
  1067
        return E_ILLEGAL_STATE_CHANGE;
markus@188
  1068
markus@188
  1069
    this->client_callbacks = new_callbacks;
markus@188
  1070
    new_callbacks->AddRef();
markus@188
  1071
markus@169
  1072
	start_keysync();
markus@84
  1073
markus@84
  1074
	return S_OK;
markus@84
  1075
}
markus@84
  1076
markus@188
  1077
STDMETHODIMP CpEpEngine::UnregisterCallbacks()
markus@84
  1078
{
markus@188
  1079
    // don't allow double deregistration.
markus@188
  1080
    // S_FALSE still is no error (as double deregistration is not fatal).
markus@188
  1081
    if (!this->client_callbacks)
markus@188
  1082
        return S_FALSE;
markus@84
  1083
markus@188
  1084
    stop_keysync();
markus@169
  1085
markus@188
  1086
    this->client_callbacks->Release();
markus@84
  1087
markus@188
  1088
    this->client_callbacks = NULL;
markus@188
  1089
markus@188
  1090
    return S_OK;
markus@84
  1091
}
markus@84
  1092
markus@177
  1093
STDMETHODIMP CpEpEngine::OpenPGPListKeyinfo(BSTR search_pattern, LPSAFEARRAY* keyinfo_list) {
markus@165
  1094
	assert(keyinfo_list);
krista@154
  1095
markus@165
  1096
	if (keyinfo_list == NULL)
markus@165
  1097
		return E_INVALIDARG;
krista@154
  1098
markus@165
  1099
	string _pattern = "";
markus@165
  1100
	if (search_pattern)
markus@165
  1101
		_pattern = utf8_string(search_pattern);
markus@165
  1102
	::stringpair_list_t* _keyinfo_list = NULL;
krista@154
  1103
markus@165
  1104
	PEP_STATUS status = ::OpenPGP_list_keyinfo(get_session(), _pattern.c_str(), &_keyinfo_list);
markus@165
  1105
	assert(status != PEP_OUT_OF_MEMORY);
markus@165
  1106
	if (status == PEP_OUT_OF_MEMORY)
markus@165
  1107
		return E_OUTOFMEMORY;
krista@154
  1108
markus@165
  1109
	if (status != ::PEP_STATUS_OK)
markus@189
  1110
		return FAIL(L"OpenPGP_list_keyinfo", status);
krista@154
  1111
markus@165
  1112
	if (_keyinfo_list && _keyinfo_list->value) {
markus@165
  1113
		::opt_field_array_from_C(_keyinfo_list, keyinfo_list);
markus@165
  1114
	}
markus@165
  1115
	else {
markus@165
  1116
		::free_stringpair_list(_keyinfo_list);
markus@165
  1117
		return FAIL(L"OpenPGP_list_keyinfo: no keys found");
markus@165
  1118
	}
markus@165
  1119
markus@165
  1120
	::free_stringpair_list(_keyinfo_list);
markus@165
  1121
	return S_OK;
markus@165
  1122
krista@154
  1123
}
krista@154
  1124
markus@172
  1125
HRESULT CpEpEngine::Fire_MessageToSend(TextMessage * msg)
markus@84
  1126
{
markus@188
  1127
	assert(msg);
markus@188
  1128
    assert(this->client_callbacks_on_sync_thread);
markus@84
  1129
markus@192
  1130
	if (!msg)
markus@192
  1131
		return E_INVALIDARG;
markus@192
  1132
markus@192
  1133
	if (!this->client_callbacks_on_sync_thread)
markus@192
  1134
		return E_ILLEGAL_METHOD_CALL;
markus@192
  1135
markus@188
  1136
    auto result = this->client_callbacks_on_sync_thread->MessageToSend(msg);
markus@84
  1137
markus@188
  1138
	return result;
markus@84
  1139
}
markus@84
  1140
markus@172
  1141
HRESULT CpEpEngine::Fire_ShowHandshake(pEpIdentity * self, pEpIdentity * partner, SyncHandshakeResult * result)
markus@84
  1142
{
markus@84
  1143
	assert(self);
markus@84
  1144
	assert(partner);
markus@84
  1145
	assert(result);
markus@188
  1146
    assert(this->client_callbacks_on_sync_thread);
markus@192
  1147
markus@192
  1148
	if (!(self && partner && result))
markus@192
  1149
		return E_INVALIDARG;
markus@192
  1150
	if (!this->client_callbacks_on_sync_thread)
markus@192
  1151
		return E_ILLEGAL_METHOD_CALL;
markus@188
  1152
    	
markus@188
  1153
	auto res = this->client_callbacks_on_sync_thread->ShowHandshake(self, partner, result);
markus@188
  1154
		
markus@188
  1155
	return res;	
markus@84
  1156
}