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