p≡p COM server adapter
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2237 lines
56 KiB

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