libetpan - fdik
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.

1681 lines
46 KiB

11 years ago
11 years ago
11 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
11 years ago
4 years ago
11 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  1. /*
  2. * libEtPan! -- a mail stuff library
  3. *
  4. * Copyright (C) 2001, 2005 - DINH Viet Hoa
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the libEtPan! project nor the names of its
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
  20. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
  23. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. * SUCH DAMAGE.
  30. */
  31. /*
  32. * $Id: mailmime_write_generic.c,v 1.13 2011/06/25 15:30:46 hoa Exp $
  33. */
  34. #ifdef HAVE_CONFIG_H
  35. # include <config.h>
  36. #endif
  37. #include "mailmime_write_generic.h"
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <time.h>
  41. #ifdef HAVE_UNISTD_H
  42. # include <unistd.h>
  43. #endif
  44. #include <sys/types.h>
  45. #include <sys/stat.h>
  46. #include <fcntl.h>
  47. #ifdef HAVE_SYS_MMAN_H
  48. # include <sys/mman.h>
  49. #endif
  50. #include <errno.h>
  51. #ifdef WIN32
  52. # include "win_etpan.h"
  53. #endif
  54. #include "mailimf_write_generic.h"
  55. #include "mailmime_content.h"
  56. #include "mailmime_types_helper.h"
  57. #include "syscall_wrappers.h"
  58. #define MAX_MAIL_COL 78
  59. #ifndef TRUE
  60. #define TRUE 1
  61. #endif
  62. #ifndef FALSE
  63. #define FALSE 0
  64. #endif
  65. static int mailmime_field_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  66. struct mailmime_field * field);
  67. static int mailmime_id_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, char * id);
  68. static int mailmime_description_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, char * descr);
  69. static int mailmime_version_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, uint32_t version);
  70. static int mailmime_encoding_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  71. struct mailmime_mechanism * encoding);
  72. static int mailmime_language_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  73. struct mailmime_language * language);
  74. static int mailmime_disposition_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  75. struct mailmime_disposition *
  76. disposition);
  77. static int
  78. mailmime_disposition_param_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  79. struct mailmime_disposition_parm * param);
  80. static int mailmime_parameter_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  81. struct mailmime_parameter * param);
  82. /*
  83. static int mailmime_content_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  84. struct mailmime_content * content);
  85. */
  86. static int mailmime_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  87. struct mailmime_type * type);
  88. static int
  89. mailmime_discrete_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  90. struct mailmime_discrete_type * discrete_type);
  91. static int
  92. mailmime_composite_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  93. struct mailmime_composite_type * composite_type);
  94. static int mailmime_sub_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  95. struct mailmime * build_info);
  96. /* ***** */
  97. int mailmime_fields_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, struct mailmime_fields * fields)
  98. {
  99. int r;
  100. clistiter * cur;
  101. for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
  102. cur = clist_next(cur)) {
  103. struct mailmime_field * field;
  104. field = cur->data;
  105. r = mailmime_field_write_driver(do_write, data, col, field);
  106. if (r != MAILIMF_NO_ERROR)
  107. return r;
  108. }
  109. return MAILIMF_NO_ERROR;
  110. }
  111. static int mailmime_field_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  112. struct mailmime_field * field)
  113. {
  114. int r;
  115. switch (field->fld_type) {
  116. case MAILMIME_FIELD_TYPE:
  117. r = mailmime_content_write_driver(do_write, data, col, field->fld_data.fld_content);
  118. break;
  119. case MAILMIME_FIELD_TRANSFER_ENCODING:
  120. r = mailmime_encoding_write_driver(do_write, data, col, field->fld_data.fld_encoding);
  121. break;
  122. case MAILMIME_FIELD_ID:
  123. r = mailmime_id_write_driver(do_write, data, col, field->fld_data.fld_id);
  124. break;
  125. case MAILMIME_FIELD_DESCRIPTION:
  126. r = mailmime_description_write_driver(do_write, data, col, field->fld_data.fld_description);
  127. break;
  128. case MAILMIME_FIELD_VERSION:
  129. r = mailmime_version_write_driver(do_write, data, col, field->fld_data.fld_version);
  130. break;
  131. case MAILMIME_FIELD_DISPOSITION:
  132. r = mailmime_disposition_write_driver(do_write, data, col, field->fld_data.fld_disposition);
  133. break;
  134. case MAILMIME_FIELD_LANGUAGE:
  135. r = mailmime_language_write_driver(do_write, data, col, field->fld_data.fld_language);
  136. break;
  137. default:
  138. r = MAILIMF_ERROR_INVAL;
  139. break;
  140. }
  141. if (r != MAILIMF_NO_ERROR)
  142. return r;
  143. return MAILIMF_NO_ERROR;
  144. }
  145. static int mailmime_id_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, char * id)
  146. {
  147. int r;
  148. r = mailimf_string_write_driver(do_write, data, col, "Content-ID: ", 12);
  149. if (r != MAILIMF_NO_ERROR)
  150. return r;
  151. r = mailimf_string_write_driver(do_write, data, col, "<", 1);
  152. if (r != MAILIMF_NO_ERROR)
  153. return r;
  154. r = mailimf_string_write_driver(do_write, data, col, id, strlen(id));
  155. if (r != MAILIMF_NO_ERROR)
  156. return r;
  157. r = mailimf_string_write_driver(do_write, data, col, ">", 1);
  158. if (r != MAILIMF_NO_ERROR)
  159. return r;
  160. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  161. if (r != MAILIMF_NO_ERROR)
  162. return r;
  163. #if 0
  164. * col = 0;
  165. #endif
  166. return MAILIMF_NO_ERROR;
  167. }
  168. static int mailmime_description_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, char * descr)
  169. {
  170. int r;
  171. r = mailimf_string_write_driver(do_write, data, col, "Content-Description: ", 21);
  172. if (r != MAILIMF_NO_ERROR)
  173. return r;
  174. r = mailimf_string_write_driver(do_write, data, col, descr, strlen(descr));
  175. if (r != MAILIMF_NO_ERROR)
  176. return r;
  177. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  178. if (r != MAILIMF_NO_ERROR)
  179. return r;
  180. #if 0
  181. * col = 0;
  182. #endif
  183. return MAILIMF_NO_ERROR;
  184. }
  185. static int mailmime_version_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, uint32_t version)
  186. {
  187. int r;
  188. char versionstr[40];
  189. r = mailimf_string_write_driver(do_write, data, col, "MIME-Version: ", 14);
  190. if (r != MAILIMF_NO_ERROR)
  191. return r;
  192. snprintf(versionstr, 40, "%i.%i", version >> 16, version & 0xFFFF);
  193. r = mailimf_string_write_driver(do_write, data, col, versionstr, strlen(versionstr));
  194. if (r != MAILIMF_NO_ERROR)
  195. return r;
  196. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  197. if (r != MAILIMF_NO_ERROR)
  198. return r;
  199. #if 0
  200. * col = 0;
  201. #endif
  202. return MAILIMF_NO_ERROR;
  203. }
  204. static int mailmime_encoding_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  205. struct mailmime_mechanism * encoding)
  206. {
  207. int r;
  208. r = mailimf_string_write_driver(do_write, data, col, "Content-Transfer-Encoding: ", 27);
  209. if (r != MAILIMF_NO_ERROR)
  210. return r;
  211. switch (encoding->enc_type) {
  212. case MAILMIME_MECHANISM_7BIT:
  213. r = mailimf_string_write_driver(do_write, data, col, "7bit", 4);
  214. break;
  215. case MAILMIME_MECHANISM_8BIT:
  216. r = mailimf_string_write_driver(do_write, data, col, "8bit", 4);
  217. break;
  218. case MAILMIME_MECHANISM_BINARY:
  219. r = mailimf_string_write_driver(do_write, data, col, "binary", 6);
  220. break;
  221. case MAILMIME_MECHANISM_QUOTED_PRINTABLE:
  222. r = mailimf_string_write_driver(do_write, data, col, "quoted-printable", 16);
  223. break;
  224. case MAILMIME_MECHANISM_BASE64:
  225. r = mailimf_string_write_driver(do_write, data, col, "base64", 6);
  226. break;
  227. case MAILMIME_MECHANISM_TOKEN:
  228. r = mailimf_string_write_driver(do_write, data, col, encoding->enc_token,
  229. strlen(encoding->enc_token));
  230. break;
  231. default:
  232. r = MAILIMF_ERROR_INVAL;
  233. break;
  234. }
  235. if (r != MAILIMF_NO_ERROR)
  236. return r;
  237. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  238. if (r != MAILIMF_NO_ERROR)
  239. return r;
  240. #if 0
  241. * col = 0;
  242. #endif
  243. return MAILIMF_NO_ERROR;
  244. }
  245. static int mailmime_language_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  246. struct mailmime_language * language)
  247. {
  248. int r;
  249. clistiter * cur;
  250. int first;
  251. r = mailimf_string_write_driver(do_write, data, col, "Content-Language: ", 18);
  252. if (r != MAILIMF_NO_ERROR)
  253. return r;
  254. first = TRUE;
  255. for(cur = clist_begin(language->lg_list) ; cur != NULL ;
  256. cur = clist_next(cur)) {
  257. char * lang;
  258. size_t len;
  259. lang = clist_content(cur);
  260. len = strlen(lang);
  261. if (!first) {
  262. r = mailimf_string_write_driver(do_write, data, col, ", ", 2);
  263. if (r != MAILIMF_NO_ERROR)
  264. return r;
  265. }
  266. else {
  267. first = FALSE;
  268. }
  269. if (* col > 1) {
  270. if (* col + len > MAX_MAIL_COL) {
  271. r = mailimf_string_write_driver(do_write, data, col, "\r\n ", 3);
  272. if (r != MAILIMF_NO_ERROR)
  273. return r;
  274. #if 0
  275. * col = 1;
  276. #endif
  277. }
  278. }
  279. r = mailimf_string_write_driver(do_write, data, col, lang, len);
  280. if (r != MAILIMF_NO_ERROR)
  281. return r;
  282. }
  283. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  284. if (r != MAILIMF_NO_ERROR)
  285. return r;
  286. #if 0
  287. * col = 0;
  288. #endif
  289. return MAILIMF_NO_ERROR;
  290. }
  291. static int mailmime_disposition_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  292. struct mailmime_disposition *
  293. disposition)
  294. {
  295. struct mailmime_disposition_type * dsp_type;
  296. int r;
  297. clistiter * cur;
  298. dsp_type = disposition->dsp_type;
  299. r = mailimf_string_write_driver(do_write, data, col, "Content-Disposition: ", 21);
  300. if (r != MAILIMF_NO_ERROR)
  301. return r;
  302. switch (dsp_type->dsp_type) {
  303. case MAILMIME_DISPOSITION_TYPE_INLINE:
  304. r = mailimf_string_write_driver(do_write, data, col, "inline", 6);
  305. break;
  306. case MAILMIME_DISPOSITION_TYPE_ATTACHMENT:
  307. r = mailimf_string_write_driver(do_write, data, col, "attachment", 10);
  308. break;
  309. case MAILMIME_DISPOSITION_TYPE_EXTENSION:
  310. r = mailimf_string_write_driver(do_write, data, col, dsp_type->dsp_extension,
  311. strlen(dsp_type->dsp_extension));
  312. break;
  313. default:
  314. r = MAILIMF_ERROR_INVAL;
  315. break;
  316. }
  317. if (r != MAILIMF_NO_ERROR)
  318. return r;
  319. for(cur = clist_begin(disposition->dsp_parms) ;
  320. cur != NULL ; cur = clist_next(cur)) {
  321. struct mailmime_disposition_parm * param;
  322. param = cur->data;
  323. r = mailimf_string_write_driver(do_write, data, col, "; ", 2);
  324. if (r != MAILIMF_NO_ERROR)
  325. return r;
  326. r = mailmime_disposition_param_write_driver(do_write, data, col, param);
  327. if (r != MAILIMF_NO_ERROR)
  328. return r;
  329. }
  330. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  331. if (r != MAILIMF_NO_ERROR)
  332. return r;
  333. return MAILIMF_NO_ERROR;
  334. }
  335. static void
  336. break_filename(char** extended_filename, const char* filename_str,
  337. size_t length, int is_encoded) {
  338. if (!extended_filename || !filename_str || length < 1)
  339. return;
  340. char* retstr = NULL;
  341. clist* line_list = clist_new();
  342. // We'll be adding a lot of ";\r\n" into the output, so we make an initial educated guess on size
  343. size_t filename_key_len = (is_encoded ? 11 : 10); // " filename*0*=" | " filename*0="
  344. size_t addl_chars_len = (is_encoded ? 3 : 5); // ";\r\n" + 2 quotes
  345. const char* equals_str = (is_encoded ? "*=" : "=\"");
  346. const char* end_str = (is_encoded ? ";\r\n" : "\";\r\n");
  347. size_t key_buffer_size = filename_key_len + 5; // This is ridiculous, because 1000+ -part filenames??? But ok.
  348. int curr_line_count = 0;
  349. int curr_char_count = 0;
  350. const char* curr_src_ptr = filename_str;
  351. const char* curr_src_end = filename_str + strlen(filename_str);
  352. size_t end_string_size = (is_encoded ? 3 : 4);
  353. char curr_line_buf[80];
  354. char* temp_octet_buffer[80];
  355. snprintf(curr_line_buf, key_buffer_size, "\r\n");
  356. clist_append(line_list, strdup(curr_line_buf));
  357. for (curr_char_count = 2; curr_src_ptr < curr_src_end; curr_line_count++) {
  358. // Start line.
  359. if (curr_line_count > 9999)
  360. return; // FIXME - free stuff
  361. char* curr_line_ptr = curr_line_buf;
  362. snprintf(curr_line_buf, key_buffer_size, " filename*%d%s", curr_line_count, equals_str);
  363. size_t curr_key_len = strlen(curr_line_buf);
  364. curr_line_ptr += curr_key_len;
  365. curr_char_count += curr_key_len;
  366. size_t max_remaining_line_chars = length - curr_key_len - addl_chars_len;
  367. unsigned int i;
  368. if (!is_encoded) {
  369. for (i = 0; i < max_remaining_line_chars && curr_src_ptr < curr_src_end; i++) {
  370. *curr_line_ptr++ = *curr_src_ptr++;
  371. curr_char_count++;
  372. }
  373. }
  374. else {
  375. // Fun fun fun.
  376. // UTF-8 characters run between one and four octets. Thus, we
  377. // should always be safe copying the first max_remaining - 3 of them
  378. // and then finding a break either there or in the next 3 chars.
  379. // Copy in the first max - 3 chars
  380. size_t max_safe = max_remaining_line_chars - 3;
  381. for (i = 0; i < max_safe && curr_src_ptr < curr_src_end; i++) {
  382. *curr_line_ptr++ = *curr_src_ptr++;
  383. curr_char_count++;
  384. }
  385. if (curr_src_ptr != curr_src_end) {
  386. // Check last copied char
  387. unsigned char tester = (unsigned char) *(curr_line_ptr - 1);
  388. // Check to see if it's the start of a four-byte char
  389. if (tester >= 0xF0) {
  390. // Add the next three
  391. for (i = 0; i < 3 && curr_src_ptr < curr_src_end; i++) {
  392. tester = (unsigned char) *curr_src_ptr++;
  393. *curr_line_ptr++ = tester;
  394. curr_char_count++;
  395. }
  396. }
  397. else if (tester >= 0x80) { // Ok, it's either two or three, or we're in the middle
  398. // Find a break in the next 3 characters.
  399. for (i = 0; i < 2 && curr_src_ptr < curr_src_end; i++) {
  400. tester = (unsigned char) *(curr_src_ptr); // this advances it one to where the src starts for analysis
  401. // Is this byte the start of a new character?
  402. if (tester < 0x7F || tester > 0xC0)
  403. break;
  404. // Nope, check the next
  405. *curr_line_ptr++ = tester;
  406. curr_src_ptr++;
  407. curr_char_count++;
  408. }
  409. }
  410. }
  411. }
  412. if (curr_src_ptr >= curr_src_end) {
  413. strcpy(curr_line_ptr, (is_encoded ? "\r\n" : "\"\r\n"));
  414. curr_char_count += (is_encoded ? 2 : 3);
  415. clist_append(line_list, strdup(curr_line_buf));
  416. break;
  417. }
  418. else {
  419. strcpy(curr_line_ptr, end_str);
  420. curr_char_count += end_string_size;
  421. clist_append(line_list, strdup(curr_line_buf));
  422. }
  423. }
  424. size_t fname_size = curr_char_count + 1;
  425. *extended_filename = calloc(fname_size, 1);
  426. clistiter* cur;
  427. // int start = 1;
  428. if (line_list) {
  429. for(cur = clist_begin(line_list) ; cur != NULL ; cur = clist_next(cur)) {
  430. // if (start) {
  431. // strcpy(*extended_filename, ((char*)(cur->data)));
  432. // start = 0;
  433. // }
  434. // else {
  435. strcat(*extended_filename, ((char*)(cur->data)));
  436. // }
  437. free(cur->data);
  438. cur->data = NULL;
  439. }
  440. }
  441. clist_free(line_list);
  442. }
  443. static int
  444. mailmime_disposition_param_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  445. struct mailmime_disposition_parm * param)
  446. {
  447. size_t len;
  448. char sizestr[20];
  449. int r;
  450. int has_extended_filename = 0;
  451. int has_encoded_filename = 0;
  452. char* extended_filename = NULL;
  453. const char* filename_key = "filename=";
  454. size_t filename_key_len = strlen(filename_key);
  455. char* fname = param->pa_data.pa_filename;
  456. const int _MIME_LINE_LENGTH = 72;
  457. const int _QUOTES_PLUS_SPACE_LEN = 3;
  458. size_t filename_strlen;
  459. switch (param->pa_type) {
  460. case MAILMIME_DISPOSITION_PARM_FILENAME:
  461. filename_strlen = strlen(fname);
  462. if (strstr(fname, "utf-8''") == fname) {
  463. // we're in for some fun here...
  464. has_encoded_filename = 1;
  465. filename_key_len++;
  466. }
  467. if ((filename_strlen + filename_key_len + _QUOTES_PLUS_SPACE_LEN) > _MIME_LINE_LENGTH)
  468. has_extended_filename = 1;
  469. size_t filename_strlen = strlen(fname);
  470. if (!has_extended_filename) {
  471. if (has_encoded_filename) {
  472. filename_key = "filename*=";
  473. }
  474. len = filename_key_len + strlen(fname);
  475. }
  476. else {
  477. break_filename(&extended_filename, fname, _MIME_LINE_LENGTH, has_encoded_filename);
  478. len = (extended_filename ? strlen(extended_filename) : 0);
  479. }
  480. break;
  481. case MAILMIME_DISPOSITION_PARM_CREATION_DATE:
  482. len = strlen("creation-date=") + strlen(param->pa_data.pa_creation_date);
  483. break;
  484. case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE:
  485. len = strlen("modification-date=") +
  486. strlen(param->pa_data.pa_modification_date);
  487. break;
  488. case MAILMIME_DISPOSITION_PARM_READ_DATE:
  489. len = strlen("read-date=") + strlen(param->pa_data.pa_read_date);
  490. break;
  491. case MAILMIME_DISPOSITION_PARM_SIZE:
  492. snprintf(sizestr, 20, "%lu", (unsigned long) param->pa_data.pa_size);
  493. len = strlen("size=") + strlen(sizestr);
  494. break;
  495. case MAILMIME_DISPOSITION_PARM_PARAMETER:
  496. len = strlen(param->pa_data.pa_parameter->pa_name) + 1 +
  497. strlen(param->pa_data.pa_parameter->pa_value);
  498. break;
  499. default:
  500. return MAILIMF_ERROR_INVAL;
  501. }
  502. // KG: FIXME - this could cause us trouble
  503. if (* col > 1 && !extended_filename) {
  504. if (* col + len > MAX_MAIL_COL) {
  505. r = mailimf_string_write_driver(do_write, data, col, "\r\n ", 3);
  506. if (r != MAILIMF_NO_ERROR)
  507. return r;
  508. #if 0
  509. * col = 1;
  510. #endif
  511. }
  512. }
  513. switch (param->pa_type) {
  514. case MAILMIME_DISPOSITION_PARM_FILENAME:
  515. if (extended_filename) {
  516. r = mailimf_string_write_driver(do_write, data, col,
  517. extended_filename,
  518. strlen(extended_filename));
  519. if (r != MAILIMF_NO_ERROR)
  520. return r;
  521. free(extended_filename);
  522. }
  523. else {
  524. r = mailimf_string_write_driver(do_write, data, col,
  525. filename_key, filename_key_len);
  526. if (r != MAILIMF_NO_ERROR)
  527. return r;
  528. r = mailimf_string_write_driver(do_write, data, col,
  529. param->pa_data.pa_filename, strlen(param->pa_data.pa_filename));
  530. if (r != MAILIMF_NO_ERROR)
  531. return r;
  532. }
  533. // param->pa_data.pa_filename, strlen(param->pa_data.pa_filename));
  534. // r = mailimf_quoted_string_write_driver(do_write, data, col,
  535. break;
  536. case MAILMIME_DISPOSITION_PARM_CREATION_DATE:
  537. r = mailimf_string_write_driver(do_write, data, col, "creation-date=", 14);
  538. if (r != MAILIMF_NO_ERROR)
  539. return r;
  540. r = mailimf_quoted_string_write_driver(do_write, data, col, param->pa_data.pa_creation_date,
  541. strlen(param->pa_data.pa_creation_date));
  542. if (r != MAILIMF_NO_ERROR)
  543. return r;
  544. break;
  545. case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE:
  546. r = mailimf_string_write_driver(do_write, data, col, "modification-date=", 18);
  547. if (r != MAILIMF_NO_ERROR)
  548. return r;
  549. r = mailimf_quoted_string_write_driver(do_write, data, col,
  550. param->pa_data.pa_modification_date,
  551. strlen(param->pa_data.pa_modification_date));
  552. if (r != MAILIMF_NO_ERROR)
  553. return r;
  554. break;
  555. case MAILMIME_DISPOSITION_PARM_READ_DATE:
  556. r = mailimf_string_write_driver(do_write, data, col, "read-date=", 10);
  557. if (r != MAILIMF_NO_ERROR)
  558. return r;
  559. r = mailimf_quoted_string_write_driver(do_write, data, col, param->pa_data.pa_read_date,
  560. strlen(param->pa_data.pa_read_date));
  561. if (r != MAILIMF_NO_ERROR)
  562. return r;
  563. break;
  564. case MAILMIME_DISPOSITION_PARM_SIZE:
  565. r = mailimf_string_write_driver(do_write, data, col, "size=", 5);
  566. if (r != MAILIMF_NO_ERROR)
  567. return r;
  568. r = mailimf_string_write_driver(do_write, data, col, sizestr, strlen(sizestr));
  569. if (r != MAILIMF_NO_ERROR)
  570. return r;
  571. break;
  572. case MAILMIME_DISPOSITION_PARM_PARAMETER:
  573. r = mailmime_parameter_write_driver(do_write, data, col, param->pa_data.pa_parameter);
  574. if (r != MAILIMF_NO_ERROR)
  575. return r;
  576. break;
  577. }
  578. return MAILIMF_NO_ERROR;
  579. }
  580. static int mailmime_parameter_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  581. struct mailmime_parameter * param)
  582. {
  583. int r;
  584. r = mailimf_string_write_driver(do_write, data, col, param->pa_name,
  585. strlen(param->pa_name));
  586. if (r != MAILIMF_NO_ERROR)
  587. return r;
  588. r = mailimf_string_write_driver(do_write, data, col, "=", 1);
  589. if (r != MAILIMF_NO_ERROR)
  590. return r;
  591. r = mailimf_quoted_string_write_driver(do_write, data, col, param->pa_value,
  592. strlen(param->pa_value));
  593. if (r != MAILIMF_NO_ERROR)
  594. return r;
  595. return MAILIMF_NO_ERROR;
  596. }
  597. int mailmime_content_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  598. struct mailmime_content * content)
  599. {
  600. clistiter * cur;
  601. size_t len;
  602. int r;
  603. r = mailmime_type_write_driver(do_write, data, col, content->ct_type);
  604. if (r != MAILIMF_NO_ERROR)
  605. return r;
  606. r = mailimf_string_write_driver(do_write, data, col, "/", 1);
  607. if (r != MAILIMF_NO_ERROR)
  608. return r;
  609. r = mailimf_string_write_driver(do_write, data, col, content->ct_subtype,
  610. strlen(content->ct_subtype));
  611. if (r != MAILIMF_NO_ERROR)
  612. return r;
  613. if (content->ct_parameters != NULL) {
  614. for(cur = clist_begin(content->ct_parameters) ;
  615. cur != NULL ; cur = clist_next(cur)) {
  616. struct mailmime_parameter * param;
  617. param = cur->data;
  618. r = mailimf_string_write_driver(do_write, data, col, "; ", 2);
  619. if (r != MAILIMF_NO_ERROR)
  620. return r;
  621. len = strlen(param->pa_name) + 1 + strlen(param->pa_value);
  622. if (* col > 1) {
  623. if (* col + len > MAX_MAIL_COL) {
  624. r = mailimf_string_write_driver(do_write, data, col, "\r\n ", 3);
  625. if (r != MAILIMF_NO_ERROR)
  626. return r;
  627. #if 0
  628. * col = 1;
  629. #endif
  630. }
  631. }
  632. r = mailmime_parameter_write_driver(do_write, data, col, param);
  633. if (r != MAILIMF_NO_ERROR)
  634. return r;
  635. }
  636. }
  637. return MAILIMF_NO_ERROR;
  638. }
  639. int mailmime_content_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  640. struct mailmime_content * content)
  641. {
  642. int r;
  643. r = mailimf_string_write_driver(do_write, data, col, "Content-Type: ", 14);
  644. if (r != MAILIMF_NO_ERROR)
  645. return r;
  646. r = mailmime_content_type_write_driver(do_write, data, col, content);
  647. if (r != MAILIMF_NO_ERROR)
  648. return r;
  649. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  650. if (r != MAILIMF_NO_ERROR)
  651. return r;
  652. return MAILIMF_NO_ERROR;
  653. }
  654. static int mailmime_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  655. struct mailmime_type * type)
  656. {
  657. int r;
  658. switch (type->tp_type) {
  659. case MAILMIME_TYPE_DISCRETE_TYPE:
  660. r = mailmime_discrete_type_write_driver(do_write, data, col, type->tp_data.tp_discrete_type);
  661. break;
  662. case MAILMIME_TYPE_COMPOSITE_TYPE:
  663. r = mailmime_composite_type_write_driver(do_write, data, col, type->tp_data.tp_composite_type);
  664. break;
  665. default:
  666. r = MAILIMF_ERROR_INVAL;
  667. break;
  668. }
  669. if (r != MAILIMF_NO_ERROR)
  670. return r;
  671. return MAILIMF_NO_ERROR;
  672. }
  673. static int
  674. mailmime_discrete_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  675. struct mailmime_discrete_type * discrete_type)
  676. {
  677. int r;
  678. switch (discrete_type->dt_type) {
  679. case MAILMIME_DISCRETE_TYPE_TEXT:
  680. r = mailimf_string_write_driver(do_write, data, col, "text", 4);
  681. break;
  682. case MAILMIME_DISCRETE_TYPE_IMAGE:
  683. r = mailimf_string_write_driver(do_write, data, col, "image", 5);
  684. break;
  685. case MAILMIME_DISCRETE_TYPE_AUDIO:
  686. r = mailimf_string_write_driver(do_write, data, col, "audio", 5);
  687. break;
  688. case MAILMIME_DISCRETE_TYPE_VIDEO:
  689. r = mailimf_string_write_driver(do_write, data, col, "video", 5);
  690. break;
  691. case MAILMIME_DISCRETE_TYPE_APPLICATION:
  692. r = mailimf_string_write_driver(do_write, data, col, "application", 11);
  693. break;
  694. case MAILMIME_DISCRETE_TYPE_EXTENSION:
  695. r = mailimf_string_write_driver(do_write, data, col, discrete_type->dt_extension,
  696. strlen(discrete_type->dt_extension));
  697. break;
  698. default:
  699. r = MAILIMF_ERROR_INVAL;
  700. break;
  701. }
  702. if (r != MAILIMF_NO_ERROR)
  703. return r;
  704. return MAILIMF_NO_ERROR;
  705. }
  706. static int
  707. mailmime_composite_type_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  708. struct mailmime_composite_type * composite_type)
  709. {
  710. int r;
  711. switch (composite_type->ct_type) {
  712. case MAILMIME_COMPOSITE_TYPE_MESSAGE:
  713. r = mailimf_string_write_driver(do_write, data, col, "message", 7);
  714. break;
  715. case MAILMIME_COMPOSITE_TYPE_MULTIPART:
  716. r = mailimf_string_write_driver(do_write, data, col, "multipart", 9);
  717. break;
  718. case MAILMIME_COMPOSITE_TYPE_EXTENSION:
  719. r = mailimf_string_write_driver(do_write, data, col, composite_type->ct_token,
  720. strlen(composite_type->ct_token));
  721. break;
  722. default:
  723. r = MAILIMF_ERROR_INVAL;
  724. break;
  725. }
  726. if (r != MAILIMF_NO_ERROR)
  727. return r;
  728. return MAILIMF_NO_ERROR;
  729. }
  730. /* ****************************************************************** */
  731. /* message */
  732. /*
  733. static int mailmime_data_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  734. struct mailmime_data * data,
  735. int is_text);
  736. */
  737. static int mailmime_text_content_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, int encoding,
  738. int istext,
  739. const char * text, size_t size);
  740. /*
  741. static int mailmime_base64_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  742. char * text, size_t size);
  743. static int mailmime_quoted_printable_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, int istext,
  744. char * text, size_t size);
  745. */
  746. static int mailmime_part_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  747. struct mailmime * build_info)
  748. {
  749. clistiter * cur;
  750. int first;
  751. int r;
  752. char * boundary;
  753. int istext;
  754. int res;
  755. istext = TRUE;
  756. boundary = NULL;
  757. if (build_info->mm_content_type != NULL) {
  758. if (build_info->mm_type == MAILMIME_MULTIPLE) {
  759. boundary = mailmime_extract_boundary(build_info->mm_content_type);
  760. if (boundary == NULL) {
  761. boundary = mailmime_generate_boundary();
  762. if (boundary == NULL) {
  763. res = MAILIMF_ERROR_MEMORY;
  764. goto err;
  765. }
  766. }
  767. }
  768. if (build_info->mm_content_type->ct_type->tp_type ==
  769. MAILMIME_TYPE_DISCRETE_TYPE) {
  770. if (build_info->mm_content_type->ct_type->tp_data.tp_discrete_type->dt_type !=
  771. MAILMIME_DISCRETE_TYPE_TEXT)
  772. istext = FALSE;
  773. }
  774. }
  775. switch (build_info->mm_type) {
  776. case MAILMIME_SINGLE:
  777. /* 1-part body */
  778. if (build_info->mm_data.mm_single != NULL) {
  779. r = mailmime_data_write_driver(do_write, data, col, build_info->mm_data.mm_single, istext);
  780. if (r != MAILIMF_NO_ERROR) {
  781. res = r;
  782. goto free_boundary;
  783. }
  784. }
  785. break;
  786. case MAILMIME_MULTIPLE:
  787. /* multi-part */
  788. /* preamble */
  789. if (build_info->mm_data.mm_multipart.mm_preamble != NULL) {
  790. r = mailmime_data_write_driver(do_write, data, col,
  791. build_info->mm_data.mm_multipart.mm_preamble, TRUE);
  792. if (r != MAILIMF_NO_ERROR) {
  793. res = r;
  794. goto free_boundary;
  795. }
  796. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  797. if (r != MAILIMF_NO_ERROR) {
  798. res = r;
  799. goto free_boundary;
  800. }
  801. }
  802. /* sub-parts */
  803. first = TRUE;
  804. for(cur = clist_begin(build_info->mm_data.mm_multipart.mm_mp_list) ;
  805. cur != NULL ; cur = clist_next(cur)) {
  806. struct mailmime * subpart;
  807. subpart = cur->data;
  808. if (!first) {
  809. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  810. if (r != MAILIMF_NO_ERROR) {
  811. res = r;
  812. goto free_boundary;
  813. }
  814. }
  815. else {
  816. first = FALSE;
  817. }
  818. r = mailimf_string_write_driver(do_write, data, col, "--", 2);
  819. if (r != MAILIMF_NO_ERROR) {
  820. res = r;
  821. goto free_boundary;
  822. }
  823. if (boundary == NULL) {
  824. // Make clang static analyzer happy.
  825. res = MAILIMF_ERROR_MEMORY;
  826. goto free_boundary;
  827. }
  828. r = mailimf_string_write_driver(do_write, data, col, boundary, strlen(boundary));
  829. if (r != MAILIMF_NO_ERROR) {
  830. res = r;
  831. goto free_boundary;
  832. }
  833. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  834. if (r != MAILIMF_NO_ERROR) {
  835. res = r;
  836. goto free_boundary;
  837. }
  838. r = mailmime_sub_write_driver(do_write, data, col, subpart);
  839. if (r != MAILIMF_NO_ERROR) {
  840. res = r;
  841. goto free_boundary;
  842. }
  843. }
  844. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  845. if (r != MAILIMF_NO_ERROR) {
  846. res = r;
  847. goto free_boundary;
  848. }
  849. r = mailimf_string_write_driver(do_write, data, col, "--", 2);
  850. if (r != MAILIMF_NO_ERROR) {
  851. res = r;
  852. goto free_boundary;
  853. }
  854. if (boundary == NULL) {
  855. // Make clang static analyzer happy.
  856. res = MAILIMF_ERROR_MEMORY;
  857. goto free_boundary;
  858. }
  859. r = mailimf_string_write_driver(do_write, data, col, boundary, strlen(boundary));
  860. if (r != MAILIMF_NO_ERROR) {
  861. res = r;
  862. goto free_boundary;
  863. }
  864. r = mailimf_string_write_driver(do_write, data, col, "--", 2);
  865. if (r != MAILIMF_NO_ERROR) {
  866. res = r;
  867. goto free_boundary;
  868. }
  869. /* epilogue */
  870. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  871. if (r != MAILIMF_NO_ERROR) {
  872. res = r;
  873. goto free_boundary;
  874. }
  875. if (build_info->mm_data.mm_multipart.mm_epilogue != NULL) {
  876. r = mailmime_data_write_driver(do_write, data, col,
  877. build_info->mm_data.mm_multipart.mm_epilogue, TRUE);
  878. if (r != MAILIMF_NO_ERROR) {
  879. res = r;
  880. goto free_boundary;
  881. }
  882. }
  883. break;
  884. case MAILMIME_MESSAGE:
  885. if (build_info->mm_data.mm_message.mm_fields != NULL) {
  886. r = mailimf_fields_write_driver(do_write, data, col,
  887. build_info->mm_data.mm_message.mm_fields);
  888. if (r != MAILIMF_NO_ERROR) {
  889. res = r;
  890. goto free_boundary;
  891. }
  892. }
  893. if (build_info->mm_mime_fields != NULL) {
  894. int r;
  895. clistiter * cur;
  896. for(cur = clist_begin(build_info->mm_mime_fields->fld_list) ;
  897. cur != NULL ;
  898. cur = clist_next(cur)) {
  899. struct mailmime_field * field;
  900. /* only MIME-Version field */
  901. field = cur->data;
  902. if (field->fld_type == MAILMIME_FIELD_VERSION) {
  903. r = mailmime_field_write_driver(do_write, data, col, field);
  904. if (r != MAILIMF_NO_ERROR) {
  905. res = r;
  906. goto free_boundary;
  907. }
  908. }
  909. }
  910. }
  911. /* encapsuled message */
  912. if (build_info->mm_data.mm_message.mm_msg_mime != NULL) {
  913. r = mailmime_sub_write_driver(do_write, data, col,
  914. build_info->mm_data.mm_message.mm_msg_mime);
  915. if (r != MAILIMF_NO_ERROR) {
  916. res = r;
  917. goto free_boundary;
  918. }
  919. }
  920. break;
  921. }
  922. free(boundary);
  923. return MAILIMF_NO_ERROR;
  924. free_boundary:
  925. free(boundary);
  926. err:
  927. return res;
  928. }
  929. static int mailmime_sub_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  930. struct mailmime * build_info)
  931. {
  932. int r;
  933. #if 0
  934. * col = 0;
  935. #endif
  936. /* MIME field - Content-Type */
  937. if (build_info->mm_content_type != NULL) {
  938. r = mailmime_content_write_driver(do_write, data, col, build_info->mm_content_type);
  939. if (r != MAILIMF_NO_ERROR)
  940. return r;
  941. }
  942. /* other MIME fields */
  943. if (build_info->mm_type != MAILMIME_MESSAGE) {
  944. if (build_info->mm_mime_fields != NULL) {
  945. r = mailmime_fields_write_driver(do_write, data, col, build_info->mm_mime_fields);
  946. if (r != MAILIMF_NO_ERROR)
  947. return r;
  948. }
  949. }
  950. else {
  951. if (build_info->mm_mime_fields != NULL) {
  952. int r;
  953. clistiter * cur;
  954. /* filter out MIME-Version */
  955. for(cur = clist_begin(build_info->mm_mime_fields->fld_list) ;
  956. cur != NULL ;
  957. cur = clist_next(cur)) {
  958. struct mailmime_field * field;
  959. field = cur->data;
  960. if (field->fld_type != MAILMIME_FIELD_VERSION) {
  961. r = mailmime_field_write_driver(do_write, data, col, field);
  962. if (r != MAILIMF_NO_ERROR) {
  963. return r;
  964. }
  965. }
  966. }
  967. }
  968. }
  969. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  970. if (r != MAILIMF_NO_ERROR)
  971. return r;
  972. #if 0
  973. * col = 0;
  974. #endif
  975. return mailmime_part_write_driver(do_write, data, col, build_info);
  976. }
  977. int mailmime_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  978. struct mailmime * build_info)
  979. {
  980. if (build_info->mm_parent != NULL)
  981. return mailmime_sub_write_driver(do_write, data, col, build_info);
  982. else
  983. return mailmime_part_write_driver(do_write, data, col, build_info);
  984. }
  985. int mailmime_data_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  986. struct mailmime_data * mime_data,
  987. int istext)
  988. {
  989. int fd;
  990. int r;
  991. char * text;
  992. struct stat buf;
  993. int res;
  994. switch (mime_data->dt_type) {
  995. case MAILMIME_DATA_TEXT:
  996. if (mime_data->dt_encoded) {
  997. r = mailimf_string_write_driver(do_write, data, col,
  998. mime_data->dt_data.dt_text.dt_data,
  999. mime_data->dt_data.dt_text.dt_length);
  1000. if (r != MAILIMF_NO_ERROR)
  1001. return r;
  1002. }
  1003. else {
  1004. r = mailmime_text_content_write_driver(do_write, data, col, mime_data->dt_encoding, istext,
  1005. mime_data->dt_data.dt_text.dt_data,
  1006. mime_data->dt_data.dt_text.dt_length);
  1007. if (r != MAILIMF_NO_ERROR)
  1008. return r;
  1009. }
  1010. break;
  1011. case MAILMIME_DATA_FILE:
  1012. fd = Open(mime_data->dt_data.dt_filename, O_RDONLY);
  1013. if (fd < 0) {
  1014. res = MAILIMF_ERROR_FILE;
  1015. goto err;
  1016. }
  1017. r = fstat(fd, &buf);
  1018. if (r < 0) {
  1019. res = MAILIMF_ERROR_FILE;
  1020. goto Close;
  1021. }
  1022. if (buf.st_size != 0) {
  1023. text = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  1024. if (text == (char *)MAP_FAILED) {
  1025. res = MAILIMF_ERROR_FILE;
  1026. goto Close;
  1027. }
  1028. if (mime_data->dt_encoded) {
  1029. r = mailimf_string_write_driver(do_write, data, col, text, buf.st_size);
  1030. if (r != MAILIMF_NO_ERROR) {
  1031. res = r;
  1032. goto unmap;
  1033. }
  1034. }
  1035. else {
  1036. r = mailmime_text_content_write_driver(do_write, data, col, mime_data->dt_encoding, istext,
  1037. text, buf.st_size);
  1038. if (r != MAILIMF_NO_ERROR) {
  1039. res = r;
  1040. goto unmap;
  1041. }
  1042. }
  1043. munmap(text, buf.st_size);
  1044. }
  1045. Close(fd);
  1046. if (r != MAILIMF_NO_ERROR)
  1047. return r;
  1048. break;
  1049. unmap:
  1050. munmap(text, buf.st_size);
  1051. Close:
  1052. Close(fd);
  1053. err:
  1054. return res;
  1055. }
  1056. return MAILIMF_NO_ERROR;
  1057. }
  1058. static int mailmime_text_content_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, int encoding,
  1059. int istext,
  1060. const char * text, size_t size)
  1061. {
  1062. switch (encoding) {
  1063. case MAILMIME_MECHANISM_QUOTED_PRINTABLE:
  1064. return mailmime_quoted_printable_write_driver(do_write, data, col, istext, text, size);
  1065. break;
  1066. case MAILMIME_MECHANISM_BASE64:
  1067. return mailmime_base64_write_driver(do_write, data, col, text, size);
  1068. break;
  1069. case MAILMIME_MECHANISM_7BIT:
  1070. case MAILMIME_MECHANISM_8BIT:
  1071. case MAILMIME_MECHANISM_BINARY:
  1072. default:
  1073. return mailimf_string_write_driver(do_write, data, col, text, size);
  1074. }
  1075. }
  1076. static const char base64_encoding[] =
  1077. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  1078. #define BASE64_MAX_COL 76
  1079. int mailmime_base64_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  1080. const char * text, size_t size)
  1081. {
  1082. int a;
  1083. int b;
  1084. int c;
  1085. size_t remains;
  1086. const char * p;
  1087. size_t count;
  1088. char ogroup[4];
  1089. int r;
  1090. remains = size;
  1091. p = text;
  1092. while (remains > 0) {
  1093. switch (remains) {
  1094. case 1:
  1095. a = (unsigned char) p[0];
  1096. b = 0;
  1097. c = 0;
  1098. count = 1;
  1099. break;
  1100. case 2:
  1101. a = (unsigned char) p[0];
  1102. b = (unsigned char) p[1];
  1103. c = 0;
  1104. count = 2;
  1105. break;
  1106. default:
  1107. a = (unsigned char) p[0];
  1108. b = (unsigned char) p[1];
  1109. c = (unsigned char) p[2];
  1110. count = 3;
  1111. break;
  1112. }
  1113. ogroup[0]= base64_encoding[a >> 2];
  1114. ogroup[1]= base64_encoding[((a & 3) << 4) | (b >> 4)];
  1115. ogroup[2]= base64_encoding[((b & 0xF) << 2) | (c >> 6)];
  1116. ogroup[3]= base64_encoding[c & 0x3F];
  1117. switch (count) {
  1118. case 1:
  1119. ogroup[2]= '=';
  1120. ogroup[3]= '=';
  1121. break;
  1122. case 2:
  1123. ogroup[3]= '=';
  1124. break;
  1125. }
  1126. if (* col + 4 > BASE64_MAX_COL) {
  1127. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  1128. if (r != MAILIMF_NO_ERROR)
  1129. return r;
  1130. #if 0
  1131. * col = 0;
  1132. #endif
  1133. }
  1134. r = mailimf_string_write_driver(do_write, data, col, ogroup, 4);
  1135. if (r != MAILIMF_NO_ERROR)
  1136. return r;
  1137. remains -= count;
  1138. p += count;
  1139. }
  1140. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  1141. return MAILIMF_NO_ERROR;
  1142. }
  1143. #if 0
  1144. #define MAX_WRITE_SIZE 512
  1145. #endif
  1146. enum {
  1147. STATE_INIT,
  1148. STATE_CR,
  1149. STATE_SPACE,
  1150. STATE_SPACE_CR
  1151. };
  1152. #if 0
  1153. static inline int write_try_buf(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  1154. char ** pstart, size_t * plen)
  1155. {
  1156. int r;
  1157. if (* plen >= MAX_WRITE_SIZE) {
  1158. r = mailimf_string_write_driver(do_write, data, col, * pstart, * plen);
  1159. if (r != MAILIMF_NO_ERROR)
  1160. return r;
  1161. * plen = 0;
  1162. }
  1163. return MAILIMF_NO_ERROR;
  1164. }
  1165. #endif
  1166. static inline int write_remaining(int (* do_write)(void *, const char *, size_t), void * data, int * col,
  1167. const char ** pstart, size_t * plen)
  1168. {
  1169. int r;
  1170. if (* plen > 0) {
  1171. r = mailimf_string_write_driver(do_write, data, col, * pstart, * plen);
  1172. if (r != MAILIMF_NO_ERROR)
  1173. return r;
  1174. * plen = 0;
  1175. }
  1176. return MAILIMF_NO_ERROR;
  1177. }
  1178. #define QP_MAX_COL 72
  1179. int mailmime_quoted_printable_write_driver(int (* do_write)(void *, const char *, size_t), void * data, int * col, int istext,
  1180. const char * text, size_t size)
  1181. {
  1182. size_t i;
  1183. const char * start;
  1184. size_t len;
  1185. char hexstr[6];
  1186. int r;
  1187. int state;
  1188. start = text;
  1189. len = 0;
  1190. state = STATE_INIT;
  1191. i = 0;
  1192. while (i < size) {
  1193. unsigned char ch;
  1194. if (* col + len > QP_MAX_COL) {
  1195. r = write_remaining(do_write, data, col, &start, &len);
  1196. if (r != MAILIMF_NO_ERROR)
  1197. return r;
  1198. start = text + i;
  1199. r = mailimf_string_write_driver(do_write, data, col, "=\r\n", 3);
  1200. if (r != MAILIMF_NO_ERROR)
  1201. return r;
  1202. }
  1203. ch = text[i];
  1204. switch (state) {
  1205. case STATE_INIT:
  1206. switch (ch) {
  1207. case ' ':
  1208. case '\t':
  1209. state = STATE_SPACE;
  1210. len ++;
  1211. i ++;
  1212. break;
  1213. case '\r':
  1214. state = STATE_CR;
  1215. i ++;
  1216. break;
  1217. case '!':
  1218. case '"':
  1219. case '#':
  1220. case '$':
  1221. case '@':
  1222. case '[':
  1223. case '\\':
  1224. case ']':
  1225. case '^':
  1226. case '`':
  1227. case '{':
  1228. case '|':
  1229. case '}':
  1230. case '~':
  1231. case '=':
  1232. case '?':
  1233. case '_':
  1234. case 'F': /* there is no more 'From' at the beginning of a line */
  1235. r = write_remaining(do_write, data, col, &start, &len);
  1236. if (r != MAILIMF_NO_ERROR)
  1237. return r;
  1238. start = text + i + 1;
  1239. snprintf(hexstr, 6, "=%02X", ch);
  1240. r = mailimf_string_write_driver(do_write, data, col, hexstr, 3);
  1241. if (r != MAILIMF_NO_ERROR)
  1242. return r;
  1243. i ++;
  1244. break;
  1245. default:
  1246. if (istext && (ch == '\n')) {
  1247. r = write_remaining(do_write, data, col, &start, &len);
  1248. if (r != MAILIMF_NO_ERROR)
  1249. return r;
  1250. start = text + i + 1;
  1251. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  1252. if (r != MAILIMF_NO_ERROR)
  1253. return r;
  1254. i ++;
  1255. break;
  1256. }
  1257. else {
  1258. if (((ch >= 33) && (ch <= 60)) || ((ch >= 62) && (ch <= 126))) {
  1259. len ++;
  1260. i ++;
  1261. }
  1262. else {
  1263. r = write_remaining(do_write, data, col, &start, &len);
  1264. if (r != MAILIMF_NO_ERROR)
  1265. return r;
  1266. start = text + i + 1;
  1267. snprintf(hexstr, 6, "=%02X", ch);
  1268. r = mailimf_string_write_driver(do_write, data, col, hexstr, 3);
  1269. if (r != MAILIMF_NO_ERROR)
  1270. return r;
  1271. i ++;
  1272. }
  1273. }
  1274. break;
  1275. }
  1276. break;
  1277. case STATE_CR:
  1278. switch (ch) {
  1279. case '\n':
  1280. r = write_remaining(do_write, data, col, &start, &len);
  1281. if (r != MAILIMF_NO_ERROR)
  1282. return r;
  1283. start = text + i + 1;
  1284. r = mailimf_string_write_driver(do_write, data, col, "\r\n", 2);
  1285. if (r != MAILIMF_NO_ERROR)
  1286. return r;
  1287. i ++;
  1288. state = STATE_INIT;
  1289. break;
  1290. default:
  1291. r = write_remaining(do_write, data, col, &start, &len);
  1292. if (r != MAILIMF_NO_ERROR)
  1293. return r;
  1294. start = text + i;
  1295. snprintf(hexstr, 6, "=%02X", '\r');
  1296. r = mailimf_string_write_driver(do_write, data, col, hexstr, 3);
  1297. if (r != MAILIMF_NO_ERROR)
  1298. return r;
  1299. state = STATE_INIT;
  1300. break;
  1301. }
  1302. break;
  1303. case STATE_SPACE:
  1304. switch (ch) {
  1305. case '\r':
  1306. state = STATE_SPACE_CR;
  1307. i ++;
  1308. break;
  1309. case '\n':
  1310. r = write_remaining(do_write, data, col, &start, &len);
  1311. if (r != MAILIMF_NO_ERROR)
  1312. return r;
  1313. start = text + i + 1;
  1314. snprintf(hexstr, 6, "=%02X\r\n", text[i - 1]);
  1315. r = mailimf_string_write_driver(do_write, data, col, hexstr, strlen(hexstr));
  1316. if (r != MAILIMF_NO_ERROR)
  1317. return r;
  1318. state = STATE_INIT;
  1319. i ++;
  1320. break;
  1321. case ' ':
  1322. case '\t':
  1323. len ++;
  1324. i ++;
  1325. break;
  1326. default:
  1327. #if 0
  1328. len += 2;
  1329. state = STATE_INIT;
  1330. i ++;
  1331. #endif
  1332. state = STATE_INIT;
  1333. break;
  1334. }
  1335. break;
  1336. case STATE_SPACE_CR:
  1337. switch (ch) {
  1338. case '\n':
  1339. r = write_remaining(do_write, data, col, &start, &len);
  1340. if (r != MAILIMF_NO_ERROR)
  1341. return r;
  1342. start = text + i + 1;
  1343. snprintf(hexstr, 6, "=%02X\r\n", text[i - 2]);
  1344. r = mailimf_string_write_driver(do_write, data, col, hexstr, strlen(hexstr));
  1345. if (r != MAILIMF_NO_ERROR)
  1346. return r;
  1347. state = STATE_INIT;
  1348. i ++;
  1349. break;
  1350. default:
  1351. r = write_remaining(do_write, data, col, &start, &len);
  1352. if (r != MAILIMF_NO_ERROR)
  1353. return r;
  1354. start = text + i + 1;
  1355. snprintf(hexstr, 6, "%c=%02X", text[i - 2], '\r');
  1356. r = mailimf_string_write_driver(do_write, data, col, hexstr, strlen(hexstr));
  1357. if (r != MAILIMF_NO_ERROR)
  1358. return r;
  1359. state = STATE_INIT;
  1360. break;
  1361. }
  1362. break;
  1363. }
  1364. }
  1365. r = write_remaining(do_write, data, col, &start, &len);
  1366. if (r != MAILIMF_NO_ERROR)
  1367. return r;
  1368. return MAILIMF_NO_ERROR;
  1369. }