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.

3221 lines
88 KiB

8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
2 years ago
8 years ago
8 years ago
8 years ago
8 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. /** @file */
  2. /** @brief File description for doxygen missing. FIXME */
  3. // This file is under GNU General Public License 3.0
  4. // see LICENSE.txt
  5. #include "etpan_mime.h"
  6. #ifndef mailmime_param_new_with_data
  7. #include <libetpan/mailprivacy_tools.h>
  8. #endif
  9. #include "pEp_internal.h"
  10. #include "platform.h"
  11. #include "mime.h"
  12. #include "wrappers.h"
  13. #include "resource_id.h"
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #include <assert.h>
  17. #include <errno.h>
  18. #define MAX_MESSAGE_ID 128
  19. /**
  20. * @internal
  21. *
  22. * <!-- generate_boundary() -->
  23. *
  24. * @brief TODO
  25. *
  26. *
  27. */
  28. static char * generate_boundary(void)
  29. {
  30. char id[MAX_MESSAGE_ID];
  31. // no cryptographically strong random needed here
  32. const long value1 = random();
  33. const long value2 = random();
  34. const long value3 = random();
  35. const long value4 = random();
  36. snprintf(id, MAX_MESSAGE_ID, "%.4lx%.4lx%.4lx%.4lx", value1, value2,
  37. value3, value4);
  38. return strdup(id);
  39. }
  40. struct mailmime * part_new_empty(
  41. struct mailmime_content * content,
  42. struct mailmime_fields * mime_fields,
  43. stringpair_list_t* param_keyvals,
  44. int force_single
  45. )
  46. {
  47. struct mailmime * build_info;
  48. clist * list = NULL;
  49. int r;
  50. int mime_type;
  51. char * attr_name = NULL;
  52. char * attr_value = NULL;
  53. struct mailmime_parameter * param = NULL;
  54. clist * parameters = NULL;
  55. char *boundary = NULL;
  56. list = NULL;
  57. if (force_single) {
  58. mime_type = MAILMIME_SINGLE;
  59. }
  60. else {
  61. switch (content->ct_type->tp_type) {
  62. case MAILMIME_TYPE_DISCRETE_TYPE:
  63. mime_type = MAILMIME_SINGLE;
  64. break;
  65. case MAILMIME_TYPE_COMPOSITE_TYPE:
  66. switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
  67. case MAILMIME_COMPOSITE_TYPE_MULTIPART:
  68. mime_type = MAILMIME_MULTIPLE;
  69. break;
  70. case MAILMIME_COMPOSITE_TYPE_MESSAGE:
  71. if (strcasecmp(content->ct_subtype, "rfc822") == 0)
  72. mime_type = MAILMIME_MESSAGE;
  73. else
  74. mime_type = MAILMIME_SINGLE;
  75. break;
  76. default:
  77. goto enomem;
  78. }
  79. break;
  80. default:
  81. goto enomem;
  82. }
  83. }
  84. if (mime_type == MAILMIME_MULTIPLE) {
  85. list = clist_new();
  86. assert(list);
  87. if (list == NULL)
  88. goto enomem;
  89. attr_name = strdup("boundary");
  90. assert(attr_name);
  91. if (attr_name == NULL)
  92. goto enomem;
  93. boundary = generate_boundary();
  94. assert(boundary);
  95. attr_value = boundary;
  96. if (attr_value == NULL)
  97. goto enomem;
  98. param = mailmime_parameter_new(attr_name, attr_value);
  99. assert(param);
  100. if (param == NULL)
  101. goto enomem;
  102. attr_name = NULL;
  103. attr_value = NULL;
  104. if (content->ct_parameters == NULL) {
  105. parameters = clist_new();
  106. assert(parameters);
  107. if (parameters == NULL)
  108. goto enomem;
  109. }
  110. else {
  111. parameters = content->ct_parameters;
  112. }
  113. r = clist_append(parameters, param);
  114. if (r)
  115. goto enomem;
  116. param = NULL;
  117. if (content->ct_parameters == NULL)
  118. content->ct_parameters = parameters;
  119. }
  120. if (param_keyvals) {
  121. stringpair_list_t* cur;
  122. for (cur = param_keyvals; cur; cur = cur->next) {
  123. attr_name = strdup(cur->value->key);
  124. attr_value = strdup(cur->value->value);
  125. param = mailmime_parameter_new(attr_name, attr_value);
  126. assert(param);
  127. if (param == NULL)
  128. goto enomem;
  129. attr_name = NULL;
  130. attr_value = NULL;
  131. if (content->ct_parameters == NULL) {
  132. parameters = clist_new();
  133. assert(parameters);
  134. if (parameters == NULL)
  135. goto enomem;
  136. }
  137. else {
  138. parameters = content->ct_parameters;
  139. }
  140. r = clist_append(parameters, param);
  141. if (r)
  142. goto enomem;
  143. param = NULL;
  144. if (content->ct_parameters == NULL)
  145. content->ct_parameters = parameters;
  146. }
  147. }
  148. build_info = mailmime_new(mime_type, NULL, 0, mime_fields, content, NULL,
  149. NULL, NULL, list, NULL, NULL);
  150. if (build_info == NULL)
  151. goto enomem;
  152. return build_info;
  153. enomem:
  154. if (list)
  155. clist_free(list);
  156. free(attr_name);
  157. free(attr_value);
  158. if (content->ct_parameters == NULL)
  159. if (parameters)
  160. clist_free(parameters);
  161. if (param)
  162. mailmime_parameter_free(param);
  163. return NULL;
  164. }
  165. struct mailmime * get_pgp_encrypted_part(void)
  166. {
  167. struct mailmime * mime = NULL;
  168. struct mailmime_fields * mime_fields = NULL;
  169. struct mailmime_content * content = NULL;
  170. int r;
  171. content = mailmime_content_new_with_str("application/pgp-encrypted");
  172. if (content == NULL)
  173. goto enomem;
  174. mime_fields = mailmime_fields_new_empty();
  175. if (mime_fields == NULL)
  176. goto enomem;
  177. mime = part_new_empty(content, mime_fields, NULL, 1);
  178. if (mime == NULL)
  179. goto enomem;
  180. mime_fields = NULL;
  181. content = NULL;
  182. r = mailmime_set_body_text(mime, "Version: 1\n", 10);
  183. if (r != 0)
  184. goto enomem;
  185. return mime;
  186. enomem:
  187. if (content)
  188. mailmime_content_free(content);
  189. if (mime_fields)
  190. mailmime_fields_free(mime_fields);
  191. if (mime)
  192. mailmime_free(mime);
  193. return NULL;
  194. }
  195. struct mailmime * get_text_part(
  196. pEp_rid_list_t* resource,
  197. const char * mime_type,
  198. const char * text,
  199. size_t length,
  200. int encoding_type
  201. )
  202. {
  203. char * disposition_name = NULL;
  204. struct mailmime_fields * mime_fields = NULL;
  205. struct mailmime * mime = NULL;
  206. struct mailmime_content * content = NULL;
  207. struct mailmime_parameter * param = NULL;
  208. struct mailmime_disposition * disposition = NULL;
  209. struct mailmime_mechanism * encoding = NULL;
  210. char* content_id = NULL;
  211. int r;
  212. if (resource != NULL && resource->rid != NULL) {
  213. switch (resource->rid_type) {
  214. case PEP_RID_CID:
  215. content_id = strdup(resource->rid);
  216. break;
  217. case PEP_RID_FILENAME:
  218. default:
  219. disposition_name = strdup(resource->rid);
  220. if (disposition_name == NULL)
  221. goto enomem;
  222. disposition =
  223. mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
  224. disposition_name, NULL, NULL, NULL, (size_t) -1);
  225. if (disposition == NULL)
  226. goto enomem;
  227. disposition_name = NULL;
  228. break;
  229. }
  230. }
  231. if (encoding_type) {
  232. encoding = mailmime_mechanism_new(encoding_type, NULL);
  233. if (encoding == NULL)
  234. goto enomem;
  235. }
  236. mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
  237. disposition, NULL);
  238. if (mime_fields == NULL)
  239. goto enomem;
  240. encoding = NULL;
  241. disposition = NULL;
  242. content_id = NULL;
  243. content = mailmime_content_new_with_str(mime_type);
  244. if (content == NULL)
  245. goto enomem;
  246. if (encoding_type != MAILMIME_MECHANISM_7BIT) {
  247. param = mailmime_param_new_with_data("charset", "utf-8");
  248. r = clist_append(content->ct_parameters, param);
  249. if (r != 0)
  250. goto enomem;
  251. }
  252. mime = part_new_empty(content, mime_fields, NULL, 1);
  253. if (mime == NULL)
  254. goto enomem;
  255. content = NULL;
  256. mime_fields = NULL;
  257. if (text) {
  258. r = mailmime_set_body_text(mime, (char *) text, length);
  259. if (r != 0)
  260. goto enomem;
  261. }
  262. return mime;
  263. enomem:
  264. free(disposition_name);
  265. if (mime_fields)
  266. mailmime_fields_free(mime_fields);
  267. if (mime)
  268. mailmime_free(mime);
  269. if (content)
  270. mailmime_content_free(content);
  271. if (param)
  272. mailmime_parameter_free(param);
  273. if (disposition)
  274. mailmime_disposition_free(disposition);
  275. if (encoding)
  276. mailmime_mechanism_free(encoding);
  277. return NULL;
  278. }
  279. struct mailmime * get_file_part(
  280. pEp_rid_list_t* resource,
  281. const char * mime_type,
  282. char * data,
  283. size_t length,
  284. bool is_nf_message_attachment // non-forwarded msg as att
  285. )
  286. {
  287. char * disposition_name = NULL;
  288. int encoding_type;
  289. struct mailmime_disposition * disposition = NULL;
  290. struct mailmime_mechanism * encoding = NULL;
  291. struct mailmime_content * content = NULL;
  292. struct mailmime * mime = NULL;
  293. struct mailmime_fields * mime_fields = NULL;
  294. char* content_id = NULL;
  295. int r;
  296. if (resource != NULL && resource->rid != NULL) {
  297. switch (resource->rid_type) {
  298. case PEP_RID_CID:
  299. content_id = strdup(resource->rid);
  300. disposition =
  301. mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
  302. NULL, NULL, NULL, NULL, (size_t) -1);
  303. if (disposition == NULL)
  304. goto enomem;
  305. break;
  306. case PEP_RID_FILENAME:
  307. default:
  308. disposition_name = strdup(resource->rid);
  309. if (disposition_name == NULL)
  310. goto enomem;
  311. disposition =
  312. mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
  313. disposition_name, NULL, NULL, NULL, (size_t) -1);
  314. if (disposition == NULL)
  315. goto enomem;
  316. disposition_name = NULL;
  317. break;
  318. }
  319. }
  320. content = mailmime_content_new_with_str(mime_type);
  321. if (content == NULL)
  322. goto enomem;
  323. encoding = NULL;
  324. bool already_ascii = !(must_chunk_be_encoded(data, length, true));
  325. if (!is_nf_message_attachment && !already_ascii) {
  326. encoding_type = MAILMIME_MECHANISM_BASE64;
  327. encoding = mailmime_mechanism_new(encoding_type, NULL);
  328. if (encoding == NULL)
  329. goto enomem;
  330. }
  331. mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
  332. disposition, NULL);
  333. if (mime_fields == NULL)
  334. goto enomem;
  335. encoding = NULL;
  336. disposition = NULL;
  337. stringpair_list_t* extra_params = NULL;
  338. if (is_nf_message_attachment)
  339. extra_params = new_stringpair_list(new_stringpair("forwarded", "no"));
  340. mime = part_new_empty(content, mime_fields, extra_params, 1);
  341. free_stringpair_list(extra_params);
  342. if (mime == NULL)
  343. goto enomem;
  344. content = NULL;
  345. mime_fields = NULL;
  346. if(length > 0)
  347. {
  348. r = mailmime_set_body_text(mime, data, length);
  349. if (r != 0)
  350. goto enomem;
  351. }
  352. return mime;
  353. enomem:
  354. free(disposition_name);
  355. if (disposition)
  356. mailmime_disposition_free(disposition);
  357. if (encoding)
  358. mailmime_mechanism_free(encoding);
  359. if (content)
  360. mailmime_content_free(content);
  361. if (mime_fields)
  362. mailmime_fields_free(mime_fields);
  363. if (mime)
  364. mailmime_free(mime);
  365. return NULL;
  366. }
  367. struct mailmime * part_multiple_new(const char *type)
  368. {
  369. struct mailmime_fields *mime_fields = NULL;
  370. struct mailmime_content *content = NULL;
  371. struct mailmime *mp = NULL;
  372. mime_fields = mailmime_fields_new_empty();
  373. if (mime_fields == NULL)
  374. goto enomem;
  375. content = mailmime_content_new_with_str(type);
  376. if (content == NULL)
  377. goto enomem;
  378. mp = part_new_empty(content, mime_fields, NULL, 0);
  379. if (mp == NULL)
  380. goto enomem;
  381. return mp;
  382. enomem:
  383. if (content)
  384. mailmime_content_free(content);
  385. if (mime_fields)
  386. mailmime_fields_free(mime_fields);
  387. return NULL;
  388. }
  389. struct mailimf_field * _new_field(
  390. int type,
  391. _new_func_t new_func,
  392. void *value
  393. )
  394. {
  395. void *data = new_func(value);
  396. assert(data);
  397. if (data == NULL)
  398. return NULL;
  399. struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
  400. assert(result);
  401. if (result == NULL) {
  402. free(data);
  403. return NULL;
  404. }
  405. result->fld_type = type;
  406. result->fld_data.fld_return_path = data;
  407. return result;
  408. }
  409. void _free_field(struct mailimf_field *field)
  410. {
  411. if (field)
  412. free(field->fld_data.fld_return_path);
  413. free(field);
  414. }
  415. int _append_field(
  416. clist *list,
  417. int type,
  418. _new_func_t new_func,
  419. void *value
  420. )
  421. {
  422. int r;
  423. struct mailimf_field * field;
  424. assert(list);
  425. assert(new_func);
  426. assert(value);
  427. field = _new_field(type, new_func, value);
  428. if (field == NULL)
  429. return -1;
  430. r = clist_append(list, field);
  431. if (r)
  432. _free_field(field);
  433. return r;
  434. }
  435. // http://media2.giga.de/2014/02/Image-28.jpg
  436. struct mailimf_date_time * timestamp_to_etpantime(const timestamp *ts)
  437. {
  438. struct mailimf_date_time * result = calloc(1,
  439. sizeof(struct mailimf_date_time));
  440. assert(result);
  441. if (result == NULL)
  442. return NULL;
  443. assert(ts);
  444. result->dt_sec = ts->tm_sec;
  445. result->dt_min = ts->tm_min;
  446. result->dt_hour = ts->tm_hour;
  447. result->dt_day = ts->tm_mday;
  448. result->dt_month = ts->tm_mon + 1;
  449. result->dt_year = ts->tm_year + 1900;
  450. result->dt_zone = (int) (ts->tm_gmtoff / 36L);
  451. return result;
  452. }
  453. timestamp * etpantime_to_timestamp(const struct mailimf_date_time *et)
  454. {
  455. timestamp * result = calloc(1, sizeof(timestamp));
  456. assert(result);
  457. if (result == NULL)
  458. return NULL;
  459. assert(et);
  460. result->tm_sec = et->dt_sec;
  461. result->tm_min = et->dt_min;
  462. result->tm_hour = et->dt_hour;
  463. result->tm_mday = et->dt_day;
  464. result->tm_mon = et->dt_month - 1;
  465. result->tm_year = et->dt_year - 1900;
  466. result->tm_gmtoff = 36L * (long) et->dt_zone;
  467. // Normalize to UTC and then forget the offset.
  468. time_t t = timegm_with_gmtoff(result);
  469. gmtime_r(&t, result);
  470. result->tm_gmtoff = 0;
  471. return result;
  472. }
  473. struct mailimf_mailbox * mailbox_from_string(
  474. const char *name,
  475. const char *address
  476. )
  477. {
  478. assert(address);
  479. if (!address)
  480. return NULL;
  481. struct mailimf_mailbox *mb = NULL;
  482. char *_name = NULL;
  483. char *_address = NULL;
  484. _name = name ? strdup(name) : strdup("");
  485. if (_name == NULL)
  486. goto enomem;
  487. char* at = strstr(address, "@");
  488. if (!at) {
  489. // Presumed URI
  490. int added_char_len = 6; // " " @URI
  491. int new_addr_len = strlen(address) + added_char_len + 1;
  492. _address = calloc(new_addr_len, 1);
  493. if (_address == NULL)
  494. goto enomem;
  495. _address[0] = '"';
  496. strlcat(_address, address, new_addr_len);
  497. strlcat(_address, "\"@URI", new_addr_len);
  498. }
  499. else {
  500. _address = strdup(address);
  501. if (_address == NULL)
  502. goto enomem;
  503. }
  504. mb = mailimf_mailbox_new(_name, _address);
  505. assert(mb);
  506. if (mb == NULL)
  507. goto enomem;
  508. return mb;
  509. enomem:
  510. free(_name);
  511. free(_address);
  512. return NULL;
  513. }
  514. struct mailimf_field * create_optional_field(
  515. const char *field,
  516. const char *value
  517. )
  518. {
  519. char *_field = NULL;
  520. char *_value = NULL;
  521. struct mailimf_optional_field *optional_field = NULL;
  522. _field = strdup(field);
  523. if (_field == NULL)
  524. goto enomem;
  525. if (!must_field_value_be_encoded(value))
  526. _value = strdup(value);
  527. else
  528. _value = mailmime_encode_subject_header("utf-8", value, 0);
  529. if (_value == NULL)
  530. goto enomem;
  531. optional_field = mailimf_optional_field_new(_field, _value);
  532. if (optional_field == NULL)
  533. goto enomem;
  534. struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
  535. assert(result);
  536. if (result == NULL)
  537. goto enomem;
  538. result->fld_type = MAILIMF_FIELD_OPTIONAL_FIELD;
  539. result->fld_data.fld_optional_field = optional_field;
  540. return result;
  541. enomem:
  542. if (optional_field) {
  543. mailimf_optional_field_free(optional_field);
  544. }
  545. else {
  546. free(_field);
  547. free(_value);
  548. }
  549. return NULL;
  550. }
  551. int _append_optional_field(
  552. clist *list,
  553. const char *field,
  554. const char *value
  555. )
  556. {
  557. int r;
  558. struct mailimf_field * optional_field =
  559. create_optional_field(field, value);
  560. if (optional_field == NULL)
  561. return -1;
  562. r = clist_append(list, optional_field);
  563. if (r)
  564. mailimf_field_free(optional_field);
  565. return r;
  566. }
  567. clist * _get_fields(struct mailmime * mime)
  568. {
  569. clist * _fieldlist = NULL;
  570. assert(mime);
  571. if (mime->mm_data.mm_message.mm_fields &&
  572. mime->mm_data.mm_message.mm_fields->fld_list) {
  573. _fieldlist = mime->mm_data.mm_message.mm_fields->fld_list;
  574. }
  575. return _fieldlist;
  576. }
  577. struct mailmime_content * _get_content(struct mailmime * mime)
  578. {
  579. struct mailmime_content * content = NULL;
  580. assert(mime);
  581. if (mime->mm_data.mm_message.mm_msg_mime)
  582. content = mime->mm_data.mm_message.mm_msg_mime->mm_content_type;
  583. return content;
  584. }
  585. /* Return a list of identifier_type and resource id (filename, cid, etc) */
  586. pEp_rid_list_t* _get_resource_id_list(struct mailmime *mime)
  587. {
  588. clist * _fieldlist = NULL;
  589. assert(mime);
  590. if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
  591. _fieldlist = mime->mm_mime_fields->fld_list;
  592. else
  593. return NULL;
  594. clistiter *cur;
  595. pEp_rid_list_t* rid_list = NULL;
  596. pEp_rid_list_t** rid_list_curr_p = &rid_list;
  597. for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
  598. struct mailmime_field * _field = clist_content(cur);
  599. /* content_id */
  600. if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
  601. pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
  602. new_rid->rid_type = PEP_RID_CID;
  603. new_rid->rid = strdup(_field->fld_data.fld_id);
  604. *rid_list_curr_p = new_rid;
  605. rid_list_curr_p = &new_rid->next;
  606. }
  607. else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
  608. /* filename */
  609. if (_field->fld_data.fld_disposition &&
  610. _field->fld_data.fld_disposition->dsp_parms) {
  611. clist * _parmlist =
  612. _field->fld_data.fld_disposition->dsp_parms;
  613. clistiter *cur2;
  614. for (cur2 = clist_begin(_parmlist); cur2; cur2 =
  615. clist_next(cur2)) {
  616. struct mailmime_disposition_parm * param =
  617. clist_content(cur2);
  618. if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
  619. pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
  620. new_rid->rid_type = PEP_RID_FILENAME;
  621. new_rid->rid = strdup(param->pa_data.pa_filename);
  622. *rid_list_curr_p = new_rid;
  623. rid_list_curr_p = &new_rid->next;
  624. }
  625. }
  626. }
  627. }
  628. }
  629. /* Will almost certainly usually be a singleton, but we need to be able to decide */
  630. return rid_list;
  631. }
  632. /* FIXME: about to be obsoleted? */
  633. char * _get_filename_or_cid(struct mailmime *mime)
  634. {
  635. clist * _fieldlist = NULL;
  636. assert(mime);
  637. if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
  638. _fieldlist = mime->mm_mime_fields->fld_list;
  639. else
  640. return NULL;
  641. clistiter *cur;
  642. char* _temp_filename_ptr = NULL;
  643. for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
  644. struct mailmime_field * _field = clist_content(cur);
  645. if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
  646. /* We prefer CIDs to filenames when both are present */
  647. free(_temp_filename_ptr); /* can be null, it's ok */
  648. return build_uri("cid", _field->fld_data.fld_id);
  649. }
  650. else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
  651. if (_field->fld_data.fld_disposition &&
  652. _field->fld_data.fld_disposition->dsp_parms &&
  653. !_temp_filename_ptr) {
  654. clist * _parmlist =
  655. _field->fld_data.fld_disposition->dsp_parms;
  656. clistiter *cur2;
  657. for (cur2 = clist_begin(_parmlist); cur2; cur2 =
  658. clist_next(cur2)) {
  659. struct mailmime_disposition_parm * param =
  660. clist_content(cur2);
  661. if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
  662. _temp_filename_ptr = build_uri("file", param->pa_data.pa_filename);
  663. break;
  664. }
  665. }
  666. }
  667. }
  668. }
  669. /* Ok, it wasn't a CID */
  670. return _temp_filename_ptr;
  671. }
  672. /**
  673. * @internal
  674. *
  675. * <!-- parameter_has_value() -->
  676. *
  677. * @brief TODO
  678. *
  679. * @param[in] *content structmailmime_content
  680. * @param[in] *name constchar
  681. * @param[in] *value constchar
  682. *
  683. */
  684. static bool parameter_has_value(
  685. struct mailmime_content *content,
  686. const char *name,
  687. const char *value
  688. )
  689. {
  690. clistiter *cur;
  691. assert(name);
  692. assert(value);
  693. clist * list = content->ct_parameters;
  694. if (list == NULL)
  695. return false;
  696. for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
  697. struct mailmime_parameter * param = clist_content(cur);
  698. if (param &&
  699. param->pa_name && strcasecmp(name, param->pa_name) == 0 &&
  700. param->pa_value && strcasecmp(value, param->pa_value) == 0)
  701. return true;
  702. }
  703. return false;
  704. }
  705. bool _is_multipart(struct mailmime_content *content, const char *subtype)
  706. {
  707. assert(content);
  708. if (content->ct_type && content->ct_type->tp_type ==
  709. MAILMIME_TYPE_COMPOSITE_TYPE &&
  710. content->ct_type->tp_data.tp_composite_type &&
  711. content->ct_type->tp_data.tp_composite_type->ct_type ==
  712. MAILMIME_COMPOSITE_TYPE_MULTIPART) {
  713. if (subtype)
  714. return content->ct_subtype &&
  715. strcasecmp(content->ct_subtype, subtype) == 0;
  716. else
  717. return true;
  718. }
  719. return false;
  720. }
  721. bool _is_PGP_MIME(struct mailmime_content *content)
  722. {
  723. assert(content);
  724. if (_is_multipart(content, "encrypted") &&
  725. parameter_has_value(content, "protocol",
  726. "application/pgp-encrypted"))
  727. return true;
  728. return false;
  729. }
  730. bool _is_text_part(struct mailmime_content *content, const char *subtype)
  731. {
  732. assert(content);
  733. if (content->ct_type && content->ct_type->tp_type ==
  734. MAILMIME_TYPE_DISCRETE_TYPE &&
  735. content->ct_type->tp_data.tp_discrete_type &&
  736. content->ct_type->tp_data.tp_discrete_type->dt_type ==
  737. MAILMIME_DISCRETE_TYPE_TEXT) {
  738. if (subtype)
  739. return content->ct_subtype &&
  740. strcasecmp(content->ct_subtype, subtype) == 0;
  741. else
  742. return true;
  743. }
  744. return false;
  745. }
  746. /**
  747. * @internal
  748. *
  749. * <!-- _is_message_part() -->
  750. *
  751. * @brief TODO
  752. *
  753. * @param[in] *content structmailmime_content
  754. * @param[in] *subtype constchar
  755. *
  756. */
  757. bool _is_message_part(struct mailmime_content *content, const char* subtype) {
  758. assert(content);
  759. if (content->ct_type && content->ct_type->tp_type == MAILMIME_TYPE_COMPOSITE_TYPE &&
  760. content->ct_type->tp_data.tp_composite_type &&
  761. content->ct_type->tp_data.tp_composite_type->ct_type ==
  762. MAILMIME_COMPOSITE_TYPE_MESSAGE) {
  763. if (subtype)
  764. return content->ct_subtype &&
  765. strcasecmp(content->ct_subtype, subtype) == 0;
  766. else
  767. return true;
  768. }
  769. return false;
  770. }
  771. int _get_content_type(
  772. const struct mailmime_content *content,
  773. char **type,
  774. char **charset
  775. )
  776. {
  777. char *_type = NULL;
  778. char *_charset = NULL;
  779. assert(content);
  780. assert(type);
  781. assert(charset);
  782. *type = NULL;
  783. *charset = NULL;
  784. if (content->ct_subtype == NULL)
  785. return EINVAL;
  786. if (content->ct_type && content->ct_type->tp_data.tp_discrete_type) {
  787. size_t len;
  788. const char *_main_type;
  789. switch (content->ct_type->tp_data.tp_discrete_type->dt_type) {
  790. case MAILMIME_DISCRETE_TYPE_TEXT:
  791. _main_type = (content->ct_subtype &&
  792. strcasecmp(content->ct_subtype, "rfc822") == 0 ?
  793. "message" : "text");
  794. break;
  795. case MAILMIME_DISCRETE_TYPE_IMAGE:
  796. _main_type = "image";
  797. break;
  798. case MAILMIME_DISCRETE_TYPE_AUDIO:
  799. _main_type = "audio";
  800. break;
  801. case MAILMIME_DISCRETE_TYPE_VIDEO:
  802. _main_type = "video";
  803. break;
  804. case MAILMIME_DISCRETE_TYPE_APPLICATION:
  805. _main_type = "application";
  806. break;
  807. case MAILMIME_DISCRETE_TYPE_EXTENSION:
  808. _main_type = "extension";
  809. break;
  810. default:
  811. return EINVAL;
  812. }
  813. len = strlen(_main_type) + 1 + strlen(content->ct_subtype) + 1;
  814. _type = calloc(1, len);
  815. assert(_type);
  816. if (_type == NULL)
  817. return ENOMEM;
  818. strncpy(_type, _main_type, len);
  819. len -= strlen(_main_type);
  820. strncat(_type, "/", len--);
  821. strncat(_type, content->ct_subtype, len);
  822. if (content->ct_parameters) {
  823. clistiter *cur;
  824. for (cur = clist_begin(content->ct_parameters); cur; cur =
  825. clist_next(cur)) {
  826. struct mailmime_parameter * param = clist_content(cur);
  827. if (param && param->pa_name && strcasecmp(param->pa_name,
  828. "charset") == 0) {
  829. _charset = param->pa_value;
  830. break;
  831. }
  832. }
  833. if (_charset)
  834. *charset = strdup(_charset);
  835. }
  836. *type = _type;
  837. return 0;
  838. }
  839. return EINVAL;
  840. }
  841. // Only for null-terminated field strings.
  842. // can this field be transported as is without modification?)
  843. // (See rfc2822, section 2.2.3 - libetpan's handling isn't quite what
  844. // we need here.)
  845. bool must_field_value_be_encoded(const char* field_value) {
  846. if (!field_value)
  847. return false;
  848. return must_chunk_be_encoded((const void*)field_value, strlen(field_value), false);
  849. }
  850. bool must_chunk_be_encoded(const void* value, size_t size, bool ignore_fws) {
  851. const char* begin_ptr = (const char*)value;
  852. const char* end_ptr = begin_ptr + size;
  853. const char* cur_char_ptr = begin_ptr;
  854. while (cur_char_ptr < end_ptr) {
  855. char cur_char = *cur_char_ptr;
  856. if (cur_char > 127 || cur_char < 0)
  857. return true;
  858. // FIXME - do we need to deal with CRCRLF here?
  859. // I guess in the worst case, it gets encoded, which
  860. // is *supposed* to be harmless...
  861. if (!ignore_fws) {
  862. if (cur_char == '\r') {
  863. const char* next = cur_char_ptr + 1;
  864. const char* nextnext = next + 1;
  865. if (next >= end_ptr || nextnext >= end_ptr
  866. || *next != '\n'
  867. || (*nextnext != ' ' && *nextnext != '\t')) {
  868. return true;
  869. }
  870. }
  871. else if (cur_char == '\n') {
  872. const char* prev = cur_char_ptr - 1;
  873. if (prev == begin_ptr || *prev != '\r')
  874. return true;
  875. }
  876. }
  877. cur_char_ptr++;
  878. }
  879. return false;
  880. }
  881. #define TMP_TEMPLATE "pEp.XXXXXXXXXXXXXXXXXXXX"
  882. #ifdef _WIN32
  883. #define PATH_SEP '\\'
  884. #else
  885. #define PATH_SEP '/'
  886. #endif
  887. static PEP_STATUS interpret_MIME(struct mailmime *mime,
  888. message *msg,
  889. bool* has_possible_pEp_msg);
  890. // This function was rewritten to use in-memory buffers instead of
  891. // temporary files when the pgp/mime support was implemented for
  892. // outlook, as the existing code did not work well on windows.
  893. /**
  894. * @internal
  895. *
  896. * <!-- render_mime() -->
  897. *
  898. * @brief TODO
  899. *
  900. * @param[in] *mime structmailmime
  901. * @param[in] **mimetext char
  902. *
  903. */
  904. static PEP_STATUS render_mime(struct mailmime *mime, char **mimetext)
  905. {
  906. PEP_STATUS status = PEP_STATUS_OK;
  907. int col;
  908. int r;
  909. size_t len;
  910. char* buf = NULL;
  911. MMAPString* buffer;
  912. buffer = mmap_string_new(NULL);
  913. if (buffer == NULL)
  914. goto enomem;
  915. col = 0;
  916. r = mailmime_write_mem(buffer, &col, mime);
  917. assert(r == MAILIMF_NO_ERROR);
  918. if (r == MAILIMF_ERROR_MEMORY)
  919. goto enomem;
  920. else if (r != MAILIMF_NO_ERROR)
  921. goto err_file;
  922. // we overallocate by 1 byte, so we have a terminating 0.
  923. len = buffer->len;
  924. buf = calloc(len + 1, 1);
  925. if (buf == NULL)
  926. goto enomem;
  927. memcpy(buf, buffer->str, len);
  928. mmap_string_free(buffer);
  929. *mimetext = buf;
  930. return PEP_STATUS_OK;
  931. err_file:
  932. status = PEP_CANNOT_CREATE_TEMP_FILE;
  933. goto pEp_error;
  934. enomem:
  935. status = PEP_OUT_OF_MEMORY;
  936. pEp_error:
  937. if (buffer)
  938. mmap_string_free(buffer);
  939. if (buf)
  940. free(buf);
  941. return status;
  942. }
  943. /**
  944. * @internal
  945. *
  946. * <!-- mime_attachment() -->
  947. *
  948. * @brief TODO
  949. *
  950. * @param[in] *blob bloblist_t
  951. * @param[in] **result structmailmime
  952. * @param[in] is_nf_message_attachment bool
  953. *
  954. */
  955. static PEP_STATUS mime_attachment(
  956. bloblist_t *blob,
  957. struct mailmime **result,
  958. bool is_nf_message_attachment // non-forwarded msg as att
  959. )
  960. {
  961. PEP_STATUS status = PEP_STATUS_OK;
  962. struct mailmime * mime = NULL;
  963. char * mime_type;
  964. assert(blob);
  965. assert(result);
  966. *result = NULL;
  967. // TODO: It seems the pEp COM server adapter sends an empty string here,
  968. // which leads to a crash later. Thus, we workaround here by treating an
  969. // empty string as NULL. We need to check whether the bug really is here,
  970. // or the pEp COM server adapter needs to be changed.
  971. if (blob->mime_type == NULL || blob->mime_type[0] == '\0')
  972. mime_type = "application/octet-stream";
  973. else
  974. mime_type = blob->mime_type;
  975. pEp_rid_list_t* resource = parse_uri(blob->filename);
  976. mime = get_file_part(resource, mime_type, blob->value, blob->size,
  977. is_nf_message_attachment);
  978. free_rid_list(resource);
  979. assert(mime);
  980. if (mime == NULL)
  981. goto enomem;
  982. *result = mime;
  983. return PEP_STATUS_OK;
  984. enomem:
  985. status = PEP_OUT_OF_MEMORY;
  986. if (mime)
  987. mailmime_free(mime);
  988. return status;
  989. }
  990. // This ONLY deals with handling the body
  991. // content when html parts are present - thus,
  992. // text/plain and text/html of the body, and
  993. // related inline attachments for the html
  994. // part. Non-inline attachments are handled
  995. // outside this call!!!!
  996. //
  997. // N.B. As a result, this will only touch the
  998. // "contained message" of pEp 2.x messages
  999. // on the initial encoding where it is turned
  1000. // into attachment data!!
  1001. /**
  1002. * @internal
  1003. *
  1004. * <!-- mime_html_text() -->
  1005. *
  1006. * @brief TODO
  1007. *
  1008. * @param[in] *plaintext constchar
  1009. * @param[in] *htmltext constchar
  1010. * @param[in] *attachments bloblist_t
  1011. * @param[in] **result structmailmime
  1012. *
  1013. */
  1014. static PEP_STATUS mime_html_text(
  1015. const char *plaintext,
  1016. const char *htmltext,
  1017. bloblist_t *attachments,
  1018. struct mailmime **result
  1019. )
  1020. {
  1021. PEP_STATUS status = PEP_STATUS_OK;
  1022. struct mailmime * top_level_html_mime = NULL;
  1023. struct mailmime * mime = NULL;
  1024. struct mailmime * submime = NULL;
  1025. int r;
  1026. assert(plaintext);
  1027. assert(htmltext);
  1028. assert(result);
  1029. *result = NULL;
  1030. pEp_rid_list_t* resource = NULL;
  1031. bool already_ascii = false;
  1032. int encoding_type = 0;
  1033. if (*plaintext != '\0') {
  1034. mime = part_multiple_new("multipart/alternative");
  1035. assert(mime);
  1036. if (mime == NULL)
  1037. goto enomem;
  1038. // KB: pEpMIME transition comment - if we start getting
  1039. // underencoding errors here, the change to checking
  1040. // for ASCII and then encoding - or not - is one place
  1041. // to start looking.
  1042. int pt_length = strlen(plaintext);
  1043. already_ascii = !(must_chunk_be_encoded(plaintext, pt_length, true));
  1044. encoding_type = (already_ascii ? 0 : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  1045. submime = get_text_part(NULL, "text/plain", plaintext,
  1046. pt_length,
  1047. encoding_type);
  1048. // reset
  1049. already_ascii = false;
  1050. encoding_type = 0;
  1051. free_rid_list(resource);
  1052. resource = NULL;
  1053. assert(submime);
  1054. if (submime == NULL)
  1055. goto enomem;
  1056. r = mailmime_smart_add_part(mime, submime);
  1057. assert(r == MAILIMF_NO_ERROR);
  1058. if (r == MAILIMF_ERROR_MEMORY) {
  1059. goto enomem;
  1060. }
  1061. else {
  1062. // mailmime_smart_add_part() takes ownership of submime
  1063. submime = NULL;
  1064. }
  1065. }
  1066. bool inlined_attachments = false;
  1067. bloblist_t* traversal_ptr = attachments;
  1068. while (traversal_ptr) {
  1069. if (traversal_ptr->disposition == PEP_CONTENT_DISP_INLINE) {
  1070. inlined_attachments = true;
  1071. break;
  1072. }
  1073. traversal_ptr = traversal_ptr->next;
  1074. }
  1075. if (inlined_attachments) {
  1076. /* Noooooo... dirk, why do you do this to me? */
  1077. submime = part_multiple_new("multipart/related");
  1078. assert(submime);
  1079. if (submime == NULL)
  1080. goto enomem;
  1081. // This is where all of the html MIME stuff will go
  1082. top_level_html_mime = submime;
  1083. if (!mime)
  1084. mime = top_level_html_mime;
  1085. else {
  1086. r = mailmime_smart_add_part(mime, top_level_html_mime);
  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. }
  1097. else {
  1098. // Otherwise, html MIME stuff gets added to the top node
  1099. // - may be NULL if there's no multipart!
  1100. top_level_html_mime = mime;
  1101. }
  1102. // resource = new_rid_node(PEP_RID_FILENAME, "msg.html");
  1103. int ht_length = strlen(htmltext);
  1104. already_ascii = !(must_chunk_be_encoded(htmltext, ht_length, true));
  1105. encoding_type = (already_ascii ? 0 : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  1106. submime = get_text_part(NULL, "text/html", htmltext,
  1107. ht_length,
  1108. encoding_type);
  1109. free_rid_list(resource);
  1110. resource = NULL;
  1111. assert(submime);
  1112. if (submime == NULL)
  1113. goto enomem;
  1114. // IF there are no inlined attachments AND mime is NULL, then
  1115. // we just have an HTML body here and won't need to
  1116. // process inlined attachments - submime will actually be
  1117. // the mime root of from this function, at least.
  1118. if (!top_level_html_mime) {
  1119. mime = submime;
  1120. submime = NULL;
  1121. }
  1122. else {
  1123. r = mailmime_smart_add_part(top_level_html_mime, submime);
  1124. assert(r == MAILIMF_NO_ERROR);
  1125. if (r == MAILIMF_ERROR_MEMORY)
  1126. goto enomem;
  1127. else {
  1128. // mailmime_smart_add_part() takes ownership of submime
  1129. submime = NULL;
  1130. }
  1131. bloblist_t *_a;
  1132. // This will never have an embedded pEp message attachment
  1133. // sent for encoding here, so we don't need to pass down
  1134. // "(don't) transport encode this" info. If it's here and
  1135. // it's not an ASCII "text/*" attachment, it'll get encoded
  1136. for (_a = attachments; _a != NULL; _a = _a->next) {
  1137. if (_a->disposition != PEP_CONTENT_DISP_INLINE)
  1138. continue;
  1139. status = mime_attachment(_a, &submime, false);
  1140. if (status != PEP_STATUS_OK)
  1141. return PEP_UNKNOWN_ERROR; // FIXME
  1142. r = mailmime_smart_add_part(top_level_html_mime, submime);
  1143. assert(r == MAILIMF_NO_ERROR);
  1144. if (r == MAILIMF_ERROR_MEMORY) {
  1145. goto enomem;
  1146. }
  1147. else {
  1148. // mailmime_smart_add_part() takes ownership of submime
  1149. submime = NULL;
  1150. }
  1151. }
  1152. }
  1153. *result = mime;
  1154. return PEP_STATUS_OK;
  1155. enomem:
  1156. status = PEP_OUT_OF_MEMORY;
  1157. if (mime)
  1158. mailmime_free(mime);
  1159. if (submime)
  1160. mailmime_free(submime);
  1161. return status;
  1162. }
  1163. /**
  1164. * @internal
  1165. *
  1166. * <!-- identity_to_mailbox() -->
  1167. *
  1168. * @brief TODO
  1169. *
  1170. * @param[in] *ident constpEp_identity
  1171. *
  1172. */
  1173. static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
  1174. {
  1175. char *_username = NULL;
  1176. struct mailimf_mailbox *mb;
  1177. if (!ident->username)
  1178. _username = strdup("");
  1179. else
  1180. _username = must_field_value_be_encoded(ident->username) ?
  1181. mailmime_encode_subject_header("utf-8", ident->username, 0) :
  1182. strdup(ident->username);
  1183. assert(_username);
  1184. if (_username == NULL)
  1185. goto enomem;
  1186. mb = mailbox_from_string(_username, ident->address);
  1187. if (mb == NULL)
  1188. goto enomem;
  1189. free(_username);
  1190. _username = NULL;
  1191. return mb;
  1192. enomem:
  1193. free(_username);
  1194. return NULL;
  1195. }
  1196. /**
  1197. * @internal
  1198. *
  1199. * <!-- identity_to_mbl() -->
  1200. *
  1201. * @brief TODO
  1202. *
  1203. * @param[in] *ident constpEp_identity
  1204. *
  1205. */
  1206. static struct mailimf_mailbox_list * identity_to_mbl(
  1207. const pEp_identity *ident)
  1208. {
  1209. struct mailimf_mailbox_list *mbl = NULL;
  1210. struct mailimf_mailbox *mb = NULL;
  1211. clist *list = NULL;
  1212. int r;
  1213. assert(ident);
  1214. list = clist_new();
  1215. if (list == NULL)
  1216. goto enomem;
  1217. mb = identity_to_mailbox(ident);
  1218. if (mb == NULL)
  1219. goto enomem;
  1220. r = clist_append(list, mb);
  1221. if (r)
  1222. goto enomem;
  1223. mbl = mailimf_mailbox_list_new(list);
  1224. if (mbl == NULL)
  1225. goto enomem;
  1226. return mbl;
  1227. enomem:
  1228. if (mb)
  1229. mailimf_mailbox_free(mb);
  1230. if (list)
  1231. clist_free(list);
  1232. return NULL;
  1233. }
  1234. /**
  1235. * @internal
  1236. *
  1237. * <!-- identity_list_to_mal() -->
  1238. *
  1239. * @brief TODO
  1240. *
  1241. * @param[in] *il identity_list
  1242. *
  1243. */
  1244. static struct mailimf_address_list * identity_list_to_mal(identity_list *il)
  1245. {
  1246. struct mailimf_address_list *mal = NULL;
  1247. struct mailimf_mailbox *mb = NULL;
  1248. struct mailimf_address * addr = NULL;
  1249. clist *list = NULL;
  1250. int r;
  1251. assert(il);
  1252. list = clist_new();
  1253. if (list == NULL)
  1254. goto enomem;
  1255. identity_list *_il;
  1256. for (_il = il; _il && _il->ident; _il = _il->next) {
  1257. mb = identity_to_mailbox(_il->ident);
  1258. if (mb == NULL)
  1259. goto enomem;
  1260. addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
  1261. if (addr == NULL)
  1262. goto enomem;
  1263. mb = NULL;
  1264. r = clist_append(list, addr);
  1265. if (r)
  1266. goto enomem;
  1267. addr = NULL;
  1268. }
  1269. mal = mailimf_address_list_new(list);
  1270. if (mal == NULL)
  1271. goto enomem;
  1272. return mal;
  1273. enomem:
  1274. if (mb)
  1275. mailimf_mailbox_free(mb);
  1276. if (addr)
  1277. mailimf_address_free(addr);
  1278. if (list)
  1279. clist_free(list);
  1280. return NULL;
  1281. }
  1282. // KB: This seems to be always called with "true",
  1283. // but there was probably a reason for this. So
  1284. // leave it for now.
  1285. /**
  1286. * @internal
  1287. *
  1288. * <!-- stringlist_to_clist() -->
  1289. *
  1290. * @brief TODO
  1291. *
  1292. * @param[in] *sl stringlist_t
  1293. * @param[in] transport_encode bool
  1294. *
  1295. */
  1296. static clist * stringlist_to_clist(stringlist_t *sl, bool transport_encode)
  1297. {
  1298. clist * cl = clist_new();
  1299. assert(cl);
  1300. if (cl == NULL)
  1301. return NULL;
  1302. if (!sl || ((!sl->value || sl->value[0] == '\0') && sl->next == NULL))
  1303. return cl;
  1304. stringlist_t *_sl;
  1305. for (_sl = sl; _sl; _sl = _sl->next) {
  1306. int r;
  1307. char * value = ((transport_encode && must_field_value_be_encoded(_sl->value)) ?
  1308. mailmime_encode_subject_header("utf-8", _sl->value, 0) :
  1309. strdup(_sl->value));
  1310. assert(value);
  1311. if (value == NULL) {
  1312. clist_free(cl);
  1313. return NULL;
  1314. }
  1315. r = clist_append(cl, value);
  1316. assert(r == 0);
  1317. if (r) {
  1318. free(value);
  1319. clist_free(cl);
  1320. return NULL;
  1321. }
  1322. }
  1323. return cl;
  1324. }
  1325. /**
  1326. * @internal
  1327. *
  1328. * <!-- build_fields() -->
  1329. *
  1330. * @brief TODO
  1331. *
  1332. * @param[in] *msg constmessage
  1333. * @param[in] **result structmailimf_fields
  1334. *
  1335. */
  1336. static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
  1337. {
  1338. PEP_STATUS status = PEP_STATUS_OK;
  1339. struct mailimf_fields * fields = NULL;
  1340. int r;
  1341. clist * fields_list = NULL;
  1342. unsigned char pEpstr[] = PEP_SUBJ_STRING; // unsigned due to UTF-8 byte fun
  1343. #ifdef WIN32
  1344. char* altstr = "pEp";
  1345. #else
  1346. char* altstr = (char*)pEpstr;
  1347. #endif
  1348. char *subject = msg->shortmsg && msg->shortmsg[0] ? msg->shortmsg : altstr;
  1349. assert(msg);
  1350. assert(result);
  1351. *result = NULL;
  1352. fields_list = clist_new();
  1353. assert(fields_list);
  1354. if (fields_list == NULL)
  1355. goto enomem;
  1356. if (msg->id && msg->id[0]) {
  1357. char *_msgid = strdup(msg->id);
  1358. assert(_msgid);
  1359. if (_msgid == NULL)
  1360. goto enomem;
  1361. r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
  1362. (_new_func_t) mailimf_message_id_new, _msgid);
  1363. if (r) {
  1364. free(_msgid);
  1365. goto enomem;
  1366. }
  1367. }
  1368. if (msg->sent) {
  1369. struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
  1370. if (dt == NULL)
  1371. goto enomem;
  1372. r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
  1373. (_new_func_t) mailimf_orig_date_new, dt);
  1374. if (r) {
  1375. mailimf_date_time_free(dt);
  1376. goto enomem;
  1377. }
  1378. dt = NULL;
  1379. }
  1380. if (msg->from) {
  1381. struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
  1382. if (from == NULL)
  1383. goto enomem;
  1384. r = _append_field(fields_list, MAILIMF_FIELD_FROM,
  1385. (_new_func_t) mailimf_from_new, from);
  1386. if (r) {
  1387. mailimf_mailbox_list_free(from);
  1388. goto enomem;
  1389. }
  1390. }
  1391. if (msg->to && msg->to->ident) {
  1392. struct mailimf_address_list *to = identity_list_to_mal(msg->to);
  1393. if (to == NULL)
  1394. goto enomem;
  1395. r = _append_field(fields_list, MAILIMF_FIELD_TO,
  1396. (_new_func_t) mailimf_to_new, to);
  1397. if (r) {
  1398. mailimf_address_list_free(to);
  1399. goto enomem;
  1400. }
  1401. }
  1402. char* _subject = NULL;
  1403. if (!must_field_value_be_encoded(subject)) {
  1404. _subject = strdup(subject);
  1405. assert(_subject);
  1406. }
  1407. else {
  1408. _subject = mailmime_encode_subject_header("utf-8", subject, 1);
  1409. }
  1410. if (_subject == NULL)
  1411. goto enomem;
  1412. r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
  1413. (_new_func_t) mailimf_subject_new, _subject);
  1414. if (r) {
  1415. free(_subject);
  1416. goto enomem;
  1417. }
  1418. if (msg->cc && msg->cc->ident) {
  1419. struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
  1420. if (cc == NULL)
  1421. goto enomem;
  1422. r = _append_field(fields_list, MAILIMF_FIELD_CC,
  1423. (_new_func_t) mailimf_cc_new, cc);
  1424. if (r) {
  1425. mailimf_address_list_free(cc);
  1426. goto enomem;
  1427. }
  1428. }
  1429. if (msg->bcc && msg->bcc->ident) {
  1430. struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
  1431. if (bcc == NULL)
  1432. goto enomem;
  1433. r = _append_field(fields_list, MAILIMF_FIELD_BCC,
  1434. (_new_func_t) mailimf_bcc_new, bcc);
  1435. if (r) {
  1436. mailimf_address_list_free(bcc);
  1437. goto enomem;
  1438. }
  1439. }
  1440. if (msg->reply_to && msg->reply_to->ident) {
  1441. struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
  1442. if (reply_to == NULL)
  1443. goto enomem;
  1444. r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
  1445. (_new_func_t) mailimf_reply_to_new, reply_to);
  1446. if (r) {
  1447. mailimf_address_list_free(reply_to);
  1448. goto enomem;
  1449. }
  1450. }
  1451. if (msg->in_reply_to && msg->in_reply_to->value) {
  1452. clist *in_reply_to = stringlist_to_clist(msg->in_reply_to, true);
  1453. if (in_reply_to == NULL)
  1454. goto enomem;
  1455. r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
  1456. (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
  1457. if (r) {
  1458. clist_free(in_reply_to);
  1459. goto enomem;
  1460. }
  1461. }
  1462. if (msg->references && msg->references->value) {
  1463. clist *references = stringlist_to_clist(msg->references, true);
  1464. if (references == NULL)
  1465. goto enomem;
  1466. r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
  1467. (_new_func_t) mailimf_references_new, references);
  1468. if (r) {
  1469. clist_free(references);
  1470. goto enomem;
  1471. }
  1472. }
  1473. if (msg->keywords && msg->keywords->value) {
  1474. clist *keywords = stringlist_to_clist(msg->keywords, true);
  1475. if (keywords == NULL)
  1476. goto enomem;
  1477. r = _append_field(fields_list, MAILIMF_FIELD_KEYWORDS,
  1478. (_new_func_t) mailimf_keywords_new, keywords);
  1479. if (r) {
  1480. clist_free(keywords);
  1481. goto enomem;
  1482. }
  1483. }
  1484. if (msg->comments && msg->comments[0]) {
  1485. char *comments = NULL;
  1486. if (!must_field_value_be_encoded(msg->comments)) {
  1487. comments = strdup(msg->comments);
  1488. assert(comments);
  1489. }
  1490. else {
  1491. comments = mailmime_encode_subject_header("utf-8", msg->comments, 0);
  1492. }
  1493. if (comments == NULL)
  1494. goto enomem;
  1495. r = _append_field(fields_list, MAILIMF_FIELD_COMMENTS,
  1496. (_new_func_t) mailimf_comments_new, comments);
  1497. if (r) {
  1498. free(comments);
  1499. goto enomem;
  1500. }
  1501. }
  1502. if (msg->opt_fields && msg->opt_fields->value) {
  1503. stringpair_list_t *_l;
  1504. for (_l = msg->opt_fields; _l && _l->value; _l = _l->next) {
  1505. char *key = _l->value->key;
  1506. char *value = _l->value->value;
  1507. if (key && value) {
  1508. r = _append_optional_field(fields_list, key, value);
  1509. if (r)
  1510. goto enomem;
  1511. }
  1512. }
  1513. }
  1514. fields = mailimf_fields_new(fields_list);
  1515. assert(fields);
  1516. if (fields == NULL)
  1517. goto enomem;
  1518. *result = fields;
  1519. return PEP_STATUS_OK;
  1520. enomem:
  1521. status = PEP_OUT_OF_MEMORY;
  1522. if (fields_list)
  1523. clist_free(fields_list);
  1524. if (fields)
  1525. mailimf_fields_free(fields);
  1526. return status;
  1527. }
  1528. /**
  1529. * @internal
  1530. *
  1531. * <!-- has_exceptional_extension() -->
  1532. *
  1533. * @brief TODO
  1534. *
  1535. * @param[in] *filename char
  1536. *
  1537. */
  1538. static bool has_exceptional_extension(char* filename) {
  1539. if (!filename)
  1540. return false;
  1541. int len = strlen(filename);
  1542. if (len < 4)
  1543. return false;
  1544. char* ext_start = filename + (len - 4);
  1545. if (strcmp(ext_start, ".pgp") == 0 || strcmp(ext_start, ".gpg") == 0 ||
  1546. strcmp(ext_start, ".asc") == 0 || strcmp(ext_start, ".pEp") == 0)
  1547. return true;
  1548. return false;
  1549. }
  1550. /**
  1551. * @internal
  1552. *
  1553. * <!-- choose_resource_id() -->
  1554. *
  1555. * @brief TODO
  1556. *
  1557. * @param[in] *rid_list pEp_rid_list_t
  1558. *
  1559. */
  1560. static pEp_rid_list_t* choose_resource_id(pEp_rid_list_t* rid_list) {
  1561. pEp_rid_list_t* retval = rid_list;
  1562. /* multiple elements - least common case */
  1563. if (rid_list && rid_list->next) {
  1564. pEp_rid_list_t* rid_list_curr = rid_list;
  1565. retval = rid_list;
  1566. while (rid_list_curr) {
  1567. pEp_resource_id_type rid_type = rid_list_curr->rid_type;
  1568. if (rid_type == PEP_RID_CID)
  1569. retval = rid_list_curr;
  1570. else if (rid_type == PEP_RID_FILENAME && has_exceptional_extension(rid_list_curr->rid))
  1571. return rid_list_curr;
  1572. rid_list_curr = rid_list_curr->next;
  1573. }
  1574. }
  1575. return retval;
  1576. }
  1577. // static void split_inlined_and_attached(bloblist_t** inlined, bloblist_t** attached) {
  1578. // bloblist_t** curr_pp = attached;
  1579. // bloblist_t* curr = *curr_pp;
  1580. //
  1581. // bloblist_t* inline_ret = NULL;
  1582. // bloblist_t** inline_curr_pp = &inline_ret;
  1583. //
  1584. // bloblist_t* att_ret = NULL;
  1585. // bloblist_t** att_curr_pp = &att_ret;
  1586. //
  1587. // while (curr) {
  1588. // if (curr->disposition == PEP_CONTENT_DISP_INLINE) {
  1589. // *inline_curr_pp = curr;
  1590. // inline_curr_pp = &(curr->next);
  1591. // }
  1592. // else {
  1593. // *att_curr_pp = curr;
  1594. // att_curr_pp = &(curr->next);
  1595. // }
  1596. // *curr_pp = curr->next;
  1597. // curr->next = NULL;
  1598. // curr = *curr_pp;
  1599. // }
  1600. //
  1601. // *inlined = inline_ret;
  1602. // *attached = att_ret;
  1603. // }
  1604. /**
  1605. * @internal
  1606. *
  1607. * <!-- mime_encode_message_plain() -->
  1608. *
  1609. * @brief TODO
  1610. *
  1611. * @param[in] *msg constmessage
  1612. * @param[in] omit_fields bool
  1613. * @param[in] **result structmailmime
  1614. * @param[in] has_pEp_msg_attachment bool
  1615. *
  1616. */
  1617. static PEP_STATUS mime_encode_message_plain(
  1618. const message *msg,
  1619. bool omit_fields,
  1620. struct mailmime **result,
  1621. bool has_pEp_msg_attachment
  1622. )
  1623. {
  1624. struct mailmime * mime = NULL;
  1625. struct mailmime * submime = NULL;
  1626. int r;
  1627. PEP_STATUS status;
  1628. //char *subject;
  1629. const char *plaintext;
  1630. char *htmltext;
  1631. assert(msg);
  1632. assert(result);
  1633. // * Process body content, including html's inlined attachments *
  1634. plaintext = (msg->longmsg) ? msg->longmsg : "";
  1635. htmltext = msg->longmsg_formatted;
  1636. if (htmltext && (htmltext[0] != '\0')) {
  1637. /* first, we need to strip out the inlined attachments to ensure this
  1638. gets set up correctly */
  1639. // Note: this only, regardless of whether this is being done
  1640. // for the to-be-embedded message attachment generation or
  1641. // an encapsulating message which contains this, touches
  1642. // the body text of this input message. So transport encoding
  1643. // only refers to the body content here and inlined-attachments, and
  1644. // is decided WITHIN this function, not as an argument.
  1645. status = mime_html_text(plaintext, htmltext, msg->attachments, &mime);
  1646. if (status != PEP_STATUS_OK)
  1647. goto pEp_error;
  1648. }
  1649. else { /* body content only consists of a plaintext block */
  1650. pEp_rid_list_t* resource = NULL;
  1651. int pt_length = strlen(plaintext);
  1652. if (is_PGP_message_text(plaintext)) {
  1653. resource = NULL;
  1654. // So... I think we got overencoding here once, which would be a bug
  1655. // in libetpan, unless it had to do with whitespace. If removing
  1656. // transport encoding as a calculation here somehow leads to overencoding,
  1657. // either we or libetpan are doing something bad.
  1658. // int encoding_type = (transport_encode ? MAILMIME_MECHANISM_7BIT : 0);
  1659. mime = get_text_part(resource, "application/octet-stream", plaintext,
  1660. pt_length, MAILMIME_MECHANISM_7BIT);
  1661. }
  1662. else {
  1663. resource = NULL;
  1664. bool already_ascii = !(must_chunk_be_encoded(plaintext, pt_length, true));
  1665. int encoding_type = (already_ascii ? MAILMIME_MECHANISM_7BIT : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  1666. mime = get_text_part(resource, "text/plain", plaintext, strlen(plaintext),
  1667. encoding_type);
  1668. }
  1669. free_rid_list(resource);
  1670. assert(mime);
  1671. if (mime == NULL)
  1672. goto enomem;
  1673. }
  1674. /* Body content processed, now process normal attachments */
  1675. bool normal_attachments = false;
  1676. bloblist_t* traversal_ptr = msg->attachments;
  1677. // If there were any inline attachments, they should have
  1678. // been stripped out in mime_html_text and dealt with.
  1679. // I'm not entirely sure what the alternative case
  1680. // is here. But basically, if there are any non-inlined
  1681. // attachments to deal with, this is designed to
  1682. // make sure we process them. So flag it for
  1683. // "hey, Bob, you got some regular attachments here"
  1684. // so Bob (obviously, the MIME engine is called Bob)
  1685. // can do the right thing in the next block.
  1686. while (traversal_ptr) {
  1687. if (traversal_ptr->disposition != PEP_CONTENT_DISP_INLINE) {
  1688. normal_attachments = true;
  1689. break;
  1690. }
  1691. traversal_ptr = traversal_ptr->next;
  1692. }
  1693. if (normal_attachments) {
  1694. submime = mime;
  1695. mime = part_multiple_new("multipart/mixed");
  1696. assert(mime);
  1697. if (mime == NULL)
  1698. goto enomem;
  1699. r = mailmime_smart_add_part(mime, submime);
  1700. assert(r == MAILIMF_NO_ERROR);
  1701. if (r == MAILIMF_ERROR_MEMORY) {
  1702. goto enomem;
  1703. }
  1704. else {
  1705. // mailmime_smart_add_part() takes ownership of submime
  1706. submime = NULL;
  1707. }
  1708. bloblist_t *_a;
  1709. bool first_one = true;
  1710. // Go through the non-inline attachments and add em.
  1711. for (_a = msg->attachments; _a != NULL; _a = _a->next) {
  1712. if (_a->disposition == PEP_CONTENT_DISP_INLINE)
  1713. continue;
  1714. // solely for readability.
  1715. bool is_pEp_msg_attachment = (first_one && has_pEp_msg_attachment);
  1716. status = mime_attachment(_a, &submime,
  1717. is_pEp_msg_attachment);
  1718. if (status != PEP_STATUS_OK)
  1719. goto pEp_error;
  1720. first_one = false;
  1721. r = mailmime_smart_add_part(mime, submime);
  1722. assert(r == MAILIMF_NO_ERROR);
  1723. if (r == MAILIMF_ERROR_MEMORY) {
  1724. goto enomem;
  1725. }
  1726. else {
  1727. // mailmime_smart_add_part() takes ownership of submime
  1728. submime = NULL;
  1729. }
  1730. }
  1731. }
  1732. *result = mime;
  1733. return PEP_STATUS_OK;
  1734. enomem:
  1735. status = PEP_OUT_OF_MEMORY;
  1736. pEp_error:
  1737. if (mime)
  1738. mailmime_free(mime);
  1739. if (submime)
  1740. mailmime_free(submime);
  1741. return status;
  1742. }
  1743. /**
  1744. * @internal
  1745. *
  1746. * <!-- mime_encode_message_PGP_MIME() -->
  1747. *
  1748. * @brief TODO
  1749. *
  1750. * @param[in] *msg constmessage
  1751. * @param[in] omit_fields bool
  1752. * @param[in] **result structmailmime
  1753. *
  1754. */
  1755. static PEP_STATUS mime_encode_message_PGP_MIME(
  1756. const message * msg,
  1757. bool omit_fields,
  1758. struct mailmime **result
  1759. )
  1760. {
  1761. struct mailmime * mime = NULL;
  1762. struct mailmime * submime = NULL;
  1763. struct mailmime_parameter * param;
  1764. int r;
  1765. PEP_STATUS status;
  1766. char *plaintext;
  1767. size_t plaintext_size;
  1768. assert(msg->attachments && msg->attachments->next &&
  1769. msg->attachments->next->value);
  1770. plaintext = msg->attachments->next->value;
  1771. plaintext_size = msg->attachments->next->size;
  1772. mime = part_multiple_new("multipart/encrypted");
  1773. assert(mime);
  1774. if (mime == NULL)
  1775. goto enomem;
  1776. param = mailmime_param_new_with_data("protocol", "application/pgp-encrypted");
  1777. clist_append(mime->mm_content_type->ct_parameters, param);
  1778. submime = get_pgp_encrypted_part();
  1779. assert(submime);
  1780. if (submime == NULL)
  1781. goto enomem;
  1782. r = mailmime_smart_add_part(mime, submime);
  1783. assert(r == MAILIMF_NO_ERROR);
  1784. if (r == MAILIMF_ERROR_MEMORY) {
  1785. goto enomem;
  1786. }
  1787. else {
  1788. // mailmime_smart_add_part() takes ownership of submime
  1789. submime = NULL;
  1790. }
  1791. pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
  1792. submime = get_text_part(resource, "application/octet-stream", plaintext,
  1793. plaintext_size, MAILMIME_MECHANISM_7BIT);
  1794. free_rid_list(resource);
  1795. assert(submime);
  1796. if (submime == NULL)
  1797. goto enomem;
  1798. r = mailmime_smart_add_part(mime, submime);
  1799. assert(r == MAILIMF_NO_ERROR);
  1800. if (r == MAILIMF_ERROR_MEMORY) {
  1801. goto enomem;
  1802. }
  1803. else {
  1804. // mailmime_smart_add_part() takes ownership of submime
  1805. submime = NULL;
  1806. }
  1807. *result = mime;
  1808. return PEP_STATUS_OK;
  1809. enomem:
  1810. status = PEP_OUT_OF_MEMORY;
  1811. if (mime)
  1812. mailmime_free(mime);
  1813. if (submime)
  1814. mailmime_free(submime);
  1815. return status;
  1816. }
  1817. DYNAMIC_API PEP_STATUS mime_encode_message(
  1818. const message * msg,
  1819. bool omit_fields,
  1820. char **mimetext,
  1821. bool has_pEp_msg_attachment
  1822. )
  1823. {
  1824. PEP_STATUS status = PEP_STATUS_OK;
  1825. struct mailmime * msg_mime = NULL;
  1826. struct mailmime * mime = NULL;
  1827. struct mailimf_fields * fields = NULL;
  1828. char *buf = NULL;
  1829. int r;
  1830. assert(msg);
  1831. assert(mimetext);
  1832. if (!(msg && mimetext))
  1833. return PEP_ILLEGAL_VALUE;
  1834. *mimetext = NULL;
  1835. switch (msg->enc_format) {
  1836. case PEP_enc_none:
  1837. status = mime_encode_message_plain(msg, omit_fields, &mime, has_pEp_msg_attachment);
  1838. break;
  1839. // I'm presuming we should hardcore ignoring has_pEp_msg_attachment here...
  1840. case PEP_enc_inline:
  1841. status = mime_encode_message_plain(msg, omit_fields, &mime, false);
  1842. break;
  1843. case PEP_enc_S_MIME:
  1844. NOT_IMPLEMENTED
  1845. case PEP_enc_PGP_MIME:
  1846. status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
  1847. break;
  1848. case PEP_enc_PEP:
  1849. // today's pEp message format is PGP/MIME from the outside
  1850. status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
  1851. break;
  1852. default:
  1853. NOT_IMPLEMENTED
  1854. }
  1855. if (status != PEP_STATUS_OK)
  1856. goto pEp_error;
  1857. msg_mime = mailmime_new_message_data(NULL);
  1858. assert(msg_mime);
  1859. if (msg_mime == NULL)
  1860. goto enomem;
  1861. r = mailmime_add_part(msg_mime, mime);
  1862. if (r) {
  1863. mailmime_free(mime);
  1864. goto enomem;
  1865. }
  1866. mime = NULL;
  1867. if (!omit_fields) {
  1868. status = build_fields(msg, &fields);
  1869. if (status != PEP_STATUS_OK)
  1870. goto pEp_error;
  1871. mailmime_set_imf_fields(msg_mime, fields);
  1872. }
  1873. status = render_mime(msg_mime, &buf);
  1874. if (status != PEP_STATUS_OK)
  1875. goto pEp_error;
  1876. mailmime_free(msg_mime);
  1877. *mimetext = buf;
  1878. return PEP_STATUS_OK;
  1879. enomem:
  1880. status = PEP_OUT_OF_MEMORY;
  1881. pEp_error:
  1882. if (msg_mime)
  1883. mailmime_free(msg_mime);
  1884. else
  1885. if (mime)
  1886. mailmime_free(mime);
  1887. return status;
  1888. }
  1889. /**
  1890. * @internal
  1891. *
  1892. * <!-- mailbox_to_identity() -->
  1893. *
  1894. * @brief TODO
  1895. *
  1896. * @param[in] *mb conststructmailimf_mailbox
  1897. *
  1898. */
  1899. static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
  1900. {
  1901. char *username = NULL;
  1902. char *address = NULL;
  1903. assert(mb);
  1904. assert(mb->mb_addr_spec);
  1905. if (mb->mb_addr_spec == NULL)
  1906. return NULL;
  1907. if (mb->mb_display_name) {
  1908. size_t index = 0;
  1909. const int r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
  1910. strlen(mb->mb_display_name), &index, "utf-8", &username);
  1911. if (r)
  1912. goto enomem;
  1913. }
  1914. const char* raw_addr = mb->mb_addr_spec;
  1915. if (raw_addr && raw_addr[0] == '"') {
  1916. int addr_len = strlen(raw_addr);
  1917. if (addr_len >= 6) { // ""@URI
  1918. const char* endcheck = strstr(raw_addr + 1, "\"@URI");
  1919. if (endcheck && *(endcheck + 5) == '\0') {
  1920. int actual_size = addr_len - 6;
  1921. address = calloc(actual_size + 1, 1);
  1922. if (!address)
  1923. goto enomem;
  1924. strlcpy(address, raw_addr + 1, actual_size + 1);
  1925. }
  1926. }
  1927. }
  1928. pEp_identity *ident = new_identity(address ? address : raw_addr, NULL, NULL, username);
  1929. if (ident == NULL)
  1930. goto enomem;
  1931. free(username);
  1932. free(address);
  1933. return ident;
  1934. enomem:
  1935. free(address);
  1936. free(username);
  1937. return NULL;
  1938. }
  1939. /**
  1940. * @internal
  1941. *
  1942. * <!-- mbl_to_identity() -->
  1943. *
  1944. * @brief TODO
  1945. *
  1946. * @param[in] *mbl conststructmailimf_mailbox_list
  1947. *
  1948. */
  1949. static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
  1950. {
  1951. struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
  1952. return mailbox_to_identity(mb);
  1953. }
  1954. /**
  1955. * @internal
  1956. *
  1957. * <!-- mal_to_identity_list() -->
  1958. *
  1959. * @brief TODO
  1960. *
  1961. * @param[in] *mal conststructmailimf_address_list
  1962. *
  1963. */
  1964. static identity_list * mal_to_identity_list(
  1965. const struct mailimf_address_list *mal
  1966. )
  1967. {
  1968. identity_list *il = new_identity_list(NULL);
  1969. if (il == NULL)
  1970. goto enomem;
  1971. // if we have nothing to translate then return an empty list
  1972. if (!mal)
  1973. return il;
  1974. clist *list = mal->ad_list;
  1975. identity_list *_il = il;
  1976. for (clistiter *cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
  1977. pEp_identity *ident;
  1978. struct mailimf_address *addr = clist_content(cur);
  1979. switch(addr->ad_type) {
  1980. case MAILIMF_ADDRESS_MAILBOX:
  1981. ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
  1982. if (ident == NULL)
  1983. goto enomem;
  1984. _il = identity_list_add(_il, ident);
  1985. if (_il == NULL)
  1986. goto enomem;
  1987. break;
  1988. case MAILIMF_ADDRESS_GROUP:
  1989. {
  1990. struct mailimf_mailbox_list * mbl =
  1991. addr->ad_data.ad_group->grp_mb_list;
  1992. for (clistiter *cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
  1993. cur2 = clist_next(cur2)) {
  1994. ident = mailbox_to_identity(clist_content(cur));
  1995. if (ident == NULL)
  1996. goto enomem;
  1997. _il = identity_list_add(_il, ident);
  1998. if (_il == NULL)
  1999. goto enomem;
  2000. }
  2001. }
  2002. break;
  2003. default:
  2004. assert(0);
  2005. goto enomem;
  2006. }
  2007. }
  2008. return il;
  2009. enomem:
  2010. free_identity_list(il);
  2011. return NULL;
  2012. }
  2013. /**
  2014. * @internal
  2015. *
  2016. * <!-- clist_to_stringlist() -->
  2017. *
  2018. * @brief TODO
  2019. *
  2020. * @param[in] *list constclist
  2021. *
  2022. */
  2023. static stringlist_t * clist_to_stringlist(const clist *list)
  2024. {
  2025. char *text = NULL;;
  2026. stringlist_t * sl = new_stringlist(NULL);
  2027. if (sl == NULL)
  2028. return NULL;
  2029. stringlist_t *_sl = sl;
  2030. for (clistiter *cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
  2031. char *phrase = clist_content(cur);
  2032. size_t index = 0;
  2033. const int r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
  2034. &index, "utf-8", &text);
  2035. if (r)
  2036. goto enomem;
  2037. _sl = stringlist_add(_sl, text);
  2038. if (_sl == NULL)
  2039. goto enomem;
  2040. free(text);
  2041. text = NULL;
  2042. }
  2043. return sl;
  2044. enomem:
  2045. free_stringlist(sl);
  2046. free(text);
  2047. return NULL;
  2048. }
  2049. /**
  2050. * @internal
  2051. *
  2052. * <!-- read_fields() -->
  2053. *
  2054. * @brief TODO
  2055. *
  2056. * @param