11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3174769Smikeh#if 0 321590Srgrimesstatic char sccsid[] = "@(#)aux.c 8.1 (Berkeley) 6/6/93"; 3374769Smikeh#endif 341590Srgrimes#endif /* not lint */ 3599112Sobrien#include <sys/cdefs.h> 3699112Sobrien__FBSDID("$FreeBSD$"); 371590Srgrimes 3891227Sbde#include <sys/time.h> 3991227Sbde 401590Srgrimes#include "rcv.h" 411590Srgrimes#include "extern.h" 421590Srgrimes 431590Srgrimes/* 441590Srgrimes * Mail -- a mail program 451590Srgrimes * 461590Srgrimes * Auxiliary functions. 471590Srgrimes */ 481590Srgrimes 4992921Simpstatic char *save2str(char *, char *); 5077274Smikeh 511590Srgrimes/* 521590Srgrimes * Return a pointer to a dynamic copy of the argument. 531590Srgrimes */ 541590Srgrimeschar * 55216564Scharniersavestr(char *str) 561590Srgrimes{ 571590Srgrimes char *new; 581590Srgrimes int size = strlen(str) + 1; 591590Srgrimes 6077274Smikeh if ((new = salloc(size)) != NULL) 611590Srgrimes bcopy(str, new, size); 6277274Smikeh return (new); 631590Srgrimes} 641590Srgrimes 651590Srgrimes/* 661590Srgrimes * Make a copy of new argument incorporating old one. 671590Srgrimes */ 68173438Sddsstatic char * 69216564Scharniersave2str(char *str, char *old) 701590Srgrimes{ 711590Srgrimes char *new; 721590Srgrimes int newsize = strlen(str) + 1; 731590Srgrimes int oldsize = old ? strlen(old) + 1 : 0; 741590Srgrimes 7577274Smikeh if ((new = salloc(newsize + oldsize)) != NULL) { 761590Srgrimes if (oldsize) { 771590Srgrimes bcopy(old, new, oldsize); 781590Srgrimes new[oldsize - 1] = ' '; 791590Srgrimes } 801590Srgrimes bcopy(str, new + oldsize, newsize); 811590Srgrimes } 8277274Smikeh return (new); 831590Srgrimes} 841590Srgrimes 851590Srgrimes/* 861590Srgrimes * Touch the named message by setting its MTOUCH flag. 871590Srgrimes * Touched messages have the effect of not being sent 881590Srgrimes * back to the system mailbox on exit. 891590Srgrimes */ 901590Srgrimesvoid 91216564Scharniertouch(struct message *mp) 921590Srgrimes{ 931590Srgrimes 941590Srgrimes mp->m_flag |= MTOUCH; 951590Srgrimes if ((mp->m_flag & MREAD) == 0) 961590Srgrimes mp->m_flag |= MREAD|MSTATUS; 971590Srgrimes} 981590Srgrimes 991590Srgrimes/* 1001590Srgrimes * Test to see if the passed file name is a directory. 1011590Srgrimes * Return true if it is. 1021590Srgrimes */ 1031590Srgrimesint 104216564Scharnierisdir(char name[]) 1051590Srgrimes{ 1061590Srgrimes struct stat sbuf; 1071590Srgrimes 1081590Srgrimes if (stat(name, &sbuf) < 0) 10977274Smikeh return (0); 11077274Smikeh return (S_ISDIR(sbuf.st_mode)); 1111590Srgrimes} 1121590Srgrimes 1131590Srgrimes/* 1141590Srgrimes * Count the number of arguments in the given string raw list. 1151590Srgrimes */ 1161590Srgrimesint 117216564Scharnierargcount(char **argv) 1181590Srgrimes{ 11977274Smikeh char **ap; 1201590Srgrimes 12177274Smikeh for (ap = argv; *ap++ != NULL;) 1228874Srgrimes ; 12377274Smikeh return (ap - argv - 1); 1241590Srgrimes} 1251590Srgrimes 1261590Srgrimes/* 1271590Srgrimes * Return the desired header line from the passed message 12877274Smikeh * pointer (or NULL if the desired header field is not available). 1291590Srgrimes */ 1301590Srgrimeschar * 131216564Scharnierhfield(const char *field, struct message *mp) 1321590Srgrimes{ 13377274Smikeh FILE *ibuf; 1341590Srgrimes char linebuf[LINESIZE]; 13577274Smikeh int lc; 13677274Smikeh char *hfield; 13777274Smikeh char *colon, *oldhfield = NULL; 1381590Srgrimes 1391590Srgrimes ibuf = setinput(mp); 1401590Srgrimes if ((lc = mp->m_lines - 1) < 0) 14177274Smikeh return (NULL); 1421590Srgrimes if (readline(ibuf, linebuf, LINESIZE) < 0) 14377274Smikeh return (NULL); 1441590Srgrimes while (lc > 0) { 1451590Srgrimes if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0) 14677274Smikeh return (oldhfield); 14727643Scharnier if ((hfield = ishfield(linebuf, colon, field)) != NULL) 1481590Srgrimes oldhfield = save2str(hfield, oldhfield); 1491590Srgrimes } 15077274Smikeh return (oldhfield); 1511590Srgrimes} 1521590Srgrimes 1531590Srgrimes/* 1541590Srgrimes * Return the next header field found in the given message. 1551590Srgrimes * Return >= 0 if something found, < 0 elsewise. 1561590Srgrimes * "colon" is set to point to the colon in the header. 1571590Srgrimes * Must deal with \ continuations & other such fraud. 1581590Srgrimes */ 1591590Srgrimesint 160216564Scharniergethfield(FILE *f, char linebuf[], int rem, char **colon) 1611590Srgrimes{ 1621590Srgrimes char line2[LINESIZE]; 16377274Smikeh char *cp, *cp2; 16477274Smikeh int c; 1651590Srgrimes 1661590Srgrimes for (;;) { 1671590Srgrimes if (--rem < 0) 16877274Smikeh return (-1); 1691590Srgrimes if ((c = readline(f, linebuf, LINESIZE)) <= 0) 17077274Smikeh return (-1); 17188227Sache for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':'; 17277274Smikeh cp++) 1731590Srgrimes ; 1741590Srgrimes if (*cp != ':' || cp == linebuf) 1751590Srgrimes continue; 1761590Srgrimes /* 1771590Srgrimes * I guess we got a headline. 1781590Srgrimes * Handle wraparounding 1791590Srgrimes */ 1801590Srgrimes *colon = cp; 1811590Srgrimes cp = linebuf + c; 1821590Srgrimes for (;;) { 1831590Srgrimes while (--cp >= linebuf && (*cp == ' ' || *cp == '\t')) 1841590Srgrimes ; 1851590Srgrimes cp++; 1861590Srgrimes if (rem <= 0) 1871590Srgrimes break; 1881590Srgrimes ungetc(c = getc(f), f); 1891590Srgrimes if (c != ' ' && c != '\t') 1901590Srgrimes break; 1911590Srgrimes if ((c = readline(f, line2, LINESIZE)) < 0) 1921590Srgrimes break; 1931590Srgrimes rem--; 1941590Srgrimes for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++) 1951590Srgrimes ; 1961590Srgrimes c -= cp2 - line2; 1971590Srgrimes if (cp + c >= linebuf + LINESIZE - 2) 1981590Srgrimes break; 1991590Srgrimes *cp++ = ' '; 2001590Srgrimes bcopy(cp2, cp, c); 2011590Srgrimes cp += c; 2021590Srgrimes } 2031590Srgrimes *cp = 0; 20477274Smikeh return (rem); 2051590Srgrimes } 2061590Srgrimes /* NOTREACHED */ 2071590Srgrimes} 2081590Srgrimes 2091590Srgrimes/* 2101590Srgrimes * Check whether the passed line is a header line of 2111590Srgrimes * the desired breed. Return the field body, or 0. 2121590Srgrimes */ 2131590Srgrimes 2141590Srgrimeschar* 215216564Scharnierishfield(char linebuf[], char *colon, const char *field) 2161590Srgrimes{ 21777274Smikeh char *cp = colon; 2181590Srgrimes 2191590Srgrimes *cp = 0; 2201590Srgrimes if (strcasecmp(linebuf, field) != 0) { 2211590Srgrimes *cp = ':'; 22277274Smikeh return (0); 2231590Srgrimes } 2241590Srgrimes *cp = ':'; 2251590Srgrimes for (cp++; *cp == ' ' || *cp == '\t'; cp++) 2261590Srgrimes ; 22777274Smikeh return (cp); 2281590Srgrimes} 2291590Srgrimes 2301590Srgrimes/* 23174769Smikeh * Copy a string and lowercase the result. 23274769Smikeh * dsize: space left in buffer (including space for NULL) 2331590Srgrimes */ 2341590Srgrimesvoid 235216564Scharnieristrncpy(char *dest, const char *src, size_t dsize) 2361590Srgrimes{ 2371590Srgrimes 23874769Smikeh strlcpy(dest, src, dsize); 239246860Sdim for (; *dest; dest++) 240246860Sdim *dest = tolower((unsigned char)*dest); 2411590Srgrimes} 2421590Srgrimes 2431590Srgrimes/* 2441590Srgrimes * The following code deals with input stacking to do source 2451590Srgrimes * commands. All but the current file pointer are saved on 2461590Srgrimes * the stack. 2471590Srgrimes */ 2481590Srgrimes 2491590Srgrimesstatic int ssp; /* Top of file stack */ 2501590Srgrimesstruct sstack { 2511590Srgrimes FILE *s_file; /* File we were in. */ 2521590Srgrimes int s_cond; /* Saved state of conditionals */ 2531590Srgrimes int s_loading; /* Loading .mailrc, etc. */ 25418532Sbde}; 25518532Sbde#define SSTACK_SIZE 64 /* XXX was NOFILE. */ 25618532Sbdestatic struct sstack sstack[SSTACK_SIZE]; 2571590Srgrimes 2581590Srgrimes/* 2591590Srgrimes * Pushdown current input file and switch to a new one. 2601590Srgrimes * Set the global flag "sourcing" so that others will realize 2611590Srgrimes * that they are no longer reading from a tty (in all probability). 2621590Srgrimes */ 2631590Srgrimesint 264216564Scharniersource(char **arglist) 2651590Srgrimes{ 2661590Srgrimes FILE *fi; 2671590Srgrimes char *cp; 2681590Srgrimes 26977274Smikeh if ((cp = expand(*arglist)) == NULL) 27077274Smikeh return (1); 2711590Srgrimes if ((fi = Fopen(cp, "r")) == NULL) { 27274769Smikeh warn("%s", cp); 27377274Smikeh return (1); 2741590Srgrimes } 27518532Sbde if (ssp >= SSTACK_SIZE - 1) { 2761590Srgrimes printf("Too much \"sourcing\" going on.\n"); 27777274Smikeh (void)Fclose(fi); 27877274Smikeh return (1); 2791590Srgrimes } 2801590Srgrimes sstack[ssp].s_file = input; 2811590Srgrimes sstack[ssp].s_cond = cond; 2821590Srgrimes sstack[ssp].s_loading = loading; 2831590Srgrimes ssp++; 2841590Srgrimes loading = 0; 2851590Srgrimes cond = CANY; 2861590Srgrimes input = fi; 2871590Srgrimes sourcing++; 28877274Smikeh return (0); 2891590Srgrimes} 2901590Srgrimes 2911590Srgrimes/* 2921590Srgrimes * Pop the current input back to the previous level. 2931590Srgrimes * Update the "sourcing" flag as appropriate. 2941590Srgrimes */ 2951590Srgrimesint 296216564Scharnierunstack(void) 2971590Srgrimes{ 2981590Srgrimes if (ssp <= 0) { 2991590Srgrimes printf("\"Source\" stack over-pop.\n"); 3001590Srgrimes sourcing = 0; 30177274Smikeh return (1); 3021590Srgrimes } 30377274Smikeh (void)Fclose(input); 3041590Srgrimes if (cond != CANY) 3051590Srgrimes printf("Unmatched \"if\"\n"); 3061590Srgrimes ssp--; 3071590Srgrimes cond = sstack[ssp].s_cond; 3081590Srgrimes loading = sstack[ssp].s_loading; 3091590Srgrimes input = sstack[ssp].s_file; 3101590Srgrimes if (ssp == 0) 3111590Srgrimes sourcing = loading; 31277274Smikeh return (0); 3131590Srgrimes} 3141590Srgrimes 3151590Srgrimes/* 3161590Srgrimes * Touch the indicated file. 3171590Srgrimes * This is nifty for the shell. 3181590Srgrimes */ 3191590Srgrimesvoid 320216564Scharnieralter(char *name) 3211590Srgrimes{ 3221590Srgrimes struct stat sb; 3231590Srgrimes struct timeval tv[2]; 3241590Srgrimes 3251590Srgrimes if (stat(name, &sb)) 3261590Srgrimes return; 327239991Sed (void)gettimeofday(&tv[0], NULL); 32888150Smikeh tv[0].tv_sec++; 329205793Sed TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtim); 3301590Srgrimes (void)utimes(name, tv); 3311590Srgrimes} 3321590Srgrimes 3331590Srgrimes/* 3341590Srgrimes * Get sender's name from this message. If the message has 3351590Srgrimes * a bunch of arpanet stuff in it, we may have to skin the name 3361590Srgrimes * before returning it. 3371590Srgrimes */ 3381590Srgrimeschar * 339216564Scharniernameof(struct message *mp, int reptype) 3401590Srgrimes{ 34177274Smikeh char *cp, *cp2; 3421590Srgrimes 3431590Srgrimes cp = skin(name1(mp, reptype)); 3441590Srgrimes if (reptype != 0 || charcount(cp, '!') < 2) 34577274Smikeh return (cp); 34674769Smikeh cp2 = strrchr(cp, '!'); 3471590Srgrimes cp2--; 3481590Srgrimes while (cp2 > cp && *cp2 != '!') 3491590Srgrimes cp2--; 3501590Srgrimes if (*cp2 == '!') 35177274Smikeh return (cp2 + 1); 35277274Smikeh return (cp); 3531590Srgrimes} 3541590Srgrimes 3551590Srgrimes/* 3561590Srgrimes * Start of a "comment". 3571590Srgrimes * Ignore it. 3581590Srgrimes */ 3591590Srgrimeschar * 360216564Scharnierskip_comment(char *cp) 3611590Srgrimes{ 36277274Smikeh int nesting = 1; 3631590Srgrimes 3641590Srgrimes for (; nesting > 0 && *cp; cp++) { 3651590Srgrimes switch (*cp) { 3661590Srgrimes case '\\': 3671590Srgrimes if (cp[1]) 3681590Srgrimes cp++; 3691590Srgrimes break; 3701590Srgrimes case '(': 3711590Srgrimes nesting++; 3721590Srgrimes break; 3731590Srgrimes case ')': 3741590Srgrimes nesting--; 3751590Srgrimes break; 3761590Srgrimes } 3771590Srgrimes } 37877274Smikeh return (cp); 3791590Srgrimes} 3801590Srgrimes 3811590Srgrimes/* 3821590Srgrimes * Skin an arpa net address according to the RFC 822 interpretation 3831590Srgrimes * of "host-phrase." 3841590Srgrimes */ 3851590Srgrimeschar * 386216564Scharnierskin(char *name) 3871590Srgrimes{ 38877274Smikeh char *nbuf, *bufend, *cp, *cp2; 38977274Smikeh int c, gotlt, lastsp; 3901590Srgrimes 39177274Smikeh if (name == NULL) 39277274Smikeh return (NULL); 39377274Smikeh if (strchr(name, '(') == NULL && strchr(name, '<') == NULL 39477274Smikeh && strchr(name, ' ') == NULL) 39577274Smikeh return (name); 39674769Smikeh 39774769Smikeh /* We assume that length(input) <= length(output) */ 39877274Smikeh if ((nbuf = malloc(strlen(name) + 1)) == NULL) 39974769Smikeh err(1, "Out of memory"); 4001590Srgrimes gotlt = 0; 4011590Srgrimes lastsp = 0; 4021590Srgrimes bufend = nbuf; 40377274Smikeh for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) { 4041590Srgrimes switch (c) { 4051590Srgrimes case '(': 4061590Srgrimes cp = skip_comment(cp); 4071590Srgrimes lastsp = 0; 4081590Srgrimes break; 4091590Srgrimes 4101590Srgrimes case '"': 4111590Srgrimes /* 4121590Srgrimes * Start of a "quoted-string". 4131590Srgrimes * Copy it in its entirety. 4141590Srgrimes */ 41577274Smikeh while ((c = *cp) != '\0') { 4161590Srgrimes cp++; 4171590Srgrimes if (c == '"') 4181590Srgrimes break; 4191590Srgrimes if (c != '\\') 4201590Srgrimes *cp2++ = c; 42177274Smikeh else if ((c = *cp) != '\0') { 4221590Srgrimes *cp2++ = c; 4231590Srgrimes cp++; 4241590Srgrimes } 4251590Srgrimes } 4261590Srgrimes lastsp = 0; 4271590Srgrimes break; 4281590Srgrimes 4291590Srgrimes case ' ': 4301590Srgrimes if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ') 4311590Srgrimes cp += 3, *cp2++ = '@'; 4321590Srgrimes else 4331590Srgrimes if (cp[0] == '@' && cp[1] == ' ') 4341590Srgrimes cp += 2, *cp2++ = '@'; 4351590Srgrimes else 4361590Srgrimes lastsp = 1; 4371590Srgrimes break; 4381590Srgrimes 4391590Srgrimes case '<': 4401590Srgrimes cp2 = bufend; 4411590Srgrimes gotlt++; 4421590Srgrimes lastsp = 0; 4431590Srgrimes break; 4441590Srgrimes 4451590Srgrimes case '>': 4461590Srgrimes if (gotlt) { 4471590Srgrimes gotlt = 0; 44877274Smikeh while ((c = *cp) != '\0' && c != ',') { 4491590Srgrimes cp++; 4501590Srgrimes if (c == '(') 4511590Srgrimes cp = skip_comment(cp); 4521590Srgrimes else if (c == '"') 45377274Smikeh while ((c = *cp) != '\0') { 4541590Srgrimes cp++; 4551590Srgrimes if (c == '"') 4561590Srgrimes break; 45777274Smikeh if (c == '\\' && *cp != '\0') 4581590Srgrimes cp++; 4591590Srgrimes } 4601590Srgrimes } 4611590Srgrimes lastsp = 0; 4621590Srgrimes break; 4631590Srgrimes } 464102412Scharnier /* FALLTHROUGH */ 4651590Srgrimes 4661590Srgrimes default: 4671590Srgrimes if (lastsp) { 4681590Srgrimes lastsp = 0; 4691590Srgrimes *cp2++ = ' '; 4701590Srgrimes } 4711590Srgrimes *cp2++ = c; 472208592Suqs if (c == ',' && !gotlt && 473208592Suqs (*cp == ' ' || *cp == '"' || *cp == '<')) { 4741590Srgrimes *cp2++ = ' '; 475208592Suqs while (*cp == ' ') 476208592Suqs cp++; 4771590Srgrimes lastsp = 0; 4781590Srgrimes bufend = cp2; 4791590Srgrimes } 4801590Srgrimes } 4811590Srgrimes } 48277274Smikeh *cp2 = '\0'; 4831590Srgrimes 48483848Smikeh if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL) 48583848Smikeh nbuf = cp; 48677274Smikeh return (nbuf); 4871590Srgrimes} 4881590Srgrimes 4891590Srgrimes/* 4901590Srgrimes * Fetch the sender's name from the passed message. 4911590Srgrimes * Reptype can be 4921590Srgrimes * 0 -- get sender's name for display purposes 4931590Srgrimes * 1 -- get sender's name for reply 4941590Srgrimes * 2 -- get sender's name for Reply 4951590Srgrimes */ 4961590Srgrimeschar * 497216564Scharniername1(struct message *mp, int reptype) 4981590Srgrimes{ 4991590Srgrimes char namebuf[LINESIZE]; 5001590Srgrimes char linebuf[LINESIZE]; 50177274Smikeh char *cp, *cp2; 50277274Smikeh FILE *ibuf; 5031590Srgrimes int first = 1; 5041590Srgrimes 50577274Smikeh if ((cp = hfield("from", mp)) != NULL) 50677274Smikeh return (cp); 50777274Smikeh if (reptype == 0 && (cp = hfield("sender", mp)) != NULL) 50877274Smikeh return (cp); 5091590Srgrimes ibuf = setinput(mp); 51027643Scharnier namebuf[0] = '\0'; 5111590Srgrimes if (readline(ibuf, linebuf, LINESIZE) < 0) 51277274Smikeh return (savestr(namebuf)); 5131590Srgrimesnewname: 51477274Smikeh for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++) 5151590Srgrimes ; 5161590Srgrimes for (; *cp == ' ' || *cp == '\t'; cp++) 5171590Srgrimes ; 5181590Srgrimes for (cp2 = &namebuf[strlen(namebuf)]; 51977274Smikeh *cp != '\0' && *cp != ' ' && *cp != '\t' && 52077274Smikeh cp2 < namebuf + LINESIZE - 1;) 5211590Srgrimes *cp2++ = *cp++; 5221590Srgrimes *cp2 = '\0'; 5231590Srgrimes if (readline(ibuf, linebuf, LINESIZE) < 0) 52477274Smikeh return (savestr(namebuf)); 52574769Smikeh if ((cp = strchr(linebuf, 'F')) == NULL) 52677274Smikeh return (savestr(namebuf)); 5271590Srgrimes if (strncmp(cp, "From", 4) != 0) 52877274Smikeh return (savestr(namebuf)); 52974769Smikeh while ((cp = strchr(cp, 'r')) != NULL) { 5301590Srgrimes if (strncmp(cp, "remote", 6) == 0) { 53174769Smikeh if ((cp = strchr(cp, 'f')) == NULL) 5321590Srgrimes break; 5331590Srgrimes if (strncmp(cp, "from", 4) != 0) 5341590Srgrimes break; 53574769Smikeh if ((cp = strchr(cp, ' ')) == NULL) 5361590Srgrimes break; 5371590Srgrimes cp++; 5381590Srgrimes if (first) { 53974769Smikeh cp2 = namebuf; 5401590Srgrimes first = 0; 5411590Srgrimes } else 54274769Smikeh cp2 = strrchr(namebuf, '!') + 1; 54374769Smikeh strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1); 5441590Srgrimes strcat(namebuf, "!"); 5451590Srgrimes goto newname; 5461590Srgrimes } 5471590Srgrimes cp++; 5481590Srgrimes } 54977274Smikeh return (savestr(namebuf)); 5501590Srgrimes} 5511590Srgrimes 5521590Srgrimes/* 553229655Suqs * Count the occurrences of c in str 5541590Srgrimes */ 5551590Srgrimesint 556216564Scharniercharcount(char *str, int c) 5571590Srgrimes{ 55877274Smikeh char *cp; 55977274Smikeh int i; 5601590Srgrimes 56177274Smikeh for (i = 0, cp = str; *cp != '\0'; cp++) 5621590Srgrimes if (*cp == c) 5631590Srgrimes i++; 56477274Smikeh return (i); 5651590Srgrimes} 5661590Srgrimes 5671590Srgrimes/* 5681590Srgrimes * See if the given header field is supposed to be ignored. 5691590Srgrimes */ 5701590Srgrimesint 571216564Scharnierisign(const char *field, struct ignoretab ignore[2]) 5721590Srgrimes{ 57374769Smikeh char realfld[LINESIZE]; 5741590Srgrimes 5751590Srgrimes if (ignore == ignoreall) 57677274Smikeh return (1); 5771590Srgrimes /* 5781590Srgrimes * Lower-case the string, so that "Status" and "status" 5791590Srgrimes * will hash to the same place. 5801590Srgrimes */ 58174769Smikeh istrncpy(realfld, field, sizeof(realfld)); 5821590Srgrimes if (ignore[1].i_count > 0) 5831590Srgrimes return (!member(realfld, ignore + 1)); 5841590Srgrimes else 5851590Srgrimes return (member(realfld, ignore)); 5861590Srgrimes} 5871590Srgrimes 5881590Srgrimesint 589216564Scharniermember(char *realfield, struct ignoretab *table) 5901590Srgrimes{ 59177274Smikeh struct ignore *igp; 5921590Srgrimes 59377274Smikeh for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link) 5941590Srgrimes if (*igp->i_field == *realfield && 5951590Srgrimes equal(igp->i_field, realfield)) 5961590Srgrimes return (1); 5971590Srgrimes return (0); 5981590Srgrimes} 599