p≡p engine
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.

3293 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
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. #ifndef __MVS__
  471. result->dt_zone = (int) (ts->tm_gmtoff / 36L);
  472. #endif
  473. return result;
  474. }
  475. timestamp * etpantime_to_timestamp(const struct mailimf_date_time *et)
  476. {
  477. timestamp * result = calloc(1, sizeof(timestamp));
  478. assert(result);
  479. if (result == NULL)
  480. return NULL;
  481. assert(et);
  482. result->tm_sec = et->dt_sec;
  483. result->tm_min = et->dt_min;
  484. result->tm_hour = et->dt_hour;
  485. result->tm_mday = et->dt_day;
  486. result->tm_mon = et->dt_month - 1;
  487. result->tm_year = et->dt_year - 1900;
  488. #ifndef __MVS__
  489. result->tm_gmtoff = 36L * (long) et->dt_zone;
  490. #endif
  491. // Normalize to UTC and then forget the offset.
  492. time_t t = timegm_with_gmtoff(result);
  493. gmtime_r(&t, result);
  494. #ifndef __MVS__
  495. result->tm_gmtoff = 0;
  496. #endif
  497. return result;
  498. }
  499. struct mailimf_mailbox * mailbox_from_string(
  500. const char *name,
  501. const char *address
  502. )
  503. {
  504. assert(address);
  505. if (!address)
  506. return NULL;
  507. struct mailimf_mailbox *mb = NULL;
  508. char *_name = NULL;
  509. char *_address = NULL;
  510. _name = name ? strdup(name) : strdup("");
  511. if (_name == NULL)
  512. goto enomem;
  513. char* at = strstr(address, "@");
  514. if (!at) {
  515. // Presumed URI
  516. int added_char_len = 6; // " " @URI
  517. int new_addr_len = strlen(address) + added_char_len + 1;
  518. _address = calloc(new_addr_len, 1);
  519. if (_address == NULL)
  520. goto enomem;
  521. _address[0] = '"';
  522. strlcat(_address, address, new_addr_len);
  523. strlcat(_address, "\"@URI", new_addr_len);
  524. }
  525. else {
  526. _address = strdup(address);
  527. if (_address == NULL)
  528. goto enomem;
  529. }
  530. mb = mailimf_mailbox_new(_name, _address);
  531. assert(mb);
  532. if (mb == NULL)
  533. goto enomem;
  534. return mb;
  535. enomem:
  536. free(_name);
  537. free(_address);
  538. return NULL;
  539. }
  540. struct mailimf_field * create_optional_field(
  541. const char *field,
  542. const char *value
  543. )
  544. {
  545. char *_field = NULL;
  546. char *_value = NULL;
  547. struct mailimf_optional_field *optional_field = NULL;
  548. _field = strdup(field);
  549. if (_field == NULL)
  550. goto enomem;
  551. if (!must_field_value_be_encoded(value))
  552. _value = strdup(value);
  553. else
  554. _value = mailmime_encode_subject_header("utf-8", value, 0);
  555. if (_value == NULL)
  556. goto enomem;
  557. optional_field = mailimf_optional_field_new(_field, _value);
  558. if (optional_field == NULL)
  559. goto enomem;
  560. struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
  561. assert(result);
  562. if (result == NULL)
  563. goto enomem;
  564. result->fld_type = MAILIMF_FIELD_OPTIONAL_FIELD;
  565. result->fld_data.fld_optional_field = optional_field;
  566. return result;
  567. enomem:
  568. if (optional_field) {
  569. mailimf_optional_field_free(optional_field);
  570. }
  571. else {
  572. free(_field);
  573. free(_value);
  574. }
  575. return NULL;
  576. }
  577. int _append_optional_field(
  578. clist *list,
  579. const char *field,
  580. const char *value
  581. )
  582. {
  583. int r;
  584. struct mailimf_field * optional_field =
  585. create_optional_field(field, value);
  586. if (optional_field == NULL)
  587. return -1;
  588. r = clist_append(list, optional_field);
  589. if (r)
  590. mailimf_field_free(optional_field);
  591. return r;
  592. }
  593. clist * _get_fields(struct mailmime * mime)
  594. {
  595. clist * _fieldlist = NULL;
  596. assert(mime);
  597. if (mime->mm_data.mm_message.mm_fields &&
  598. mime->mm_data.mm_message.mm_fields->fld_list) {
  599. _fieldlist = mime->mm_data.mm_message.mm_fields->fld_list;
  600. }
  601. return _fieldlist;
  602. }
  603. struct mailmime_content * _get_content(struct mailmime * mime)
  604. {
  605. struct mailmime_content * content = NULL;
  606. assert(mime);
  607. if (mime->mm_data.mm_message.mm_msg_mime)
  608. content = mime->mm_data.mm_message.mm_msg_mime->mm_content_type;
  609. return content;
  610. }
  611. /* Return a list of identifier_type and resource id (filename, cid, etc) */
  612. pEp_rid_list_t* _get_resource_id_list(struct mailmime *mime)
  613. {
  614. clist * _fieldlist = NULL;
  615. assert(mime);
  616. if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
  617. _fieldlist = mime->mm_mime_fields->fld_list;
  618. else
  619. return NULL;
  620. clistiter *cur;
  621. pEp_rid_list_t* rid_list = NULL;
  622. pEp_rid_list_t** rid_list_curr_p = &rid_list;
  623. for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
  624. struct mailmime_field * _field = clist_content(cur);
  625. /* content_id */
  626. if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
  627. pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
  628. new_rid->rid_type = PEP_RID_CID;
  629. new_rid->rid = strdup(_field->fld_data.fld_id);
  630. *rid_list_curr_p = new_rid;
  631. rid_list_curr_p = &new_rid->next;
  632. }
  633. else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
  634. /* filename */
  635. if (_field->fld_data.fld_disposition &&
  636. _field->fld_data.fld_disposition->dsp_parms) {
  637. clist * _parmlist =
  638. _field->fld_data.fld_disposition->dsp_parms;
  639. clistiter *cur2;
  640. for (cur2 = clist_begin(_parmlist); cur2; cur2 =
  641. clist_next(cur2)) {
  642. struct mailmime_disposition_parm * param =
  643. clist_content(cur2);
  644. if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
  645. pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
  646. new_rid->rid_type = PEP_RID_FILENAME;
  647. new_rid->rid = strdup(param->pa_data.pa_filename);
  648. *rid_list_curr_p = new_rid;
  649. rid_list_curr_p = &new_rid->next;
  650. }
  651. }
  652. }
  653. }
  654. }
  655. /* Will almost certainly usually be a singleton, but we need to be able to decide */
  656. return rid_list;
  657. }
  658. /* FIXME: about to be obsoleted? */
  659. char * _get_filename_or_cid(struct mailmime *mime)
  660. {
  661. clist * _fieldlist = NULL;
  662. assert(mime);
  663. if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
  664. _fieldlist = mime->mm_mime_fields->fld_list;
  665. else
  666. return NULL;
  667. clistiter *cur;
  668. char* _temp_filename_ptr = NULL;
  669. for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
  670. struct mailmime_field * _field = clist_content(cur);
  671. if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
  672. /* We prefer CIDs to filenames when both are present */
  673. free(_temp_filename_ptr); /* can be null, it's ok */
  674. return build_uri("cid", _field->fld_data.fld_id);
  675. }
  676. else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
  677. if (_field->fld_data.fld_disposition &&
  678. _field->fld_data.fld_disposition->dsp_parms &&
  679. !_temp_filename_ptr) {
  680. clist * _parmlist =
  681. _field->fld_data.fld_disposition->dsp_parms;
  682. clistiter *cur2;
  683. for (cur2 = clist_begin(_parmlist); cur2; cur2 =
  684. clist_next(cur2)) {
  685. struct mailmime_disposition_parm * param =
  686. clist_content(cur2);
  687. if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
  688. _temp_filename_ptr = build_uri("file", param->pa_data.pa_filename);
  689. break;
  690. }
  691. }
  692. }
  693. }
  694. }
  695. /* Ok, it wasn't a CID */
  696. return _temp_filename_ptr;
  697. }
  698. /**
  699. * @internal
  700. *
  701. * <!-- parameter_has_value() -->
  702. *
  703. * @brief TODO
  704. *
  705. * @param[in] *content structmailmime_content
  706. * @param[in] *name constchar
  707. * @param[in] *value constchar
  708. *
  709. */
  710. static bool parameter_has_value(
  711. struct mailmime_content *content,
  712. const char *name,
  713. const char *value
  714. )
  715. {
  716. clistiter *cur;
  717. assert(name);
  718. assert(value);
  719. clist * list = content->ct_parameters;
  720. if (list == NULL)
  721. return false;
  722. for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
  723. struct mailmime_parameter * param = clist_content(cur);
  724. if (param &&
  725. param->pa_name && strcasecmp(name, param->pa_name) == 0 &&
  726. param->pa_value && strcasecmp(value, param->pa_value) == 0)
  727. return true;
  728. }
  729. return false;
  730. }
  731. bool _is_multipart(struct mailmime_content *content, const char *subtype)
  732. {
  733. assert(content);
  734. if (content->ct_type && content->ct_type->tp_type ==
  735. MAILMIME_TYPE_COMPOSITE_TYPE &&
  736. content->ct_type->tp_data.tp_composite_type &&
  737. content->ct_type->tp_data.tp_composite_type->ct_type ==
  738. MAILMIME_COMPOSITE_TYPE_MULTIPART) {
  739. if (subtype)
  740. return content->ct_subtype &&
  741. strcasecmp(content->ct_subtype, subtype) == 0;
  742. else
  743. return true;
  744. }
  745. return false;
  746. }
  747. bool _is_PGP_MIME(struct mailmime_content *content)
  748. {
  749. assert(content);
  750. if (_is_multipart(content, "encrypted") &&
  751. parameter_has_value(content, "protocol",
  752. "application/pgp-encrypted"))
  753. return true;
  754. return false;
  755. }
  756. bool _is_text_part(struct mailmime_content *content, const char *subtype)
  757. {
  758. assert(content);
  759. if (content->ct_type && content->ct_type->tp_type ==
  760. MAILMIME_TYPE_DISCRETE_TYPE &&
  761. content->ct_type->tp_data.tp_discrete_type &&
  762. content->ct_type->tp_data.tp_discrete_type->dt_type ==
  763. MAILMIME_DISCRETE_TYPE_TEXT) {
  764. if (subtype)
  765. return content->ct_subtype &&
  766. strcasecmp(content->ct_subtype, subtype) == 0;
  767. else
  768. return true;
  769. }
  770. return false;
  771. }
  772. /**
  773. * @internal
  774. *
  775. * <!-- _is_message_part() -->
  776. *
  777. * @brief TODO
  778. *
  779. * @param[in] *content structmailmime_content
  780. * @param[in] *subtype constchar
  781. *
  782. */
  783. bool _is_message_part(struct mailmime_content *content, const char* subtype) {
  784. assert(content);
  785. if (content->ct_type && content->ct_type->tp_type == MAILMIME_TYPE_COMPOSITE_TYPE &&
  786. content->ct_type->tp_data.tp_composite_type &&
  787. content->ct_type->tp_data.tp_composite_type->ct_type ==
  788. MAILMIME_COMPOSITE_TYPE_MESSAGE) {
  789. if (subtype)
  790. return content->ct_subtype &&
  791. strcasecmp(content->ct_subtype, subtype) == 0;
  792. else
  793. return true;
  794. }
  795. return false;
  796. }
  797. int _get_content_type(
  798. const struct mailmime_content *content,
  799. char **type,
  800. char **charset
  801. )
  802. {
  803. char *_type = NULL;
  804. char *_charset = NULL;
  805. assert(content);
  806. assert(type);
  807. assert(charset);
  808. *type = NULL;
  809. *charset = NULL;
  810. if (content->ct_subtype == NULL)
  811. return EINVAL;
  812. if (content->ct_type && content->ct_type->tp_data.tp_discrete_type) {
  813. size_t len;
  814. const char *_main_type;
  815. switch (content->ct_type->tp_data.tp_discrete_type->dt_type) {
  816. case MAILMIME_DISCRETE_TYPE_TEXT:
  817. _main_type = (content->ct_subtype &&
  818. strcasecmp(content->ct_subtype, "rfc822") == 0 ?
  819. "message" : "text");
  820. break;
  821. case MAILMIME_DISCRETE_TYPE_IMAGE:
  822. _main_type = "image";
  823. break;
  824. case MAILMIME_DISCRETE_TYPE_AUDIO:
  825. _main_type = "audio";
  826. break;
  827. case MAILMIME_DISCRETE_TYPE_VIDEO:
  828. _main_type = "video";
  829. break;
  830. case MAILMIME_DISCRETE_TYPE_APPLICATION:
  831. _main_type = "application";
  832. break;
  833. case MAILMIME_DISCRETE_TYPE_EXTENSION:
  834. _main_type = "extension";
  835. break;
  836. default:
  837. return EINVAL;
  838. }
  839. len = strlen(_main_type) + 1 + strlen(content->ct_subtype) + 1;
  840. _type = calloc(1, len);
  841. assert(_type);
  842. if (_type == NULL)
  843. return ENOMEM;
  844. strncpy(_type, _main_type, len);
  845. len -= strlen(_main_type);
  846. strncat(_type, "/", len--);
  847. strncat(_type, content->ct_subtype, len);
  848. if (content->ct_parameters) {
  849. clistiter *cur;
  850. for (cur = clist_begin(content->ct_parameters); cur; cur =
  851. clist_next(cur)) {
  852. struct mailmime_parameter * param = clist_content(cur);
  853. if (param && param->pa_name && strcasecmp(param->pa_name,
  854. "charset") == 0) {
  855. _charset = param->pa_value;
  856. break;
  857. }
  858. }
  859. if (_charset)
  860. *charset = strdup(_charset);
  861. }
  862. *type = _type;
  863. return 0;
  864. }
  865. return EINVAL;
  866. }
  867. // Only for null-terminated field strings.
  868. // can this field be transported as is without modification?)
  869. // (See rfc2822, section 2.2.3 - libetpan's handling isn't quite what
  870. // we need here.)
  871. bool must_field_value_be_encoded(const char* field_value) {
  872. if (!field_value)
  873. return false;
  874. return must_chunk_be_encoded((const void*)field_value, strlen(field_value), false);
  875. }
  876. bool must_chunk_be_encoded(const void* value, size_t size, bool ignore_fws) {
  877. const char* begin_ptr = (const char*)value;
  878. const char* end_ptr = begin_ptr + size;
  879. const char* cur_char_ptr = begin_ptr;
  880. while (cur_char_ptr < end_ptr) {
  881. char cur_char = *cur_char_ptr;
  882. if (cur_char > 127 || cur_char < 0)
  883. return true;
  884. // FIXME - do we need to deal with CRCRLF here?
  885. // I guess in the worst case, it gets encoded, which
  886. // is *supposed* to be harmless...
  887. if (!ignore_fws) {
  888. if (cur_char == '\r') {
  889. const char* next = cur_char_ptr + 1;
  890. const char* nextnext = next + 1;
  891. if (next >= end_ptr || nextnext >= end_ptr
  892. || *next != '\n'
  893. || (*nextnext != ' ' && *nextnext != '\t')) {
  894. return true;
  895. }
  896. }
  897. else if (cur_char == '\n') {
  898. const char* prev = cur_char_ptr - 1;
  899. if (prev == begin_ptr || *prev != '\r')
  900. return true;
  901. }
  902. }
  903. cur_char_ptr++;
  904. }
  905. return ascii_exceeds_line_length(value, size);
  906. }
  907. #define TMP_TEMPLATE "pEp.XXXXXXXXXXXXXXXXXXXX"
  908. #ifdef _WIN32
  909. #define PATH_SEP '\\'
  910. #else
  911. #define PATH_SEP '/'
  912. #endif
  913. static PEP_STATUS interpret_MIME(struct mailmime *mime,
  914. message *msg,
  915. bool* has_possible_pEp_msg);
  916. // This function was rewritten to use in-memory buffers instead of
  917. // temporary files when the pgp/mime support was implemented for
  918. // outlook, as the existing code did not work well on windows.
  919. /**
  920. * @internal
  921. *
  922. * <!-- render_mime() -->
  923. *
  924. * @brief TODO
  925. *
  926. * @param[in] *mime structmailmime
  927. * @param[in] **mimetext char
  928. *
  929. * @retval PEP_STATUS_OK
  930. * @retval PEP_OUT_OF_MEMORY out of memory
  931. * @retval any other value on error
  932. */
  933. static PEP_STATUS render_mime(struct mailmime *mime, char **mimetext)
  934. {
  935. PEP_STATUS status = PEP_STATUS_OK;
  936. int col;
  937. int r;
  938. size_t len;
  939. char* buf = NULL;
  940. MMAPString* buffer;
  941. buffer = mmap_string_new(NULL);
  942. if (buffer == NULL)
  943. goto enomem;
  944. col = 0;
  945. r = mailmime_write_mem(buffer, &col, mime);
  946. assert(r == MAILIMF_NO_ERROR);
  947. if (r == MAILIMF_ERROR_MEMORY)
  948. goto enomem;
  949. else if (r != MAILIMF_NO_ERROR)
  950. goto err_file;
  951. // we overallocate by 1 byte, so we have a terminating 0.
  952. len = buffer->len;
  953. buf = calloc(len + 1, 1);
  954. if (buf == NULL)
  955. goto enomem;
  956. memcpy(buf, buffer->str, len);
  957. mmap_string_free(buffer);
  958. *mimetext = buf;
  959. return PEP_STATUS_OK;
  960. err_file:
  961. status = PEP_CANNOT_CREATE_TEMP_FILE;
  962. goto pEp_error;
  963. enomem:
  964. status = PEP_OUT_OF_MEMORY;
  965. pEp_error:
  966. if (buffer)
  967. mmap_string_free(buffer);
  968. if (buf)
  969. free(buf);
  970. return status;
  971. }
  972. /**
  973. * @internal
  974. *
  975. * <!-- mime_attachment() -->
  976. *
  977. * @brief TODO
  978. *
  979. * @param[in] *blob bloblist_t
  980. * @param[in] **result structmailmime
  981. * @param[in] is_nf_message_attachment bool
  982. *
  983. * @retval PEP_STATUS_OK
  984. * @retval PEP_OUT_OF_MEMORY out of memory
  985. * @retval any other value on error
  986. *
  987. */
  988. static PEP_STATUS mime_attachment(
  989. bloblist_t *blob,
  990. struct mailmime **result,
  991. bool is_nf_message_attachment // non-forwarded msg as att
  992. )
  993. {
  994. PEP_STATUS status = PEP_STATUS_OK;
  995. struct mailmime * mime = NULL;
  996. char * mime_type;
  997. assert(blob);
  998. assert(result);
  999. *result = NULL;
  1000. // TODO: It seems the pEp COM server adapter sends an empty string here,
  1001. // which leads to a crash later. Thus, we workaround here by treating an
  1002. // empty string as NULL. We need to check whether the bug really is here,
  1003. // or the pEp COM server adapter needs to be changed.
  1004. if (blob->mime_type == NULL || blob->mime_type[0] == '\0')
  1005. mime_type = "application/octet-stream";
  1006. else
  1007. mime_type = blob->mime_type;
  1008. pEp_rid_list_t* resource = parse_uri(blob->filename);
  1009. mime = get_file_part(resource, mime_type, blob->value, blob->size,
  1010. is_nf_message_attachment);
  1011. free_rid_list(resource);
  1012. assert(mime);
  1013. if (mime == NULL)
  1014. goto enomem;
  1015. *result = mime;
  1016. return PEP_STATUS_OK;
  1017. enomem:
  1018. status = PEP_OUT_OF_MEMORY;
  1019. if (mime)
  1020. mailmime_free(mime);
  1021. return status;
  1022. }
  1023. // This ONLY deals with handling the body
  1024. // content when html parts are present - thus,
  1025. // text/plain and text/html of the body, and
  1026. // related inline attachments for the html
  1027. // part. Non-inline attachments are handled
  1028. // outside this call!!!!
  1029. //
  1030. // N.B. As a result, this will only touch the
  1031. // "contained message" of pEp 2.x messages
  1032. // on the initial encoding where it is turned
  1033. // into attachment data!!
  1034. /**
  1035. * @internal
  1036. *
  1037. * <!-- mime_html_text() -->
  1038. *
  1039. * @brief TODO
  1040. *
  1041. * @param[in] *plaintext constchar
  1042. * @param[in] *htmltext constchar
  1043. * @param[in] *attachments bloblist_t
  1044. * @param[in] **result structmailmime
  1045. *
  1046. * @retval PEP_STATUS_OK
  1047. * @retval PEP_OUT_OF_MEMORY out of memory
  1048. * @retval any other value on error
  1049. */
  1050. static PEP_STATUS mime_html_text(
  1051. const char *plaintext,
  1052. const char *htmltext,
  1053. bloblist_t *attachments,
  1054. struct mailmime **result
  1055. )
  1056. {
  1057. PEP_STATUS status = PEP_STATUS_OK;
  1058. struct mailmime * top_level_html_mime = NULL;
  1059. struct mailmime * mime = NULL;
  1060. struct mailmime * submime = NULL;
  1061. int r;
  1062. assert(plaintext);
  1063. assert(htmltext);
  1064. assert(result);
  1065. *result = NULL;
  1066. pEp_rid_list_t* resource = NULL;
  1067. bool already_ascii = false;
  1068. int encoding_type = 0;
  1069. if (*plaintext != '\0') {
  1070. mime = part_multiple_new("multipart/alternative");
  1071. assert(mime);
  1072. if (mime == NULL)
  1073. goto enomem;
  1074. // KB: pEpMIME transition comment - if we start getting
  1075. // underencoding errors here, the change to checking
  1076. // for ASCII and then encoding - or not - is one place
  1077. // to start looking.
  1078. int pt_length = strlen(plaintext);
  1079. already_ascii = !(must_chunk_be_encoded(plaintext, pt_length, true));
  1080. encoding_type = (already_ascii ? 0 : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  1081. submime = get_text_part(NULL, "text/plain", plaintext,
  1082. pt_length,
  1083. encoding_type);
  1084. // reset
  1085. already_ascii = false;
  1086. encoding_type = 0;
  1087. free_rid_list(resource);
  1088. resource = NULL;
  1089. assert(submime);
  1090. if (submime == NULL)
  1091. goto enomem;
  1092. r = mailmime_smart_add_part(mime, submime);
  1093. assert(r == MAILIMF_NO_ERROR);
  1094. if (r == MAILIMF_ERROR_MEMORY) {
  1095. goto enomem;
  1096. }
  1097. else {
  1098. // mailmime_smart_add_part() takes ownership of submime
  1099. submime = NULL;
  1100. }
  1101. }
  1102. bool inlined_attachments = false;
  1103. bloblist_t* traversal_ptr = attachments;
  1104. while (traversal_ptr) {
  1105. if (traversal_ptr->disposition == PEP_CONTENT_DISP_INLINE) {
  1106. inlined_attachments = true;
  1107. break;
  1108. }
  1109. traversal_ptr = traversal_ptr->next;
  1110. }
  1111. if (inlined_attachments) {
  1112. /* Noooooo... dirk, why do you do this to me? */
  1113. submime = part_multiple_new("multipart/related");
  1114. assert(submime);
  1115. if (submime == NULL)
  1116. goto enomem;
  1117. // This is where all of the html MIME stuff will go
  1118. top_level_html_mime = submime;
  1119. if (!mime)
  1120. mime = top_level_html_mime;
  1121. else {
  1122. r = mailmime_smart_add_part(mime, top_level_html_mime);
  1123. assert(r == MAILIMF_NO_ERROR);
  1124. if (r == MAILIMF_ERROR_MEMORY) {
  1125. goto enomem;
  1126. }
  1127. else {
  1128. // mailmime_smart_add_part() takes ownership of submime
  1129. submime = NULL;
  1130. }
  1131. }
  1132. }
  1133. else {
  1134. // Otherwise, html MIME stuff gets added to the top node
  1135. // - may be NULL if there's no multipart!
  1136. top_level_html_mime = mime;
  1137. }
  1138. // resource = new_rid_node(PEP_RID_FILENAME, "msg.html");
  1139. int ht_length = strlen(htmltext);
  1140. already_ascii = !(must_chunk_be_encoded(htmltext, ht_length, true));
  1141. encoding_type = (already_ascii ? 0 : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  1142. submime = get_text_part(NULL, "text/html", htmltext,
  1143. ht_length,
  1144. encoding_type);
  1145. free_rid_list(resource);
  1146. resource = NULL;
  1147. assert(submime);
  1148. if (submime == NULL)
  1149. goto enomem;
  1150. // IF there are no inlined attachments AND mime is NULL, then
  1151. // we just have an HTML body here and won't need to
  1152. // process inlined attachments - submime will actually be
  1153. // the mime root of from this function, at least.
  1154. if (!top_level_html_mime) {
  1155. mime = submime;
  1156. submime = NULL;
  1157. }
  1158. else {
  1159. r = mailmime_smart_add_part(top_level_html_mime, submime);
  1160. assert(r == MAILIMF_NO_ERROR);
  1161. if (r == MAILIMF_ERROR_MEMORY)
  1162. goto enomem;
  1163. else {
  1164. // mailmime_smart_add_part() takes ownership of submime
  1165. submime = NULL;
  1166. }
  1167. bloblist_t *_a;
  1168. // This will never have an embedded pEp message attachment
  1169. // sent for encoding here, so we don't need to pass down
  1170. // "(don't) transport encode this" info. If it's here and
  1171. // it's not an ASCII "text/*" attachment, it'll get encoded
  1172. for (_a = attachments; _a != NULL; _a = _a->next) {
  1173. if (_a->disposition != PEP_CONTENT_DISP_INLINE)
  1174. continue;
  1175. status = mime_attachment(_a, &submime, false);
  1176. if (status != PEP_STATUS_OK)
  1177. return PEP_UNKNOWN_ERROR; // FIXME
  1178. r = mailmime_smart_add_part(top_level_html_mime, submime);
  1179. assert(r == MAILIMF_NO_ERROR);
  1180. if (r == MAILIMF_ERROR_MEMORY) {
  1181. goto enomem;
  1182. }
  1183. else {
  1184. // mailmime_smart_add_part() takes ownership of submime
  1185. submime = NULL;
  1186. }
  1187. }
  1188. }
  1189. *result = mime;
  1190. return PEP_STATUS_OK;
  1191. enomem:
  1192. status = PEP_OUT_OF_MEMORY;
  1193. if (mime)
  1194. mailmime_free(mime);
  1195. if (submime)
  1196. mailmime_free(submime);
  1197. return status;
  1198. }
  1199. /**
  1200. * @internal
  1201. *
  1202. * <!-- identity_to_mailbox() -->
  1203. *
  1204. * @brief TODO
  1205. *
  1206. * @param[in] *ident constpEp_identity
  1207. *
  1208. */
  1209. static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
  1210. {
  1211. char *_username = NULL;
  1212. struct mailimf_mailbox *mb;
  1213. if (!ident->username)
  1214. _username = strdup("");
  1215. else
  1216. _username = must_field_value_be_encoded(ident->username) ?
  1217. mailmime_encode_subject_header("utf-8", ident->username, 0) :
  1218. strdup(ident->username);
  1219. assert(_username);
  1220. if (_username == NULL)
  1221. goto enomem;
  1222. mb = mailbox_from_string(_username, ident->address);
  1223. if (mb == NULL)
  1224. goto enomem;
  1225. free(_username);
  1226. _username = NULL;
  1227. return mb;
  1228. enomem:
  1229. free(_username);
  1230. return NULL;
  1231. }
  1232. /**
  1233. * @internal
  1234. *
  1235. * <!-- identity_to_mbl() -->
  1236. *
  1237. * @brief TODO
  1238. *
  1239. * @param[in] *ident constpEp_identity
  1240. *
  1241. */
  1242. static struct mailimf_mailbox_list * identity_to_mbl(
  1243. const pEp_identity *ident)
  1244. {
  1245. struct mailimf_mailbox_list *mbl = NULL;
  1246. struct mailimf_mailbox *mb = NULL;
  1247. clist *list = NULL;
  1248. int r;
  1249. assert(ident);
  1250. list = clist_new();
  1251. if (list == NULL)
  1252. goto enomem;
  1253. mb = identity_to_mailbox(ident);
  1254. if (mb == NULL)
  1255. goto enomem;
  1256. r = clist_append(list, mb);
  1257. if (r)
  1258. goto enomem;
  1259. mbl = mailimf_mailbox_list_new(list);
  1260. if (mbl == NULL)
  1261. goto enomem;
  1262. return mbl;
  1263. enomem:
  1264. if (mb)
  1265. mailimf_mailbox_free(mb);
  1266. if (list)
  1267. clist_free(list);
  1268. return NULL;
  1269. }
  1270. /**
  1271. * @internal
  1272. *
  1273. * <!-- identity_list_to_mal() -->
  1274. *
  1275. * @brief TODO
  1276. *
  1277. * @param[in] *il identity_list
  1278. *
  1279. */
  1280. static struct mailimf_address_list * identity_list_to_mal(identity_list *il)
  1281. {
  1282. struct mailimf_address_list *mal = NULL;
  1283. struct mailimf_mailbox *mb = NULL;
  1284. struct mailimf_address * addr = NULL;
  1285. clist *list = NULL;
  1286. int r;
  1287. assert(il);
  1288. list = clist_new();
  1289. if (list == NULL)
  1290. goto enomem;
  1291. identity_list *_il;
  1292. for (_il = il; _il && _il->ident; _il = _il->next) {
  1293. mb = identity_to_mailbox(_il->ident);
  1294. if (mb == NULL)
  1295. goto enomem;
  1296. addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
  1297. if (addr == NULL)
  1298. goto enomem;
  1299. mb = NULL;
  1300. r = clist_append(list, addr);
  1301. if (r)
  1302. goto enomem;
  1303. addr = NULL;
  1304. }
  1305. mal = mailimf_address_list_new(list);
  1306. if (mal == NULL)
  1307. goto enomem;
  1308. return mal;
  1309. enomem:
  1310. if (mb)
  1311. mailimf_mailbox_free(mb);
  1312. if (addr)
  1313. mailimf_address_free(addr);
  1314. if (list)
  1315. clist_free(list);
  1316. return NULL;
  1317. }
  1318. // KB: This seems to be always called with "true",
  1319. // but there was probably a reason for this. So
  1320. // leave it for now.
  1321. /**
  1322. * @internal
  1323. *
  1324. * <!-- stringlist_to_clist() -->
  1325. *
  1326. * @brief TODO
  1327. *
  1328. * @param[in] *sl stringlist_t
  1329. * @param[in] transport_encode bool
  1330. *
  1331. */
  1332. static clist * stringlist_to_clist(stringlist_t *sl, bool transport_encode)
  1333. {
  1334. clist * cl = clist_new();
  1335. assert(cl);
  1336. if (cl == NULL)
  1337. return NULL;
  1338. if (!sl || ((!sl->value || sl->value[0] == '\0') && sl->next == NULL))
  1339. return cl;
  1340. stringlist_t *_sl;
  1341. for (_sl = sl; _sl; _sl = _sl->next) {
  1342. int r;
  1343. char * value = ((transport_encode && must_field_value_be_encoded(_sl->value)) ?
  1344. mailmime_encode_subject_header("utf-8", _sl->value, 0) :
  1345. strdup(_sl->value));
  1346. assert(value);
  1347. if (value == NULL) {
  1348. clist_free(cl);
  1349. return NULL;
  1350. }
  1351. r = clist_append(cl, value);
  1352. assert(r == 0);
  1353. if (r) {
  1354. free(value);
  1355. clist_free(cl);
  1356. return NULL;
  1357. }
  1358. }
  1359. return cl;
  1360. }
  1361. /**
  1362. * @internal
  1363. *
  1364. * <!-- build_fields() -->
  1365. *
  1366. * @brief TODO
  1367. *
  1368. * @param[in] *msg constmessage
  1369. * @param[in] **result structmailimf_fields
  1370. *
  1371. * @retval PEP_STATUS_OK
  1372. * @retval PEP_OUT_OF_MEMORY out of memory
  1373. * @retval any other value on error
  1374. */
  1375. static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
  1376. {
  1377. PEP_STATUS status = PEP_STATUS_OK;
  1378. struct mailimf_fields * fields = NULL;
  1379. int r;
  1380. clist * fields_list = NULL;
  1381. unsigned char pEpstr[] = PEP_SUBJ_STRING; // unsigned due to UTF-8 byte fun
  1382. #ifdef WIN32
  1383. char* altstr = "pEp";
  1384. #else
  1385. char* altstr = (char*)pEpstr;
  1386. #endif
  1387. char *subject = msg->shortmsg && msg->shortmsg[0] ? msg->shortmsg : altstr;
  1388. assert(msg);
  1389. assert(result);
  1390. *result = NULL;
  1391. fields_list = clist_new();
  1392. assert(fields_list);
  1393. if (fields_list == NULL)
  1394. goto enomem;
  1395. if (msg->id && msg->id[0]) {
  1396. char *_msgid = strdup(msg->id);
  1397. assert(_msgid);
  1398. if (_msgid == NULL)
  1399. goto enomem;
  1400. r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
  1401. (_new_func_t) mailimf_message_id_new, _msgid);
  1402. if (r) {
  1403. free(_msgid);
  1404. goto enomem;
  1405. }
  1406. }
  1407. if (msg->sent) {
  1408. struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
  1409. if (dt == NULL)
  1410. goto enomem;
  1411. r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
  1412. (_new_func_t) mailimf_orig_date_new, dt);
  1413. if (r) {
  1414. mailimf_date_time_free(dt);
  1415. goto enomem;
  1416. }
  1417. dt = NULL;
  1418. }
  1419. if (msg->from) {
  1420. struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
  1421. if (from == NULL)
  1422. goto enomem;
  1423. r = _append_field(fields_list, MAILIMF_FIELD_FROM,
  1424. (_new_func_t) mailimf_from_new, from);
  1425. if (r) {
  1426. mailimf_mailbox_list_free(from);
  1427. goto enomem;
  1428. }
  1429. }
  1430. if (msg->to && msg->to->ident) {
  1431. struct mailimf_address_list *to = identity_list_to_mal(msg->to);
  1432. if (to == NULL)
  1433. goto enomem;
  1434. r = _append_field(fields_list, MAILIMF_FIELD_TO,
  1435. (_new_func_t) mailimf_to_new, to);
  1436. if (r) {
  1437. mailimf_address_list_free(to);
  1438. goto enomem;
  1439. }
  1440. }
  1441. char* _subject = NULL;
  1442. if (!must_field_value_be_encoded(subject)) {
  1443. _subject = strdup(subject);
  1444. assert(_subject);
  1445. }
  1446. else {
  1447. _subject = mailmime_encode_subject_header("utf-8", subject, 1);
  1448. }
  1449. if (_subject == NULL)
  1450. goto enomem;
  1451. r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
  1452. (_new_func_t) mailimf_subject_new, _subject);
  1453. if (r) {
  1454. free(_subject);
  1455. goto enomem;
  1456. }
  1457. if (msg->cc && msg->cc->ident) {
  1458. struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
  1459. if (cc == NULL)
  1460. goto enomem;
  1461. r = _append_field(fields_list, MAILIMF_FIELD_CC,
  1462. (_new_func_t) mailimf_cc_new, cc);
  1463. if (r) {
  1464. mailimf_address_list_free(cc);
  1465. goto enomem;
  1466. }
  1467. }
  1468. if (msg->bcc && msg->bcc->ident) {
  1469. struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
  1470. if (bcc == NULL)
  1471. goto enomem;
  1472. r = _append_field(fields_list, MAILIMF_FIELD_BCC,
  1473. (_new_func_t) mailimf_bcc_new, bcc);
  1474. if (r) {
  1475. mailimf_address_list_free(bcc);
  1476. goto enomem;
  1477. }
  1478. }
  1479. if (msg->reply_to && msg->reply_to->ident) {
  1480. struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
  1481. if (reply_to == NULL)
  1482. goto enomem;
  1483. r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
  1484. (_new_func_t) mailimf_reply_to_new, reply_to);
  1485. if (r) {
  1486. mailimf_address_list_free(reply_to);
  1487. goto enomem;
  1488. }
  1489. }
  1490. if (msg->in_reply_to && msg->in_reply_to->value) {
  1491. clist *in_reply_to = stringlist_to_clist(msg->in_reply_to, true);
  1492. if (in_reply_to == NULL)
  1493. goto enomem;
  1494. r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
  1495. (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
  1496. if (r) {
  1497. clist_free(in_reply_to);
  1498. goto enomem;
  1499. }
  1500. }
  1501. if (msg->references && msg->references->value) {
  1502. clist *references = stringlist_to_clist(msg->references, true);
  1503. if (references == NULL)
  1504. goto enomem;
  1505. r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
  1506. (_new_func_t) mailimf_references_new, references);
  1507. if (