CpEpEngine.cpp
author Markus Schaber <markus@pep-security.net>
Thu, 01 Sep 2016 23:58:16 +0200
branchoutlook_mime_support
changeset 156 8c9f8ce2c3a8
parent 155 0264d4b637a4
child 162 38cdf441c2cb
permissions -rw-r--r--
Hardwire format to PGP/MIME in the com server adapter, as discussed on
dev@.
     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_compromized(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_compromized(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, const 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, const pEp_identity *self, const 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(), (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)
  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_STATUS status = ::encrypt_message(get_session(), _src, _extra, &msg_dst, PEP_enc_PGP_MIME);
  1129     ::free_stringlist(_extra);
  1130 
  1131     if (status == PEP_STATUS_OK)
  1132         text_message_from_C(dst, msg_dst);
  1133     else
  1134         text_message_from_C(dst, _src);
  1135 
  1136     ::free_message(msg_dst);
  1137     ::free_message(_src);
  1138 
  1139     if (status == PEP_OUT_OF_MEMORY)
  1140         return E_OUTOFMEMORY;
  1141 
  1142     return S_OK;
  1143 }
  1144 
  1145 STDMETHODIMP CpEpEngine::decrypt_message(text_message * src, text_message * dst, SAFEARRAY ** keylist, pEp_color *rating)
  1146 {
  1147     assert(src);
  1148     assert(dst);
  1149     assert(keylist);
  1150     assert(rating);
  1151 
  1152     *keylist = NULL;
  1153     *rating = pEp_rating_undefined;
  1154 
  1155     ::message *_src = text_message_to_C(src);
  1156     ::message *msg_dst = NULL;
  1157     ::stringlist_t *_keylist;
  1158     ::PEP_color _rating;
  1159 
  1160     PEP_decrypt_flags_t flags = 0; 
  1161     PEP_STATUS status = ::decrypt_message(get_session(), _src, &msg_dst, &_keylist, &_rating, &flags);
  1162     // TODO : output decrypt flags.
  1163 
  1164     if (msg_dst)
  1165         text_message_from_C(dst, msg_dst);
  1166 
  1167     ::free_message(_src);
  1168     ::free_message(msg_dst);
  1169 
  1170     if (_keylist) {
  1171         *keylist = string_array(_keylist);
  1172         free_stringlist(_keylist);
  1173     }
  1174 
  1175     *rating = (pEp_color) _rating;
  1176 
  1177     return S_OK;
  1178 }
  1179 
  1180 STDMETHODIMP CpEpEngine::outgoing_message_color(text_message *msg, pEp_color * pVal)
  1181 {
  1182     assert(msg);
  1183     assert(pVal);
  1184 
  1185     ::message *_msg = text_message_to_C(msg);
  1186 
  1187     PEP_color _color;
  1188     PEP_STATUS status = ::outgoing_message_color(get_session(), _msg, &_color);
  1189     if (status != PEP_STATUS_OK)
  1190         return FAIL(L"cannot get message color");
  1191 
  1192     *pVal = (pEp_color) _color;
  1193     return S_OK;
  1194 }
  1195 
  1196 STDMETHODIMP CpEpEngine::identity_color(struct pEp_identity_s *ident, pEp_color * pVal)
  1197 {
  1198     ::pEp_identity *_ident;
  1199 
  1200     assert(ident);
  1201     assert(pVal);
  1202 
  1203     try {
  1204         _ident = new_identity(ident);
  1205     }
  1206     catch (bad_alloc&) {
  1207         return E_OUTOFMEMORY;
  1208     }
  1209     catch (exception&) {
  1210         return E_FAIL;
  1211     }
  1212 
  1213     PEP_color _color;
  1214     PEP_STATUS status = ::identity_color(get_session(), _ident, &_color);
  1215     free_identity(_ident);
  1216     if (status != PEP_STATUS_OK)
  1217         return FAIL(L"cannot get message color");
  1218 
  1219     *pVal = (pEp_color) _color;
  1220     return S_OK;
  1221 }
  1222 
  1223 STDMETHODIMP CpEpEngine::trust_personal_key(struct pEp_identity_s *ident, struct pEp_identity_s *result)
  1224 {
  1225     ::pEp_identity *_ident;
  1226 
  1227     assert(ident);
  1228     assert(result);
  1229 
  1230     try {
  1231         _ident = new_identity(ident);
  1232     }
  1233     catch (bad_alloc&) {
  1234         return E_OUTOFMEMORY;
  1235     }
  1236     catch (exception&) {
  1237         return E_FAIL;
  1238     }
  1239 
  1240     if (verbose_mode) {
  1241         stringstream ss;
  1242         ss << "trust_personal_key called with ";
  1243         ss << utf8_string(ident->address);
  1244         ss << L": ";
  1245         ss << ident->comm_type;
  1246         verbose(ss.str());
  1247     }
  1248 
  1249     PEP_STATUS status = ::trust_personal_key(get_session(), _ident);
  1250 
  1251     if (verbose_mode) {
  1252         stringstream ss;
  1253         ss << "result ";
  1254         ss << status;
  1255         ss << " for ";
  1256         ss << _ident->address;
  1257         ss << L": ";
  1258         ss << _ident->comm_type;
  1259         verbose(ss.str());
  1260     }
  1261 
  1262     if (status == PEP_STATUS_OK)
  1263         copy_identity(result, _ident);
  1264 
  1265     free_identity(_ident);
  1266     if (status == PEP_OUT_OF_MEMORY)
  1267         return E_OUTOFMEMORY;
  1268     else if (status != PEP_STATUS_OK)
  1269         return FAIL(L"failure while executing trust_personal_key()");
  1270 
  1271     return S_OK;
  1272 }
  1273 
  1274 
  1275 // Event callbacks
  1276 
  1277 STDMETHODIMP CpEpEngine::register_callbacks(IpEpEngineCallbacks* new_callbacks) 
  1278 {
  1279 	callbacks cbs = get_callbacks();
  1280 	vector<IpEpEngineCallbacks*>& vec = cbs;
  1281 
  1282 	vec.push_back(new_callbacks);
  1283 	new_callbacks->AddRef();
  1284 
  1285 	return S_OK;
  1286 }
  1287 
  1288 STDMETHODIMP CpEpEngine::unregister_callbacks(IpEpEngineCallbacks* obsolete_callbacks) 
  1289 {
  1290 	callbacks cbs = get_callbacks();
  1291 	vector<IpEpEngineCallbacks*>& vec = cbs;
  1292 
  1293 	auto position = std::find(vec.begin(), vec.end(), obsolete_callbacks);
  1294 	if (position != vec.end()) {
  1295 		vec.erase(position);
  1296 		obsolete_callbacks->Release();
  1297 		return S_OK;
  1298 	}
  1299 
  1300 	return S_FALSE;
  1301 }
  1302 
  1303 HRESULT CpEpEngine::Fire_MessageToSend(text_message * msg)
  1304 {
  1305 	callbacks cbs = get_callbacks();
  1306 	vector<IpEpEngineCallbacks*>& vec = cbs;
  1307 
  1308 	assert(msg);
  1309 
  1310 	for (auto it = vec.begin(); it != vec.end(); ++it) 
  1311 	{
  1312 		auto res = (*it)->MessageToSend(msg);
  1313 		if (res != S_OK)
  1314 			return res;
  1315 	}
  1316 	return S_OK;
  1317 }
  1318 
  1319 HRESULT CpEpEngine::Fire_ShowHandshake(pEp_identity_s * self, pEp_identity_s * partner, sync_handshake_result_s * result)
  1320 {
  1321 	callbacks cbs = get_callbacks();
  1322 	vector<IpEpEngineCallbacks*>& vec = cbs;
  1323 
  1324 	assert(self);
  1325 	assert(partner);
  1326 	assert(result);
  1327 
  1328 	for (auto it = vec.begin(); it != vec.end(); ++it)
  1329 	{
  1330 		auto res = (*it)->ShowHandshake(self, partner, result);
  1331 		if (res != S_OK)
  1332 			return res;
  1333 	}
  1334 	return S_OK;
  1335 }