// CpEpEngine.cpp : Implementation of CpEpEngine #include "stdafx.h" #include "CpEpEngine.h" using namespace std; using namespace pEp::utility; // CpEpEngine STDMETHODIMP CpEpEngine::InterfaceSupportsErrorInfo(REFIID riid) { static const IID* const arr[] = { &IID_IpEpEngine }; for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++) { if (InlineIsEqualGUID(*arr[i],riid)) return S_OK; } return S_FALSE; } #define FAIL(msg) error(msg) STDMETHODIMP CpEpEngine::verbose_logging(VARIANT_BOOL enable) { verbose_mode = enable != VARIANT_FALSE; return S_OK; } STDMETHODIMP CpEpEngine::passive_mode(VARIANT_BOOL enable) { ::config_passive_mode(get_session(), enable != VARIANT_FALSE); return S_OK; } STDMETHODIMP CpEpEngine::unencrypted_subject(VARIANT_BOOL enable) { ::config_unencrypted_subject(get_session(), enable != VARIANT_FALSE); return S_OK; } STDMETHODIMP CpEpEngine::log(BSTR title, BSTR entity, BSTR description, BSTR comment) { string _title; string _entity; string _description; string _comment; HRESULT result = S_OK; assert(title); if (title) _title = utf8_string(title); else result = E_INVALIDARG; assert(entity); if (entity) _entity = utf8_string(entity); else result = E_INVALIDARG; if (description) _description = utf8_string(description); if (comment) _comment = utf8_string(comment); if (result != S_OK) return result; PEP_STATUS _status = ::log_event(get_session(), _title.c_str(), _entity.c_str(), _description.c_str(), _comment.c_str()); assert(_status == PEP_STATUS_OK); if (_status != PEP_STATUS_OK) return FAIL(L"log_event"); else return S_OK; } STDMETHODIMP CpEpEngine::decrypt(BSTR ctext, BSTR * ptext, LPSAFEARRAY * key_list, pEp_STATUS * status) { assert(ctext); assert(ptext); assert(key_list); assert(status); if (ctext == NULL || ptext == NULL || key_list == NULL || status == NULL) { if (ptext) *ptext = NULL; if (key_list) *key_list = NULL; if (status) *status = pEp_UNENCRYPTED; return E_INVALIDARG; } string _ctext = utf8_string(ctext); char *_ptext = NULL; size_t _psize = 0; ::stringlist_t *_keylist = NULL; PEP_STATUS _status; _status = ::decrypt_and_verify(get_session(), _ctext.c_str(), _ctext.size(), &_ptext, &_psize, &_keylist); assert(_status != PEP_OUT_OF_MEMORY); if (_status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; *status = (pEp_STATUS) _status; if (_ptext == NULL) { if (_keylist) { string msg; if (_keylist->value[0] != 0) { msg = _keylist->value; } else { for (::stringlist_t *s = _keylist->next; s != NULL; s = s->next) { if (s->value) { msg += s->value; msg += ";"; } } } ::free_stringlist(_keylist); return FAIL(utf16_bstr(msg)); } else return FAIL(L"cannot decrypt"); } *ptext = utf16_bstr(_ptext); pEp_free(_ptext); if (_keylist && _keylist->value) *key_list = string_array(_keylist); else *key_list = NULL; ::free_stringlist(_keylist); return S_OK; } STDMETHODIMP CpEpEngine::decrypt_b(BSTR ctext, LPSAFEARRAY * ptext, LPSAFEARRAY * key_list, pEp_STATUS * status) { assert(ctext); assert(ptext); assert(key_list); assert(status); if (ctext == NULL || ptext == NULL || key_list == NULL || status == NULL) { if (ptext) *ptext = NULL; if (key_list) *key_list = NULL; if (status) *status = pEp_UNENCRYPTED; return E_INVALIDARG; } // Welcome to Windoze string hell! char *_ctext = NULL; _bstr_t bstr_ctext(ctext, true); int w_csize = bstr_ctext.length() + 1; int _csize = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, (wchar_t *) bstr_ctext, w_csize, NULL, 0, NULL, NULL); if (_csize) { _ctext = new char[_csize]; WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, (wchar_t *) bstr_ctext, w_csize, _ctext, _csize, NULL, NULL); } char *_ptext = NULL; size_t _psize = 0; ::stringlist_t *_keylist = NULL; PEP_STATUS _status; _status = ::decrypt_and_verify(get_session(), _ctext, _csize, &_ptext, &_psize, &_keylist); assert(_status != PEP_OUT_OF_MEMORY); delete[] _ctext; if (_status == PEP_OUT_OF_MEMORY) { ::free_stringlist(_keylist); return E_OUTOFMEMORY; } *status = (pEp_STATUS) _status; if (_ptext == NULL) { ::free_stringlist(_keylist); return FAIL(L"decrypt_and_verify"); } CComSafeArray sa_ptext; HRESULT _result = sa_ptext.Create(_psize, 0); assert(_result == S_OK); if (_result == E_OUTOFMEMORY) { pEp_free(_ptext); ::free_stringlist(_keylist); return E_OUTOFMEMORY; } else if (_result != S_OK) { pEp_free(_ptext); ::free_stringlist(_keylist); return FAIL(L"CComSafeArray::Create"); } memcpy(sa_ptext.m_psa->pvData, _ptext, _psize); *ptext = sa_ptext.Detach(); ::pEp_free(_ptext); if (_keylist && _keylist->value) *key_list = string_array(_keylist); else *key_list = NULL; ::free_stringlist(_keylist); return S_OK; } STDMETHODIMP CpEpEngine::verify(BSTR text, BSTR signature, LPSAFEARRAY * key_list, pEp_STATUS * verify_status) { assert(text); assert(signature); assert(key_list); if (text == NULL || signature == NULL || key_list == NULL) return E_INVALIDARG; string _text = utf8_string(text); string _signature = utf8_string(signature); ::stringlist_t *_keylist = NULL; PEP_STATUS _status; _status = ::verify_text(get_session(), _text.c_str(), _text.size(), _signature.c_str(), _signature.size(), &_keylist); assert(_status != PEP_OUT_OF_MEMORY); if (_status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (_status == PEP_DECRYPT_WRONG_FORMAT || _status == PEP_UNKNOWN_ERROR) return FAIL(L"verify_text"); *verify_status = (pEp_STATUS) _status; if (_keylist && _keylist->value) *key_list = string_array(_keylist); else *key_list = NULL; ::free_stringlist(_keylist); return S_OK; } STDMETHODIMP CpEpEngine::encrypt(SAFEARRAY * key_list, BSTR ptext, BSTR * ctext, pEp_STATUS * status) { assert(key_list); assert(ptext); assert(ctext); assert(status); if (ctext == NULL || ptext == NULL || key_list == NULL || status == NULL) { if (ctext) *ctext = NULL; if (status) *status = pEp_UNKNOWN_ERROR; return E_INVALIDARG; } HRESULT result = S_OK; ::stringlist_t *_keylist = new_stringlist(key_list); string _ptext = utf8_string(ptext); char *_ctext = NULL; size_t _csize = 0; PEP_STATUS _status; _status = ::encrypt_and_sign(get_session(), _keylist, _ptext.c_str(), _ptext.size(), &_ctext, &_csize); assert(_status != PEP_OUT_OF_MEMORY); ::free_stringlist(_keylist); if (_status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; *status = (pEp_STATUS) _status; if (_ctext == NULL) return FAIL(L"encrypt_and_sign"); *ctext = utf16_bstr(_ctext); pEp_free(_ctext); return S_OK; } STDMETHODIMP CpEpEngine::encrypt_b(SAFEARRAY * key_list, SAFEARRAY * ptext, BSTR * ctext, pEp_STATUS * status) { assert(key_list); assert(ptext); assert(ctext); assert(status); if (ctext == NULL || ptext == NULL || key_list == NULL || status == NULL) { if (ctext) *ctext = NULL; if (status) *status = pEp_UNKNOWN_ERROR; return E_INVALIDARG; } HRESULT result = S_OK; ::stringlist_t *_keylist = new_stringlist(key_list); char *_ctext = NULL; size_t _csize = 0; ::PEP_STATUS _status; _status = ::encrypt_and_sign(get_session(), _keylist, (const char *) ptext->pvData, ptext->rgsabound[0].cElements, &_ctext, &_csize); assert(_status != PEP_OUT_OF_MEMORY); ::free_stringlist(_keylist); if (_status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; *status = (pEp_STATUS) _status; if (_ctext == NULL) return FAIL(L"encrypt_and_sign"); *status = (pEp_STATUS) _status; wchar_t *w_ctext = NULL; int w_csize = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, _ctext, _csize, NULL, 0); if (w_csize) { w_ctext = new wchar_t[w_csize + 1]; MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, _ctext, _csize, w_ctext, w_csize); w_ctext[w_csize] = 0; // this is for debugging; Visual Studio will crash without that if you're unlucky } *ctext = ::SysAllocStringLen(w_ctext, w_csize); assert(ctext); delete[] w_ctext; pEp_free(_ctext); if (ctext == NULL) return E_OUTOFMEMORY; return S_OK; } STDMETHODIMP CpEpEngine::trustword(LONG value, BSTR lang, BSTR * word) { assert(value >= 0 && value <= 65535); assert(word); HRESULT result = S_OK; uint16_t _value = 0; if (value < 0 || value > 65535) result = E_INVALIDARG; else _value = (uint16_t) value; string _lang = "en"; if (lang) { _lang = utf8_string(lang); if (_lang.length() != 2) result = E_INVALIDARG; } if (word == NULL) result = E_INVALIDARG; if (result != S_OK) return result; char *_word = NULL; size_t _wsize = 0; PEP_STATUS status = ::trustword(get_session(), _value, _lang.c_str(), &_word, &_wsize); assert(status != PEP_OUT_OF_MEMORY); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (_word == NULL) { *word = NULL; return FAIL(L"trustword"); } else { *word = utf16_bstr(_word); pEp_free(_word); return S_OK; } } STDMETHODIMP CpEpEngine::trustwords(BSTR fpr, BSTR lang, LONG max_words, BSTR * words) { assert(fpr); assert(max_words >= 0); assert(words); HRESULT result = S_OK; string _fpr; if (fpr) _fpr = utf8_string(fpr); else result = E_INVALIDARG; string _lang; if (lang) { _lang = utf8_string(lang); if (_lang.length()) { if (_lang.length() != 2) result = E_INVALIDARG; } else _lang = "en"; } else _lang = "en"; if (max_words < 0) result = E_INVALIDARG; if (words == NULL) result = E_INVALIDARG; if (result != S_OK) return result; char *_words = NULL; size_t _wsize = 0; PEP_STATUS status = ::trustwords(get_session(), _fpr.c_str(), _lang.c_str(), &_words, &_wsize, max_words); assert(status != PEP_OUT_OF_MEMORY); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (_words == NULL) { *words = NULL; return FAIL(L"trustwords"); } else { *words = utf16_bstr(_words); pEp_free(_words); return S_OK; } } STDMETHODIMP CpEpEngine::get_crashdump_log(LONG maxlines, BSTR * log) { assert(maxlines >= 0); assert(log); if (!(maxlines >= 0 && log)) return E_INVALIDARG; char *_log; PEP_STATUS status = ::get_crashdump_log(get_session(), (int) maxlines, &_log); assert(status == PEP_STATUS_OK); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (status != PEP_STATUS_OK || _log == NULL) return FAIL(L"get_crashdump_log"); *log = utf16_bstr(_log); pEp_free(_log); return S_OK; } STDMETHODIMP CpEpEngine::get_languagelist(BSTR * languages) { assert(languages); if (!languages) return E_INVALIDARG; char *_languages; PEP_STATUS status = ::get_languagelist(get_session(), &_languages); assert(status == PEP_STATUS_OK); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (status != PEP_STATUS_OK || _languages == NULL) return FAIL(L"get_languagelist"); *languages = utf16_bstr(_languages); pEp_free(_languages); return S_OK; } STDMETHODIMP CpEpEngine::get_phrase(BSTR lang, LONG phrase_id, BSTR * phrase) { assert(lang && phrase_id >= 0 && phrase); if (!(lang && phrase_id >= 0 && phrase)) return E_INVALIDARG; string _lang = utf8_string(lang); assert(_lang.length() == 2); if (_lang.length() != 2) return E_INVALIDARG; char *_phrase; PEP_STATUS status = ::get_phrase(get_session(), _lang.c_str(), (int) phrase_id, &_phrase); assert(status == PEP_STATUS_OK); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (status != PEP_STATUS_OK || _phrase == NULL) return FAIL(L"get_phrase"); *phrase = utf16_bstr(_phrase); pEp_free(_phrase); return S_OK; } STDMETHODIMP CpEpEngine::get_identity(BSTR address, BSTR user_id, pEp_identity_s * ident) { assert(address); assert(user_id); assert(ident); if (address == NULL) return E_INVALIDARG; if (user_id == NULL) return E_INVALIDARG; if (ident == NULL) return E_INVALIDARG; string _address = utf8_string(address); string _user_id = utf8_string(user_id); ::pEp_identity *_ident = NULL; PEP_STATUS status = ::get_identity(get_session(), _address.c_str(), _user_id.c_str(), &_ident); assert(status != PEP_OUT_OF_MEMORY); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (_ident == NULL) { return FAIL(L"get_identity"); } copy_identity(ident, _ident); ::free_identity(_ident); return S_OK; } STDMETHODIMP CpEpEngine::set_identity(pEp_identity_s * ident) { assert(ident); assert(ident->address); assert(ident->fpr); assert(ident->username); assert(ident->user_id); if (ident == NULL || ident->address == NULL || ident->fpr == NULL || ident->username == NULL || ident->user_id == NULL) return E_INVALIDARG; ::pEp_identity *_ident = new_identity(ident); ::PEP_STATUS status = ::set_identity(get_session(), _ident); ::free_identity(_ident); if (status != ::PEP_STATUS_OK) return FAIL(L"set_identity"); else return S_OK; } STDMETHODIMP CpEpEngine::generate_keypair(pEp_identity_s * ident, BSTR * fpr) { assert(ident); assert(ident->address); assert(ident->username); assert(fpr); if (ident == NULL || ident->address == NULL || ident->username == NULL || fpr == NULL) return E_INVALIDARG; ::pEp_identity *_ident = new_identity(ident); ::pEp_free(_ident->fpr); _ident->fpr = NULL; ::PEP_STATUS status = ::generate_keypair(get_session(), _ident); assert(status != ::PEP_OUT_OF_MEMORY); if (status == ::PEP_OUT_OF_MEMORY) { ::free_identity(_ident); return E_OUTOFMEMORY; } if (_ident->fpr) *fpr = utf16_bstr(_ident->fpr); ::free_identity(_ident); if (status != ::PEP_STATUS_OK) return FAIL(L"generate_keypair"); return S_OK; } STDMETHODIMP CpEpEngine::delete_keypair(BSTR fpr) { assert(fpr); if (fpr == NULL) return E_INVALIDARG; string _fpr = utf8_string(fpr); ::PEP_STATUS status = ::delete_keypair(get_session(), _fpr.c_str()); assert(status != PEP_OUT_OF_MEMORY); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (status != ::PEP_STATUS_OK) return FAIL(L"delete_keypair"); else return S_OK; } STDMETHODIMP CpEpEngine::import_key(BSTR key_data) { assert(key_data); if (key_data == NULL) return E_INVALIDARG; string _key_data = utf8_string(key_data); PEP_STATUS status = ::import_key(get_session(), _key_data.c_str(), _key_data.length(), NULL); assert(status != PEP_OUT_OF_MEMORY); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (status != pEp_STATUS_OK) return FAIL(L"import_key"); else return S_OK; } STDMETHODIMP CpEpEngine::import_key_b(SAFEARRAY * key_data) { assert(key_data); if (key_data == NULL) return E_INVALIDARG; ::PEP_STATUS status = ::import_key(get_session(), (const char *) key_data->pvData, key_data->rgsabound[0].cElements, NULL); assert(status != ::PEP_OUT_OF_MEMORY); if (status == ::PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (status != ::PEP_STATUS_OK) return FAIL(L"import_key"); else return S_OK; } STDMETHODIMP CpEpEngine::export_key(BSTR fpr, BSTR * key_data) { assert(fpr); assert(key_data); if (fpr == NULL || key_data == NULL) return E_INVALIDARG; string _fpr = utf8_string(fpr); char *_key_data = NULL; size_t _size = 0; ::PEP_STATUS status = ::export_key(get_session(), _fpr.c_str(), &_key_data, &_size); assert(status != ::PEP_OUT_OF_MEMORY); if (status == ::PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (status != ::PEP_STATUS_OK) return FAIL(L"export_key"); _bstr_t b_key_data(utf16_string(_key_data).c_str()); pEp_free(_key_data); *key_data = b_key_data.Detach(); return S_OK; } STDMETHODIMP CpEpEngine::recv_key(BSTR pattern) { assert(pattern); if (pattern == NULL) return E_INVALIDARG; string _pattern = utf8_string(pattern); PEP_STATUS status = ::recv_key(get_session(), _pattern.c_str()); assert(status != PEP_OUT_OF_MEMORY); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (status != ::PEP_STATUS_OK) return FAIL(L"recv_key"); else return S_OK; } STDMETHODIMP CpEpEngine::find_keys(BSTR pattern, LPSAFEARRAY * key_list) { assert(pattern); assert(key_list); if (pattern == NULL || key_list == NULL) return E_INVALIDARG; string _pattern = utf8_string(pattern); ::stringlist_t *_keylist = NULL; PEP_STATUS status = ::find_keys(get_session(), _pattern.c_str(), &_keylist); assert(status != PEP_OUT_OF_MEMORY); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (status != ::PEP_STATUS_OK) return FAIL(L"find_keys"); if (_keylist && _keylist->value) { *key_list = string_array(_keylist); } else { ::free_stringlist(_keylist); return FAIL(L"find_keys: no keys found"); } ::free_stringlist(_keylist); return S_OK; } STDMETHODIMP CpEpEngine::send_key(BSTR pattern) { assert(pattern); if (pattern == NULL) return E_INVALIDARG; string _pattern = utf8_string(pattern); ::PEP_STATUS status = ::send_key(get_session(), _pattern.c_str()); if (status != ::PEP_STATUS_OK) return FAIL(L"send_key"); else return S_OK; } STDMETHODIMP CpEpEngine::start_keyserver_lookup() { if (identity_queue.load()) return S_OK; identity_queue.store(new identity_queue_t()); keymanagement_thread = new thread(::do_keymanagement, retrieve_next_identity, (void *) identity_queue.load()); return S_OK; } STDMETHODIMP CpEpEngine::stop_keyserver_lookup() { if (identity_queue.load() == NULL) return S_OK; identity_queue_t *_iq = identity_queue.load(); identity_queue.store(NULL); pEp_identity_cpp shutdown; _iq->push_front(shutdown); keymanagement_thread->join(); delete keymanagement_thread; keymanagement_thread = NULL; delete _iq; return S_OK; } STDMETHODIMP CpEpEngine::examine_identity(pEp_identity_s * ident) { assert(ident); if (ident == NULL) return E_INVALIDARG; if (identity_queue.load() == NULL) { try { identity_queue.load()->push_back(ident); } catch (bad_alloc) { return E_OUTOFMEMORY; } } return S_OK; } STDMETHODIMP CpEpEngine::myself(struct pEp_identity_s *ident, struct pEp_identity_s *result) { assert(ident); assert(result); if (ident == NULL || result == NULL) return E_INVALIDARG; ::pEp_identity *_ident = new_identity(ident); assert(_ident); if (_ident == NULL) return E_OUTOFMEMORY; // DEBUG CODE - REMOVE BEFORE RELEASE! // sync_handshake_result_s handshakeResult; // // HRESULT res = Fire_ShowHandshake(ident, result, &handshakeResult); // // HRESULT res2 = Fire_TestEvent(15, _bstr_t( "hallo")); PEP_STATUS status = ::myself(get_session(), _ident); if (status == PEP_STATUS_OK) { assert(_ident->fpr); copy_identity(result, _ident); ::free_identity(_ident); return S_OK; } else { ::free_identity(_ident); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; else return FAIL(L"myself"); } } STDMETHODIMP CpEpEngine::update_identity(struct pEp_identity_s *ident, struct pEp_identity_s *result) { assert(ident); assert(result); if (ident == NULL || result == NULL) return E_INVALIDARG; ::pEp_identity *_ident = new_identity(ident); assert(_ident); if (_ident == NULL) return E_OUTOFMEMORY; PEP_STATUS status = ::update_identity(get_session(), _ident); if (status == PEP_STATUS_OK) { assert(_ident->fpr); copy_identity(result, _ident); ::free_identity(_ident); return S_OK; } else { ::free_identity(_ident); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; else return FAIL(L"update_identity"); } } STDMETHODIMP CpEpEngine::key_compromized(struct pEp_identity_s *ident) { ::pEp_identity *_ident; assert(ident); try { _ident = new_identity(ident); } catch (bad_alloc&) { return E_OUTOFMEMORY; } catch (exception&) { return E_FAIL; } PEP_STATUS status = ::key_compromized(get_session(), _ident); free_identity(_ident); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (status == PEP_KEY_NOT_FOUND) return FAIL(L"key not found"); if (status != ::PEP_STATUS_OK) return FAIL(L"cannot revoke compromized key"); return S_OK; } STDMETHODIMP CpEpEngine::key_reset_trust(struct pEp_identity_s *ident) { ::pEp_identity *_ident; assert(ident); try { _ident = new_identity(ident); } catch (bad_alloc&) { return E_OUTOFMEMORY; } catch (exception&) { return E_FAIL; } PEP_STATUS status = ::key_reset_trust(get_session(), _ident); free_identity(_ident); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; if (status == PEP_KEY_NOT_FOUND) return FAIL(L"key not found"); if (status != ::PEP_STATUS_OK) return FAIL(L"cannot reset trust"); return S_OK; } int CpEpEngine::examine_identity(pEp_identity *ident, void *management) { assert(ident); assert(management); if (!(ident && management)) return -1; CpEpEngine *me = (CpEpEngine *) management; if (me->identity_queue.load() == NULL) return 0; try { me->identity_queue.load()->push_back(ident); } catch (exception&) { return -1; } return 0; } ::pEp_identity * CpEpEngine::retrieve_next_identity(void *management) { assert(management); identity_queue_t *iq = (identity_queue_t *) management; do /* poll queue */ { if (iq->size()) break; ::Sleep(100); } while (true); ::pEp_identity *_ident; pEp_identity_cpp& ident = iq->front(); if (ident.address.size() == 0) return NULL; _ident = ident.to_pEp_identity(); iq->pop_front(); return _ident; } PEP_STATUS CpEpEngine::messageToSend(void * obj, const message *msg) { assert(msg); if (msg == NULL) return PEP_ILLEGAL_VALUE; text_message _msg; memset(&_msg, 0, sizeof(text_message)); text_message_from_C(&_msg, msg); CpEpEngine *me = (CpEpEngine *) obj; HRESULT r = me->Fire_MessageToSend(&_msg); assert(r == S_OK); clear_text_message(&_msg); if (r == E_OUTOFMEMORY) return PEP_OUT_OF_MEMORY; if (r != S_OK) return PEP_UNKNOWN_ERROR; return PEP_STATUS_OK; } PEP_STATUS CpEpEngine::showHandshake(void * obj, const pEp_identity *self, const pEp_identity *partner) { assert(self && partner); if (!(self && partner)) return PEP_ILLEGAL_VALUE; pEp_identity_s _self; copy_identity(&_self, self); pEp_identity_s _partner; copy_identity(&_partner, partner); CpEpEngine *me = (CpEpEngine *) obj; sync_handshake_result_s _result; HRESULT r = me->Fire_ShowHandshake(&_self, &_partner, &_result); assert(r == S_OK); clear_identity_s(_self); clear_identity_s(_partner); if (r == E_OUTOFMEMORY) return PEP_OUT_OF_MEMORY; if (r != S_OK) return PEP_UNKNOWN_ERROR; PEP_STATUS status = deliverHandshakeResult(me->get_session(), (sync_handshake_result) (int) _result); return status; } STDMETHODIMP CpEpEngine::blacklist_add(BSTR fpr) { assert(fpr); string _fpr = utf8_string(fpr); PEP_STATUS status = ::blacklist_add(get_session(), _fpr.c_str()); assert(status == PEP_STATUS_OK); if (status != PEP_STATUS_OK) return FAIL(L"blacklist_add failed in pEp engine"); return S_OK; } STDMETHODIMP CpEpEngine::blacklist_delete(BSTR fpr) { assert(fpr); string _fpr = utf8_string(fpr); PEP_STATUS status = ::blacklist_delete(get_session(), _fpr.c_str()); assert(status == PEP_STATUS_OK); if (status != PEP_STATUS_OK) return FAIL(L"blacklist_delete failed in pEp engine"); return S_OK; } STDMETHODIMP CpEpEngine::blacklist_is_listed(BSTR fpr, VARIANT_BOOL *listed) { assert(fpr); assert(listed); string _fpr = utf8_string(fpr); bool result; PEP_STATUS status = ::blacklist_is_listed(get_session(), _fpr.c_str(), &result); assert(status == PEP_STATUS_OK); if (status != PEP_STATUS_OK) return FAIL(L"blacklist_is_listed failed in pEp engine"); *listed = result ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } STDMETHODIMP CpEpEngine::blacklist_retrieve(SAFEARRAY **blacklist) { assert(blacklist); ::stringlist_t *_blacklist = NULL; PEP_STATUS status = ::blacklist_retrieve(get_session(), &_blacklist); assert(status == PEP_STATUS_OK); if (status != PEP_STATUS_OK) return FAIL(L"blacklist_retrieve failed in pEp engine"); assert(_blacklist); *blacklist = string_array(_blacklist); return S_OK; } HRESULT CpEpEngine::error(_bstr_t msg) { _bstr_t helpFile = L""; _bstr_t source = L"pEp COM Adapter"; ICreateErrorInfo *cei; if (SUCCEEDED(CreateErrorInfo(&cei))) { cei->SetDescription(msg); cei->SetGUID(__uuidof(IpEpEngine)); cei->SetHelpContext(0); cei->SetHelpFile(helpFile); cei->SetSource(source); IErrorInfo *errinfo; if (SUCCEEDED(cei->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &errinfo))) { SetErrorInfo(0, errinfo); errinfo->Release(); } cei->Release(); } return E_FAIL; } STDMETHODIMP CpEpEngine::encrypt_message(text_message * src, text_message * dst, SAFEARRAY * extra) { assert(src); assert(dst); ::message *_src = text_message_to_C(src); ::message *msg_dst; ::stringlist_t *_extra = new_stringlist(extra); PEP_STATUS status = ::encrypt_message(get_session(), _src, _extra, &msg_dst, PEP_enc_pieces); ::free_stringlist(_extra); if (status == PEP_STATUS_OK) text_message_from_C(dst, msg_dst); else text_message_from_C(dst, _src); ::free_message(msg_dst); ::free_message(_src); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; return S_OK; } STDMETHODIMP CpEpEngine::decrypt_message(text_message * src, text_message * dst, SAFEARRAY ** keylist, pEp_color *rating) { assert(src); assert(dst); assert(keylist); assert(rating); *keylist = NULL; *rating = pEp_rating_undefined; ::message *_src = text_message_to_C(src); ::message *msg_dst = NULL; ::stringlist_t *_keylist; ::PEP_color _rating; PEP_decrypt_flags_t flags = 0; PEP_STATUS status = ::decrypt_message(get_session(), _src, &msg_dst, &_keylist, &_rating, &flags); // TODO : output decrypt flags. if (msg_dst) text_message_from_C(dst, msg_dst); ::free_message(_src); ::free_message(msg_dst); if (_keylist) { *keylist = string_array(_keylist); free_stringlist(_keylist); } *rating = (pEp_color) _rating; return S_OK; } STDMETHODIMP CpEpEngine::outgoing_message_color(text_message *msg, pEp_color * pVal) { assert(msg); assert(pVal); ::message *_msg = text_message_to_C(msg); PEP_color _color; PEP_STATUS status = ::outgoing_message_color(get_session(), _msg, &_color); if (status != PEP_STATUS_OK) return FAIL(L"cannot get message color"); *pVal = (pEp_color) _color; return S_OK; } STDMETHODIMP CpEpEngine::identity_color(struct pEp_identity_s *ident, pEp_color * pVal) { ::pEp_identity *_ident; assert(ident); assert(pVal); try { _ident = new_identity(ident); } catch (bad_alloc&) { return E_OUTOFMEMORY; } catch (exception&) { return E_FAIL; } PEP_color _color; PEP_STATUS status = ::identity_color(get_session(), _ident, &_color); free_identity(_ident); if (status != PEP_STATUS_OK) return FAIL(L"cannot get message color"); *pVal = (pEp_color) _color; return S_OK; } STDMETHODIMP CpEpEngine::trust_personal_key(struct pEp_identity_s *ident, struct pEp_identity_s *result) { ::pEp_identity *_ident; assert(ident); assert(result); try { _ident = new_identity(ident); } catch (bad_alloc&) { return E_OUTOFMEMORY; } catch (exception&) { return E_FAIL; } if (verbose_mode) { stringstream ss; ss << "trust_personal_key called with "; ss << utf8_string(ident->address); ss << L": "; ss << ident->comm_type; verbose(ss.str()); } PEP_STATUS status = ::trust_personal_key(get_session(), _ident); if (verbose_mode) { stringstream ss; ss << "result "; ss << status; ss << " for "; ss << _ident->address; ss << L": "; ss << _ident->comm_type; verbose(ss.str()); } if (status == PEP_STATUS_OK) copy_identity(result, _ident); free_identity(_ident); if (status == PEP_OUT_OF_MEMORY) return E_OUTOFMEMORY; else if (status != PEP_STATUS_OK) return FAIL(L"failure while executing trust_personal_key()"); return S_OK; } // Event callbacks STDMETHODIMP CpEpEngine::register_callbacks(IpEpEngineCallbacks* new_callbacks) { callbacks cbs = get_callbacks(); vector& vec = cbs; vec.push_back(new_callbacks); new_callbacks->AddRef(); return S_OK; } STDMETHODIMP CpEpEngine::unregister_callbacks(IpEpEngineCallbacks* obsolete_callbacks) { callbacks cbs = get_callbacks(); vector& vec = cbs; auto position = std::find(vec.begin(), vec.end(), obsolete_callbacks); if (position != vec.end()) { vec.erase(position); obsolete_callbacks->Release(); return S_OK; } return S_FALSE; } HRESULT CpEpEngine::Fire_MessageToSend(text_message * msg) { callbacks cbs = get_callbacks(); vector& vec = cbs; assert(msg); for (auto it = vec.begin(); it != vec.end(); ++it) { auto res = (*it)->MessageToSend(msg); if (res != S_OK) return res; } return S_OK; } HRESULT CpEpEngine::Fire_ShowHandshake(pEp_identity_s * self, pEp_identity_s * partner, sync_handshake_result_s * result) { callbacks cbs = get_callbacks(); vector& vec = cbs; assert(self); assert(partner); assert(result); for (auto it = vec.begin(); it != vec.end(); ++it) { auto res = (*it)->ShowHandshake(self, partner, result); if (res != S_OK) return res; } return S_OK; }