|
|
researchv10 Norman
#ident "@(#)aux.c 1.4 'attmail mail(1) command'"
#ident "@(#)mailx:aux.c 1.14.2.1"
/* Copyright (c) 1984 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#ident "@(#)mailx:aux.c 1.14"
#include "rcv.h"
/*
* mailx -- a modified version of a University of California at Berkeley
* mail program
*
* Auxiliary functions.
*/
static char *phrase();
static char *ripoff();
/*
* Return a pointer to a dynamic copy of the argument.
*/
char *
savestr(str)
char *str;
{
register char *cp, *cp2, *top;
for (cp = str; *cp; cp++)
;
top = salloc((unsigned)(cp-str + 1));
if (top == NOSTR)
return(NOSTR);
for (cp = str, cp2 = top; *cp; cp++)
*cp2++ = *cp;
*cp2 = 0;
return(top);
}
/*
* Announce a fatal error and die.
*/
panic(str)
char *str;
{
fprintf(stderr,"mailx: Panic - %s\n",str);
exit(1);
/* NOTREACHED */
}
/*
* 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.
*/
void
touch(mesg)
{
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;
}
/*
* Test to see if the passed file name is a directory.
* Return true if it is.
*/
isdir(name)
char name[];
{
struct stat sbuf;
if (stat(name, &sbuf) < 0)
return(0);
return((sbuf.st_mode & S_IFMT) == S_IFDIR);
}
/*
* Count the number of arguments in the given string raw list.
*/
argcount(argv)
char **argv;
{
register char **ap;
for (ap = argv; *ap != NOSTR; ap++)
;
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.
*/
offsetofaddr(off)
off_t off;
{
off_t a;
a = off & 0777;
return((int) a);
}
/*
* Return the desired header line from the passed message
* pointer (or NOSTR if the desired header field is not available).
*/
char *
hfield(field, mp, add)
char field[];
struct message *mp;
char *(*add)();
{
register FILE *ibuf;
char linebuf[LINESIZE];
register long lc;
char *r = NOSTR;
ibuf = setinput(mp);
if ((lc = mp->m_lines) <= 0)
return(NOSTR);
if (readline(ibuf, linebuf) < 0)
return(NOSTR);
lc--;
while ((lc = gethfield(ibuf, linebuf, lc)) >= 0)
if (ishfield(linebuf, field))
r = (*add)(r, hcontents(linebuf));
return r;
}
/*
* Return the next header field found in the given message.
* Return > 0 if something found, <= 0 elsewise.
* Must deal with \ continuations & other such fraud.
*/
gethfield(f, linebuf, rem)
register FILE *f;
char linebuf[];
register long rem;
{
char line2[LINESIZE];
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]))
continue;
if (!headerp(linebuf))
return(-1);
/*
* I guess we got a headline.
* Handle wraparounding
*/
for (;;) {
if (rem <= 0)
break;
c = getc(f);
ungetc(c, f);
if (!isspace(c) || c == '\n')
break;
if (readline(f, line2) < 0)
break;
rem--;
cp2 = line2;
for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
;
if (strlen(linebuf) + strlen(cp2) >= 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);
}
if ((c = strlen(linebuf)) > 0) {
cp = &linebuf[c-1];
while (cp > linebuf && isspace(*cp))
cp--;
*++cp = 0;
}
return(rem);
}
/* NOTREACHED */
}
/*
* Check whether the passed line is a header line of
* the desired breed.
*/
ishfield(linebuf, field)
char linebuf[], field[];
{
register char *cp;
register char c;
if ((cp = strchr(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);
}
*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 = strchr(hfield, ':')) == NOSTR)
return(NOSTR);
cp++;
while (*cp && isspace(*cp))
cp++;
return(cp);
}
/*
* Compare two strings, ignoring case.
*/
icequal(s1, s2)
register char *s1, *s2;
{
while (toupper(*s1++) == toupper(*s2))
if (*s2++ == 0)
return(1);
return(0);
}
/*
* Copy a string, lowercasing it as we go.
*/
void
istrcpy(dest, src)
char *dest, *src;
{
register char *cp, *cp2;
cp2 = dest;
cp = src;
do {
*cp2++ = tolower(*cp);
} while (*cp++ != 0);
}
/*
* The following code deals with input stacking to do source
* commands. All but the current file pointer are saved on
* the stack.
*/
static int ssp = -1; /* Top of file stack */
static struct sstack {
FILE *s_file; /* File we were in. */
int s_cond; /* Saved state of conditionals */
int s_loading; /* Loading .mailrc, etc. */
} *sstack;
/*
* 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[];
{
register FILE *fi;
register char *cp;
if ((cp = expand(name)) == NOSTR)
return(1);
if ((fi = fopen(cp, "r")) == NULL) {
printf("Unable to open %s\n",cp);
return(1);
}
if ( !maxfiles ) {
if ( (maxfiles=ulimit(4, 0)) < 0 )
maxfiles = _NFILE;
sstack = (struct sstack *)calloc(maxfiles, sizeof(struct sstack));
if ( sstack == NULL ) {
printf("Couldn't allocate memory for sourcing stack\n");
fclose(fi);
return(1);
}
}
sstack[++ssp].s_file = input;
sstack[ssp].s_cond = cond;
sstack[ssp].s_loading = loading;
loading = 0;
cond = CANY;
input = fi;
sourcing++;
return(0);
}
/*
* Pop the current input back to the previous level.
* Update the "sourcing" flag as appropriate.
*/
unstack()
{
if (ssp < 0) {
printf("\"Source\" stack over-pop.\n");
sourcing = 0;
return(1);
}
fclose(input);
if (cond != CANY)
printf("Unmatched \"if\"\n");
cond = sstack[ssp].s_cond;
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[];
{
int rc = utime(name, utimep);
if (rc != 0) {
fprintf(stderr, "Cannot utime %s in aux:alter\n", name);
fprintf(stderr, "Errno: %d\n", errno);
}
}
/*
* Examine the passed line buffer and
* return true if it is all blanks and tabs.
*/
blankline(linebuf)
char linebuf[];
{
register char *cp;
for (cp = linebuf; *cp; cp++)
if (!any(*cp, " \t"))
return(0);
return(1);
}
/*
* Skin an arpa net address according to the RFC 822 interpretation
* of "host-phrase."
*/
static char *
phrase(name, token, comma)
char *name;
{
register char c;
register char *cp, *cp2;
char *bufend;
int gotlt, lastsp;
char nbuf[LINESIZE];
int nesting;
if (name == NOSTR)
return(NOSTR);
gotlt = 0;
lastsp = 0;
bufend = nbuf;
for (cp = name, cp2 = bufend; (c = *cp++) != 0;) {
switch (c) {
case '(':
/*
Start of a comment, ignore it.
*/
nesting = 1;
while ((c = *cp) != 0) {
cp++;
switch(c) {
case '\\':
if (*cp == 0) goto outcm;
cp++;
break;
case '(':
nesting++;
break;
case ')':
--nesting;
break;
}
if (nesting <= 0) break;
}
outcm:
lastsp = 0;
break;
case '"':
/*
Start a quoted string.
Copy it in its entirety.
*/
while ((c = *cp) != 0) {
cp++;
switch (c) {
case '\\':
if ((c = *cp) == 0) goto outqs;
cp++;
break;
case '"':
goto outqs;
}
*cp2++ = c;
}
outqs:
lastsp = 0;
break;
case '@': /* adb */
case '.': /* adb */
/* suppress spaces around specials */ /* adb */
if( lastsp ) lastsp = 0; /* adb */
while( *cp && isspace(*cp) ) cp++; /* adb */
*cp2++ = c; /* adb */
break; /* adb */
case ' ':
case '\t':
case '\n':
if (token && (!comma || c == '\n')) {
done:
cp[-1] = 0;
return cp;
}
lastsp = 1;
break;
case ',':
*cp2++ = c;
if (gotlt != '<' && (isspace(*cp) || !*cp)) {
if (token)
goto done;
bufend = cp2 + 1;
gotlt = 0;
}
break;
case '<':
cp2 = bufend;
gotlt = c;
lastsp = 0;
break;
case '>':
if (gotlt == '<') {
gotlt = c;
break;
}
/* FALLTHROUGH . . . */
default:
if (gotlt == 0 || gotlt == '<') {
if (lastsp) {
lastsp = 0;
*cp2++ = ' ';
}
*cp2++ = c;
}
break;
}
}
*cp2 = 0;
return (token ? --cp : equal(name, nbuf) ? name : savestr(nbuf));
}
char *
skin(name)
char *name;
{
return phrase(name, 0, 0);
}
char *
yankword(name, word, comma)
char *name, *word;
{
char *cp;
if (name == 0)
return 0;
while (isspace(*name))
name++;
if (*name == 0)
return 0;
cp = phrase(name, 1, comma);
strcpy(word, name);
return cp;
}
docomma(s)
char *s;
{
if (s == NOSTR)
return 0;
if (strpbrk(s, "(<"))
return 1;
while (s = strchr(s, ','))
if (!*++s || isspace(*s))
return 1;
return 0;
}
#ifdef V9
/*
* Fetch senders address from the UPAS-delivered envelope
*/
char *
Fromname(mp)
register struct message *mp;
{
char namebuf[LINESIZE];
char linebuf[LINESIZE];
register char *cp, *cp2;
register FILE *ibuf;
ibuf = setinput(mp);
copy("", namebuf);
if (readline(ibuf, linebuf) <= 0)
return(savestr(namebuf));
for (cp = linebuf; *cp != ' '; cp++)
;
while (any(*cp, " \t"))
cp++;
for (cp2 = namebuf; *cp && !any(*cp, " \t") &&
cp2-namebuf < LINESIZE-1; *cp2++ = *cp++)
;
*cp2 = '\0';
return(savestr(namebuf));
}
#endif /* V9 */
/*
* Fetch the sender's name from the passed message.
*/
char *
nameof(mp)
register struct message *mp;
{
char namebuf[LINESIZE];
char linebuf[LINESIZE];
register char *cp, *cp2;
register FILE *ibuf;
int first = 1, wint = 0;
if (value("from")
&& ((cp = hfield("reply-to", mp, addto)) != NOSTR
|| (cp = hfield("from", mp, addto)) != NOSTR))
return ripoff(cp);
ibuf = setinput(mp);
copy("", namebuf);
if (readline(ibuf, linebuf) <= 0)
return(savestr(namebuf));
newname:
for (cp = linebuf; *cp != ' '; cp++)
;
while (any(*cp, " \t"))
cp++;
for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") &&
cp2-namebuf < LINESIZE-1; *cp2++ = *cp++)
;
*cp2 = '\0';
for (;;) {
if (readline(ibuf, linebuf) <= 0)
break;
if (substr(linebuf,"forwarded by ") != -1)
continue;
if (linebuf[0] == 'F')
cp = linebuf;
else if (linebuf[0] == '>')
cp = linebuf + 1;
else
break;
if (strncmp(cp, "From ", 5) != 0)
break;
if ((wint = substr(cp, "remote from ")) != -1) {
cp += wint + 12;
if (first) {
copy(cp, namebuf);
first = 0;
} else
strcpy(strrchr(namebuf, '!')+1, cp);
strcat(namebuf, "!");
goto newname;
} else
break;
}
for (cp = namebuf; *cp == '!'; cp++);
while (ishost(host, cp))
cp = strchr(cp, '!') + 1;
if (value("mustbang") && !strchr(cp, '!'))
cp = strcat(strcat(strcpy(linebuf, host), "!"), cp);
if (cp2 = hfield("from", mp, addto))
return(splice(cp, cp2));
else
return(savestr(cp));
}
/*
* Splice an address into a commented recipient header.
*/
char *
splice(addr, hdr)
char *addr, *hdr;
{
char buf[LINESIZE];
char *cp, *cp2;
if (cp = strchr(hdr, '<')) {
strncpy(buf, hdr, cp-hdr+1);
buf[cp-hdr+1] = 0;
strcat(buf, addr);
if (cp = strchr(cp, '>'))
strcat(buf, cp);
} else if (cp = strchr(hdr, '(')) {
strcpy(buf, addr);
strcat(buf, " ");
if( cp2 = strchr(cp, ')')) /* adb */
strncat(buf, cp, cp2-cp+1); /* adb */
else /* adb */
strcat(buf, cp); /* adb */
} else
strcpy(buf, addr);
return savestr(ripoff(buf));
}
static char *
ripoff(buf)
register char *buf;
{
register char *cp;
cp = buf + strlen(buf);
while (--cp >= buf && isspace(*cp));
if (cp >= buf && *cp == ',')
cp--;
*++cp = 0;
return buf;
}
/*
* Are any of the characters in the two strings the same?
*/
anyof(s1, s2)
register char *s1, *s2;
{
register int c;
while ((c = *s1++) != 0)
if (any(c, s2))
return(1);
return(0);
}
/*
* See if the given header field is supposed to be ignored.
*/
isign(field)
char *field;
{
char realfld[BUFSIZ];
register int h;
register struct ignore *igp;
istrcpy(realfld, field);
h = hash(realfld);
for (igp = ignore[h]; igp != 0; igp = igp->i_link)
if (strcmp(igp->i_field, realfld) == 0)
return(1);
return(0);
}
/*
This routine looks for string2 in string1.
If found, it returns the position string2 is found at,
otherwise it returns a -1.
*/
substr(string1, string2)
char *string1, *string2;
{
int i,j, len1, len2;
len1 = strlen(string1);
len2 = strlen(string2);
for (i=0; i < len1 - len2 + 1; i++) {
for (j = 0; j < len2 && string1[i+j] == string2[j]; j++);
if (j == len2) return(i);
}
return(-1);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.