util.c revision 77274
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 496196Sdes * 596196Sdes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 796196Sdes * are met: 896196Sdes * 1. Redistributions of source code must retain the above copyright 996196Sdes * notice, this list of conditions and the following disclaimer. 1096196Sdes * 2. Redistributions in binary form must reproduce the above copyright 1196196Sdes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 351590Srgrimes#if 0 361590Srgrimesstatic char sccsid[] = "@(#)aux.c 8.1 (Berkeley) 6/6/93"; 371590Srgrimes#endif 381590Srgrimesstatic const char rcsid[] = 391590Srgrimes "$FreeBSD: head/usr.bin/mail/aux.c 77274 2001-05-27 20:26:22Z mikeh $"; 401590Srgrimes#endif /* not lint */ 411590Srgrimes 4227919Scharnier#include "rcv.h" 431590Srgrimes#include "extern.h" 441590Srgrimes 451590Srgrimes/* 461590Srgrimes * Mail -- a mail program 47105235Scharnier * 481590Srgrimes * Auxiliary functions. 4929922Smarkm */ 501590Srgrimes 51105235Scharnierstatic char *save2str __P((char *, char *)); 521590Srgrimes 53105235Scharnier/* 54105235Scharnier * Return a pointer to a dynamic copy of the argument. 55105235Scharnier */ 561590Srgrimeschar * 571590Srgrimessavestr(str) 581590Srgrimes char *str; 5995621Smarkm{ 601590Srgrimes char *new; 61120547Stjr int size = strlen(str) + 1; 621590Srgrimes 631590Srgrimes if ((new = salloc(size)) != NULL) 641590Srgrimes bcopy(str, new, size); 651590Srgrimes return (new); 661590Srgrimes} 671590Srgrimes 681590Srgrimes/* 691590Srgrimes * Make a copy of new argument incorporating old one. 708232Sdg */ 711590Srgrimeschar * 7227919Scharniersave2str(str, old) 731590Srgrimes char *str, *old; 741590Srgrimes{ 7540103Smarkm char *new; 761590Srgrimes int newsize = strlen(str) + 1; 7796197Sdes int oldsize = old ? strlen(old) + 1 : 0; 781590Srgrimes 791590Srgrimes if ((new = salloc(newsize + oldsize)) != NULL) { 80120547Stjr if (oldsize) { 811590Srgrimes bcopy(old, new, oldsize); 821590Srgrimes new[oldsize - 1] = ' '; 831590Srgrimes } 841590Srgrimes bcopy(str, new + oldsize, newsize); 851590Srgrimes } 861590Srgrimes return (new); 871590Srgrimes} 881590Srgrimes 891590Srgrimes/* 901590Srgrimes * Touch the named message by setting its MTOUCH flag. 911590Srgrimes * Touched messages have the effect of not being sent 921590Srgrimes * back to the system mailbox on exit. 931590Srgrimes */ 941590Srgrimesvoid 951590Srgrimestouch(mp) 96120547Stjr struct message *mp; 97120547Stjr{ 98120547Stjr 9957232Sshin mp->m_flag |= MTOUCH; 1001590Srgrimes if ((mp->m_flag & MREAD) == 0) 1011590Srgrimes mp->m_flag |= MREAD|MSTATUS; 1021590Srgrimes} 1031590Srgrimes 1041590Srgrimes/* 1051590Srgrimes * Test to see if the passed file name is a directory. 1061590Srgrimes * Return true if it is. 10792921Simp */ 10892921Simpint 10992921Simpisdir(name) 11092921Simp char name[]; 11192921Simp{ 112105268Smarkm struct stat sbuf; 11392921Simp 11492921Simp if (stat(name, &sbuf) < 0) 11595621Smarkm return (0); 11692921Simp return (S_ISDIR(sbuf.st_mode)); 11792921Simp} 11892921Simp 11992921Simp/* 12092921Simp * Count the number of arguments in the given string raw list. 12192921Simp */ 12292921Simpint 12392921Simpargcount(argv) 12492921Simp char **argv; 1251590Srgrimes{ 1261590Srgrimes char **ap; 12793057Simp 1281590Srgrimes for (ap = argv; *ap++ != NULL;) 1291590Srgrimes ; 1301590Srgrimes return (ap - argv - 1); 131120547Stjr} 1321590Srgrimes 133105268Smarkm/* 134105268Smarkm * Return the desired header line from the passed message 13547549Sbde * pointer (or NULL if the desired header field is not available). 136120547Stjr */ 13796196Sdeschar * 138148726Sstefanfhfield(field, mp) 139148726Sstefanf const char *field; 1401590Srgrimes struct message *mp; 1418232Sdg{ 1421590Srgrimes FILE *ibuf; 14347549Sbde char linebuf[LINESIZE]; 1441590Srgrimes int lc; 14529922Smarkm char *hfield; 1461590Srgrimes char *colon, *oldhfield = NULL; 1471590Srgrimes 1481590Srgrimes ibuf = setinput(mp); 1491590Srgrimes if ((lc = mp->m_lines - 1) < 0) 1501590Srgrimes return (NULL); 1511590Srgrimes if (readline(ibuf, linebuf, LINESIZE) < 0) 1521590Srgrimes return (NULL); 1531590Srgrimes while (lc > 0) { 1541590Srgrimes if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0) 1551590Srgrimes return (oldhfield); 1561590Srgrimes if ((hfield = ishfield(linebuf, colon, field)) != NULL) 1571590Srgrimes oldhfield = save2str(hfield, oldhfield); 1581590Srgrimes } 159140569Sru return (oldhfield); 16024360Simp} 1611590Srgrimes 16257232Sshin/* 16357232Sshin * Return the next header field found in the given message. 16457232Sshin * Return >= 0 if something found, < 0 elsewise. 16557232Sshin * "colon" is set to point to the colon in the header. 16657232Sshin * Must deal with \ continuations & other such fraud. 16757232Sshin */ 16857232Sshinint 16957232Sshingethfield(f, linebuf, rem, colon) 1701590Srgrimes FILE *f; 1711590Srgrimes char linebuf[]; 1721590Srgrimes int rem; 1738232Sdg char **colon; 1748232Sdg{ 1758232Sdg char line2[LINESIZE]; 1761590Srgrimes char *cp, *cp2; 1771590Srgrimes int c; 1781590Srgrimes 1791590Srgrimes for (;;) { 1801590Srgrimes if (--rem < 0) 1811590Srgrimes return (-1); 1821590Srgrimes if ((c = readline(f, linebuf, LINESIZE)) <= 0) 1831590Srgrimes return (-1); 1841590Srgrimes for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':'; 1851590Srgrimes cp++) 18647488Speter ; 18747549Sbde if (*cp != ':' || cp == linebuf) 18847549Sbde continue; 18947488Speter /* 19047488Speter * I guess we got a headline. 1911590Srgrimes * Handle wraparounding 1921590Srgrimes */ 1931590Srgrimes *colon = cp; 1941590Srgrimes cp = linebuf + c; 1951590Srgrimes for (;;) { 1961590Srgrimes while (--cp >= linebuf && (*cp == ' ' || *cp == '\t')) 1971590Srgrimes ; 1981590Srgrimes cp++; 1991590Srgrimes if (rem <= 0) 2001590Srgrimes break; 20134897Smarkm ungetc(c = getc(f), f); 2021590Srgrimes if (c != ' ' && c != '\t') 2031590Srgrimes break; 20434897Smarkm if ((c = readline(f, line2, LINESIZE)) < 0) 2051590Srgrimes break; 2061590Srgrimes rem--; 20727919Scharnier for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++) 20827919Scharnier ; 2091590Srgrimes c -= cp2 - line2; 2101590Srgrimes if (cp + c >= linebuf + LINESIZE - 2) 21147488Speter break; 21247488Speter *cp++ = ' '; 2131590Srgrimes bcopy(cp2, cp, c); 2141590Srgrimes cp += c; 215105268Smarkm } 2161590Srgrimes *cp = 0; 21727919Scharnier return (rem); 2181590Srgrimes } 219120547Stjr /* NOTREACHED */ 220120547Stjr} 221120547Stjr 222120547Stjr/* 223120547Stjr * Check whether the passed line is a header line of 224120547Stjr * the desired breed. Return the field body, or 0. 225120547Stjr */ 226120547Stjr 227120547Stjrchar* 2281590Srgrimesishfield(linebuf, colon, field) 2291590Srgrimes char linebuf[]; 2301590Srgrimes char *colon; 2311590Srgrimes const char *field; 2321590Srgrimes{ 2331590Srgrimes char *cp = colon; 2341590Srgrimes 2351590Srgrimes *cp = 0; 2361590Srgrimes if (strcasecmp(linebuf, field) != 0) { 2371590Srgrimes *cp = ':'; 2381590Srgrimes return (0); 2391590Srgrimes } 2401590Srgrimes *cp = ':'; 2411590Srgrimes for (cp++; *cp == ' ' || *cp == '\t'; cp++) 2421590Srgrimes ; 2431590Srgrimes return (cp); 24457232Sshin} 2451590Srgrimes 2461590Srgrimes/* 2471590Srgrimes * Copy a string and lowercase the result. 2481590Srgrimes * dsize: space left in buffer (including space for NULL) 2491590Srgrimes */ 2501590Srgrimesvoid 25127919Scharnieristrncpy(dest, src, dsize) 2528232Sdg char *dest; 2538232Sdg const char *src; 25427919Scharnier size_t dsize; 2558232Sdg{ 25656590Sshin 2571590Srgrimes strlcpy(dest, src, dsize); 25856590Sshin while (*dest) 25956590Sshin *dest++ = tolower(*dest); 26056590Sshin} 26156590Sshin 26256590Sshin/* 26356590Sshin * The following code deals with input stacking to do source 26456590Sshin * commands. All but the current file pointer are saved on 26556590Sshin * the stack. 2661590Srgrimes */ 2671590Srgrimes 2681590Srgrimesstatic int ssp; /* Top of file stack */ 2691590Srgrimesstruct sstack { 2701590Srgrimes FILE *s_file; /* File we were in. */ 2711590Srgrimes int s_cond; /* Saved state of conditionals */ 272120547Stjr int s_loading; /* Loading .mailrc, etc. */ 2731590Srgrimes}; 2741590Srgrimes#define SSTACK_SIZE 64 /* XXX was NOFILE. */ 27593057Simpstatic struct sstack sstack[SSTACK_SIZE]; 2761590Srgrimes 2771590Srgrimes/* 2781590Srgrimes * Pushdown current input file and switch to a new one. 2791590Srgrimes * Set the global flag "sourcing" so that others will realize 2801590Srgrimes * that they are no longer reading from a tty (in all probability). 281120547Stjr */ 2821590Srgrimesint 2831590Srgrimessource(arglist) 28427919Scharnier char **arglist; 2851590Srgrimes{ 2861590Srgrimes FILE *fi; 2871590Srgrimes char *cp; 2881590Srgrimes 289105235Scharnier if ((cp = expand(*arglist)) == NULL) 2901590Srgrimes return (1); 2911590Srgrimes if ((fi = Fopen(cp, "r")) == NULL) { 2921590Srgrimes warn("%s", cp); 293105235Scharnier return (1); 2941590Srgrimes } 2951590Srgrimes if (ssp >= SSTACK_SIZE - 1) { 2961590Srgrimes printf("Too much \"sourcing\" going on.\n"); 2971590Srgrimes (void)Fclose(fi); 2981590Srgrimes return (1); 2991590Srgrimes } 3001590Srgrimes sstack[ssp].s_file = input; 3011590Srgrimes sstack[ssp].s_cond = cond; 3021590Srgrimes sstack[ssp].s_loading = loading; 3031590Srgrimes ssp++; 3041590Srgrimes loading = 0; 3051590Srgrimes cond = CANY; 3061590Srgrimes input = fi; 307105235Scharnier sourcing++; 3081590Srgrimes return (0); 3091590Srgrimes} 3101590Srgrimes 3111590Srgrimes/* 3121590Srgrimes * Pop the current input back to the previous level. 31393057Simp * Update the "sourcing" flag as appropriate. 3141590Srgrimes */ 3151590Srgrimesint 3161590Srgrimesunstack() 3171590Srgrimes{ 3181590Srgrimes if (ssp <= 0) { 3191590Srgrimes printf("\"Source\" stack over-pop.\n"); 3201590Srgrimes sourcing = 0; 3211590Srgrimes return (1); 32218286Sbde } 32393057Simp (void)Fclose(input); 3241590Srgrimes if (cond != CANY) 3251590Srgrimes printf("Unmatched \"if\"\n"); 3261590Srgrimes ssp--; 3271590Srgrimes cond = sstack[ssp].s_cond; 3281590Srgrimes loading = sstack[ssp].s_loading; 3291590Srgrimes input = sstack[ssp].s_file; 3301590Srgrimes if (ssp == 0) 3311590Srgrimes sourcing = loading; 3321590Srgrimes return (0); 3331590Srgrimes} 3341590Srgrimes 3351590Srgrimes/* 3361590Srgrimes * Touch the indicated file. 3371590Srgrimes * This is nifty for the shell. 3381590Srgrimes */ 3391590Srgrimesvoid 3401590Srgrimesalter(name) 3411590Srgrimes char *name; 3421590Srgrimes{ 343105268Smarkm struct stat sb; 3441590Srgrimes struct timeval tv[2]; 34595621Smarkm 3461590Srgrimes if (stat(name, &sb)) 3471590Srgrimes return; 3481590Srgrimes tv[0].tv_sec = time((time_t *)0) + 1; 3491590Srgrimes tv[1].tv_sec = sb.st_mtime; 3501590Srgrimes tv[0].tv_usec = tv[1].tv_usec = 0; 3511590Srgrimes (void)utimes(name, tv); 3521590Srgrimes} 3531590Srgrimes 354105268Smarkm/* 3551590Srgrimes * Get sender's name from this message. If the message has 35695621Smarkm * a bunch of arpanet stuff in it, we may have to skin the name 3571590Srgrimes * before returning it. 35897788Smike */ 35997788Smikechar * 3601590Srgrimesnameof(mp, reptype) 3611590Srgrimes struct message *mp; 36297788Smike int reptype; 3631590Srgrimes{ 3641590Srgrimes char *cp, *cp2; 3651590Srgrimes 3661590Srgrimes cp = skin(name1(mp, reptype)); 36797788Smike if (reptype != 0 || charcount(cp, '!') < 2) 3681590Srgrimes return (cp); 3691590Srgrimes cp2 = strrchr(cp, '!'); 3701590Srgrimes cp2--; 3711590Srgrimes while (cp2 > cp && *cp2 != '!') 3721590Srgrimes cp2--; 3731590Srgrimes if (*cp2 == '!') 3741590Srgrimes return (cp2 + 1); 3751590Srgrimes return (cp); 3761590Srgrimes} 3771590Srgrimes 3781590Srgrimes/* 37993057Simp * Start of a "comment". 3801590Srgrimes * Ignore it. 38193057Simp */ 3821590Srgrimeschar * 3831590Srgrimesskip_comment(cp) 3841590Srgrimes char *cp; 3851590Srgrimes{ 3861590Srgrimes int nesting = 1; 3871590Srgrimes 3881590Srgrimes for (; nesting > 0 && *cp; cp++) { 3891590Srgrimes switch (*cp) { 3901590Srgrimes case '\\': 3911590Srgrimes if (cp[1]) 3921590Srgrimes cp++; 3931590Srgrimes break; 3941590Srgrimes case '(': 3951590Srgrimes nesting++; 3961590Srgrimes break; 3971590Srgrimes case ')': 3981590Srgrimes nesting--; 3991590Srgrimes break; 4001590Srgrimes } 4011590Srgrimes } 4021590Srgrimes return (cp); 4031590Srgrimes} 4041590Srgrimes 4051590Srgrimes/* 4061590Srgrimes * Skin an arpa net address according to the RFC 822 interpretation 4071590Srgrimes * of "host-phrase." 408120547Stjr */ 4091590Srgrimeschar * 4101590Srgrimesskin(name) 4111590Srgrimes char *name; 412120547Stjr{ 413120547Stjr char *nbuf, *bufend, *cp, *cp2; 4141590Srgrimes int c, gotlt, lastsp; 4151590Srgrimes 4161590Srgrimes if (name == NULL) 4171590Srgrimes return (NULL); 4181590Srgrimes if (strchr(name, '(') == NULL && strchr(name, '<') == NULL 4191590Srgrimes && strchr(name, ' ') == NULL) 420105268Smarkm return (name); 4211590Srgrimes 4221590Srgrimes /* We assume that length(input) <= length(output) */ 423105268Smarkm if ((nbuf = malloc(strlen(name) + 1)) == NULL) 424105268Smarkm err(1, "Out of memory"); 425105268Smarkm gotlt = 0; 426105268Smarkm lastsp = 0; 427120547Stjr bufend = nbuf; 428120547Stjr for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) { 429120547Stjr switch (c) { 430120547Stjr case '(': 4311590Srgrimes cp = skip_comment(cp); 4321590Srgrimes lastsp = 0; 4331590Srgrimes break; 4341590Srgrimes 4351590Srgrimes case '"': 43693057Simp /* 4371590Srgrimes * Start of a "quoted-string". 43893057Simp * Copy it in its entirety. 4391590Srgrimes */ 4401590Srgrimes while ((c = *cp) != '\0') { 4411590Srgrimes cp++; 4421590Srgrimes if (c == '"') 4431590Srgrimes break; 4441590Srgrimes if (c != '\\') 4451590Srgrimes *cp2++ = c; 4461590Srgrimes else if ((c = *cp) != '\0') { 4471590Srgrimes *cp2++ = c; 4481590Srgrimes cp++; 4491590Srgrimes } 4501590Srgrimes } 4511590Srgrimes lastsp = 0; 4521590Srgrimes break; 4531590Srgrimes 4541590Srgrimes case ' ': 4551590Srgrimes if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ') 4561590Srgrimes cp += 3, *cp2++ = '@'; 4571590Srgrimes else 4581590Srgrimes if (cp[0] == '@' && cp[1] == ' ') 4591590Srgrimes cp += 2, *cp2++ = '@'; 4601590Srgrimes else 4611590Srgrimes lastsp = 1; 462120547Stjr break; 4631590Srgrimes 4641590Srgrimes case '<': 4651590Srgrimes cp2 = bufend; 4661590Srgrimes gotlt++; 4671590Srgrimes lastsp = 0; 468105268Smarkm break; 4691590Srgrimes 47095621Smarkm case '>': 4711590Srgrimes if (gotlt) { 4721590Srgrimes gotlt = 0; 4731590Srgrimes while ((c = *cp) != '\0' && c != ',') { 4741590Srgrimes cp++; 4751590Srgrimes if (c == '(') 4761590Srgrimes cp = skip_comment(cp); 4771590Srgrimes else if (c == '"') 4781590Srgrimes while ((c = *cp) != '\0') { 4791590Srgrimes cp++; 4801590Srgrimes if (c == '"') 4811590Srgrimes break; 4821590Srgrimes if (c == '\\' && *cp != '\0') 4831590Srgrimes cp++; 4841590Srgrimes } 48593057Simp } 4861590Srgrimes lastsp = 0; 4871590Srgrimes break; 4881590Srgrimes } 4891590Srgrimes /* Fall into . . . */ 4901590Srgrimes 4911590Srgrimes default: 4921590Srgrimes if (lastsp) { 4931590Srgrimes lastsp = 0; 4941590Srgrimes *cp2++ = ' '; 4951590Srgrimes } 4961590Srgrimes *cp2++ = c; 4971590Srgrimes if (c == ',' && !gotlt) { 4981590Srgrimes *cp2++ = ' '; 4991590Srgrimes for (; *cp == ' '; cp++) 500105268Smarkm ; 5011590Srgrimes lastsp = 0; 5021590Srgrimes bufend = cp2; 5031590Srgrimes } 5041590Srgrimes } 5051590Srgrimes } 5061590Srgrimes *cp2 = '\0'; 5071590Srgrimes 5081590Srgrimes if ((nbuf = realloc(nbuf, strlen(nbuf) + 1)) == NULL) 5091590Srgrimes err(1, "Out of memory"); 510105268Smarkm return (nbuf); 511105268Smarkm} 5121590Srgrimes 5131590Srgrimes/* 514105268Smarkm * Fetch the sender's name from the passed message. 5151590Srgrimes * Reptype can be 51695621Smarkm * 0 -- get sender's name for display purposes 5171590Srgrimes * 1 -- get sender's name for reply 518120547Stjr * 2 -- get sender's name for Reply 519120547Stjr */ 5201590Srgrimeschar * 5211590Srgrimesname1(mp, reptype) 5221590Srgrimes struct message *mp; 5231590Srgrimes int reptype; 5241590Srgrimes{ 5251590Srgrimes char namebuf[LINESIZE]; 5261590Srgrimes char linebuf[LINESIZE]; 5271590Srgrimes char *cp, *cp2; 5281590Srgrimes FILE *ibuf; 5291590Srgrimes int first = 1; 5301590Srgrimes 53195621Smarkm if ((cp = hfield("from", mp)) != NULL) 5321590Srgrimes return (cp); 5331590Srgrimes if (reptype == 0 && (cp = hfield("sender", mp)) != NULL) 5341590Srgrimes return (cp); 5351590Srgrimes ibuf = setinput(mp); 5361590Srgrimes namebuf[0] = '\0'; 5371590Srgrimes if (readline(ibuf, linebuf, LINESIZE) < 0) 5381590Srgrimes return (savestr(namebuf)); 5391590Srgrimesnewname: 5401590Srgrimes for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++) 5411590Srgrimes ; 5421590Srgrimes for (; *cp == ' ' || *cp == '\t'; cp++) 5431590Srgrimes ; 5441590Srgrimes for (cp2 = &namebuf[strlen(namebuf)]; 5451590Srgrimes *cp != '\0' && *cp != ' ' && *cp != '\t' && 5461590Srgrimes cp2 < namebuf + LINESIZE - 1;) 5471590Srgrimes *cp2++ = *cp++; 5481590Srgrimes *cp2 = '\0'; 5491590Srgrimes if (readline(ibuf, linebuf, LINESIZE) < 0) 5501590Srgrimes return (savestr(namebuf)); 5511590Srgrimes if ((cp = strchr(linebuf, 'F')) == NULL) 552120547Stjr return (savestr(namebuf)); 553120547Stjr if (strncmp(cp, "From", 4) != 0) 554120547Stjr return (savestr(namebuf)); 5551590Srgrimes while ((cp = strchr(cp, 'r')) != NULL) { 5561590Srgrimes if (strncmp(cp, "remote", 6) == 0) { 557120547Stjr if ((cp = strchr(cp, 'f')) == NULL) 558120547Stjr break; 559120547Stjr if (strncmp(cp, "from", 4) != 0) 5601590Srgrimes break; 5611590Srgrimes if ((cp = strchr(cp, ' ')) == NULL) 562120547Stjr break; 5631590Srgrimes cp++; 5641590Srgrimes if (first) { 56527919Scharnier cp2 = namebuf; 5661590Srgrimes first = 0; 5671590Srgrimes } else 5681590Srgrimes cp2 = strrchr(namebuf, '!') + 1; 5691590Srgrimes strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1); 5701590Srgrimes strcat(namebuf, "!"); 5711590Srgrimes goto newname; 5721590Srgrimes } 5731590Srgrimes cp++; 5741590Srgrimes } 5751590Srgrimes return (savestr(namebuf)); 5761590Srgrimes} 5771590Srgrimes 5781590Srgrimes/* 5791590Srgrimes * Count the occurances of c in str 5801590Srgrimes */ 5811590Srgrimesint 5821590Srgrimescharcount(str, c) 5831590Srgrimes char *str; 5841590Srgrimes int c; 5851590Srgrimes{ 5861590Srgrimes char *cp; 5871590Srgrimes int i; 5881590Srgrimes 5891590Srgrimes for (i = 0, cp = str; *cp != '\0'; cp++) 5901590Srgrimes if (*cp == c) 5911590Srgrimes i++; 5921590Srgrimes return (i); 5931590Srgrimes} 5941590Srgrimes 5951590Srgrimes/* 5961590Srgrimes * See if the given header field is supposed to be ignored. 59793057Simp */ 5981590Srgrimesint 599105268Smarkmisign(field, ignore) 6001590Srgrimes const char *field; 601105268Smarkm struct ignoretab ignore[2]; 6021590Srgrimes{ 603105268Smarkm char realfld[LINESIZE]; 6041590Srgrimes 6051590Srgrimes if (ignore == ignoreall) 60691434Sfenner return (1); 6071590Srgrimes /* 6081590Srgrimes * Lower-case the string, so that "Status" and "status" 6091590Srgrimes * will hash to the same place. 6101590Srgrimes */ 6111590Srgrimes istrncpy(realfld, field, sizeof(realfld)); 6121590Srgrimes if (ignore[1].i_count > 0) 6131590Srgrimes return (!member(realfld, ignore + 1)); 6141590Srgrimes else 6151590Srgrimes return (member(realfld, ignore)); 6161590Srgrimes} 6171590Srgrimes 6181590Srgrimesint 6191590Srgrimesmember(realfield, table) 6201590Srgrimes char *realfield; 6211590Srgrimes struct ignoretab *table; 6221590Srgrimes{ 6231590Srgrimes struct ignore *igp; 6241590Srgrimes 6251590Srgrimes for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link) 6261590Srgrimes if (*igp->i_field == *realfield && 627105268Smarkm equal(igp->i_field, realfield)) 6281590Srgrimes return (1); 6291590Srgrimes return (0); 6301590Srgrimes} 6311590Srgrimes