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

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * rfc822.c -- code for slicing and dicing RFC822 mail headers
  3.  *
  4.  * Copyright 1997 by Eric S. Raymond
  5.  * For license terms, see the file COPYING in this directory.
  6.  */
  7. #include  <stdio.h>
  8. #include  <ctype.h>
  9. #include  <string.h>
  10. #if defined(STDC_HEADERS)
  11. #include  <stdlib.h>
  12. #endif
  13. #include "config.h"
  14. #include "fetchmail.h"
  15. #define HEADER_END(p) ((p)[0] == 'n' && ((p)[1] != ' ' && (p)[1] != 't'))
  16. #ifdef TESTMAIN
  17. static int verbose;
  18. char *program_name = "rfc822";
  19. #endif /* TESTMAIN */
  20. char *reply_hack(buf, host)
  21. /* hack message headers so replies will work properly */
  22. char *buf; /* header to be hacked */
  23. const char *host; /* server hostname */
  24. {
  25.     char *from, *cp, last_nws = '', *parens_from = NULL;
  26.     int parendepth, state, has_bare_name_part, has_host_part;
  27. #ifndef TESTMAIN
  28.     int addresscount = 1;
  29. #endif /* TESTMAIN */
  30.     if (strncasecmp("From: ", buf, 6)
  31. && strncasecmp("To: ", buf, 4)
  32. && strncasecmp("Reply-To: ", buf, 10)
  33. && strncasecmp("Return-Path: ", buf, 13)
  34. && strncasecmp("Cc: ", buf, 4)
  35. && strncasecmp("Bcc: ", buf, 5)
  36. && strncasecmp("Resent-From: ", buf, 13)
  37. && strncasecmp("Resent-To: ", buf, 11)
  38. && strncasecmp("Resent-Cc: ", buf, 11)
  39. && strncasecmp("Resent-Bcc: ", buf, 12)
  40. && strncasecmp("Apparently-From:", buf, 16)
  41. && strncasecmp("Apparently-To:", buf, 14)
  42. && strncasecmp("Sender:", buf, 7)
  43. && strncasecmp("Resent-Sender:", buf, 14)
  44.        ) {
  45. return(buf);
  46.     }
  47. #ifndef TESTMAIN
  48.     if (outlevel >= O_DEBUG)
  49. report_build(stdout, "About to rewrite %s", buf);
  50.     /* make room to hack the address; buf must be malloced */
  51.     for (cp = buf; *cp; cp++)
  52. if (*cp == ',' || isspace(*cp))
  53.     addresscount++;
  54.     buf = (char *)xrealloc(buf, strlen(buf) + addresscount * strlen(host) + 1);
  55. #endif /* TESTMAIN */
  56.     /*
  57.      * This is going to foo up on some ill-formed addresses.
  58.      * Note that we don't rewrite the fake address <> in order to
  59.      * avoid screwing up bounce suppression with a null Return-Path.
  60.      */
  61.     parendepth = state = 0;
  62.     has_host_part = has_bare_name_part = FALSE;
  63.     for (from = buf; *from; from++)
  64.     {
  65. #ifdef TESTMAIN
  66. if (verbose)
  67. {
  68.     printf("state %d: %s", state, buf);
  69.     printf("%*s^n", from - buf + 10, " ");
  70. }
  71. #endif /* TESTMAIN */
  72. if (state != 2)
  73. {
  74.     if (*from == '(')
  75. ++parendepth;
  76.     else if (*from == ')')
  77. --parendepth;
  78. }
  79. if (!parendepth && !has_host_part)
  80.     switch (state)
  81.     {
  82.     case 0: /* before header colon */
  83. if (*from == ':')
  84.     state = 1;
  85. break;
  86.     case 1: /* we've seen the colon, we're looking for addresses */
  87. if (!isspace(*from))
  88.     last_nws = *from;
  89. if (*from == '<')
  90.     state = 3;
  91. else if (*from == '@')
  92.     has_host_part = TRUE;
  93. else if (*from == '"')
  94.     state = 2;
  95. /*
  96.  * Not expanding on last non-WS == ';' deals with groupnames,
  97.  * an obscure misfeature described in sections
  98.  * 6.1, 6.2.6, and A.1.5 of the RFC822 standard.
  99.  */
  100. else if ((*from == ',' || HEADER_END(from))
  101.  && has_bare_name_part
  102.  && !has_host_part
  103.  && last_nws != ';')
  104. {
  105.     int hostlen;
  106.     char *p;
  107.     p = from;
  108.     if (parens_from)
  109. from = parens_from;
  110.     while (isspace(*from) || (*from == ','))
  111. --from;
  112.     from++;
  113.     hostlen = strlen(host);
  114.     for (cp = from + strlen(from); cp >= from; --cp)
  115. cp[hostlen+1] = *cp;
  116.     *from++ = '@';
  117.     memcpy(from, host, hostlen);
  118.     from = p + hostlen + 1;
  119.     has_host_part = TRUE;
  120. else if (from[1] == '('
  121.  && has_bare_name_part
  122.  && !has_host_part
  123.  && last_nws != ';' && last_nws != ')')
  124. {
  125.     parens_from = from;
  126. else if (!isspace(*from))
  127.     has_bare_name_part = TRUE;
  128. break;
  129.     case 2: /* we're in a string */
  130. if (*from == '"')
  131.     state = 1;
  132. break;
  133.     case 3: /* we're in a <>-enclosed address */
  134. if (*from == '@')
  135.     has_host_part = TRUE;
  136. else if (*from == '>' && from[-1] != '<')
  137. {
  138.     state = 1;
  139.     if (!has_host_part)
  140.     {
  141. int hostlen;
  142. hostlen = strlen(host);
  143. for (cp = from + strlen(from); cp >= from; --cp)
  144.     cp[hostlen+1] = *cp;
  145. *from++ = '@';
  146. memcpy(from, host, hostlen);
  147. from += hostlen;
  148. has_host_part = TRUE;
  149.     }
  150. }
  151. break;
  152.     }
  153. /*
  154.  * If we passed a comma, reset everything.
  155.  */
  156. if (from[-1] == ',' && !parendepth) {
  157.   has_host_part = has_bare_name_part = FALSE;
  158.   parens_from = NULL;
  159. }
  160.     }
  161. #ifndef TESTMAIN
  162.     if (outlevel >= O_DEBUG)
  163. report_complete(stdout, "Rewritten version is %sn", buf);
  164. #endif /* TESTMAIN */
  165.     return(buf);
  166. }
  167. char *nxtaddr(hdr)
  168. /* parse addresses in succession out of a specified RFC822 header */
  169. const char *hdr; /* header to be parsed, NUL to continue previous hdr */
  170. {
  171.     static char *tp, address[POPBUFSIZE+1];
  172.     static const char *hp;
  173.     static int state, oldstate;
  174. #ifdef TESTMAIN
  175.     static const char *orighdr;
  176. #endif /* TESTMAIN */
  177.     int parendepth = 0;
  178. #define START_HDR 0 /* before header colon */
  179. #define SKIP_JUNK 1 /* skip whitespace, n, and junk */
  180. #define BARE_ADDRESS 2 /* collecting address without delimiters */
  181. #define INSIDE_DQUOTE 3 /* inside double quotes */
  182. #define INSIDE_PARENS 4 /* inside parentheses */
  183. #define INSIDE_BRACKETS 5 /* inside bracketed address */
  184. #define ENDIT_ALL 6 /* after last address */
  185.     if (hdr)
  186.     {
  187. hp = hdr;
  188. state = START_HDR;
  189. #ifdef TESTMAIN
  190. orighdr = hdr;
  191. #endif /* TESTMAIN */
  192. tp = address;
  193.     }
  194.     for (; *hp; hp++)
  195.     {
  196. #ifdef TESTMAIN
  197. if (verbose)
  198. {
  199.     printf("state %d: %s", state, orighdr);
  200.     printf("%*s^n", hp - orighdr + 10, " ");
  201. }
  202. #endif /* TESTMAIN */
  203. if (state == ENDIT_ALL) /* after last address */
  204.     return(NULL);
  205. else if (HEADER_END(hp))
  206. {
  207.     state = ENDIT_ALL;
  208.     if (tp > address)
  209.     {
  210. while (isspace(*--tp))
  211.     continue;
  212. *++tp = '';
  213.     }
  214.     return(tp > address ? (tp = address) : (char *)NULL);
  215. }
  216. else if (*hp == '\') /* handle RFC822 escaping */
  217. {
  218.     if (state != INSIDE_PARENS)
  219.     {
  220. *tp++ = *hp++; /* take the escape */
  221. *tp++ = *hp; /* take following char */
  222.     }
  223. }
  224. else switch (state)
  225. {
  226. case START_HDR:   /* before header colon */
  227.     if (*hp == ':')
  228. state = SKIP_JUNK;
  229.     break;
  230. case SKIP_JUNK: /* looking for address start */
  231.     if (*hp == '"') /* quoted string */
  232.     {
  233. oldstate = SKIP_JUNK;
  234.         state = INSIDE_DQUOTE;
  235. *tp++ = *hp;
  236.     }
  237.     else if (*hp == '(') /* address comment -- ignore */
  238.     {
  239. parendepth = 1;
  240. oldstate = SKIP_JUNK;
  241. state = INSIDE_PARENS;    
  242.     }
  243.     else if (*hp == '<') /* begin <address> */
  244.     {
  245. state = INSIDE_BRACKETS;
  246. tp = address;
  247.     }
  248.     else if (*hp != ',' && !isspace(*hp))
  249.     {
  250. --hp;
  251.         state = BARE_ADDRESS;
  252.     }
  253.     break;
  254. case BARE_ADDRESS:    /* collecting address without delimiters */
  255.     if (*hp == ',')   /* end of address */
  256.     {
  257. if (tp > address)
  258. {
  259.     *tp++ = '';
  260.     state = SKIP_JUNK;
  261.     return(tp = address);
  262. }
  263.     }
  264.     else if (*hp == '(')   /* beginning of comment */
  265.     {
  266. parendepth = 1;
  267. oldstate = BARE_ADDRESS;
  268. state = INSIDE_PARENS;    
  269.     }
  270.     else if (*hp == '<')   /* beginning of real address */
  271.     {
  272. state = INSIDE_BRACKETS;
  273. tp = address;
  274.     }
  275.     else if (!isspace(*hp))  /* just take it, ignoring whitespace */
  276. *tp++ = *hp;
  277.     break;
  278. case INSIDE_DQUOTE: /* we're in a quoted string, copy verbatim */
  279.     if (*hp != '"')
  280.         *tp++ = *hp;
  281.     else
  282.     {
  283.         *tp++ = *hp;
  284. state = oldstate;
  285.     }
  286.     break;
  287. case INSIDE_PARENS: /* we're in a parenthesized comment, ignore */
  288.     if (*hp == '(')
  289. ++parendepth;
  290.     else if (*hp == ')')
  291. --parendepth;
  292.     if (parendepth == 0)
  293. state = oldstate;
  294.     break;
  295. case INSIDE_BRACKETS: /* possible <>-enclosed address */
  296.     if (*hp == '>') /* end of address */
  297.     {
  298. *tp++ = '';
  299. state = SKIP_JUNK;
  300. ++hp;
  301. return(tp = address);
  302.     }
  303.     else if (*hp == '<') /* nested <> */
  304.         tp = address;
  305.     else if (*hp == '"') /* quoted address */
  306.     {
  307.         *tp++ = *hp;
  308. oldstate = INSIDE_BRACKETS;
  309. state = INSIDE_DQUOTE;
  310.     }
  311.     else /* just copy address */
  312. *tp++ = *hp;
  313.     break;
  314. }
  315.     }
  316.     return(NULL);
  317. }
  318. #ifdef TESTMAIN
  319. static void parsebuf(char *longbuf, int reply)
  320. {
  321.     char *cp;
  322.     if (reply)
  323.     {
  324. reply_hack(longbuf, "HOSTNAME.NET");
  325. printf("Rewritten buffer: %s", longbuf);
  326.     }
  327.     else
  328. if ((cp = nxtaddr(longbuf)) != (char *)NULL)
  329.     do {
  330. printf("t-> "%s"n", cp);
  331.     } while
  332. ((cp = nxtaddr((char *)NULL)) != (char *)NULL);
  333. }
  334. main(int argc, char *argv[])
  335. {
  336.     char buf[MSGBUFSIZE], longbuf[BUFSIZ];
  337.     int ch, reply;
  338.     
  339.     verbose = reply = FALSE;
  340.     while ((ch = getopt(argc, argv, "rv")) != EOF)
  341. switch(ch)
  342. {
  343. case 'r':
  344.     reply = TRUE;
  345.     break;
  346. case 'v':
  347.     verbose = TRUE;
  348.     break;
  349. }
  350.     while (fgets(buf, sizeof(buf)-1, stdin))
  351.     {
  352. if (buf[0] == ' ' || buf[0] == 't')
  353.     strcat(longbuf, buf);
  354. else if (!strncasecmp("From: ", buf, 6)
  355.     || !strncasecmp("To: ", buf, 4)
  356.     || !strncasecmp("Reply-", buf, 6)
  357.     || !strncasecmp("Cc: ", buf, 4)
  358.     || !strncasecmp("Bcc: ", buf, 5))
  359.     strcpy(longbuf, buf);
  360. else if (longbuf[0])
  361. {
  362.     if (verbose)
  363. fputs(longbuf, stdout);
  364.     parsebuf(longbuf, reply);
  365.     longbuf[0] = '';
  366. }
  367.     }
  368.     if (longbuf[0])
  369.     {
  370. if (verbose)
  371.     fputs(longbuf, stdout);
  372. parsebuf(longbuf, reply);
  373.     }
  374. }
  375. #endif /* TESTMAIN */
  376. /* rfc822.c end */