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.

3288 lines
91 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
2 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
2 years ago
2 years ago
1 year ago
1 year ago
1 year ago
  1. /**
  2. * @file etpan_mime.c
  3. * @brief File description for doxygen missing. FIXME
  4. * @license GNU General Public License 3.0 - see LICENSE.txt
  5. */
  6. #include "etpan_mime.h"
  7. #ifndef mailmime_param_new_with_data
  8. #include <libetpan/mailprivacy_tools.h>
  9. #endif
  10. #include "pEp_internal.h"
  11. #include "platform.h"
  12. #include "mime.h"
  13. #include "wrappers.h"
  14. #include "resource_id.h"
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <assert.h>
  18. #include <errno.h>
  19. #define MAX_MESSAGE_ID 128
  20. #define MAX_IMF_LINE_LEN 998
  21. static bool ascii_exceeds_line_length(const char* data, size_t size) {
  22. const char* curr_pos = data;
  23. const char* last_pos = data;
  24. const char* end_pos = data + size;
  25. const char* crlf = "\r\n";
  26. while ((curr_pos + MAX_IMF_LINE_LEN) < end_pos) {
  27. last_pos = curr_pos;
  28. curr_pos = strnstr(curr_pos, crlf, end_pos - curr_pos);
  29. if (!curr_pos)
  30. return true;
  31. if (curr_pos - last_pos > MAX_IMF_LINE_LEN)
  32. return true;
  33. curr_pos += 2;
  34. }
  35. return false;
  36. }
  37. /**
  38. * @internal
  39. *
  40. * <!-- generate_boundary() -->
  41. *
  42. * @brief TODO
  43. *
  44. *
  45. */
  46. static char * generate_boundary(void)
  47. {
  48. char id[MAX_MESSAGE_ID];
  49. // no cryptographically strong random needed here
  50. const long value1 = random();
  51. const long value2 = random();
  52. const long value3 = random();
  53. const long value4 = random();
  54. snprintf(id, MAX_MESSAGE_ID, "%.4lx%.4lx%.4lx%.4lx", value1, value2,
  55. value3, value4);
  56. return strdup(id);
  57. }
  58. struct mailmime * part_new_empty(
  59. struct mailmime_content * content,
  60. struct mailmime_fields * mime_fields,
  61. stringpair_list_t* param_keyvals,
  62. int force_single
  63. )
  64. {
  65. struct mailmime * build_info;
  66. clist * list = NULL;
  67. int r;
  68. int mime_type;
  69. char * attr_name = NULL;
  70. char * attr_value = NULL;
  71. struct mailmime_parameter * param = NULL;
  72. clist * parameters = NULL;
  73. char *boundary = NULL;
  74. list = NULL;
  75. if (force_single) {
  76. mime_type = MAILMIME_SINGLE;
  77. }
  78. else {
  79. switch (content->ct_type->tp_type) {
  80. case MAILMIME_TYPE_DISCRETE_TYPE:
  81. mime_type = MAILMIME_SINGLE;
  82. break;
  83. case MAILMIME_TYPE_COMPOSITE_TYPE:
  84. switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
  85. case MAILMIME_COMPOSITE_TYPE_MULTIPART:
  86. mime_type = MAILMIME_MULTIPLE;
  87. break;
  88. case MAILMIME_COMPOSITE_TYPE_MESSAGE:
  89. if (strcasecmp(content->ct_subtype, "rfc822") == 0)
  90. mime_type = MAILMIME_MESSAGE;
  91. else
  92. mime_type = MAILMIME_SINGLE;
  93. break;
  94. default:
  95. goto enomem;
  96. }
  97. break;
  98. default:
  99. goto enomem;
  100. }
  101. }
  102. if (mime_type == MAILMIME_MULTIPLE) {
  103. list = clist_new();
  104. assert(list);
  105. if (list == NULL)
  106. goto enomem;
  107. attr_name = strdup("boundary");
  108. assert(attr_name);
  109. if (attr_name == NULL)
  110. goto enomem;
  111. boundary = generate_boundary();
  112. assert(boundary);
  113. attr_value = boundary;
  114. if (attr_value == NULL)
  115. goto enomem;
  116. param = mailmime_parameter_new(attr_name, attr_value);
  117. assert(param);
  118. if (param == NULL)
  119. goto enomem;
  120. attr_name = NULL;
  121. attr_value = NULL;
  122. if (content->ct_parameters == NULL) {
  123. parameters = clist_new();
  124. assert(parameters);
  125. if (parameters == NULL)
  126. goto enomem;
  127. }
  128. else {
  129. parameters = content->ct_parameters;
  130. }
  131. r = clist_append(parameters, param);
  132. if (r)
  133. goto enomem;
  134. param = NULL;
  135. if (content->ct_parameters == NULL)
  136. content->ct_parameters = parameters;
  137. }
  138. if (param_keyvals) {
  139. stringpair_list_t* cur;
  140. for (cur = param_keyvals; cur; cur = cur->next) {
  141. attr_name = strdup(cur->value->key);
  142. attr_value = strdup(cur->value->value);
  143. param = mailmime_parameter_new(attr_name, attr_value);
  144. assert(param);
  145. if (param == NULL)
  146. goto enomem;
  147. attr_name = NULL;
  148. attr_value = NULL;
  149. if (content->ct_parameters == NULL) {
  150. parameters = clist_new();
  151. assert(parameters);
  152. if (parameters == NULL)
  153. goto enomem;
  154. }
  155. else {
  156. parameters = content->ct_parameters;
  157. }
  158. r = clist_append(parameters, param);
  159. if (r)
  160. goto enomem;
  161. param = NULL;
  162. if (content->ct_parameters == NULL)
  163. content->ct_parameters = parameters;
  164. }
  165. }
  166. build_info = mailmime_new(mime_type, NULL, 0, mime_fields, content, NULL,
  167. NULL, NULL, list, NULL, NULL);
  168. if (build_info == NULL)
  169. goto enomem;
  170. return build_info;
  171. enomem:
  172. if (list)
  173. clist_free(list);
  174. free(attr_name);
  175. free(attr_value);
  176. if (content->ct_parameters == NULL)
  177. if (parameters)
  178. clist_free(parameters);
  179. if (param)
  180. mailmime_parameter_free(param);
  181. return NULL;
  182. }
  183. struct mailmime * get_pgp_encrypted_part(void)
  184. {
  185. struct mailmime * mime = NULL;
  186. struct mailmime_fields * mime_fields = NULL;
  187. struct mailmime_content * content = NULL;
  188. int r;
  189. content = mailmime_content_new_with_str("application/pgp-encrypted");
  190. if (content == NULL)
  191. goto enomem;
  192. mime_fields = mailmime_fields_new_empty();
  193. if (mime_fields == NULL)
  194. goto enomem;
  195. mime = part_new_empty(content, mime_fields, NULL, 1);
  196. if (mime == NULL)
  197. goto enomem;
  198. mime_fields = NULL;
  199. content = NULL;
  200. r = mailmime_set_body_text(mime, "Version: 1\n", 10);
  201. if (r != 0)
  202. goto enomem;
  203. return mime;
  204. enomem:
  205. if (content)
  206. mailmime_content_free(content);
  207. if (mime_fields)
  208. mailmime_fields_free(mime_fields);
  209. if (mime)
  210. mailmime_free(mime);
  211. return NULL;
  212. }
  213. struct mailmime * get_text_part(
  214. pEp_rid_list_t* resource,
  215. const char * mime_type,
  216. const char * text,
  217. size_t length,
  218. int encoding_type
  219. )
  220. {
  221. char * disposition_name = NULL;
  222. struct mailmime_fields * mime_fields = NULL;
  223. struct mailmime * mime = NULL;
  224. struct mailmime_content * content = NULL;
  225. struct mailmime_parameter * param = NULL;
  226. struct mailmime_disposition * disposition = NULL;
  227. struct mailmime_mechanism * encoding = NULL;
  228. char* content_id = NULL;
  229. int r;
  230. if (resource != NULL && resource->rid != NULL) {
  231. switch (resource->rid_type) {
  232. case PEP_RID_CID:
  233. content_id = strdup(resource->rid);
  234. break;
  235. case PEP_RID_FILENAME:
  236. default:
  237. disposition_name = strdup(resource->rid);
  238. if (disposition_name == NULL)
  239. goto enomem;
  240. disposition =
  241. mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
  242. disposition_name, NULL, NULL, NULL, (size_t) -1);
  243. if (disposition == NULL)
  244. goto enomem;
  245. disposition_name = NULL;
  246. break;
  247. }
  248. }
  249. if (encoding_type) {
  250. encoding = mailmime_mechanism_new(encoding_type, NULL);
  251. if (encoding == NULL)
  252. goto enomem;
  253. }
  254. mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
  255. disposition, NULL);
  256. if (mime_fields == NULL)
  257. goto enomem;
  258. encoding = NULL;
  259. disposition = NULL;
  260. content_id = NULL;
  261. content = mailmime_content_new_with_str(mime_type);
  262. if (content == NULL)
  263. goto enomem;
  264. if (encoding_type != MAILMIME_MECHANISM_7BIT) {
  265. param = mailmime_param_new_with_data("charset", "utf-8");
  266. r = clist_append(content->ct_parameters, param);
  267. if (r != 0)
  268. goto enomem;
  269. }
  270. mime = part_new_empty(content, mime_fields, NULL, 1);
  271. if (mime == NULL)
  272. goto enomem;
  273. content = NULL;
  274. mime_fields = NULL;
  275. if (text) {
  276. r = mailmime_set_body_text(mime, (char *) text, length);
  277. if (r != 0)
  278. goto enomem;
  279. }
  280. return mime;
  281. enomem:
  282. free(disposition_name);
  283. if (mime_fields)
  284. mailmime_fields_free(mime_fields);
  285. if (mime)
  286. mailmime_free(mime);
  287. if (content)
  288. mailmime_content_free(content);
  289. if (param)
  290. mailmime_parameter_free(param);
  291. if (disposition)
  292. mailmime_disposition_free(disposition);
  293. if (encoding)
  294. mailmime_mechanism_free(encoding);
  295. return NULL;
  296. }
  297. struct mailmime * get_file_part(
  298. pEp_rid_list_t* resource,
  299. const char * mime_type,
  300. char * data,
  301. size_t length,
  302. bool is_nf_message_attachment // non-forwarded msg as att
  303. )
  304. {
  305. char * disposition_name = NULL;
  306. int encoding_type;
  307. struct mailmime_disposition * disposition = NULL;
  308. struct mailmime_mechanism * encoding = NULL;
  309. struct mailmime_content * content = NULL;
  310. struct mailmime * mime = NULL;
  311. struct mailmime_fields * mime_fields = NULL;
  312. char* content_id = NULL;
  313. int r;
  314. if (resource != NULL && resource->rid != NULL) {
  315. switch (resource->rid_type) {
  316. case PEP_RID_CID:
  317. content_id = strdup(resource->rid);
  318. disposition =
  319. mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
  320. NULL, NULL, NULL, NULL, (size_t) -1);
  321. if (disposition == NULL)
  322. goto enomem;
  323. break;
  324. case PEP_RID_FILENAME:
  325. default:
  326. disposition_name = strdup(resource->rid);
  327. if (disposition_name == NULL)
  328. goto enomem;
  329. disposition =
  330. mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
  331. disposition_name, NULL, NULL, NULL, (size_t) -1);
  332. if (disposition == NULL)
  333. goto enomem;
  334. disposition_name = NULL;
  335. break;
  336. }
  337. }
  338. content = mailmime_content_new_with_str(mime_type);
  339. if (content == NULL)
  340. goto enomem;
  341. encoding = NULL;
  342. bool already_ascii = !(must_chunk_be_encoded(data, length, true));
  343. // check to be sure, if it is already ascii, that line lengths aren't also
  344. // exceeded. Otherwise, we should base64-encode anyway.
  345. if (!is_nf_message_attachment && !already_ascii) {
  346. encoding_type = MAILMIME_MECHANISM_BASE64;
  347. encoding = mailmime_mechanism_new(encoding_type, NULL);
  348. if (encoding == NULL)
  349. goto enomem;
  350. }
  351. mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
  352. disposition, NULL);
  353. if (mime_fields == NULL)
  354. goto enomem;
  355. encoding = NULL;
  356. disposition = NULL;
  357. stringpair_list_t* extra_params = NULL;
  358. if (is_nf_message_attachment)
  359. extra_params = new_stringpair_list(new_stringpair("forwarded", "no"));
  360. mime = part_new_empty(content, mime_fields, extra_params, 1);
  361. free_stringpair_list(extra_params);
  362. if (mime == NULL)
  363. goto enomem;
  364. content = NULL;
  365. mime_fields = NULL;
  366. if(length > 0)
  367. {
  368. r = mailmime_set_body_text(mime, data, length);
  369. if (r != 0)
  370. goto enomem;
  371. }
  372. return mime;
  373. enomem:
  374. free(disposition_name);
  375. if (disposition)
  376. mailmime_disposition_free(disposition);
  377. if (encoding)
  378. mailmime_mechanism_free(encoding);
  379. if (content)
  380. mailmime_content_free(content);
  381. if (mime_fields)
  382. mailmime_fields_free(mime_fields);
  383. if (mime)
  384. mailmime_free(mime);
  385. return NULL;
  386. }
  387. struct mailmime * part_multiple_new(const char *type)
  388. {
  389. struct mailmime_fields *mime_fields = NULL;
  390. struct mailmime_content *content = NULL;
  391. struct mailmime *mp = NULL;
  392. mime_fields = mailmime_fields_new_empty();
  393. if (mime_fields == NULL)
  394. goto enomem;
  395. content = mailmime_content_new_with_str(type);
  396. if (content == NULL)
  397. goto enomem;
  398. mp = part_new_empty(content, mime_fields, NULL, 0);
  399. if (mp == NULL)
  400. goto enomem;
  401. return mp;
  402. enomem:
  403. if (content)
  404. mailmime_content_free(content);
  405. if (mime_fields)
  406. mailmime_fields_free(mime_fields);
  407. return NULL;
  408. }
  409. struct mailimf_field * _new_field(
  410. int type,
  411. _new_func_t new_func,
  412. void *value
  413. )
  414. {
  415. void *data = new_func(value);
  416. assert(data);
  417. if (data == NULL)
  418. return NULL;
  419. struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
  420. assert(result);
  421. if (result == NULL) {
  422. free(data);
  423. return NULL;
  424. }
  425. result->fld_type = type;
  426. result->fld_data.fld_return_path = data;
  427. return result;
  428. }
  429. void _free_field(struct mailimf_field *field)
  430. {
  431. if (field)
  432. free(field->fld_data.fld_return_path);
  433. free(field);
  434. }
  435. int _append_field(
  436. clist *list,
  437. int type,
  438. _new_func_t new_func,
  439. void *value
  440. )
  441. {
  442. int r;
  443. struct mailimf_field * field;
  444. assert(list);
  445. assert(new_func);
  446. assert(value);
  447. field = _new_field(type, new_func, value);
  448. if (field == NULL)
  449. return -1;
  450. r = clist_append(list, field);
  451. if (r)
  452. _free_field(field);
  453. return r;
  454. }
  455. // http://media2.giga.de/2014/02/Image-28.jpg
  456. struct mailimf_date_time * timestamp_to_etpantime(const timestamp *ts)
  457. {
  458. struct mailimf_date_time * result = calloc(1,
  459. sizeof(struct mailimf_date_time));
  460. assert(result);
  461. if (result == NULL)
  462. return NULL;
  463. assert(ts);
  464. result->dt_sec = ts->tm_sec;
  465. result->dt_min = ts->tm_min;
  466. result->dt_hour = ts->tm_hour;
  467. result->dt_day = ts->tm_mday;
  468. result->dt_month = ts->tm_mon + 1;
  469. result->dt_year = ts->tm_year + 1900;
  470. result->dt_zone = (int) (ts->tm_gmtoff / 36L);
  471. return result;
  472. }
  473. timestamp * etpantime_to_timestamp(const struct mailimf_date_time *et)
  474. {
  475. timestamp * result = calloc(1, sizeof(timestamp));
  476. assert(result);
  477. if (result == NULL)
  478. return NULL;
  479. assert(et);
  480. result->tm_sec = et->dt_sec;
  481. result->tm_min = et->dt_min;
  482. result->tm_hour = et->dt_hour;
  483. result->tm_mday = et->dt_day;
  484. result->tm_mon = et->dt_month - 1;
  485. result->tm_year = et->dt_year - 1900;
  486. result->tm_gmtoff = 36L * (long) et->dt_zone;
  487. // Normalize to UTC and then forget the offset.
  488. time_t t = timegm_with_gmtoff(result);
  489. gmtime_r(&t, result);
  490. result->tm_gmtoff = 0;
  491. return result;
  492. }
  493. struct mailimf_mailbox * mailbox_from_string(
  494. const char *name,
  495. const char *address
  496. )
  497. {
  498. assert(address);
  499. if (!address)
  500. return NULL;
  501. struct mailimf_mailbox *mb = NULL;
  502. char *_name = NULL;
  503. char *_address = NULL;
  504. _name = name ? strdup(name) : strdup("");
  505. if (_name == NULL)
  506. goto enomem;
  507. char* at = strstr(address, "@");
  508. if (!at) {
  509. // Presumed URI
  510. int added_char_len = 6; // " " @URI
  511. int new_addr_len = strlen(address) + added_char_len + 1;
  512. _address = calloc(new_addr_len, 1);
  513. if (_address == NULL)
  514. goto enomem;
  515. _address[0] = '"';
  516. strlcat(_address, address, new_addr_len);
  517. strlcat(_address, "\"@URI", new_addr_len);
  518. }
  519. else {
  520. _address = strdup(address);
  521. if (_address == NULL)
  522. goto enomem;
  523. }
  524. mb = mailimf_mailbox_new(_name, _address);
  525. assert(mb);
  526. if (mb == NULL)
  527. goto enomem;
  528. return mb;
  529. enomem:
  530. free(_name);
  531. free(_address);
  532. return NULL;
  533. }
  534. struct mailimf_field * create_optional_field(
  535. const char *field,
  536. const char *value
  537. )
  538. {
  539. char *_field = NULL;
  540. char *_value = NULL;
  541. struct mailimf_optional_field *optional_field = NULL;
  542. _field = strdup(field);
  543. if (_field == NULL)
  544. goto enomem;
  545. if (!must_field_value_be_encoded(value))
  546. _value = strdup(value);
  547. else
  548. _value = mailmime_encode_subject_header("utf-8", value, 0);
  549. if (_value == NULL)
  550. goto enomem;
  551. optional_field = mailimf_optional_field_new(_field, _value);
  552. if (optional_field == NULL)
  553. goto enomem;
  554. struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
  555. assert(result);
  556. if (result == NULL)
  557. goto enomem;
  558. result->fld_type = MAILIMF_FIELD_OPTIONAL_FIELD;
  559. result->fld_data.fld_optional_field = optional_field;
  560. return result;
  561. enomem:
  562. if (optional_field) {
  563. mailimf_optional_field_free(optional_field);
  564. }
  565. else {
  566. free(_field);
  567. free(_value);
  568. }
  569. return NULL;
  570. }
  571. int _append_optional_field(
  572. clist *list,
  573. const char *field,
  574. const char *value
  575. )
  576. {
  577. int r;
  578. struct mailimf_field * optional_field =
  579. create_optional_field(field, value);
  580. if (optional_field == NULL)
  581. return -1;
  582. r = clist_append(list, optional_field);
  583. if (r)
  584. mailimf_field_free(optional_field);
  585. return r;
  586. }
  587. clist * _get_fields(struct mailmime * mime)
  588. {
  589. clist * _fieldlist = NULL;
  590. assert(mime);
  591. if (mime->mm_data.mm_message.mm_fields &&
  592. mime->mm_data.mm_message.mm_fields->fld_list) {
  593. _fieldlist = mime->mm_data.mm_message.mm_fields->fld_list;
  594. }
  595. return _fieldlist;
  596. }
  597. struct mailmime_content * _get_content(struct mailmime * mime)
  598. {
  599. struct mailmime_content * content = NULL;
  600. assert(mime);
  601. if (mime->mm_data.mm_message.mm_msg_mime)
  602. content = mime->mm_data.mm_message.mm_msg_mime->mm_content_type;
  603. return content;
  604. }
  605. /* Return a list of identifier_type and resource id (filename, cid, etc) */
  606. pEp_rid_list_t* _get_resource_id_list(struct mailmime *mime)
  607. {
  608. clist * _fieldlist = NULL;
  609. assert(mime);
  610. if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
  611. _fieldlist = mime->mm_mime_fields->fld_list;
  612. else
  613. return NULL;
  614. clistiter *cur;
  615. pEp_rid_list_t* rid_list = NULL;
  616. pEp_rid_list_t** rid_list_curr_p = &rid_list;
  617. for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
  618. struct mailmime_field * _field = clist_content(cur);
  619. /* content_id */
  620. if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
  621. pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
  622. new_rid->rid_type = PEP_RID_CID;
  623. new_rid->rid = strdup(_field->fld_data.fld_id);
  624. *rid_list_curr_p = new_rid;
  625. rid_list_curr_p = &new_rid->next;
  626. }
  627. else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
  628. /* filename */
  629. if (_field->fld_data.fld_disposition &&
  630. _field->fld_data.fld_disposition->dsp_parms) {
  631. clist * _parmlist =
  632. _field->fld_data.fld_disposition->dsp_parms;
  633. clistiter *cur2;
  634. for (cur2 = clist_begin(_parmlist); cur2; cur2 =
  635. clist_next(cur2)) {
  636. struct mailmime_disposition_parm * param =
  637. clist_content(cur2);
  638. if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
  639. pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
  640. new_rid->rid_type = PEP_RID_FILENAME;
  641. new_rid->rid = strdup(param->pa_data.pa_filename);
  642. *rid_list_curr_p = new_rid;
  643. rid_list_curr_p = &new_rid->next;
  644. }
  645. }
  646. }
  647. }
  648. }
  649. /* Will almost certainly usually be a singleton, but we need to be able to decide */
  650. return rid_list;
  651. }
  652. /* FIXME: about to be obsoleted? */
  653. char * _get_filename_or_cid(struct mailmime *mime)
  654. {
  655. clist * _fieldlist = NULL;
  656. assert(mime);
  657. if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
  658. _fieldlist = mime->mm_mime_fields->fld_list;
  659. else
  660. return NULL;
  661. clistiter *cur;
  662. char* _temp_filename_ptr = NULL;
  663. for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
  664. struct mailmime_field * _field = clist_content(cur);
  665. if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
  666. /* We prefer CIDs to filenames when both are present */
  667. free(_temp_filename_ptr); /* can be null, it's ok */
  668. return build_uri("cid", _field->fld_data.fld_id);
  669. }
  670. else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
  671. if (_field->fld_data.fld_disposition &&
  672. _field->fld_data.fld_disposition->dsp_parms &&
  673. !_temp_filename_ptr) {
  674. clist * _parmlist =
  675. _field->fld_data.fld_disposition->dsp_parms;
  676. clistiter *cur2;
  677. for (cur2 = clist_begin(_parmlist); cur2; cur2 =
  678. clist_next(cur2)) {
  679. struct mailmime_disposition_parm * param =
  680. clist_content(cur2);
  681. if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
  682. _temp_filename_ptr = build_uri("file", param->pa_data.pa_filename);
  683. break;
  684. }
  685. }
  686. }
  687. }
  688. }
  689. /* Ok, it wasn't a CID */
  690. return _temp_filename_ptr;
  691. }
  692. /**
  693. * @internal
  694. *
  695. * <!-- parameter_has_value() -->
  696. *
  697. * @brief TODO
  698. *
  699. * @param[in] *content structmailmime_content
  700. * @param[in] *name constchar
  701. * @param[in] *value constchar
  702. *
  703. */
  704. static bool parameter_has_value(
  705. struct mailmime_content *content,
  706. const char *name,
  707. const char *value
  708. )
  709. {
  710. clistiter *cur;
  711. assert(name);
  712. assert(value);
  713. clist * list = content->ct_parameters;
  714. if (list == NULL)
  715. return false;
  716. for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
  717. struct mailmime_parameter * param = clist_content(cur);
  718. if (param &&
  719. param->pa_name && strcasecmp(name, param->pa_name) == 0 &&
  720. param->pa_value && strcasecmp(value, param->pa_value) == 0)
  721. return true;
  722. }
  723. return false;
  724. }
  725. bool _is_multipart(struct mailmime_content *content, const char *subtype)
  726. {
  727. assert(content);
  728. if (content->ct_type && content->ct_type->tp_type ==
  729. MAILMIME_TYPE_COMPOSITE_TYPE &&
  730. content->ct_type->tp_data.tp_composite_type &&
  731. content->ct_type->tp_data.tp_composite_type->ct_type ==
  732. MAILMIME_COMPOSITE_TYPE_MULTIPART) {
  733. if (subtype)
  734. return content->ct_subtype &&
  735. strcasecmp(content->ct_subtype, subtype) == 0;
  736. else
  737. return true;
  738. }
  739. return false;
  740. }
  741. bool _is_PGP_MIME(struct mailmime_content *content)
  742. {
  743. assert(content);
  744. if (_is_multipart(content, "encrypted") &&
  745. parameter_has_value(content, "protocol",
  746. "application/pgp-encrypted"))
  747. return true;
  748. return false;
  749. }
  750. bool _is_text_part(struct mailmime_content *content, const char *subtype)
  751. {
  752. assert(content);
  753. if (content->ct_type && content->ct_type->tp_type ==
  754. MAILMIME_TYPE_DISCRETE_TYPE &&
  755. content->ct_type->tp_data.tp_discrete_type &&
  756. content->ct_type->tp_data.tp_discrete_type->dt_type ==
  757. MAILMIME_DISCRETE_TYPE_TEXT) {
  758. if (subtype)
  759. return content->ct_subtype &&
  760. strcasecmp(content->ct_subtype, subtype) == 0;
  761. else
  762. return true;
  763. }
  764. return false;
  765. }
  766. /**
  767. * @internal
  768. *
  769. * <!-- _is_message_part() -->
  770. *
  771. * @brief TODO
  772. *
  773. * @param[in] *content structmailmime_content
  774. * @param[in] *subtype constchar
  775. *
  776. */
  777. bool _is_message_part(struct mailmime_content *content, const char* subtype) {
  778. assert(content);
  779. if (content->ct_type && content->ct_type->tp_type == MAILMIME_TYPE_COMPOSITE_TYPE &&
  780. content->ct_type->tp_data.tp_composite_type &&
  781. content->ct_type->tp_data.tp_composite_type->ct_type ==
  782. MAILMIME_COMPOSITE_TYPE_MESSAGE) {
  783. if (subtype)
  784. return content->ct_subtype &&
  785. strcasecmp(content->ct_subtype, subtype) == 0;
  786. else
  787. return true;
  788. }
  789. return false;
  790. }
  791. int _get_content_type(
  792. const struct mailmime_content *content,
  793. char **type,
  794. char **charset
  795. )
  796. {
  797. char *_type = NULL;
  798. char *_charset = NULL;
  799. assert(content);
  800. assert(type);
  801. assert(charset);
  802. *type = NULL;
  803. *charset = NULL;
  804. if (content->ct_subtype == NULL)
  805. return EINVAL;
  806. if (content->ct_type && content->ct_type->tp_data.tp_discrete_type) {
  807. size_t len;
  808. const char *_main_type;
  809. switch (content->ct_type->tp_data.tp_discrete_type->dt_type) {
  810. case MAILMIME_DISCRETE_TYPE_TEXT:
  811. _main_type = (content->ct_subtype &&
  812. strcasecmp(content->ct_subtype, "rfc822") == 0 ?
  813. "message" : "text");
  814. break;
  815. case MAILMIME_DISCRETE_TYPE_IMAGE:
  816. _main_type = "image";
  817. break;
  818. case MAILMIME_DISCRETE_TYPE_AUDIO:
  819. _main_type = "audio";
  820. break;
  821. case MAILMIME_DISCRETE_TYPE_VIDEO:
  822. _main_type = "video";
  823. break;
  824. case MAILMIME_DISCRETE_TYPE_APPLICATION:
  825. _main_type = "application";
  826. break;
  827. case MAILMIME_DISCRETE_TYPE_EXTENSION:
  828. _main_type = "extension";
  829. break;
  830. default:
  831. return EINVAL;
  832. }
  833. len = strlen(_main_type) + 1 + strlen(content->ct_subtype) + 1;
  834. _type = calloc(1, len);
  835. assert(_type);
  836. if (_type == NULL)
  837. return ENOMEM;
  838. strncpy(_type, _main_type, len);
  839. len -= strlen(_main_type);
  840. strncat(_type, "/", len--);
  841. strncat(_type, content->ct_subtype, len);
  842. if (content->ct_parameters) {
  843. clistiter *cur;
  844. for (cur = clist_begin(content->ct_parameters); cur; cur =
  845. clist_next(cur)) {
  846. struct mailmime_parameter * param = clist_content(cur);
  847. if (param && param->pa_name && strcasecmp(param->pa_name,
  848. "charset") == 0) {
  849. _charset = param->pa_value;
  850. break;
  851. }
  852. }
  853. if (_charset)
  854. *charset = strdup(_charset);
  855. }
  856. *type = _type;
  857. return 0;
  858. }
  859. return EINVAL;
  860. }
  861. // Only for null-terminated field strings.
  862. // can this field be transported as is without modification?)
  863. // (See rfc2822, section 2.2.3 - libetpan's handling isn't quite what
  864. // we need here.)
  865. bool must_field_value_be_encoded(const char* field_value) {
  866. if (!field_value)
  867. return false;
  868. return must_chunk_be_encoded((const void*)field_value, strlen(field_value), false);
  869. }
  870. bool must_chunk_be_encoded(const void* value, size_t size, bool ignore_fws) {
  871. const char* begin_ptr = (const char*)value;
  872. const char* end_ptr = begin_ptr + size;
  873. const char* cur_char_ptr = begin_ptr;
  874. while (cur_char_ptr < end_ptr) {
  875. char cur_char = *cur_char_ptr;
  876. if (cur_char > 127 || cur_char < 0)
  877. return true;
  878. // FIXME - do we need to deal with CRCRLF here?
  879. // I guess in the worst case, it gets encoded, which
  880. // is *supposed* to be harmless...
  881. if (!ignore_fws) {
  882. if (cur_char == '\r') {
  883. const char* next = cur_char_ptr + 1;
  884. const char* nextnext = next + 1;
  885. if (next >= end_ptr || nextnext >= end_ptr
  886. || *next != '\n'
  887. || (*nextnext != ' ' && *nextnext != '\t')) {
  888. return true;
  889. }
  890. }
  891. else if (cur_char == '\n') {
  892. const char* prev = cur_char_ptr - 1;
  893. if (prev == begin_ptr || *prev != '\r')
  894. return true;
  895. }
  896. }
  897. cur_char_ptr++;
  898. }
  899. return ascii_exceeds_line_length(value, size);
  900. }
  901. #define TMP_TEMPLATE "pEp.XXXXXXXXXXXXXXXXXXXX"
  902. #ifdef _WIN32
  903. #define PATH_SEP '\\'
  904. #else
  905. #define PATH_SEP '/'
  906. #endif
  907. static PEP_STATUS interpret_MIME(struct mailmime *mime,
  908. message *msg,
  909. bool* has_possible_pEp_msg);
  910. // This function was rewritten to use in-memory buffers instead of
  911. // temporary files when the pgp/mime support was implemented for
  912. // outlook, as the existing code did not work well on windows.
  913. /**
  914. * @internal
  915. *
  916. * <!-- render_mime() -->
  917. *
  918. * @brief TODO
  919. *
  920. * @param[in] *mime structmailmime
  921. * @param[in] **mimetext char
  922. *
  923. * @retval PEP_STATUS_OK
  924. * @retval PEP_OUT_OF_MEMORY out of memory
  925. * @retval any other value on error
  926. */
  927. static PEP_STATUS render_mime(struct mailmime *mime, char **mimetext)
  928. {
  929. PEP_STATUS status = PEP_STATUS_OK;
  930. int col;
  931. int r;
  932. size_t len;
  933. char* buf = NULL;
  934. MMAPString* buffer;
  935. buffer = mmap_string_new(NULL);
  936. if (buffer == NULL)
  937. goto enomem;
  938. col = 0;
  939. r = mailmime_write_mem(buffer, &col, mime);
  940. assert(r == MAILIMF_NO_ERROR);
  941. if (r == MAILIMF_ERROR_MEMORY)
  942. goto enomem;
  943. else if (r != MAILIMF_NO_ERROR)
  944. goto err_file;
  945. // we overallocate by 1 byte, so we have a terminating 0.
  946. len = buffer->len;
  947. buf = calloc(len + 1, 1);
  948. if (buf == NULL)
  949. goto enomem;
  950. memcpy(buf, buffer->str, len);
  951. mmap_string_free(buffer);
  952. *mimetext = buf;
  953. return PEP_STATUS_OK;
  954. err_file:
  955. status = PEP_CANNOT_CREATE_TEMP_FILE;
  956. goto pEp_error;
  957. enomem:
  958. status = PEP_OUT_OF_MEMORY;
  959. pEp_error:
  960. if (buffer)
  961. mmap_string_free(buffer);
  962. if (buf)
  963. free(buf);
  964. return status;
  965. }
  966. /**
  967. * @internal
  968. *
  969. * <!-- mime_attachment() -->
  970. *
  971. * @brief TODO
  972. *
  973. * @param[in] *blob bloblist_t
  974. * @param[in] **result structmailmime
  975. * @param[in] is_nf_message_attachment bool
  976. *
  977. * @retval PEP_STATUS_OK
  978. * @retval PEP_OUT_OF_MEMORY out of memory
  979. * @retval any other value on error
  980. *
  981. */
  982. static PEP_STATUS mime_attachment(
  983. bloblist_t *blob,
  984. struct mailmime **result,
  985. bool is_nf_message_attachment // non-forwarded msg as att
  986. )
  987. {
  988. PEP_STATUS status = PEP_STATUS_OK;
  989. struct mailmime * mime = NULL;
  990. char * mime_type;
  991. assert(blob);
  992. assert(result);
  993. *result = NULL;
  994. // TODO: It seems the pEp COM server adapter sends an empty string here,
  995. // which leads to a crash later. Thus, we workaround here by treating an
  996. // empty string as NULL. We need to check whether the bug really is here,
  997. // or the pEp COM server adapter needs to be changed.
  998. if (blob->mime_type == NULL || blob->mime_type[0] == '\0')
  999. mime_type = "application/octet-stream";
  1000. else
  1001. mime_type = blob->mime_type;
  1002. pEp_rid_list_t* resource = parse_uri(blob->filename);
  1003. mime = get_file_part(resource, mime_type, blob->value, blob->size,
  1004. is_nf_message_attachment);
  1005. free_rid_list(resource);
  1006. assert(mime);
  1007. if (mime == NULL)
  1008. goto enomem;
  1009. *result = mime;
  1010. return PEP_STATUS_OK;
  1011. enomem:
  1012. status = PEP_OUT_OF_MEMORY;
  1013. if (mime)
  1014. mailmime_free(mime);
  1015. return status;
  1016. }
  1017. // This ONLY deals with handling the body
  1018. // content when html parts are present - thus,
  1019. // text/plain and text/html of the body, and
  1020. // related inline attachments for the html
  1021. // part. Non-inline attachments are handled
  1022. // outside this call!!!!
  1023. //
  1024. // N.B. As a result, this will only touch the
  1025. // "contained message" of pEp 2.x messages
  1026. // on the initial encoding where it is turned
  1027. // into attachment data!!
  1028. /**
  1029. * @internal
  1030. *
  1031. * <!-- mime_html_text() -->
  1032. *
  1033. * @brief TODO
  1034. *
  1035. * @param[in] *plaintext constchar
  1036. * @param[in] *htmltext constchar
  1037. * @param[in] *attachments bloblist_t
  1038. * @param[in] **result structmailmime
  1039. *
  1040. * @retval PEP_STATUS_OK
  1041. * @retval PEP_OUT_OF_MEMORY out of memory
  1042. * @retval any other value on error
  1043. */
  1044. static PEP_STATUS mime_html_text(
  1045. const char *plaintext,
  1046. const char *htmltext,
  1047. bloblist_t *attachments,
  1048. struct mailmime **result
  1049. )
  1050. {
  1051. PEP_STATUS status = PEP_STATUS_OK;
  1052. struct mailmime * top_level_html_mime = NULL;
  1053. struct mailmime * mime = NULL;
  1054. struct mailmime * submime = NULL;
  1055. int r;
  1056. assert(plaintext);
  1057. assert(htmltext);
  1058. assert(result);
  1059. *result = NULL;
  1060. pEp_rid_list_t* resource = NULL;
  1061. bool already_ascii = false;
  1062. int encoding_type = 0;
  1063. if (*plaintext != '\0') {
  1064. mime = part_multiple_new("multipart/alternative");
  1065. assert(mime);
  1066. if (mime == NULL)
  1067. goto enomem;
  1068. // KB: pEpMIME transition comment - if we start getting
  1069. // underencoding errors here, the change to checking
  1070. // for ASCII and then encoding - or not - is one place
  1071. // to start looking.
  1072. int pt_length = strlen(plaintext);
  1073. already_ascii = !(must_chunk_be_encoded(plaintext, pt_length, true));
  1074. encoding_type = (already_ascii ? 0 : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  1075. submime = get_text_part(NULL, "text/plain", plaintext,
  1076. pt_length,
  1077. encoding_type);
  1078. // reset
  1079. already_ascii = false;
  1080. encoding_type = 0;
  1081. free_rid_list(resource);
  1082. resource = NULL;
  1083. assert(submime);
  1084. if (submime == NULL)
  1085. goto enomem;
  1086. r = mailmime_smart_add_part(mime, submime);
  1087. assert(r == MAILIMF_NO_ERROR);
  1088. if (r == MAILIMF_ERROR_MEMORY) {
  1089. goto enomem;
  1090. }
  1091. else {
  1092. // mailmime_smart_add_part() takes ownership of submime
  1093. submime = NULL;
  1094. }
  1095. }
  1096. bool inlined_attachments = false;
  1097. bloblist_t* traversal_ptr = attachments;
  1098. while (traversal_ptr) {
  1099. if (traversal_ptr->disposition == PEP_CONTENT_DISP_INLINE) {
  1100. inlined_attachments = true;
  1101. break;
  1102. }
  1103. traversal_ptr = traversal_ptr->next;
  1104. }
  1105. if (inlined_attachments) {
  1106. /* Noooooo... dirk, why do you do this to me? */
  1107. submime = part_multiple_new("multipart/related");
  1108. assert(submime);
  1109. if (submime == NULL)
  1110. goto enomem;
  1111. // This is where all of the html MIME stuff will go
  1112. top_level_html_mime = submime;
  1113. if (!mime)
  1114. mime = top_level_html_mime;
  1115. else {
  1116. r = mailmime_smart_add_part(mime, top_level_html_mime);
  1117. assert(r == MAILIMF_NO_ERROR);
  1118. if (r == MAILIMF_ERROR_MEMORY) {
  1119. goto enomem;
  1120. }
  1121. else {
  1122. // mailmime_smart_add_part() takes ownership of submime
  1123. submime = NULL;
  1124. }
  1125. }
  1126. }
  1127. else {
  1128. // Otherwise, html MIME stuff gets added to the top node
  1129. // - may be NULL if there's no multipart!
  1130. top_level_html_mime = mime;
  1131. }
  1132. // resource = new_rid_node(PEP_RID_FILENAME, "msg.html");
  1133. int ht_length = strlen(htmltext);
  1134. already_ascii = !(must_chunk_be_encoded(htmltext, ht_length, true));
  1135. encoding_type = (already_ascii ? 0 : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  1136. submime = get_text_part(NULL, "text/html", htmltext,
  1137. ht_length,
  1138. encoding_type);
  1139. free_rid_list(resource);
  1140. resource = NULL;
  1141. assert(submime);
  1142. if (submime == NULL)
  1143. goto enomem;
  1144. // IF there are no inlined attachments AND mime is NULL, then
  1145. // we just have an HTML body here and won't need to
  1146. // process inlined attachments - submime will actually be
  1147. // the mime root of from this function, at least.
  1148. if (!top_level_html_mime) {
  1149. mime = submime;
  1150. submime = NULL;
  1151. }
  1152. else {
  1153. r = mailmime_smart_add_part(top_level_html_mime, submime);
  1154. assert(r == MAILIMF_NO_ERROR);
  1155. if (r == MAILIMF_ERROR_MEMORY)
  1156. goto enomem;
  1157. else {
  1158. // mailmime_smart_add_part() takes ownership of submime
  1159. submime = NULL;
  1160. }
  1161. bloblist_t *_a;
  1162. // This will never have an embedded pEp message attachment
  1163. // sent for encoding here, so we don't need to pass down
  1164. // "(don't) transport encode this" info. If it's here and
  1165. // it's not an ASCII "text/*" attachment, it'll get encoded
  1166. for (_a = attachments; _a != NULL; _a = _a->next) {
  1167. if (_a->disposition != PEP_CONTENT_DISP_INLINE)
  1168. continue;
  1169. status = mime_attachment(_a, &submime, false);
  1170. if (status != PEP_STATUS_OK)
  1171. return PEP_UNKNOWN_ERROR; // FIXME
  1172. r = mailmime_smart_add_part(top_level_html_mime, submime);
  1173. assert(r == MAILIMF_NO_ERROR);
  1174. if (r == MAILIMF_ERROR_MEMORY) {
  1175. goto enomem;
  1176. }
  1177. else {
  1178. // mailmime_smart_add_part() takes ownership of submime
  1179. submime = NULL;
  1180. }
  1181. }
  1182. }
  1183. *result = mime;
  1184. return PEP_STATUS_OK;
  1185. enomem:
  1186. status = PEP_OUT_OF_MEMORY;
  1187. if (mime)
  1188. mailmime_free(mime);
  1189. if (submime)
  1190. mailmime_free(submime);
  1191. return status;
  1192. }
  1193. /**
  1194. * @internal
  1195. *
  1196. * <!-- identity_to_mailbox() -->
  1197. *
  1198. * @brief TODO
  1199. *
  1200. * @param[in] *ident constpEp_identity
  1201. *
  1202. */
  1203. static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
  1204. {
  1205. char *_username = NULL;
  1206. struct mailimf_mailbox *mb;
  1207. if (!ident->username)
  1208. _username = strdup("");
  1209. else
  1210. _username = must_field_value_be_encoded(ident->username) ?
  1211. mailmime_encode_subject_header("utf-8", ident->username, 0) :
  1212. strdup(ident->username);
  1213. assert(_username);
  1214. if (_username == NULL)
  1215. goto enomem;
  1216. mb = mailbox_from_string(_username, ident->address);
  1217. if (mb == NULL)
  1218. goto enomem;
  1219. free(_username);
  1220. _username = NULL;
  1221. return mb;
  1222. enomem:
  1223. free(_username);
  1224. return NULL;
  1225. }
  1226. /**
  1227. * @internal
  1228. *
  1229. * <!-- identity_to_mbl() -->
  1230. *
  1231. * @brief TODO
  1232. *
  1233. * @param[in] *ident constpEp_identity
  1234. *
  1235. */
  1236. static struct mailimf_mailbox_list * identity_to_mbl(
  1237. const pEp_identity *ident)
  1238. {
  1239. struct mailimf_mailbox_list *mbl = NULL;
  1240. struct mailimf_mailbox *mb = NULL;
  1241. clist *list = NULL;
  1242. int r;
  1243. assert(ident);
  1244. list = clist_new();
  1245. if (list == NULL)
  1246. goto enomem;
  1247. mb = identity_to_mailbox(ident);
  1248. if (mb == NULL)
  1249. goto enomem;
  1250. r = clist_append(list, mb);
  1251. if (r)
  1252. goto enomem;
  1253. mbl = mailimf_mailbox_list_new(list);
  1254. if (mbl == NULL)
  1255. goto enomem;
  1256. return mbl;
  1257. enomem:
  1258. if (mb)
  1259. mailimf_mailbox_free(mb);
  1260. if (list)
  1261. clist_free(list);
  1262. return NULL;
  1263. }
  1264. /**
  1265. * @internal
  1266. *
  1267. * <!-- identity_list_to_mal() -->
  1268. *
  1269. * @brief TODO
  1270. *
  1271. * @param[in] *il identity_list
  1272. *
  1273. */
  1274. static struct mailimf_address_list * identity_list_to_mal(identity_list *il)
  1275. {
  1276. struct mailimf_address_list *mal = NULL;
  1277. struct mailimf_mailbox *mb = NULL;
  1278. struct mailimf_address * addr = NULL;
  1279. clist *list = NULL;
  1280. int r;
  1281. assert(il);
  1282. list = clist_new();
  1283. if (list == NULL)
  1284. goto enomem;
  1285. identity_list *_il;
  1286. for (_il = il; _il && _il->ident; _il = _il->next) {
  1287. mb = identity_to_mailbox(_il->ident);
  1288. if (mb == NULL)
  1289. goto enomem;
  1290. addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
  1291. if (addr == NULL)
  1292. goto enomem;
  1293. mb = NULL;
  1294. r = clist_append(list, addr);
  1295. if (r)
  1296. goto enomem;
  1297. addr = NULL;
  1298. }
  1299. mal = mailimf_address_list_new(list);
  1300. if (mal == NULL)
  1301. goto enomem;
  1302. return mal;
  1303. enomem:
  1304. if (mb)
  1305. mailimf_mailbox_free(mb);
  1306. if (addr)
  1307. mailimf_address_free(addr);
  1308. if (list)
  1309. clist_free(list);
  1310. return NULL;
  1311. }
  1312. // KB: This seems to be always called with "true",
  1313. // but there was probably a reason for this. So
  1314. // leave it for now.
  1315. /**
  1316. * @internal
  1317. *
  1318. * <!-- stringlist_to_clist() -->
  1319. *
  1320. * @brief TODO
  1321. *
  1322. * @param[in] *sl stringlist_t
  1323. * @param[in] transport_encode bool
  1324. *
  1325. */
  1326. static clist * stringlist_to_clist(stringlist_t *sl, bool transport_encode)
  1327. {
  1328. clist * cl = clist_new();
  1329. assert(cl);
  1330. if (cl == NULL)
  1331. return NULL;
  1332. if (!sl || ((!sl->value || sl->value[0] == '\0') && sl->next == NULL))
  1333. return cl;
  1334. stringlist_t *_sl;
  1335. for (_sl = sl; _sl; _sl = _sl->next) {
  1336. int r;
  1337. char * value = ((transport_encode && must_field_value_be_encoded(_sl->value)) ?
  1338. mailmime_encode_subject_header("utf-8", _sl->value, 0) :
  1339. strdup(_sl->value));
  1340. assert(value);
  1341. if (value == NULL) {
  1342. clist_free(cl);
  1343. return NULL;
  1344. }
  1345. r = clist_append(cl, value);
  1346. assert(r == 0);
  1347. if (r) {
  1348. free(value);
  1349. clist_free(cl);
  1350. return NULL;
  1351. }
  1352. }
  1353. return cl;
  1354. }
  1355. /**
  1356. * @internal
  1357. *
  1358. * <!-- build_fields() -->
  1359. *
  1360. * @brief TODO
  1361. *
  1362. * @param[in] *msg constmessage
  1363. * @param[in] **result structmailimf_fields
  1364. *
  1365. * @retval PEP_STATUS_OK
  1366. * @retval PEP_OUT_OF_MEMORY out of memory
  1367. * @retval any other value on error
  1368. */
  1369. static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
  1370. {
  1371. PEP_STATUS status = PEP_STATUS_OK;
  1372. struct mailimf_fields * fields = NULL;
  1373. int r;
  1374. clist * fields_list = NULL;
  1375. unsigned char pEpstr[] = PEP_SUBJ_STRING; // unsigned due to UTF-8 byte fun
  1376. #ifdef WIN32
  1377. char* altstr = "pEp";
  1378. #else
  1379. char* altstr = (char*)pEpstr;
  1380. #endif
  1381. char *subject = msg->shortmsg && msg->shortmsg[0] ? msg->shortmsg : altstr;
  1382. assert(msg);
  1383. assert(result);
  1384. *result = NULL;
  1385. fields_list = clist_new();
  1386. assert(fields_list);
  1387. if (fields_list == NULL)
  1388. goto enomem;
  1389. if (msg->id && msg->id[0]) {
  1390. char *_msgid = strdup(msg->id);
  1391. assert(_msgid);
  1392. if (_msgid == NULL)
  1393. goto enomem;
  1394. r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
  1395. (_new_func_t) mailimf_message_id_new, _msgid);
  1396. if (r) {
  1397. free(_msgid);
  1398. goto enomem;
  1399. }
  1400. }
  1401. if (msg->sent) {
  1402. struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
  1403. if (dt == NULL)
  1404. goto enomem;
  1405. r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
  1406. (_new_func_t) mailimf_orig_date_new, dt);
  1407. if (r) {
  1408. mailimf_date_time_free(dt);
  1409. goto enomem;
  1410. }
  1411. dt = NULL;
  1412. }
  1413. if (msg->from) {
  1414. struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
  1415. if (from == NULL)
  1416. goto enomem;
  1417. r = _append_field(fields_list, MAILIMF_FIELD_FROM,
  1418. (_new_func_t) mailimf_from_new, from);
  1419. if (r) {
  1420. mailimf_mailbox_list_free(from);
  1421. goto enomem;
  1422. }
  1423. }
  1424. if (msg->to && msg->to->ident) {
  1425. struct mailimf_address_list *to = identity_list_to_mal(msg->to);
  1426. if (to == NULL)
  1427. goto enomem;
  1428. r = _append_field(fields_list, MAILIMF_FIELD_TO,
  1429. (_new_func_t) mailimf_to_new, to);
  1430. if (r) {
  1431. mailimf_address_list_free(to);
  1432. goto enomem;
  1433. }
  1434. }
  1435. char* _subject = NULL;
  1436. if (!must_field_value_be_encoded(subject)) {
  1437. _subject = strdup(subject);
  1438. assert(_subject);
  1439. }
  1440. else {
  1441. _subject = mailmime_encode_subject_header("utf-8", subject, 1);
  1442. }
  1443. if (_subject == NULL)
  1444. goto enomem;
  1445. r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
  1446. (_new_func_t) mailimf_subject_new, _subject);
  1447. if (r) {
  1448. free(_subject);
  1449. goto enomem;
  1450. }
  1451. if (msg->cc && msg->cc->ident) {
  1452. struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
  1453. if (cc == NULL)
  1454. goto enomem;
  1455. r = _append_field(fields_list, MAILIMF_FIELD_CC,
  1456. (_new_func_t) mailimf_cc_new, cc);
  1457. if (r) {
  1458. mailimf_address_list_free(cc);
  1459. goto enomem;
  1460. }
  1461. }
  1462. if (msg->bcc && msg->bcc->ident) {
  1463. struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
  1464. if (bcc == NULL)
  1465. goto enomem;
  1466. r = _append_field(fields_list, MAILIMF_FIELD_BCC,
  1467. (_new_func_t) mailimf_bcc_new, bcc);
  1468. if (r) {
  1469. mailimf_address_list_free(bcc);
  1470. goto enomem;
  1471. }
  1472. }
  1473. if (msg->reply_to && msg->reply_to->ident) {
  1474. struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
  1475. if (reply_to == NULL)
  1476. goto enomem;
  1477. r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
  1478. (_new_func_t) mailimf_reply_to_new, reply_to);
  1479. if (r) {
  1480. mailimf_address_list_free(reply_to);
  1481. goto enomem;
  1482. }
  1483. }
  1484. if (msg->in_reply_to && msg->in_reply_to->value) {
  1485. clist *in_reply_to = stringlist_to_clist(msg->in_reply_to, true);
  1486. if (in_reply_to == NULL)
  1487. goto enomem;
  1488. r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
  1489. (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
  1490. if (r) {
  1491. clist_free(in_reply_to);
  1492. goto enomem;
  1493. }
  1494. }
  1495. if (msg->references && msg->references->value) {
  1496. clist *references = stringlist_to_clist(msg->references, true);
  1497. if (references == NULL)
  1498. goto enomem;
  1499. r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
  1500. (_new_func_t) mailimf_references_new, references);
  1501. if (r) {
  1502. clist_free(references);
  1503. goto enomem;
  1504. }
  1505. }
  1506. if (msg->keywords && msg->keywords->value) {
  1507. clist *keywords = stringlist_to_clist(msg->keywords, true);
  1508. if (keywords == NULL)
  1509. goto enomem;
  1510. r = _append_field(fields_list, MAILIMF_FIELD_KEYWORDS,
  1511. (_new_func_t) mailimf_keywords_new, keywords);
  1512. if (r) {
  1513. clist_free(keywords);
  1514. goto enomem;
  1515. }
  1516. }
  1517. if (msg->comments && msg->comments[0]) {
  1518. char *comments = NULL;
  1519. if (!must_field_value_be_encoded(msg->comments)) {
  1520. comments = strdup(msg->comments);
  1521. assert(comments);
  1522. }
  1523. else {
  1524. comments = mailmime_encode_subject_header("utf-8", msg->comments, 0);
  1525. }
  1526. if (comments == NULL)
  1527. goto enomem;
  1528. r = _append_field(fields_list, MAILIMF_FIELD_COMMENTS,
  1529. (_new_func_t) mailimf_comments_new, comments);
  1530. if (r) {
  1531. free(comments);
  1532. goto enomem;
  1533. }
  1534. }
  1535. if (msg->opt_fields && msg->opt_fields->value) {
  1536. stringpair_list_t *_l;
  1537. for (_l = msg->opt_fields; _l && _l->value; _l = _l->next) {
  1538. char *key = _l->value->key;
  1539. char *value = _l->value->value;
  1540. if (key && value) {
  1541. r = _append_optional_field(fields_list, key, value);
  1542. if (r)
  1543. goto enomem;
  1544. }
  1545. }
  1546. }
  1547. fields = mailimf_fields_new(fields_list);
  1548. assert(fields);
  1549. if (fields == NULL)
  1550. goto enomem;
  1551. *result = fields;
  1552. return PEP_STATUS_OK;
  1553. enomem:
  1554. status = PEP_OUT_OF_MEMORY;
  1555. if (fields_list)
  1556. clist_free(fields_list);
  1557. if (fields)
  1558. mailimf_fields_free(fields);
  1559. return status;
  1560. }
  1561. /**
  1562. * @internal
  1563. *
  1564. * <!-- has_exceptional_extension() -->
  1565. *
  1566. * @brief TODO
  1567. *
  1568. * @param[in] *filename char
  1569. *
  1570. */
  1571. static bool has_exceptional_extension(char* filename) {
  1572. if (!filename)
  1573. return false;
  1574. int len = strlen(filename);
  1575. if (len < 4)
  1576. return false;
  1577. char* ext_start = filename + (len - 4);
  1578. if (strcmp(ext_start, ".pgp") == 0 || strcmp(ext_start, ".gpg") == 0 ||
  1579. strcmp(ext_start, ".asc") == 0 || strcmp(ext_start, ".pEp") == 0)
  1580. return true;
  1581. return false;
  1582. }
  1583. /**
  1584. * @internal
  1585. *
  1586. * <!-- choose_resource_id() -->
  1587. *
  1588. * @brief TODO
  1589. *
  1590. * @param[in] *rid_list pEp_rid_list_t
  1591. *
  1592. */
  1593. static pEp_rid_list_t* choose_resource_id(pEp_rid_list_t* rid_list) {
  1594. pEp_rid_list_t* retval = rid_list;