CpEpEngine.cpp
author Volker Birk <vb@pep-project.org>
Thu, 16 Apr 2015 20:43:31 +0200
changeset 0 0aa9866d751c
child 4 fdd8cf02d2cc
permissions -rw-r--r--
initial commit
     1 // CpEpEngine.cpp : Implementation of CpEpEngine
     2 
     3 #include "stdafx.h"
     4 #include "CpEpEngine.h"
     5 
     6 
     7 // CpEpEngine
     8 
     9 STDMETHODIMP CpEpEngine::InterfaceSupportsErrorInfo(REFIID riid)
    10 {
    11 	static const IID* const arr[] = 
    12 	{
    13 		&IID_IpEpEngine
    14 	};
    15 
    16 	for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
    17 	{
    18 		if (InlineIsEqualGUID(*arr[i],riid))
    19 			return S_OK;
    20 	}
    21 	return S_FALSE;
    22 }
    23 
    24 #define FAIL(msg) error(msg)
    25 
    26 using namespace std;
    27 
    28 static CComSafeArray<BSTR> string_array(const ::stringlist_t *stringlist)
    29 {
    30     CComSafeArray<BSTR> sa_string_list;
    31     int n = 0;
    32     for (const ::stringlist_t *k = stringlist; k != NULL; k = k->next) {
    33         if (k->value) {
    34             HRESULT _result = sa_string_list.Add(utf16_bstr(k->value).Detach(), false);
    35             assert(_result == S_OK);
    36             if (_result == E_OUTOFMEMORY)
    37                 throw std::bad_alloc();
    38             ++n;
    39         }
    40     }
    41 
    42     return sa_string_list;
    43 }
    44 
    45 static ::stringlist_t * new_stringlist(const SAFEARRAY * safearray)
    46 {
    47     CComSafeArray<BSTR> sa(safearray);
    48     int n_strings = 0;
    49     ::stringlist_t *_stringlist = ::new_stringlist((const char *) NULL);
    50     assert(_stringlist);
    51     if (_stringlist == NULL)
    52         throw std::bad_alloc();
    53 
    54     n_strings = sa.GetUpperBound() - sa.GetLowerBound() + 1;
    55     ::stringlist_t *k = _stringlist;
    56     for (int i = 0, j = sa.GetLowerBound(); i<n_strings; ++i, ++j) {
    57         k = ::stringlist_add(k, utf8_string(sa.GetAt(j)).c_str());
    58         assert(k);
    59         if (k == NULL) {
    60             ::free_stringlist(_stringlist);
    61             throw std::bad_alloc();
    62         }
    63     }
    64 
    65     return _stringlist;
    66 }
    67 
    68 static ::pEp_identity *new_identity(const pEp_identity_s * ident)
    69 {
    70     ::pEp_identity *_ident;
    71 
    72     string _address;
    73     string _fpr;
    74     string _user_id;
    75     string _username;
    76 
    77     if (ident->address)
    78         _address = utf8_string(ident->address);
    79     if (ident->fpr) {
    80         _fpr = utf8_string(ident->fpr);
    81         for (auto p = _fpr.begin(); p != _fpr.end(); ++p) {
    82             if (*p >= 'A' && *p <= 'Z')
    83                 continue;
    84             if (*p >= '0' && *p <= '9')
    85                 continue;
    86             throw invalid_argument("invalid hex digits in fingerprint");
    87         }
    88     }
    89     if (ident->user_id)
    90         _user_id = utf8_string(ident->user_id);
    91     if (ident->username)
    92         _username = utf8_string(ident->username);
    93 
    94     _ident = ::new_identity(_address.c_str(), _fpr.c_str(), _user_id.c_str(), _username.c_str());
    95     assert(_ident);
    96     if (_ident == NULL)
    97         throw bad_alloc();
    98 
    99     _ident->comm_type = (PEP_comm_type) ident->comm_type;
   100 
   101     if (ident->lang) {
   102         string _lang = utf8_string(ident->lang);
   103         if (_lang.length() != 0) {
   104             if (_lang.length() != 2) {
   105                 ::free_identity(_ident);
   106                 throw invalid_argument("invalid language code");
   107             }
   108             if (_lang[0] < 'a' || _lang[0] > 'z') {
   109                 ::free_identity(_ident);
   110                 throw invalid_argument("invalid language code");
   111             }
   112             if (_lang[1] < 'a' || _lang[1] > 'z') {
   113                 ::free_identity(_ident);
   114                 throw invalid_argument("invalid language code");
   115             }
   116             _ident->lang[0] = _lang[0];
   117             _ident->lang[1] = _lang[1];
   118         }
   119     }
   120 
   121     return _ident;
   122 }
   123 
   124 static void copy_identity(pEp_identity_s * ident_s, const pEp_identity * ident)
   125 {
   126     ::memset(ident_s, 0, sizeof(pEp_identity_s));
   127 
   128     if (ident->address)
   129         ident_s->address = utf16_bstr(ident->address).Detach();
   130     if (ident->fpr)
   131         ident_s->fpr = utf16_bstr(ident->fpr).Detach();
   132     if (ident->user_id)
   133         ident_s->user_id = utf16_bstr(ident->user_id).Detach();
   134     if (ident->username)
   135         ident_s->username = utf16_bstr(ident->username).Detach();
   136     ident_s->comm_type = (pEp_comm_type) ident->comm_type;
   137     if (ident->lang)
   138         ident_s->lang = utf16_bstr(ident->lang).Detach();
   139 }
   140 
   141 // CpEpEngine
   142 
   143 ::pEp_identity *CpEpEngine::new_identity(const CpEpEngine::pEp_identity_cpp& ident)
   144 {
   145     ::pEp_identity *_ident = ::new_identity(ident.address.c_str(), ident.fpr.c_str(), ident.user_id.c_str(), ident.username.c_str());
   146     assert(_ident);
   147     if (_ident == NULL)
   148         throw bad_alloc();
   149 
   150     _ident->comm_type = (::PEP_comm_type) ident.comm_type;
   151     _ident->me = ident.me;
   152 
   153     assert(ident.lang.size() == 0 || ident.lang.size() == 2);
   154 
   155     if (ident.lang.size()) {
   156         _ident->lang[0] = ident.lang[0];
   157         _ident->lang[1] = ident.lang[1];
   158     }
   159 
   160     return _ident;
   161 }
   162 
   163 STDMETHODIMP CpEpEngine::log(BSTR title, BSTR entity, BSTR description, BSTR comment)
   164 {
   165     string _title;
   166     string _entity;
   167     string _description;
   168     string _comment;
   169     HRESULT result = S_OK;
   170 
   171     assert(title);
   172     if (title)
   173         _title = utf8_string(title);
   174     else
   175         result = E_INVALIDARG;
   176 
   177     assert(entity);
   178     if (entity)
   179         _entity = utf8_string(entity);
   180     else
   181         result = E_INVALIDARG;
   182 
   183     if (description)
   184         _description = utf8_string(description);
   185 
   186     if (comment)
   187         _comment = utf8_string(comment);
   188 
   189     if (result != S_OK)
   190         return result;
   191 
   192     PEP_STATUS _status = ::log_event(get_session(), _title.c_str(), _entity.c_str(), _description.c_str(), _comment.c_str());
   193     assert(_status == PEP_STATUS_OK);
   194     if (_status != PEP_STATUS_OK)
   195         return FAIL(L"log_event");
   196     else
   197         return S_OK;
   198 }
   199 
   200 
   201 STDMETHODIMP CpEpEngine::decrypt(BSTR ctext, BSTR * ptext, LPSAFEARRAY * key_list, pEp_STATUS * status)
   202 {
   203     assert(ctext);
   204     assert(ptext);
   205     assert(key_list);
   206     assert(status);
   207 
   208     if (ctext == NULL || ptext == NULL || key_list == NULL || status == NULL) {
   209         if (ptext)
   210             *ptext = NULL;
   211         if (key_list)
   212             *key_list = NULL;
   213         if (status)
   214             *status = pEp_UNENCRYPTED;
   215         return E_INVALIDARG;
   216     }
   217 
   218     string _ctext = utf8_string(ctext);
   219 
   220     char *_ptext = NULL;
   221     size_t _psize = 0;
   222     ::stringlist_t *_keylist = NULL;
   223     PEP_STATUS _status;
   224 
   225     _status = ::decrypt_and_verify(get_session(), _ctext.c_str(), _ctext.size(), &_ptext, &_psize, &_keylist);
   226     assert(_status != PEP_OUT_OF_MEMORY);
   227     if (_status == PEP_OUT_OF_MEMORY)
   228         return E_OUTOFMEMORY;
   229 
   230     *status = (pEp_STATUS) _status;
   231     if (_ptext == NULL) {
   232         if (_keylist) {
   233             string msg;
   234             if (_keylist->value[0] != 0) {
   235                 msg = _keylist->value;
   236             }
   237             else {
   238                 for (::stringlist_t *s = _keylist->next; s != NULL; s = s->next) {
   239                     if (s->value) {
   240                         msg += s->value;
   241                         msg += ";";
   242                     }
   243                 }
   244             }
   245             ::free_stringlist(_keylist);
   246 
   247             return FAIL(utf16_bstr(msg));
   248         }
   249         else
   250             return FAIL(L"cannot decrypt");
   251     }
   252 
   253     *ptext = utf16_bstr(_ptext).Detach();
   254     pEp_free(_ptext);
   255 
   256     if (_keylist && _keylist->value)
   257         *key_list = string_array(_keylist).Detach();
   258     else
   259         *key_list = NULL;
   260     ::free_stringlist(_keylist);
   261 
   262     return S_OK;
   263 }
   264 
   265 STDMETHODIMP CpEpEngine::decrypt_b(BSTR ctext, LPSAFEARRAY * ptext, LPSAFEARRAY * key_list, pEp_STATUS * status)
   266 {
   267     assert(ctext);
   268     assert(ptext);
   269     assert(key_list);
   270     assert(status);
   271 
   272     if (ctext == NULL || ptext == NULL || key_list == NULL || status == NULL) {
   273         if (ptext)
   274             *ptext = NULL;
   275         if (key_list)
   276             *key_list = NULL;
   277         if (status)
   278             *status = pEp_UNENCRYPTED;
   279         return E_INVALIDARG;
   280     }
   281 
   282     // Welcome to Windoze string hell!
   283 
   284     char *_ctext = NULL;
   285     _bstr_t bstr_ctext(ctext, true);
   286     int w_csize = bstr_ctext.length() + 1;
   287     int _csize = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, (wchar_t *) bstr_ctext, w_csize, NULL, 0, NULL, NULL);
   288     if (_csize) {
   289         _ctext = new char[_csize];
   290         WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, (wchar_t *) bstr_ctext, w_csize, _ctext, _csize, NULL, NULL);
   291     }
   292 
   293     char *_ptext = NULL;
   294     size_t _psize = 0;
   295     ::stringlist_t *_keylist = NULL;
   296     PEP_STATUS _status;
   297 
   298     _status = ::decrypt_and_verify(get_session(), _ctext, _csize, &_ptext, &_psize, &_keylist);
   299     assert(_status != PEP_OUT_OF_MEMORY);
   300     delete[] _ctext;
   301     if (_status == PEP_OUT_OF_MEMORY) {
   302         ::free_stringlist(_keylist);
   303         return E_OUTOFMEMORY;
   304     }
   305     *status = (pEp_STATUS) _status;
   306 
   307     if (_ptext == NULL) {
   308         ::free_stringlist(_keylist);
   309         return FAIL(L"decrypt_and_verify");
   310     }
   311 
   312     CComSafeArray<BYTE> sa_ptext;
   313 
   314     HRESULT _result = sa_ptext.Create(_psize, 0);
   315     assert(_result == S_OK);
   316     if (_result == E_OUTOFMEMORY) {
   317         pEp_free(_ptext);
   318         ::free_stringlist(_keylist);
   319         return E_OUTOFMEMORY;
   320     }
   321     else if (_result != S_OK) {
   322         pEp_free(_ptext);
   323         ::free_stringlist(_keylist);
   324         return FAIL(L"CComSafeArray<BYTE>::Create");
   325     }
   326 
   327     memcpy(sa_ptext.m_psa->pvData, _ptext, _psize);
   328     *ptext = sa_ptext.Detach();
   329     ::pEp_free(_ptext);
   330 
   331     if (_keylist && _keylist->value)
   332         *key_list = string_array(_keylist).Detach();
   333     else
   334         *key_list = NULL;
   335     ::free_stringlist(_keylist);
   336 
   337     return S_OK;
   338 }
   339 
   340 STDMETHODIMP CpEpEngine::verify(BSTR text, BSTR signature, LPSAFEARRAY * key_list, pEp_STATUS * verify_status)
   341 {
   342     assert(text);
   343     assert(signature);
   344     assert(key_list);
   345 
   346     if (text == NULL || signature == NULL || key_list == NULL)
   347         return E_INVALIDARG;
   348 
   349     string _text = utf8_string(text);
   350     string _signature = utf8_string(signature);
   351 
   352     ::stringlist_t *_keylist = NULL;
   353     PEP_STATUS _status;
   354     _status = ::verify_text(get_session(), _text.c_str(), _text.size(), _signature.c_str(), _signature.size(), &_keylist);
   355     assert(_status != PEP_OUT_OF_MEMORY);
   356     if (_status == PEP_OUT_OF_MEMORY)
   357         return E_OUTOFMEMORY;
   358     if (_status == PEP_DECRYPT_WRONG_FORMAT || _status == PEP_UNKNOWN_ERROR)
   359         return FAIL(L"verify_text");
   360 
   361     *verify_status = (pEp_STATUS) _status;
   362 
   363     if (_keylist && _keylist->value)
   364         *key_list = string_array(_keylist).Detach();
   365     else
   366         *key_list = NULL;
   367     ::free_stringlist(_keylist);
   368 
   369     return S_OK;
   370 }
   371 
   372 STDMETHODIMP CpEpEngine::encrypt(SAFEARRAY * key_list, BSTR ptext, BSTR * ctext, pEp_STATUS * status)
   373 {
   374     assert(key_list);
   375     assert(ptext);
   376     assert(ctext);
   377     assert(status);
   378 
   379     if (ctext == NULL || ptext == NULL || key_list == NULL || status == NULL) {
   380         if (ctext)
   381             *ctext = NULL;
   382         if (status)
   383             *status = pEp_UNKNOWN_ERROR;
   384         return E_INVALIDARG;
   385     }
   386 
   387     HRESULT result = S_OK;
   388 
   389     ::stringlist_t *_keylist = new_stringlist(key_list);
   390     string _ptext = utf8_string(ptext);
   391 
   392     char *_ctext = NULL;
   393     size_t _csize = 0;
   394     PEP_STATUS _status;
   395 
   396     _status = ::encrypt_and_sign(get_session(), _keylist, _ptext.c_str(), _ptext.size(), &_ctext, &_csize);
   397 
   398     assert(_status != PEP_OUT_OF_MEMORY);
   399     ::free_stringlist(_keylist);
   400     if (_status == PEP_OUT_OF_MEMORY)
   401         return E_OUTOFMEMORY;
   402     *status = (pEp_STATUS) _status;
   403 
   404     if (_ctext == NULL)
   405         return FAIL(L"encrypt_and_sign");
   406 
   407     *ctext = utf16_bstr(_ctext).Detach();
   408     pEp_free(_ctext);
   409 
   410     return S_OK;
   411 }
   412 
   413 STDMETHODIMP CpEpEngine::encrypt_b(SAFEARRAY * key_list, SAFEARRAY * ptext, BSTR * ctext, pEp_STATUS * status)
   414 {
   415     assert(key_list);
   416     assert(ptext);
   417     assert(ctext);
   418     assert(status);
   419 
   420     if (ctext == NULL || ptext == NULL || key_list == NULL || status == NULL) {
   421         if (ctext)
   422             *ctext = NULL;
   423         if (status)
   424             *status = pEp_UNKNOWN_ERROR;
   425         return E_INVALIDARG;
   426     }
   427 
   428     HRESULT result = S_OK;
   429 
   430     ::stringlist_t *_keylist = new_stringlist(key_list);
   431 
   432     char *_ctext = NULL;
   433     size_t _csize = 0;
   434     ::PEP_STATUS _status;
   435 
   436     _status = ::encrypt_and_sign(get_session(), _keylist, (const char *) ptext->pvData, ptext->rgsabound[0].cElements, &_ctext, &_csize);
   437     assert(_status != PEP_OUT_OF_MEMORY);
   438     ::free_stringlist(_keylist);
   439     if (_status == PEP_OUT_OF_MEMORY)
   440         return E_OUTOFMEMORY;
   441     *status = (pEp_STATUS) _status;
   442 
   443     if (_ctext == NULL)
   444         return FAIL(L"encrypt_and_sign");
   445 
   446     *status = (pEp_STATUS) _status;
   447     wchar_t *w_ctext = NULL;
   448     int w_csize = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, _ctext, _csize, NULL, 0);
   449     if (w_csize) {
   450         w_ctext = new wchar_t[w_csize + 1];
   451         MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, _ctext, _csize, w_ctext, w_csize);
   452         w_ctext[w_csize] = 0; // this is for debugging; Visual Studio will crash without that if you're unlucky
   453     }
   454     *ctext = ::SysAllocStringLen(w_ctext, w_csize);
   455     assert(ctext);
   456     delete[] w_ctext;
   457     pEp_free(_ctext);
   458     if (ctext == NULL)
   459         return E_OUTOFMEMORY;
   460 
   461     return S_OK;
   462 }
   463 
   464 STDMETHODIMP CpEpEngine::safeword(LONG value, BSTR lang, BSTR * word)
   465 {
   466     assert(value >= 0 && value <= 65535);
   467     assert(word);
   468 
   469     HRESULT result = S_OK;
   470 
   471     uint16_t _value = 0;
   472     if (value < 0 || value > 65535)
   473         result = E_INVALIDARG;
   474     else
   475         _value = (uint16_t) value;
   476 
   477     string _lang = "en";
   478     if (lang) {
   479         _lang = utf8_string(lang);
   480         if (_lang.length() != 2)
   481             result = E_INVALIDARG;
   482     }
   483 
   484     if (word == NULL)
   485         result = E_INVALIDARG;
   486 
   487     if (result != S_OK)
   488         return result;
   489 
   490     char *_word = NULL;
   491     size_t _wsize = 0;
   492 
   493     PEP_STATUS status = ::safeword(get_session(), _value, _lang.c_str(), &_word, &_wsize);
   494     assert(status != PEP_OUT_OF_MEMORY);
   495     if (status == PEP_OUT_OF_MEMORY)
   496         return E_OUTOFMEMORY;
   497 
   498     if (_word == NULL) {
   499         *word = NULL;
   500         return FAIL(L"safeword");
   501     }
   502     else {
   503         *word = utf16_bstr(_word).Detach();
   504         pEp_free(_word);
   505         return S_OK;
   506     }
   507 }
   508 
   509 STDMETHODIMP CpEpEngine::safewords(BSTR fpr, BSTR lang, LONG max_words, BSTR * words)
   510 {
   511     assert(fpr);
   512     assert(max_words >= 0);
   513     assert(words);
   514 
   515     HRESULT result = S_OK;
   516 
   517     string _fpr;
   518     if (fpr)
   519         _fpr = utf8_string(fpr);
   520     else
   521         result = E_INVALIDARG;
   522 
   523     string _lang;
   524     if (lang) {
   525         _lang = utf8_string(lang);
   526         if (_lang.length()) {
   527             if (_lang.length() != 2)
   528                 result = E_INVALIDARG;
   529         }
   530         else
   531             _lang = "en";
   532     }
   533     else
   534         _lang = "en";
   535 
   536     if (max_words < 0)
   537         result = E_INVALIDARG;
   538 
   539     if (words == NULL)
   540         result = E_INVALIDARG;
   541 
   542     if (result != S_OK)
   543         return result;
   544 
   545     char *_words = NULL;
   546     size_t _wsize = 0;
   547 
   548     PEP_STATUS status = ::safewords(get_session(), _fpr.c_str(), _lang.c_str(), &_words, &_wsize, max_words);
   549     assert(status != PEP_OUT_OF_MEMORY);
   550     if (status == PEP_OUT_OF_MEMORY)
   551         return E_OUTOFMEMORY;
   552 
   553     if (_words == NULL) {
   554         *words = NULL;
   555         return FAIL(L"safewords");
   556     }
   557     else {
   558         *words = utf16_bstr(_words).Detach();
   559         pEp_free(_words);
   560         return S_OK;
   561     }
   562 }
   563 
   564 STDMETHODIMP CpEpEngine::get_identity(BSTR address, pEp_identity_s * ident)
   565 {
   566     assert(address);
   567     assert(ident);
   568 
   569     if (address == NULL)
   570         return E_INVALIDARG;
   571 
   572     if (ident == NULL)
   573         return E_INVALIDARG;
   574 
   575     string _address = utf8_string(address);
   576     ::pEp_identity *_ident = NULL;
   577     PEP_STATUS status = ::get_identity(get_session(), _address.c_str(), &_ident);
   578     assert(status != PEP_OUT_OF_MEMORY);
   579     if (status == PEP_OUT_OF_MEMORY)
   580         return E_OUTOFMEMORY;
   581 
   582     if (_ident == NULL) {
   583         return FAIL(L"get_identity");
   584     }
   585 
   586     copy_identity(ident, _ident);
   587     ::free_identity(_ident);
   588 
   589     return S_OK;
   590 }
   591 
   592 STDMETHODIMP CpEpEngine::set_identity(pEp_identity_s * ident)
   593 {
   594     assert(ident);
   595     assert(ident->address);
   596     assert(ident->fpr);
   597     assert(ident->username);
   598     assert(ident->user_id);
   599 
   600     if (ident == NULL || ident->address == NULL || ident->fpr == NULL
   601         || ident->username == NULL || ident->user_id == NULL)
   602         return E_INVALIDARG;
   603 
   604     ::pEp_identity *_ident = new_identity(ident);
   605     ::PEP_STATUS status = ::set_identity(get_session(), _ident);
   606     ::free_identity(_ident);
   607 
   608     if (status != ::PEP_STATUS_OK)
   609         return FAIL(L"set_identity");
   610     else
   611         return S_OK;
   612 }
   613 
   614 STDMETHODIMP CpEpEngine::generate_keypair(pEp_identity_s * ident, BSTR * fpr)
   615 {
   616     assert(ident);
   617     assert(ident->address);
   618     assert(ident->username);
   619     assert(fpr);
   620 
   621     if (ident == NULL || ident->address == NULL || ident->username == NULL || fpr == NULL)
   622         return E_INVALIDARG;
   623 
   624     ::pEp_identity *_ident = new_identity(ident);
   625     ::pEp_free(_ident->fpr);
   626     _ident->fpr = NULL;
   627 
   628     ::PEP_STATUS status = ::generate_keypair(get_session(), _ident);
   629     assert(status != ::PEP_OUT_OF_MEMORY);
   630     if (status == ::PEP_OUT_OF_MEMORY) {
   631         ::free_identity(_ident);
   632         return E_OUTOFMEMORY;
   633     }
   634 
   635     if (_ident->fpr)
   636         *fpr = utf16_bstr(_ident->fpr).Detach();
   637 
   638     ::free_identity(_ident);
   639 
   640     if (status != ::PEP_STATUS_OK)
   641         return FAIL(L"generate_keypair");
   642 
   643     return S_OK;
   644 }
   645 
   646 STDMETHODIMP CpEpEngine::delete_keypair(BSTR fpr)
   647 {
   648     assert(fpr);
   649 
   650     if (fpr == NULL)
   651         return E_INVALIDARG;
   652 
   653     string _fpr = utf8_string(fpr);
   654 
   655     ::PEP_STATUS status = ::delete_keypair(get_session(), _fpr.c_str());
   656     assert(status != PEP_OUT_OF_MEMORY);
   657     if (status == PEP_OUT_OF_MEMORY)
   658         return E_OUTOFMEMORY;
   659 
   660     if (status != ::PEP_STATUS_OK)
   661         return FAIL(L"delete_keypair");
   662     else
   663         return S_OK;
   664 }
   665 
   666 STDMETHODIMP CpEpEngine::import_key(BSTR key_data)
   667 {
   668     assert(key_data);
   669 
   670     if (key_data == NULL)
   671         return E_INVALIDARG;
   672 
   673     string _key_data = utf8_string(key_data);
   674 
   675     PEP_STATUS status = ::import_key(get_session(), _key_data.c_str(), _key_data.length());
   676     assert(status != PEP_OUT_OF_MEMORY);
   677     if (status == PEP_OUT_OF_MEMORY)
   678         return E_OUTOFMEMORY;
   679 
   680     if (status != pEp_STATUS_OK)
   681         return FAIL(L"import_key");
   682     else
   683         return S_OK;
   684 }
   685 
   686 STDMETHODIMP CpEpEngine::import_key_b(SAFEARRAY * key_data)
   687 {
   688     assert(key_data);
   689 
   690     if (key_data == NULL)
   691         return E_INVALIDARG;
   692 
   693     ::PEP_STATUS status = ::import_key(get_session(), (const char *) key_data->pvData, key_data->rgsabound[0].cElements);
   694     assert(status != ::PEP_OUT_OF_MEMORY);
   695     if (status == ::PEP_OUT_OF_MEMORY)
   696         return E_OUTOFMEMORY;
   697 
   698     if (status != ::PEP_STATUS_OK)
   699         return FAIL(L"import_key");
   700     else
   701         return S_OK;
   702 }
   703 
   704 STDMETHODIMP CpEpEngine::export_key(BSTR fpr, BSTR * key_data)
   705 {
   706     assert(fpr);
   707     assert(key_data);
   708 
   709     if (fpr == NULL || key_data == NULL)
   710         return E_INVALIDARG;
   711 
   712     string _fpr = utf8_string(fpr);
   713     char *_key_data = NULL;
   714     size_t _size = 0;
   715 
   716     ::PEP_STATUS status = ::export_key(get_session(), _fpr.c_str(), &_key_data, &_size);
   717     assert(status != ::PEP_OUT_OF_MEMORY);
   718     if (status == ::PEP_OUT_OF_MEMORY)
   719         return E_OUTOFMEMORY;
   720 
   721     if (status != ::PEP_STATUS_OK)
   722         return FAIL(L"export_key");
   723 
   724     _bstr_t b_key_data(utf16_string(_key_data).c_str());
   725     pEp_free(_key_data);
   726     *key_data = b_key_data.Detach();
   727 
   728     return S_OK;
   729 }
   730 
   731 STDMETHODIMP CpEpEngine::recv_key(BSTR pattern)
   732 {
   733     assert(pattern);
   734 
   735     if (pattern == NULL)
   736         return E_INVALIDARG;
   737 
   738     string _pattern = utf8_string(pattern);
   739 
   740     PEP_STATUS status = ::recv_key(get_session(), _pattern.c_str());
   741     assert(status != PEP_OUT_OF_MEMORY);
   742     if (status == PEP_OUT_OF_MEMORY)
   743         return E_OUTOFMEMORY;
   744 
   745     if (status != ::PEP_STATUS_OK)
   746         return FAIL(L"recv_key");
   747     else
   748         return S_OK;
   749 }
   750 
   751 STDMETHODIMP CpEpEngine::find_keys(BSTR pattern, LPSAFEARRAY * key_list)
   752 {
   753     assert(pattern);
   754     assert(key_list);
   755 
   756     if (pattern == NULL || key_list == NULL)
   757         return E_INVALIDARG;
   758 
   759     string _pattern = utf8_string(pattern);
   760     ::stringlist_t *_keylist = NULL;
   761 
   762     PEP_STATUS status = ::find_keys(get_session(), _pattern.c_str(), &_keylist);
   763     assert(status != PEP_OUT_OF_MEMORY);
   764     if (status == PEP_OUT_OF_MEMORY)
   765         return E_OUTOFMEMORY;
   766 
   767     if (status != ::PEP_STATUS_OK)
   768         return FAIL(L"find_keys");
   769 
   770     if (_keylist && _keylist->value) {
   771         *key_list = string_array(_keylist).Detach();
   772     }
   773     else {
   774         ::free_stringlist(_keylist);
   775         return FAIL(L"find_keys: no keys found");
   776     }
   777 
   778     ::free_stringlist(_keylist);
   779     return S_OK;
   780 }
   781 
   782 STDMETHODIMP CpEpEngine::send_key(BSTR pattern)
   783 {
   784     assert(pattern);
   785 
   786     if (pattern == NULL)
   787         return E_INVALIDARG;
   788 
   789     string _pattern = utf8_string(pattern);
   790 
   791     ::PEP_STATUS status = ::send_key(get_session(), _pattern.c_str());
   792 
   793     if (status != ::PEP_STATUS_OK)
   794         return FAIL(L"send_key");
   795     else
   796         return S_OK;
   797 }
   798 
   799 STDMETHODIMP CpEpEngine::examine_identity(pEp_identity_s * ident)
   800 {
   801     assert(ident);
   802     if (ident == NULL)
   803         return E_INVALIDARG;
   804 
   805     try {
   806         identity_queue->push_back(ident);
   807     }
   808     catch (bad_alloc) {
   809         return E_OUTOFMEMORY;
   810     }
   811 
   812     return S_OK;
   813 }
   814 
   815 STDMETHODIMP CpEpEngine::examine_myself(pEp_identity_s * myself)
   816 {
   817     assert(myself);
   818     if (myself == NULL)
   819         return E_INVALIDARG;
   820 
   821     pEp_identity_cpp _ident(myself);
   822     _ident.me = true;
   823 
   824     ::log_event(get_session(), "examine_myself", "debug", _ident.address.c_str(), NULL);
   825     try {
   826         identity_queue->push_front(_ident);
   827     }
   828     catch (bad_alloc) {
   829         return E_OUTOFMEMORY;
   830     }
   831 
   832     return S_OK;
   833 }
   834 
   835 STDMETHODIMP CpEpEngine::myself(struct pEp_identity_s *ident, struct pEp_identity_s *result)
   836 {
   837     assert(ident);
   838     assert(result);
   839 
   840     if (ident == NULL || result == NULL)
   841         return E_INVALIDARG;
   842 
   843     ::pEp_identity *_ident = new_identity(ident);
   844     assert(_ident);
   845     if (_ident == NULL)
   846         return E_OUTOFMEMORY;
   847 
   848     PEP_STATUS status = ::myself(get_session(), _ident);
   849 
   850     if (status == PEP_STATUS_OK) {
   851         assert(_ident->fpr);
   852         copy_identity(result, _ident);
   853         ::free_identity(_ident);
   854         return S_OK;
   855     }
   856     else {
   857         ::free_identity(_ident);
   858         if (status == PEP_OUT_OF_MEMORY)
   859             return E_OUTOFMEMORY;
   860         else
   861             return FAIL(L"myself");
   862     }
   863 }
   864 
   865 STDMETHODIMP CpEpEngine::update_identity(struct pEp_identity_s *ident, struct pEp_identity_s *result)
   866 {
   867     assert(ident);
   868     assert(result);
   869 
   870     if (ident == NULL || result == NULL)
   871         return E_INVALIDARG;
   872 
   873     ::pEp_identity *_ident = new_identity(ident);
   874     assert(_ident);
   875     if (_ident == NULL)
   876         return E_OUTOFMEMORY;
   877 
   878     PEP_STATUS status = ::update_identity(get_session(), _ident);
   879 
   880     if (status == PEP_STATUS_OK) {
   881         assert(_ident->fpr);
   882         copy_identity(result, _ident);
   883         if (_ident->comm_type == PEP_ct_unknown || _ident->comm_type == PEP_ct_key_expired) {
   884             pEp_identity_cpp _ident_cpp(_ident);
   885             identity_queue->push_back(_ident_cpp);
   886         }
   887         ::free_identity(_ident);
   888         return S_OK;
   889     }
   890     else {
   891         ::free_identity(_ident);
   892         if (status == PEP_OUT_OF_MEMORY)
   893             return E_OUTOFMEMORY;
   894         else
   895             return FAIL(L"update_identity");
   896     }
   897 }
   898 
   899 ::pEp_identity * CpEpEngine::retrieve_next_identity(void *management)
   900 {
   901     assert(management);
   902     identity_queue_t *iq = (identity_queue_t *) management;
   903 
   904     do /* poll queue */ {
   905         if (iq->size())
   906             break;
   907         ::Sleep(100);
   908     } while (true);
   909 
   910     ::pEp_identity *_ident;
   911     pEp_identity_cpp& ident = iq->front();
   912 
   913     if (ident.address.size() == 0) {
   914         delete iq;
   915         return NULL;
   916     }
   917 
   918     _ident = new_identity(ident);
   919     iq->pop_front();
   920 
   921     return _ident;
   922 }
   923 
   924 HRESULT CpEpEngine::error(_bstr_t msg)
   925 {
   926     _bstr_t helpFile = L"";
   927     _bstr_t source = L"pEp COM Adapter";
   928 
   929     ICreateErrorInfo *cei;
   930     if (SUCCEEDED(CreateErrorInfo(&cei))) {
   931         cei->SetDescription(msg);
   932         cei->SetGUID(__uuidof(IpEpEngine));
   933         cei->SetHelpContext(0);
   934         cei->SetHelpFile(helpFile);
   935         cei->SetSource(source);
   936 
   937         IErrorInfo *errinfo;
   938         if (SUCCEEDED(cei->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &errinfo))) {
   939             SetErrorInfo(0, errinfo);
   940             errinfo->Release();
   941         }
   942         cei->Release();
   943     }
   944     return E_FAIL;
   945 }