CpEpEngine.cpp
author Markus Schaber <markus@pep-security.net>
Sun, 02 Oct 2016 15:38:37 +0200
branchkeysync
changeset 167 9bdd481dd300
parent 165 77dfd1defafa
child 169 d776268c12a7
permissions -rw-r--r--
Expose flags for en- and decryption
     1 // CpEpEngine.cpp : Implementation of CpEpEngine
     2 
     3 #include "stdafx.h"
     4 #include "CpEpEngine.h"
     5 
     6 using namespace std;
     7 using namespace pEp::utility;
     8 
     9 // CpEpEngine
    10 
    11 STDMETHODIMP CpEpEngine::InterfaceSupportsErrorInfo(REFIID riid)
    12 {
    13 	static const IID* const arr[] =
    14 	{
    15 		&IID_IpEpEngine
    16 	};
    17 
    18 	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
    19 	{
    20 		if (InlineIsEqualGUID(*arr[i], riid))
    21 			return S_OK;
    22 	}
    23 	return S_FALSE;
    24 }
    25 
    26 #define FAIL(msg) error(msg)
    27 
    28 STDMETHODIMP CpEpEngine::verbose_logging(VARIANT_BOOL enable)
    29 {
    30 	verbose_mode = enable != VARIANT_FALSE;
    31 	return S_OK;
    32 }
    33 
    34 STDMETHODIMP CpEpEngine::passive_mode(VARIANT_BOOL enable)
    35 {
    36 	::config_passive_mode(get_session(), enable != VARIANT_FALSE);
    37 	return S_OK;
    38 }
    39 
    40 STDMETHODIMP CpEpEngine::unencrypted_subject(VARIANT_BOOL enable)
    41 {
    42 	::config_unencrypted_subject(get_session(), enable != VARIANT_FALSE);
    43 	return S_OK;
    44 }
    45 
    46 STDMETHODIMP CpEpEngine::log(BSTR title, BSTR entity, BSTR description, BSTR comment)
    47 {
    48 	string _title;
    49 	string _entity;
    50 	string _description;
    51 	string _comment;
    52 	HRESULT result = S_OK;
    53 
    54 	assert(title);
    55 	if (title)
    56 		_title = utf8_string(title);
    57 	else
    58 		result = E_INVALIDARG;
    59 
    60 	assert(entity);
    61 	if (entity)
    62 		_entity = utf8_string(entity);
    63 	else
    64 		result = E_INVALIDARG;
    65 
    66 	if (description)
    67 		_description = utf8_string(description);
    68 
    69 	if (comment)
    70 		_comment = utf8_string(comment);
    71 
    72 	if (result != S_OK)
    73 		return result;
    74 
    75 	PEP_STATUS _status = ::log_event(get_session(), _title.c_str(), _entity.c_str(), _description.c_str(), _comment.c_str());
    76 	assert(_status == PEP_STATUS_OK);
    77 	if (_status != PEP_STATUS_OK)
    78 		return FAIL(L"log_event");
    79 	else
    80 		return S_OK;
    81 }
    82 
    83 
    84 STDMETHODIMP CpEpEngine::decrypt(BSTR ctext, BSTR * ptext, LPSAFEARRAY * key_list, pEp_STATUS * status)
    85 {
    86 	assert(ctext);
    87 	assert(ptext);
    88 	assert(key_list);
    89 	assert(status);
    90 
    91 	if (ctext == NULL || ptext == NULL || key_list == NULL || status == NULL) {
    92 		if (ptext)
    93 			*ptext = NULL;
    94 		if (key_list)
    95 			*key_list = NULL;
    96 		if (status)
    97 			*status = pEp_UNENCRYPTED;
    98 		return E_INVALIDARG;
    99 	}
   100 
   101 	string _ctext = utf8_string(ctext);
   102 
   103 	char *_ptext = NULL;
   104 	size_t _psize = 0;
   105 	::stringlist_t *_keylist = NULL;
   106 	PEP_STATUS _status;
   107 
   108 	_status = ::decrypt_and_verify(get_session(), _ctext.c_str(), _ctext.size(), &_ptext, &_psize, &_keylist);
   109 	assert(_status != PEP_OUT_OF_MEMORY);
   110 	if (_status == PEP_OUT_OF_MEMORY)
   111 		return E_OUTOFMEMORY;
   112 
   113 	*status = (pEp_STATUS)_status;
   114 	if (_ptext == NULL) {
   115 		if (_keylist) {
   116 			string msg;
   117 			if (_keylist->value[0] != 0) {
   118 				msg = _keylist->value;
   119 			}
   120 			else {
   121 				for (::stringlist_t *s = _keylist->next; s != NULL; s = s->next) {
   122 					if (s->value) {
   123 						msg += s->value;
   124 						msg += ";";
   125 					}
   126 				}
   127 			}
   128 			::free_stringlist(_keylist);
   129 
   130 			return FAIL(utf16_bstr(msg));
   131 		}
   132 		else
   133 			return FAIL(L"cannot decrypt");
   134 	}
   135 
   136 	*ptext = utf16_bstr(_ptext);
   137 	pEp_free(_ptext);
   138 
   139 	if (_keylist && _keylist->value)
   140 		*key_list = string_array(_keylist);
   141 	else
   142 		*key_list = NULL;
   143 	::free_stringlist(_keylist);
   144 
   145 	return S_OK;
   146 }
   147 
   148 STDMETHODIMP CpEpEngine::decrypt_b(BSTR ctext, LPSAFEARRAY * ptext, LPSAFEARRAY * key_list, pEp_STATUS * status)
   149 {
   150 	assert(ctext);
   151 	assert(ptext);
   152 	assert(key_list);
   153 	assert(status);
   154 
   155 	if (ctext == NULL || ptext == NULL || key_list == NULL || status == NULL) {
   156 		if (ptext)
   157 			*ptext = NULL;
   158 		if (key_list)
   159 			*key_list = NULL;
   160 		if (status)
   161 			*status = pEp_UNENCRYPTED;
   162 		return E_INVALIDARG;
   163 	}
   164 
   165 	// Welcome to Windoze string hell!
   166 
   167 	char *_ctext = NULL;
   168 	_bstr_t bstr_ctext(ctext, true);
   169 	int w_csize = bstr_ctext.length() + 1;
   170 	int _csize = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, (wchar_t *)bstr_ctext, w_csize, NULL, 0, NULL, NULL);
   171 	if (_csize) {
   172 		_ctext = new char[_csize];
   173 		WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, (wchar_t *)bstr_ctext, w_csize, _ctext, _csize, NULL, NULL);
   174 	}
   175 
   176 	char *_ptext = NULL;
   177 	size_t _psize = 0;
   178 	::stringlist_t *_keylist = NULL;
   179 	PEP_STATUS _status;
   180 
   181 	_status = ::decrypt_and_verify(get_session(), _ctext, _csize, &_ptext, &_psize, &_keylist);
   182 	assert(_status != PEP_OUT_OF_MEMORY);
   183 	delete[] _ctext;
   184 	if (_status == PEP_OUT_OF_MEMORY) {
   185 		::free_stringlist(_keylist);
   186 		return E_OUTOFMEMORY;
   187 	}
   188 	*status = (pEp_STATUS)_status;
   189 
   190 	if (_ptext == NULL) {
   191 		::free_stringlist(_keylist);
   192 		return FAIL(L"decrypt_and_verify");
   193 	}
   194 
   195 	CComSafeArray<BYTE> sa_ptext;
   196 
   197 	HRESULT _result = sa_ptext.Create(_psize, 0);
   198 	assert(_result == S_OK);
   199 	if (_result == E_OUTOFMEMORY) {
   200 		pEp_free(_ptext);
   201 		::free_stringlist(_keylist);
   202 		return E_OUTOFMEMORY;
   203 	}
   204 	else if (_result != S_OK) {
   205 		pEp_free(_ptext);
   206 		::free_stringlist(_keylist);
   207 		return FAIL(L"CComSafeArray<BYTE>::Create");
   208 	}
   209 
   210 	memcpy(sa_ptext.m_psa->pvData, _ptext, _psize);
   211 	*ptext = sa_ptext.Detach();
   212 	::pEp_free(_ptext);
   213 
   214 	if (_keylist && _keylist->value)
   215 		*key_list = string_array(_keylist);
   216 	else
   217 		*key_list = NULL;
   218 	::free_stringlist(_keylist);
   219 
   220 	return S_OK;
   221 }
   222 
   223 STDMETHODIMP CpEpEngine::verify(BSTR text, BSTR signature, LPSAFEARRAY * key_list, pEp_STATUS * verify_status)
   224 {
   225 	assert(text);
   226 	assert(signature);
   227 	assert(key_list);
   228 
   229 	if (text == NULL || signature == NULL || key_list == NULL)
   230 		return E_INVALIDARG;
   231 
   232 	string _text = utf8_string(text);
   233 	string _signature = utf8_string(signature);
   234 
   235 	::stringlist_t *_keylist = NULL;
   236 	PEP_STATUS _status;
   237 	_status = ::verify_text(get_session(), _text.c_str(), _text.size(), _signature.c_str(), _signature.size(), &_keylist);
   238 	assert(_status != PEP_OUT_OF_MEMORY);
   239 	if (_status == PEP_OUT_OF_MEMORY)
   240 		return E_OUTOFMEMORY;
   241 	if (_status == PEP_DECRYPT_WRONG_FORMAT || _status == PEP_UNKNOWN_ERROR)
   242 		return FAIL(L"verify_text");
   243 
   244 	*verify_status = (pEp_STATUS)_status;
   245 
   246 	if (_keylist && _keylist->value)
   247 		*key_list = string_array(_keylist);
   248 	else
   249 		*key_list = NULL;
   250 	::free_stringlist(_keylist);
   251 
   252 	return S_OK;
   253 }
   254 
   255 STDMETHODIMP CpEpEngine::encrypt(SAFEARRAY * key_list, BSTR ptext, BSTR * ctext, pEp_STATUS * status)
   256 {
   257 	assert(key_list);
   258 	assert(ptext);
   259 	assert(ctext);
   260 	assert(status);
   261 
   262 	if (ctext == NULL || ptext == NULL || key_list == NULL || status == NULL) {
   263 		if (ctext)
   264 			*ctext = NULL;
   265 		if (status)
   266 			*status = pEp_UNKNOWN_ERROR;
   267 		return E_INVALIDARG;
   268 	}
   269 
   270 	HRESULT result = S_OK;
   271 
   272 	::stringlist_t *_keylist = new_stringlist(key_list);
   273 	string _ptext = utf8_string(ptext);
   274 
   275 	char *_ctext = NULL;
   276 	size_t _csize = 0;
   277 	PEP_STATUS _status;
   278 
   279 	_status = ::encrypt_and_sign(get_session(), _keylist, _ptext.c_str(), _ptext.size(), &_ctext, &_csize);
   280 
   281 	assert(_status != PEP_OUT_OF_MEMORY);
   282 	::free_stringlist(_keylist);
   283 	if (_status == PEP_OUT_OF_MEMORY)
   284 		return E_OUTOFMEMORY;
   285 	*status = (pEp_STATUS)_status;
   286 
   287 	if (_ctext == NULL)
   288 		return FAIL(L"encrypt_and_sign");
   289 
   290 	*ctext = utf16_bstr(_ctext);
   291 	pEp_free(_ctext);
   292 
   293 	return S_OK;
   294 }
   295 
   296 STDMETHODIMP CpEpEngine::encrypt_b(SAFEARRAY * key_list, SAFEARRAY * ptext, BSTR * ctext, pEp_STATUS * status)
   297 {
   298 	assert(key_list);
   299 	assert(ptext);
   300 	assert(ctext);
   301 	assert(status);
   302 
   303 	if (ctext == NULL || ptext == NULL || key_list == NULL || status == NULL) {
   304 		if (ctext)
   305 			*ctext = NULL;
   306 		if (status)
   307 			*status = pEp_UNKNOWN_ERROR;
   308 		return E_INVALIDARG;
   309 	}
   310 
   311 	HRESULT result = S_OK;
   312 
   313 	::stringlist_t *_keylist = new_stringlist(key_list);
   314 
   315 	char *_ctext = NULL;
   316 	size_t _csize = 0;
   317 	::PEP_STATUS _status;
   318 
   319 	_status = ::encrypt_and_sign(get_session(), _keylist, (const char *)ptext->pvData, ptext->rgsabound[0].cElements, &_ctext, &_csize);
   320 	assert(_status != PEP_OUT_OF_MEMORY);
   321 	::free_stringlist(_keylist);
   322 	if (_status == PEP_OUT_OF_MEMORY)
   323 		return E_OUTOFMEMORY;
   324 	*status = (pEp_STATUS)_status;
   325 
   326 	if (_ctext == NULL)
   327 		return FAIL(L"encrypt_and_sign");
   328 
   329 	*status = (pEp_STATUS)_status;
   330 	wchar_t *w_ctext = NULL;
   331 	int w_csize = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, _ctext, _csize, NULL, 0);
   332 	if (w_csize) {
   333 		w_ctext = new wchar_t[w_csize + 1];
   334 		MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, _ctext, _csize, w_ctext, w_csize);
   335 		w_ctext[w_csize] = 0; // this is for debugging; Visual Studio will crash without that if you're unlucky
   336 	}
   337 	*ctext = ::SysAllocStringLen(w_ctext, w_csize);
   338 	assert(ctext);
   339 	delete[] w_ctext;
   340 	pEp_free(_ctext);
   341 	if (ctext == NULL)
   342 		return E_OUTOFMEMORY;
   343 
   344 	return S_OK;
   345 }
   346 
   347 STDMETHODIMP CpEpEngine::trustword(LONG value, BSTR lang, BSTR * word)
   348 {
   349 	assert(value >= 0 && value <= 65535);
   350 	assert(word);
   351 
   352 	HRESULT result = S_OK;
   353 
   354 	uint16_t _value = 0;
   355 	if (value < 0 || value > 65535)
   356 		result = E_INVALIDARG;
   357 	else
   358 		_value = (uint16_t)value;
   359 
   360 	string _lang = "en";
   361 	if (lang) {
   362 		_lang = utf8_string(lang);
   363 		if (_lang.length() != 2)
   364 			result = E_INVALIDARG;
   365 	}
   366 
   367 	if (word == NULL)
   368 		result = E_INVALIDARG;
   369 
   370 	if (result != S_OK)
   371 		return result;
   372 
   373 	char *_word = NULL;
   374 	size_t _wsize = 0;
   375 
   376 	PEP_STATUS status = ::trustword(get_session(), _value, _lang.c_str(), &_word, &_wsize);
   377 	assert(status != PEP_OUT_OF_MEMORY);
   378 	if (status == PEP_OUT_OF_MEMORY)
   379 		return E_OUTOFMEMORY;
   380 
   381 	if (_word == NULL) {
   382 		*word = NULL;
   383 		return FAIL(L"trustword");
   384 	}
   385 	else {
   386 		*word = utf16_bstr(_word);
   387 		pEp_free(_word);
   388 		return S_OK;
   389 	}
   390 }
   391 
   392 STDMETHODIMP CpEpEngine::trustwords(BSTR fpr, BSTR lang, LONG max_words, BSTR * words)
   393 {
   394 	assert(fpr);
   395 	assert(max_words >= 0);
   396 	assert(words);
   397 
   398 	HRESULT result = S_OK;
   399 
   400 	string _fpr;
   401 	if (fpr)
   402 		_fpr = utf8_string(fpr);
   403 	else
   404 		result = E_INVALIDARG;
   405 
   406 	string _lang;
   407 	if (lang) {
   408 		_lang = utf8_string(lang);
   409 		if (_lang.length()) {
   410 			if (_lang.length() != 2)
   411 				result = E_INVALIDARG;
   412 		}
   413 		else
   414 			_lang = "en";
   415 	}
   416 	else
   417 		_lang = "en";
   418 
   419 	if (max_words < 0)
   420 		result = E_INVALIDARG;
   421 
   422 	if (words == NULL)
   423 		result = E_INVALIDARG;
   424 
   425 	if (result != S_OK)
   426 		return result;
   427 
   428 	char *_words = NULL;
   429 	size_t _wsize = 0;
   430 
   431 	PEP_STATUS status = ::trustwords(get_session(), _fpr.c_str(), _lang.c_str(), &_words, &_wsize, max_words);
   432 	assert(status != PEP_OUT_OF_MEMORY);
   433 	if (status == PEP_OUT_OF_MEMORY)
   434 		return E_OUTOFMEMORY;
   435 
   436 	if (_words == NULL) {
   437 		*words = NULL;
   438 		return FAIL(L"trustwords");
   439 	}
   440 	else {
   441 		*words = utf16_bstr(_words);
   442 		pEp_free(_words);
   443 		return S_OK;
   444 	}
   445 }
   446 
   447 STDMETHODIMP CpEpEngine::get_crashdump_log(LONG maxlines, BSTR * log)
   448 {
   449 	assert(maxlines >= 0);
   450 	assert(log);
   451 
   452 	if (!(maxlines >= 0 && log))
   453 		return E_INVALIDARG;
   454 
   455 	char *_log;
   456 	PEP_STATUS status = ::get_crashdump_log(get_session(), (int)maxlines, &_log);
   457 	assert(status == PEP_STATUS_OK);
   458 	if (status == PEP_OUT_OF_MEMORY)
   459 		return E_OUTOFMEMORY;
   460 	if (status != PEP_STATUS_OK || _log == NULL)
   461 		return FAIL(L"get_crashdump_log");
   462 
   463 	*log = utf16_bstr(_log);
   464 	pEp_free(_log);
   465 	return S_OK;
   466 }
   467 
   468 STDMETHODIMP CpEpEngine::get_engine_version(BSTR * engine_version)
   469 {
   470 	assert(engine_version);
   471 
   472 	if (!engine_version)
   473 		return E_INVALIDARG;
   474 
   475 	const char *_enginge_version = ::get_engine_version();
   476 
   477 	if (_enginge_version == NULL)
   478 		return FAIL(L"get_engine_version");
   479 
   480 	*engine_version = utf16_bstr(_enginge_version);
   481 
   482 	return S_OK;
   483 }
   484 
   485 STDMETHODIMP CpEpEngine::get_languagelist(BSTR * languages)
   486 {
   487 	assert(languages);
   488 
   489 	if (!languages)
   490 		return E_INVALIDARG;
   491 
   492 	char *_languages;
   493 	PEP_STATUS status = ::get_languagelist(get_session(), &_languages);
   494 	assert(status == PEP_STATUS_OK);
   495 	if (status == PEP_OUT_OF_MEMORY)
   496 		return E_OUTOFMEMORY;
   497 	if (status != PEP_STATUS_OK || _languages == NULL)
   498 		return FAIL(L"get_languagelist");
   499 
   500 	*languages = utf16_bstr(_languages);
   501 	pEp_free(_languages);
   502 	return S_OK;
   503 }
   504 
   505 STDMETHODIMP CpEpEngine::get_phrase(BSTR lang, LONG phrase_id, BSTR * phrase)
   506 {
   507 	assert(lang && phrase_id >= 0 && phrase);
   508 
   509 	if (!(lang && phrase_id >= 0 && phrase))
   510 		return E_INVALIDARG;
   511 
   512 	string _lang = utf8_string(lang);
   513 	assert(_lang.length() == 2);
   514 	if (_lang.length() != 2)
   515 		return E_INVALIDARG;
   516 
   517 	char *_phrase;
   518 	PEP_STATUS status = ::get_phrase(get_session(), _lang.c_str(), (int)phrase_id, &_phrase);
   519 	assert(status == PEP_STATUS_OK);
   520 	if (status == PEP_OUT_OF_MEMORY)
   521 		return E_OUTOFMEMORY;
   522 	if (status != PEP_STATUS_OK || _phrase == NULL)
   523 		return FAIL(L"get_phrase");
   524 
   525 	*phrase = utf16_bstr(_phrase);
   526 	pEp_free(_phrase);
   527 	return S_OK;
   528 }
   529 
   530 STDMETHODIMP CpEpEngine::get_identity(BSTR address, BSTR user_id, pEp_identity_s * ident)
   531 {
   532 	assert(address);
   533 	assert(user_id);
   534 	assert(ident);
   535 
   536 	if (address == NULL)
   537 		return E_INVALIDARG;
   538 	if (user_id == NULL)
   539 		return E_INVALIDARG;
   540 	if (ident == NULL)
   541 		return E_INVALIDARG;
   542 
   543 	string _address = utf8_string(address);
   544 	string _user_id = utf8_string(user_id);
   545 
   546 	::pEp_identity *_ident = NULL;
   547 	PEP_STATUS status = ::get_identity(get_session(), _address.c_str(), _user_id.c_str(), &_ident);
   548 	assert(status != PEP_OUT_OF_MEMORY);
   549 	if (status == PEP_OUT_OF_MEMORY)
   550 		return E_OUTOFMEMORY;
   551 
   552 	if (_ident == NULL) {
   553 		return FAIL(L"get_identity");
   554 	}
   555 
   556 	copy_identity(ident, _ident);
   557 	::free_identity(_ident);
   558 
   559 	return S_OK;
   560 }
   561 
   562 STDMETHODIMP CpEpEngine::set_identity(pEp_identity_s * ident)
   563 {
   564 	assert(ident);
   565 	assert(ident->address);
   566 	assert(ident->fpr);
   567 	assert(ident->username);
   568 	assert(ident->user_id);
   569 
   570 	if (ident == NULL || ident->address == NULL || ident->fpr == NULL
   571 		|| ident->username == NULL || ident->user_id == NULL)
   572 		return E_INVALIDARG;
   573 
   574 	::pEp_identity *_ident = new_identity(ident);
   575 	::PEP_STATUS status = ::set_identity(get_session(), _ident);
   576 	::free_identity(_ident);
   577 
   578 	if (status != ::PEP_STATUS_OK)
   579 		return FAIL(L"set_identity");
   580 	else
   581 		return S_OK;
   582 }
   583 
   584 STDMETHODIMP CpEpEngine::generate_keypair(pEp_identity_s * ident, BSTR * fpr)
   585 {
   586 	assert(ident);
   587 	assert(ident->address);
   588 	assert(ident->username);
   589 	assert(fpr);
   590 
   591 	if (ident == NULL || ident->address == NULL || ident->username == NULL || fpr == NULL)
   592 		return E_INVALIDARG;
   593 
   594 	::pEp_identity *_ident = new_identity(ident);
   595 	::pEp_free(_ident->fpr);
   596 	_ident->fpr = NULL;
   597 
   598 	::PEP_STATUS status = ::generate_keypair(get_session(), _ident);
   599 	assert(status != ::PEP_OUT_OF_MEMORY);
   600 	if (status == ::PEP_OUT_OF_MEMORY) {
   601 		::free_identity(_ident);
   602 		return E_OUTOFMEMORY;
   603 	}
   604 
   605 	if (_ident->fpr)
   606 		*fpr = utf16_bstr(_ident->fpr);
   607 
   608 	::free_identity(_ident);
   609 
   610 	if (status != ::PEP_STATUS_OK)
   611 		return FAIL(L"generate_keypair");
   612 
   613 	return S_OK;
   614 }
   615 
   616 STDMETHODIMP CpEpEngine::delete_keypair(BSTR fpr)
   617 {
   618 	assert(fpr);
   619 
   620 	if (fpr == NULL)
   621 		return E_INVALIDARG;
   622 
   623 	string _fpr = utf8_string(fpr);
   624 
   625 	::PEP_STATUS status = ::delete_keypair(get_session(), _fpr.c_str());
   626 	assert(status != PEP_OUT_OF_MEMORY);
   627 	if (status == PEP_OUT_OF_MEMORY)
   628 		return E_OUTOFMEMORY;
   629 
   630 	if (status != ::PEP_STATUS_OK)
   631 		return FAIL(L"delete_keypair");
   632 	else
   633 		return S_OK;
   634 }
   635 
   636 STDMETHODIMP CpEpEngine::import_key(BSTR key_data)
   637 {
   638 	assert(key_data);
   639 
   640 	if (key_data == NULL)
   641 		return E_INVALIDARG;
   642 
   643 	string _key_data = utf8_string(key_data);
   644 
   645 	PEP_STATUS status = ::import_key(get_session(), _key_data.c_str(), _key_data.length(), NULL);
   646 	assert(status != PEP_OUT_OF_MEMORY);
   647 	if (status == PEP_OUT_OF_MEMORY)
   648 		return E_OUTOFMEMORY;
   649 
   650 	if (status != pEp_STATUS_OK)
   651 		return FAIL(L"import_key");
   652 	else
   653 		return S_OK;
   654 }
   655 
   656 STDMETHODIMP CpEpEngine::import_key_b(SAFEARRAY * key_data)
   657 {
   658 	assert(key_data);
   659 
   660 	if (key_data == NULL)
   661 		return E_INVALIDARG;
   662 
   663 	::PEP_STATUS status = ::import_key(get_session(), (const char *)key_data->pvData, key_data->rgsabound[0].cElements, NULL);
   664 	assert(status != ::PEP_OUT_OF_MEMORY);
   665 	if (status == ::PEP_OUT_OF_MEMORY)
   666 		return E_OUTOFMEMORY;
   667 
   668 	if (status != ::PEP_STATUS_OK)
   669 		return FAIL(L"import_key");
   670 	else
   671 		return S_OK;
   672 }
   673 
   674 STDMETHODIMP CpEpEngine::export_key(BSTR fpr, BSTR * key_data)
   675 {
   676 	assert(fpr);
   677 	assert(key_data);
   678 
   679 	if (fpr == NULL || key_data == NULL)
   680 		return E_INVALIDARG;
   681 
   682 	string _fpr = utf8_string(fpr);
   683 	char *_key_data = NULL;
   684 	size_t _size = 0;
   685 
   686 	::PEP_STATUS status = ::export_key(get_session(), _fpr.c_str(), &_key_data, &_size);
   687 	assert(status != ::PEP_OUT_OF_MEMORY);
   688 	if (status == ::PEP_OUT_OF_MEMORY)
   689 		return E_OUTOFMEMORY;
   690 
   691 	if (status != ::PEP_STATUS_OK)
   692 		return FAIL(L"export_key");
   693 
   694 	_bstr_t b_key_data(utf16_string(_key_data).c_str());
   695 	pEp_free(_key_data);
   696 	*key_data = b_key_data.Detach();
   697 
   698 	return S_OK;
   699 }
   700 
   701 STDMETHODIMP CpEpEngine::recv_key(BSTR pattern)
   702 {
   703 	assert(pattern);
   704 
   705 	if (pattern == NULL)
   706 		return E_INVALIDARG;
   707 
   708 	string _pattern = utf8_string(pattern);
   709 
   710 	PEP_STATUS status = ::recv_key(get_session(), _pattern.c_str());
   711 	assert(status != PEP_OUT_OF_MEMORY);
   712 	if (status == PEP_OUT_OF_MEMORY)
   713 		return E_OUTOFMEMORY;
   714 
   715 	if (status != ::PEP_STATUS_OK)
   716 		return FAIL(L"recv_key");
   717 	else
   718 		return S_OK;
   719 }
   720 
   721 STDMETHODIMP CpEpEngine::find_keys(BSTR pattern, LPSAFEARRAY * key_list)
   722 {
   723 	assert(pattern);
   724 	assert(key_list);
   725 
   726 	if (pattern == NULL || key_list == NULL)
   727 		return E_INVALIDARG;
   728 
   729 	string _pattern = utf8_string(pattern);
   730 	::stringlist_t *_keylist = NULL;
   731 
   732 	PEP_STATUS status = ::find_keys(get_session(), _pattern.c_str(), &_keylist);
   733 	assert(status != PEP_OUT_OF_MEMORY);
   734 	if (status == PEP_OUT_OF_MEMORY)
   735 		return E_OUTOFMEMORY;
   736 
   737 	if (status != ::PEP_STATUS_OK)
   738 		return FAIL(L"find_keys");
   739 
   740 	if (_keylist && _keylist->value) {
   741 		*key_list = string_array(_keylist);
   742 	}
   743 	else {
   744 		::free_stringlist(_keylist);
   745 		return FAIL(L"find_keys: no keys found");
   746 	}
   747 
   748 	::free_stringlist(_keylist);
   749 	return S_OK;
   750 }
   751 
   752 STDMETHODIMP CpEpEngine::send_key(BSTR pattern)
   753 {
   754 	assert(pattern);
   755 
   756 	if (pattern == NULL)
   757 		return E_INVALIDARG;
   758 
   759 	string _pattern = utf8_string(pattern);
   760 
   761 	::PEP_STATUS status = ::send_key(get_session(), _pattern.c_str());
   762 
   763 	if (status != ::PEP_STATUS_OK)
   764 		return FAIL(L"send_key");
   765 	else
   766 		return S_OK;
   767 }
   768 
   769 STDMETHODIMP CpEpEngine::start_keyserver_lookup()
   770 {
   771 	if (identity_queue.load())
   772 		return S_OK;
   773 
   774 	identity_queue.store(new identity_queue_t());
   775 	keymanagement_thread = new thread(::do_keymanagement, retrieve_next_identity, (void *)identity_queue.load());
   776 
   777 	return S_OK;
   778 }
   779 
   780 STDMETHODIMP CpEpEngine::stop_keyserver_lookup()
   781 {
   782 	if (identity_queue.load() == NULL)
   783 		return S_OK;
   784 
   785 	identity_queue_t *_iq = identity_queue.load();
   786 	identity_queue.store(NULL);
   787 
   788 	pEp_identity_cpp shutdown;
   789 	_iq->push_front(shutdown);
   790 
   791 	keymanagement_thread->join();
   792 	delete keymanagement_thread;
   793 	keymanagement_thread = NULL;
   794 
   795 	delete _iq;
   796 
   797 	return S_OK;
   798 }
   799 
   800 STDMETHODIMP CpEpEngine::examine_identity(pEp_identity_s * ident)
   801 {
   802 	assert(ident);
   803 	if (ident == NULL)
   804 		return E_INVALIDARG;
   805 
   806 	if (identity_queue.load() == NULL) {
   807 		try {
   808 			identity_queue.load()->push_back(ident);
   809 		}
   810 		catch (bad_alloc) {
   811 			return E_OUTOFMEMORY;
   812 		}
   813 	}
   814 
   815 	return S_OK;
   816 }
   817 
   818 STDMETHODIMP CpEpEngine::myself(struct pEp_identity_s *ident, struct pEp_identity_s *result)
   819 {
   820 	assert(ident);
   821 	assert(result);
   822 
   823 	if (ident == NULL || result == NULL)
   824 		return E_INVALIDARG;
   825 
   826 	::pEp_identity *_ident = new_identity(ident);
   827 	assert(_ident);
   828 	if (_ident == NULL)
   829 		return E_OUTOFMEMORY;
   830 
   831 	// DEBUG CODE - REMOVE BEFORE RELEASE!
   832 	// sync_handshake_result_s handshakeResult;
   833 	//
   834 	// HRESULT res = Fire_ShowHandshake(ident, result, &handshakeResult);
   835 	// 
   836 	// HRESULT res2 = Fire_TestEvent(15, _bstr_t( "hallo"));
   837 
   838 	PEP_STATUS status = ::myself(get_session(), _ident);
   839 
   840 	if (status == PEP_STATUS_OK) {
   841 		assert(_ident->fpr);
   842 		copy_identity(result, _ident);
   843 		::free_identity(_ident);
   844 		return S_OK;
   845 	}
   846 	else {
   847 		::free_identity(_ident);
   848 		if (status == PEP_OUT_OF_MEMORY)
   849 			return E_OUTOFMEMORY;
   850 		else
   851 			return FAIL(L"myself");
   852 	}
   853 }
   854 
   855 STDMETHODIMP CpEpEngine::update_identity(struct pEp_identity_s *ident, struct pEp_identity_s *result)
   856 {
   857 	assert(ident);
   858 	assert(result);
   859 
   860 	if (ident == NULL || result == NULL)
   861 		return E_INVALIDARG;
   862 
   863 	::pEp_identity *_ident = new_identity(ident);
   864 	assert(_ident);
   865 	if (_ident == NULL)
   866 		return E_OUTOFMEMORY;
   867 
   868 	PEP_STATUS status = ::update_identity(get_session(), _ident);
   869 
   870 	if (status == PEP_STATUS_OK) {
   871 		assert(_ident->fpr);
   872 		copy_identity(result, _ident);
   873 		::free_identity(_ident);
   874 		return S_OK;
   875 	}
   876 	else {
   877 		::free_identity(_ident);
   878 		if (status == PEP_OUT_OF_MEMORY)
   879 			return E_OUTOFMEMORY;
   880 		else
   881 			return FAIL(L"update_identity");
   882 	}
   883 }
   884 
   885 STDMETHODIMP CpEpEngine::key_mistrusted(struct pEp_identity_s *ident)
   886 {
   887 	::pEp_identity *_ident;
   888 
   889 	assert(ident);
   890 
   891 	try {
   892 		_ident = new_identity(ident);
   893 	}
   894 	catch (bad_alloc&) {
   895 		return E_OUTOFMEMORY;
   896 	}
   897 	catch (exception&) {
   898 		return E_FAIL;
   899 	}
   900 
   901 	PEP_STATUS status = ::key_mistrusted(get_session(), _ident);
   902 	free_identity(_ident);
   903 
   904 	if (status == PEP_OUT_OF_MEMORY)
   905 		return E_OUTOFMEMORY;
   906 
   907 	if (status == PEP_KEY_NOT_FOUND)
   908 		return FAIL(L"key not found");
   909 
   910 	if (status != ::PEP_STATUS_OK)
   911 		return FAIL(L"cannot revoke compromized key");
   912 
   913 	return S_OK;
   914 }
   915 
   916 STDMETHODIMP CpEpEngine::key_reset_trust(struct pEp_identity_s *ident)
   917 {
   918 	::pEp_identity *_ident;
   919 
   920 	assert(ident);
   921 
   922 	try {
   923 		_ident = new_identity(ident);
   924 	}
   925 	catch (bad_alloc&) {
   926 		return E_OUTOFMEMORY;
   927 	}
   928 	catch (exception&) {
   929 		return E_FAIL;
   930 	}
   931 
   932 	PEP_STATUS status = ::key_reset_trust(get_session(), _ident);
   933 	free_identity(_ident);
   934 
   935 	if (status == PEP_OUT_OF_MEMORY)
   936 		return E_OUTOFMEMORY;
   937 
   938 	if (status == PEP_KEY_NOT_FOUND)
   939 		return FAIL(L"key not found");
   940 
   941 	if (status != ::PEP_STATUS_OK)
   942 		return FAIL(L"cannot reset trust");
   943 
   944 	return S_OK;
   945 }
   946 
   947 int CpEpEngine::examine_identity(pEp_identity *ident, void *management)
   948 {
   949 	assert(ident);
   950 	assert(management);
   951 	if (!(ident && management))
   952 		return -1;
   953 
   954 	CpEpEngine *me = (CpEpEngine *)management;
   955 
   956 	if (me->identity_queue.load() == NULL)
   957 		return 0;
   958 
   959 	try {
   960 		me->identity_queue.load()->push_back(ident);
   961 	}
   962 	catch (exception&) {
   963 		return -1;
   964 	}
   965 
   966 	return 0;
   967 }
   968 
   969 ::pEp_identity * CpEpEngine::retrieve_next_identity(void *management)
   970 {
   971 	assert(management);
   972 	identity_queue_t *iq = (identity_queue_t *)management;
   973 
   974 	do /* poll queue */ {
   975 		if (iq->size())
   976 			break;
   977 		::Sleep(100);
   978 	} while (true);
   979 
   980 	::pEp_identity *_ident;
   981 	pEp_identity_cpp& ident = iq->front();
   982 
   983 	if (ident.address.size() == 0)
   984 		return NULL;
   985 
   986 	_ident = ident.to_pEp_identity();
   987 	iq->pop_front();
   988 
   989 	return _ident;
   990 }
   991 
   992 PEP_STATUS CpEpEngine::messageToSend(void * obj, message *msg)
   993 {
   994 	assert(msg);
   995 	if (msg == NULL)
   996 		return PEP_ILLEGAL_VALUE;
   997 
   998 	text_message _msg;
   999 	memset(&_msg, 0, sizeof(text_message));
  1000 
  1001 	text_message_from_C(&_msg, msg);
  1002 	CpEpEngine *me = (CpEpEngine *)obj;
  1003 	HRESULT r = me->Fire_MessageToSend(&_msg);
  1004 	assert(r == S_OK);
  1005 	clear_text_message(&_msg);
  1006 	if (r == E_OUTOFMEMORY)
  1007 		return PEP_OUT_OF_MEMORY;
  1008 	if (r != S_OK)
  1009 		return PEP_UNKNOWN_ERROR;
  1010 
  1011 	return PEP_STATUS_OK;
  1012 }
  1013 
  1014 PEP_STATUS CpEpEngine::showHandshake(void * obj, pEp_identity *self, pEp_identity *partner)
  1015 {
  1016 	assert(self && partner);
  1017 	if (!(self && partner))
  1018 		return PEP_ILLEGAL_VALUE;
  1019 
  1020 	pEp_identity_s _self;
  1021 	copy_identity(&_self, self);
  1022 	pEp_identity_s _partner;
  1023 	copy_identity(&_partner, partner);
  1024 	CpEpEngine *me = (CpEpEngine *)obj;
  1025 	sync_handshake_result_s _result;
  1026 	HRESULT r = me->Fire_ShowHandshake(&_self, &_partner, &_result);
  1027 	assert(r == S_OK);
  1028 	clear_identity_s(_self);
  1029 	clear_identity_s(_partner);
  1030 	if (r == E_OUTOFMEMORY)
  1031 		return PEP_OUT_OF_MEMORY;
  1032 	if (r != S_OK)
  1033 		return PEP_UNKNOWN_ERROR;
  1034 
  1035 	PEP_STATUS status = deliverHandshakeResult(me->get_session(), partner, (sync_handshake_result)(int)_result);
  1036 	return status;
  1037 }
  1038 
  1039 STDMETHODIMP CpEpEngine::blacklist_add(BSTR fpr)
  1040 {
  1041 	assert(fpr);
  1042 
  1043 	string _fpr = utf8_string(fpr);
  1044 	PEP_STATUS status = ::blacklist_add(get_session(), _fpr.c_str());
  1045 	assert(status == PEP_STATUS_OK);
  1046 	if (status != PEP_STATUS_OK)
  1047 		return FAIL(L"blacklist_add failed in pEp engine");
  1048 
  1049 	return S_OK;
  1050 }
  1051 
  1052 STDMETHODIMP CpEpEngine::blacklist_delete(BSTR fpr)
  1053 {
  1054 	assert(fpr);
  1055 
  1056 	string _fpr = utf8_string(fpr);
  1057 	PEP_STATUS status = ::blacklist_delete(get_session(), _fpr.c_str());
  1058 	assert(status == PEP_STATUS_OK);
  1059 	if (status != PEP_STATUS_OK)
  1060 		return FAIL(L"blacklist_delete failed in pEp engine");
  1061 
  1062 	return S_OK;
  1063 }
  1064 
  1065 STDMETHODIMP CpEpEngine::blacklist_is_listed(BSTR fpr, VARIANT_BOOL *listed)
  1066 {
  1067 	assert(fpr);
  1068 	assert(listed);
  1069 
  1070 	string _fpr = utf8_string(fpr);
  1071 	bool result;
  1072 	PEP_STATUS status = ::blacklist_is_listed(get_session(), _fpr.c_str(), &result);
  1073 	assert(status == PEP_STATUS_OK);
  1074 	if (status != PEP_STATUS_OK)
  1075 		return FAIL(L"blacklist_is_listed failed in pEp engine");
  1076 
  1077 	*listed = result ? VARIANT_TRUE : VARIANT_FALSE;
  1078 	return S_OK;
  1079 }
  1080 
  1081 STDMETHODIMP CpEpEngine::blacklist_retrieve(SAFEARRAY **blacklist)
  1082 {
  1083 	assert(blacklist);
  1084 
  1085 	::stringlist_t *_blacklist = NULL;
  1086 	PEP_STATUS status = ::blacklist_retrieve(get_session(), &_blacklist);
  1087 	assert(status == PEP_STATUS_OK);
  1088 	if (status != PEP_STATUS_OK)
  1089 		return FAIL(L"blacklist_retrieve failed in pEp engine");
  1090 	assert(_blacklist);
  1091 
  1092 	*blacklist = string_array(_blacklist);
  1093 	return S_OK;
  1094 }
  1095 
  1096 HRESULT CpEpEngine::error(_bstr_t msg)
  1097 {
  1098 	_bstr_t helpFile = L"";
  1099 	_bstr_t source = L"pEp COM Adapter";
  1100 
  1101 	ICreateErrorInfo *cei;
  1102 	if (SUCCEEDED(CreateErrorInfo(&cei))) {
  1103 		cei->SetDescription(msg);
  1104 		cei->SetGUID(__uuidof(IpEpEngine));
  1105 		cei->SetHelpContext(0);
  1106 		cei->SetHelpFile(helpFile);
  1107 		cei->SetSource(source);
  1108 
  1109 		IErrorInfo *errinfo;
  1110 		if (SUCCEEDED(cei->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &errinfo))) {
  1111 			SetErrorInfo(0, errinfo);
  1112 			errinfo->Release();
  1113 		}
  1114 		cei->Release();
  1115 	}
  1116 	return E_FAIL;
  1117 }
  1118 
  1119 STDMETHODIMP CpEpEngine::encrypt_message(text_message * src, text_message * dst, SAFEARRAY * extra, pEpEncryptFlags flags)
  1120 {
  1121 	assert(src);
  1122 	assert(dst);
  1123 
  1124 	::message *_src = text_message_to_C(src);
  1125 	::message *msg_dst;
  1126 	::stringlist_t *_extra = new_stringlist(extra);
  1127 
  1128 	// _PEP_enc_format is intentionally hardcoded to PEP_enc_PEP:
  1129 	// 2016-10-02 14:10 < fdik> schabi: actually, all adapters now must use PEP_enc_PEP
  1130 	PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t) flags;
  1131 	PEP_STATUS status = ::encrypt_message(get_session(), _src, _extra, &msg_dst, PEP_enc_PEP, engineFlags);
  1132 	::free_stringlist(_extra);
  1133 
  1134 	if (status == PEP_STATUS_OK)
  1135 		text_message_from_C(dst, msg_dst);
  1136 	else
  1137 		text_message_from_C(dst, _src);
  1138 
  1139 	::free_message(msg_dst);
  1140 	::free_message(_src);
  1141 
  1142 	if (status == PEP_OUT_OF_MEMORY)
  1143 		return E_OUTOFMEMORY;
  1144 
  1145 	return S_OK;
  1146 }
  1147 
  1148 STDMETHODIMP CpEpEngine::decrypt_message(text_message * src, text_message * dst, SAFEARRAY ** keylist, pEpDecryptFlags *flags, pEp_rating *rating)
  1149 {
  1150 	assert(src);
  1151 	assert(dst);
  1152 	assert(keylist);
  1153 	assert(rating);
  1154 
  1155 	*keylist = NULL;
  1156 	*rating = pEp_rating_undefined;
  1157 
  1158 	::message *_src = text_message_to_C(src);
  1159 	::message *msg_dst = NULL;
  1160 	::stringlist_t *_keylist;
  1161 	::PEP_rating _rating;
  1162 
  1163 	PEP_decrypt_flags_t engineflags = 0;
  1164 	PEP_STATUS status = ::decrypt_message(get_session(), _src, &msg_dst, &_keylist, &_rating, &engineflags);
  1165 
  1166 	*flags = (pEpDecryptFlags)engineflags;
  1167 
  1168 	if (msg_dst)
  1169 		text_message_from_C(dst, msg_dst);
  1170 
  1171 	::free_message(_src);
  1172 	::free_message(msg_dst);
  1173 
  1174 	if (_keylist) {
  1175 		*keylist = string_array(_keylist);
  1176 		free_stringlist(_keylist);
  1177 	}
  1178 
  1179 	*rating = (pEp_rating)_rating;
  1180 
  1181 	return S_OK;
  1182 }
  1183 
  1184 STDMETHODIMP CpEpEngine::outgoing_message_rating(text_message *msg, pEp_rating * pVal)
  1185 {
  1186 	assert(msg);
  1187 	assert(pVal);
  1188 
  1189 	::message *_msg = text_message_to_C(msg);
  1190 
  1191 	PEP_rating _rating;
  1192 	PEP_STATUS status = ::outgoing_message_rating(get_session(), _msg, &_rating);
  1193 	if (status != PEP_STATUS_OK)
  1194 		return FAIL(L"cannot get message rating");
  1195 
  1196 	*pVal = (pEp_rating)_rating;
  1197 	return S_OK;
  1198 }
  1199 
  1200 STDMETHODIMP CpEpEngine::identity_rating(struct pEp_identity_s *ident, pEp_rating * pVal)
  1201 {
  1202 	::pEp_identity *_ident;
  1203 
  1204 	assert(ident);
  1205 	assert(pVal);
  1206 
  1207 	try {
  1208 		_ident = new_identity(ident);
  1209 	}
  1210 	catch (bad_alloc&) {
  1211 		return E_OUTOFMEMORY;
  1212 	}
  1213 	catch (exception&) {
  1214 		return E_FAIL;
  1215 	}
  1216 
  1217 	PEP_rating _rating;
  1218 	PEP_STATUS status = ::identity_rating(get_session(), _ident, &_rating);
  1219 	free_identity(_ident);
  1220 	if (status != PEP_STATUS_OK)
  1221 		return FAIL(L"cannot get message color");
  1222 
  1223 	*pVal = (pEp_rating)_rating;
  1224 	return S_OK;
  1225 }
  1226 
  1227 STDMETHODIMP CpEpEngine::color_from_rating(pEp_rating rating, pEp_color * pVal)
  1228 {
  1229 	assert(pVal);
  1230 
  1231 	PEP_rating engineRating = (PEP_rating)rating;
  1232 	PEP_color _color = ::color_from_rating(engineRating);
  1233 
  1234 	*pVal = (pEp_color)_color;
  1235 
  1236 	return S_OK;
  1237 }
  1238 
  1239 STDMETHODIMP CpEpEngine::trust_personal_key(struct pEp_identity_s *ident, struct pEp_identity_s *result)
  1240 {
  1241 	::pEp_identity *_ident;
  1242 
  1243 	assert(ident);
  1244 	assert(result);
  1245 
  1246 	try {
  1247 		_ident = new_identity(ident);
  1248 	}
  1249 	catch (bad_alloc&) {
  1250 		return E_OUTOFMEMORY;
  1251 	}
  1252 	catch (exception&) {
  1253 		return E_FAIL;
  1254 	}
  1255 
  1256 	if (verbose_mode) {
  1257 		stringstream ss;
  1258 		ss << "trust_personal_key called with ";
  1259 		ss << utf8_string(ident->address);
  1260 		ss << L": ";
  1261 		ss << ident->comm_type;
  1262 		verbose(ss.str());
  1263 	}
  1264 
  1265 	PEP_STATUS status = ::trust_personal_key(get_session(), _ident);
  1266 
  1267 	if (verbose_mode) {
  1268 		stringstream ss;
  1269 		ss << "result ";
  1270 		ss << status;
  1271 		ss << " for ";
  1272 		ss << _ident->address;
  1273 		ss << L": ";
  1274 		ss << _ident->comm_type;
  1275 		verbose(ss.str());
  1276 	}
  1277 
  1278 	if (status == PEP_STATUS_OK)
  1279 		copy_identity(result, _ident);
  1280 
  1281 	free_identity(_ident);
  1282 	if (status == PEP_OUT_OF_MEMORY)
  1283 		return E_OUTOFMEMORY;
  1284 	else if (status != PEP_STATUS_OK)
  1285 		return FAIL(L"failure while executing trust_personal_key()");
  1286 
  1287 	return S_OK;
  1288 }
  1289 
  1290 // keysync api
  1291 
  1292 std::mutex CpEpEngine::keysync_mutex;
  1293 std::condition_variable CpEpEngine::keysync_condition;
  1294 std::thread *CpEpEngine::keysync_thread = NULL;
  1295 std::queue<void*> CpEpEngine::keysync_queue;
  1296 bool CpEpEngine::keysync_thread_running = FALSE;
  1297 bool CpEpEngine::keysync_abort_requested = FALSE;
  1298 PEP_SESSION CpEpEngine::keysync_session;
  1299 
  1300 STDMETHODIMP CpEpEngine::start_keysync()
  1301 {
  1302 	// acquire the lock
  1303 	std::unique_lock<std::mutex> lock(keysync_mutex);
  1304 
  1305 	// Check if we're already running.
  1306 	if (keysync_thread_running)
  1307 		return S_OK;
  1308 
  1309 	// Check if a concurrent abort was requested and is in progress
  1310 	if (keysync_abort_requested)
  1311 		return S_FALSE;
  1312 
  1313 	PEP_STATUS status = ::init(&keysync_session);
  1314 	assert(status = PEP_STATUS_OK);
  1315 
  1316 	// we pass the address of our mutex as management pointer, to do safety checks.
  1317 	keysync_thread = new thread(::do_sync_protocol, keysync_session, &keysync_mutex);
  1318 
  1319 	// flag to signal we're running
  1320 	keysync_thread_running = true;
  1321 
  1322 	return S_OK;
  1323 }
  1324 
  1325 STDMETHODIMP CpEpEngine::stop_keysync()
  1326 {
  1327 	// acquire the lock
  1328 	std::unique_lock<std::mutex> lock(keysync_mutex);
  1329 
  1330 	// check whether we're actually running, or there's a concurrent abort
  1331 	if (keysync_abort_requested || !keysync_thread_running)
  1332 		return S_OK;
  1333 
  1334 	// signal that we're gonna abort
  1335 	keysync_abort_requested = true;
  1336 
  1337 	// Notify the keysync thread
  1338 	keysync_condition.notify_all();
  1339 
  1340 	// Wait for the other thread to finish and clean up
  1341 	while (keysync_thread_running)
  1342 		keysync_condition.wait(lock);
  1343 
  1344 	// wait for the thread to end
  1345 	keysync_thread->join();
  1346 
  1347 	// clean up
  1348 	delete keysync_thread;
  1349 	keysync_thread = NULL;
  1350 	release(keysync_session);
  1351 	keysync_abort_requested = false;
  1352 }
  1353 
  1354 int CpEpEngine::inject_sync_msg(void * msg, void * management)
  1355 {
  1356 	// check argument
  1357 	if (!msg)
  1358 		return E_INVALIDARG;
  1359 
  1360 	// sanity check
  1361 	if (management != &keysync_mutex)
  1362 		return ERROR_INVALID_HANDLE;
  1363 
  1364 	// acquire the lock
  1365 	std::unique_lock<std::mutex> lock(keysync_mutex);
  1366 
  1367 	// check whether we're running:
  1368 	if (keysync_abort_requested || !keysync_thread_running)
  1369 		return E_ASYNC_OPERATION_NOT_STARTED;
  1370 
  1371 	// queue the message
  1372 	keysync_queue.push(msg);
  1373 
  1374 	// notify the receivers
  1375 	keysync_condition.notify_all();
  1376 }
  1377 
  1378 void * CpEpEngine::retreive_next_sync_msg(void * management)
  1379 {
  1380 	// sanity check
  1381 	assert(management == &keysync_mutex);
  1382 
  1383 	// acquire the lock
  1384 	std::unique_lock<std::mutex> lock(keysync_mutex);
  1385 
  1386 	// as long as we're supposed to be active 
  1387 	// (we won't wait for the queue to empty currently...)
  1388 	while (!keysync_abort_requested)
  1389 	{
  1390 		// If the queue is empty, wait for a signal, and try again.
  1391 		if (keysync_queue.empty())
  1392 		{
  1393 			keysync_condition.wait(lock);
  1394 			continue;
  1395 		}
  1396 
  1397 		// Pop the message and return it.
  1398 		void* msg = keysync_queue.front();
  1399 		assert(msg);
  1400 
  1401 		keysync_queue.pop();
  1402 		
  1403 		return msg;
  1404 	}
  1405 
  1406 	// we acknowledge that we're quitting...
  1407 	keysync_thread_running = false;
  1408 
  1409 	// We signal the main thread that we got his signal
  1410 	// so it can gain the mutex again and call join() on us.
  1411 	keysync_condition.notify_all();
  1412 
  1413 	// and tell the pep engine we're done.
  1414 	return NULL;
  1415 }
  1416 
  1417 
  1418 // Event callbacks
  1419 
  1420 STDMETHODIMP CpEpEngine::register_callbacks(IpEpEngineCallbacks* new_callbacks)
  1421 {
  1422 	callbacks cbs = get_callbacks();
  1423 	vector<IpEpEngineCallbacks*>& vec = cbs;
  1424 
  1425 	vec.push_back(new_callbacks);
  1426 	new_callbacks->AddRef();
  1427 
  1428 	return S_OK;
  1429 }
  1430 
  1431 STDMETHODIMP CpEpEngine::unregister_callbacks(IpEpEngineCallbacks* obsolete_callbacks)
  1432 {
  1433 	callbacks cbs = get_callbacks();
  1434 	vector<IpEpEngineCallbacks*>& vec = cbs;
  1435 
  1436 	auto position = std::find(vec.begin(), vec.end(), obsolete_callbacks);
  1437 	if (position != vec.end()) {
  1438 		vec.erase(position);
  1439 		obsolete_callbacks->Release();
  1440 		return S_OK;
  1441 	}
  1442 
  1443 	return S_FALSE;
  1444 }
  1445 
  1446 STDMETHODIMP CpEpEngine::OpenPGP_list_keyinfo(BSTR search_pattern, LPSAFEARRAY* keyinfo_list) {
  1447 	assert(keyinfo_list);
  1448 
  1449 	if (keyinfo_list == NULL)
  1450 		return E_INVALIDARG;
  1451 
  1452 	string _pattern = "";
  1453 	if (search_pattern)
  1454 		_pattern = utf8_string(search_pattern);
  1455 	::stringpair_list_t* _keyinfo_list = NULL;
  1456 
  1457 	PEP_STATUS status = ::OpenPGP_list_keyinfo(get_session(), _pattern.c_str(), &_keyinfo_list);
  1458 	assert(status != PEP_OUT_OF_MEMORY);
  1459 	if (status == PEP_OUT_OF_MEMORY)
  1460 		return E_OUTOFMEMORY;
  1461 
  1462 	if (status != ::PEP_STATUS_OK)
  1463 		return FAIL(L"OpenPGP_list_keyinfo");
  1464 
  1465 	if (_keyinfo_list && _keyinfo_list->value) {
  1466 		::opt_field_array_from_C(_keyinfo_list, keyinfo_list);
  1467 	}
  1468 	else {
  1469 		::free_stringpair_list(_keyinfo_list);
  1470 		return FAIL(L"OpenPGP_list_keyinfo: no keys found");
  1471 	}
  1472 
  1473 	::free_stringpair_list(_keyinfo_list);
  1474 	return S_OK;
  1475 
  1476 }
  1477 
  1478 HRESULT CpEpEngine::Fire_MessageToSend(text_message * msg)
  1479 {
  1480 	callbacks cbs = get_callbacks();
  1481 	vector<IpEpEngineCallbacks*>& vec = cbs;
  1482 
  1483 	assert(msg);
  1484 
  1485 	for (auto it = vec.begin(); it != vec.end(); ++it)
  1486 	{
  1487 		auto res = (*it)->MessageToSend(msg);
  1488 		if (res != S_OK)
  1489 			return res;
  1490 	}
  1491 	return S_OK;
  1492 }
  1493 
  1494 HRESULT CpEpEngine::Fire_ShowHandshake(pEp_identity_s * self, pEp_identity_s * partner, sync_handshake_result_s * result)
  1495 {
  1496 	callbacks cbs = get_callbacks();
  1497 	vector<IpEpEngineCallbacks*>& vec = cbs;
  1498 
  1499 	assert(self);
  1500 	assert(partner);
  1501 	assert(result);
  1502 
  1503 	for (auto it = vec.begin(); it != vec.end(); ++it)
  1504 	{
  1505 		auto res = (*it)->ShowHandshake(self, partner, result);
  1506 		if (res != S_OK)
  1507 			return res;
  1508 	}
  1509 	return S_OK;
  1510 }