X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/a0852086e51a651b82a22dd5e6a4ae93749fb5c7..a12ff48697cac43c0bd58aadc3f665316752562b:/usr/src/usr.bin/mail/aux.c diff --git a/usr/src/usr.bin/mail/aux.c b/usr/src/usr.bin/mail/aux.c index 0d82d3c7a6..1fbc0e5e30 100644 --- a/usr/src/usr.bin/mail/aux.c +++ b/usr/src/usr.bin/mail/aux.c @@ -1,9 +1,16 @@ -# +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * %sccs.include.redist.c% + */ + +#ifndef lint +static char sccsid[] = "@(#)aux.c 8.1 (Berkeley) %G%"; +#endif /* not lint */ #include "rcv.h" -#include -#include -#include +#include "extern.h" /* * Mail -- a mail program @@ -11,98 +18,84 @@ * Auxiliary functions. */ -static char *SccsId = "@(#)aux.c 2.2 %G%"; - /* * Return a pointer to a dynamic copy of the argument. */ - char * savestr(str) char *str; { - register char *cp, *cp2, *top; + char *new; + int size = strlen(str) + 1; - for (cp = str; *cp; cp++) - ; - top = salloc(cp-str + 1); - if (top == NOSTR) - return(NOSTR); - for (cp = str, cp2 = top; *cp; cp++) - *cp2++ = *cp; - *cp2 = 0; - return(top); + if ((new = salloc(size)) != NOSTR) + bcopy(str, new, size); + return new; } /* - * Copy the name from the passed header line into the passed - * name buffer. Null pad the name buffer. + * Make a copy of new argument incorporating old one. */ - -copyname(linebuf, nbuf) - char *linebuf, *nbuf; +char * +save2str(str, old) + char *str, *old; { - register char *cp, *cp2; - - for (cp = linebuf + 5, cp2 = nbuf; *cp != ' ' && cp2-nbuf < 8; cp++) - *cp2++ = *cp; - while (cp2-nbuf < 8) - *cp2++ = 0; + char *new; + int newsize = strlen(str) + 1; + int oldsize = old ? strlen(old) + 1 : 0; + + if ((new = salloc(newsize + oldsize)) != NOSTR) { + if (oldsize) { + bcopy(old, new, oldsize); + new[oldsize - 1] = ' '; + } + bcopy(str, new + oldsize, newsize); + } + return new; } /* * Announce a fatal error and die. */ +#if __STDC__ +#include +#else +#include +#endif -panic(str) - char *str; -{ - prs("panic: "); - prs(str); - prs("\n"); - exit(1); -} - -/* - * Catch stdio errors and report them more nicely. - */ - -_error(str) - char *str; +void +#if __STDC__ +panic(const char *fmt, ...) +#else +panic(fmt, va_alist) + char *fmt; + va_dcl +#endif { - prs("Stdio Error: "); - prs(str); - prs("\n"); + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "panic: "); + vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + fflush(stderr); abort(); } -/* - * Print a string on diagnostic output. - */ - -prs(str) - char *str; -{ - register char *s; - - for (s = str; *s; s++) - ; - write(2, str, s-str); -} - /* * Touch the named message by setting its MTOUCH flag. * Touched messages have the effect of not being sent * back to the system mailbox on exit. */ - -touch(mesg) -{ +void +touch(mp) register struct message *mp; +{ - if (mesg < 1 || mesg > msgCount) - return; - mp = &message[mesg-1]; mp->m_flag |= MTOUCH; if ((mp->m_flag & MREAD) == 0) mp->m_flag |= MREAD|MSTATUS; @@ -112,7 +105,7 @@ touch(mesg) * Test to see if the passed file name is a directory. * Return true if it is. */ - +int isdir(name) char name[]; { @@ -123,82 +116,24 @@ isdir(name) return((sbuf.st_mode & S_IFMT) == S_IFDIR); } -/* - * Compute the size in characters of the passed message - */ - -unsigned int -msize(messp) - struct message *messp; -{ - register struct message *mp; - - mp = messp; - return(mp->m_size); -} - /* * Count the number of arguments in the given string raw list. */ - +int argcount(argv) char **argv; { register char **ap; - for (ap = argv; *ap != NOSTR; ap++) + for (ap = argv; *ap++ != NOSTR;) ; - return(ap-argv); -} - -/* - * Given a file address, determine the - * block number it represents. - */ - -blockof(off) - off_t off; -{ - off_t a; - - a = off >> 9; - a &= 077777; - return((int) a); -} - -/* - * Take a file address, and determine - * its offset in the current block. - */ - -offsetof(off) - off_t off; -{ - off_t a; - - a = off & 0777; - return((int) a); -} - -/* - * Determine if the passed file is actually a tty, via a call to - * gtty. This is not totally reliable, but . . . - */ - -isatty(f) -{ - struct sgttyb buf; - - if (gtty(f, &buf) < 0) - return(0); - return(1); + return ap - argv - 1; } /* * Return the desired header line from the passed message * pointer (or NOSTR if the desired header field is not available). */ - char * hfield(field, mp) char field[]; @@ -207,170 +142,120 @@ hfield(field, mp) register FILE *ibuf; char linebuf[LINESIZE]; register int lc; + register char *hfield; + char *colon, *oldhfield = NOSTR; ibuf = setinput(mp); - if ((lc = mp->m_lines) <= 0) - return(NOSTR); - if (readline(ibuf, linebuf) < 0) - return(NOSTR); - lc--; - do { - lc = gethfield(ibuf, linebuf, lc); - if (lc == -1) - return(NOSTR); - if (ishfield(linebuf, field)) - return(savestr(hcontents(linebuf))); - } while (lc > 0); - return(NOSTR); + if ((lc = mp->m_lines - 1) < 0) + return NOSTR; + if (readline(ibuf, linebuf, LINESIZE) < 0) + return NOSTR; + while (lc > 0) { + if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0) + return oldhfield; + if (hfield = ishfield(linebuf, colon, field)) + oldhfield = save2str(hfield, oldhfield); + } + return oldhfield; } /* * Return the next header field found in the given message. - * Return > 0 if something found, <= 0 elsewise. + * Return >= 0 if something found, < 0 elsewise. + * "colon" is set to point to the colon in the header. * Must deal with \ continuations & other such fraud. */ - -gethfield(f, linebuf, rem) +int +gethfield(f, linebuf, rem, colon) register FILE *f; char linebuf[]; register int rem; + char **colon; { char line2[LINESIZE]; - long loc; register char *cp, *cp2; register int c; - for (;;) { - if (rem <= 0) - return(-1); - if (readline(f, linebuf) < 0) - return(-1); - rem--; - if (strlen(linebuf) == 0) - return(-1); - if (isspace(linebuf[0])) + if (--rem < 0) + return -1; + if ((c = readline(f, linebuf, LINESIZE)) <= 0) + return -1; + for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':'; + cp++) + ; + if (*cp != ':' || cp == linebuf) continue; - if (linebuf[0] == '>') - continue; - cp = index(linebuf, ':'); - if (cp == NOSTR) - continue; - for (cp2 = linebuf; cp2 < cp; cp2++) - if (isdigit(*cp2)) - continue; - /* * I guess we got a headline. * Handle wraparounding */ - + *colon = cp; + cp = linebuf + c; for (;;) { + while (--cp >= linebuf && (*cp == ' ' || *cp == '\t')) + ; + cp++; if (rem <= 0) break; -#ifdef CANTELL - loc = ftell(f); - if (readline(f, line2) < 0) - break; - rem--; - if (!isspace(line2[0])) { - fseek(f, loc, 0); - rem++; - break; - } -#else - c = getc(f); - ungetc(c, f); - if (!isspace(c) || c == '\n') + ungetc(c = getc(f), f); + if (c != ' ' && c != '\t') break; - if (readline(f, line2) < 0) + if ((c = readline(f, line2, LINESIZE)) < 0) break; rem--; -#endif - cp2 = line2; - for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++) + for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++) ; - if (strlen(linebuf) + strlen(cp2) >= LINESIZE-2) + c -= cp2 - line2; + if (cp + c >= linebuf + LINESIZE - 2) break; - cp = &linebuf[strlen(linebuf)]; - while (cp > linebuf && - (isspace(cp[-1]) || cp[-1] == '\\')) - cp--; *cp++ = ' '; - for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++) - ; - strcpy(cp, cp2); + bcopy(cp2, cp, c); + cp += c; } - if ((c = strlen(linebuf)) > 0) { - cp = &linebuf[c-1]; - while (cp > linebuf && isspace(*cp)) - cp--; - *++cp = 0; - } - return(rem); + *cp = 0; + return rem; } /* NOTREACHED */ } /* * Check whether the passed line is a header line of - * the desired breed. + * the desired breed. Return the field body, or 0. */ -ishfield(linebuf, field) +char* +ishfield(linebuf, colon, field) char linebuf[], field[]; + char *colon; { - register char *cp; - register int c; + register char *cp = colon; - if ((cp = index(linebuf, ':')) == NOSTR) - return(0); - if (cp == linebuf) - return(0); - cp--; - while (cp > linebuf && isspace(*cp)) - cp--; - c = *++cp; *cp = 0; - if (icequal(linebuf ,field)) { - *cp = c; - return(1); + if (strcasecmp(linebuf, field) != 0) { + *cp = ':'; + return 0; } - *cp = c; - return(0); -} - -/* - * Extract the non label information from the given header field - * and return it. - */ - -char * -hcontents(hfield) - char hfield[]; -{ - register char *cp; - - if ((cp = index(hfield, ':')) == NOSTR) - return(NOSTR); - cp++; - while (*cp && isspace(*cp)) - cp++; - return(cp); + *cp = ':'; + for (cp++; *cp == ' ' || *cp == '\t'; cp++) + ; + return cp; } /* - * Compare two strings, ignoring case. + * Copy a string, lowercasing it as we go. */ - -icequal(s1, s2) - register char *s1, *s2; +void +istrcpy(dest, src) + register char *dest, *src; { - while (raise(*s1++) == raise(*s2)) - if (*s2++ == 0) - return(1); - return(0); + do { + if (isupper(*src)) + *dest++ = tolower(*src); + else + *dest++ = *src; + } while (*src++ != 0); } /* @@ -379,127 +264,103 @@ icequal(s1, s2) * the stack. */ -static int ssp = -1; /* Top of file stack */ +static int ssp; /* Top of file stack */ struct sstack { FILE *s_file; /* File we were in. */ int s_cond; /* Saved state of conditionals */ -} sstack[_NFILE]; + int s_loading; /* Loading .mailrc, etc. */ +} sstack[NOFILE]; /* * Pushdown current input file and switch to a new one. * Set the global flag "sourcing" so that others will realize * that they are no longer reading from a tty (in all probability). */ - -source(name) - char name[]; +int +source(arglist) + char **arglist; { - register FILE *fi; - register char *cp; + FILE *fi; + char *cp; - if ((cp = expand(name)) == NOSTR) + if ((cp = expand(*arglist)) == NOSTR) return(1); - if ((fi = fopen(cp, "r")) == NULL) { + if ((fi = Fopen(cp, "r")) == NULL) { perror(cp); return(1); } - if (ssp >= _NFILE-2) { + if (ssp >= NOFILE - 1) { printf("Too much \"sourcing\" going on.\n"); - fclose(fi); + Fclose(fi); return(1); } - sstack[++ssp].s_file = input; + sstack[ssp].s_file = input; sstack[ssp].s_cond = cond; + sstack[ssp].s_loading = loading; + ssp++; + loading = 0; cond = CANY; input = fi; sourcing++; return(0); } -/* - * Source a file, but do nothing if the file cannot be opened. - */ - -source1(name) - char name[]; -{ - register int f; - - if ((f = open(name, 0)) < 0) - return(0); - close(f); - source(name); -} - /* * Pop the current input back to the previous level. * Update the "sourcing" flag as appropriate. */ - +int unstack() { - if (ssp < 0) { + if (ssp <= 0) { printf("\"Source\" stack over-pop.\n"); sourcing = 0; return(1); } - fclose(input); + Fclose(input); if (cond != CANY) printf("Unmatched \"if\"\n"); + ssp--; cond = sstack[ssp].s_cond; - input = sstack[ssp--].s_file; - if (ssp < 0) - sourcing = 0; + loading = sstack[ssp].s_loading; + input = sstack[ssp].s_file; + if (ssp == 0) + sourcing = loading; return(0); } /* * Touch the indicated file. * This is nifty for the shell. - * If we have the utime() system call, this is better served - * by using that, since it will work for empty files. - * On non-utime systems, we must sleep a second, then read. */ - +void alter(name) - char name[]; + char *name; { -#ifdef UTIME - struct stat statb; - long time(); - time_t time_p[2]; -#else - register int pid, f; - char w; -#endif UTIME + struct stat sb; + struct timeval tv[2]; + time_t time(); -#ifdef UTIME - if (stat(name, &statb) < 0) - return; - time_p[0] = time((long *) 0) + 1; - time_p[1] = statb.st_mtime; - utime(name, time_p); -#else - sleep(1); - if ((f = open(name, 0)) < 0) + if (stat(name, &sb)) return; - read(f, &w, 1); - exit(0); -#endif + tv[0].tv_sec = time((time_t *)0) + 1; + tv[1].tv_sec = sb.st_mtime; + tv[0].tv_usec = tv[1].tv_usec = 0; + (void)utimes(name, tv); } /* * Examine the passed line buffer and * return true if it is all blanks and tabs. */ - +int blankline(linebuf) char linebuf[]; { register char *cp; for (cp = linebuf; *cp; cp++) - if (!any(*cp, " \t")) + if (*cp != ' ' && *cp != '\t') return(0); return(1); } @@ -512,13 +373,51 @@ blankline(linebuf) char * nameof(mp, reptype) register struct message *mp; + int reptype; +{ + register char *cp, *cp2; + + cp = skin(name1(mp, reptype)); + if (reptype != 0 || charcount(cp, '!') < 2) + return(cp); + cp2 = rindex(cp, '!'); + cp2--; + while (cp2 > cp && *cp2 != '!') + cp2--; + if (*cp2 == '!') + return(cp2 + 1); + return(cp); +} + +/* + * Start of a "comment". + * Ignore it. + */ +char * +skip_comment(cp) + register char *cp; { + register nesting = 1; - return(skin(name1(mp, reptype))); + for (; nesting > 0 && *cp; cp++) { + switch (*cp) { + case '\\': + if (cp[1]) + cp++; + break; + case '(': + nesting++; + break; + case ')': + nesting--; + break; + } + } + return cp; } /* - * Skin an arpa net address according to the RFC 733 interpretation + * Skin an arpa net address according to the RFC 822 interpretation * of "host-phrase." */ char * @@ -527,38 +426,79 @@ skin(name) { register int c; register char *cp, *cp2; + char *bufend; int gotlt, lastsp; char nbuf[BUFSIZ]; if (name == NOSTR) return(NOSTR); - if (index(name, '(') == NOSTR && index(name, '<') == NOSTR) + if (index(name, '(') == NOSTR && index(name, '<') == NOSTR + && index(name, ' ') == NOSTR) return(name); gotlt = 0; lastsp = 0; - for (cp = name, cp2 = nbuf, c = *cp++; *cp; c = *cp++) { + bufend = nbuf; + for (cp = name, cp2 = bufend; c = *cp++; ) { switch (c) { case '(': - while (*cp != ')' && *cp != 0) - cp++; - if (*cp) + cp = skip_comment(cp); + lastsp = 0; + break; + + case '"': + /* + * Start of a "quoted-string". + * Copy it in its entirety. + */ + while (c = *cp) { cp++; + if (c == '"') + break; + if (c != '\\') + *cp2++ = c; + else if (c = *cp) { + *cp2++ = c; + cp++; + } + } + lastsp = 0; break; case ' ': - lastsp = 1; + if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ') + cp += 3, *cp2++ = '@'; + else + if (cp[0] == '@' && cp[1] == ' ') + cp += 2, *cp2++ = '@'; + else + lastsp = 1; break; case '<': - cp2 = nbuf; + cp2 = bufend; gotlt++; lastsp = 0; break; case '>': - if (gotlt) - goto done; - + if (gotlt) { + gotlt = 0; + while ((c = *cp) && c != ',') { + cp++; + if (c == '(') + cp = skip_comment(cp); + else if (c == '"') + while (c = *cp) { + cp++; + if (c == '"') + break; + if (c == '\\' && *cp) + cp++; + } + } + lastsp = 0; + break; + } /* Fall into . . . */ default: @@ -567,10 +507,15 @@ skin(name) *cp2++ = ' '; } *cp2++ = c; - break; + if (c == ',' && !gotlt) { + *cp2++ = ' '; + for (; *cp == ' '; cp++) + ; + lastsp = 0; + bufend = cp2; + } } } -done: *cp2 = 0; return(savestr(nbuf)); @@ -583,10 +528,10 @@ done: * 1 -- get sender's name for reply * 2 -- get sender's name for Reply */ - char * name1(mp, reptype) register struct message *mp; + int reptype; { char namebuf[LINESIZE]; char linebuf[LINESIZE]; @@ -594,26 +539,24 @@ name1(mp, reptype) register FILE *ibuf; int first = 1; -#ifndef DELIVERMAIL if ((cp = hfield("from", mp)) != NOSTR) - return(cp); + return cp; if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR) - return(cp); -#endif + return cp; ibuf = setinput(mp); - copy("", namebuf); - if (readline(ibuf, linebuf) <= 0) + namebuf[0] = 0; + if (readline(ibuf, linebuf, LINESIZE) < 0) return(savestr(namebuf)); newname: - for (cp = linebuf; *cp != ' '; cp++) + for (cp = linebuf; *cp && *cp != ' '; cp++) ; - while (any(*cp, " \t")) - cp++; - for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") && - cp2-namebuf < LINESIZE-1; *cp2++ = *cp++) + for (; *cp == ' ' || *cp == '\t'; cp++) ; + for (cp2 = &namebuf[strlen(namebuf)]; + *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;) + *cp2++ = *cp++; *cp2 = '\0'; - if (readline(ibuf, linebuf) <= 0) + if (readline(ibuf, linebuf, LINESIZE) < 0) return(savestr(namebuf)); if ((cp = index(linebuf, 'F')) == NULL) return(savestr(namebuf)); @@ -629,7 +572,7 @@ newname: break; cp++; if (first) { - copy(cp, namebuf); + strcpy(namebuf, cp); first = 0; } else strcpy(rindex(namebuf, '!')+1, cp); @@ -642,87 +585,95 @@ newname: } /* - * Find the rightmost pointer to an instance of the - * character in the string and return it. + * Count the occurances of c in str */ - -char * -rindex(str, c) - char str[]; - register int c; +int +charcount(str, c) + char *str; + int c; { - register char *cp, *cp2; + register char *cp; + register int i; - for (cp = str, cp2 = NOSTR; *cp; cp++) - if (c == *cp) - cp2 = cp; - return(cp2); + for (i = 0, cp = str; *cp; cp++) + if (*cp == c) + i++; + return(i); } /* - * See if the string is a number. + * Are any of the characters in the two strings the same? */ - -numeric(str) - char str[]; +int +anyof(s1, s2) + register char *s1, *s2; { - register char *cp = str; - while (*cp) - if (!isdigit(*cp++)) - return(0); - return(1); + while (*s1) + if (index(s2, *s1++)) + return 1; + return 0; } /* - * Are any of the characters in the two strings the same? + * Convert c to upper case */ - -anyof(s1, s2) - register char *s1, *s2; -{ +int +raise(c) register int c; +{ - while (c = *s1++) - if (any(c, s2)) - return(1); - return(0); + if (islower(c)) + return toupper(c); + return c; } /* - * Determine the leftmost index of the character - * in the string. + * Copy s1 to s2, return pointer to null in s2. */ - char * -index(str, ch) - char *str; +copy(s1, s2) + register char *s1, *s2; { - register char *cp; - register int c; - for (c = ch, cp = str; *cp; cp++) - if (*cp == c) - return(cp); - return(NOSTR); + while (*s2++ = *s1++) + ; + return s2 - 1; } /* - * String compare two strings of bounded length. + * See if the given header field is supposed to be ignored. */ +int +isign(field, ignore) + char *field; + struct ignoretab ignore[2]; +{ + char realfld[BUFSIZ]; + + if (ignore == ignoreall) + return 1; + /* + * Lower-case the string, so that "Status" and "status" + * will hash to the same place. + */ + istrcpy(realfld, field); + if (ignore[1].i_count > 0) + return (!member(realfld, ignore + 1)); + else + return (member(realfld, ignore)); +} -strncmp(as1, as2, an) - char *as1, *as2; +int +member(realfield, table) + register char *realfield; + struct ignoretab *table; { - register char *s1, *s2; - register int n; + register struct ignore *igp; - s1 = as1; - s2 = as2; - n = an; - while (--n >= 0 && *s1 == *s2++) - if (*s1++ == '\0') - return(0); - return(n<0 ? 0 : *s1 - *--s2); + for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link) + if (*igp->i_field == *realfield && + equal(igp->i_field, realfield)) + return (1); + return (0); } -