util.c revision 99112
1139823Simp/* 221259Swollman * Copyright (c) 1980, 1993 321259Swollman * The Regents of the University of California. All rights reserved. 421259Swollman * 521259Swollman * Redistribution and use in source and binary forms, with or without 621259Swollman * modification, are permitted provided that the following conditions 721259Swollman * are met: 821259Swollman * 1. Redistributions of source code must retain the above copyright 921259Swollman * notice, this list of conditions and the following disclaimer. 1021259Swollman * 2. Redistributions in binary form must reproduce the above copyright 1121259Swollman * notice, this list of conditions and the following disclaimer in the 1221259Swollman * documentation and/or other materials provided with the distribution. 1321259Swollman * 3. All advertising materials mentioning features or use of this software 1421259Swollman * must display the following acknowledgement: 1521259Swollman * This product includes software developed by the University of 1621259Swollman * California, Berkeley and its contributors. 1721259Swollman * 4. Neither the name of the University nor the names of its contributors 1821259Swollman * may be used to endorse or promote products derived from this software 1921259Swollman * without specific prior written permission. 2021259Swollman * 2121259Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2221259Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2321259Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2421259Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2521259Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2621259Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2721259Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2821259Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2921259Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3050477Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3121259Swollman * SUCH DAMAGE. 3221259Swollman */ 3321259Swollman 3421259Swollman#ifndef lint 3521259Swollman#if 0 3621259Swollmanstatic char sccsid[] = "@(#)aux.c 8.1 (Berkeley) 6/6/93"; 3721259Swollman#endif 3821259Swollman#endif /* not lint */ 3921259Swollman#include <sys/cdefs.h> 4021259Swollman__FBSDID("$FreeBSD: head/usr.bin/mail/aux.c 99112 2002-06-30 05:25:07Z obrien $"); 4121259Swollman 4221259Swollman#include <sys/time.h> 4321259Swollman 4421259Swollman#include "rcv.h" 4521259Swollman#include "extern.h" 4621259Swollman 4721259Swollman/* 4821259Swollman * Mail -- a mail program 4921259Swollman * 5021259Swollman * Auxiliary functions. 51108533Sschweikh */ 5221259Swollman 5321259Swollmanstatic char *save2str(char *, char *); 5421259Swollman 5521259Swollman/* 56108533Sschweikh * Return a pointer to a dynamic copy of the argument. 5721259Swollman */ 5821259Swollmanchar * 5921259Swollmansavestr(str) 6021259Swollman char *str; 6121259Swollman{ 6221259Swollman char *new; 6321259Swollman int size = strlen(str) + 1; 6421259Swollman 6521259Swollman if ((new = salloc(size)) != NULL) 6683366Sjulian bcopy(str, new, size); 6721259Swollman return (new); 6885074Sru} 6921259Swollman 7021259Swollman/* 71142215Sglebius * Make a copy of new argument incorporating old one. 72155051Sglebius */ 73191148Skmacychar * 7421259Swollmansave2str(str, old) 7521259Swollman char *str, *old; 7621259Swollman{ 7721259Swollman char *new; 7869224Sjlemon int newsize = strlen(str) + 1; 7969152Sjlemon int oldsize = old ? strlen(old) + 1 : 0; 80126264Smlaier 81186207Skmacy if ((new = salloc(newsize + oldsize)) != NULL) { 8269224Sjlemon if (oldsize) { 8374914Sjhb bcopy(old, new, oldsize); 8474914Sjhb new[oldsize - 1] = ' '; 85186199Skmacy } 8683130Sjlemon bcopy(str, new + oldsize, newsize); 87132712Srwatson } 8869152Sjlemon return (new); 89121816Sbrooks} 90121816Sbrooks 91130416Smlaier/* 92130416Smlaier * Touch the named message by setting its MTOUCH flag. 9360938Sjake * Touched messages have the effect of not being sent 9460938Sjake * back to the system mailbox on exit. 9560938Sjake */ 9672084Sphkvoid 97159781Smlaiertouch(mp) 9821259Swollman struct message *mp; 9921259Swollman{ 10021259Swollman 10121259Swollman mp->m_flag |= MTOUCH; 10221259Swollman if ((mp->m_flag & MREAD) == 0) 10321259Swollman mp->m_flag |= MREAD|MSTATUS; 10421259Swollman} 10521259Swollman 10621259Swollman/* 10721259Swollman * Test to see if the passed file name is a directory. 10869152Sjlemon * Return true if it is. 10921259Swollman */ 11021259Swollmanint 11121259Swollmanisdir(name) 11221259Swollman char name[]; 11321259Swollman{ 11421259Swollman struct stat sbuf; 11521259Swollman 11684380Smjacob if (stat(name, &sbuf) < 0) 11721259Swollman return (0); 11821259Swollman return (S_ISDIR(sbuf.st_mode)); 119147256Sbrooks} 120191688Szec 12160938Sjake/* 122121816Sbrooks * Count the number of arguments in the given string raw list. 123121816Sbrooks */ 124121816Sbrooksint 125191367Srwatsonargcount(argv) 12621259Swollman char **argv; 127128291Sluigi{ 128128291Sluigi char **ap; 129128315Sluigi 130128315Sluigi for (ap = argv; *ap++ != NULL;) 131128315Sluigi ; 132128315Sluigi return (ap - argv - 1); 133128291Sluigi} 134128315Sluigi 135152315Sru/* 136128291Sluigi * Return the desired header line from the passed message 137133741Sjmg * pointer (or NULL if the desired header field is not available). 13883130Sjlemon */ 139142901Sglebiuschar * 14021259Swollmanhfield(field, mp) 14121259Swollman const char *field; 14221259Swollman struct message *mp; 143155051Sglebius{ 144102052Ssobomax FILE *ibuf; 145162070Sandre char linebuf[LINESIZE]; 146162070Sandre int lc; 14721259Swollman char *hfield; 14821259Swollman char *colon, *oldhfield = NULL; 14921259Swollman 15021404Swollman ibuf = setinput(mp); 15121404Swollman if ((lc = mp->m_lines - 1) < 0) 15221259Swollman return (NULL); 15321259Swollman if (readline(ibuf, linebuf, LINESIZE) < 0) 15492725Salfred return (NULL); 155191148Skmacy while (lc > 0) { 156106931Ssam if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0) 157106931Ssam return (oldhfield); 15821259Swollman if ((hfield = ishfield(linebuf, colon, field)) != NULL) 15992725Salfred oldhfield = save2str(hfield, oldhfield); 16021259Swollman } 16192725Salfred return (oldhfield); 16221259Swollman} 16392725Salfred 16421259Swollman/* 16592725Salfred * Return the next header field found in the given message. 16621404Swollman * Return >= 0 if something found, < 0 elsewise. 16792725Salfred * "colon" is set to point to the colon in the header. 168189230Srwatson * Must deal with \ continuations & other such fraud. 169189230Srwatson */ 170189230Srwatsonint 171189230Srwatsongethfield(f, linebuf, rem, colon) 172152315Sru FILE *f; 173174388Skmacy char linebuf[]; 174148265Srwatson int rem; 175130416Smlaier char **colon; 176123220Simp{ 177127828Sluigi char line2[LINESIZE]; 178146986Sthompsa char *cp, *cp2; 179146986Sthompsa int c; 180122524Srwatson 181121161Sume for (;;) { 182127828Sluigi if (--rem < 0) 183127828Sluigi return (-1); 184121161Sume if ((c = readline(f, linebuf, LINESIZE)) <= 0) 185121470Sume return (-1); 186186199Skmacy for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':'; 187145320Sglebius cp++) 188148640Srwatson ; 189186119Sqingli if (*cp != ':' || cp == linebuf) 190152209Sthompsa continue; 191159781Smlaier /* 192159781Smlaier * I guess we got a headline. 193159781Smlaier * Handle wraparounding 194168793Sthompsa */ 195191367Srwatson *colon = cp; 196189230Srwatson cp = linebuf + c; 197189230Srwatson for (;;) { 198189230Srwatson while (--cp >= linebuf && (*cp == ' ' || *cp == '\t')) 199189230Srwatson ; 200189230Srwatson cp++; 201189230Srwatson if (rem <= 0) 202191367Srwatson break; 203189230Srwatson ungetc(c = getc(f), f); 204189230Srwatson if (c != ' ' && c != '\t') 20521259Swollman break; 20669152Sjlemon if ((c = readline(f, line2, LINESIZE)) < 0) 20792725Salfred break; 20821259Swollman rem--; 209128376Sluigi for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++) 210128376Sluigi ; 211128376Sluigi c -= cp2 - line2; 212128376Sluigi if (cp + c >= linebuf + LINESIZE - 2) 21321259Swollman break; 21421259Swollman *cp++ = ' '; 21521259Swollman bcopy(cp2, cp, c); 21621259Swollman cp += c; 21721259Swollman } 21821259Swollman *cp = 0; 219128871Sandre return (rem); 22021259Swollman } 22158698Sjlemon /* NOTREACHED */ 22221259Swollman} 22321259Swollman 22421259Swollman/* 22521259Swollman * Check whether the passed line is a header line of 22621259Swollman * the desired breed. Return the field body, or 0. 22721259Swollman */ 22821259Swollman 22921259Swollmanchar* 23021259Swollmanishfield(linebuf, colon, field) 23121259Swollman char linebuf[]; 23221259Swollman char *colon; 23321259Swollman const char *field; 234136950Sjmg{ 23521259Swollman char *cp = colon; 23653541Sshin 23753541Sshin *cp = 0; 23853541Sshin if (strcasecmp(linebuf, field) != 0) { 239160981Sbrooks *cp = ':'; 24053541Sshin return (0); 24121259Swollman } 242148640Srwatson *cp = ':'; 243148640Srwatson for (cp++; *cp == ' ' || *cp == '\t'; cp++) 244148640Srwatson ; 245148640Srwatson return (cp); 246148640Srwatson} 247148640Srwatson 248148640Srwatson/* 249148640Srwatson * Copy a string and lowercase the result. 250148640Srwatson * dsize: space left in buffer (including space for NULL) 251148640Srwatson */ 25221259Swollmanvoid 25321259Swollmanistrncpy(dest, src, dsize) 25421259Swollman char *dest; 25521259Swollman const char *src; 25621259Swollman size_t dsize; 25772200Sbmilekic{ 25872200Sbmilekic 259130416Smlaier strlcpy(dest, src, dsize); 26069152Sjlemon while (*dest) 26169152Sjlemon *dest++ = tolower((unsigned char)*dest); 26269152Sjlemon} 26321259Swollman 26469152Sjlemon/* 26569152Sjlemon * The following code deals with input stacking to do source 26669152Sjlemon * commands. All but the current file pointer are saved on 26769152Sjlemon * the stack. 26869152Sjlemon */ 26969152Sjlemon 27069152Sjlemonstatic int ssp; /* Top of file stack */ 27169152Sjlemonstruct sstack { 27269152Sjlemon FILE *s_file; /* File we were in. */ 27369152Sjlemon int s_cond; /* Saved state of conditionals */ 27469152Sjlemon int s_loading; /* Loading .mailrc, etc. */ 27569152Sjlemon}; 27669152Sjlemon#define SSTACK_SIZE 64 /* XXX was NOFILE. */ 27769152Sjlemonstatic struct sstack sstack[SSTACK_SIZE]; 27869152Sjlemon 27969152Sjlemon/* 28069152Sjlemon * Pushdown current input file and switch to a new one. 28169152Sjlemon * Set the global flag "sourcing" so that others will realize 28269152Sjlemon * that they are no longer reading from a tty (in all probability). 28369152Sjlemon */ 28469152Sjlemonint 28569152Sjlemonsource(arglist) 28669152Sjlemon char **arglist; 28769152Sjlemon{ 28869152Sjlemon FILE *fi; 28969152Sjlemon char *cp; 29069152Sjlemon 29169152Sjlemon if ((cp = expand(*arglist)) == NULL) 29269152Sjlemon return (1); 29369152Sjlemon if ((fi = Fopen(cp, "r")) == NULL) { 29469152Sjlemon warn("%s", cp); 29569152Sjlemon return (1); 29669152Sjlemon } 297136950Sjmg if (ssp >= SSTACK_SIZE - 1) { 29869152Sjlemon printf("Too much \"sourcing\" going on.\n"); 29969152Sjlemon (void)Fclose(fi); 30069152Sjlemon return (1); 30169152Sjlemon } 30269152Sjlemon sstack[ssp].s_file = input; 30369152Sjlemon sstack[ssp].s_cond = cond; 30469152Sjlemon sstack[ssp].s_loading = loading; 30569152Sjlemon ssp++; 30669152Sjlemon loading = 0; 30769152Sjlemon cond = CANY; 30869152Sjlemon input = fi; 30969152Sjlemon sourcing++; 310130416Smlaier return (0); 311130416Smlaier} 312130416Smlaier 313130416Smlaier/* 31469152Sjlemon * Pop the current input back to the previous level. 31569152Sjlemon * Update the "sourcing" flag as appropriate. 31669152Sjlemon */ 31769152Sjlemonint 31869152Sjlemonunstack() 31969152Sjlemon{ 32069152Sjlemon if (ssp <= 0) { 32169152Sjlemon printf("\"Source\" stack over-pop.\n"); 32269152Sjlemon sourcing = 0; 323130416Smlaier return (1); 324130416Smlaier } 325130416Smlaier (void)Fclose(input); 326130416Smlaier if (cond != CANY) 327130416Smlaier printf("Unmatched \"if\"\n"); 328130416Smlaier ssp--; 32955205Speter cond = sstack[ssp].s_cond; 330126264Smlaier loading = sstack[ssp].s_loading; 331126264Smlaier input = sstack[ssp].s_file; 332126264Smlaier if (ssp == 0) 333126264Smlaier sourcing = loading; 334126264Smlaier return (0); 335126264Smlaier} 336126264Smlaier 337126264Smlaier/* 338126264Smlaier * Touch the indicated file. 339126264Smlaier * This is nifty for the shell. 340159781Smlaier */ 341159781Smlaiervoid 342159781Smlaieralter(name) 343159781Smlaier char *name; 344159781Smlaier{ 345159781Smlaier struct stat sb; 346159781Smlaier struct timeval tv[2]; 347159781Smlaier 348159781Smlaier if (stat(name, &sb)) 349159781Smlaier return; 350159781Smlaier (void)gettimeofday(&tv[0], (struct timezone *)NULL); 351159781Smlaier tv[0].tv_sec++; 352159781Smlaier TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec); 353159781Smlaier (void)utimes(name, tv); 354159781Smlaier} 355159781Smlaier 356159781Smlaier/* 357159781Smlaier * Get sender's name from this message. If the message has 358159781Smlaier * a bunch of arpanet stuff in it, we may have to skin the name 359159781Smlaier * before returning it. 360159781Smlaier */ 361159781Smlaierchar * 362159781Smlaiernameof(mp, reptype) 363159781Smlaier struct message *mp; 364159781Smlaier int reptype; 365159781Smlaier{ 366159781Smlaier char *cp, *cp2; 367159781Smlaier 368159781Smlaier cp = skin(name1(mp, reptype)); 369159781Smlaier if (reptype != 0 || charcount(cp, '!') < 2) 370159781Smlaier return (cp); 371121470Sume cp2 = strrchr(cp, '!'); 372186199Skmacy cp2--; 373121470Sume while (cp2 > cp && *cp2 != '!') 374186199Skmacy cp2--; 375186199Skmacy if (*cp2 == '!') 376186199Skmacy return (cp2 + 1); 377186199Skmacy return (cp); 378186199Skmacy} 379186199Skmacy 380186199Skmacy/* 381186199Skmacy * Start of a "comment". 382186119Sqingli * Ignore it. 383186199Skmacy */ 384186199Skmacychar * 385186199Skmacyskip_comment(cp) 386137065Srwatson char *cp; 387137065Srwatson{ 388130416Smlaier int nesting = 1; 389130416Smlaier 390130416Smlaier for (; nesting > 0 && *cp; cp++) { 391130416Smlaier switch (*cp) { 39221259Swollman case '\\': 393132712Srwatson if (cp[1]) 394132712Srwatson cp++; 395130416Smlaier break; 396130416Smlaier case '(': 397130416Smlaier nesting++; 398130416Smlaier break; 399130416Smlaier case ')': 400130416Smlaier nesting--; 401130416Smlaier break; 402130416Smlaier } 403130416Smlaier } 404130416Smlaier return (cp); 405130416Smlaier} 406130416Smlaier 407130416Smlaier/* 408130416Smlaier * Skin an arpa net address according to the RFC 822 interpretation 409130416Smlaier * of "host-phrase." 410130416Smlaier */ 411130416Smlaierchar * 412130416Smlaierskin(name) 41321259Swollman char *name; 414130416Smlaier{ 415130416Smlaier char *nbuf, *bufend, *cp, *cp2; 416130416Smlaier int c, gotlt, lastsp; 417130508Smlaier 418130416Smlaier if (name == NULL) 419130416Smlaier return (NULL); 420130416Smlaier if (strchr(name, '(') == NULL && strchr(name, '<') == NULL 421130416Smlaier && strchr(name, ' ') == NULL) 422130416Smlaier return (name); 423130416Smlaier 424130416Smlaier /* We assume that length(input) <= length(output) */ 425130416Smlaier if ((nbuf = malloc(strlen(name) + 1)) == NULL) 426130416Smlaier err(1, "Out of memory"); 427130416Smlaier gotlt = 0; 428130416Smlaier lastsp = 0; 429130416Smlaier bufend = nbuf; 430130416Smlaier for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) { 431130416Smlaier switch (c) { 432130416Smlaier case '(': 433130416Smlaier cp = skip_comment(cp); 434130508Smlaier lastsp = 0; 435130416Smlaier break; 436130416Smlaier 437130416Smlaier case '"': 438130416Smlaier /* 439130416Smlaier * Start of a "quoted-string". 440130416Smlaier * Copy it in its entirety. 441130416Smlaier */ 442130416Smlaier while ((c = *cp) != '\0') { 443130416Smlaier cp++; 444130416Smlaier if (c == '"') 445130416Smlaier break; 446130416Smlaier if (c != '\\') 447130416Smlaier *cp2++ = c; 448130416Smlaier else if ((c = *cp) != '\0') { 449130416Smlaier *cp2++ = c; 450130416Smlaier cp++; 451130416Smlaier } 452130416Smlaier } 453130416Smlaier lastsp = 0; 454130416Smlaier break; 455130416Smlaier 456130416Smlaier case ' ': 457130416Smlaier if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ') 458130416Smlaier cp += 3, *cp2++ = '@'; 459130416Smlaier else 460130416Smlaier if (cp[0] == '@' && cp[1] == ' ') 461130416Smlaier cp += 2, *cp2++ = '@'; 462130416Smlaier else 463130416Smlaier lastsp = 1; 464130416Smlaier break; 465130416Smlaier 466130416Smlaier case '<': 467130416Smlaier cp2 = bufend; 468130416Smlaier gotlt++; 469130416Smlaier lastsp = 0; 470130416Smlaier break; 471130416Smlaier 472130416Smlaier case '>': 473130416Smlaier if (gotlt) { 474130416Smlaier gotlt = 0; 475148886Srwatson while ((c = *cp) != '\0' && c != ',') { 476148886Srwatson cp++; 477148886Srwatson if (c == '(') 478148886Srwatson cp = skip_comment(cp); 479130416Smlaier else if (c == '"') 480130416Smlaier while ((c = *cp) != '\0') { 481130416Smlaier cp++; 482130416Smlaier if (c == '"') 483130416Smlaier break; 484130416Smlaier if (c == '\\' && *cp != '\0') 485130416Smlaier cp++; 486130416Smlaier } 487130416Smlaier } 488130416Smlaier lastsp = 0; 489130416Smlaier break; 490130416Smlaier } 491148886Srwatson /* Fall into . . . */ 492132712Srwatson 493130416Smlaier default: 494130416Smlaier if (lastsp) { 495130416Smlaier lastsp = 0; 496130416Smlaier *cp2++ = ' '; 497130512Smlaier } 498130416Smlaier *cp2++ = c; 499130416Smlaier if (c == ',' && *cp == ' ' && !gotlt) { 500130416Smlaier *cp2++ = ' '; 501130416Smlaier while (*++cp == ' ') 502130416Smlaier ; 503130416Smlaier lastsp = 0; 504130416Smlaier bufend = cp2; 505130416Smlaier } 506130416Smlaier } 507130416Smlaier } 508130416Smlaier *cp2 = '\0'; 509130416Smlaier 510130416Smlaier if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL) 511130416Smlaier nbuf = cp; 512130416Smlaier return (nbuf); 513130416Smlaier} 514130416Smlaier 515130416Smlaier/* 516130416Smlaier * Fetch the sender's name from the passed message. 517130416Smlaier * Reptype can be 518130416Smlaier * 0 -- get sender's name for display purposes 519130416Smlaier * 1 -- get sender's name for reply 520130416Smlaier * 2 -- get sender's name for Reply 521130416Smlaier */ 522130416Smlaierchar * 523130416Smlaiername1(mp, reptype) 524130416Smlaier struct message *mp; 525130416Smlaier int reptype; 526130416Smlaier{ 527130416Smlaier char namebuf[LINESIZE]; 528130416Smlaier char linebuf[LINESIZE]; 529130416Smlaier char *cp, *cp2; 530132152Smlaier FILE *ibuf; 531132152Smlaier int first = 1; 532130416Smlaier 533130416Smlaier if ((cp = hfield("from", mp)) != NULL) 534130416Smlaier return (cp); 535130416Smlaier if (reptype == 0 && (cp = hfield("sender", mp)) != NULL) 536130416Smlaier return (cp); 537130416Smlaier ibuf = setinput(mp); 538130416Smlaier namebuf[0] = '\0'; 539130416Smlaier if (readline(ibuf, linebuf, LINESIZE) < 0) 540130416Smlaier return (savestr(namebuf)); 541132152Smlaiernewname: 542132152Smlaier for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++) 543132152Smlaier ; 544130416Smlaier for (; *cp == ' ' || *cp == '\t'; cp++) 545130416Smlaier ; 546130416Smlaier for (cp2 = &namebuf[strlen(namebuf)]; 547130416Smlaier *cp != '\0' && *cp != ' ' && *cp != '\t' && 548130416Smlaier cp2 < namebuf + LINESIZE - 1;) 549130416Smlaier *cp2++ = *cp++; 550130416Smlaier *cp2 = '\0'; 551186207Skmacy if (readline(ibuf, linebuf, LINESIZE) < 0) 552186213Skmacy return (savestr(namebuf)); 553186213Skmacy if ((cp = strchr(linebuf, 'F')) == NULL) 554186213Skmacy return (savestr(namebuf)); 555186213Skmacy if (strncmp(cp, "From", 4) != 0) 556186213Skmacy return (savestr(namebuf)); 557186213Skmacy while ((cp = strchr(cp, 'r')) != NULL) { 558186213Skmacy if (strncmp(cp, "remote", 6) == 0) { 559186213Skmacy if ((cp = strchr(cp, 'f')) == NULL) 560186213Skmacy break; 561186207Skmacy if (strncmp(cp, "from", 4) != 0) 562186213Skmacy break; 563186207Skmacy if ((cp = strchr(cp, ' ')) == NULL) 564186207Skmacy break; 565186213Skmacy cp++; 566186213Skmacy if (first) { 567186207Skmacy cp2 = namebuf; 568191033Skmacy first = 0; 569191033Skmacy } else 570191033Skmacy cp2 = strrchr(namebuf, '!') + 1; 571191033Skmacy strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1); 572191033Skmacy strcat(namebuf, "!"); 573191033Skmacy goto newname; 574186207Skmacy } 575186207Skmacy cp++; 576186213Skmacy } 577186207Skmacy return (savestr(namebuf)); 578186213Skmacy} 579186213Skmacy 580186213Skmacy/* 581186207Skmacy * Count the occurances of c in str 582186207Skmacy */ 583186207Skmacyint 584186207Skmacycharcount(str, c) 585186207Skmacy char *str; 586186207Skmacy int c; 587186207Skmacy{ 588186207Skmacy char *cp; 589186207Skmacy int i; 590186207Skmacy 591186207Skmacy for (i = 0, cp = str; *cp != '\0'; cp++) 592186207Skmacy if (*cp == c) 593186207Skmacy i++; 594191033Skmacy return (i); 595191033Skmacy} 596191033Skmacy 597191033Skmacy/* 598191033Skmacy * See if the given header field is supposed to be ignored. 599191033Skmacy */ 600191033Skmacyint 601191033Skmacyisign(field, ignore) 602191033Skmacy const char *field; 603191033Skmacy struct ignoretab ignore[2]; 604191033Skmacy{ 605186207Skmacy char realfld[LINESIZE]; 606191033Skmacy 607191033Skmacy if (ignore == ignoreall) 608186207Skmacy return (1); 609191033Skmacy /* 610191033Skmacy * Lower-case the string, so that "Status" and "status" 611191033Skmacy * will hash to the same place. 612191033Skmacy */ 613191033Skmacy istrncpy(realfld, field, sizeof(realfld)); 614191033Skmacy if (ignore[1].i_count > 0) 615191033Skmacy return (!member(realfld, ignore + 1)); 616191033Skmacy else 617191033Skmacy return (member(realfld, ignore)); 618191033Skmacy} 61949459Sbrian 62049459Sbrianint 62149459Sbrianmember(realfield, table) 62249459Sbrian char *realfield; 62349459Sbrian struct ignoretab *table; 62449459Sbrian{ 62549459Sbrian struct ignore *igp; 62655205Speter 62721259Swollman for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link) 62821259Swollman if (*igp->i_field == *realfield && 62921259Swollman equal(igp->i_field, realfield)) 63021259Swollman return (1); 63121259Swollman return (0); 63221259Swollman} 633128291Sluigi