rfc2045rewrite.c
上传用户:s81996212
上传日期:2007-01-04
资源大小:722k
文件大小:9k
源码类别:

WEB邮件程序

开发平台:

C/C++

  1. /*
  2. ** Copyright 1998 - 1999 Double Precision, Inc.  See COPYING for
  3. ** distribution information.
  4. */
  5. #if HAVE_CONFIG_H
  6. #include "config.h"
  7. #endif
  8. #include "rfc2045.h"
  9. #include "rfc2045charset.h"
  10. #if HAVE_UNISTD_H
  11. #include <unistd.h>
  12. #endif
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <ctype.h>
  16. #include       <string.h>
  17. #if    HAVE_STRINGS_H
  18. #include       <strings.h>
  19. #endif
  20. /* $Id: rfc2045rewrite.c,v 1.9 2000/01/31 04:49:39 mrsam Exp $ */
  21. static char *rw_boundary_root;
  22. static int rw_boundary_cnt;
  23. static const char *rw_appname;
  24. static FILE *fdin;
  25. static int fdout;
  26. static int (*fdout_func)(const char *, int, void *);
  27. static void *fdout_arg;
  28. static char fdout_buf[512];
  29. static char *fdout_ptr;
  30. static size_t fdout_left;
  31. extern void rfc2045_enomem();
  32. /* Quoted printable encoding */
  33. static void qpe_start();
  34. static int qpe_do(const char *, size_t, void *);
  35. static void qpe_end();
  36. static int conv_err;
  37. static int fdout_flush()
  38. {
  39. int n=fdout_ptr-fdout_buf;
  40. int i=0;
  41. char *p=fdout_buf;
  42. while (n)
  43. {
  44. i=fdout_func ? (*fdout_func)(p, n, fdout_arg):
  45. write(fdout, p, n);
  46. if (i <= 0) return (-1);
  47. p += i;
  48. n -= i;
  49. }
  50. fdout_ptr=fdout_buf;
  51. fdout_left=sizeof(fdout_buf);
  52. return (0);
  53. }
  54. static int fdout_add(const char *p, size_t cnt)
  55. {
  56. while (cnt)
  57. {
  58. if (cnt < fdout_left)
  59. {
  60. memcpy(fdout_ptr, p, cnt);
  61. fdout_ptr += cnt;
  62. fdout_left -= cnt;
  63. return (0);
  64. }
  65. if (fdout_left == 0)
  66. {
  67. if (fdout_flush()) return (-1);
  68. continue;
  69. }
  70. memcpy(fdout_ptr, p, fdout_left);
  71. p += fdout_left;
  72. cnt -= fdout_left;
  73. fdout_ptr += fdout_left;
  74. fdout_left=0;
  75. }
  76. return (0);
  77. }
  78. static int do_8bit(const char *p, size_t cnt, void *ptr)
  79. {
  80. if (fdout_add(p, cnt))
  81. conv_err=1;
  82. return (0);
  83. }
  84. static int fdout_autoconverted(const char *oldte, const char *newte)
  85. {
  86. if (fdout_add("X-Mime-Autoconverted: from ", 27) ||
  87. fdout_add(oldte, strlen(oldte)) ||
  88. fdout_add(" to ", 4) ||
  89. fdout_add(newte, strlen(newte)) ||
  90. (rw_appname && (fdout_add(" by ", 4) ||
  91. fdout_add(rw_appname, strlen(rw_appname)))) ||
  92. fdout_add("n", 1)) return (-1);
  93. return (0);
  94. }
  95. static int fdout_value(const char *);
  96. static int fdout_attr(const struct rfc2045attr *a)
  97. {
  98. if (fdout_add(a->name, strlen(a->name))) return (-1);
  99. if (a->value && (fdout_add("=", 1) || fdout_value(a->value)))
  100. return (-1);
  101. return (0);
  102. }
  103. static int fdout_value(const char *v)
  104. {
  105. size_t i,j;
  106. for (i=0; v[i]; i++)
  107. {
  108. if ( !isalnum((int)(unsigned char)v[i]) && v[i] != '-')
  109. {
  110. if (fdout_add(""", 1)) return (-1);
  111. for (j=i=0; v[i]; i++)
  112. if (v[i] == '\' || v[i] == '"')
  113. {
  114. if (fdout_add(v+j, i-j) ||
  115. fdout_add("\", 1))
  116. return (-1);
  117. j=i;
  118. }
  119. if (fdout_add(v+j, i-j) || fdout_add(""", 1))
  120. return (-1);
  121. return (0);
  122. }
  123. }
  124. return (fdout_add(v, i));
  125. }
  126. #define TE(p) ((p)->rw_transfer_encoding ? 
  127. (p)->rw_transfer_encoding: (p)->content_transfer_encoding)
  128. static int rwmime(struct rfc2045 *p)
  129. {
  130. static char mimever[]="Mime-Version: 1.0n";
  131. const char *te;
  132. struct rfc2045attr *a;
  133. if (!p->parent)
  134. if (fdout_add(mimever, sizeof(mimever)-1)) return (-1);
  135. if (p->content_type)
  136. {
  137. if (fdout_add("Content-Type: ", 14) ||
  138. fdout_add(p->content_type, strlen(p->content_type)))
  139. return (-1);
  140. for (a=p->content_type_attr; a; a=a->next)
  141. {
  142. if (!a->name || strcmp(a->name, "boundary") == 0)
  143. continue;
  144. if ( fdout_add("; ", 2) ||
  145. fdout_attr(a)) return (-1);
  146. }
  147. }
  148. if (p->firstpart
  149. && p->firstpart->next /* ADDED 8/30/99, see below */)
  150. {
  151. char buf[80];
  152. ++rw_boundary_cnt;
  153. sprintf(buf, "-%d", rw_boundary_cnt);
  154. if ( fdout_add("; boundary="", 12) ||
  155. fdout_add(rw_boundary_root, strlen(rw_boundary_root)) ||
  156. fdout_add(buf, strlen(buf)) ||
  157. fdout_add(""", 1)) return (-1);
  158. }
  159. if (fdout_add("n", 1)) return (-1);
  160. /* Show content transfer encoding for top section, or if it's
  161. ** different than the parent.
  162. */
  163. te=TE(p);
  164. if (te && (!p->parent || strcmp(te, TE(p->parent))))
  165. {
  166. if (fdout_add("Content-Transfer-Encoding: ", 27) ||
  167. fdout_add(te, strlen(te)) ||
  168. fdout_add("n", 1)) return (-1);
  169. }
  170. return (0);
  171. }
  172. static int dorw(struct rfc2045 *p)
  173. {
  174. /* WTF STATIC??? */ int seen_mime=0;
  175. char buf[256];
  176. int c;
  177. int bcnt;
  178. if (fseek(fdin, p->startpos, SEEK_SET) == -1) return (-1);
  179. if (p->parent)
  180. {
  181. seen_mime=1;
  182. if (rwmime(p)) return (-1);
  183. }
  184. while (fgets(buf, sizeof(buf), fdin))
  185. {
  186. if (buf[0] == 'n') break;
  187. if (RFC2045_ISMIME1DEF(p->mime_version) &&
  188. strncasecmp(buf, "mime-version:", 13) == 0 &&
  189. !seen_mime)
  190. {
  191. seen_mime=1;
  192. rwmime(p);
  193. if (strchr(buf, 'n') == NULL)
  194. while ((c=getc(fdin)) >= 0 && c != 'n')
  195. ;
  196. while ((c=getc(fdin)) >= 0 && c != 'n' && isspace(c))
  197. while ((c=getc(fdin)) >= 0 && c != 'n')
  198. ;
  199. if (c >= 0) ungetc(c, fdin);
  200. continue;
  201. }
  202. if (!RFC2045_ISMIME1DEF(p->mime_version) || (
  203. strncasecmp(buf, "mime-version:", 13) &&
  204. strncasecmp(buf, "content-type:", 13) &&
  205. strncasecmp(buf, "content-transfer-encoding:", 26))
  206. )
  207. {
  208. do
  209. {
  210. do
  211. {
  212. if (fdout_add(buf, strlen(buf)))
  213. return (-1);
  214. } while (strchr(buf, 'n') == NULL &&
  215. fgets(buf, sizeof(buf), fdin));
  216. c=getc(fdin);
  217. if (c >= 0) ungetc(c, fdin);
  218. } while (c >= 0 && c != 'n' && isspace(c) &&
  219.     fgets(buf, sizeof(buf), fdin));
  220. }
  221. else
  222. while ( (c=getc(fdin)) >= 0 &&
  223. (ungetc(c, fdin), c) != 'n' && isspace(c))
  224. {
  225. while (fgets(buf, sizeof(buf), fdin) &&
  226. strchr(buf, 'n') == NULL)
  227. ;
  228. }
  229. }
  230. if (RFC2045_ISMIME1DEF(p->mime_version))
  231. {
  232. if (!seen_mime)
  233. if (rwmime(p)) return (-1);
  234. if (!p->firstpart && p->rw_transfer_encoding)
  235. if (fdout_autoconverted(p->content_transfer_encoding,
  236. p->rw_transfer_encoding)) return (-1);
  237. }
  238. if (fdout_add("n", 1)) return (-1);
  239. if (fseek(fdin, p->startbody, SEEK_SET) == -1) return (-1);
  240. /* For non-multipart section, just print the body */
  241. if (!p->firstpart)
  242. {
  243. off_t ps=p->startbody;
  244. int convmode=0;
  245. if (p->rw_transfer_encoding)
  246. {
  247. if ( strcasecmp(p->rw_transfer_encoding,
  248. "quoted-printable") == 0)
  249. convmode=RFC2045_RW_7BIT;
  250. else
  251. convmode=RFC2045_RW_8BIT;
  252. }
  253. conv_err=0;
  254. if (convmode == RFC2045_RW_7BIT)
  255. {
  256. qpe_start();
  257. rfc2045_cdecode_start(p, &qpe_do, 0);
  258. }
  259. if (convmode == RFC2045_RW_8BIT)
  260. {
  261. rfc2045_cdecode_start(p, &do_8bit, 0);
  262. }
  263. while (ps < p->endbody)
  264. {
  265. int n;
  266. if (p->endbody - ps > sizeof(buf))
  267. n=sizeof(buf);
  268. else n=p->endbody-ps;
  269. n=fread(buf, 1, n, fdin);
  270. if (n <= 0) return (-1);
  271. if (convmode)
  272. rfc2045_cdecode(p, buf, n);
  273. else if (fdout_add(buf, n)) conv_err=1;
  274. ps += n;
  275. if (conv_err) break;
  276. }
  277. if (convmode == RFC2045_RW_7BIT)
  278. {
  279. rfc2045_cdecode_end(p);
  280. qpe_end();
  281. }
  282. if (convmode == RFC2045_RW_8BIT)
  283. {
  284. rfc2045_cdecode_end(p);
  285. }
  286. if (conv_err) return (-1);
  287. return (0);
  288. }
  289. bcnt=rw_boundary_cnt;
  290. /* Sam 8/30/99 fix - handle message/rfc822:
  291.             --boundary
  292.             Content-Type: message/rfc822
  293.          --><-- we're here, DON'T add RFC2045MIMEMSG and rest of crap here
  294. */
  295. if (p->firstpart->next == 0)
  296. {
  297. int rc;
  298. p->firstpart->parent=0;
  299. rc=dorw(p->firstpart);
  300. p->firstpart->parent=p;
  301. return (rc);
  302. }
  303. if (fdout_add(RFC2045MIMEMSG, sizeof(RFC2045MIMEMSG)-1))
  304. return (-1);
  305. for (p=p->firstpart; p; p=p->next)
  306. {
  307. if (p->isdummy) continue;
  308. sprintf(buf, "n--%s-%dn", rw_boundary_root, bcnt);
  309. if (fdout_add(buf, strlen(buf))) return (-1);
  310. if (dorw(p) != 0) return(-1);
  311. }
  312. sprintf(buf, "n--%s-%d--n", rw_boundary_root, bcnt);
  313. if (fdout_add(buf, strlen(buf))) return (-1);
  314. return (0);
  315. }
  316. static int rfc2045_rewrite_common(struct rfc2045 *, int, const char *);
  317. int rfc2045_rewrite(struct rfc2045 *p, int fdin_arg, int fdout_arg,
  318. const char *appname)
  319. {
  320. fdout=fdout_arg;
  321. fdout_func=0;
  322. return (rfc2045_rewrite_common(p, fdin_arg, appname));
  323. }
  324. int rfc2045_rewrite_func(struct rfc2045 *p, int fdin_arg,
  325. int (*funcarg)(const char *, int, void *), void *funcargarg,
  326. const char *appname)
  327. {
  328. fdout= -1;
  329. fdout_func=funcarg;
  330. fdout_arg=funcargarg;
  331. return (rfc2045_rewrite_common(p, fdin_arg, appname));
  332. }
  333. static int rfc2045_rewrite_common(struct rfc2045 *p,
  334. int fdin_arg, const char *appname)
  335. {
  336. int rc;
  337. int fd=dup(fdin_arg);
  338. if (fd < 0) return (-1);
  339. rw_appname=appname;
  340. fdin=fdopen(fd, "r");
  341. if (!fdin)
  342. {
  343. close(fd);
  344. return (-1);
  345. }
  346. fdout_ptr=fdout_buf;
  347. fdout_left=sizeof(fdout_buf);
  348. rw_boundary_root=rfc2045_mk_boundary(p, fd);
  349. if (rw_boundary_root == 0)
  350. rc= -1;
  351. else
  352. {
  353. rw_boundary_cnt=1;
  354. rc=dorw(p);
  355. free(rw_boundary_root);
  356. }
  357. if (rc == 0 && fdout_ptr > fdout_buf)
  358. rc=fdout_flush();
  359. fclose(fdin);
  360. return (rc);
  361. }
  362. static int qpe_pos;
  363. static void qpe_start()
  364. {
  365. qpe_pos=0;
  366. }
  367. static int qpe_do(const char *p, size_t i, void *ptr)
  368. {
  369. size_t j,k;
  370. if (conv_err) return (0);
  371. for (j=k=0; j<i; j++)
  372. {
  373. if (p[j] == 'n')
  374. {
  375. if (fdout_add(p+k, j+1-k)) conv_err=1;
  376. k=j+1;
  377. qpe_pos=0;
  378. continue;
  379. }
  380. if (qpe_pos >= 72)
  381. {
  382. if (fdout_add(p+k, j-k) ||
  383. fdout_add("=n", 2)) conv_err=1;
  384. k=j;
  385. qpe_pos=0;
  386. }
  387. if (p[j] < 32 || p[j] >= 127 || p[j] == '=')
  388. {
  389. char buf[3];
  390. static char xdigit[16]="0123456789ABCDEF";
  391. unsigned n= (unsigned char)p[j];
  392. buf[0]='=';
  393. buf[1]=xdigit[ n / 16];
  394. buf[2]=xdigit[ n % 16];
  395. if (fdout_add(p+k, j-k) ||
  396. fdout_add(buf, 3)) conv_err=1;
  397. qpe_pos += 2;
  398. k=j+1;
  399. }
  400. ++qpe_pos;
  401. }
  402. if (fdout_add(p+k, j-k)) conv_err=1;
  403. return (0);
  404. }
  405. static void qpe_end()
  406. {
  407. }