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