#include <stdio.h> #include <ctype.h> #include "mail.h" #include "string.h" #include "header.h" #include "aux.h" #include <regexp.h> /* imported */ extern char *malloc(); extern char *strcpy(); extern char *strchr(); extern int strncmp(); extern void exit(); /* predeclared */ extern void addheader(); extern void addbody(); /* global to this file */ static regexp *rfprog; static regexp *fprog; /* imported */ extern int extrafrom; /* * Input header from standard input. Actually two extra lines are also * read, but this is a problem. Save some header lines in the header * array. */ extern getheader(fgetsp, fp) char *(*fgetsp)(); FILE *fp; { char buf[4096]; string *line; string *from=NULL; string *date=NULL; char *cp; header *hp; int n; /* * forget any old headers */ for (hp = hdrs; *(hp->name) != '\0'; hp++) hp->line = (string *)0; /* * preload the first line for the parsing below */ if((*fgetsp)(buf, sizeof buf, fp) == 0) return ferror(fp) ? -1 : 0; /* If the first line of an rfc822 message * is a unix from line, use that to `seed' the From: and * Date: fields. */ if(strncmp(buf, "From ", 5)==0) { if (getunixfrom(buf, &from, &date)==0) { for (hp = hdrs; *(hp->name) != '\0'; hp++) { if (STRCMP("UnixFrom:", hp) == 0) { hp->line = from; from = (string *)0; continue; }; if (STRCMP("UnixDate:", hp) == 0) { hp->line = date; date = (string *)0; continue; }; } return 0; } } /* Now get real 822 headers */ while (buf[0] != '\n' && buf[0] != '\0') { /* gather a multiple line header field */ line = s_new(); do { s_append(line, buf); if((*fgetsp)(buf, sizeof buf, fp) == 0) { if(ferror(fp)) return -1; *buf = 0; break; } } while (*buf==' ' || *buf=='\t'); /* header lines must contain `:' with no preceding white */ for(cp=s_to_c(line); *cp; cp++) if(isspace(*cp) || *cp==':') break; if (*cp != ':') { addbody(line); break; } /* look for `important' headers */ for (hp = hdrs; *(hp->name) != '\0'; hp++) { if (cistrncmp(s_to_c(line), hp->name, hp->size) == 0) { hp->line = line; break; }; } addheader(line); } /* at this point, buf contains a line of the body */ if(buf[0]) addbody(s_copy(buf)); return 0; } /* * Keep a (circular) list of header lines to output. */ typedef struct quux{ struct quux *next; string *line; } hlist; static hlist dummy = { &dummy, '\0' }; static hlist *list = &dummy; /* * Add to list of header lines. */ extern void addheader(line) string *line; { hlist *thing; thing = (hlist *)malloc(sizeof(hlist)); if (thing == NULL) { perror("reading header"); exit(1); } thing->line = line; thing->next = list->next; list->next = thing; list = thing; } /* * Print list of headers. */ extern int printheaders(fputsp, fp, originalfrom) FILE *fp; int (*fputsp)(); { hlist *thing, *othing; int printed = 0; for(thing = list->next->next; thing != &dummy; ){ printed++; if(originalfrom && strncmp(s_to_c(thing->line), "From:", 5)==0) (*fputsp)("Original-", fp); (*fputsp)(s_to_c(thing->line), fp); s_free(thing->line); othing = thing; thing = thing->next; free(othing); } list = dummy.next = &dummy; /* reinitialize for future calls */ return(printed); } /* * Keep a (circular) list of body lines to output. */ static hlist bdummy = { &bdummy, '\0' }; static hlist *blist = &bdummy; /* * Add to list of body lines. */ extern void addbody(line) string *line; { hlist *thing; thing = (hlist *)malloc(sizeof(hlist)); if (thing == NULL) { perror("reading header"); exit(1); } thing->line = line; thing->next = blist->next; blist->next = thing; blist = thing; } /* * Print list of body lines */ extern void printbodies(fputsp, fp) FILE *fp; int (*fputsp)(); { hlist *thing, *othing; int line = 0; for(thing = blist->next->next; thing != &bdummy; ){ /* dump extraneous new line */ if(line++!=0 || *s_to_c(thing->line)!='\n') (*fputsp)(s_to_c(thing->line), fp); s_free(thing->line); othing = thing; thing = thing->next; free(othing); } blist = bdummy.next = &bdummy; } /* * extract sender and date from a unix remote from line. return -1 * if its the wrong format, 0 otherwise. */ getunixfrom(line, fpp, dpp) char *line; string **fpp; string **dpp; { regsubexp subexp[10]; if (rfprog == NULL) rfprog = regcomp(REMFROMRE); if (regexec(rfprog, line, subexp, 10)) { *fpp = s_new(); append_match(subexp, *fpp, REMSYSMATCH); s_append(*fpp, "!"); append_match(subexp, *fpp, REMSENDERMATCH); *dpp = s_new(); append_match(subexp, *dpp, REMDATEMATCH); return 0; } if (fprog == NULL) fprog = regcomp(FROMRE); if (regexec(fprog, line, subexp, 10)) { *fpp = s_new(); append_match(subexp, *fpp, SENDERMATCH); *dpp = s_new(); append_match(subexp, *dpp, DATEMATCH); return 0; } return -1; } /* * The addr is either the first whitespace delimited token or * the first thing enclosed in "<" ">". * Sets extrafrom > 0 if a from line with other cruft in it. */ extern string * getaddr(line) char *line; { register char *lp; register int comment = 0; register int anticomment = 0; register int inquote = 0; static string *sender=0; if (!sender) sender = s_new(); s_restart(sender); lp = line; for (; *lp; lp++) { if (comment) { if (*lp=='(') comment++; if (*lp==')') comment--; continue; } if (anticomment) { if (*lp=='>') { if (*(lp+1)!='\n') extrafrom++; break; } } if (inquote) { if (*lp=='"') inquote = 0; s_putc(sender, *lp); continue; } switch (*lp) { case '\t': case '\n': break; case ' ': if (cistrncmp(lp, " at ", sizeof(" at ")-1)==0) { s_putc(sender, '@'); lp += sizeof(" at ")-2; } break; case '<': anticomment = 1; if(*s_to_c(sender)!='\0') extrafrom++; s_restart(sender); break; case '(': extrafrom++; comment++; break; case '"': inquote = 1; /* fall through */ default: s_putc(sender, *lp); break; } } s_terminate(sender); s_restart(sender); return(sender); } /* * case independent string compare */ extern int cistrncmp(s1, s2, n) char *s1; char *s2; { int c1, c2; for(; *s1 && n>0; n--, s1++, s2++){ c1 = isupper(*s1) ? tolower(*s1) : *s1; c2 = isupper(*s2) ? tolower(*s2) : *s2; if (c1 != c2) return -1; } return(0); }