CpEpEngine.cpp
author Thomas
Mon, 10 Aug 2020 11:30:59 +0200
changeset 451 5450988fa873
parent 449 ef89f31611af
permissions -rw-r--r--
Add the ensure_passphrase callback during init
     1 // CpEpEngine.cpp : Implementation of CpEpEngine
     2 
     3 #include "stdafx.h"
     4 #include "CpEpEngine.h"
     5 #include "GateKeeper.h"
     6 #include "LocalJSONAdapter.h"
     7 
     8 using namespace std;
     9 using namespace pEp::utility;
    10 
    11 // CpEpEngine
    12 
    13 CpEpEngine::callback_container CpEpEngine::sync_callbacks;
    14 
    15 // the init_mutex protects our initialization and destruction
    16 // against a running keysync thread, and it ensures that the
    17 // keysync thread actually has finished before we're destructed.
    18 
    19 std::mutex CpEpEngine::init_mutex;
    20 atomic< int > CpEpEngine::count = 0;
    21 
    22 extern LocalJSONAdapter* ljs;
    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::ConfigCipherSuite(pEpCipherSuite cipherSuite)
    61 {
    62     PEP_STATUS status = ::config_cipher_suite(session(), (PEP_CIPHER_SUITE)cipherSuite);
    63 
    64     if (status)
    65         return FAIL(L"config_cipher_suite", status);
    66 
    67     return S_OK;
    68 }
    69 
    70 STDMETHODIMP CpEpEngine::ImportKey(BSTR keyData, LPSAFEARRAY * privateKeys)
    71 {
    72     assert(keyData);
    73 
    74     if (!keyData)
    75         return E_INVALIDARG;
    76 
    77     string key_data = utf8_string(keyData);
    78     size_t size = SysStringLen(keyData);
    79     ::identity_list *private_keys = nullptr;
    80 
    81     PEP_STATUS status = passphrase_cache.api(::import_key, session(), key_data.c_str(), size, &private_keys);
    82     assert(status != ::PEP_OUT_OF_MEMORY);
    83     if (status == ::PEP_OUT_OF_MEMORY)
    84         return E_OUTOFMEMORY;
    85 
    86     if ((status != PEP_STATUS_OK) && (status != PEP_KEY_IMPORTED))
    87         return FAIL(L"import_key", status);
    88 
    89     SAFEARRAY * _privateKeys = nullptr;
    90     try {
    91         _privateKeys = array_from_C<pEpIdentity, identity_list>(private_keys);
    92     }
    93     catch (exception& ex)
    94     {
    95         ::free_identity_list(private_keys);
    96         try {
    97             dynamic_cast<bad_alloc&>(ex);
    98         }
    99         catch (bad_cast&)
   100         {
   101             return FAIL(ex.what());
   102         }
   103         return E_OUTOFMEMORY;
   104     }
   105     free_identity_list(private_keys);
   106 
   107     *privateKeys = _privateKeys;
   108 
   109     return status;
   110 }
   111 
   112 
   113 STDMETHODIMP CpEpEngine::ExportKey(BSTR fpr, BSTR * keyData)
   114 {
   115     assert(fpr);
   116     assert(keyData);
   117 
   118     if (!(fpr && keyData))
   119         return E_INVALIDARG;
   120 
   121     string _fpr = utf8_string(fpr);
   122     char *_key_data = NULL;
   123     size_t _size = 0;
   124 
   125     PEP_STATUS status = passphrase_cache.api(::export_key, session(), _fpr.c_str(), &_key_data, &_size);
   126     assert(status != ::PEP_OUT_OF_MEMORY);
   127     if (status == ::PEP_OUT_OF_MEMORY)
   128         return E_OUTOFMEMORY;
   129 
   130     if (status != PEP_STATUS_OK)
   131         return FAIL(L"export_key", status);
   132 
   133     _bstr_t b_key_data(utf16_string(_key_data).c_str());
   134     pEp_free(_key_data);
   135     *keyData = b_key_data.Detach();
   136 
   137     return S_OK;
   138 }
   139 
   140 STDMETHODIMP CpEpEngine::LeaveDeviceGroup()
   141 {
   142     PEP_STATUS status = passphrase_cache.api(::leave_device_group, session());
   143 
   144     if (status == PEP_OUT_OF_MEMORY)
   145         return E_OUTOFMEMORY;
   146 
   147     if (status != PEP_STATUS_OK)
   148         return FAIL(L"cannot leave device group", status);
   149 
   150     return S_OK;
   151 }
   152 
   153 STDMETHODIMP CpEpEngine::Log(BSTR title, BSTR entity, BSTR description, BSTR comment)
   154 {
   155     string _title;
   156     string _entity;
   157     string _description;
   158     string _comment;
   159     HRESULT result = S_OK;
   160 
   161     assert(title);
   162     if (title)
   163         _title = utf8_string(title);
   164     else
   165         result = E_INVALIDARG;
   166 
   167     assert(entity);
   168     if (entity)
   169         _entity = utf8_string(entity);
   170     else
   171         result = E_INVALIDARG;
   172 
   173     if (description)
   174         _description = utf8_string(description);
   175 
   176     if (comment)
   177         _comment = utf8_string(comment);
   178 
   179     if (result != S_OK)
   180         return result;
   181 
   182     PEP_STATUS _status = ::log_event(session(), _title.c_str(), _entity.c_str(), _description.c_str(), _comment.c_str());
   183     assert(_status == PEP_STATUS_OK);
   184     if (_status != PEP_STATUS_OK)
   185         return FAIL(L"log_event", _status);
   186     else
   187         return S_OK;
   188 }
   189 
   190 STDMETHODIMP CpEpEngine::Trustwords(BSTR fpr, BSTR lang, LONG max_words, BSTR * words)
   191 {
   192     assert(fpr);
   193     assert(max_words >= 0);
   194     assert(words);
   195 
   196     HRESULT result = S_OK;
   197 
   198     string _fpr;
   199     if (fpr)
   200         _fpr = utf8_string(fpr);
   201     else
   202         result = E_INVALIDARG;
   203 
   204     string _lang;
   205     if (lang) {
   206         _lang = utf8_string(lang);
   207         if (_lang.length()) {
   208             if (_lang.length() != 2)
   209                 result = E_INVALIDARG;
   210         }
   211         else
   212             _lang = "en";
   213     }
   214     else
   215         _lang = "en";
   216 
   217     if (max_words < 0)
   218         result = E_INVALIDARG;
   219 
   220     if (words == NULL)
   221         result = E_INVALIDARG;
   222 
   223     if (result != S_OK)
   224         return result;
   225 
   226     char *_words = NULL;
   227     size_t _wsize = 0;
   228 
   229     PEP_STATUS status = ::trustwords(session(), _fpr.c_str(), _lang.c_str(), &_words, &_wsize, max_words);
   230     assert(status != PEP_OUT_OF_MEMORY);
   231     if (status == PEP_OUT_OF_MEMORY)
   232         return E_OUTOFMEMORY;
   233 
   234     if (_words == NULL) {
   235         *words = NULL;
   236         return FAIL(L"Trustwords: _words == NULL", status);
   237     }
   238     else {
   239         *words = utf16_bstr(_words);
   240         pEp_free(_words);
   241         return S_OK;
   242     }
   243 }
   244 
   245 STDMETHODIMP CpEpEngine::GetTrustwordsForFprs(BSTR fpr1, BSTR fpr2, BSTR lang, VARIANT_BOOL full, BSTR *words)
   246 {
   247     assert(fpr1);
   248     assert(fpr2);
   249     assert(words);
   250 
   251     if (!(fpr1 && fpr2 && words))
   252     {
   253         return E_INVALIDARG;
   254     }
   255 
   256     HRESULT result = S_OK;
   257     string _fpr1;
   258     string _fpr2;
   259     string _lang;
   260     *words = NULL;
   261 
   262     try {
   263 
   264         _fpr1 = utf8_string(fpr1);
   265         _fpr2 = utf8_string(fpr2);
   266 
   267         if (lang) {
   268             _lang = utf8_string(lang);
   269             if (_lang.length() == 0) {
   270                 _lang = "en";
   271             }
   272             else if (_lang.length() != 2) {
   273                 result = E_INVALIDARG;
   274             }
   275         }
   276         else {
   277             _lang = "en";
   278         }
   279     }
   280     catch (bad_alloc&) {
   281         result = E_OUTOFMEMORY;
   282     }
   283     catch (exception& ex) {
   284         result = FAIL(ex.what());
   285     }
   286 
   287     char* _words;
   288     size_t _size;
   289     if (result == S_OK) {
   290         auto status = ::get_trustwords_for_fprs(session(), _fpr1.c_str(), _fpr2.c_str(), _lang.c_str(), &_words, &_size, full != 0 /* convert variant bool to C bool */);
   291 
   292         if (status == PEP_OUT_OF_MEMORY) {
   293             result = E_OUTOFMEMORY;
   294         }
   295         else if (status == PEP_TRUSTWORD_NOT_FOUND) {
   296             result = FAIL(L"GetTrustwords: Trustword not found", status);
   297         }
   298         else if (!words) {
   299             result = FAIL(L"GetTrustwords: _words == NULL", status);
   300         }
   301         else {
   302             *words = utf16_bstr(_words);
   303             pEp_free(_words);
   304         }
   305     }
   306 
   307     return result;
   308 }
   309 
   310 STDMETHODIMP CpEpEngine::GetTrustwords(struct pEpIdentity *id1, struct pEpIdentity *id2, BSTR lang, VARIANT_BOOL full, BSTR *words)
   311 {
   312     assert(id1);
   313     assert(id2);
   314     assert(words);
   315 
   316     if (!(id1 && id2 && words))
   317     {
   318         return E_INVALIDARG;
   319     }
   320 
   321     HRESULT result = S_OK;
   322 
   323     pEp_identity* _id1 = NULL;
   324     pEp_identity* _id2 = NULL;
   325     string _lang;
   326     *words = NULL;
   327 
   328     try {
   329         _id1 = new_identity(id1);
   330         _id2 = new_identity(id2);
   331 
   332         if (lang) {
   333             _lang = utf8_string(lang);
   334             if (_lang.length() == 0) {
   335                 _lang = "en";
   336             }
   337             else if (_lang.length() != 2) {
   338                 result = E_INVALIDARG;
   339             }
   340         }
   341         else {
   342             _lang = "en";
   343         }
   344     }
   345     catch (bad_alloc&) {
   346         result = E_OUTOFMEMORY;
   347     }
   348     catch (exception& ex) {
   349         result = FAIL(ex.what());
   350     }
   351 
   352     char* _words;
   353     size_t _size;
   354     if (result == S_OK) {
   355         auto status = ::get_trustwords(session(), _id1, _id2, _lang.c_str(), &_words, &_size, full != 0 /* convert variant bool to C bool */);
   356 
   357         if (status == PEP_OUT_OF_MEMORY) {
   358             result = E_OUTOFMEMORY;
   359         }
   360         else if (status == PEP_TRUSTWORD_NOT_FOUND) {
   361             result = FAIL(L"GetTrustwords: Trustword not found", status);
   362         }
   363         else if (!words) {
   364             result = FAIL(L"GetTrustwords: _words == NULL", status);
   365         }
   366         else {
   367             *words = utf16_bstr(_words);
   368             pEp_free(_words);
   369         }
   370     }
   371 
   372     free_identity(_id1);
   373     free_identity(_id2);
   374 
   375     return result;
   376 }
   377 
   378 STDMETHODIMP CpEpEngine::GetMessageTrustwords(
   379     /* [in] */ struct TextMessage *msg,
   380     /* [in] */ struct pEpIdentity *receivedBy,
   381     /* [in] */ SAFEARRAY *keylist,
   382     /* [defaultvalue][in] */ BSTR lang,
   383     /* [defaultvalue][in] */ VARIANT_BOOL full,
   384     /* [retval][out] */ BSTR *words) {
   385     assert(msg);
   386     assert(receivedBy);
   387     assert(words);
   388 
   389     if (!(msg && receivedBy && words))
   390     {
   391         return E_INVALIDARG;
   392     }
   393 
   394     HRESULT result = S_OK;
   395 
   396     pEp_identity * _received_by = NULL;
   397     ::message * _msg = NULL;
   398     ::stringlist_t *_keylist = NULL;
   399     string _lang;
   400     *words = NULL;
   401 
   402     try {
   403         _received_by = new_identity(receivedBy);
   404         _msg = text_message_to_C(msg);
   405 
   406         if (keylist) {
   407             _keylist = new_stringlist(keylist);
   408         }
   409 
   410         if (lang) {
   411             _lang = utf8_string(lang);
   412             if (_lang.length() == 0) {
   413                 _lang = "en";
   414             }
   415             else if (_lang.length() != 2) {
   416                 result = E_INVALIDARG;
   417             }
   418         }
   419         else {
   420             _lang = "en";
   421         }
   422     }
   423     catch (bad_alloc&) {
   424         result = E_OUTOFMEMORY;
   425     }
   426     catch (exception& ex) {
   427         result = FAIL(ex.what());
   428     }
   429 
   430     char* _words = NULL;
   431     if (result == S_OK) {
   432         auto status = passphrase_cache.api(::get_message_trustwords,
   433             session(),
   434             _msg,
   435             _keylist,
   436             _received_by,
   437             _lang.c_str(),
   438             &_words,
   439             full != 0 /* convert variant bool to C bool */);
   440 
   441         if (status == PEP_OUT_OF_MEMORY) {
   442             result = E_OUTOFMEMORY;
   443         }
   444         else if (status == PEP_TRUSTWORD_NOT_FOUND) {
   445             result = FAIL(L"GetTrustwords: Trustword not found", status);
   446         }
   447         else if (!words) {
   448             result = FAIL(L"GetTrustwords: _words == NULL", status);
   449         }
   450         else {
   451             *words = utf16_bstr(_words);
   452         }
   453     }
   454 
   455     ::pEp_free(_words);
   456     ::free_message(_msg);
   457     ::free_stringlist(_keylist);
   458     ::free_identity(_received_by);
   459 
   460     return result;
   461 }
   462 
   463 STDMETHODIMP CpEpEngine::GetCrashdumpLog(LONG maxlines, BSTR * log)
   464 {
   465     // COM-18: Currently, long == int on windows, so the check
   466     // for INT_MAX is not strictly necessary. However, the code
   467     // might get copy-pasted to other adapters in the future,
   468     // so safety first...
   469     assert(maxlines >= 0 && maxlines <= INT_MAX);
   470     assert(log);
   471 
   472     if (!(maxlines >= 0 && maxlines <= INT_MAX && log))
   473         return E_INVALIDARG;
   474 
   475     char *_log;
   476     PEP_STATUS status = ::get_crashdump_log(session(), (int)maxlines, &_log);
   477     assert(status == PEP_STATUS_OK);
   478     if (status == PEP_OUT_OF_MEMORY)
   479         return E_OUTOFMEMORY;
   480     if (status != PEP_STATUS_OK)
   481         return FAIL(L"GetCrashdumpLog", status);
   482     if (_log == NULL)
   483         return FAIL(L"GetCrashdumpLog: _log == NULL");
   484 
   485     *log = utf16_bstr(_log);
   486     pEp_free(_log);
   487     return S_OK;
   488 }
   489 
   490 STDMETHODIMP CpEpEngine::GetEngineVersion(BSTR * engine_version)
   491 {
   492     assert(engine_version);
   493 
   494     if (!engine_version)
   495         return E_INVALIDARG;
   496 
   497     const char *_engine_version = ::get_engine_version();
   498 
   499     if (_engine_version == NULL)
   500         return FAIL(L"GetEngineVersion: _engine_version == NULL");
   501 
   502     *engine_version = utf16_bstr(_engine_version);
   503 
   504     return S_OK;
   505 }
   506 
   507 STDMETHODIMP CpEpEngine::GetLanguageList(BSTR * languages)
   508 {
   509     assert(languages);
   510 
   511     if (!languages)
   512         return E_INVALIDARG;
   513 
   514     char *_languages;
   515     PEP_STATUS status = ::get_languagelist(session(), &_languages);
   516     assert(status == PEP_STATUS_OK);
   517     if (status == PEP_OUT_OF_MEMORY)
   518         return E_OUTOFMEMORY;
   519     if (status != PEP_STATUS_OK)
   520         return FAIL(L"GetLanguageList", status);
   521     if (_languages == NULL)
   522         return FAIL(L"GetLanguageList: _languages == NULL");
   523 
   524     *languages = utf16_bstr(_languages);
   525     pEp_free(_languages);
   526     return S_OK;
   527 }
   528 
   529 STDMETHODIMP CpEpEngine::SetIdentityFlags(struct pEpIdentity *identity, pEpIdentityFlags flags)
   530 {
   531     assert(identity);
   532     if (!identity)
   533         return E_INVALIDARG;
   534 
   535     ::pEp_identity *_ident = nullptr;
   536 
   537     try {
   538         _ident = new_identity(identity);
   539         assert(_ident);
   540         if (_ident == NULL)
   541             return E_OUTOFMEMORY;
   542     }
   543     catch (bad_alloc&) {
   544         return E_OUTOFMEMORY;
   545     }
   546     catch (exception& ex) {
   547         return FAIL(ex.what());;
   548     }
   549 
   550     PEP_STATUS status = passphrase_cache.api(::set_identity_flags, session(), _ident, (identity_flags_t)flags);
   551     ::free_identity(_ident);
   552     if (status != PEP_STATUS_OK)
   553         return FAIL(_T("SetIdentityFlags"), status);
   554 
   555     return S_OK;
   556 }
   557 
   558 STDMETHODIMP CpEpEngine::UnsetIdentityFlags(struct pEpIdentity *identity, pEpIdentityFlags flags)
   559 {
   560     assert(identity);
   561     if (!identity)
   562         return E_INVALIDARG;
   563 
   564     ::pEp_identity *_ident = nullptr;
   565 
   566     try {
   567         _ident = new_identity(identity);
   568         assert(_ident);
   569         if (_ident == NULL)
   570             return E_OUTOFMEMORY;
   571     }
   572     catch (bad_alloc&) {
   573         return E_OUTOFMEMORY;
   574     }
   575     catch (exception& ex) {
   576         return FAIL(ex.what());;
   577     }
   578 
   579     PEP_STATUS status = passphrase_cache.api(::unset_identity_flags, session(), _ident, (identity_flags_t)flags);
   580     ::free_identity(_ident);
   581     if (status != PEP_STATUS_OK)
   582         return FAIL(_T("UnsetIdentityFlags"), status);
   583 
   584     return S_OK;
   585 }
   586 
   587 STDMETHODIMP CpEpEngine::StartKeyserverLookup()
   588 {
   589     if (identity_queue.load())
   590         return S_OK;
   591 
   592     identity_queue.store(new identity_queue_t());
   593     keymanagement_thread = new thread(::do_keymanagement, retrieve_next_identity, (void *)identity_queue.load());
   594 
   595     return S_OK;
   596 }
   597 
   598 STDMETHODIMP CpEpEngine::StopKeyserverLookup()
   599 {
   600     if (identity_queue.load() == NULL)
   601         return S_OK;
   602 
   603     identity_queue_t *_iq = identity_queue.load();
   604     identity_queue.store(NULL);
   605 
   606     pEp_identity_cpp shutdown;
   607     _iq->push_front(shutdown);
   608 
   609     keymanagement_thread->join();
   610     delete keymanagement_thread;
   611     keymanagement_thread = NULL;
   612 
   613     delete _iq;
   614 
   615     return S_OK;
   616 }
   617 
   618 STDMETHODIMP CpEpEngine::MIMEDecodeMessage(BSTR mimeText, TextMessage *msg)
   619 {
   620     assert(mimeText);
   621 
   622     if (!mimeText)
   623         return E_INVALIDARG;
   624 
   625     string _mimeText = utf8_string(mimeText);
   626     size_t size = SysStringLen(mimeText);
   627     ::message *_msg = NULL;
   628 
   629     PEP_STATUS status = mime_decode_message(_mimeText.c_str(), size, &_msg, nullptr);
   630     assert(status != ::PEP_OUT_OF_MEMORY);
   631     if (status == ::PEP_OUT_OF_MEMORY)
   632         return E_OUTOFMEMORY;
   633 
   634     if (status != PEP_STATUS_OK)
   635         return FAIL(L"mime_decode_message", status);
   636 
   637     if (_msg)
   638         text_message_from_C(msg, _msg);
   639 
   640     free_message(_msg);
   641 
   642     return status;
   643 }
   644 
   645 
   646 STDMETHODIMP CpEpEngine::MIMEEncodeMessage(TextMessage *msg, VARIANT_BOOL omitFields, BSTR *mimeText)
   647 {
   648     assert(msg);
   649 
   650     if (!msg)
   651         return E_INVALIDARG;
   652 
   653     ::message *_msg = NULL;
   654     try {
   655         _msg = text_message_to_C(msg);
   656     }
   657     catch (bad_alloc&) {
   658         return E_OUTOFMEMORY;
   659     }
   660     catch (exception& ex) {
   661         return FAIL(ex.what());
   662     }
   663 
   664     char *_mimeText;
   665 
   666     PEP_STATUS status = mime_encode_message(_msg, omitFields != 0, &_mimeText, false);
   667     free_message(_msg);
   668 
   669     assert(status != ::PEP_OUT_OF_MEMORY);
   670     if (status == ::PEP_OUT_OF_MEMORY)
   671         return E_OUTOFMEMORY;
   672 
   673     if (status != PEP_STATUS_OK)
   674         return FAIL(L"mime_encode_message", status);
   675 
   676     *mimeText = utf16_bstr(_mimeText);
   677     pEp_free(_mimeText);
   678 
   679     return status;
   680 }
   681 
   682 STDMETHODIMP CpEpEngine::Myself(struct pEpIdentity *ident, struct pEpIdentity *result)
   683 {
   684     assert(ident);
   685     assert(result);
   686 
   687     if (!(ident && result))
   688         return E_INVALIDARG;
   689 
   690     ::pEp_identity *_ident = 0;
   691 
   692     try {
   693         _ident = new_identity(ident);
   694         assert(_ident);
   695         if (_ident == NULL)
   696             return E_OUTOFMEMORY;
   697     }
   698     catch (bad_alloc&) {
   699         return E_OUTOFMEMORY;
   700     }
   701     catch (exception& ex) {
   702         return FAIL(ex.what());;
   703     }
   704 
   705     PEP_STATUS status;
   706     if (passphrase_for_new_keys != "")
   707         status = ::config_passphrase_for_new_keys(session(), true, passphrase_for_new_keys.c_str());
   708     else
   709         status = ::config_passphrase_for_new_keys(session(), false, passphrase_for_new_keys.c_str());
   710     status = passphrase_cache.api(::myself, session(), _ident);
   711 
   712     if (status == PEP_STATUS_OK) {
   713         assert(_ident->fpr);
   714         copy_identity(result, _ident);
   715         ::free_identity(_ident);
   716         return S_OK;
   717     }
   718     else {
   719         ::free_identity(_ident);
   720         if (status == PEP_OUT_OF_MEMORY)
   721             return E_OUTOFMEMORY;
   722         else
   723             return FAIL(L"myself", status);
   724     }
   725 }
   726 
   727 STDMETHODIMP CpEpEngine::UpdateIdentity(struct pEpIdentity *ident, struct pEpIdentity *result)
   728 {
   729     assert(ident);
   730     assert(result);
   731 
   732     if (!(ident && result))
   733         return E_INVALIDARG;
   734 
   735     ::pEp_identity *_ident;
   736     try {
   737         _ident = new_identity(ident);
   738     }
   739     catch (bad_alloc&) {
   740         return E_OUTOFMEMORY;
   741     }
   742     catch (exception& ex) {
   743         return FAIL(ex.what());
   744     }
   745 
   746     assert(_ident);
   747     if (_ident == NULL)
   748         return E_OUTOFMEMORY;
   749 
   750     PEP_STATUS status = passphrase_cache.api(::update_identity, session(), _ident);
   751 
   752     if (status == PEP_STATUS_OK) {
   753         copy_identity(result, _ident);
   754         ::free_identity(_ident);
   755         return S_OK;
   756     }
   757     else if (status == PEP_GET_KEY_FAILED || status == PEP_KEY_NOT_FOUND) {
   758         if (_ident->fpr) {
   759             pEp_free(_ident->fpr);
   760             _ident->fpr = NULL;
   761         }
   762         copy_identity(result, _ident);
   763         result->Fpr = NULL;
   764         ::free_identity(_ident);
   765         return S_OK;
   766     }
   767     else {
   768         ::free_identity(_ident);
   769         if (status == PEP_OUT_OF_MEMORY)
   770             return E_OUTOFMEMORY;
   771         else
   772             return FAIL(L"UpdateIdentity", status);
   773     }
   774 }
   775 
   776 STDMETHODIMP CpEpEngine::KeyMistrusted(struct pEpIdentity *ident)
   777 {
   778     ::pEp_identity *_ident;
   779 
   780     assert(ident);
   781     if (!ident)
   782         return E_INVALIDARG;
   783 
   784     try {
   785         _ident = new_identity(ident);
   786     }
   787     catch (bad_alloc&) {
   788         return E_OUTOFMEMORY;
   789     }
   790     catch (exception& ex) {
   791         return FAIL(ex.what());;
   792     }
   793 
   794     PEP_STATUS status = passphrase_cache.api(::key_mistrusted, session(), _ident);
   795     free_identity(_ident);
   796 
   797     if (status == PEP_OUT_OF_MEMORY)
   798         return E_OUTOFMEMORY;
   799 
   800     if (status == PEP_KEY_NOT_FOUND)
   801         return FAIL(L"key not found");
   802 
   803     if (status != PEP_STATUS_OK)
   804         return FAIL(L"cannot revoke compromised key", status);
   805 
   806     return S_OK;
   807 }
   808 
   809 STDMETHODIMP CpEpEngine::IspEpUser(/* [in] */ struct pEpIdentity *ident, /* [retval][out] */ VARIANT_BOOL *ispEp)
   810 {
   811     ::pEp_identity *_ident;
   812 
   813     assert(ident);
   814     if (!ident)
   815         return E_INVALIDARG;
   816 
   817     try {
   818         _ident = new_identity(ident);
   819     }
   820     catch (bad_alloc&) {
   821         return E_OUTOFMEMORY;
   822     }
   823     catch (exception& ex) {
   824         return FAIL(ex.what());;
   825     }
   826 
   827     bool is_pep = FALSE;
   828     PEP_STATUS status = passphrase_cache.api(::is_pEp_user, session(), _ident, &is_pep);
   829 
   830     *ispEp = is_pep;
   831 
   832     if (status == PEP_CANNOT_FIND_PERSON)
   833         return FAIL(L"Cannot find identity!", status);
   834 
   835     if (status == PEP_ILLEGAL_VALUE)
   836         return E_INVALIDARG;
   837 
   838     if (status != PEP_STATUS_OK)
   839         return FAIL(L"Engine is_pEp_user returned error", status);
   840 
   841     return S_OK;
   842 }
   843 
   844 STDMETHODIMP CpEpEngine::KeyResetIdentity(struct pEpIdentity ident, BSTR fpr)
   845 {
   846     ::pEp_identity *_ident;
   847 
   848     try {
   849         _ident = new_identity(&ident);
   850     }
   851     catch (bad_alloc&) {
   852         return E_OUTOFMEMORY;
   853     }
   854     catch (exception& ex) {
   855         return FAIL(ex.what());;
   856     }
   857 
   858     string _fpr = utf8_string(fpr);
   859 
   860     PEP_STATUS status = passphrase_cache.api(::key_reset_identity, session(), _ident, _fpr.c_str());
   861 
   862     free_identity(_ident);
   863 
   864     if (status == PEP_OUT_OF_MEMORY)
   865         return E_OUTOFMEMORY;
   866 
   867     if (status == PEP_KEY_NOT_FOUND)
   868         return FAIL(L"key not found");
   869 
   870     if (status != PEP_STATUS_OK)
   871         return FAIL(L"cannot reset identity", status);
   872 
   873     return S_OK;
   874 }
   875 
   876 STDMETHODIMP CpEpEngine::KeyResetUser(BSTR userId, BSTR fpr)
   877 {
   878     string _userId = utf8_string(userId);
   879     string _fpr = utf8_string(fpr);
   880 
   881     PEP_STATUS status = passphrase_cache.api(::key_reset_user, session(), _userId.c_str(), _fpr.c_str());
   882 
   883     if (status == PEP_OUT_OF_MEMORY)
   884         return E_OUTOFMEMORY;
   885 
   886     if (status == PEP_KEY_NOT_FOUND)
   887         return FAIL(L"key not found");
   888 
   889     if (status != PEP_STATUS_OK)
   890         return FAIL(L"cannot reset user", status);
   891 
   892     return S_OK;
   893 }
   894 
   895 STDMETHODIMP CpEpEngine::KeyResetAllOwnKeys()
   896 {
   897     PEP_STATUS status = passphrase_cache.api(::key_reset_all_own_keys, session());
   898 
   899     if (status == PEP_OUT_OF_MEMORY)
   900         return E_OUTOFMEMORY;
   901 
   902     if (status != PEP_STATUS_OK)
   903         return FAIL(L"cannot reset all own keys", status);
   904 
   905     return S_OK;
   906 }
   907 
   908 STDMETHODIMP CpEpEngine::KeyResetTrust(struct pEpIdentity *ident)
   909 {
   910     ::pEp_identity *_ident;
   911 
   912     assert(ident);
   913 
   914     if (!ident)
   915         return E_INVALIDARG;
   916 
   917     try {
   918         _ident = new_identity(ident);
   919     }
   920     catch (bad_alloc&) {
   921         return E_OUTOFMEMORY;
   922     }
   923     catch (exception& ex) {
   924         return FAIL(ex.what());;
   925     }
   926 
   927     PEP_STATUS status = passphrase_cache.api(::key_reset_trust, session(), _ident);
   928     free_identity(_ident);
   929 
   930     if (status == PEP_OUT_OF_MEMORY)
   931         return E_OUTOFMEMORY;
   932 
   933     if (status == PEP_KEY_NOT_FOUND)
   934         return FAIL(L"key not found");
   935 
   936     if (status != PEP_STATUS_OK)
   937         return FAIL(L"cannot reset trust", status);
   938 
   939     return S_OK;
   940 }
   941 
   942 int CpEpEngine::examine_identity(pEp_identity *ident, void *management)
   943 {
   944     assert(ident);
   945     assert(management);
   946     if (!(ident && management))
   947         return -1;
   948 
   949     CpEpEngine *me = (CpEpEngine *)management;
   950 
   951     if (me->identity_queue.load() == NULL)
   952         return 0;
   953 
   954     try {
   955         me->identity_queue.load()->push_back(ident);
   956     }
   957     catch (exception&) {
   958         return -1;
   959     }
   960 
   961     return 0;
   962 }
   963 
   964 ::pEp_identity * CpEpEngine::retrieve_next_identity(void *management)
   965 {
   966     assert(management);
   967     if (!management)
   968         return NULL;
   969 
   970     identity_queue_t *iq = (identity_queue_t *)management;
   971 
   972     do /* poll queue */ {
   973         if (iq->size())
   974             break;
   975         ::Sleep(100);
   976     } while (true);
   977 
   978     ::pEp_identity *_ident;
   979     pEp_identity_cpp& ident = iq->front();
   980 
   981     if (ident.address.size() == 0)
   982         return NULL;
   983 
   984     _ident = ident.to_pEp_identity();
   985     iq->pop_front();
   986 
   987     return _ident;
   988 }
   989 
   990 static IpEpEngineCallbacks * _unmarshaled_consumer(CpEpEngine::callback_container::Container::iterator p)
   991 {
   992     if (!p->cdata && p->pdata && p->pdata->marshaled) {
   993         HRESULT r = CoGetInterfaceAndReleaseStream(p->pdata->marshaled, IID_IpEpEngineCallbacks, (LPVOID*)&p->cdata);
   994         if (!SUCCEEDED(r))
   995             throw runtime_error("_unmarshaled_consumer(): CoGetInterfaceAndReleaseStream() failed");
   996         p->pdata->marshaled = nullptr;
   997     }
   998     else if (p->cdata && !p->pdata) {
   999         p->cdata->Release();
  1000         p->cdata = nullptr;
  1001     }
  1002 
  1003     return p->cdata;
  1004 }
  1005 
  1006 PEP_STATUS CpEpEngine::messageToSend(message *msg)
  1007 {
  1008     bool in_sync = on_sync_thread();
  1009 
  1010     for (auto p = sync_callbacks.begin(); p != sync_callbacks.end(); ++p) {
  1011         IpEpEngineCallbacks *cb = in_sync ? _unmarshaled_consumer(p) : p->pdata->unmarshaled;
  1012 
  1013         if (cb) {
  1014             TextMessage _msg;
  1015             memset(&_msg, 0, sizeof(TextMessage));
  1016 
  1017             text_message_from_C(&_msg, msg);
  1018             HRESULT r = cb->MessageToSend(&_msg);
  1019             assert(r == S_OK);
  1020             clear_text_message(&_msg);
  1021             if (r == E_OUTOFMEMORY)
  1022                 return PEP_OUT_OF_MEMORY;
  1023             if (r != S_OK)
  1024                 return PEP_UNKNOWN_ERROR;
  1025         }
  1026     }
  1027 
  1028     if (ljs)
  1029         ljs->messageToSend(msg);
  1030 
  1031     sync_callbacks.compact();
  1032 
  1033     return PEP_STATUS_OK;
  1034 }
  1035 
  1036 PEP_STATUS CpEpEngine::notifyHandshake(::pEp_identity *self, ::pEp_identity *partner, ::sync_handshake_signal signal)
  1037 {
  1038     assert(signal);
  1039     if (!signal)
  1040         return PEP_ILLEGAL_VALUE;
  1041 
  1042     bool in_sync = on_sync_thread();
  1043 
  1044     // fire all of them
  1045     for (auto p = sync_callbacks.begin(); p != sync_callbacks.end(); ++p) {
  1046         IpEpEngineCallbacks *cb = in_sync ? _unmarshaled_consumer(p) : p->pdata->unmarshaled;
  1047 
  1048         if (cb) {
  1049             pEpIdentity _self;
  1050             copy_identity(&_self, self);
  1051             pEpIdentity _partner;
  1052             copy_identity(&_partner, partner);
  1053 
  1054             SyncHandshakeSignal _signal = (SyncHandshakeSignal)signal;
  1055             HRESULT r = cb->NotifyHandshake(&_self, &_partner, _signal);
  1056             assert(r == S_OK);
  1057             clear_identity_s(_self);
  1058             clear_identity_s(_partner);
  1059             if (r == E_OUTOFMEMORY)
  1060                 return PEP_OUT_OF_MEMORY;
  1061         }
  1062     }
  1063 
  1064     sync_callbacks.compact();
  1065 
  1066     return PEP_STATUS_OK;
  1067 }
  1068 
  1069 STDMETHODIMP CpEpEngine::BlacklistAdd(BSTR fpr)
  1070 {
  1071     assert(fpr);
  1072     if (!fpr)
  1073         return E_INVALIDARG;
  1074 
  1075     string _fpr = utf8_string(fpr);
  1076     PEP_STATUS status = passphrase_cache.api(::blacklist_add, session(), _fpr.c_str());
  1077     assert(status == PEP_STATUS_OK);
  1078     if (status != PEP_STATUS_OK)
  1079         return FAIL(L"blacklist_add failed in pEp engine", status);
  1080 
  1081     return S_OK;
  1082 }
  1083 
  1084 STDMETHODIMP CpEpEngine::BlacklistDelete(BSTR fpr)
  1085 {
  1086     assert(fpr);
  1087     if (!fpr)
  1088         return E_INVALIDARG;
  1089 
  1090     string _fpr = utf8_string(fpr);
  1091     PEP_STATUS status = passphrase_cache.api(::blacklist_delete, session(), _fpr.c_str());
  1092     assert(status == PEP_STATUS_OK);
  1093     if (status != PEP_STATUS_OK)
  1094         return FAIL(L"blacklist_delete failed in pEp engine", status);
  1095 
  1096     return S_OK;
  1097 }
  1098 
  1099 STDMETHODIMP CpEpEngine::BlacklistIsListed(BSTR fpr, VARIANT_BOOL *listed)
  1100 {
  1101     assert(fpr);
  1102     assert(listed);
  1103 
  1104     if (!(fpr && listed))
  1105         return E_INVALIDARG;
  1106 
  1107     string _fpr = utf8_string(fpr);
  1108     bool result;
  1109     PEP_STATUS status = passphrase_cache.api(::blacklist_is_listed, session(), _fpr.c_str(), &result);
  1110     assert(status == PEP_STATUS_OK);
  1111     if (status != PEP_STATUS_OK)
  1112         return FAIL(L"blacklist_is_listed failed in pEp engine", status);
  1113 
  1114     *listed = result ? VARIANT_TRUE : VARIANT_FALSE;
  1115     return S_OK;
  1116 }
  1117 
  1118 STDMETHODIMP CpEpEngine::BlacklistRetrieve(SAFEARRAY **blacklist)
  1119 {
  1120     assert(blacklist);
  1121 
  1122     if (!blacklist)
  1123         return E_INVALIDARG;
  1124 
  1125     ::stringlist_t *_blacklist = NULL;
  1126     PEP_STATUS status = passphrase_cache.api(::blacklist_retrieve, session(), &_blacklist);
  1127     assert(status == PEP_STATUS_OK);
  1128     if (status != PEP_STATUS_OK)
  1129         return FAIL(L"blacklist_retrieve failed in pEp engine", status);
  1130     assert(_blacklist);
  1131 
  1132     *blacklist = string_array(_blacklist);
  1133     ::free_stringlist(_blacklist);
  1134     return S_OK;
  1135 }
  1136 
  1137 HRESULT CpEpEngine::error(_bstr_t msg)
  1138 {
  1139     _bstr_t helpFile = L"";
  1140     _bstr_t source = L"pEp COM Adapter";
  1141 
  1142     ICreateErrorInfo *cei;
  1143     if (SUCCEEDED(CreateErrorInfo(&cei))) {
  1144         cei->SetDescription(msg);
  1145         cei->SetGUID(__uuidof(IpEpEngine));
  1146         cei->SetHelpContext(0);
  1147         cei->SetHelpFile(helpFile);
  1148         cei->SetSource(source);
  1149 
  1150         IErrorInfo *errinfo;
  1151         if (SUCCEEDED(cei->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &errinfo))) {
  1152             SetErrorInfo(0, errinfo);
  1153             errinfo->Release();
  1154         }
  1155         cei->Release();
  1156     }
  1157     return E_FAIL;
  1158 }
  1159 
  1160 HRESULT CpEpEngine::error(_bstr_t msg, PEP_STATUS status)
  1161 {
  1162     std::stringstream stream;
  1163     stream << msg;
  1164     stream << ": ";
  1165     stream << pEp_status_to_string(status);
  1166     stream << std::hex << " (" << status << ")";
  1167 
  1168     error(stream.str().c_str());
  1169 
  1170     if (status == ::PEP_OUT_OF_MEMORY)
  1171         return E_OUTOFMEMORY;
  1172 
  1173     return MAKE_HRESULT(1, FACILITY_ITF, (0xFFFF & status));
  1174 }
  1175 
  1176 STDMETHODIMP CpEpEngine::EncryptMessage(TextMessage * src, TextMessage * dst, SAFEARRAY * extra, pEpEncryptFlags flags, pEpEncFormat encFormat)
  1177 {
  1178     assert(src);
  1179     assert(dst);
  1180 
  1181     if (!(src && dst))
  1182         return E_INVALIDARG;
  1183 
  1184     ::message *_src = NULL;
  1185     try {
  1186         _src = text_message_to_C(src);
  1187     }
  1188     catch (bad_alloc&) {
  1189         return E_OUTOFMEMORY;
  1190     }
  1191     catch (exception& ex) {
  1192         return FAIL(ex.what());
  1193     }
  1194 
  1195     _PEP_enc_format _encFormat = (_PEP_enc_format)encFormat;
  1196 
  1197     // COM-19: Initialize msg_dst to NULL, or we end up calling
  1198     // free_message() below with a pointer to random garbage in
  1199     // case of an error in encrypt_message().
  1200     ::message *msg_dst = NULL;
  1201     ::stringlist_t *_extra = new_stringlist(extra); // can cope with NULL
  1202 
  1203     // _PEP_enc_format used to be intentionally hardcoded to PEP_enc_PEP:
  1204     // Since COM-74, this has been changed to an explicit parameter, to allow the engine to attach
  1205     // the keys and headers to outgoing, unencrypted messages.
  1206     PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t)flags;
  1207     PEP_STATUS status = passphrase_cache.api(::encrypt_message, session(), _src, _extra, &msg_dst, _encFormat, engineFlags);
  1208     ::free_stringlist(_extra);
  1209 
  1210     if (status == PEP_STATUS_OK)
  1211         text_message_from_C(dst, msg_dst);
  1212     else
  1213         text_message_from_C(dst, _src);
  1214 
  1215     ::free_message(msg_dst);
  1216     ::free_message(_src);
  1217 
  1218     if (status == PEP_OUT_OF_MEMORY)
  1219         return E_OUTOFMEMORY;
  1220 
  1221     // COM-41: Enhanced PEP status handling
  1222     if ((status != PEP_STATUS_OK) && (status < PEP_UNENCRYPTED || status >= PEP_TRUSTWORD_NOT_FOUND))
  1223         return FAIL("Failure to encrypt message", status);
  1224 
  1225     // Statii like PEP_UNENCRYPTED due to no private key
  1226     // should not be a catastrophic failure here. Using S_FALSE
  1227     // still allows clients to differentiate with S_OK,
  1228     // although this does not work out of the box with
  1229     // the standard .NET mapping of COM.
  1230     if (status != PEP_STATUS_OK)
  1231         return S_FALSE;
  1232 
  1233     return S_OK;
  1234 }
  1235 
  1236 STDMETHODIMP CpEpEngine::EncryptMessageAndAddPrivKey(TextMessage * src, TextMessage * dst, BSTR to_fpr, pEpEncryptFlags flags, pEpEncFormat encFormat)
  1237 {
  1238     assert(src);
  1239     assert(dst);
  1240     assert(to_fpr);
  1241 
  1242     if (!(src && dst))
  1243         return E_INVALIDARG;
  1244 
  1245     ::message *_src = NULL;
  1246     try {
  1247         _src = text_message_to_C(src);
  1248     }
  1249     catch (bad_alloc&) {
  1250         return E_OUTOFMEMORY;
  1251     }
  1252     catch (exception& ex) {
  1253         return FAIL(ex.what());
  1254     }
  1255 
  1256     _PEP_enc_format _encFormat = (_PEP_enc_format)encFormat;
  1257 
  1258     // COM-19: Initialize msg_dst to NULL, or we end up calling
  1259     // free_message() below with a pointer to random garbage in
  1260     // case of an error in encrypt_message().
  1261     ::message *msg_dst = NULL;
  1262 
  1263     string _to_fpr = utf8_string(to_fpr);
  1264     // _PEP_enc_format used to be intentionally hardcoded to PEP_enc_PEP:
  1265     // Since COM-74, this has been changed to an explicit parameter, to allow the engine to attach
  1266     // the keys and headers to outgoing, unencrypted messages.
  1267     PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t)flags;
  1268     PEP_STATUS status = passphrase_cache.api(::encrypt_message_and_add_priv_key, session(), _src, &msg_dst, _to_fpr.c_str(), _encFormat, engineFlags);
  1269 
  1270     if (status == PEP_STATUS_OK)
  1271         text_message_from_C(dst, msg_dst);
  1272     else
  1273         text_message_from_C(dst, _src);
  1274 
  1275     ::free_message(msg_dst);
  1276     ::free_message(_src);
  1277 
  1278     if (status == PEP_OUT_OF_MEMORY)
  1279         return E_OUTOFMEMORY;
  1280 
  1281     // COM-41: Enhanced PEP status handling
  1282     if ((status != PEP_STATUS_OK) && (status < PEP_UNENCRYPTED || status >= PEP_TRUSTWORD_NOT_FOUND))
  1283         return FAIL("Failure to encrypt message", status);
  1284 
  1285     // Statii like PEP_UNENCRYPTED due to no private key
  1286     // should not be a catastrophic failure here. Using S_FALSE
  1287     // still allows clients to differentiate with S_OK,
  1288     // although this does not work out of the box with
  1289     // the standard .NET mapping of COM.
  1290     if (status != PEP_STATUS_OK)
  1291         return S_FALSE;
  1292 
  1293     return S_OK;
  1294 }
  1295 
  1296 STDMETHODIMP CpEpEngine::EncryptMessageForSelf(pEpIdentity * targetId, TextMessage * src,
  1297     /* [in] */ SAFEARRAY *extra, TextMessage * dst, pEpEncryptFlags flags)
  1298 {
  1299     assert(targetId);
  1300     assert(src);
  1301     assert(dst);
  1302 
  1303     if (!(targetId && src && dst))
  1304         return E_INVALIDARG;
  1305 
  1306     PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t)flags;
  1307 
  1308     ::pEp_identity *_target_id = new_identity(targetId);
  1309 
  1310     ::message *_src = NULL;
  1311     try {
  1312         _src = text_message_to_C(src);
  1313     }
  1314     catch (bad_alloc&) {
  1315         return E_OUTOFMEMORY;
  1316     }
  1317     catch (exception& ex) {
  1318         return FAIL(ex.what());
  1319     }
  1320 
  1321     ::stringlist_t* _extra = NULL;
  1322     HRESULT result = S_OK;
  1323     ::message *msg_dst = NULL;
  1324     PEP_STATUS status = PEP_STATUS_OK;
  1325 
  1326     try {
  1327         if (extra) {
  1328             _extra = new_stringlist(extra);
  1329         }
  1330 
  1331         // COM-19: Initialize msg_dst to NULL, or we end up calling
  1332         // free_message() below with a pointer to random garbage in
  1333         // case of an error in encrypt_message_for_self().
  1334         status = passphrase_cache.api(::encrypt_message_for_self, session(), _target_id, _src, _extra, &msg_dst, PEP_enc_PEP, engineFlags);
  1335 
  1336         if (status == PEP_STATUS_OK)
  1337             text_message_from_C(dst, msg_dst);
  1338         else
  1339             text_message_from_C(dst, _src);
  1340     }
  1341     catch (bad_alloc&) {
  1342         result = E_OUTOFMEMORY;
  1343     }
  1344     catch (exception& ex) {
  1345         result = FAIL(ex.what());
  1346     }
  1347 
  1348     ::free_message(msg_dst);
  1349     ::free_message(_src);
  1350     ::free_identity(_target_id);
  1351     ::free_stringlist(_extra);
  1352 
  1353     if (status == PEP_OUT_OF_MEMORY)
  1354         return E_OUTOFMEMORY;
  1355 
  1356     // Different to encrypt_message, this should never fail (we ought to always
  1357     // have a private key for ourself).#
  1358     if (status != PEP_STATUS_OK)
  1359         return FAIL("Failure to encrypt message", status);
  1360 
  1361     return result;
  1362 }
  1363 
  1364 STDMETHODIMP CpEpEngine::DecryptMessage(TextMessage * src, TextMessage * dst, SAFEARRAY ** keylist, pEpDecryptFlags *flags, pEpRating *rating)
  1365 {
  1366     assert(src);
  1367     assert(dst);
  1368     assert(keylist);
  1369     assert(flags);
  1370     assert(rating);
  1371 
  1372     if (!(src && dst && keylist && flags && rating))
  1373         return E_INVALIDARG;
  1374 
  1375     *rating = pEpRatingUndefined;
  1376 
  1377     ::message *_src = NULL;
  1378     try {
  1379         _src = text_message_to_C(src);
  1380     }
  1381     catch (bad_alloc&) {
  1382         return E_OUTOFMEMORY;
  1383     }
  1384     catch (exception& ex) {
  1385         return FAIL(ex.what());
  1386     }
  1387     ::message *msg_dst = NULL;
  1388     ::stringlist_t *_keylist = new_stringlist(*keylist);
  1389     ::PEP_rating _rating;
  1390 
  1391     PEP_decrypt_flags_t engineflags = (PEP_decrypt_flags_t)*flags;
  1392     PEP_STATUS status = passphrase_cache.api(::decrypt_message, session(), _src, &msg_dst, &_keylist, &_rating, &engineflags);
  1393 
  1394     *flags = (pEpDecryptFlags)engineflags;
  1395 
  1396     if (_src)
  1397         text_message_from_C(src, _src);
  1398 
  1399     if (msg_dst)
  1400         text_message_from_C(dst, msg_dst);
  1401 
  1402     ::free_message(_src);
  1403     ::free_message(msg_dst);
  1404 
  1405     if (_keylist) {
  1406         *keylist = string_array(_keylist);
  1407         free_stringlist(_keylist);
  1408     }
  1409 
  1410     *rating = (pEpRating)_rating;
  1411 
  1412     return S_OK;
  1413 }
  1414 
  1415 STDMETHODIMP CpEpEngine::ReEvaluateMessageRating(TextMessage * msg, SAFEARRAY * x_KeyList, pEpRating x_EncStatus, pEpRating *rating)
  1416 {
  1417     assert(msg);
  1418     assert(x_EncStatus != PEP_rating_undefined);
  1419     assert(rating);
  1420 
  1421     if (!(msg && x_EncStatus != PEP_rating_undefined && rating))
  1422         return E_INVALIDARG;
  1423 
  1424     *rating = pEpRatingUndefined;
  1425 
  1426     ::message *_msg = NULL;
  1427     try {
  1428         _msg = text_message_to_C(msg);
  1429     }
  1430     catch (bad_alloc&) {
  1431         return E_OUTOFMEMORY;
  1432     }
  1433     catch (exception& ex) {
  1434         return FAIL(ex.what());
  1435     }
  1436 
  1437     ::stringlist_t *_keylist = new_stringlist(x_KeyList);
  1438     ::PEP_rating _rating = PEP_rating_undefined;
  1439 
  1440     PEP_STATUS status = passphrase_cache.api(::re_evaluate_message_rating, session(), _msg, _keylist, (PEP_rating)x_EncStatus, &_rating);
  1441 
  1442     ::free_stringlist(_keylist);
  1443     ::free_message(_msg);
  1444 
  1445     *rating = (pEpRating)_rating;
  1446 
  1447     return S_OK;
  1448 }
  1449 
  1450 STDMETHODIMP CpEpEngine::OutgoingMessageRating(TextMessage *msg, pEpRating * pVal)
  1451 {
  1452     assert(msg);
  1453     assert(pVal);
  1454 
  1455     if (!(msg  && pVal))
  1456         return E_INVALIDARG;
  1457 
  1458     ::message *_msg = NULL;
  1459     try {
  1460         _msg = text_message_to_C(msg);
  1461     }
  1462     catch (bad_alloc&) {
  1463         return E_OUTOFMEMORY;
  1464     }
  1465     catch (exception& ex) {
  1466         return FAIL(ex.what());
  1467     }
  1468 
  1469     PEP_rating _rating;
  1470     PEP_STATUS status = passphrase_cache.api(::outgoing_message_rating, session(), _msg, &_rating);
  1471     if (status != PEP_STATUS_OK)
  1472         return FAIL(L"cannot get message rating", status);
  1473 
  1474     *pVal = (pEpRating)_rating;
  1475     return S_OK;
  1476 }
  1477 
  1478 STDMETHODIMP CpEpEngine::OutgoingMessageRatingPreview(TextMessage *msg, pEpRating * pVal)
  1479 {
  1480     assert(msg);
  1481     assert(pVal);
  1482 
  1483     if (!(msg  && pVal))
  1484         return E_INVALIDARG;
  1485 
  1486     ::message *_msg = NULL;
  1487     try {
  1488         _msg = text_message_to_C(msg);
  1489     }
  1490     catch (bad_alloc&) {
  1491         return E_OUTOFMEMORY;
  1492     }
  1493     catch (exception& ex) {
  1494         return FAIL(ex.what());
  1495     }
  1496 
  1497     PEP_rating _rating;
  1498     PEP_STATUS status = ::outgoing_message_rating_preview(session(), _msg, &_rating);
  1499     if (status != PEP_STATUS_OK)
  1500         return FAIL(L"cannot get message rating", status);
  1501 
  1502     *pVal = (pEpRating)_rating;
  1503     return S_OK;
  1504 }
  1505 
  1506 STDMETHODIMP CpEpEngine::IdentityRating(struct pEpIdentity *ident, pEpRating * pVal)
  1507 {
  1508     ::pEp_identity *_ident;
  1509 
  1510     assert(ident);
  1511     assert(pVal);
  1512 
  1513     if (!(ident  && pVal))
  1514         return E_INVALIDARG;
  1515 
  1516     try {
  1517         _ident = new_identity(ident);
  1518     }
  1519     catch (bad_alloc&) {
  1520         return E_OUTOFMEMORY;
  1521     }
  1522     catch (exception& ex) {
  1523         return FAIL(ex.what());;
  1524     }
  1525 
  1526     PEP_rating _rating;
  1527     PEP_STATUS status = passphrase_cache.api(::identity_rating, session(), _ident, &_rating);
  1528     free_identity(_ident);
  1529 
  1530     if (status != PEP_STATUS_OK)
  1531         return FAIL(L"cannot get message color", status);
  1532 
  1533     *pVal = (pEpRating)_rating;
  1534     return S_OK;
  1535 }
  1536 
  1537 STDMETHODIMP CpEpEngine::ColorFromRating(pEpRating rating, pEpColor * pVal)
  1538 {
  1539     assert(pVal);
  1540 
  1541     if (!pVal)
  1542         return E_INVALIDARG;
  1543 
  1544     PEP_rating engineRating = (PEP_rating)rating;
  1545     PEP_color _color = ::color_from_rating(engineRating);
  1546 
  1547     *pVal = (pEpColor)_color;
  1548 
  1549     return S_OK;
  1550 }
  1551 
  1552 STDMETHODIMP CpEpEngine::OwnIdentitiesRetrieve(LPSAFEARRAY* ownIdentities)
  1553 {
  1554     assert(ownIdentities);
  1555     if (!ownIdentities)
  1556         return E_INVALIDARG;
  1557 
  1558     *ownIdentities = nullptr;
  1559 
  1560     ::identity_list *il = nullptr;
  1561     PEP_STATUS status = passphrase_cache.api(::own_identities_retrieve, session(), &il);
  1562     if (status == PEP_OUT_OF_MEMORY) {
  1563         return E_OUTOFMEMORY;
  1564     }
  1565     else if (status != PEP_STATUS_OK)
  1566     {
  1567         return FAIL(_T("OwnIdentitiesRetrieve"), status);
  1568     }
  1569 
  1570     SAFEARRAY * _own_identities = nullptr;
  1571     try {
  1572         _own_identities = array_from_C<pEpIdentity, identity_list>(il);
  1573     }
  1574     catch (exception& ex)
  1575     {
  1576         ::free_identity_list(il);
  1577         try {
  1578             dynamic_cast<bad_alloc&>(ex);
  1579         }
  1580         catch (bad_cast&)
  1581         {
  1582             return FAIL(ex.what());
  1583         }
  1584         return E_OUTOFMEMORY;
  1585     }
  1586     free_identity_list(il);
  1587 
  1588     *ownIdentities = _own_identities;
  1589     return S_OK;
  1590 }
  1591 
  1592 STDMETHODIMP CpEpEngine::TrustPersonalKey(struct pEpIdentity *ident, struct pEpIdentity *result)
  1593 {
  1594     ::pEp_identity *_ident;
  1595 
  1596     assert(ident);
  1597     assert(result);
  1598 
  1599     if (!ident || !result)
  1600         return E_INVALIDARG;
  1601 
  1602     try {
  1603         _ident = new_identity(ident);
  1604     }
  1605     catch (bad_alloc&) {
  1606         return E_OUTOFMEMORY;
  1607     }
  1608     catch (exception& ex) {
  1609         return FAIL(ex.what());;
  1610     }
  1611 
  1612     if (verbose_mode) {
  1613         stringstream ss;
  1614         ss << "TrustPersonalKey called with ";
  1615         ss << utf8_string(ident->Address);
  1616         ss << L": ";
  1617         ss << ident->CommType;
  1618         verbose(ss.str());
  1619     }
  1620 
  1621     PEP_STATUS status = passphrase_cache.api(::trust_personal_key, session(), _ident);
  1622 
  1623     if (verbose_mode) {
  1624         stringstream ss;
  1625         ss << "result ";
  1626         ss << status;
  1627         ss << " for ";
  1628         ss << _ident->address;
  1629         ss << L": ";
  1630         ss << _ident->comm_type;
  1631         verbose(ss.str());
  1632     }
  1633 
  1634     if (status == PEP_STATUS_OK)
  1635         copy_identity(result, _ident);
  1636 
  1637     free_identity(_ident);
  1638     if (status == PEP_OUT_OF_MEMORY)
  1639         return E_OUTOFMEMORY;
  1640     else if (status != PEP_STATUS_OK)
  1641         return FAIL(L"failure while executing TrustPersonalKey()", status);
  1642 
  1643     return S_OK;
  1644 }
  1645 
  1646 // Force an update check now
  1647 STDMETHODIMP CpEpEngine::UpdateNow(BSTR productCode, VARIANT_BOOL *didUpdate)
  1648 {
  1649     BOOL result = FALSE;
  1650 
  1651     try
  1652     {
  1653         _bstr_t pc(productCode);
  1654         wstring _pc = pc;
  1655 
  1656         auto products = pEp::GateKeeper::gatekeeper()->registered_products();
  1657         for (auto p = products.begin(); p != products.end(); ++p) {
  1658             if (_pc == p->first) {
  1659                 result = pEp::GateKeeper::gatekeeper()->update_product(*p);
  1660                 break;
  1661             }
  1662         }
  1663     }
  1664     catch (bad_alloc&) {
  1665         return E_OUTOFMEMORY;
  1666     }
  1667     catch (exception& ex) {
  1668         return FAIL(ex.what());;
  1669     }
  1670 
  1671     *didUpdate = result;
  1672     return S_OK;
  1673 }
  1674 
  1675 // Event callbacks
  1676 
  1677 STDMETHODIMP CpEpEngine::RegisterCallbacks(IpEpEngineCallbacks* new_callbacks)
  1678 {
  1679     // check for valid parameter
  1680     if (!new_callbacks)
  1681         return E_INVALIDARG;
  1682 
  1683     // don't allow double registration.
  1684     if (this->client_callbacks)
  1685         return E_ILLEGAL_STATE_CHANGE;
  1686 
  1687     this->client_callbacks = new_callbacks;
  1688     new_callbacks->AddRef();
  1689 
  1690     // provide callbacks to sync
  1691     LPSTREAM marshaled_callbacks = nullptr;
  1692     auto result = CoMarshalInterThreadInterfaceInStream(IID_IpEpEngineCallbacks, client_callbacks, &marshaled_callbacks);
  1693     assert(SUCCEEDED(result));
  1694     assert(marshaled_callbacks);
  1695     sync_callbacks.insert(new MarshaledCallbacks({ this->client_callbacks, marshaled_callbacks }));
  1696 
  1697     return S_OK;
  1698 }
  1699 
  1700 STDMETHODIMP CpEpEngine::UnregisterCallbacks()
  1701 {
  1702     // don't allow double deregistration.
  1703     // S_FALSE still is no error (as double deregistration is not fatal).
  1704     if (!this->client_callbacks)
  1705         return S_FALSE;
  1706 
  1707     for (auto p = sync_callbacks.begin(); p != sync_callbacks.end(); ++p) {
  1708         if (p->pdata && p->pdata->unmarshaled == this->client_callbacks) {
  1709             if (p->pdata->marshaled)
  1710                 p->pdata->marshaled->Release();
  1711             if (p->pdata->unmarshaled)
  1712                 p->pdata->unmarshaled->Release();
  1713             delete p->pdata;
  1714             p->pdata = nullptr;
  1715             break;
  1716         }
  1717     }
  1718 
  1719     this->client_callbacks->Release();
  1720     this->client_callbacks = nullptr;
  1721 
  1722     return S_OK;
  1723 }
  1724 
  1725 STDMETHODIMP CpEpEngine::OpenPGPListKeyinfo(BSTR search_pattern, LPSAFEARRAY* keyinfo_list) {
  1726     assert(keyinfo_list);
  1727 
  1728     if (keyinfo_list == NULL)
  1729         return E_INVALIDARG;
  1730 
  1731     string _pattern = "";
  1732     if (search_pattern)
  1733         _pattern = utf8_string(search_pattern);
  1734     ::stringpair_list_t* _keyinfo_list = NULL;
  1735 
  1736     PEP_STATUS status = passphrase_cache.api(::OpenPGP_list_keyinfo, session(), _pattern.c_str(), &_keyinfo_list);
  1737     assert(status != PEP_OUT_OF_MEMORY);
  1738     if (status == PEP_OUT_OF_MEMORY)
  1739         return E_OUTOFMEMORY;
  1740 
  1741     if (status != PEP_STATUS_OK)
  1742         return FAIL(L"OpenPGP_list_keyinfo", status);
  1743 
  1744     if (_keyinfo_list && _keyinfo_list->value) {
  1745         ::opt_field_array_from_C(_keyinfo_list, keyinfo_list);
  1746     }
  1747     else {
  1748         ::free_stringpair_list(_keyinfo_list);
  1749         return FAIL(L"OpenPGP_list_keyinfo: no keys found");
  1750     }
  1751 
  1752     ::free_stringpair_list(_keyinfo_list);
  1753     return S_OK;
  1754 
  1755 }
  1756 
  1757 STDMETHODIMP CpEpEngine::SetOwnKey(pEpIdentity * ident, BSTR fpr, struct pEpIdentity *result)
  1758 {
  1759     assert(ident);
  1760     assert(result);
  1761     assert(fpr);
  1762 
  1763     if (!(ident && result))
  1764         return E_INVALIDARG;
  1765 
  1766     ::pEp_identity *_ident;
  1767     try {
  1768         _ident = new_identity(ident);
  1769     }
  1770     catch (bad_alloc&) {
  1771         return E_OUTOFMEMORY;
  1772     }
  1773     catch (exception& ex) {
  1774         return FAIL(ex.what());
  1775     }
  1776 
  1777     assert(_ident);
  1778     if (_ident == NULL)
  1779         return E_OUTOFMEMORY;
  1780 
  1781     string _fpr = utf8_string(fpr);
  1782     PEP_STATUS status = passphrase_cache.api(::set_own_key, session(), _ident, _fpr.c_str());
  1783 
  1784     if (status == PEP_STATUS_OK) {
  1785         copy_identity(result, _ident);
  1786         ::free_identity(_ident);
  1787         return S_OK;
  1788     }
  1789     else {
  1790         ::free_identity(_ident);
  1791         if (status == PEP_OUT_OF_MEMORY)
  1792             return E_OUTOFMEMORY;
  1793         else
  1794             return FAIL(L"SetOwnKey", status);
  1795     }
  1796 
  1797     return S_OK;
  1798 }
  1799 
  1800 STDMETHODIMP CpEpEngine::TrustOwnKey(pEpIdentity * ident)
  1801 {
  1802     assert(ident);
  1803 
  1804     if (!ident)
  1805         return E_INVALIDARG;
  1806 
  1807     ::pEp_identity *_ident;
  1808     try {
  1809         _ident = new_identity(ident);
  1810     }
  1811     catch (bad_alloc&) {
  1812         return E_OUTOFMEMORY;
  1813     }
  1814     catch (exception& ex) {
  1815         return FAIL(ex.what());
  1816     }
  1817 
  1818     assert(_ident);
  1819     if (_ident == NULL)
  1820         return E_OUTOFMEMORY;
  1821 
  1822     PEP_STATUS status = passphrase_cache.api(::trust_own_key, session(), _ident);
  1823 
  1824     ::free_identity(_ident);
  1825 
  1826     if (status == PEP_STATUS_OK)
  1827         return S_OK;
  1828     else if (status == PEP_OUT_OF_MEMORY)
  1829         return E_OUTOFMEMORY;
  1830     else
  1831         return FAIL(L"TrustOwnKey", status);
  1832 }
  1833 
  1834 STDMETHODIMP CpEpEngine::Startup()
  1835 {
  1836     try
  1837     {
  1838         // this must be unblocked, because it's not possible to have two API calls in parallel
  1839         // start_sync() may send notifyHandshake() to ask for a passphrase; when this happens
  1840         // the client needs to call ConfigPassphrase() while the startup process is being executed
  1841         // so we need to return from Startup() immediately to make this possible
  1842 
  1843         auto sync_starter_thread = std::thread(pEp::CallbackDispatcher::start_sync);
  1844         sync_starter_thread.detach();
  1845     }
  1846     catch (bad_alloc&) {
  1847         return E_OUTOFMEMORY;
  1848     }
  1849     catch (exception& ex) {
  1850         return FAIL(ex.what());
  1851     }
  1852 
  1853     return S_OK;
  1854 }
  1855 
  1856 STDMETHODIMP CpEpEngine::GetKeyRating(BSTR fpr, pEpComType *commType)
  1857 {
  1858     assert(fpr);
  1859 
  1860     if (!fpr)
  1861         return E_INVALIDARG;
  1862 
  1863     string _fpr = utf8_string(fpr);
  1864 
  1865     PEP_comm_type _commType;
  1866     PEP_STATUS status = passphrase_cache.api(::get_key_rating, session(), _fpr.c_str(), &_commType);
  1867     if (status != PEP_STATUS_OK)
  1868         return FAIL(L"cannot get key rating", status);
  1869 
  1870     *commType = (pEpComType)_commType;
  1871 
  1872     return S_OK;
  1873 }
  1874 
  1875 STDMETHODIMP CpEpEngine::GetKeyRatingForUser(BSTR userId, BSTR fpr, pEpRating *rating)
  1876 {
  1877     assert(userId);
  1878     assert(fpr);
  1879 
  1880     if (!(userId && fpr))
  1881         return E_INVALIDARG;
  1882 
  1883     string user_id = utf8_string(userId);
  1884     string _fpr = utf8_string(fpr);
  1885 
  1886     PEP_rating _rating;
  1887     PEP_STATUS status = passphrase_cache.api(::get_key_rating_for_user, session(), user_id.c_str(), _fpr.c_str(), &_rating);
  1888     if (status != PEP_STATUS_OK)
  1889         return FAIL(L"cannot get key rating for user", status);
  1890 
  1891     *rating = (pEpRating)_rating;
  1892 
  1893     return S_OK;
  1894 }
  1895 
  1896 STDMETHODIMP CpEpEngine::DeliverHandshakeResult(enum SyncHandshakeResult result, SAFEARRAY *identities_sharing)
  1897 {
  1898     sync_handshake_result _result = (sync_handshake_result)result;
  1899     identity_list *_identities_sharing = NULL;
  1900     if (identities_sharing)
  1901     {
  1902         try {
  1903             _identities_sharing = identities(identities_sharing);
  1904         }
  1905         catch (bad_alloc&) {
  1906             return E_OUTOFMEMORY;
  1907         }
  1908     }
  1909 
  1910     PEP_STATUS status = ::deliverHandshakeResult(session(), _result, _identities_sharing);
  1911     free_identity_list(_identities_sharing);
  1912     switch (status) {
  1913     case PEP_STATUS_OK:
  1914         break;
  1915     case PEP_OUT_OF_MEMORY:
  1916         return E_OUTOFMEMORY;
  1917     default:
  1918         return FAIL(L"deliverHandshakeResult is reporting an error", status);
  1919     }
  1920 
  1921     return S_OK;
  1922 }
  1923 
  1924 STDMETHODIMP CpEpEngine::PERToXERSyncMessage(TextMessage *msg, BSTR * xer)
  1925 {
  1926     assert(msg);
  1927 
  1928     if (!msg)
  1929         return E_INVALIDARG;
  1930 
  1931     ::message *_msg = NULL;
  1932     try {
  1933         _msg = text_message_to_C(msg);
  1934     }
  1935     catch (bad_alloc&) {
  1936         return E_OUTOFMEMORY;
  1937     }
  1938     catch (exception& ex) {
  1939         return FAIL(ex.what());
  1940     }
  1941 
  1942     char* text;
  1943     char* val = _msg->attachments->value;
  1944 
  1945     PEP_STATUS status = ::PER_to_XER_Sync_msg(val, strlen(val), &text);
  1946     free_message(_msg);
  1947 
  1948     if (status != PEP_STATUS_OK)
  1949         return FAIL(L"cannot get XER", status);
  1950 
  1951     *xer = utf16_bstr(text);
  1952     pEp_free(text);
  1953 
  1954     return S_OK;
  1955 }
  1956 
  1957 STDMETHODIMP CpEpEngine::DisableIdentityForSync(struct pEpIdentity * ident)
  1958 {
  1959     assert(ident);
  1960 
  1961     if (!ident)
  1962         return E_INVALIDARG;
  1963 
  1964     ::pEp_identity *_ident;
  1965     try {
  1966         _ident = new_identity(ident);
  1967     }
  1968     catch (bad_alloc&) {
  1969         return E_OUTOFMEMORY;
  1970     }
  1971     catch (exception& ex) {
  1972         return FAIL(ex.what());
  1973     }
  1974 
  1975     assert(_ident);
  1976     if (_ident == NULL)
  1977         return E_OUTOFMEMORY;
  1978 
  1979     PEP_STATUS status = passphrase_cache.api(::disable_identity_for_sync, session(), _ident);
  1980 
  1981     ::free_identity(_ident);
  1982 
  1983     if (status == PEP_STATUS_OK)
  1984         return S_OK;
  1985     else if (status == PEP_OUT_OF_MEMORY)
  1986         return E_OUTOFMEMORY;
  1987     else
  1988         return FAIL(L"DisableIdentityForSync", status);
  1989 }
  1990 
  1991 STDMETHODIMP CpEpEngine::EnableIdentityForSync(struct pEpIdentity * ident)
  1992 {
  1993     assert(ident);
  1994 
  1995     if (!ident)
  1996         return E_INVALIDARG;
  1997 
  1998     ::pEp_identity *_ident;
  1999     try {
  2000         _ident = new_identity(ident);
  2001     }
  2002     catch (bad_alloc&) {
  2003         return E_OUTOFMEMORY;
  2004     }
  2005     catch (exception& ex) {
  2006         return FAIL(ex.what());
  2007     }
  2008 
  2009     assert(_ident);
  2010     if (_ident == NULL)
  2011         return E_OUTOFMEMORY;
  2012 
  2013     PEP_STATUS status = passphrase_cache.api(::enable_identity_for_sync, session(), _ident);
  2014 
  2015     ::free_identity(_ident);
  2016 
  2017     if (status == PEP_STATUS_OK)
  2018         return S_OK;
  2019     else if (status == PEP_OUT_OF_MEMORY)
  2020         return E_OUTOFMEMORY;
  2021     else
  2022         return FAIL(L"EnableIdentityForSync", status);
  2023 }
  2024 
  2025 STDMETHODIMP CpEpEngine::PerMachineDirectory(BSTR * directory)
  2026 {
  2027     assert(directory);
  2028 
  2029     if (!directory)
  2030         return E_INVALIDARG;
  2031 
  2032     const char *_directory = ::per_machine_directory();
  2033 
  2034     if (_directory == NULL)
  2035         return FAIL(L"PerMachineDirectory: _directory is NULL");
  2036 
  2037     *directory = utf16_bstr(_directory);
  2038 
  2039     return S_OK;
  2040 }
  2041 
  2042 STDMETHODIMP CpEpEngine::PerUserDirectory(BSTR * directory)
  2043 {
  2044     assert(directory);
  2045 
  2046     if (!directory)
  2047         return E_INVALIDARG;
  2048 
  2049     const char *_directory = ::per_user_directory();
  2050 
  2051     if (_directory == NULL)
  2052         return FAIL(L"PerUserDirectory: _directory is NULL");
  2053 
  2054     *directory = utf16_bstr(_directory);
  2055 
  2056     return S_OK;
  2057 }
  2058 
  2059 STDMETHODIMP CpEpEngine::RatingFromCommType(pEpComType commType, pEpRating * rating)
  2060 {
  2061     PEP_comm_type _comm_type = (PEP_comm_type)commType;
  2062     PEP_rating _rating = ::rating_from_comm_type(_comm_type);
  2063 
  2064     *rating = (pEpRating)_rating;
  2065 
  2066     return S_OK;
  2067 }
  2068 
  2069 STDMETHODIMP CpEpEngine::GetIsSyncRunning(VARIANT_BOOL *running)
  2070 {
  2071     *running = pEp::Adapter::is_sync_running();
  2072     return S_OK;
  2073 }
  2074 
  2075 STDMETHODIMP CpEpEngine::ShutDownSync()
  2076 {
  2077     pEp::callback_dispatcher.stop_sync();
  2078     return S_OK;
  2079 }
  2080 
  2081 STDMETHODIMP CpEpEngine::ConfigPassphrase(BSTR passphrase)
  2082 {
  2083     string _passphrase = "";
  2084 
  2085     if (passphrase)
  2086         _passphrase = utf8_string(passphrase);
  2087 
  2088     PEP_STATUS status = ::config_passphrase(session(), passphrase_cache.add(_passphrase));
  2089 
  2090     if (status == PEP_STATUS_OK)
  2091         return S_OK;
  2092     else if (status == PEP_OUT_OF_MEMORY)
  2093         return E_OUTOFMEMORY;
  2094     else
  2095         return FAIL(L"ConfigPassphrase", status);
  2096 }
  2097 
  2098 STDMETHODIMP CpEpEngine::ConfigPassphraseForNewKeys(VARIANT_BOOL enable, BSTR passphrase)
  2099 {
  2100     string _passphrase = "";
  2101     
  2102     if (passphrase)
  2103         _passphrase = utf8_string(passphrase);
  2104 
  2105     passphrase_for_new_keys = _passphrase;
  2106     PEP_STATUS status = ::config_passphrase_for_new_keys(session(), enable, passphrase_cache.add_stored(_passphrase));
  2107 
  2108     if (status == PEP_STATUS_OK)
  2109         return S_OK;
  2110     else if (status == PEP_OUT_OF_MEMORY)
  2111         return E_OUTOFMEMORY;
  2112     else
  2113         return FAIL(L"ConfigPassphraseForNewKeys", status);
  2114 }
  2115 
  2116 STDMETHODIMP CpEpEngine::ShowNotification(BSTR title, BSTR message) 
  2117 {
  2118     pEp::GateKeeper::gatekeeper()->show_notification(title, message);
  2119     return S_OK;
  2120 }