2 * rfc822.c -- code for slicing and dicing RFC822 mail headers
4 * Copyright 1996 by Eric S. Raymond
6 * For license terms, see the file COPYING in this directory.
12 #if defined(STDC_HEADERS)
16 #include "fetchmail.h"
18 void reply_hack(buf, host)
19 /* hack message headers so replies will work properly */
20 char *buf; /* header to be hacked */
21 const char *host; /* server hostname */
24 int parendepth, state = 0, tokencount = 0;
25 char mycopy[POPBUFSIZE+1];
27 if (strncmp("From: ", buf, 6)
28 && strncmp("To: ", buf, 4)
29 && strncmp("Reply-", buf, 6)
30 && strncmp("Cc: ", buf, 4)
31 && strncmp("Bcc: ", buf, 5)) {
36 for (from = mycopy; *from; from++)
40 case 0: /* before header colon */
45 case 1: /* we've seen the colon, we're looking for addresses */
48 else if (*from == '(')
53 else if (*from == '<' || isalnum(*from))
55 else if (isspace(*from))
59 case 2: /* found a token boundary -- reset without copying */
60 if (*from != ' ' && *from != '\t')
68 case 3: /* we're in a quoted human name, copy and ignore */
73 case 4: /* we're in a parenthesized human name, copy and ignore */
76 else if (*from == ')')
82 case 5: /* the real work gets done here */
84 * We're in something that might be an address part,
85 * either a bare unquoted/unparenthesized text or text
86 * enclosed in <> as per RFC822.
88 /* if the address part contains an @, don't mess with it */
92 /* If the address token is not properly terminated, ignore it. */
93 else if (*from == ' ' || *from == '\t')
98 * The only lookahead case. If we're looking at space or tab,
99 * we might be looking at a local name immediately followed
102 for (cp = from; isspace(*cp); cp++)
114 * On proper termination with no @, insert hostname.
115 * Case '>' catches <>-enclosed mail IDs. Case ',' catches
116 * comma-separated bare IDs.
118 else if (strchr(">,", *from))
127 /* a single local name alone on the line */
128 else if (*from == '\n' && tokencount == 1)
136 /* everything else, including alphanumerics, just passes through */
139 case 6: /* we're in a remote mail ID, no need to append hostname */
140 if (*from == '>' || *from == ',' || isspace(*from))
145 /* all characters from the old buffer get copied to the new one */
152 /* parse addresses in succession out of a specified RFC822 header */
153 const char *hdr; /* header to be parsed, NUL to continue previous hdr */
155 static char *tp, address[POPBUFSIZE+1];
156 static const char *hp;
157 static int state, oldstate;
161 * Note 1: RFC822 escaping with \ is *not* handled. Note 2: it is
162 * important that this routine not stop on \r, since we use \r as
163 * a marker for RFC822 continuations elsewhere.
165 #define START_HDR 0 /* before header colon */
166 #define SKIP_JUNK 1 /* skip whitespace, \n, and junk */
167 #define BARE_ADDRESS 2 /* collecting address without delimiters */
168 #define INSIDE_DQUOTE 3 /* inside double quotes */
169 #define INSIDE_PARENS 4 /* inside parentheses */
170 #define INSIDE_BRACKETS 5 /* inside bracketed address */
171 #define ENDIT_ALL 6 /* after last address */
183 case START_HDR: /* before header colon */
196 case SKIP_JUNK: /* looking for address start */
197 if (*hp == '\n') /* no more addresses */
202 else if (*hp == '"') /* quoted string */
204 oldstate = SKIP_JUNK;
205 state = INSIDE_DQUOTE;
208 else if (*hp == '(') /* address comment -- ignore */
211 state = INSIDE_PARENS;
213 else if (*hp == '<') /* begin <address> */
215 state = INSIDE_BRACKETS;
218 else if (!isspace(*hp)) /* ignore space */
221 state = BARE_ADDRESS;
225 case BARE_ADDRESS: /* collecting address without delimiters */
226 if (*hp == '\n') /* end of bare address */
230 return(tp = address);
232 else if (*hp == ',' || isspace(*hp)) /* end of address */
239 return(tp = address);
242 else /* just take it */
244 state = BARE_ADDRESS;
249 case INSIDE_DQUOTE: /* we're in a quoted string, copy verbatim */
264 case INSIDE_PARENS: /* we're in a parenthesized comment, ignore */
275 case INSIDE_BRACKETS: /* possible <>-enclosed address */
276 if (*hp == '>') /* end of address */
281 return(tp = address);
283 else if (*hp == '<') /* nested <> */
285 else if (*hp == '"') /* quoted address */
288 oldstate = INSIDE_BRACKETS;
289 state = INSIDE_DQUOTE;
291 else /* just copy address */
295 case ENDIT_ALL: /* after last address */
305 main(int argc, char *argv[])
307 char buf[POPBUFSIZE], *cp;
309 while (fgets(buf, sizeof(buf)-1, stdin))
311 if (strncmp("From: ", buf, 6)
312 && strncmp("To: ", buf, 4)
313 && strncmp("Reply-", buf, 6)
314 && strncmp("Cc: ", buf, 4)
315 && strncmp("Bcc: ", buf, 5))
320 if ((cp = nxtaddr(buf)) != (char *)NULL)
324 ((cp = nxtaddr((char *)NULL)) != (char *)NULL);
329 #endif /* TESTMAIN */