# include # include # include # include # include # include # include "sendmail.h" SCCSID(@(#)util.c 3.17 06/07/82); /* ** STRIPQUOTES -- Strip quotes & quote bits from a string. ** ** Runs through a string and strips off unquoted quote ** characters and quote bits. This is done in place. ** ** Parameters: ** s -- the string to strip. ** qf -- if set, remove actual `` " '' characters ** as well as the quote bits. ** ** Returns: ** none. ** ** Side Effects: ** none. ** ** Called By: ** deliver */ stripquotes(s, qf) char *s; bool qf; { register char *p; register char *q; register char c; if (s == NULL) return; for (p = q = s; (c = *p++) != '\0'; ) { if (c != '"' || !qf) *q++ = c & 0177; } *q = '\0'; } /* ** CAPITALIZE -- return a copy of a string, properly capitalized. ** ** Parameters: ** s -- the string to capitalize. ** ** Returns: ** a pointer to a properly capitalized string. ** ** Side Effects: ** none. */ char * capitalize(s) register char *s; { static char buf[50]; register char *p; p = buf; for (;;) { while (!isalpha(*s) && *s != '\0') *p++ = *s++; if (*s == '\0') break; *p++ = toupper(*s++); while (isalpha(*s)) *p++ = *s++; } *p = '\0'; return (buf); } /* ** XALLOC -- Allocate memory and bitch wildly on failure. ** ** THIS IS A CLUDGE. This should be made to give a proper ** error -- but after all, what can we do? ** ** Parameters: ** sz -- size of area to allocate. ** ** Returns: ** pointer to data region. ** ** Side Effects: ** Memory is allocated. */ char * xalloc(sz) register int sz; { register char *p; p = malloc(sz); if (p == NULL) { syserr("Out of memory!!"); exit(EX_UNAVAILABLE); } return (p); } /* ** NEWSTR -- make copy of string. ** ** Space is allocated for it using xalloc. ** ** Parameters: ** string to copy. ** ** Returns: ** pointer to new string. ** ** Side Effects: ** none. */ char * newstr(s) register char *s; { register char *p; p = xalloc(strlen(s) + 1); (void) strcpy(p, s); return (p); } /* ** COPYPLIST -- copy list of pointers. ** ** This routine is the equivalent of newstr for lists of ** pointers. ** ** Parameters: ** list -- list of pointers to copy. ** Must be NULL terminated. ** copycont -- if TRUE, copy the contents of the vector ** (which must be a string) also. ** ** Returns: ** a copy of 'list'. ** ** Side Effects: ** none. */ char ** copyplist(list, copycont) char **list; bool copycont; { register char **vp; register char **newvp; for (vp = list; *vp != NULL; vp++) continue; vp++; newvp = (char **) xalloc((vp - list) * sizeof *vp); bmove((char *) list, (char *) newvp, (vp - list) * sizeof *vp); if (copycont) { for (vp = newvp; *vp != NULL; vp++) *vp = newstr(*vp); } return (newvp); } /* ** PRINTAV -- print argument vector. ** ** Parameters: ** av -- argument vector. ** ** Returns: ** none. ** ** Side Effects: ** prints av. */ # ifdef DEBUG printav(av) register char **av; { while (*av != NULL) { printf("\t%08x=", *av); xputs(*av++); putchar('\n'); } } # endif DEBUG /* ** LOWER -- turn letter into lower case. ** ** Parameters: ** c -- character to turn into lower case. ** ** Returns: ** c, in lower case. ** ** Side Effects: ** none. */ char lower(c) register char c; { if (isascii(c) && isupper(c)) c = c - 'A' + 'a'; return (c); } /* ** XPUTS -- put string doing control escapes. ** ** Parameters: ** s -- string to put. ** ** Returns: ** none. ** ** Side Effects: ** output to stdout */ # ifdef DEBUG xputs(s) register char *s; { register char c; while ((c = *s++) != '\0') { if (!isascii(c)) { putchar('\\'); c &= 0177; } if (iscntrl(c)) { putchar('^'); c |= 0100; } putchar(c); } (void) fflush(stdout); } # endif DEBUG /* ** MAKELOWER -- Translate a line into lower case ** ** Parameters: ** p -- the string to translate. If NULL, return is ** immediate. ** ** Returns: ** none. ** ** Side Effects: ** String pointed to by p is translated to lower case. ** ** Called By: ** parse */ makelower(p) register char *p; { register char c; if (p == NULL) return; for (; (c = *p) != '\0'; p++) if (isascii(c) && isupper(c)) *p = c - 'A' + 'a'; } /* ** SAMEWORD -- return TRUE if the words are the same ** ** Ignores case. ** ** Parameters: ** a, b -- the words to compare. ** ** Returns: ** TRUE if a & b match exactly (modulo case) ** FALSE otherwise. ** ** Side Effects: ** none. */ bool sameword(a, b) register char *a, *b; { while (lower(*a) == lower(*b)) { if (*a == '\0') return (TRUE); a++; b++; } return (FALSE); } /* ** CLEAR -- clear a block of memory ** ** Parameters: ** p -- location to clear. ** l -- number of bytes to clear. ** ** Returns: ** none. ** ** Side Effects: ** none. */ clear(p, l) register char *p; register int l; { while (l-- > 0) *p++ = 0; } /* ** BUILDFNAME -- build full name from gecos style entry. ** ** This routine interprets the strange entry that would appear ** in the GECOS field of the password file. ** ** Parameters: ** p -- name to build. ** login -- the login name of this user (for &). ** buf -- place to put the result. ** ** Returns: ** none. ** ** Side Effects: ** none. */ buildfname(p, login, buf) register char *p; char *login; char *buf; { register char *bp = buf; if (*p == '*') p++; while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') { if (*p == '&') { (void) strcpy(bp, login); *bp = toupper(*bp); while (*bp != '\0') bp++; p++; } else *bp++ = *p++; } *bp = '\0'; } /* ** SAFEFILE -- return true if a file exists and is safe for a user. ** ** Parameters: ** fn -- filename to check. ** uid -- uid to compare against. ** mode -- mode bits that must match. ** ** Returns: ** TRUE if fn exists, is owned by uid, and matches mode. ** FALSE otherwise. ** ** Side Effects: ** none. */ bool safefile(fn, uid, mode) char *fn; int uid; int mode; { struct stat stbuf; if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && (stbuf.st_mode & mode) == mode) return (TRUE); return (FALSE); } /* ** FIXCRLF -- fix in line. ** ** Looks for the combination and turns it into the ** UNIX canonical character. It only takes one line, ** i.e., it is assumed that the first found is the end ** of the line. ** ** Parameters: ** line -- the line to fix. ** stripnl -- if true, strip the newline also. ** ** Returns: ** none. ** ** Side Effects: ** line is changed in place. */ fixcrlf(line, stripnl) char *line; bool stripnl; { register char *p; p = index(line, '\n'); if (p == NULL) return; if (p[-1] == '\r') p--; if (!stripnl) *p++ = '\n'; *p = '\0'; } /* ** SYSLOG -- fake entry to fool lint */ # ifdef LOG # ifdef lint /*VARARGS2*/ syslog(pri, fmt, args) int pri; char *fmt; { pri = *fmt; args = pri; pri = args; } # endif lint # endif LOG /* ** DFOPEN -- determined file open ** ** This routine has the semantics of fopen, except that it will ** keep trying a few times to make this happen. The idea is that ** on very loaded systems, we may run out of resources (inodes, ** whatever), so this tries to get around it. */ FILE * dfopen(filename, mode) char *filename; char *mode; { register int tries; register FILE *fp; extern int errno; for (tries = 0; tries < 10; tries++) { sleep(10 * tries); errno = 0; fp = fopen(filename, mode); if (fp != NULL || errno != ENFILE) break; } return (fp); } /* ** PUTLINE -- put a line like fputs obeying SMTP conventions ** ** Parameters: ** l -- line to put. ** fp -- file to put it onto. ** fullsmtp -- if set, obey strictest SMTP conventions. ** ** Returns: ** none ** ** Side Effects: ** output of l to fp. */ # define SMTPLINELIM 120 /* maximum line length */ putline(l, fp, fullsmtp) char *l; FILE *fp; bool fullsmtp; { register char *p; char s1, s2; if (!fullsmtp) { fputs(l, fp); return; } /* find the end of the line */ p = index('\n', l); if (p == NULL) p = &l[strlen(l)]; /* check for line overflow */ while (p - l > SMTPLINELIM) { register char *q = &l[SMTPLINELIM - 1]; char svchar = *q; *q = '\0'; fputs(l, fp); fputs("!\r\n", fp); *q = svchar; l = q; } /* output last part */ *p = '\0'; fputs(l, fp); fputs("\r\n", fp); *p = '\n'; }