CpEpEngine.cpp
author Volker Birk <vb@pep.foundation>
Sat, 20 Oct 2018 23:07:43 +0200
branchsync
changeset 298 06734cf5b96a
parent 297 a48f0545e221
child 303 c9b7a1d0d160
permissions -rw-r--r--
adding static variable
     1 // CpEpEngine.cpp : Implementation of CpEpEngine
     2 
     3 #include "stdafx.h"
     4 #include "CpEpEngine.h"
     5 #include <mutex>
     6 #include "GateKeeper.h"
     7 #include "..\libpEpAdapter\Adapter.hh"
     8 
     9 using namespace std;
    10 using namespace pEp::utility;
    11 using namespace pEp::Adapter;
    12 
    13 // CpEpEngine
    14 
    15 pEp::pc_container< CpEpEngine::MarshaledCallbacks, IpEpEngineCallbacks > CpEpEngine::sync_callbacks;
    16 
    17 // the init_mutex protects our initialization and destruction
    18 // against a running keysync thread, and it ensures that the
    19 // keysync thread actually has finished before we're destructed.
    20 
    21 std::mutex CpEpEngine::init_mutex;
    22 atomic< int > CpEpEngine::count = 0;
    23 
    24 STDMETHODIMP CpEpEngine::InterfaceSupportsErrorInfo(REFIID riid)
    25 {
    26     static const IID* const arr[] =
    27     {
    28         &IID_IpEpEngine,
    29     };
    30 
    31     for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
    32     {
    33         if (InlineIsEqualGUID(*arr[i], riid))
    34             return S_OK;
    35     }
    36     return S_FALSE;
    37 }
    38 
    39 // The second argument is optional, and currently supports PEP_STATUS.
    40 #define FAIL(msg, ...) error(msg, __VA_ARGS__)
    41 
    42 STDMETHODIMP CpEpEngine::VerboseLogging(VARIANT_BOOL enable)
    43 {
    44     verbose_mode = enable != VARIANT_FALSE;
    45     return S_OK;
    46 }
    47 
    48 STDMETHODIMP CpEpEngine::PassiveMode(VARIANT_BOOL enable)
    49 {
    50     ::config_passive_mode(session(), enable != VARIANT_FALSE);
    51     return S_OK;
    52 }
    53 
    54 STDMETHODIMP CpEpEngine::UnencryptedSubject(VARIANT_BOOL enable)
    55 {
    56     ::config_unencrypted_subject(session(), enable != VARIANT_FALSE);
    57     return S_OK;
    58 }
    59 
    60 STDMETHODIMP CpEpEngine::ExportKey(BSTR fpr, BSTR * keyData)
    61 {
    62     assert(fpr);
    63     assert(keyData);
    64 
    65     if (!(fpr && keyData))
    66         return E_INVALIDARG;
    67 
    68     string _fpr = utf8_string(fpr);
    69     char *_key_data = NULL;
    70     size_t _size = 0;
    71 
    72     PEP_STATUS status = ::export_key(session(), _fpr.c_str(), &_key_data, &_size);
    73     assert(status != ::PEP_OUT_OF_MEMORY);
    74     if (status == ::PEP_OUT_OF_MEMORY)
    75         return E_OUTOFMEMORY;
    76 
    77     if (status != PEP_STATUS_OK)
    78         return FAIL(L"export_key", status);
    79 
    80     _bstr_t b_key_data(utf16_string(_key_data).c_str());
    81     pEp_free(_key_data);
    82     *keyData = b_key_data.Detach();
    83 
    84     return S_OK;
    85 }
    86 
    87 STDMETHODIMP CpEpEngine::Log(BSTR title, BSTR entity, BSTR description, BSTR comment)
    88 {
    89     string _title;
    90     string _entity;
    91     string _description;
    92     string _comment;
    93     HRESULT result = S_OK;
    94 
    95     assert(title);
    96     if (title)
    97         _title = utf8_string(title);
    98     else
    99         result = E_INVALIDARG;
   100 
   101     assert(entity);
   102     if (entity)
   103         _entity = utf8_string(entity);
   104     else
   105         result = E_INVALIDARG;
   106 
   107     if (description)
   108         _description = utf8_string(description);
   109 
   110     if (comment)
   111         _comment = utf8_string(comment);
   112 
   113     if (result != S_OK)
   114         return result;
   115 
   116     PEP_STATUS _status = ::log_event(session(), _title.c_str(), _entity.c_str(), _description.c_str(), _comment.c_str());
   117     assert(_status == PEP_STATUS_OK);
   118     if (_status != PEP_STATUS_OK)
   119         return FAIL(L"log_event", _status);
   120     else
   121         return S_OK;
   122 }
   123 
   124 STDMETHODIMP CpEpEngine::Trustwords(BSTR fpr, BSTR lang, LONG max_words, BSTR * words)
   125 {
   126     assert(fpr);
   127     assert(max_words >= 0);
   128     assert(words);
   129 
   130     HRESULT result = S_OK;
   131 
   132     string _fpr;
   133     if (fpr)
   134         _fpr = utf8_string(fpr);
   135     else
   136         result = E_INVALIDARG;
   137 
   138     string _lang;
   139     if (lang) {
   140         _lang = utf8_string(lang);
   141         if (_lang.length()) {
   142             if (_lang.length() != 2)
   143                 result = E_INVALIDARG;
   144         }
   145         else
   146             _lang = "en";
   147     }
   148     else
   149         _lang = "en";
   150 
   151     if (max_words < 0)
   152         result = E_INVALIDARG;
   153 
   154     if (words == NULL)
   155         result = E_INVALIDARG;
   156 
   157     if (result != S_OK)
   158         return result;
   159 
   160     char *_words = NULL;
   161     size_t _wsize = 0;
   162 
   163     PEP_STATUS status = ::trustwords(session(), _fpr.c_str(), _lang.c_str(), &_words, &_wsize, max_words);
   164     assert(status != PEP_OUT_OF_MEMORY);
   165     if (status == PEP_OUT_OF_MEMORY)
   166         return E_OUTOFMEMORY;
   167 
   168     if (_words == NULL) {
   169         *words = NULL;
   170         return FAIL(L"Trustwords: _words == NULL", status);
   171     }
   172     else {
   173         *words = utf16_bstr(_words);
   174         pEp_free(_words);
   175         return S_OK;
   176     }
   177 }
   178 
   179 STDMETHODIMP CpEpEngine::GetTrustwords(struct pEpIdentity *id1, struct pEpIdentity *id2, BSTR lang, VARIANT_BOOL full, BSTR *words)
   180 {
   181     assert(id1);
   182     assert(id2);
   183     assert(words);
   184 
   185     if (!(id1 && id2 && words))
   186     {
   187         return E_INVALIDARG;
   188     }
   189 
   190     HRESULT result = S_OK;
   191 
   192     pEp_identity* _id1 = NULL;
   193     pEp_identity* _id2 = NULL;
   194     string _lang;
   195     *words = NULL;
   196 
   197     try {
   198         _id1 = new_identity(id1);
   199         _id2 = new_identity(id2);
   200 
   201         if (lang) {
   202             _lang = utf8_string(lang);
   203             if (_lang.length() == 0) {
   204                 _lang = "en";
   205             }
   206             else if (_lang.length() != 2) {
   207                 result = E_INVALIDARG;
   208             }
   209         }
   210         else {
   211             _lang = "en";
   212         }
   213     }
   214     catch (bad_alloc&) {
   215         result = E_OUTOFMEMORY;
   216     }
   217     catch (exception& ex) {
   218         result = FAIL(ex.what());
   219     }
   220 
   221     char* _words;
   222     size_t _size;
   223     if (result == S_OK) {
   224         auto status = ::get_trustwords(session(), _id1, _id2, _lang.c_str(), &_words, &_size, full != 0 /* convert variant bool to C bool */);
   225 
   226         if (status == PEP_OUT_OF_MEMORY) {
   227             result = E_OUTOFMEMORY;
   228         }
   229         else if (status == PEP_TRUSTWORD_NOT_FOUND) {
   230             result = FAIL(L"GetTrustwords: Trustword not found", status);
   231         }
   232         else if (!words) {
   233             result = FAIL(L"GetTrustwords: _words == NULL", status);
   234         }
   235         else {
   236             *words = utf16_bstr(_words);
   237             pEp_free(_words);
   238         }
   239     }
   240 
   241     free_identity(_id1);
   242     free_identity(_id2);
   243 
   244     return result;
   245 }
   246 
   247 STDMETHODIMP CpEpEngine::GetMessageTrustwords(
   248     /* [in] */ struct TextMessage *msg,
   249     /* [in] */ struct pEpIdentity *receivedBy,
   250     /* [in] */ SAFEARRAY *keylist,
   251     /* [defaultvalue][in] */ BSTR lang,
   252     /* [defaultvalue][in] */ VARIANT_BOOL full,
   253     /* [retval][out] */ BSTR *words) {
   254     assert(msg);
   255     assert(receivedBy);
   256     assert(words);
   257 
   258     if (!(msg && receivedBy && words))
   259     {
   260         return E_INVALIDARG;
   261     }
   262 
   263     HRESULT result = S_OK;
   264 
   265     pEp_identity * _received_by = NULL;
   266     ::message * _msg = NULL;
   267     ::stringlist_t *_keylist = NULL;
   268     string _lang;
   269     *words = NULL;
   270 
   271     try {
   272         _received_by = new_identity(receivedBy);
   273         _msg = text_message_to_C(msg);
   274 
   275         if (keylist) {
   276             _keylist = new_stringlist(keylist);
   277         }
   278 
   279         if (lang) {
   280             _lang = utf8_string(lang);
   281             if (_lang.length() == 0) {
   282                 _lang = "en";
   283             }
   284             else if (_lang.length() != 2) {
   285                 result = E_INVALIDARG;
   286             }
   287         }
   288         else {
   289             _lang = "en";
   290         }
   291     }
   292     catch (bad_alloc&) {
   293         result = E_OUTOFMEMORY;
   294     }
   295     catch (exception& ex) {
   296         result = FAIL(ex.what());
   297     }
   298 
   299     char* _words = NULL;
   300     if (result == S_OK) {
   301         auto status = ::get_message_trustwords(
   302             session(),
   303             _msg,
   304             _keylist,
   305             _received_by,
   306             _lang.c_str(),
   307             &_words,
   308             full != 0 /* convert variant bool to C bool */);
   309 
   310         if (status == PEP_OUT_OF_MEMORY) {
   311             result = E_OUTOFMEMORY;
   312         }
   313         else if (status == PEP_TRUSTWORD_NOT_FOUND) {
   314             result = FAIL(L"GetTrustwords: Trustword not found", status);
   315         }
   316         else if (!words) {
   317             result = FAIL(L"GetTrustwords: _words == NULL", status);
   318         }
   319         else {
   320             *words = utf16_bstr(_words);
   321         }
   322     }
   323 
   324     ::pEp_free(_words);
   325     ::free_message(_msg);
   326     ::free_stringlist(_keylist);
   327     ::free_identity(_received_by);
   328 
   329     return result;
   330 }
   331 
   332 STDMETHODIMP CpEpEngine::GetCrashdumpLog(LONG maxlines, BSTR * log)
   333 {
   334     // COM-18: Currently, long == int on windows, so the check
   335     // for INT_MAX is not strictly necessary. However, the code
   336     // might get copy-pasted to other adapters in the future,
   337     // so safety first...
   338     assert(maxlines >= 0 && maxlines <= INT_MAX);
   339     assert(log);
   340 
   341     if (!(maxlines >= 0 && maxlines <= INT_MAX && log))
   342         return E_INVALIDARG;
   343 
   344     char *_log;
   345     PEP_STATUS status = ::get_crashdump_log(session(), (int)maxlines, &_log);
   346     assert(status == PEP_STATUS_OK);
   347     if (status == PEP_OUT_OF_MEMORY)
   348         return E_OUTOFMEMORY;
   349     if (status != PEP_STATUS_OK)
   350         return FAIL(L"GetCrashdumpLog", status);
   351     if (_log == NULL)
   352         return FAIL(L"GetCrashdumpLog: _log == NULL");
   353 
   354     *log = utf16_bstr(_log);
   355     pEp_free(_log);
   356     return S_OK;
   357 }
   358 
   359 STDMETHODIMP CpEpEngine::GetEngineVersion(BSTR * engine_version)
   360 {
   361     assert(engine_version);
   362 
   363     if (!engine_version)
   364         return E_INVALIDARG;
   365 
   366     const char *_engine_version = ::get_engine_version();
   367 
   368     if (_engine_version == NULL)
   369         return FAIL(L"GetEngineVersion: _engine_version == NULL");
   370 
   371     *engine_version = utf16_bstr(_engine_version);
   372 
   373     return S_OK;
   374 }
   375 
   376 STDMETHODIMP CpEpEngine::GetLanguageList(BSTR * languages)
   377 {
   378     assert(languages);
   379 
   380     if (!languages)
   381         return E_INVALIDARG;
   382 
   383     char *_languages;
   384     PEP_STATUS status = ::get_languagelist(session(), &_languages);
   385     assert(status == PEP_STATUS_OK);
   386     if (status == PEP_OUT_OF_MEMORY)
   387         return E_OUTOFMEMORY;
   388     if (status != PEP_STATUS_OK)
   389         return FAIL(L"GetLanguageList", status);
   390     if (_languages == NULL)
   391         return FAIL(L"GetLanguageList: _languages == NULL");
   392 
   393     *languages = utf16_bstr(_languages);
   394     pEp_free(_languages);
   395     return S_OK;
   396 }
   397 
   398 STDMETHODIMP CpEpEngine::SetIdentityFlags(struct pEpIdentity *identity, pEpIdentityFlags flags)
   399 {
   400     assert(identity);
   401     if (!identity)
   402         return E_INVALIDARG;
   403 
   404     ::pEp_identity *_ident = nullptr;
   405 
   406     try {
   407         _ident = new_identity(identity);
   408         assert(_ident);
   409         if (_ident == NULL)
   410             return E_OUTOFMEMORY;
   411     }
   412     catch (bad_alloc&) {
   413         return E_OUTOFMEMORY;
   414     }
   415     catch (exception& ex) {
   416         return FAIL(ex.what());;
   417     }
   418 
   419     PEP_STATUS status = ::set_identity_flags(session(), _ident, (identity_flags_t)flags);
   420     ::free_identity(_ident);
   421     if (status != PEP_STATUS_OK)
   422         return FAIL(_T("SetIdentityFlags"), status);
   423 
   424     return S_OK;
   425 }
   426 
   427 STDMETHODIMP CpEpEngine::UnsetIdentityFlags(struct pEpIdentity *identity, pEpIdentityFlags flags)
   428 {
   429     assert(identity);
   430     if (!identity)
   431         return E_INVALIDARG;
   432 
   433     ::pEp_identity *_ident = nullptr;
   434 
   435     try {
   436         _ident = new_identity(identity);
   437         assert(_ident);
   438         if (_ident == NULL)
   439             return E_OUTOFMEMORY;
   440     }
   441     catch (bad_alloc&) {
   442         return E_OUTOFMEMORY;
   443     }
   444     catch (exception& ex) {
   445         return FAIL(ex.what());;
   446     }
   447 
   448     PEP_STATUS status = ::unset_identity_flags(session(), _ident, (identity_flags_t)flags);
   449     ::free_identity(_ident);
   450     if (status != PEP_STATUS_OK)
   451         return FAIL(_T("UnsetIdentityFlags"), status);
   452 
   453     return S_OK;
   454 }
   455 
   456 STDMETHODIMP CpEpEngine::StartKeyserverLookup()
   457 {
   458     if (identity_queue.load())
   459         return S_OK;
   460 
   461     identity_queue.store(new identity_queue_t());
   462     keymanagement_thread = new thread(::do_keymanagement, retrieve_next_identity, (void *)identity_queue.load());
   463 
   464     return S_OK;
   465 }
   466 
   467 STDMETHODIMP CpEpEngine::StopKeyserverLookup()
   468 {
   469     if (identity_queue.load() == NULL)
   470         return S_OK;
   471 
   472     identity_queue_t *_iq = identity_queue.load();
   473     identity_queue.store(NULL);
   474 
   475     pEp_identity_cpp shutdown;
   476     _iq->push_front(shutdown);
   477 
   478     keymanagement_thread->join();
   479     delete keymanagement_thread;
   480     keymanagement_thread = NULL;
   481 
   482     delete _iq;
   483 
   484     return S_OK;
   485 }
   486 
   487 STDMETHODIMP CpEpEngine::Myself(struct pEpIdentity *ident, struct pEpIdentity *result)
   488 {
   489     assert(ident);
   490     assert(result);
   491 
   492     if (!(ident && result))
   493         return E_INVALIDARG;
   494 
   495     ::pEp_identity *_ident = 0;
   496 
   497     try {
   498         _ident = new_identity(ident);
   499         assert(_ident);
   500         if (_ident == NULL)
   501             return E_OUTOFMEMORY;
   502     }
   503     catch (bad_alloc&) {
   504         return E_OUTOFMEMORY;
   505     }
   506     catch (exception& ex) {
   507         return FAIL(ex.what());;
   508     }
   509 
   510 
   511     // DEBUG CODE - REMOVE BEFORE RELEASE!
   512     // SyncHandshakeResult handshakeResult;
   513     //
   514     // HRESULT res = Fire_NotifyHandshake(ident, result, signal, &handshakeResult);
   515     // 
   516     // HRESULT res2 = Fire_TestEvent(15, _bstr_t( "hallo"));
   517 
   518     PEP_STATUS status = ::myself(session(), _ident);
   519 
   520     if (status == PEP_STATUS_OK) {
   521         assert(_ident->fpr);
   522         copy_identity(result, _ident);
   523         ::free_identity(_ident);
   524         return S_OK;
   525     }
   526     else {
   527         ::free_identity(_ident);
   528         if (status == PEP_OUT_OF_MEMORY)
   529             return E_OUTOFMEMORY;
   530         else
   531             return FAIL(L"myself", status);
   532     }
   533 }
   534 
   535 STDMETHODIMP CpEpEngine::UpdateIdentity(struct pEpIdentity *ident, struct pEpIdentity *result)
   536 {
   537     assert(ident);
   538     assert(result);
   539 
   540     if (!(ident && result))
   541         return E_INVALIDARG;
   542 
   543     ::pEp_identity *_ident;
   544     try {
   545         _ident = new_identity(ident);
   546     }
   547     catch (bad_alloc&) {
   548         return E_OUTOFMEMORY;
   549     }
   550     catch (exception& ex) {
   551         return FAIL(ex.what());
   552     }
   553 
   554     assert(_ident);
   555     if (_ident == NULL)
   556         return E_OUTOFMEMORY;
   557 
   558     PEP_STATUS status = ::update_identity(session(), _ident);
   559 
   560     if (status == PEP_STATUS_OK) {
   561         copy_identity(result, _ident);
   562         ::free_identity(_ident);
   563         return S_OK;
   564     }
   565     else if (status == PEP_GET_KEY_FAILED || status == PEP_KEY_NOT_FOUND) {
   566         if (_ident->fpr) {
   567             pEp_free(_ident->fpr);
   568             _ident->fpr = NULL;
   569         }
   570         copy_identity(result, _ident);
   571         result->Fpr = NULL;
   572         ::free_identity(_ident);
   573         return S_OK;
   574     }
   575     else {
   576         ::free_identity(_ident);
   577         if (status == PEP_OUT_OF_MEMORY)
   578             return E_OUTOFMEMORY;
   579         else
   580             return FAIL(L"UpdateIdentity", status);
   581     }
   582 }
   583 
   584 STDMETHODIMP CpEpEngine::KeyMistrusted(struct pEpIdentity *ident)
   585 {
   586     ::pEp_identity *_ident;
   587 
   588     assert(ident);
   589     if (!ident)
   590         return E_INVALIDARG;
   591 
   592     try {
   593         _ident = new_identity(ident);
   594     }
   595     catch (bad_alloc&) {
   596         return E_OUTOFMEMORY;
   597     }
   598     catch (exception& ex) {
   599         return FAIL(ex.what());;
   600     }
   601 
   602     PEP_STATUS status = ::key_mistrusted(session(), _ident);
   603     free_identity(_ident);
   604 
   605     if (status == PEP_OUT_OF_MEMORY)
   606         return E_OUTOFMEMORY;
   607 
   608     if (status == PEP_KEY_NOT_FOUND)
   609         return FAIL(L"key not found");
   610 
   611     if (status != PEP_STATUS_OK)
   612         return FAIL(L"cannot revoke compromized key", status);
   613 
   614     return S_OK;
   615 }
   616 
   617 //STDMETHODIMP CpEpEngine::UndoLastMistrust()
   618 //{
   619 //    return FAIL(L"function UndoLastMistrust() not available any more - use KeyResetTrust() instead!", PEP_ILLEGAL_VALUE);
   620 //}
   621 
   622 STDMETHODIMP CpEpEngine::IspEpUser(/* [in] */ struct pEpIdentity *ident, /* [retval][out] */ VARIANT_BOOL *ispEp) 
   623 {
   624     ::pEp_identity *_ident;
   625 
   626     assert(ident);
   627     if (!ident)
   628         return E_INVALIDARG;
   629 
   630     try {
   631         _ident = new_identity(ident);
   632     }
   633     catch (bad_alloc&) {
   634         return E_OUTOFMEMORY;
   635     }
   636     catch (exception& ex) {
   637         return FAIL(ex.what());;
   638     }
   639 
   640     bool is_pep = FALSE;
   641     PEP_STATUS status = ::is_pEp_user(session(), _ident, &is_pep);
   642 
   643     *ispEp = is_pep;
   644 
   645     if (status == PEP_CANNOT_FIND_PERSON)
   646         return FAIL(L"Cannot find identity!", status);
   647 
   648     if (status == PEP_ILLEGAL_VALUE)
   649         return E_INVALIDARG;
   650 
   651     if (status != PEP_STATUS_OK)
   652         return FAIL(L"Engine is_pEp_user returned error", status);
   653 
   654     return S_OK;
   655 }
   656 
   657 STDMETHODIMP CpEpEngine::KeyResetTrust(struct pEpIdentity *ident)
   658 {
   659     ::pEp_identity *_ident;
   660 
   661     assert(ident);
   662 
   663     if (!ident)
   664         return E_INVALIDARG;
   665 
   666     try {
   667         _ident = new_identity(ident);
   668     }
   669     catch (bad_alloc&) {
   670         return E_OUTOFMEMORY;
   671     }
   672     catch (exception& ex) {
   673         return FAIL(ex.what());;
   674     }
   675 
   676     PEP_STATUS status = ::key_reset_trust(session(), _ident);
   677     free_identity(_ident);
   678 
   679     if (status == PEP_OUT_OF_MEMORY)
   680         return E_OUTOFMEMORY;
   681 
   682     if (status == PEP_KEY_NOT_FOUND)
   683         return FAIL(L"key not found");
   684 
   685     if (status != PEP_STATUS_OK)
   686         return FAIL(L"cannot reset trust", status);
   687 
   688     return S_OK;
   689 }
   690 
   691 int CpEpEngine::examine_identity(pEp_identity *ident, void *management)
   692 {
   693     assert(ident);
   694     assert(management);
   695     if (!(ident && management))
   696         return -1;
   697 
   698     CpEpEngine *me = (CpEpEngine *)management;
   699 
   700     if (me->identity_queue.load() == NULL)
   701         return 0;
   702 
   703     try {
   704         me->identity_queue.load()->push_back(ident);
   705     }
   706     catch (exception&) {
   707         return -1;
   708     }
   709 
   710     return 0;
   711 }
   712 
   713 ::pEp_identity * CpEpEngine::retrieve_next_identity(void *management)
   714 {
   715     assert(management);
   716     if (!management)
   717         return NULL;
   718 
   719     identity_queue_t *iq = (identity_queue_t *)management;
   720 
   721     do /* poll queue */ {
   722         if (iq->size())
   723             break;
   724         ::Sleep(100);
   725     } while (true);
   726 
   727     ::pEp_identity *_ident;
   728     pEp_identity_cpp& ident = iq->front();
   729 
   730     if (ident.address.size() == 0)
   731         return NULL;
   732 
   733     _ident = ident.to_pEp_identity();
   734     iq->pop_front();
   735 
   736     return _ident;
   737 }
   738 
   739 PEP_STATUS CpEpEngine::_messageToSend(message *msg, bool in_sync)
   740 {
   741     assert(msg);
   742     if (!msg)
   743         return PEP_ILLEGAL_VALUE;
   744 
   745     for (auto p = sync_callbacks.begin(); p != sync_callbacks.end(); ++p) {
   746         IpEpEngineCallbacks *cb = p->pdata->unmarshaled;
   747 
   748         if (cb) {
   749             TextMessage _msg;
   750             memset(&_msg, 0, sizeof(TextMessage));
   751 
   752             text_message_from_C(&_msg, msg);
   753             HRESULT r = cb->MessageToSend(&_msg);
   754             assert(r == S_OK);
   755             clear_text_message(&_msg);
   756             if (r == E_OUTOFMEMORY)
   757                 return PEP_OUT_OF_MEMORY;
   758             if (r != S_OK)
   759                 return PEP_UNKNOWN_ERROR;
   760         }
   761     }
   762 
   763     return PEP_STATUS_OK;
   764 }
   765 
   766 PEP_STATUS CpEpEngine::messageToSend(message *msg)
   767 {
   768     return _messageToSend(msg);
   769 }
   770 
   771 PEP_STATUS CpEpEngine::messageToSend_sync(message *msg)
   772 {
   773     return _messageToSend(msg, true);
   774 }
   775 
   776 PEP_STATUS CpEpEngine::_notifyHandshake(::pEp_identity *self, ::pEp_identity *partner, sync_handshake_signal signal, bool in_sync)
   777 {
   778     assert(self && partner);
   779     if (!(self && partner))
   780         return PEP_ILLEGAL_VALUE;
   781 
   782     // fire all of them
   783     for (auto p = sync_callbacks.begin(); p != sync_callbacks.end(); ++p) {
   784         IpEpEngineCallbacks *cb = nullptr;
   785         if (in_sync)
   786             cb = p->cdata;
   787         else
   788             cb = p->pdata->unmarshaled;
   789 
   790         if (cb) {
   791             pEpIdentity _self;
   792             copy_identity(&_self, self);
   793             pEpIdentity _partner;
   794             copy_identity(&_partner, partner);
   795 
   796             SyncHandshakeSignal _signal = (SyncHandshakeSignal)signal;
   797             SyncHandshakeResult result;
   798             HRESULT r = cb->NotifyHandshake(&_self, &_partner, _signal, &result);
   799             assert(r == S_OK);
   800             clear_identity_s(_self);
   801             clear_identity_s(_partner);
   802             if (r == E_OUTOFMEMORY)
   803                 return PEP_OUT_OF_MEMORY;
   804         }
   805     }
   806 
   807     return PEP_STATUS_OK;
   808 }
   809 
   810 PEP_STATUS CpEpEngine::notifyHandshake(::pEp_identity *self, ::pEp_identity *partner, sync_handshake_signal signal)
   811 {
   812     return _notifyHandshake(self, partner, signal);
   813 }
   814 
   815 PEP_STATUS CpEpEngine::notifyHandshake_sync(::pEp_identity *self, ::pEp_identity *partner, sync_handshake_signal signal)
   816 {
   817     return _notifyHandshake(self, partner, signal, true);
   818 }
   819 
   820 STDMETHODIMP CpEpEngine::BlacklistAdd(BSTR fpr)
   821 {
   822     assert(fpr);
   823     if (!fpr)
   824         return E_INVALIDARG;
   825 
   826     string _fpr = utf8_string(fpr);
   827     PEP_STATUS status = ::blacklist_add(session(), _fpr.c_str());
   828     assert(status == PEP_STATUS_OK);
   829     if (status != PEP_STATUS_OK)
   830         return FAIL(L"blacklist_add failed in pEp engine", status);
   831 
   832     return S_OK;
   833 }
   834 
   835 STDMETHODIMP CpEpEngine::BlacklistDelete(BSTR fpr)
   836 {
   837     assert(fpr);
   838     if (!fpr)
   839         return E_INVALIDARG;
   840 
   841     string _fpr = utf8_string(fpr);
   842     PEP_STATUS status = ::blacklist_delete(session(), _fpr.c_str());
   843     assert(status == PEP_STATUS_OK);
   844     if (status != PEP_STATUS_OK)
   845         return FAIL(L"blacklist_delete failed in pEp engine", status);
   846 
   847     return S_OK;
   848 }
   849 
   850 STDMETHODIMP CpEpEngine::BlacklistIsListed(BSTR fpr, VARIANT_BOOL *listed)
   851 {
   852     assert(fpr);
   853     assert(listed);
   854 
   855     if (!(fpr && listed))
   856         return E_INVALIDARG;
   857 
   858     string _fpr = utf8_string(fpr);
   859     bool result;
   860     PEP_STATUS status = ::blacklist_is_listed(session(), _fpr.c_str(), &result);
   861     assert(status == PEP_STATUS_OK);
   862     if (status != PEP_STATUS_OK)
   863         return FAIL(L"blacklist_is_listed failed in pEp engine", status);
   864 
   865     *listed = result ? VARIANT_TRUE : VARIANT_FALSE;
   866     return S_OK;
   867 }
   868 
   869 STDMETHODIMP CpEpEngine::BlacklistRetrieve(SAFEARRAY **blacklist)
   870 {
   871     assert(blacklist);
   872 
   873     if (!blacklist)
   874         return E_INVALIDARG;
   875 
   876     ::stringlist_t *_blacklist = NULL;
   877     PEP_STATUS status = ::blacklist_retrieve(session(), &_blacklist);
   878     assert(status == PEP_STATUS_OK);
   879     if (status != PEP_STATUS_OK)
   880         return FAIL(L"blacklist_retrieve failed in pEp engine", status);
   881     assert(_blacklist);
   882 
   883     *blacklist = string_array(_blacklist);
   884     ::free_stringlist(_blacklist);
   885     return S_OK;
   886 }
   887 
   888 HRESULT CpEpEngine::error(_bstr_t msg)
   889 {
   890     _bstr_t helpFile = L"";
   891     _bstr_t source = L"pEp COM Adapter";
   892 
   893     ICreateErrorInfo *cei;
   894     if (SUCCEEDED(CreateErrorInfo(&cei))) {
   895         cei->SetDescription(msg);
   896         cei->SetGUID(__uuidof(IpEpEngine));
   897         cei->SetHelpContext(0);
   898         cei->SetHelpFile(helpFile);
   899         cei->SetSource(source);
   900 
   901         IErrorInfo *errinfo;
   902         if (SUCCEEDED(cei->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &errinfo))) {
   903             SetErrorInfo(0, errinfo);
   904             errinfo->Release();
   905         }
   906         cei->Release();
   907     }
   908     return E_FAIL;
   909 }
   910 
   911 HRESULT CpEpEngine::error(_bstr_t msg, PEP_STATUS status)
   912 {
   913     std::stringstream stream;
   914     stream << msg;
   915     stream << ": ";
   916     stream << std::hex << status;
   917 
   918     error(stream.str().c_str());
   919 
   920     if (status == ::PEP_OUT_OF_MEMORY)
   921         return E_OUTOFMEMORY;
   922 
   923     return MAKE_HRESULT(1, FACILITY_ITF, (0xFFFF & status));
   924 }
   925 
   926 STDMETHODIMP CpEpEngine::EncryptMessage(TextMessage * src, TextMessage * dst, SAFEARRAY * extra, pEpEncryptFlags flags, pEpEncFormat encFormat)
   927 {
   928     assert(src);
   929     assert(dst);
   930 
   931     if (!(src && dst))
   932         return E_INVALIDARG;
   933 
   934     ::message *_src = text_message_to_C(src);
   935 
   936     _PEP_enc_format _encFormat = (_PEP_enc_format)encFormat;
   937 
   938     // COM-19: Initialize msg_dst to NULL, or we end up calling
   939     // free_message() below with a pointer to random garbage in
   940     // case of an error in encrypt_message().
   941     ::message *msg_dst = NULL;
   942     ::stringlist_t *_extra = new_stringlist(extra); // can cope with NULL
   943 
   944     // _PEP_enc_format used to be intentionally hardcoded to PEP_enc_PEP:
   945     // Since COM-74, this has been changed to an explicit parameter, to allow the engine to attach
   946     // the keys and headers to outgoing, unencrypted messages.
   947     PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t)flags;
   948     PEP_STATUS status = ::encrypt_message(session(), _src, _extra, &msg_dst, _encFormat, engineFlags);
   949     ::free_stringlist(_extra);
   950 
   951     if (status == PEP_STATUS_OK)
   952         text_message_from_C(dst, msg_dst);
   953     else
   954         text_message_from_C(dst, _src);
   955 
   956     ::free_message(msg_dst);
   957     ::free_message(_src);
   958 
   959     if (status == PEP_OUT_OF_MEMORY)
   960         return E_OUTOFMEMORY;
   961 
   962     // COM-41: Enhanced PEP status handling
   963     if ((status != PEP_STATUS_OK) && (status < PEP_UNENCRYPTED || status >= PEP_TRUSTWORD_NOT_FOUND))
   964         return FAIL("Failure to encrypt message", status);
   965 
   966     // Statii like PEP_UNENCRYPTED due to no private key
   967     // should not be a catastrophic failure here. Using S_FALSE
   968     // still allows clients to differentiate with S_OK,
   969     // although this does not work out of the box with
   970     // the standard .NET mapping of COM.
   971     if (status != PEP_STATUS_OK)
   972         return S_FALSE;
   973 
   974     return S_OK;
   975 }
   976 
   977 STDMETHODIMP CpEpEngine::EncryptMessageAndAddPrivKey(TextMessage * src, TextMessage * dst, BSTR to_fpr, pEpEncryptFlags flags, pEpEncFormat encFormat)
   978 {
   979     assert(src);
   980     assert(dst);
   981     assert(to_fpr);
   982 
   983     if (!(src && dst))
   984         return E_INVALIDARG;
   985 
   986     ::message *_src = text_message_to_C(src);
   987 
   988     _PEP_enc_format _encFormat = (_PEP_enc_format)encFormat;
   989 
   990     // COM-19: Initialize msg_dst to NULL, or we end up calling
   991     // free_message() below with a pointer to random garbage in
   992     // case of an error in encrypt_message().
   993     ::message *msg_dst = NULL;
   994 
   995     string _to_fpr = utf8_string(to_fpr);
   996                                                     // _PEP_enc_format used to be intentionally hardcoded to PEP_enc_PEP:
   997                                                     // Since COM-74, this has been changed to an explicit parameter, to allow the engine to attach
   998                                                     // the keys and headers to outgoing, unencrypted messages.
   999     PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t)flags;
  1000     PEP_STATUS status = ::encrypt_message_and_add_priv_key(session(), _src, &msg_dst, _to_fpr.c_str(), _encFormat, engineFlags);
  1001 
  1002     if (status == PEP_STATUS_OK)
  1003         text_message_from_C(dst, msg_dst);
  1004     else
  1005         text_message_from_C(dst, _src);
  1006 
  1007     ::free_message(msg_dst);
  1008     ::free_message(_src);
  1009 
  1010     if (status == PEP_OUT_OF_MEMORY)
  1011         return E_OUTOFMEMORY;
  1012 
  1013     // COM-41: Enhanced PEP status handling
  1014     if ((status != PEP_STATUS_OK) && (status < PEP_UNENCRYPTED || status >= PEP_TRUSTWORD_NOT_FOUND))
  1015         return FAIL("Failure to encrypt message", status);
  1016 
  1017     // Statii like PEP_UNENCRYPTED due to no private key
  1018     // should not be a catastrophic failure here. Using S_FALSE
  1019     // still allows clients to differentiate with S_OK,
  1020     // although this does not work out of the box with
  1021     // the standard .NET mapping of COM.
  1022     if (status != PEP_STATUS_OK)
  1023         return S_FALSE;
  1024 
  1025     return S_OK;
  1026 }
  1027 
  1028 STDMETHODIMP CpEpEngine::EncryptMessageForSelf(pEpIdentity * targetId, TextMessage * src,
  1029     /* [in] */ SAFEARRAY *extra, TextMessage * dst, pEpEncryptFlags flags)
  1030 {
  1031     assert(targetId);
  1032     assert(src);
  1033     assert(dst);
  1034 
  1035     if (!(targetId && src && dst))
  1036         return E_INVALIDARG;
  1037 
  1038     PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t)flags;
  1039 
  1040     ::pEp_identity *_target_id = new_identity(targetId);
  1041 
  1042     ::message *_src = text_message_to_C(src);
  1043 
  1044     ::stringlist_t* _extra = NULL;
  1045     HRESULT result = S_OK;
  1046     ::message *msg_dst = NULL;
  1047     PEP_STATUS status = PEP_STATUS_OK;
  1048 
  1049     try {
  1050         if (extra) {
  1051             _extra = new_stringlist(extra);
  1052         }
  1053 
  1054         // COM-19: Initialize msg_dst to NULL, or we end up calling
  1055         // free_message() below with a pointer to random garbage in
  1056         // case of an error in encrypt_message_for_self().
  1057         status = ::encrypt_message_for_self(session(), _target_id, _src, _extra, &msg_dst, PEP_enc_PEP, engineFlags);
  1058 
  1059         if (status == PEP_STATUS_OK)
  1060             text_message_from_C(dst, msg_dst);
  1061         else
  1062             text_message_from_C(dst, _src);
  1063     } catch (bad_alloc&) {
  1064         result = E_OUTOFMEMORY;
  1065     }
  1066     catch (exception& ex) {
  1067         result = FAIL(ex.what());
  1068     }
  1069 
  1070     ::free_message(msg_dst);
  1071     ::free_message(_src);
  1072     ::free_identity(_target_id);
  1073     ::free_stringlist(_extra);
  1074 
  1075     if (status == PEP_OUT_OF_MEMORY)
  1076         return E_OUTOFMEMORY;
  1077 
  1078     // Different to encrypt_message, this should never fail (we ought to always
  1079     // have a private key for ourself).#
  1080     if (status != PEP_STATUS_OK)
  1081         return FAIL("Failure to encrypt message", status);
  1082 
  1083     return result;
  1084 }
  1085 
  1086 STDMETHODIMP CpEpEngine::DecryptMessage(TextMessage * src, TextMessage * dst, SAFEARRAY ** keylist, pEpDecryptFlags *flags, pEpRating *rating)
  1087 {
  1088     assert(src);
  1089     assert(dst);
  1090     assert(keylist);
  1091     assert(flags);
  1092     assert(rating);
  1093 
  1094     if (!(src && dst && keylist && flags && rating))
  1095         return E_INVALIDARG;
  1096 
  1097     *rating = pEpRatingUndefined;
  1098 
  1099     ::message *_src = text_message_to_C(src);
  1100     ::message *msg_dst = NULL;
  1101     ::stringlist_t *_keylist = new_stringlist(*keylist);
  1102     ::PEP_rating _rating;
  1103 
  1104     PEP_decrypt_flags_t engineflags = (PEP_decrypt_flags_t) *flags;
  1105     PEP_STATUS status = ::decrypt_message(session(), _src, &msg_dst, &_keylist, &_rating, &engineflags);
  1106 
  1107     *flags = (pEpDecryptFlags)engineflags;
  1108 
  1109     if (engineflags & PEP_decrypt_flag_src_modified)
  1110         text_message_from_C(src, _src);
  1111 
  1112     if (msg_dst)
  1113         text_message_from_C(dst, msg_dst);
  1114 
  1115     ::free_message(_src);
  1116     ::free_message(msg_dst);
  1117 
  1118     if (_keylist) {
  1119         *keylist = string_array(_keylist);
  1120         free_stringlist(_keylist);
  1121     }
  1122 
  1123     *rating = (pEpRating)_rating;
  1124 
  1125     return S_OK;
  1126 }
  1127 
  1128 STDMETHODIMP CpEpEngine::ReEvaluateMessageRating(TextMessage * msg, SAFEARRAY * x_KeyList, pEpRating x_EncStatus, pEpRating *rating)
  1129 {
  1130     assert(msg);
  1131     assert(x_EncStatus != PEP_rating_undefined);
  1132     assert(rating);
  1133 
  1134     if (!(msg && x_EncStatus != PEP_rating_undefined && rating))
  1135         return E_INVALIDARG;
  1136 
  1137     *rating = pEpRatingUndefined;
  1138 
  1139     ::message *_msg = text_message_to_C(msg);
  1140     ::stringlist_t *_keylist = new_stringlist(x_KeyList);
  1141     ::PEP_rating _rating = PEP_rating_undefined;
  1142 
  1143     PEP_STATUS status = ::re_evaluate_message_rating(session(), _msg, _keylist, (PEP_rating)x_EncStatus, &_rating);
  1144 
  1145     ::free_stringlist(_keylist);
  1146     ::free_message(_msg);
  1147 
  1148     *rating = (pEpRating)_rating;
  1149 
  1150     return S_OK;
  1151 }
  1152 
  1153 STDMETHODIMP CpEpEngine::OutgoingMessageRating(TextMessage *msg, pEpRating * pVal)
  1154 {
  1155     assert(msg);
  1156     assert(pVal);
  1157 
  1158     if (!(msg  && pVal))
  1159         return E_INVALIDARG;
  1160 
  1161     ::message *_msg = text_message_to_C(msg);
  1162 
  1163     PEP_rating _rating;
  1164     PEP_STATUS status = ::outgoing_message_rating(session(), _msg, &_rating);
  1165     if (status != PEP_STATUS_OK)
  1166         return FAIL(L"cannot get message rating", status);
  1167 
  1168     *pVal = (pEpRating)_rating;
  1169     return S_OK;
  1170 }
  1171 
  1172 STDMETHODIMP CpEpEngine::OutgoingMessageRatingPreview(TextMessage *msg, pEpRating * pVal)
  1173 {
  1174 	assert(msg);
  1175 	assert(pVal);
  1176 
  1177 	if (!(msg  && pVal))
  1178 		return E_INVALIDARG;
  1179 
  1180 	::message *_msg = text_message_to_C(msg);
  1181 
  1182 	PEP_rating _rating;
  1183 	PEP_STATUS status = ::outgoing_message_rating_preview(session(), _msg, &_rating);
  1184 	if (status != PEP_STATUS_OK)
  1185 		return FAIL(L"cannot get message rating", status);
  1186 
  1187 	*pVal = (pEpRating)_rating;
  1188 	return S_OK;
  1189 }
  1190 
  1191 STDMETHODIMP CpEpEngine::IdentityRating(struct pEpIdentity *ident, pEpRating * pVal)
  1192 {
  1193     ::pEp_identity *_ident;
  1194 
  1195     assert(ident);
  1196     assert(pVal);
  1197 
  1198     if (!(ident  && pVal))
  1199         return E_INVALIDARG;
  1200 
  1201     try {
  1202         _ident = new_identity(ident);
  1203     }
  1204     catch (bad_alloc&) {
  1205         return E_OUTOFMEMORY;
  1206     }
  1207     catch (exception& ex) {
  1208         return FAIL(ex.what());;
  1209     }
  1210 
  1211     PEP_rating _rating;
  1212     PEP_STATUS status = ::identity_rating(session(), _ident, &_rating);
  1213     free_identity(_ident);
  1214 
  1215     if (status != PEP_STATUS_OK)
  1216         return FAIL(L"cannot get message color", status);
  1217 
  1218     *pVal = (pEpRating)_rating;
  1219     return S_OK;
  1220 }
  1221 
  1222 STDMETHODIMP CpEpEngine::ColorFromRating(pEpRating rating, pEpColor * pVal)
  1223 {
  1224     assert(pVal);
  1225 
  1226     if (!pVal)
  1227         return E_INVALIDARG;
  1228 
  1229     PEP_rating engineRating = (PEP_rating)rating;
  1230     PEP_color _color = ::color_from_rating(engineRating);
  1231 
  1232     *pVal = (pEpColor)_color;
  1233 
  1234     return S_OK;
  1235 }
  1236 
  1237 STDMETHODIMP CpEpEngine::OwnIdentitiesRetrieve(LPSAFEARRAY* ownIdentities)
  1238 {
  1239     assert(ownIdentities);
  1240     if (!ownIdentities)
  1241         return E_INVALIDARG;
  1242 
  1243     *ownIdentities = nullptr;
  1244 
  1245     ::identity_list *il = nullptr;
  1246     PEP_STATUS status = ::own_identities_retrieve(session(), &il);
  1247     if (status == PEP_OUT_OF_MEMORY) {
  1248         return E_OUTOFMEMORY;
  1249     }
  1250     else if (status != PEP_STATUS_OK)
  1251     {
  1252         return FAIL(_T("OwnIdentitiesRetrieve"), status);
  1253     }
  1254 
  1255     SAFEARRAY * _own_identities = nullptr;
  1256     try {
  1257         _own_identities = array_from_C<pEpIdentity, identity_list>(il);
  1258     }
  1259     catch (exception& ex)
  1260     {
  1261         ::free_identity_list(il);
  1262         try {
  1263             dynamic_cast<bad_alloc&>(ex);
  1264         }
  1265         catch (bad_cast&)
  1266         {
  1267             return FAIL(ex.what());
  1268         }
  1269         return E_OUTOFMEMORY;
  1270     }
  1271     free_identity_list(il);
  1272 
  1273     *ownIdentities = _own_identities;
  1274     return S_OK;
  1275 }
  1276 
  1277 STDMETHODIMP CpEpEngine::TrustPersonalKey(struct pEpIdentity *ident, struct pEpIdentity *result)
  1278 {
  1279     ::pEp_identity *_ident;
  1280 
  1281     assert(ident);
  1282     assert(result);
  1283 
  1284     if (!ident || !result)
  1285         return E_INVALIDARG;
  1286 
  1287     try {
  1288         _ident = new_identity(ident);
  1289     }
  1290     catch (bad_alloc&) {
  1291         return E_OUTOFMEMORY;
  1292     }
  1293     catch (exception& ex) {
  1294         return FAIL(ex.what());;
  1295     }
  1296 
  1297     if (verbose_mode) {
  1298         stringstream ss;
  1299         ss << "TrustPersonalKey called with ";
  1300         ss << utf8_string(ident->Address);
  1301         ss << L": ";
  1302         ss << ident->CommType;
  1303         verbose(ss.str());
  1304     }
  1305 
  1306     PEP_STATUS status = ::trust_personal_key(session(), _ident);
  1307 
  1308     if (verbose_mode) {
  1309         stringstream ss;
  1310         ss << "result ";
  1311         ss << status;
  1312         ss << " for ";
  1313         ss << _ident->address;
  1314         ss << L": ";
  1315         ss << _ident->comm_type;
  1316         verbose(ss.str());
  1317     }
  1318 
  1319     if (status == PEP_STATUS_OK)
  1320         copy_identity(result, _ident);
  1321 
  1322     free_identity(_ident);
  1323     if (status == PEP_OUT_OF_MEMORY)
  1324         return E_OUTOFMEMORY;
  1325     else if (status != PEP_STATUS_OK)
  1326         return FAIL(L"failure while executing TrustPersonalKey()", status);
  1327 
  1328     return S_OK;
  1329 }
  1330 
  1331 // Force an update check now
  1332 STDMETHODIMP CpEpEngine::UpdateNow()
  1333 {
  1334     try
  1335     {
  1336         ::pEp::GateKeeper::update_now();
  1337     }
  1338     catch (bad_alloc&) {
  1339         return E_OUTOFMEMORY;
  1340     }
  1341     catch (exception& ex) {
  1342         return FAIL(ex.what());;
  1343     }
  1344 
  1345     return S_OK;
  1346 }
  1347 
  1348 // Event callbacks
  1349 
  1350 STDMETHODIMP CpEpEngine::RegisterCallbacks(IpEpEngineCallbacks* new_callbacks)
  1351 {
  1352     // check for valid parameter
  1353     if (!new_callbacks)
  1354         return E_INVALIDARG;
  1355 
  1356     // don't allow double registration.
  1357     if (this->client_callbacks)
  1358         return E_ILLEGAL_STATE_CHANGE;
  1359 
  1360     this->client_callbacks = new_callbacks;
  1361     new_callbacks->AddRef();
  1362 
  1363     // provide callbacks to sync
  1364     LPSTREAM marshaled_callbacks;
  1365     auto result = CoMarshalInterThreadInterfaceInStream(IID_IpEpEngineCallbacks, client_callbacks, &marshaled_callbacks);
  1366     assert(SUCCEEDED(result));
  1367     assert(marshaled_callbacks);
  1368     sync_callbacks.insert(new MarshaledCallbacks({ this->client_callbacks, marshaled_callbacks }));
  1369 
  1370     return S_OK;
  1371 }
  1372 
  1373 STDMETHODIMP CpEpEngine::UnregisterCallbacks()
  1374 {
  1375     // don't allow double deregistration.
  1376     // S_FALSE still is no error (as double deregistration is not fatal).
  1377     if (!this->client_callbacks)
  1378         return S_FALSE;
  1379 
  1380     for (auto p = sync_callbacks.begin(); p != sync_callbacks.end(); ++p) {
  1381         if (p->pdata->unmarshaled == this->client_callbacks) {
  1382             delete p->pdata;
  1383             sync_callbacks.erase(p);
  1384             break;
  1385         }
  1386     }
  1387 
  1388     this->client_callbacks->Release();
  1389     this->client_callbacks = NULL;
  1390 
  1391     return S_OK;
  1392 }
  1393 
  1394 STDMETHODIMP CpEpEngine::OpenPGPListKeyinfo(BSTR search_pattern, LPSAFEARRAY* keyinfo_list) {
  1395     assert(keyinfo_list);
  1396 
  1397     if (keyinfo_list == NULL)
  1398         return E_INVALIDARG;
  1399 
  1400     string _pattern = "";
  1401     if (search_pattern)
  1402         _pattern = utf8_string(search_pattern);
  1403     ::stringpair_list_t* _keyinfo_list = NULL;
  1404 
  1405     PEP_STATUS status = ::OpenPGP_list_keyinfo(session(), _pattern.c_str(), &_keyinfo_list);
  1406     assert(status != PEP_OUT_OF_MEMORY);
  1407     if (status == PEP_OUT_OF_MEMORY)
  1408         return E_OUTOFMEMORY;
  1409 
  1410     if (status != PEP_STATUS_OK)
  1411         return FAIL(L"OpenPGP_list_keyinfo", status);
  1412 
  1413     if (_keyinfo_list && _keyinfo_list->value) {
  1414         ::opt_field_array_from_C(_keyinfo_list, keyinfo_list);
  1415     }
  1416     else {
  1417         ::free_stringpair_list(_keyinfo_list);
  1418         return FAIL(L"OpenPGP_list_keyinfo: no keys found");
  1419     }
  1420 
  1421     ::free_stringpair_list(_keyinfo_list);
  1422     return S_OK;
  1423 
  1424 }
  1425 
  1426 STDMETHODIMP CpEpEngine::SetOwnKey(pEpIdentity * ident, BSTR fpr, struct pEpIdentity *result)
  1427 {
  1428 	assert(ident);
  1429 	assert(result);
  1430 	assert(fpr);
  1431 
  1432 	if (!(ident && result))
  1433 		return E_INVALIDARG;
  1434 
  1435 	::pEp_identity *_ident;
  1436 	try {
  1437 		_ident = new_identity(ident);
  1438 	}
  1439 	catch (bad_alloc&) {
  1440 		return E_OUTOFMEMORY;
  1441 	}
  1442 	catch (exception& ex) {
  1443 		return FAIL(ex.what());
  1444 	}
  1445 
  1446 	assert(_ident);
  1447 	if (_ident == NULL)
  1448 		return E_OUTOFMEMORY;
  1449 
  1450 	string _fpr = utf8_string(fpr);
  1451 	PEP_STATUS status = ::set_own_key(session(), _ident, _fpr.c_str());
  1452 
  1453 	if (status == PEP_STATUS_OK) {
  1454 		copy_identity(result, _ident);
  1455 		::free_identity(_ident);
  1456 		return S_OK;
  1457 	}
  1458 	else {
  1459 		::free_identity(_ident);
  1460 		if (status == PEP_OUT_OF_MEMORY)
  1461 			return E_OUTOFMEMORY;
  1462 		else
  1463 			return FAIL(L"SetOwnKey", status);
  1464 	}
  1465 
  1466 	return S_OK;
  1467 }