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

WEB邮件程序

开发平台:

C/C++

  1. /*
  2. ** Copyright 1998 - 1999 Double Precision, Inc.  See COPYING for
  3. ** distribution information.
  4. */
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include "rfc822.h"
  10. #include "rfc2047.h"
  11. static const char rcsid[]="$Id: rfc2047.c,v 1.1 2000/02/23 02:41:19 mrsam Exp $";
  12. static const char xdigit[]="0123456789ABCDEF";
  13. static char *rfc2047_search_quote(const char **ptr)
  14. {
  15. const char *p= *ptr;
  16. char *s;
  17. while (**ptr && **ptr != '?')
  18. ++ *ptr;
  19. if ((s=malloc( *ptr - p + 1)) == 0)
  20. return (0);
  21. memcpy(s, p, *ptr-p);
  22. s[*ptr - p]=0;
  23. return (s);
  24. }
  25. static int nyb(int c)
  26. {
  27. const char *p;
  28. c=toupper( (int)(unsigned char)c );
  29. p=strchr(xdigit, c);
  30. return (p ? p-xdigit:0);
  31. }
  32. static unsigned char decode64tab[256];
  33. static int decode64tab_init=0;
  34. static size_t decodebase64(char *ptr, size_t cnt)
  35. {
  36. size_t  i, j;
  37. char    a,b,c;
  38. size_t  k;
  39. if (!decode64tab_init)
  40. {
  41. for (i=0; i<256; i++)   decode64tab[i]=0;
  42. for (i=0; i<64; i++)
  43. decode64tab[ (int)
  44. ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i])]=i;
  45. decode64tab[ (int)'=' ] = 99;
  46. }
  47. i=cnt / 4;
  48. i=i*4;
  49. k=0;
  50. for (j=0; j<i; j += 4)
  51. {
  52. int     w=decode64tab[(int)(unsigned char)ptr[j]];
  53. int     x=decode64tab[(int)(unsigned char)ptr[j+1]];
  54. int     y=decode64tab[(int)(unsigned char)ptr[j+2]];
  55. int     z=decode64tab[(int)(unsigned char)ptr[j+3]];
  56. a= (w << 2) | (x >> 4);
  57. b= (x << 4) | (y >> 2);
  58. c= (y << 6) | z;
  59. ptr[k++]=a;
  60. if ( ptr[j+2] != '=')
  61. ptr[k++]=b;
  62. if ( ptr[j+3] != '=')
  63. ptr[k++]=c;
  64. }
  65. return (k);
  66. }
  67. /*
  68. ** This is the main rfc2047 decoding function.  It receives rfc2047-encoded
  69. ** text, and a callback function.  The callback function is repeatedly
  70. ** called, each time receiving a piece of decoded text.  The decoded
  71. ** info includes a text fragment - string, string length arg - followed
  72. ** by the character set, followed by a context pointer that is received
  73. ** from the caller.  If the callback function returns non-zero, rfc2047
  74. ** decoding terminates, returning the result code.  Otherwise,
  75. ** rfc2047_decode returns 0 after a successfull decoding (-1 if malloc
  76. ** failed).
  77. */
  78. int rfc2047_decode(const char *text, int (*func)(const char *, int,
  79. const char *, void *),
  80. void *arg)
  81. {
  82. int rc;
  83. int had_last_word=0;
  84. const char *p;
  85. char *chset;
  86. char *encoding;
  87. char *enctext;
  88. while (text && *text)
  89. {
  90. if (text[0] != '=' || text[1] != '?')
  91. {
  92. p=text;
  93. while (*text)
  94. {
  95. if (text[0] == '=' && text[1] == '?')
  96. break;
  97. if (!isspace((int)(unsigned char)*text))
  98. had_last_word=0;
  99. ++text;
  100. }
  101. if (text > p && !had_last_word)
  102. {
  103. rc=(*func)(p, text-p, 0, arg);
  104. if (rc) return (rc);
  105. }
  106. continue;
  107. }
  108. text += 2;
  109. if ((chset=rfc2047_search_quote( &text )) == 0)
  110. return (-1);
  111. if (*text) ++text;
  112. if ((encoding=rfc2047_search_quote( &text )) == 0)
  113. {
  114. free(chset);
  115. return (-1);
  116. }
  117. if (*text) ++text;
  118. if ((enctext=rfc2047_search_quote( &text )) == 0)
  119. {
  120. free(encoding);
  121. free(chset);
  122. return (-1);
  123. }
  124. if (*text == '?' && text[1] == '=')
  125. text += 2;
  126. if (strcmp(encoding, "Q") == 0 || strcmp(encoding, "q") == 0)
  127. {
  128. char *q, *r;
  129. for (q=r=enctext; *q; )
  130. {
  131. if (*q == '=' && q[1] && q[2])
  132. {
  133. *r++ = (char)(
  134. nyb(q[1])*16+nyb(q[2]));
  135. q += 3;
  136. continue;
  137. }
  138. *r++ = *q++ ;
  139. }
  140. *r=0;
  141. }
  142. else if (strcmp(encoding, "B") == 0 || strcmp(encoding, "b")==0)
  143. {
  144. enctext[decodebase64(enctext, strlen(enctext))]=0;
  145. }
  146. rc=(*func)(enctext, strlen(enctext), chset, arg);
  147. free(enctext);
  148. free(chset);
  149. free(encoding);
  150. if (rc) return (rc);
  151. had_last_word=1; /* Ignore blanks between enc words */
  152. }
  153. return (0);
  154. }
  155. /*
  156. ** rfc2047_decode_simple just strips out the rfc2047 decoding, throwing away
  157. ** the character set.  This is done by calling rfc2047_decode twice, once
  158. ** to count the number of characters in the decoded text, the second time to
  159. ** actually do it.
  160. */
  161. struct simple_info {
  162. char *string;
  163. int index;
  164. const char *mychset;
  165. } ;
  166. static int count_simple(const char *txt, int len, const char *chset,
  167. void *arg)
  168. {
  169. struct simple_info *iarg= (struct simple_info *)arg;
  170. iarg->index += len;
  171. return (0);
  172. }
  173. static int save_simple(const char *txt, int len, const char *chset,
  174. void *arg)
  175. {
  176. struct simple_info *iarg= (struct simple_info *)arg;
  177. memcpy(iarg->string+iarg->index, txt, len);
  178. iarg->index += len;
  179. return (0);
  180. }
  181. char *rfc2047_decode_simple(const char *text)
  182. {
  183. struct simple_info info;
  184. info.index=1;
  185. if (rfc2047_decode(text, &count_simple, &info))
  186. return (0);
  187. if ((info.string=malloc(info.index)) == 0) return (0);
  188. info.index=0;
  189. if (rfc2047_decode(text, &save_simple, &info))
  190. {
  191. free(info.string);
  192. return (0);
  193. }
  194. info.string[info.index]=0;
  195. return (info.string);
  196. }
  197. /*
  198. ** rfc2047_decode_enhanced is like simply, but prefixes the character set
  199. ** name before the text, in brackets.
  200. */
  201. static int do_enhanced(const char *txt, int len, const char *chset,
  202. void *arg,
  203. int (*func)(const char *, int, const char *, void *)
  204. )
  205. {
  206. int rc=0;
  207. struct simple_info *info=(struct simple_info *)arg;
  208. if (chset && info->mychset && strcmp(chset, info->mychset) == 0)
  209. chset=0;
  210. if (chset)
  211. {
  212. rc= (*func)(" [", 2, 0, arg);
  213. if (rc == 0)
  214. rc= (*func)(chset, strlen(chset), 0, arg);
  215. if (rc == 0)
  216. rc= (*func)("] ", 2, 0, arg);
  217. }
  218. if (rc == 0)
  219. rc= (*func)(txt, len, 0, arg);
  220. return (rc);
  221. }
  222. static int count_enhanced(const char *txt, int len, const char *chset,
  223. void *arg)
  224. {
  225. return (do_enhanced(txt, len, chset, arg, &count_simple));
  226. }
  227. static int save_enhanced(const char *txt, int len, const char *chset,
  228. void *arg)
  229. {
  230. return (do_enhanced(txt, len, chset, arg, &save_simple));
  231. }
  232. char *rfc2047_decode_enhanced(const char *text, const char *mychset)
  233. {
  234. struct simple_info info;
  235. info.mychset=mychset;
  236. info.index=1;
  237. if (rfc2047_decode(text, &count_enhanced, &info))
  238. return (0);
  239. if ((info.string=malloc(info.index)) == 0) return (0);
  240. info.index=0;
  241. if (rfc2047_decode(text, &save_enhanced, &info))
  242. {
  243. free(info.string);
  244. return (0);
  245. }
  246. info.string[info.index]=0;
  247. return (info.string);
  248. }
  249. void rfc2047_print(const struct rfc822a *a,
  250. const char *charset,
  251. void (*print_func)(char, void *),
  252. void (*print_separator)(const char *, void *), void *ptr)
  253. {
  254. rfc822_print_common(a, &rfc2047_decode_enhanced, charset,
  255. print_func, print_separator, ptr);
  256. }
  257. static char *a_rfc2047_encode_str(const char *str, const char *charset);
  258. static void rfc2047_encode_header_do(const struct rfc822a *a,
  259. const char *charset,
  260. void (*print_func)(char, void *),
  261. void (*print_separator)(const char *, void *), void *ptr)
  262. {
  263. rfc822_print_common(a, &a_rfc2047_encode_str, charset,
  264. print_func, print_separator, ptr);
  265. }
  266. /*
  267. ** When MIMEifying names from an RFC822 list of addresses, strip quotes
  268. ** before MIMEifying them, and add them afterwards.
  269. */
  270. static char *a_rfc2047_encode_str(const char *str, const char *charset)
  271. {
  272. size_t l=strlen(str);
  273. char *p, *s;
  274. if (*str != '"' || str[l-1] != '"')
  275. return (rfc2047_encode_str(str, charset));
  276. p=malloc(l);
  277. if (!p) return (0);
  278. memcpy(p, str+1, l-2);
  279. p[l-2]=0;
  280. s=rfc2047_encode_str(p, charset);
  281. free(p);
  282. if (!s) return (0);
  283. p=malloc(strlen(s)+3);
  284. if (!p)
  285. {
  286. free(s);
  287. return (0);
  288. }
  289. p[0]='"';
  290. strcpy(p+1, s);
  291. strcat(p, """);
  292. free(s);
  293. return (p);
  294. }
  295. static void count(char c, void *p);
  296. static void counts(const char *c, void *p);
  297. static void save(char c, void *p);
  298. static void saves(const char *c, void *p);
  299. char *rfc2047_encode_header(const struct rfc822a *a,
  300.         const char *charset)
  301. {
  302. size_t l;
  303. char *s, *p;
  304. l=1;
  305. rfc2047_encode_header_do(a, charset, &count, &counts, &l);
  306. if ((s=malloc(l)) == 0) return (0);
  307. p=s;
  308. rfc2047_encode_header_do(a, charset, &save, &saves, &p);
  309. *p=0;
  310. return (s);
  311. }
  312. static void count(char c, void *p)
  313. {
  314. ++*(size_t *)p;
  315. }
  316. static void counts(const char *c, void *p)
  317. {
  318. while (*c) count(*c++, p);
  319. }
  320. static void save(char c, void *p)
  321. {
  322. **(char **)p=c;
  323. ++*(char **)p;
  324. }
  325. static void saves(const char *c, void *p)
  326. {
  327. while (*c) save(*c++, p);
  328. }
  329. int rfc2047_encode_callback(const char *str, const char *charset,
  330. int (*func)(const char *, size_t, void *), void *arg)
  331. {
  332. int rc;
  333. while (*str)
  334. {
  335. size_t i, c;
  336. for (i=0; str[i]; i++)
  337. if ((str[i] & 0x80) || str[i] == '"')
  338. break;
  339. if (str[i] == 0)
  340. return ( i ? (*func)(str, i, arg):0);
  341. /* Find start of word */
  342. while (i)
  343. {
  344. --i;
  345. if (isspace((int)(unsigned char)str[i]))
  346. {
  347. ++i;
  348. break;
  349. }
  350. }
  351. if (i)
  352. {
  353. rc= (*func)(str, i, arg);
  354. if (rc) return (rc);
  355. str += i;
  356. }
  357. for (i=0; str[i]; i++)
  358. if (isspace((int)(unsigned char)str[i]))
  359. break;
  360. /* Output mimeified text, insert spaces at 70+ character
  361. ** boundaries for line wrapping.
  362. */
  363. c=0;
  364. while (i)
  365. {
  366. if (c == 0)
  367. {
  368. if ( (rc=(*func)("=?", 2, arg)) != 0 ||
  369. (rc=(*func)(charset, strlen(charset),
  370. arg)) != 0 ||
  371. (rc=(*func)("?Q?", 3, arg)) != 0)
  372. return (rc);
  373. c += strlen(charset)+5;
  374. }
  375. if ((*str & 0x80) || *str == '"')
  376. {
  377. char buf[3];
  378. buf[0]='=';
  379. buf[1]=xdigit[ ( *str >> 4) & 0x0F ];
  380. buf[2]=xdigit[ *str & 0x0F ];
  381. if ( (rc=(*func)(buf, 3, arg)) != 0)
  382. return (rc);
  383. c += 3;
  384. ++str;
  385. --i;
  386. }
  387. else
  388. {
  389. size_t j;
  390. for (j=0; j < i && !(str[j] & 0x80) &&
  391. str[j] != '"'; j++)
  392. if (j + c >= 70)
  393. break;
  394. if ( (rc=(*func)(str, j, arg)) != 0)
  395. return (rc);
  396. c += j;
  397. str += j;
  398. i -= j;
  399. }
  400. if (i == 0 || c >= 70)
  401. {
  402. if ( (rc=(*func)("?= ", i ? 3:2, arg)) != 0)
  403. return (rc);
  404. c=0;
  405. }
  406. }
  407. }
  408. return (0);
  409. }
  410. static int count_char(const char *c, size_t l, void *p)
  411. {
  412. size_t *i=(size_t *)p;
  413. *i += l;
  414. return (0);
  415. }
  416. static int save_char(const char *c, size_t l, void *p)
  417. {
  418. char **s=(char **)p;
  419. memcpy(*s, c, l);
  420. *s += l;
  421. return (0);
  422. }
  423. char *rfc2047_encode_str(const char *str, const char *charset)
  424. {
  425. size_t i=1;
  426. char *s, *p;
  427. (void)rfc2047_encode_callback(str, charset, &count_char, &i);
  428. if ((s=malloc(i)) == 0) return (0);
  429. p=s;
  430. (void)rfc2047_encode_callback(str, charset, &save_char, &p);
  431. *p=0;
  432. return (s);
  433. }