C++11 library providing functionality common to all adapters.
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.

537 lines
16 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. // This file is under GNU General Public License 3.0
  2. // see LICENSE.txt
  3. #include "message_cache.hh"
  4. #include <cassert>
  5. #include <cstring>
  6. #include <climits>
  7. #include <random>
  8. pEp::MessageCache pEp::message_cache;
  9. namespace pEp {
  10. MessageCache::MessageCache()
  11. {
  12. std::random_device r;
  13. std::default_random_engine e(r());
  14. std::uniform_int_distribution<long long> u(1, LLONG_MAX >> 1);
  15. id_range = u(e);
  16. next_id = u(e);
  17. }
  18. PEP_STATUS MessageCache::cache_decrypt_message(
  19. PEP_SESSION session,
  20. message *src,
  21. message **dst,
  22. stringlist_t **keylist,
  23. PEP_rating *rating,
  24. PEP_decrypt_flags_t *flags)
  25. {
  26. return message_cache.decrypt_message(session, src, dst, keylist, rating, flags);
  27. }
  28. PEP_STATUS MessageCache::cache_mime_encode_message(
  29. int one,
  30. const message *msg,
  31. bool omit_fields,
  32. char **mimetext,
  33. bool has_pEp_msg_attachment)
  34. {
  35. which _one = (which)one;
  36. return message_cache.mime_encode_message(_one, msg, omit_fields, mimetext, has_pEp_msg_attachment);
  37. }
  38. PEP_STATUS MessageCache::cache_mime_decode_message(
  39. const char *mimetext,
  40. size_t size,
  41. message **msg,
  42. bool *has_possible_pEp_msg)
  43. {
  44. return message_cache.mime_decode_message(mimetext, size, msg, has_possible_pEp_msg);
  45. }
  46. PEP_STATUS MessageCache::cache_encrypt_message(
  47. PEP_SESSION session,
  48. message *src,
  49. stringlist_t *extra,
  50. message **dst,
  51. PEP_enc_format enc_format,
  52. PEP_encrypt_flags_t flags)
  53. {
  54. return message_cache.encrypt_message(session, src, extra, dst, enc_format, flags);
  55. }
  56. PEP_STATUS MessageCache::cache_encrypt_message_for_self(
  57. PEP_SESSION session,
  58. pEp_identity *target_id,
  59. message *src,
  60. stringlist_t *extra,
  61. message **dst,
  62. PEP_enc_format enc_format,
  63. PEP_encrypt_flags_t flags)
  64. {
  65. return message_cache
  66. .encrypt_message_for_self(session, target_id, src, extra, dst, enc_format, flags);
  67. }
  68. PEP_STATUS MessageCache::cache_release(std::string id)
  69. {
  70. message_cache.release(id);
  71. return PEP_STATUS_OK;
  72. }
  73. void MessageCache::release(std::string id)
  74. {
  75. try {
  76. std::lock_guard<std::mutex> l(message_cache._mtx);
  77. ::free_message(_cache.at(id).src);
  78. ::free_message(_cache.at(id).dst);
  79. _cache.erase(id);
  80. } catch (...) {
  81. }
  82. }
  83. static char *dup(const char *src)
  84. {
  85. if (!src)
  86. return nullptr;
  87. char *dst = ::strdup(src);
  88. assert(dst);
  89. if (!dst)
  90. throw std::bad_alloc();
  91. return dst;
  92. }
  93. static timestamp *dup(const ::timestamp *src)
  94. {
  95. if (!src)
  96. return nullptr;
  97. ::timestamp *dst = ::timestamp_dup(src);
  98. if (!dst)
  99. throw std::bad_alloc();
  100. return dst;
  101. }
  102. static ::pEp_identity *dup(const ::pEp_identity *src)
  103. {
  104. if (!src)
  105. return nullptr;
  106. ::pEp_identity *dst = ::identity_dup(src);
  107. if (!dst)
  108. throw std::bad_alloc();
  109. return dst;
  110. }
  111. static identity_list *dup(const ::identity_list *src)
  112. {
  113. if (!src)
  114. return nullptr;
  115. ::identity_list *dst = ::identity_list_dup(src);
  116. if (!dst)
  117. throw std::bad_alloc();
  118. return dst;
  119. }
  120. static stringlist_t *dup(const ::stringlist_t *src)
  121. {
  122. if (!src)
  123. return nullptr;
  124. ::stringlist_t *dst = ::stringlist_dup(src);
  125. if (!dst)
  126. throw std::bad_alloc();
  127. return dst;
  128. }
  129. static stringpair_list_t *dup(const ::stringpair_list_t *src)
  130. {
  131. if (!src)
  132. return nullptr;
  133. ::stringpair_list_t *dst = ::stringpair_list_dup(src);
  134. if (!dst)
  135. throw std::bad_alloc();
  136. return dst;
  137. }
  138. static ::message_ref_list *dup(const ::message_ref_list *src)
  139. {
  140. if (!src)
  141. return nullptr;
  142. ::message_ref_list *dst = (::message_ref_list *)::calloc(1, sizeof(::message_ref_list));
  143. assert(dst);
  144. if (!dst)
  145. throw std::bad_alloc();
  146. ::message_ref_list *d = dst;
  147. for (const message_ref_list *s = src; s; s = s->next) {
  148. d->msg_ref = s->msg_ref;
  149. if (s->next) {
  150. d->next = (::message_ref_list *)::calloc(1, sizeof(::message_ref_list));
  151. assert(d);
  152. if (!d)
  153. throw std::bad_alloc();
  154. d = d->next;
  155. }
  156. }
  157. return dst;
  158. }
  159. static bool emptystr(const char *str)
  160. {
  161. if (!(str && str[0]))
  162. return true;
  163. return false;
  164. }
  165. static ::message *empty_message_copy(const ::message *src, std::string _id = "", bool get_longmsg = false)
  166. {
  167. if (!src)
  168. return nullptr;
  169. ::message *dst = ::new_message(src->dir);
  170. if (!dst)
  171. throw std::bad_alloc();
  172. dst->id = dup(src->id);
  173. if (get_longmsg) {
  174. if (!emptystr(src->shortmsg)) {
  175. dst->shortmsg = dup(src->shortmsg);
  176. }
  177. // We need either longmsg or longmsg_formatted for a "message preview".
  178. if (!emptystr(src->longmsg)) {
  179. dst->longmsg = dup(src->longmsg);
  180. } else {
  181. if (!emptystr(src->longmsg_formatted)) {
  182. dst->longmsg_formatted = dup(src->longmsg_formatted);
  183. }
  184. }
  185. } else {
  186. // It is a pEp convention to return at least one of shortmsg, longmsg or longmsg_formatted.
  187. if (!emptystr(src->shortmsg)) {
  188. dst->shortmsg = dup(src->shortmsg);
  189. } else {
  190. if (!emptystr(src->longmsg)) {
  191. dst->longmsg = dup("pEp");
  192. } else {
  193. if (!emptystr(src->longmsg_formatted)) {
  194. dst->longmsg_formatted = dup("<pEp/>");
  195. }
  196. }
  197. }
  198. }
  199. // attachments are never copied
  200. dst->rawmsg_ref = src->rawmsg_ref;
  201. dst->rawmsg_size = src->rawmsg_size;
  202. dst->sent = dup(src->sent);
  203. dst->recv = dup(src->recv);
  204. dst->from = dup(src->from);
  205. dst->to = dup(src->to);
  206. dst->cc = dup(src->cc);
  207. dst->bcc = dup(src->bcc);
  208. dst->reply_to = dup(src->reply_to);
  209. dst->in_reply_to = dup(src->in_reply_to);
  210. dst->refering_msg_ref = src->refering_msg_ref;
  211. dst->references = dup(src->references);
  212. dst->refered_by = dup(src->refered_by);
  213. dst->keywords = dup(src->keywords);
  214. dst->comments = dup(src->comments);
  215. dst->enc_format = src->enc_format;
  216. dst->_sender_fpr = dup(src->_sender_fpr);
  217. if (_id == "") {
  218. dst->opt_fields = dup(src->opt_fields);
  219. } else {
  220. dst->opt_fields = ::new_stringpair_list(
  221. ::new_stringpair("X-pEp-Adapter-Cache-ID", _id.c_str()));
  222. if (!dst->opt_fields)
  223. throw std::bad_alloc();
  224. dst->opt_fields->next = dup(src->opt_fields);
  225. }
  226. return dst;
  227. }
  228. static void correctAttachmentsOrder(bloblist_t *&bl)
  229. {
  230. // only execute if there are exactly two attachments, both with
  231. // a non-empty MIME type
  232. if (bl && bl->next && !bl->next->next && !emptystr(bl->mime_type) &&
  233. !emptystr(bl->next->mime_type)) {
  234. // if this is most likely an PGP/MIME compliant format then correct
  235. // order of attachments
  236. if (std::string(bl->mime_type) == "application/octet-stream" &&
  237. std::string(bl->next->mime_type) == "application/pgp-encrypted") {
  238. bloblist_t *one = bl->next;
  239. bloblist_t *two = bl;
  240. bl = one;
  241. bl->next = two;
  242. bl->next->next = nullptr;
  243. }
  244. }
  245. }
  246. static void swapContent(::message *&part, ::message *&full)
  247. {
  248. free(part->longmsg);
  249. part->longmsg = full->longmsg;
  250. full->longmsg = nullptr;
  251. free(part->longmsg_formatted);
  252. part->longmsg_formatted = full->longmsg_formatted;
  253. full->longmsg_formatted = nullptr;
  254. free_bloblist(part->attachments);
  255. part->attachments = full->attachments;
  256. full->attachments = nullptr;
  257. }
  258. PEP_STATUS MessageCache::decrypt_message(
  259. PEP_SESSION session,
  260. message *src,
  261. message **dst,
  262. stringlist_t **keylist,
  263. PEP_rating *rating,
  264. PEP_decrypt_flags_t *flags)
  265. {
  266. if (!src || cacheID(src) == "")
  267. return PEP_ILLEGAL_VALUE;
  268. ::message *_msg;
  269. std::string _id = cacheID(src);
  270. {
  271. std::lock_guard<std::mutex> l(_mtx);
  272. _msg = message_cache._cache.at(_id).src;
  273. swapContent(src, _msg);
  274. }
  275. // if attachments got reordered correct
  276. correctAttachmentsOrder(src->attachments);
  277. ::message *_dst = nullptr;
  278. PEP_STATUS status = ::decrypt_message(session, src, &_dst, keylist, rating, flags);
  279. *dst = empty_message_copy(_dst, _id, true);
  280. {
  281. std::lock_guard<std::mutex> l(_mtx);
  282. swapContent(_msg, src);
  283. ::free_message(message_cache._cache.at(_id).dst);
  284. message_cache._cache.at(_id).dst = _dst;
  285. }
  286. return status;
  287. }
  288. PEP_STATUS MessageCache::mime_encode_message(
  289. which one,
  290. const message *msg,
  291. bool omit_fields,
  292. char **mimetext,
  293. bool has_pEp_msg_attachment)
  294. {
  295. if (!msg || cacheID(msg) == "")
  296. return PEP_ILLEGAL_VALUE;
  297. if (one != msg_src && one != msg_dst)
  298. return PEP_ILLEGAL_VALUE;
  299. ::message *_msg = empty_message_copy(msg);
  300. if (one == msg_src) {
  301. std::lock_guard<std::mutex> l(_mtx);
  302. ::message *_src = _cache.at(cacheID(msg)).src;
  303. swapContent(_msg, _src);
  304. } else /* msg_dst */ {
  305. std::lock_guard<std::mutex> l(_mtx);
  306. ::message *_dst = _cache.at(cacheID(msg)).dst;
  307. swapContent(_msg, _dst);
  308. }
  309. removeCacheID(_msg);
  310. PEP_STATUS status = ::mime_encode_message(_msg, omit_fields, mimetext, has_pEp_msg_attachment);
  311. ::free_message(_msg);
  312. cache_release(cacheID(msg));
  313. return status;
  314. }
  315. void MessageCache::generateCacheID(::message *msg)
  316. {
  317. std::string _range = std::to_string(id_range);
  318. std::string _id = std::to_string(next_id++);
  319. std::string cid = _range + _id;
  320. // if opt_fields is an empty list generate a new list
  321. if (!msg->opt_fields || !msg->opt_fields->value) {
  322. free_stringpair_list(msg->opt_fields);
  323. msg->opt_fields = ::new_stringpair_list(
  324. ::new_stringpair("X-pEp-Adapter-Cache-ID", cid.c_str()));
  325. if (!msg->opt_fields)
  326. throw std::bad_alloc();
  327. } else {
  328. // add the cache ID as first field to an existing list
  329. auto spl = msg->opt_fields;
  330. msg->opt_fields = ::new_stringpair_list(
  331. ::new_stringpair("X-pEp-Adapter-Cache-ID", cid.c_str()));
  332. if (!msg->opt_fields) {
  333. msg->opt_fields = spl;
  334. throw std::bad_alloc();
  335. }
  336. msg->opt_fields->next = spl;
  337. }
  338. }
  339. std::string MessageCache::cacheID(const ::message *msg)
  340. {
  341. for (auto spl = msg->opt_fields; spl && spl->value; spl = spl->next) {
  342. assert(spl->value->key);
  343. if (spl->value->key && std::string(spl->value->key) == "X-pEp-Adapter-Cache-ID") {
  344. assert(spl->value->value);
  345. if (spl->value->value)
  346. return spl->value->value;
  347. else
  348. return "";
  349. }
  350. }
  351. return "";
  352. }
  353. void MessageCache::removeCacheID(::message *msg)
  354. {
  355. // if the first element in the list is the cache ID then skip
  356. if (msg->opt_fields && msg->opt_fields->value && msg->opt_fields->value->key &&
  357. std::string(msg->opt_fields->value->key) == "X-pEp-Adapter-Cache-ID") {
  358. auto n = msg->opt_fields->next;
  359. msg->opt_fields->next = nullptr;
  360. ::free_stringpair_list(msg->opt_fields);
  361. msg->opt_fields = n;
  362. } else {
  363. // go through the list and remove
  364. ::stringpair_list_t *prev = nullptr;
  365. for (auto spl = msg->opt_fields; spl && spl->value; spl = spl->next) {
  366. assert(spl->value->key);
  367. if (spl->value->key && std::string(spl->value->key) == "X-pEp-Adapter-Cache-ID") {
  368. auto next = spl->next;
  369. spl->next = nullptr;
  370. ::free_stringpair_list(spl);
  371. prev->next = next;
  372. break;
  373. }
  374. prev = spl;
  375. }
  376. }
  377. }
  378. PEP_STATUS MessageCache::mime_decode_message(
  379. const char *mimetext,
  380. size_t size,
  381. message **msg,
  382. bool *has_possible_pEp_msg)
  383. {
  384. ::message *_msg = nullptr;
  385. PEP_STATUS status = ::mime_decode_message(mimetext, size, &_msg, has_possible_pEp_msg);
  386. if (status)
  387. return status;
  388. generateCacheID(_msg);
  389. *msg = empty_message_copy(_msg);
  390. {
  391. std::lock_guard<std::mutex> l(_mtx);
  392. message_cache._cache.emplace(std::make_pair(cacheID(_msg), cache_entry(_msg, nullptr)));
  393. }
  394. return status;
  395. }
  396. PEP_STATUS MessageCache::encrypt_message(
  397. PEP_SESSION session,
  398. message *src,
  399. stringlist_t *extra,
  400. message **dst,
  401. PEP_enc_format enc_format,
  402. PEP_encrypt_flags_t flags)
  403. {
  404. ::message *_msg;
  405. std::string _id = cacheID(src);
  406. {
  407. std::lock_guard<std::mutex> l(_mtx);
  408. _msg = message_cache._cache.at(_id).src;
  409. swapContent(src, _msg);
  410. }
  411. ::message *_dst = nullptr;
  412. PEP_STATUS status = ::encrypt_message(session, src, extra, &_dst, enc_format, flags);
  413. *dst = empty_message_copy(_dst, _id);
  414. {
  415. std::lock_guard<std::mutex> l(_mtx);
  416. swapContent(_msg, src);
  417. ::free_message(message_cache._cache.at(_id).dst);
  418. message_cache._cache.at(_id).dst = _dst;
  419. }
  420. return status;
  421. }
  422. PEP_STATUS MessageCache::encrypt_message_for_self(
  423. PEP_SESSION session,
  424. pEp_identity *target_id,
  425. message *src,
  426. stringlist_t *extra,
  427. message **dst,
  428. PEP_enc_format enc_format,
  429. PEP_encrypt_flags_t flags)
  430. {
  431. ::message *_msg;
  432. std::string _id = cacheID(src);
  433. {
  434. std::lock_guard<std::mutex> l(_mtx);
  435. _msg = message_cache._cache.at(_id).src;
  436. swapContent(src, _msg);
  437. }
  438. ::message *_dst = nullptr;
  439. PEP_STATUS status = ::encrypt_message_for_self(
  440. session,
  441. target_id,
  442. src,
  443. extra,
  444. &_dst,
  445. enc_format,
  446. flags);
  447. *dst = empty_message_copy(_dst, _id);
  448. {
  449. std::lock_guard<std::mutex> l(_mtx);
  450. swapContent(_msg, src);
  451. ::free_message(message_cache._cache.at(_id).dst);
  452. message_cache._cache.at(_id).dst = _dst;
  453. }
  454. return status;
  455. }
  456. }; // namespace pEp