const char *host; /* server hostname */
{
const char *from;
- int parendepth, state = 0, tokencount = 0;
- char mycopy[POPBUFSIZE+1];
+ int parendepth, oldstate, state = 0, has_host_part = FALSE;
+ char mycopy[MSGBUFSIZE+1];
if (strncmp("From: ", buf, 6)
&& strncmp("To: ", buf, 4)
strcpy(mycopy, buf);
for (from = mycopy; *from; from++)
{
-#ifdef FOO
- printf("state %d: %s", state, mycopy);
- printf("%*s^\n", from - mycopy + 10, " ");
-#endif /* TESTMAIN */
- switch (state)
- {
- case 0: /* before header colon */
- if (*from == ':')
- state = 1;
- break;
-
- case 1: /* we've seen the colon, we're looking for addresses */
- if (*from == '"')
- state = 3;
- else if (*from == '(')
- {
- parendepth = 1;
- state = 4;
- }
- else if (*from == '<' || isalnum(*from))
- state = 5;
- else if (isspace(*from))
- state = 2;
- break;
-
- case 2: /* found a token boundary -- reset without copying */
- if (*from != ' ' && *from != '\t')
+#define INSERT_HOSTNAME \
+ strcpy(buf, "@"); \
+ strcat(buf, host); \
+ buf += strlen(buf); \
+ has_host_part = TRUE;
+
+ if (*from == '(')
+ ++parendepth;
+ else if (*from == ')')
+ --parendepth;
+
+ if (!parendepth)
+ switch (state)
{
- tokencount++;
- state = 1;
- --from;
- continue;
- }
-
- case 3: /* we're in a quoted human name, copy and ignore */
- if (*from == '"')
- state = 1;
- break;
-
- case 4: /* we're in a parenthesized human name, copy and ignore */
- if (*from == '(')
- ++parendepth;
- else if (*from == ')')
- --parendepth;
- if (parendepth == 0)
- state = 1;
- break;
-
- case 5: /* the real work gets done here */
- /*
- * We're in something that might be an address part,
- * either a bare unquoted/unparenthesized text or text
- * enclosed in <> as per RFC822.
- */
- /* if the address part contains an @, don't mess with it */
- if (*from == '@')
- state = 6;
-
- /* If the address token is not properly terminated, ignore it. */
- else if (*from == ' ' || *from == '\t')
- {
- const char *cp;
-
- /*
- * The only lookahead case. If we're looking at space or tab,
- * we might be looking at a local name immediately followed
- * by a human name.
- */
- for (cp = from; isspace(*cp); cp++)
- continue;
- if (*cp == '(')
- {
- strcpy(buf, "@");
- strcat(buf, host);
- buf += strlen(buf);
+ case 0: /* before header colon */
+ if (*from == ':')
state = 1;
+ break;
+
+ case 1: /* we've seen the colon, we're looking for addresses */
+ if (*from == '<')
+ state = 2;
+ else if (*from == '@')
+ has_host_part = TRUE;
+ else if ((*from == ',' || *from == '\n') && !has_host_part)
+ {
+ INSERT_HOSTNAME
}
- }
-
- /*
- * On proper termination with no @, insert hostname.
- * Case '>' catches <>-enclosed mail IDs. Case ',' catches
- * comma-separated bare IDs.
- */
- else if (strchr(">,", *from))
- {
- strcpy(buf, "@");
- strcat(buf, host);
- buf += strlen(buf);
- tokencount = 0;
- state = 1;
- }
+ break;
- /* a single local name alone on the line */
- else if (*from == '\n' && tokencount == 1)
- {
- strcpy(buf, "@");
- strcat(buf, host);
- buf += strlen(buf);
- state = 2;
+ case 2: /* we're in a <>-enclosed address */
+ if (*from == '@')
+ has_host_part = TRUE;
+ else if (*from == '>' && !has_host_part)
+ {
+ INSERT_HOSTNAME
+ }
+ break;
}
- /* everything else, including alphanumerics, just passes through */
- break;
-
- case 6: /* we're in a remote mail ID, no need to append hostname */
- if (*from == '>' || *from == ',' || isspace(*from))
- state = 1;
- break;
- }
-
/* all characters from the old buffer get copied to the new one */
*buf++ = *from;
+#undef INSERT_HOSTNAME
}
- *buf++ = '\0';
+
+ *buf = '\0';
}
char *nxtaddr(hdr)