util.c revision 88150
136285Sbrian/* 236285Sbrian * Copyright (c) 1980, 1993 336285Sbrian * The Regents of the University of California. All rights reserved. 436285Sbrian * 536285Sbrian * Redistribution and use in source and binary forms, with or without 636285Sbrian * modification, are permitted provided that the following conditions 736285Sbrian * are met: 836285Sbrian * 1. Redistributions of source code must retain the above copyright 936285Sbrian * notice, this list of conditions and the following disclaimer. 1036285Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1136285Sbrian * notice, this list of conditions and the following disclaimer in the 1236285Sbrian * documentation and/or other materials provided with the distribution. 1336285Sbrian * 3. All advertising materials mentioning features or use of this software 1436285Sbrian * must display the following acknowledgement: 1536285Sbrian * This product includes software developed by the University of 1636285Sbrian * California, Berkeley and its contributors. 1736285Sbrian * 4. Neither the name of the University nor the names of its contributors 1836285Sbrian * may be used to endorse or promote products derived from this software 1936285Sbrian * without specific prior written permission. 2036285Sbrian * 2136285Sbrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2236285Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2336285Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2436285Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2536285Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2650479Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2736285Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2836285Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2936452Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3036285Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3136285Sbrian * SUCH DAMAGE. 3236285Sbrian */ 3356413Sbrian 3436285Sbrian#ifndef lint 3536285Sbrian#if 0 3636285Sbrianstatic char sccsid[] = "@(#)aux.c 8.1 (Berkeley) 6/6/93"; 3736285Sbrian#endif 3836285Sbrianstatic const char rcsid[] = 3936285Sbrian "$FreeBSD: head/usr.bin/mail/aux.c 88150 2001-12-18 20:52:09Z mikeh $"; 4036285Sbrian#endif /* not lint */ 4153298Sbrian 4253298Sbrian#include "rcv.h" 4353298Sbrian#include "extern.h" 4453298Sbrian 4553298Sbrian/* 4636285Sbrian * Mail -- a mail program 47102500Sbrian * 4836285Sbrian * Auxiliary functions. 4936285Sbrian */ 5036285Sbrian 5136285Sbrianstatic char *save2str __P((char *, char *)); 5236345Sbrian 5336285Sbrian/* 5436285Sbrian * Return a pointer to a dynamic copy of the argument. 5536285Sbrian */ 5646686Sbrianchar * 5737009Sbriansavestr(str) 5836285Sbrian char *str; 5936285Sbrian{ 6036285Sbrian char *new; 6136285Sbrian int size = strlen(str) + 1; 6236285Sbrian 6336285Sbrian if ((new = salloc(size)) != NULL) 6436285Sbrian bcopy(str, new, size); 6536285Sbrian return (new); 6636285Sbrian} 6736285Sbrian 6836285Sbrian/* 6981634Sbrian * Make a copy of new argument incorporating old one. 7081634Sbrian */ 7136285Sbrianchar * 7236285Sbriansave2str(str, old) 7336285Sbrian char *str, *old; 7436285Sbrian{ 7536285Sbrian char *new; 7636285Sbrian int newsize = strlen(str) + 1; 7736285Sbrian int oldsize = old ? strlen(old) + 1 : 0; 7836285Sbrian 7943313Sbrian if ((new = salloc(newsize + oldsize)) != NULL) { 8043313Sbrian if (oldsize) { 8143313Sbrian bcopy(old, new, oldsize); 8281634Sbrian new[oldsize - 1] = ' '; 8381634Sbrian } 8436285Sbrian bcopy(str, new + oldsize, newsize); 8536285Sbrian } 8636285Sbrian return (new); 8736285Sbrian} 8846686Sbrian 8936285Sbrian/* 9036285Sbrian * Touch the named message by setting its MTOUCH flag. 9136285Sbrian * Touched messages have the effect of not being sent 9236285Sbrian * back to the system mailbox on exit. 9338174Sbrian */ 9436285Sbrianvoid 9540561Sbriantouch(mp) 9671657Sbrian struct message *mp; 9781697Sbrian{ 9893418Sbrian 9971971Sbrian mp->m_flag |= MTOUCH; 10075212Sbrian if ((mp->m_flag & MREAD) == 0) 10136285Sbrian mp->m_flag |= MREAD|MSTATUS; 10264670Sbrian} 10364670Sbrian 10436285Sbrian/* 10553684Sbrian * Test to see if the passed file name is a directory. 10653684Sbrian * Return true if it is. 10752942Sbrian */ 10836285Sbrianint 10936285Sbrianisdir(name) 11055146Sbrian char name[]; 11136285Sbrian{ 11236285Sbrian struct stat sbuf; 11336285Sbrian 11436285Sbrian if (stat(name, &sbuf) < 0) 11536285Sbrian return (0); 11636285Sbrian return (S_ISDIR(sbuf.st_mode)); 11736285Sbrian} 11836285Sbrian 11936285Sbrian/* 12036285Sbrian * Count the number of arguments in the given string raw list. 12136285Sbrian */ 12236285Sbrianint 12336285Sbrianargcount(argv) 12436285Sbrian char **argv; 12536285Sbrian{ 12636285Sbrian char **ap; 12736285Sbrian 12836285Sbrian for (ap = argv; *ap++ != NULL;) 12936285Sbrian ; 13036285Sbrian return (ap - argv - 1); 13136285Sbrian} 13271971Sbrian 13393418Sbrian/* 13471971Sbrian * Return the desired header line from the passed message 13571974Sbrian * pointer (or NULL if the desired header field is not available). 13636314Sbrian */ 13736285Sbrianchar * 13836285Sbrianhfield(field, mp) 13936285Sbrian const char *field; 14036285Sbrian struct message *mp; 14136285Sbrian{ 14236285Sbrian FILE *ibuf; 14336285Sbrian char linebuf[LINESIZE]; 14436285Sbrian int lc; 14536314Sbrian char *hfield; 14636285Sbrian char *colon, *oldhfield = NULL; 14736285Sbrian 14836285Sbrian ibuf = setinput(mp); 14981634Sbrian if ((lc = mp->m_lines - 1) < 0) 15081634Sbrian return (NULL); 15181634Sbrian if (readline(ibuf, linebuf, LINESIZE) < 0) 15281634Sbrian return (NULL); 15381634Sbrian while (lc > 0) { 15481634Sbrian if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0) 15581634Sbrian return (oldhfield); 15636285Sbrian if ((hfield = ishfield(linebuf, colon, field)) != NULL) 15736285Sbrian oldhfield = save2str(hfield, oldhfield); 15836285Sbrian } 15936285Sbrian return (oldhfield); 16036285Sbrian} 16136314Sbrian 16236285Sbrian/* 16336285Sbrian * Return the next header field found in the given message. 16436285Sbrian * Return >= 0 if something found, < 0 elsewise. 16536285Sbrian * "colon" is set to point to the colon in the header. 16636285Sbrian * Must deal with \ continuations & other such fraud. 167134789Sbrian */ 16836285Sbrianint 16936285Sbriangethfield(f, linebuf, rem, colon) 17036285Sbrian FILE *f; 17136285Sbrian char linebuf[]; 17236285Sbrian int rem; 17359084Sbrian char **colon; 17436285Sbrian{ 17536285Sbrian char line2[LINESIZE]; 17636285Sbrian char *cp, *cp2; 17759084Sbrian int c; 17859084Sbrian 17959084Sbrian for (;;) { 18059084Sbrian if (--rem < 0) 18159084Sbrian return (-1); 18259084Sbrian if ((c = readline(f, linebuf, LINESIZE)) <= 0) 18359084Sbrian return (-1); 18459084Sbrian for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':'; 18559084Sbrian cp++) 18659084Sbrian ; 18759084Sbrian if (*cp != ':' || cp == linebuf) 18859084Sbrian continue; 18959084Sbrian /* 19036285Sbrian * I guess we got a headline. 19159084Sbrian * Handle wraparounding 19236285Sbrian */ 19336285Sbrian *colon = cp; 19436285Sbrian cp = linebuf + c; 19598243Sbrian for (;;) { 19638544Sbrian while (--cp >= linebuf && (*cp == ' ' || *cp == '\t')) 19738544Sbrian ; 19838544Sbrian cp++; 19938544Sbrian if (rem <= 0) 20038544Sbrian break; 20138544Sbrian ungetc(c = getc(f), f); 20238544Sbrian if (c != ' ' && c != '\t') 20338544Sbrian break; 20438544Sbrian if ((c = readline(f, line2, LINESIZE)) < 0) 20538544Sbrian break; 20638544Sbrian rem--; 20738544Sbrian for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++) 20838544Sbrian ; 20938544Sbrian c -= cp2 - line2; 21038544Sbrian if (cp + c >= linebuf + LINESIZE - 2) 21138544Sbrian break; 21238544Sbrian *cp++ = ' '; 21338544Sbrian bcopy(cp2, cp, c); 21438544Sbrian cp += c; 21538544Sbrian } 21638544Sbrian *cp = 0; 21738544Sbrian return (rem); 21838544Sbrian } 21981634Sbrian /* NOTREACHED */ 22038544Sbrian} 22138544Sbrian 22238544Sbrian/* 22338544Sbrian * Check whether the passed line is a header line of 22436285Sbrian * the desired breed. Return the field body, or 0. 22536928Sbrian */ 22636928Sbrian 22736928Sbrianchar* 22836928Sbrianishfield(linebuf, colon, field) 22936928Sbrian char linebuf[]; 23036285Sbrian char *colon; 23196153Sbrian const char *field; 23236928Sbrian{ 23396153Sbrian char *cp = colon; 23496153Sbrian 23596153Sbrian *cp = 0; 23696153Sbrian if (strcasecmp(linebuf, field) != 0) { 23796153Sbrian *cp = ':'; 23896153Sbrian return (0); 23936928Sbrian } 24036928Sbrian *cp = ':'; 24162977Sbrian for (cp++; *cp == ' ' || *cp == '\t'; cp++) 24236928Sbrian ; 24336928Sbrian return (cp); 24438174Sbrian} 24536928Sbrian 24636928Sbrian/* 24736928Sbrian * Copy a string and lowercase the result. 24836928Sbrian * dsize: space left in buffer (including space for NULL) 24936928Sbrian */ 25036928Sbrianvoid 25136928Sbrianistrncpy(dest, src, dsize) 25236928Sbrian char *dest; 25349434Sbrian const char *src; 25449434Sbrian size_t dsize; 25549434Sbrian{ 25636928Sbrian 25796153Sbrian strlcpy(dest, src, dsize); 25896153Sbrian while (*dest) 25996153Sbrian *dest++ = tolower(*dest); 26096153Sbrian} 26196153Sbrian 26236928Sbrian/* 26396153Sbrian * The following code deals with input stacking to do source 26436928Sbrian * commands. All but the current file pointer are saved on 26536928Sbrian * the stack. 26636928Sbrian */ 26736285Sbrian 26836285Sbrianstatic int ssp; /* Top of file stack */ 26936285Sbrianstruct sstack { 27036285Sbrian FILE *s_file; /* File we were in. */ 27149434Sbrian int s_cond; /* Saved state of conditionals */ 27249434Sbrian int s_loading; /* Loading .mailrc, etc. */ 27349434Sbrian}; 27449978Sbrian#define SSTACK_SIZE 64 /* XXX was NOFILE. */ 27549434Sbrianstatic struct sstack sstack[SSTACK_SIZE]; 27636285Sbrian 27749434Sbrian/* 27836285Sbrian * Pushdown current input file and switch to a new one. 27936285Sbrian * Set the global flag "sourcing" so that others will realize 28036285Sbrian * that they are no longer reading from a tty (in all probability). 28136285Sbrian */ 28236928Sbrianint 28336928Sbriansource(arglist) 28436928Sbrian char **arglist; 28549434Sbrian{ 28681634Sbrian FILE *fi; 28781634Sbrian char *cp; 28881634Sbrian 28981634Sbrian if ((cp = expand(*arglist)) == NULL) 29096153Sbrian return (1); 29196153Sbrian if ((fi = Fopen(cp, "r")) == NULL) { 29296153Sbrian warn("%s", cp); 29398243Sbrian return (1); 29481634Sbrian } 29581634Sbrian if (ssp >= SSTACK_SIZE - 1) { 29681634Sbrian printf("Too much \"sourcing\" going on.\n"); 29736285Sbrian (void)Fclose(fi); 29879165Sbrian return (1); 29979165Sbrian } 30036285Sbrian sstack[ssp].s_file = input; 30136285Sbrian sstack[ssp].s_cond = cond; 30236285Sbrian sstack[ssp].s_loading = loading; 30336285Sbrian ssp++; 30436285Sbrian loading = 0; 30536285Sbrian cond = CANY; 30636285Sbrian input = fi; 30736285Sbrian sourcing++; 30849978Sbrian return (0); 30949434Sbrian} 31036928Sbrian 31136312Sbrian/* 31259070Sbrian * Pop the current input back to the previous level. 31336312Sbrian * Update the "sourcing" flag as appropriate. 31436285Sbrian */ 31536285Sbrianint 31636285Sbrianunstack() 31736285Sbrian{ 31881634Sbrian if (ssp <= 0) { 31981634Sbrian printf("\"Source\" stack over-pop.\n"); 32096153Sbrian sourcing = 0; 32196153Sbrian return (1); 32296153Sbrian } 32396153Sbrian (void)Fclose(input); 32481634Sbrian if (cond != CANY) 32581634Sbrian printf("Unmatched \"if\"\n"); 32681634Sbrian ssp--; 32781634Sbrian cond = sstack[ssp].s_cond; 32849434Sbrian loading = sstack[ssp].s_loading; 32959070Sbrian input = sstack[ssp].s_file; 33059070Sbrian if (ssp == 0) 33159070Sbrian sourcing = loading; 33259070Sbrian return (0); 33336928Sbrian} 33436285Sbrian 33559070Sbrian/* 33659070Sbrian * Touch the indicated file. 33759070Sbrian * This is nifty for the shell. 33859070Sbrian */ 33959070Sbrianvoid 34059070Sbrianalter(name) 34159070Sbrian char *name; 34259070Sbrian{ 34336312Sbrian struct stat sb; 34459070Sbrian struct timeval tv[2]; 34549434Sbrian 34636312Sbrian if (stat(name, &sb)) 34736928Sbrian return; 34836928Sbrian (void)gettimeofday(&tv[0], (struct timezone *)NULL); 34936928Sbrian tv[0].tv_sec++; 35037019Sbrian TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec); 35136928Sbrian (void)utimes(name, tv); 35236928Sbrian} 35359070Sbrian 35493422Sbrian/* 35559070Sbrian * Get sender's name from this message. If the message has 35681634Sbrian * a bunch of arpanet stuff in it, we may have to skin the name 35793422Sbrian * before returning it. 35893422Sbrian */ 35936285Sbrianchar * 36036285Sbriannameof(mp, reptype) 36136285Sbrian struct message *mp; 36236285Sbrian int reptype; 36336285Sbrian{ 36436285Sbrian char *cp, *cp2; 36536285Sbrian 36636285Sbrian cp = skin(name1(mp, reptype)); 36736285Sbrian if (reptype != 0 || charcount(cp, '!') < 2) 36893422Sbrian return (cp); 36936285Sbrian cp2 = strrchr(cp, '!'); 37036285Sbrian cp2--; 37136285Sbrian while (cp2 > cp && *cp2 != '!') 37236285Sbrian cp2--; 37336285Sbrian if (*cp2 == '!') 37481634Sbrian return (cp2 + 1); 37536285Sbrian return (cp); 37636285Sbrian} 37736285Sbrian 37859070Sbrian/* 37959070Sbrian * Start of a "comment". 38037060Sbrian * Ignore it. 38193422Sbrian */ 38236285Sbrianchar * 38336285Sbrianskip_comment(cp) 38436285Sbrian char *cp; 38536285Sbrian{ 38637007Sbrian int nesting = 1; 38736285Sbrian 38836285Sbrian for (; nesting > 0 && *cp; cp++) { 38936285Sbrian switch (*cp) { 39036285Sbrian case '\\': 39136285Sbrian if (cp[1]) 39236285Sbrian cp++; 39336285Sbrian break; 39436285Sbrian case '(': 39536285Sbrian nesting++; 39636285Sbrian break; 39736285Sbrian case ')': 39836285Sbrian nesting--; 39936285Sbrian break; 40036285Sbrian } 40136285Sbrian } 40236285Sbrian return (cp); 40336285Sbrian} 40436285Sbrian 40537007Sbrian/* 40637007Sbrian * Skin an arpa net address according to the RFC 822 interpretation 40737007Sbrian * of "host-phrase." 40871970Sbrian */ 40937007Sbrianchar * 41037007Sbrianskin(name) 41137007Sbrian char *name; 41237007Sbrian{ 41336285Sbrian char *nbuf, *bufend, *cp, *cp2; 41436285Sbrian int c, gotlt, lastsp; 41536285Sbrian 41636285Sbrian if (name == NULL) 41736285Sbrian return (NULL); 41836285Sbrian if (strchr(name, '(') == NULL && strchr(name, '<') == NULL 41936285Sbrian && strchr(name, ' ') == NULL) 42036285Sbrian return (name); 42136285Sbrian 42236285Sbrian /* We assume that length(input) <= length(output) */ 42396153Sbrian if ((nbuf = malloc(strlen(name) + 1)) == NULL) 42496153Sbrian err(1, "Out of memory"); 42596153Sbrian gotlt = 0; 42696153Sbrian lastsp = 0; 42736285Sbrian bufend = nbuf; 42881634Sbrian for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) { 42981634Sbrian switch (c) { 43036285Sbrian case '(': 43181634Sbrian cp = skip_comment(cp); 43293422Sbrian lastsp = 0; 43336285Sbrian break; 43437007Sbrian 43536285Sbrian case '"': 43636285Sbrian /* 43736285Sbrian * Start of a "quoted-string". 43837007Sbrian * Copy it in its entirety. 43936285Sbrian */ 44036285Sbrian while ((c = *cp) != '\0') { 44136285Sbrian cp++; 44237018Sbrian if (c == '"') 44336285Sbrian break; 44436285Sbrian if (c != '\\') 44536285Sbrian *cp2++ = c; 44636285Sbrian else if ((c = *cp) != '\0') { 44737018Sbrian *cp2++ = c; 44836285Sbrian cp++; 44936285Sbrian } 45036285Sbrian } 45158028Sbrian lastsp = 0; 45236285Sbrian break; 45336285Sbrian 45436285Sbrian case ' ': 45554912Sbrian if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ') 45661534Sbrian cp += 3, *cp2++ = '@'; 45754912Sbrian else 45836285Sbrian if (cp[0] == '@' && cp[1] == ' ') 45936285Sbrian cp += 2, *cp2++ = '@'; 46036285Sbrian else 46136285Sbrian lastsp = 1; 46236285Sbrian break; 46336285Sbrian 46436285Sbrian case '<': 46536285Sbrian cp2 = bufend; 46681634Sbrian gotlt++; 46781634Sbrian lastsp = 0; 46836285Sbrian break; 46936928Sbrian 47036928Sbrian case '>': 47136285Sbrian if (gotlt) { 47261534Sbrian gotlt = 0; 47361534Sbrian while ((c = *cp) != '\0' && c != ',') { 47436285Sbrian cp++; 47538544Sbrian if (c == '(') 47638544Sbrian cp = skip_comment(cp); 47736285Sbrian else if (c == '"') 47836285Sbrian while ((c = *cp) != '\0') { 47936285Sbrian cp++; 48036452Sbrian if (c == '"') 48136285Sbrian break; 48238544Sbrian if (c == '\\' && *cp != '\0') 48338544Sbrian cp++; 48438544Sbrian } 48538544Sbrian } 48638544Sbrian lastsp = 0; 48738544Sbrian break; 48836285Sbrian } 48936285Sbrian /* Fall into . . . */ 49036285Sbrian 49136285Sbrian default: 49243693Sbrian if (lastsp) { 49343693Sbrian lastsp = 0; 49443693Sbrian *cp2++ = ' '; 49543693Sbrian } 49636714Sbrian *cp2++ = c; 49736714Sbrian if (c == ',' && *cp == ' ' && !gotlt) { 49836714Sbrian *cp2++ = ' '; 49936714Sbrian while (*++cp == ' ') 50036285Sbrian ; 50136285Sbrian lastsp = 0; 50236285Sbrian bufend = cp2; 50358038Sbrian } 50436285Sbrian } 50536314Sbrian } 50636285Sbrian *cp2 = '\0'; 50736285Sbrian 50836285Sbrian if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL) 50936285Sbrian nbuf = cp; 51036285Sbrian return (nbuf); 51158028Sbrian} 51236285Sbrian 51336285Sbrian/* 51436285Sbrian * Fetch the sender's name from the passed message. 51536285Sbrian * Reptype can be 51636285Sbrian * 0 -- get sender's name for display purposes 51736285Sbrian * 1 -- get sender's name for reply 51836285Sbrian * 2 -- get sender's name for Reply 51936285Sbrian */ 52043693Sbrianchar * 52143693Sbrianname1(mp, reptype) 52243693Sbrian struct message *mp; 52343693Sbrian int reptype; 52443693Sbrian{ 52536285Sbrian char namebuf[LINESIZE]; 52636285Sbrian char linebuf[LINESIZE]; 52736285Sbrian char *cp, *cp2; 52836285Sbrian FILE *ibuf; 52936285Sbrian int first = 1; 53036285Sbrian 53136285Sbrian if ((cp = hfield("from", mp)) != NULL) 532134789Sbrian return (cp); 53336285Sbrian if (reptype == 0 && (cp = hfield("sender", mp)) != NULL) 53436285Sbrian return (cp); 53536285Sbrian ibuf = setinput(mp); 53662977Sbrian namebuf[0] = '\0'; 53781634Sbrian if (readline(ibuf, linebuf, LINESIZE) < 0) 53836285Sbrian return (savestr(namebuf)); 53936285Sbriannewname: 54036285Sbrian for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++) 54136285Sbrian ; 54236285Sbrian for (; *cp == ' ' || *cp == '\t'; cp++) 54336285Sbrian ; 54436285Sbrian for (cp2 = &namebuf[strlen(namebuf)]; 54536285Sbrian *cp != '\0' && *cp != ' ' && *cp != '\t' && 54643693Sbrian cp2 < namebuf + LINESIZE - 1;) 54743693Sbrian *cp2++ = *cp++; 54843693Sbrian *cp2 = '\0'; 54943693Sbrian if (readline(ibuf, linebuf, LINESIZE) < 0) 55043693Sbrian return (savestr(namebuf)); 55136285Sbrian if ((cp = strchr(linebuf, 'F')) == NULL) 55236285Sbrian return (savestr(namebuf)); 55336285Sbrian if (strncmp(cp, "From", 4) != 0) 55496043Sbrian return (savestr(namebuf)); 55556413Sbrian while ((cp = strchr(cp, 'r')) != NULL) { 55636285Sbrian if (strncmp(cp, "remote", 6) == 0) { 55756413Sbrian if ((cp = strchr(cp, 'f')) == NULL) 55896043Sbrian break; 55956413Sbrian if (strncmp(cp, "from", 4) != 0) 56056413Sbrian break; 56156413Sbrian if ((cp = strchr(cp, ' ')) == NULL) 56256413Sbrian break; 56356413Sbrian cp++; 56456413Sbrian if (first) { 56536285Sbrian cp2 = namebuf; 56656413Sbrian first = 0; 56756413Sbrian } else 56836285Sbrian cp2 = strrchr(namebuf, '!') + 1; 56956413Sbrian strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1); 57036285Sbrian strcat(namebuf, "!"); 57136285Sbrian goto newname; 57256413Sbrian } 57356413Sbrian cp++; 57456413Sbrian } 57556413Sbrian return (savestr(namebuf)); 57656413Sbrian} 57756413Sbrian 57856413Sbrian/* 57956413Sbrian * Count the occurances of c in str 58081634Sbrian */ 58181634Sbrianint 58281897Sbriancharcount(str, c) 58381634Sbrian char *str; 58481634Sbrian int c; 58581634Sbrian{ 58656413Sbrian char *cp; 58756413Sbrian int i; 58881634Sbrian 58981634Sbrian for (i = 0, cp = str; *cp != '\0'; cp++) 59036285Sbrian if (*cp == c) 59181634Sbrian i++; 59236285Sbrian return (i); 59336285Sbrian} 59436285Sbrian 59581634Sbrian/* 59681634Sbrian * See if the given header field is supposed to be ignored. 59736285Sbrian */ 59856413Sbrianint 59956413Sbrianisign(field, ignore) 60036285Sbrian const char *field; 60136285Sbrian struct ignoretab ignore[2]; 60236285Sbrian{ 60336285Sbrian char realfld[LINESIZE]; 60436285Sbrian 60536285Sbrian if (ignore == ignoreall) 60636285Sbrian return (1); 60736285Sbrian /* 60881634Sbrian * Lower-case the string, so that "Status" and "status" 60981634Sbrian * will hash to the same place. 61036285Sbrian */ 61136285Sbrian istrncpy(realfld, field, sizeof(realfld)); 61236285Sbrian if (ignore[1].i_count > 0) 61336285Sbrian return (!member(realfld, ignore + 1)); 61436285Sbrian else 61536285Sbrian return (member(realfld, ignore)); 61636285Sbrian} 61781634Sbrian 61881634Sbrianint 61962938Sbrianmember(realfield, table) 62037955Sbrian char *realfield; 62136285Sbrian struct ignoretab *table; 62236285Sbrian{ 62336285Sbrian struct ignore *igp; 62436285Sbrian 62598243Sbrian for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link) 62636285Sbrian if (*igp->i_field == *realfield && 62736285Sbrian equal(igp->i_field, realfield)) 62836285Sbrian return (1); 62936285Sbrian return (0); 63036285Sbrian} 63136285Sbrian