CpEpEngine.cpp
author Volker Birk <vb@pep.foundation>
Mon, 22 Oct 2018 17:54:28 +0200
branchsync
changeset 307 eb5012d87405
parent 306 68a6adf189f8
child 308 0017f25f860d
permissions -rw-r--r--
simplify
     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)
   740 {
   741     assert(msg);
   742     if (!msg)
   743         return PEP_ILLEGAL_VALUE;
   744 
   745     bool in_sync = on_sync_thread();
   746 
   747     for (auto p = sync_callbacks.begin(); p != sync_callbacks.end(); ++p) {
   748         IpEpEngineCallbacks *cb;
   749         if (in_sync)
   750             cb = p->cdata;
   751         else
   752             cb = p->pdata->unmarshaled;
   753 
   754         if (cb) {
   755             TextMessage _msg;
   756             memset(&_msg, 0, sizeof(TextMessage));
   757 
   758             text_message_from_C(&_msg, msg);
   759             HRESULT r = cb->MessageToSend(&_msg);
   760             assert(r == S_OK);
   761             clear_text_message(&_msg);
   762             if (r == E_OUTOFMEMORY)
   763                 return PEP_OUT_OF_MEMORY;
   764             if (r != S_OK)
   765                 return PEP_UNKNOWN_ERROR;
   766         }
   767     }
   768 
   769     return PEP_STATUS_OK;
   770 }
   771 
   772 PEP_STATUS CpEpEngine::notifyHandshake(::pEp_identity *self, ::pEp_identity *partner, sync_handshake_signal signal)
   773 {
   774     assert(self && partner);
   775     if (!(self && partner))
   776         return PEP_ILLEGAL_VALUE;
   777 
   778     bool in_sync = on_sync_thread();
   779 
   780     // fire all of them
   781     for (auto p = sync_callbacks.begin(); p != sync_callbacks.end(); ++p) {
   782         IpEpEngineCallbacks *cb;
   783         if (in_sync)
   784             cb = p->cdata;
   785         else
   786             cb = p->pdata->unmarshaled;
   787 
   788         if (cb) {
   789             pEpIdentity _self;
   790             copy_identity(&_self, self);
   791             pEpIdentity _partner;
   792             copy_identity(&_partner, partner);
   793 
   794             SyncHandshakeSignal _signal = (SyncHandshakeSignal)signal;
   795             SyncHandshakeResult result;
   796             HRESULT r = cb->NotifyHandshake(&_self, &_partner, _signal, &result);
   797             assert(r == S_OK);
   798             clear_identity_s(_self);
   799             clear_identity_s(_partner);
   800             if (r == E_OUTOFMEMORY)
   801                 return PEP_OUT_OF_MEMORY;
   802         }
   803     }
   804 
   805     return PEP_STATUS_OK;
   806 }
   807 
   808 STDMETHODIMP CpEpEngine::BlacklistAdd(BSTR fpr)
   809 {
   810     assert(fpr);
   811     if (!fpr)
   812         return E_INVALIDARG;
   813 
   814     string _fpr = utf8_string(fpr);
   815     PEP_STATUS status = ::blacklist_add(session(), _fpr.c_str());
   816     assert(status == PEP_STATUS_OK);
   817     if (status != PEP_STATUS_OK)
   818         return FAIL(L"blacklist_add failed in pEp engine", status);
   819 
   820     return S_OK;
   821 }
   822 
   823 STDMETHODIMP CpEpEngine::BlacklistDelete(BSTR fpr)
   824 {
   825     assert(fpr);
   826     if (!fpr)
   827         return E_INVALIDARG;
   828 
   829     string _fpr = utf8_string(fpr);
   830     PEP_STATUS status = ::blacklist_delete(session(), _fpr.c_str());
   831     assert(status == PEP_STATUS_OK);
   832     if (status != PEP_STATUS_OK)
   833         return FAIL(L"blacklist_delete failed in pEp engine", status);
   834 
   835     return S_OK;
   836 }
   837 
   838 STDMETHODIMP CpEpEngine::BlacklistIsListed(BSTR fpr, VARIANT_BOOL *listed)
   839 {
   840     assert(fpr);
   841     assert(listed);
   842 
   843     if (!(fpr && listed))
   844         return E_INVALIDARG;
   845 
   846     string _fpr = utf8_string(fpr);
   847     bool result;
   848     PEP_STATUS status = ::blacklist_is_listed(session(), _fpr.c_str(), &result);
   849     assert(status == PEP_STATUS_OK);
   850     if (status != PEP_STATUS_OK)
   851         return FAIL(L"blacklist_is_listed failed in pEp engine", status);
   852 
   853     *listed = result ? VARIANT_TRUE : VARIANT_FALSE;
   854     return S_OK;
   855 }
   856 
   857 STDMETHODIMP CpEpEngine::BlacklistRetrieve(SAFEARRAY **blacklist)
   858 {
   859     assert(blacklist);
   860 
   861     if (!blacklist)
   862         return E_INVALIDARG;
   863 
   864     ::stringlist_t *_blacklist = NULL;
   865     PEP_STATUS status = ::blacklist_retrieve(session(), &_blacklist);
   866     assert(status == PEP_STATUS_OK);
   867     if (status != PEP_STATUS_OK)
   868         return FAIL(L"blacklist_retrieve failed in pEp engine", status);
   869     assert(_blacklist);
   870 
   871     *blacklist = string_array(_blacklist);
   872     ::free_stringlist(_blacklist);
   873     return S_OK;
   874 }
   875 
   876 HRESULT CpEpEngine::error(_bstr_t msg)
   877 {
   878     _bstr_t helpFile = L"";
   879     _bstr_t source = L"pEp COM Adapter";
   880 
   881     ICreateErrorInfo *cei;
   882     if (SUCCEEDED(CreateErrorInfo(&cei))) {
   883         cei->SetDescription(msg);
   884         cei->SetGUID(__uuidof(IpEpEngine));
   885         cei->SetHelpContext(0);
   886         cei->SetHelpFile(helpFile);
   887         cei->SetSource(source);
   888 
   889         IErrorInfo *errinfo;
   890         if (SUCCEEDED(cei->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &errinfo))) {
   891             SetErrorInfo(0, errinfo);
   892             errinfo->Release();
   893         }
   894         cei->Release();
   895     }
   896     return E_FAIL;
   897 }
   898 
   899 HRESULT CpEpEngine::error(_bstr_t msg, PEP_STATUS status)
   900 {
   901     std::stringstream stream;
   902     stream << msg;
   903     stream << ": ";
   904     stream << std::hex << status;
   905 
   906     error(stream.str().c_str());
   907 
   908     if (status == ::PEP_OUT_OF_MEMORY)
   909         return E_OUTOFMEMORY;
   910 
   911     return MAKE_HRESULT(1, FACILITY_ITF, (0xFFFF & status));
   912 }
   913 
   914 STDMETHODIMP CpEpEngine::EncryptMessage(TextMessage * src, TextMessage * dst, SAFEARRAY * extra, pEpEncryptFlags flags, pEpEncFormat encFormat)
   915 {
   916     assert(src);
   917     assert(dst);
   918 
   919     if (!(src && dst))
   920         return E_INVALIDARG;
   921 
   922     ::message *_src = text_message_to_C(src);
   923 
   924     _PEP_enc_format _encFormat = (_PEP_enc_format)encFormat;
   925 
   926     // COM-19: Initialize msg_dst to NULL, or we end up calling
   927     // free_message() below with a pointer to random garbage in
   928     // case of an error in encrypt_message().
   929     ::message *msg_dst = NULL;
   930     ::stringlist_t *_extra = new_stringlist(extra); // can cope with NULL
   931 
   932     // _PEP_enc_format used to be intentionally hardcoded to PEP_enc_PEP:
   933     // Since COM-74, this has been changed to an explicit parameter, to allow the engine to attach
   934     // the keys and headers to outgoing, unencrypted messages.
   935     PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t)flags;
   936     PEP_STATUS status = ::encrypt_message(session(), _src, _extra, &msg_dst, _encFormat, engineFlags);
   937     ::free_stringlist(_extra);
   938 
   939     if (status == PEP_STATUS_OK)
   940         text_message_from_C(dst, msg_dst);
   941     else
   942         text_message_from_C(dst, _src);
   943 
   944     ::free_message(msg_dst);
   945     ::free_message(_src);
   946 
   947     if (status == PEP_OUT_OF_MEMORY)
   948         return E_OUTOFMEMORY;
   949 
   950     // COM-41: Enhanced PEP status handling
   951     if ((status != PEP_STATUS_OK) && (status < PEP_UNENCRYPTED || status >= PEP_TRUSTWORD_NOT_FOUND))
   952         return FAIL("Failure to encrypt message", status);
   953 
   954     // Statii like PEP_UNENCRYPTED due to no private key
   955     // should not be a catastrophic failure here. Using S_FALSE
   956     // still allows clients to differentiate with S_OK,
   957     // although this does not work out of the box with
   958     // the standard .NET mapping of COM.
   959     if (status != PEP_STATUS_OK)
   960         return S_FALSE;
   961 
   962     return S_OK;
   963 }
   964 
   965 STDMETHODIMP CpEpEngine::EncryptMessageAndAddPrivKey(TextMessage * src, TextMessage * dst, BSTR to_fpr, pEpEncryptFlags flags, pEpEncFormat encFormat)
   966 {
   967     assert(src);
   968     assert(dst);
   969     assert(to_fpr);
   970 
   971     if (!(src && dst))
   972         return E_INVALIDARG;
   973 
   974     ::message *_src = text_message_to_C(src);
   975 
   976     _PEP_enc_format _encFormat = (_PEP_enc_format)encFormat;
   977 
   978     // COM-19: Initialize msg_dst to NULL, or we end up calling
   979     // free_message() below with a pointer to random garbage in
   980     // case of an error in encrypt_message().
   981     ::message *msg_dst = NULL;
   982 
   983     string _to_fpr = utf8_string(to_fpr);
   984                                                     // _PEP_enc_format used to be intentionally hardcoded to PEP_enc_PEP:
   985                                                     // Since COM-74, this has been changed to an explicit parameter, to allow the engine to attach
   986                                                     // the keys and headers to outgoing, unencrypted messages.
   987     PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t)flags;
   988     PEP_STATUS status = ::encrypt_message_and_add_priv_key(session(), _src, &msg_dst, _to_fpr.c_str(), _encFormat, engineFlags);
   989 
   990     if (status == PEP_STATUS_OK)
   991         text_message_from_C(dst, msg_dst);
   992     else
   993         text_message_from_C(dst, _src);
   994 
   995     ::free_message(msg_dst);
   996     ::free_message(_src);
   997 
   998     if (status == PEP_OUT_OF_MEMORY)
   999         return E_OUTOFMEMORY;
  1000 
  1001     // COM-41: Enhanced PEP status handling
  1002     if ((status != PEP_STATUS_OK) && (status < PEP_UNENCRYPTED || status >= PEP_TRUSTWORD_NOT_FOUND))
  1003         return FAIL("Failure to encrypt message", status);
  1004 
  1005     // Statii like PEP_UNENCRYPTED due to no private key
  1006     // should not be a catastrophic failure here. Using S_FALSE
  1007     // still allows clients to differentiate with S_OK,
  1008     // although this does not work out of the box with
  1009     // the standard .NET mapping of COM.
  1010     if (status != PEP_STATUS_OK)
  1011         return S_FALSE;
  1012 
  1013     return S_OK;
  1014 }
  1015 
  1016 STDMETHODIMP CpEpEngine::EncryptMessageForSelf(pEpIdentity * targetId, TextMessage * src,
  1017     /* [in] */ SAFEARRAY *extra, TextMessage * dst, pEpEncryptFlags flags)
  1018 {
  1019     assert(targetId);
  1020     assert(src);
  1021     assert(dst);
  1022 
  1023     if (!(targetId && src && dst))
  1024         return E_INVALIDARG;
  1025 
  1026     PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t)flags;
  1027 
  1028     ::pEp_identity *_target_id = new_identity(targetId);
  1029 
  1030     ::message *_src = text_message_to_C(src);
  1031 
  1032     ::stringlist_t* _extra = NULL;
  1033     HRESULT result = S_OK;
  1034     ::message *msg_dst = NULL;
  1035     PEP_STATUS status = PEP_STATUS_OK;
  1036 
  1037     try {
  1038         if (extra) {
  1039             _extra = new_stringlist(extra);
  1040         }
  1041 
  1042         // COM-19: Initialize msg_dst to NULL, or we end up calling
  1043         // free_message() below with a pointer to random garbage in
  1044         // case of an error in encrypt_message_for_self().
  1045         status = ::encrypt_message_for_self(session(), _target_id, _src, _extra, &msg_dst, PEP_enc_PEP, engineFlags);
  1046 
  1047         if (status == PEP_STATUS_OK)
  1048             text_message_from_C(dst, msg_dst);
  1049         else
  1050             text_message_from_C(dst, _src);
  1051     } catch (bad_alloc&) {
  1052         result = E_OUTOFMEMORY;
  1053     }
  1054     catch (exception& ex) {
  1055         result = FAIL(ex.what());
  1056     }
  1057 
  1058     ::free_message(msg_dst);
  1059     ::free_message(_src);
  1060     ::free_identity(_target_id);
  1061     ::free_stringlist(_extra);
  1062 
  1063     if (status == PEP_OUT_OF_MEMORY)
  1064         return E_OUTOFMEMORY;
  1065 
  1066     // Different to encrypt_message, this should never fail (we ought to always
  1067     // have a private key for ourself).#
  1068     if (status != PEP_STATUS_OK)
  1069         return FAIL("Failure to encrypt message", status);
  1070 
  1071     return result;
  1072 }
  1073 
  1074 STDMETHODIMP CpEpEngine::DecryptMessage(TextMessage * src, TextMessage * dst, SAFEARRAY ** keylist, pEpDecryptFlags *flags, pEpRating *rating)
  1075 {
  1076     assert(src);
  1077     assert(dst);
  1078     assert(keylist);
  1079     assert(flags);
  1080     assert(rating);
  1081 
  1082     if (!(src && dst && keylist && flags && rating))
  1083         return E_INVALIDARG;
  1084 
  1085     *rating = pEpRatingUndefined;
  1086 
  1087     ::message *_src = text_message_to_C(src);
  1088     ::message *msg_dst = NULL;
  1089     ::stringlist_t *_keylist = new_stringlist(*keylist);
  1090     ::PEP_rating _rating;
  1091 
  1092     PEP_decrypt_flags_t engineflags = (PEP_decrypt_flags_t) *flags;
  1093     PEP_STATUS status = ::decrypt_message(session(), _src, &msg_dst, &_keylist, &_rating, &engineflags);
  1094 
  1095     *flags = (pEpDecryptFlags)engineflags;
  1096 
  1097     if (engineflags & PEP_decrypt_flag_src_modified)
  1098         text_message_from_C(src, _src);
  1099 
  1100     if (msg_dst)
  1101         text_message_from_C(dst, msg_dst);
  1102 
  1103     ::free_message(_src);
  1104     ::free_message(msg_dst);
  1105 
  1106     if (_keylist) {
  1107         *keylist = string_array(_keylist);
  1108         free_stringlist(_keylist);
  1109     }
  1110 
  1111     *rating = (pEpRating)_rating;
  1112 
  1113     return S_OK;
  1114 }
  1115 
  1116 STDMETHODIMP CpEpEngine::ReEvaluateMessageRating(TextMessage * msg, SAFEARRAY * x_KeyList, pEpRating x_EncStatus, pEpRating *rating)
  1117 {
  1118     assert(msg);
  1119     assert(x_EncStatus != PEP_rating_undefined);
  1120     assert(rating);
  1121 
  1122     if (!(msg && x_EncStatus != PEP_rating_undefined && rating))
  1123         return E_INVALIDARG;
  1124 
  1125     *rating = pEpRatingUndefined;
  1126 
  1127     ::message *_msg = text_message_to_C(msg);
  1128     ::stringlist_t *_keylist = new_stringlist(x_KeyList);
  1129     ::PEP_rating _rating = PEP_rating_undefined;
  1130 
  1131     PEP_STATUS status = ::re_evaluate_message_rating(session(), _msg, _keylist, (PEP_rating)x_EncStatus, &_rating);
  1132 
  1133     ::free_stringlist(_keylist);
  1134     ::free_message(_msg);
  1135 
  1136     *rating = (pEpRating)_rating;
  1137 
  1138     return S_OK;
  1139 }
  1140 
  1141 STDMETHODIMP CpEpEngine::OutgoingMessageRating(TextMessage *msg, pEpRating * pVal)
  1142 {
  1143     assert(msg);
  1144     assert(pVal);
  1145 
  1146     if (!(msg  && pVal))
  1147         return E_INVALIDARG;
  1148 
  1149     ::message *_msg = text_message_to_C(msg);
  1150 
  1151     PEP_rating _rating;
  1152     PEP_STATUS status = ::outgoing_message_rating(session(), _msg, &_rating);
  1153     if (status != PEP_STATUS_OK)
  1154         return FAIL(L"cannot get message rating", status);
  1155 
  1156     *pVal = (pEpRating)_rating;
  1157     return S_OK;
  1158 }
  1159 
  1160 STDMETHODIMP CpEpEngine::OutgoingMessageRatingPreview(TextMessage *msg, pEpRating * pVal)
  1161 {
  1162 	assert(msg);
  1163 	assert(pVal);
  1164 
  1165 	if (!(msg  && pVal))
  1166 		return E_INVALIDARG;
  1167 
  1168 	::message *_msg = text_message_to_C(msg);
  1169 
  1170 	PEP_rating _rating;
  1171 	PEP_STATUS status = ::outgoing_message_rating_preview(session(), _msg, &_rating);
  1172 	if (status != PEP_STATUS_OK)
  1173 		return FAIL(L"cannot get message rating", status);
  1174 
  1175 	*pVal = (pEpRating)_rating;
  1176 	return S_OK;
  1177 }
  1178 
  1179 STDMETHODIMP CpEpEngine::IdentityRating(struct pEpIdentity *ident, pEpRating * pVal)
  1180 {
  1181     ::pEp_identity *_ident;
  1182 
  1183     assert(ident);
  1184     assert(pVal);
  1185 
  1186     if (!(ident  && pVal))
  1187         return E_INVALIDARG;
  1188 
  1189     try {
  1190         _ident = new_identity(ident);
  1191     }
  1192     catch (bad_alloc&) {
  1193         return E_OUTOFMEMORY;
  1194     }
  1195     catch (exception& ex) {
  1196         return FAIL(ex.what());;
  1197     }
  1198 
  1199     PEP_rating _rating;
  1200     PEP_STATUS status = ::identity_rating(session(), _ident, &_rating);
  1201     free_identity(_ident);
  1202 
  1203     if (status != PEP_STATUS_OK)
  1204         return FAIL(L"cannot get message color", status);
  1205 
  1206     *pVal = (pEpRating)_rating;
  1207     return S_OK;
  1208 }
  1209 
  1210 STDMETHODIMP CpEpEngine::ColorFromRating(pEpRating rating, pEpColor * pVal)
  1211 {
  1212     assert(pVal);
  1213 
  1214     if (!pVal)
  1215         return E_INVALIDARG;
  1216 
  1217     PEP_rating engineRating = (PEP_rating)rating;
  1218     PEP_color _color = ::color_from_rating(engineRating);
  1219 
  1220     *pVal = (pEpColor)_color;
  1221 
  1222     return S_OK;
  1223 }
  1224 
  1225 STDMETHODIMP CpEpEngine::OwnIdentitiesRetrieve(LPSAFEARRAY* ownIdentities)
  1226 {
  1227     assert(ownIdentities);
  1228     if (!ownIdentities)
  1229         return E_INVALIDARG;
  1230 
  1231     *ownIdentities = nullptr;
  1232 
  1233     ::identity_list *il = nullptr;
  1234     PEP_STATUS status = ::own_identities_retrieve(session(), &il);
  1235     if (status == PEP_OUT_OF_MEMORY) {
  1236         return E_OUTOFMEMORY;
  1237     }
  1238     else if (status != PEP_STATUS_OK)
  1239     {
  1240         return FAIL(_T("OwnIdentitiesRetrieve"), status);
  1241     }
  1242 
  1243     SAFEARRAY * _own_identities = nullptr;
  1244     try {
  1245         _own_identities = array_from_C<pEpIdentity, identity_list>(il);
  1246     }
  1247     catch (exception& ex)
  1248     {
  1249         ::free_identity_list(il);
  1250         try {
  1251             dynamic_cast<bad_alloc&>(ex);
  1252         }
  1253         catch (bad_cast&)
  1254         {
  1255             return FAIL(ex.what());
  1256         }
  1257         return E_OUTOFMEMORY;
  1258     }
  1259     free_identity_list(il);
  1260 
  1261     *ownIdentities = _own_identities;
  1262     return S_OK;
  1263 }
  1264 
  1265 STDMETHODIMP CpEpEngine::TrustPersonalKey(struct pEpIdentity *ident, struct pEpIdentity *result)
  1266 {
  1267     ::pEp_identity *_ident;
  1268 
  1269     assert(ident);
  1270     assert(result);
  1271 
  1272     if (!ident || !result)
  1273         return E_INVALIDARG;
  1274 
  1275     try {
  1276         _ident = new_identity(ident);
  1277     }
  1278     catch (bad_alloc&) {
  1279         return E_OUTOFMEMORY;
  1280     }
  1281     catch (exception& ex) {
  1282         return FAIL(ex.what());;
  1283     }
  1284 
  1285     if (verbose_mode) {
  1286         stringstream ss;
  1287         ss << "TrustPersonalKey called with ";
  1288         ss << utf8_string(ident->Address);
  1289         ss << L": ";
  1290         ss << ident->CommType;
  1291         verbose(ss.str());
  1292     }
  1293 
  1294     PEP_STATUS status = ::trust_personal_key(session(), _ident);
  1295 
  1296     if (verbose_mode) {
  1297         stringstream ss;
  1298         ss << "result ";
  1299         ss << status;
  1300         ss << " for ";
  1301         ss << _ident->address;
  1302         ss << L": ";
  1303         ss << _ident->comm_type;
  1304         verbose(ss.str());
  1305     }
  1306 
  1307     if (status == PEP_STATUS_OK)
  1308         copy_identity(result, _ident);
  1309 
  1310     free_identity(_ident);
  1311     if (status == PEP_OUT_OF_MEMORY)
  1312         return E_OUTOFMEMORY;
  1313     else if (status != PEP_STATUS_OK)
  1314         return FAIL(L"failure while executing TrustPersonalKey()", status);
  1315 
  1316     return S_OK;
  1317 }
  1318 
  1319 // Force an update check now
  1320 STDMETHODIMP CpEpEngine::UpdateNow()
  1321 {
  1322     try
  1323     {
  1324         ::pEp::GateKeeper::update_now();
  1325     }
  1326     catch (bad_alloc&) {
  1327         return E_OUTOFMEMORY;
  1328     }
  1329     catch (exception& ex) {
  1330         return FAIL(ex.what());;
  1331     }
  1332 
  1333     return S_OK;
  1334 }
  1335 
  1336 // Event callbacks
  1337 
  1338 STDMETHODIMP CpEpEngine::RegisterCallbacks(IpEpEngineCallbacks* new_callbacks)
  1339 {
  1340     // check for valid parameter
  1341     if (!new_callbacks)
  1342         return E_INVALIDARG;
  1343 
  1344     // don't allow double registration.
  1345     if (this->client_callbacks)
  1346         return E_ILLEGAL_STATE_CHANGE;
  1347 
  1348     this->client_callbacks = new_callbacks;
  1349     new_callbacks->AddRef();
  1350 
  1351     // provide callbacks to sync
  1352     LPSTREAM marshaled_callbacks;
  1353     auto result = CoMarshalInterThreadInterfaceInStream(IID_IpEpEngineCallbacks, client_callbacks, &marshaled_callbacks);
  1354     assert(SUCCEEDED(result));
  1355     assert(marshaled_callbacks);
  1356     sync_callbacks.insert(new MarshaledCallbacks({ this->client_callbacks, marshaled_callbacks }));
  1357 
  1358     return S_OK;
  1359 }
  1360 
  1361 STDMETHODIMP CpEpEngine::UnregisterCallbacks()
  1362 {
  1363     // don't allow double deregistration.
  1364     // S_FALSE still is no error (as double deregistration is not fatal).
  1365     if (!this->client_callbacks)
  1366         return S_FALSE;
  1367 
  1368     for (auto p = sync_callbacks.begin(); p != sync_callbacks.end(); ++p) {
  1369         if (p->pdata->unmarshaled == this->client_callbacks) {
  1370             delete p->pdata;
  1371             sync_callbacks.erase(p);
  1372             break;
  1373         }
  1374     }
  1375 
  1376     this->client_callbacks->Release();
  1377     this->client_callbacks = NULL;
  1378 
  1379     return S_OK;
  1380 }
  1381 
  1382 STDMETHODIMP CpEpEngine::OpenPGPListKeyinfo(BSTR search_pattern, LPSAFEARRAY* keyinfo_list) {
  1383     assert(keyinfo_list);
  1384 
  1385     if (keyinfo_list == NULL)
  1386         return E_INVALIDARG;
  1387 
  1388     string _pattern = "";
  1389     if (search_pattern)
  1390         _pattern = utf8_string(search_pattern);
  1391     ::stringpair_list_t* _keyinfo_list = NULL;
  1392 
  1393     PEP_STATUS status = ::OpenPGP_list_keyinfo(session(), _pattern.c_str(), &_keyinfo_list);
  1394     assert(status != PEP_OUT_OF_MEMORY);
  1395     if (status == PEP_OUT_OF_MEMORY)
  1396         return E_OUTOFMEMORY;
  1397 
  1398     if (status != PEP_STATUS_OK)
  1399         return FAIL(L"OpenPGP_list_keyinfo", status);
  1400 
  1401     if (_keyinfo_list && _keyinfo_list->value) {
  1402         ::opt_field_array_from_C(_keyinfo_list, keyinfo_list);
  1403     }
  1404     else {
  1405         ::free_stringpair_list(_keyinfo_list);
  1406         return FAIL(L"OpenPGP_list_keyinfo: no keys found");
  1407     }
  1408 
  1409     ::free_stringpair_list(_keyinfo_list);
  1410     return S_OK;
  1411 
  1412 }
  1413 
  1414 STDMETHODIMP CpEpEngine::SetOwnKey(pEpIdentity * ident, BSTR fpr, struct pEpIdentity *result)
  1415 {
  1416 	assert(ident);
  1417 	assert(result);
  1418 	assert(fpr);
  1419 
  1420 	if (!(ident && result))
  1421 		return E_INVALIDARG;
  1422 
  1423 	::pEp_identity *_ident;
  1424 	try {
  1425 		_ident = new_identity(ident);
  1426 	}
  1427 	catch (bad_alloc&) {
  1428 		return E_OUTOFMEMORY;
  1429 	}
  1430 	catch (exception& ex) {
  1431 		return FAIL(ex.what());
  1432 	}
  1433 
  1434 	assert(_ident);
  1435 	if (_ident == NULL)
  1436 		return E_OUTOFMEMORY;
  1437 
  1438 	string _fpr = utf8_string(fpr);
  1439 	PEP_STATUS status = ::set_own_key(session(), _ident, _fpr.c_str());
  1440 
  1441 	if (status == PEP_STATUS_OK) {
  1442 		copy_identity(result, _ident);
  1443 		::free_identity(_ident);
  1444 		return S_OK;
  1445 	}
  1446 	else {
  1447 		::free_identity(_ident);
  1448 		if (status == PEP_OUT_OF_MEMORY)
  1449 			return E_OUTOFMEMORY;
  1450 		else
  1451 			return FAIL(L"SetOwnKey", status);
  1452 	}
  1453 
  1454 	return S_OK;
  1455 }