1*8a16b7a1SPedro F. Giffuni /*- 2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*8a16b7a1SPedro F. Giffuni * 40bee4c2cSEd Schouten * Copyright (c) 1980, 1993 50bee4c2cSEd Schouten * The Regents of the University of California. All rights reserved. 60bee4c2cSEd Schouten * 70bee4c2cSEd Schouten * Redistribution and use in source and binary forms, with or without 80bee4c2cSEd Schouten * modification, are permitted provided that the following conditions 90bee4c2cSEd Schouten * are met: 100bee4c2cSEd Schouten * 1. Redistributions of source code must retain the above copyright 110bee4c2cSEd Schouten * notice, this list of conditions and the following disclaimer. 120bee4c2cSEd Schouten * 2. Redistributions in binary form must reproduce the above copyright 130bee4c2cSEd Schouten * notice, this list of conditions and the following disclaimer in the 140bee4c2cSEd Schouten * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 160bee4c2cSEd Schouten * may be used to endorse or promote products derived from this software 170bee4c2cSEd Schouten * without specific prior written permission. 180bee4c2cSEd Schouten * 190bee4c2cSEd Schouten * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 200bee4c2cSEd Schouten * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 210bee4c2cSEd Schouten * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 220bee4c2cSEd Schouten * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 230bee4c2cSEd Schouten * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 240bee4c2cSEd Schouten * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 250bee4c2cSEd Schouten * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 260bee4c2cSEd Schouten * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 270bee4c2cSEd Schouten * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 280bee4c2cSEd Schouten * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 290bee4c2cSEd Schouten * SUCH DAMAGE. 300bee4c2cSEd Schouten */ 310bee4c2cSEd Schouten 320bee4c2cSEd Schouten #ifndef lint 330bee4c2cSEd Schouten #if 0 340bee4c2cSEd Schouten static char sccsid[] = "@(#)aux.c 8.1 (Berkeley) 6/6/93"; 350bee4c2cSEd Schouten #endif 360bee4c2cSEd Schouten #endif /* not lint */ 370bee4c2cSEd Schouten #include <sys/cdefs.h> 380bee4c2cSEd Schouten __FBSDID("$FreeBSD$"); 390bee4c2cSEd Schouten 400bee4c2cSEd Schouten #include <sys/time.h> 410bee4c2cSEd Schouten 42ae7d5745SJilles Tjoelker #include <fcntl.h> 43ae7d5745SJilles Tjoelker 440bee4c2cSEd Schouten #include "rcv.h" 450bee4c2cSEd Schouten #include "extern.h" 460bee4c2cSEd Schouten 470bee4c2cSEd Schouten /* 480bee4c2cSEd Schouten * Mail -- a mail program 490bee4c2cSEd Schouten * 500bee4c2cSEd Schouten * Auxiliary functions. 510bee4c2cSEd Schouten */ 520bee4c2cSEd Schouten 530bee4c2cSEd Schouten static char *save2str(char *, char *); 540bee4c2cSEd Schouten 550bee4c2cSEd Schouten /* 560bee4c2cSEd Schouten * Return a pointer to a dynamic copy of the argument. 570bee4c2cSEd Schouten */ 580bee4c2cSEd Schouten char * 596d8484b0SPhilippe Charnier savestr(char *str) 600bee4c2cSEd Schouten { 610bee4c2cSEd Schouten char *new; 620bee4c2cSEd Schouten int size = strlen(str) + 1; 630bee4c2cSEd Schouten 640bee4c2cSEd Schouten if ((new = salloc(size)) != NULL) 650bee4c2cSEd Schouten bcopy(str, new, size); 660bee4c2cSEd Schouten return (new); 670bee4c2cSEd Schouten } 680bee4c2cSEd Schouten 690bee4c2cSEd Schouten /* 700bee4c2cSEd Schouten * Make a copy of new argument incorporating old one. 710bee4c2cSEd Schouten */ 720bee4c2cSEd Schouten static char * 736d8484b0SPhilippe Charnier save2str(char *str, char *old) 740bee4c2cSEd Schouten { 750bee4c2cSEd Schouten char *new; 760bee4c2cSEd Schouten int newsize = strlen(str) + 1; 770bee4c2cSEd Schouten int oldsize = old ? strlen(old) + 1 : 0; 780bee4c2cSEd Schouten 790bee4c2cSEd Schouten if ((new = salloc(newsize + oldsize)) != NULL) { 800bee4c2cSEd Schouten if (oldsize) { 810bee4c2cSEd Schouten bcopy(old, new, oldsize); 820bee4c2cSEd Schouten new[oldsize - 1] = ' '; 830bee4c2cSEd Schouten } 840bee4c2cSEd Schouten bcopy(str, new + oldsize, newsize); 850bee4c2cSEd Schouten } 860bee4c2cSEd Schouten return (new); 870bee4c2cSEd Schouten } 880bee4c2cSEd Schouten 890bee4c2cSEd Schouten /* 900bee4c2cSEd Schouten * Touch the named message by setting its MTOUCH flag. 910bee4c2cSEd Schouten * Touched messages have the effect of not being sent 920bee4c2cSEd Schouten * back to the system mailbox on exit. 930bee4c2cSEd Schouten */ 940bee4c2cSEd Schouten void 956d8484b0SPhilippe Charnier touch(struct message *mp) 960bee4c2cSEd Schouten { 970bee4c2cSEd Schouten 980bee4c2cSEd Schouten mp->m_flag |= MTOUCH; 990bee4c2cSEd Schouten if ((mp->m_flag & MREAD) == 0) 1000bee4c2cSEd Schouten mp->m_flag |= MREAD|MSTATUS; 1010bee4c2cSEd Schouten } 1020bee4c2cSEd Schouten 1030bee4c2cSEd Schouten /* 1040bee4c2cSEd Schouten * Test to see if the passed file name is a directory. 1050bee4c2cSEd Schouten * Return true if it is. 1060bee4c2cSEd Schouten */ 1070bee4c2cSEd Schouten int 1086d8484b0SPhilippe Charnier isdir(char name[]) 1090bee4c2cSEd Schouten { 1100bee4c2cSEd Schouten struct stat sbuf; 1110bee4c2cSEd Schouten 1120bee4c2cSEd Schouten if (stat(name, &sbuf) < 0) 1130bee4c2cSEd Schouten return (0); 1140bee4c2cSEd Schouten return (S_ISDIR(sbuf.st_mode)); 1150bee4c2cSEd Schouten } 1160bee4c2cSEd Schouten 1170bee4c2cSEd Schouten /* 1180bee4c2cSEd Schouten * Count the number of arguments in the given string raw list. 1190bee4c2cSEd Schouten */ 1200bee4c2cSEd Schouten int 1216d8484b0SPhilippe Charnier argcount(char **argv) 1220bee4c2cSEd Schouten { 1230bee4c2cSEd Schouten char **ap; 1240bee4c2cSEd Schouten 1250bee4c2cSEd Schouten for (ap = argv; *ap++ != NULL;) 1260bee4c2cSEd Schouten ; 1270bee4c2cSEd Schouten return (ap - argv - 1); 1280bee4c2cSEd Schouten } 1290bee4c2cSEd Schouten 1300bee4c2cSEd Schouten /* 1310bee4c2cSEd Schouten * Return the desired header line from the passed message 1320bee4c2cSEd Schouten * pointer (or NULL if the desired header field is not available). 1330bee4c2cSEd Schouten */ 1340bee4c2cSEd Schouten char * 1356d8484b0SPhilippe Charnier hfield(const char *field, struct message *mp) 1360bee4c2cSEd Schouten { 1370bee4c2cSEd Schouten FILE *ibuf; 1380bee4c2cSEd Schouten char linebuf[LINESIZE]; 1390bee4c2cSEd Schouten int lc; 1400bee4c2cSEd Schouten char *hfield; 1410bee4c2cSEd Schouten char *colon, *oldhfield = NULL; 1420bee4c2cSEd Schouten 1430bee4c2cSEd Schouten ibuf = setinput(mp); 1440bee4c2cSEd Schouten if ((lc = mp->m_lines - 1) < 0) 1450bee4c2cSEd Schouten return (NULL); 1460bee4c2cSEd Schouten if (readline(ibuf, linebuf, LINESIZE) < 0) 1470bee4c2cSEd Schouten return (NULL); 1480bee4c2cSEd Schouten while (lc > 0) { 1490bee4c2cSEd Schouten if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0) 1500bee4c2cSEd Schouten return (oldhfield); 1510bee4c2cSEd Schouten if ((hfield = ishfield(linebuf, colon, field)) != NULL) 1520bee4c2cSEd Schouten oldhfield = save2str(hfield, oldhfield); 1530bee4c2cSEd Schouten } 1540bee4c2cSEd Schouten return (oldhfield); 1550bee4c2cSEd Schouten } 1560bee4c2cSEd Schouten 1570bee4c2cSEd Schouten /* 1580bee4c2cSEd Schouten * Return the next header field found in the given message. 1590bee4c2cSEd Schouten * Return >= 0 if something found, < 0 elsewise. 1600bee4c2cSEd Schouten * "colon" is set to point to the colon in the header. 1610bee4c2cSEd Schouten * Must deal with \ continuations & other such fraud. 1620bee4c2cSEd Schouten */ 1630bee4c2cSEd Schouten int 1646d8484b0SPhilippe Charnier gethfield(FILE *f, char linebuf[], int rem, char **colon) 1650bee4c2cSEd Schouten { 1660bee4c2cSEd Schouten char line2[LINESIZE]; 1670bee4c2cSEd Schouten char *cp, *cp2; 1680bee4c2cSEd Schouten int c; 1690bee4c2cSEd Schouten 1700bee4c2cSEd Schouten for (;;) { 1710bee4c2cSEd Schouten if (--rem < 0) 1720bee4c2cSEd Schouten return (-1); 1730bee4c2cSEd Schouten if ((c = readline(f, linebuf, LINESIZE)) <= 0) 1740bee4c2cSEd Schouten return (-1); 1750bee4c2cSEd Schouten for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':'; 1760bee4c2cSEd Schouten cp++) 1770bee4c2cSEd Schouten ; 1780bee4c2cSEd Schouten if (*cp != ':' || cp == linebuf) 1790bee4c2cSEd Schouten continue; 1800bee4c2cSEd Schouten /* 1810bee4c2cSEd Schouten * I guess we got a headline. 1820bee4c2cSEd Schouten * Handle wraparounding 1830bee4c2cSEd Schouten */ 1840bee4c2cSEd Schouten *colon = cp; 1850bee4c2cSEd Schouten cp = linebuf + c; 1860bee4c2cSEd Schouten for (;;) { 1870bee4c2cSEd Schouten while (--cp >= linebuf && (*cp == ' ' || *cp == '\t')) 1880bee4c2cSEd Schouten ; 1890bee4c2cSEd Schouten cp++; 1900bee4c2cSEd Schouten if (rem <= 0) 1910bee4c2cSEd Schouten break; 1920bee4c2cSEd Schouten ungetc(c = getc(f), f); 1930bee4c2cSEd Schouten if (c != ' ' && c != '\t') 1940bee4c2cSEd Schouten break; 1950bee4c2cSEd Schouten if ((c = readline(f, line2, LINESIZE)) < 0) 1960bee4c2cSEd Schouten break; 1970bee4c2cSEd Schouten rem--; 1980bee4c2cSEd Schouten for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++) 1990bee4c2cSEd Schouten ; 2000bee4c2cSEd Schouten c -= cp2 - line2; 2010bee4c2cSEd Schouten if (cp + c >= linebuf + LINESIZE - 2) 2020bee4c2cSEd Schouten break; 2030bee4c2cSEd Schouten *cp++ = ' '; 2040bee4c2cSEd Schouten bcopy(cp2, cp, c); 2050bee4c2cSEd Schouten cp += c; 2060bee4c2cSEd Schouten } 2070bee4c2cSEd Schouten *cp = 0; 2080bee4c2cSEd Schouten return (rem); 2090bee4c2cSEd Schouten } 2100bee4c2cSEd Schouten /* NOTREACHED */ 2110bee4c2cSEd Schouten } 2120bee4c2cSEd Schouten 2130bee4c2cSEd Schouten /* 2140bee4c2cSEd Schouten * Check whether the passed line is a header line of 2150bee4c2cSEd Schouten * the desired breed. Return the field body, or 0. 2160bee4c2cSEd Schouten */ 2170bee4c2cSEd Schouten 2180bee4c2cSEd Schouten char* 219eeb341a9SPedro F. Giffuni ishfield(char *linebuf, char *colon, const char *field) 2200bee4c2cSEd Schouten { 2210bee4c2cSEd Schouten char *cp = colon; 2220bee4c2cSEd Schouten 2230bee4c2cSEd Schouten *cp = 0; 2240bee4c2cSEd Schouten if (strcasecmp(linebuf, field) != 0) { 2250bee4c2cSEd Schouten *cp = ':'; 2260bee4c2cSEd Schouten return (0); 2270bee4c2cSEd Schouten } 2280bee4c2cSEd Schouten *cp = ':'; 2290bee4c2cSEd Schouten for (cp++; *cp == ' ' || *cp == '\t'; cp++) 2300bee4c2cSEd Schouten ; 2310bee4c2cSEd Schouten return (cp); 2320bee4c2cSEd Schouten } 2330bee4c2cSEd Schouten 2340bee4c2cSEd Schouten /* 2350bee4c2cSEd Schouten * Copy a string and lowercase the result. 2360bee4c2cSEd Schouten * dsize: space left in buffer (including space for NULL) 2370bee4c2cSEd Schouten */ 2380bee4c2cSEd Schouten void 2396d8484b0SPhilippe Charnier istrncpy(char *dest, const char *src, size_t dsize) 2400bee4c2cSEd Schouten { 2410bee4c2cSEd Schouten 2420bee4c2cSEd Schouten strlcpy(dest, src, dsize); 243ca83b975SDimitry Andric for (; *dest; dest++) 244ca83b975SDimitry Andric *dest = tolower((unsigned char)*dest); 2450bee4c2cSEd Schouten } 2460bee4c2cSEd Schouten 2470bee4c2cSEd Schouten /* 2480bee4c2cSEd Schouten * The following code deals with input stacking to do source 2490bee4c2cSEd Schouten * commands. All but the current file pointer are saved on 2500bee4c2cSEd Schouten * the stack. 2510bee4c2cSEd Schouten */ 2520bee4c2cSEd Schouten 2530bee4c2cSEd Schouten static int ssp; /* Top of file stack */ 2540bee4c2cSEd Schouten struct sstack { 2550bee4c2cSEd Schouten FILE *s_file; /* File we were in. */ 2560bee4c2cSEd Schouten int s_cond; /* Saved state of conditionals */ 2570bee4c2cSEd Schouten int s_loading; /* Loading .mailrc, etc. */ 2580bee4c2cSEd Schouten }; 2590bee4c2cSEd Schouten #define SSTACK_SIZE 64 /* XXX was NOFILE. */ 2600bee4c2cSEd Schouten static struct sstack sstack[SSTACK_SIZE]; 2610bee4c2cSEd Schouten 2620bee4c2cSEd Schouten /* 2630bee4c2cSEd Schouten * Pushdown current input file and switch to a new one. 2640bee4c2cSEd Schouten * Set the global flag "sourcing" so that others will realize 2650bee4c2cSEd Schouten * that they are no longer reading from a tty (in all probability). 2660bee4c2cSEd Schouten */ 2670bee4c2cSEd Schouten int 2686d8484b0SPhilippe Charnier source(char **arglist) 2690bee4c2cSEd Schouten { 2700bee4c2cSEd Schouten FILE *fi; 2710bee4c2cSEd Schouten char *cp; 2720bee4c2cSEd Schouten 2730bee4c2cSEd Schouten if ((cp = expand(*arglist)) == NULL) 2740bee4c2cSEd Schouten return (1); 2750bee4c2cSEd Schouten if ((fi = Fopen(cp, "r")) == NULL) { 2760bee4c2cSEd Schouten warn("%s", cp); 2770bee4c2cSEd Schouten return (1); 2780bee4c2cSEd Schouten } 2790bee4c2cSEd Schouten if (ssp >= SSTACK_SIZE - 1) { 2800bee4c2cSEd Schouten printf("Too much \"sourcing\" going on.\n"); 2810bee4c2cSEd Schouten (void)Fclose(fi); 2820bee4c2cSEd Schouten return (1); 2830bee4c2cSEd Schouten } 2840bee4c2cSEd Schouten sstack[ssp].s_file = input; 2850bee4c2cSEd Schouten sstack[ssp].s_cond = cond; 2860bee4c2cSEd Schouten sstack[ssp].s_loading = loading; 2870bee4c2cSEd Schouten ssp++; 2880bee4c2cSEd Schouten loading = 0; 2890bee4c2cSEd Schouten cond = CANY; 2900bee4c2cSEd Schouten input = fi; 2910bee4c2cSEd Schouten sourcing++; 2920bee4c2cSEd Schouten return (0); 2930bee4c2cSEd Schouten } 2940bee4c2cSEd Schouten 2950bee4c2cSEd Schouten /* 2960bee4c2cSEd Schouten * Pop the current input back to the previous level. 2970bee4c2cSEd Schouten * Update the "sourcing" flag as appropriate. 2980bee4c2cSEd Schouten */ 2990bee4c2cSEd Schouten int 3006d8484b0SPhilippe Charnier unstack(void) 3010bee4c2cSEd Schouten { 3020bee4c2cSEd Schouten if (ssp <= 0) { 3030bee4c2cSEd Schouten printf("\"Source\" stack over-pop.\n"); 3040bee4c2cSEd Schouten sourcing = 0; 3050bee4c2cSEd Schouten return (1); 3060bee4c2cSEd Schouten } 3070bee4c2cSEd Schouten (void)Fclose(input); 3080bee4c2cSEd Schouten if (cond != CANY) 3090bee4c2cSEd Schouten printf("Unmatched \"if\"\n"); 3100bee4c2cSEd Schouten ssp--; 3110bee4c2cSEd Schouten cond = sstack[ssp].s_cond; 3120bee4c2cSEd Schouten loading = sstack[ssp].s_loading; 3130bee4c2cSEd Schouten input = sstack[ssp].s_file; 3140bee4c2cSEd Schouten if (ssp == 0) 3150bee4c2cSEd Schouten sourcing = loading; 3160bee4c2cSEd Schouten return (0); 3170bee4c2cSEd Schouten } 3180bee4c2cSEd Schouten 3190bee4c2cSEd Schouten /* 3200bee4c2cSEd Schouten * Touch the indicated file. 3210bee4c2cSEd Schouten * This is nifty for the shell. 3220bee4c2cSEd Schouten */ 3230bee4c2cSEd Schouten void 3246d8484b0SPhilippe Charnier alter(char *name) 3250bee4c2cSEd Schouten { 326ae7d5745SJilles Tjoelker struct timespec ts[2]; 3270bee4c2cSEd Schouten 328ae7d5745SJilles Tjoelker (void)clock_gettime(CLOCK_REALTIME, &ts[0]); 329ae7d5745SJilles Tjoelker ts[0].tv_sec++; 330ae7d5745SJilles Tjoelker ts[1].tv_sec = 0; 331ae7d5745SJilles Tjoelker ts[1].tv_nsec = UTIME_OMIT; 332ae7d5745SJilles Tjoelker (void)utimensat(AT_FDCWD, name, ts, 0); 3330bee4c2cSEd Schouten } 3340bee4c2cSEd Schouten 3350bee4c2cSEd Schouten /* 3360bee4c2cSEd Schouten * Get sender's name from this message. If the message has 3370bee4c2cSEd Schouten * a bunch of arpanet stuff in it, we may have to skin the name 3380bee4c2cSEd Schouten * before returning it. 3390bee4c2cSEd Schouten */ 3400bee4c2cSEd Schouten char * 3416d8484b0SPhilippe Charnier nameof(struct message *mp, int reptype) 3420bee4c2cSEd Schouten { 3430bee4c2cSEd Schouten char *cp, *cp2; 3440bee4c2cSEd Schouten 3450bee4c2cSEd Schouten cp = skin(name1(mp, reptype)); 3460bee4c2cSEd Schouten if (reptype != 0 || charcount(cp, '!') < 2) 3470bee4c2cSEd Schouten return (cp); 3480bee4c2cSEd Schouten cp2 = strrchr(cp, '!'); 3490bee4c2cSEd Schouten cp2--; 3500bee4c2cSEd Schouten while (cp2 > cp && *cp2 != '!') 3510bee4c2cSEd Schouten cp2--; 3520bee4c2cSEd Schouten if (*cp2 == '!') 3530bee4c2cSEd Schouten return (cp2 + 1); 3540bee4c2cSEd Schouten return (cp); 3550bee4c2cSEd Schouten } 3560bee4c2cSEd Schouten 3570bee4c2cSEd Schouten /* 3580bee4c2cSEd Schouten * Start of a "comment". 3590bee4c2cSEd Schouten * Ignore it. 3600bee4c2cSEd Schouten */ 3610bee4c2cSEd Schouten char * 3626d8484b0SPhilippe Charnier skip_comment(char *cp) 3630bee4c2cSEd Schouten { 3640bee4c2cSEd Schouten int nesting = 1; 3650bee4c2cSEd Schouten 3660bee4c2cSEd Schouten for (; nesting > 0 && *cp; cp++) { 3670bee4c2cSEd Schouten switch (*cp) { 3680bee4c2cSEd Schouten case '\\': 3690bee4c2cSEd Schouten if (cp[1]) 3700bee4c2cSEd Schouten cp++; 3710bee4c2cSEd Schouten break; 3720bee4c2cSEd Schouten case '(': 3730bee4c2cSEd Schouten nesting++; 3740bee4c2cSEd Schouten break; 3750bee4c2cSEd Schouten case ')': 3760bee4c2cSEd Schouten nesting--; 3770bee4c2cSEd Schouten break; 3780bee4c2cSEd Schouten } 3790bee4c2cSEd Schouten } 3800bee4c2cSEd Schouten return (cp); 3810bee4c2cSEd Schouten } 3820bee4c2cSEd Schouten 3830bee4c2cSEd Schouten /* 3840bee4c2cSEd Schouten * Skin an arpa net address according to the RFC 822 interpretation 3850bee4c2cSEd Schouten * of "host-phrase." 3860bee4c2cSEd Schouten */ 3870bee4c2cSEd Schouten char * 3886d8484b0SPhilippe Charnier skin(char *name) 3890bee4c2cSEd Schouten { 3900bee4c2cSEd Schouten char *nbuf, *bufend, *cp, *cp2; 3910bee4c2cSEd Schouten int c, gotlt, lastsp; 3920bee4c2cSEd Schouten 3930bee4c2cSEd Schouten if (name == NULL) 3940bee4c2cSEd Schouten return (NULL); 3950bee4c2cSEd Schouten if (strchr(name, '(') == NULL && strchr(name, '<') == NULL 3960bee4c2cSEd Schouten && strchr(name, ' ') == NULL) 3970bee4c2cSEd Schouten return (name); 3980bee4c2cSEd Schouten 3990bee4c2cSEd Schouten /* We assume that length(input) <= length(output) */ 4000bee4c2cSEd Schouten if ((nbuf = malloc(strlen(name) + 1)) == NULL) 4010bee4c2cSEd Schouten err(1, "Out of memory"); 4020bee4c2cSEd Schouten gotlt = 0; 4030bee4c2cSEd Schouten lastsp = 0; 4040bee4c2cSEd Schouten bufend = nbuf; 4050bee4c2cSEd Schouten for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) { 4060bee4c2cSEd Schouten switch (c) { 4070bee4c2cSEd Schouten case '(': 4080bee4c2cSEd Schouten cp = skip_comment(cp); 4090bee4c2cSEd Schouten lastsp = 0; 4100bee4c2cSEd Schouten break; 4110bee4c2cSEd Schouten 4120bee4c2cSEd Schouten case '"': 4130bee4c2cSEd Schouten /* 4140bee4c2cSEd Schouten * Start of a "quoted-string". 4150bee4c2cSEd Schouten * Copy it in its entirety. 4160bee4c2cSEd Schouten */ 4170bee4c2cSEd Schouten while ((c = *cp) != '\0') { 4180bee4c2cSEd Schouten cp++; 4190bee4c2cSEd Schouten if (c == '"') 4200bee4c2cSEd Schouten break; 4210bee4c2cSEd Schouten if (c != '\\') 4220bee4c2cSEd Schouten *cp2++ = c; 4230bee4c2cSEd Schouten else if ((c = *cp) != '\0') { 4240bee4c2cSEd Schouten *cp2++ = c; 4250bee4c2cSEd Schouten cp++; 4260bee4c2cSEd Schouten } 4270bee4c2cSEd Schouten } 4280bee4c2cSEd Schouten lastsp = 0; 4290bee4c2cSEd Schouten break; 4300bee4c2cSEd Schouten 4310bee4c2cSEd Schouten case ' ': 4320bee4c2cSEd Schouten if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ') 4330bee4c2cSEd Schouten cp += 3, *cp2++ = '@'; 4340bee4c2cSEd Schouten else 4350bee4c2cSEd Schouten if (cp[0] == '@' && cp[1] == ' ') 4360bee4c2cSEd Schouten cp += 2, *cp2++ = '@'; 4370bee4c2cSEd Schouten else 4380bee4c2cSEd Schouten lastsp = 1; 4390bee4c2cSEd Schouten break; 4400bee4c2cSEd Schouten 4410bee4c2cSEd Schouten case '<': 4420bee4c2cSEd Schouten cp2 = bufend; 4430bee4c2cSEd Schouten gotlt++; 4440bee4c2cSEd Schouten lastsp = 0; 4450bee4c2cSEd Schouten break; 4460bee4c2cSEd Schouten 4470bee4c2cSEd Schouten case '>': 4480bee4c2cSEd Schouten if (gotlt) { 4490bee4c2cSEd Schouten gotlt = 0; 4500bee4c2cSEd Schouten while ((c = *cp) != '\0' && c != ',') { 4510bee4c2cSEd Schouten cp++; 4520bee4c2cSEd Schouten if (c == '(') 4530bee4c2cSEd Schouten cp = skip_comment(cp); 4540bee4c2cSEd Schouten else if (c == '"') 4550bee4c2cSEd Schouten while ((c = *cp) != '\0') { 4560bee4c2cSEd Schouten cp++; 4570bee4c2cSEd Schouten if (c == '"') 4580bee4c2cSEd Schouten break; 4590bee4c2cSEd Schouten if (c == '\\' && *cp != '\0') 4600bee4c2cSEd Schouten cp++; 4610bee4c2cSEd Schouten } 4620bee4c2cSEd Schouten } 4630bee4c2cSEd Schouten lastsp = 0; 4640bee4c2cSEd Schouten break; 4650bee4c2cSEd Schouten } 4660bee4c2cSEd Schouten /* FALLTHROUGH */ 4670bee4c2cSEd Schouten 4680bee4c2cSEd Schouten default: 4690bee4c2cSEd Schouten if (lastsp) { 4700bee4c2cSEd Schouten lastsp = 0; 4710bee4c2cSEd Schouten *cp2++ = ' '; 4720bee4c2cSEd Schouten } 4730bee4c2cSEd Schouten *cp2++ = c; 474a1d170a0SUlrich Spörlein if (c == ',' && !gotlt && 475a1d170a0SUlrich Spörlein (*cp == ' ' || *cp == '"' || *cp == '<')) { 4760bee4c2cSEd Schouten *cp2++ = ' '; 477a1d170a0SUlrich Spörlein while (*cp == ' ') 478a1d170a0SUlrich Spörlein cp++; 4790bee4c2cSEd Schouten lastsp = 0; 4800bee4c2cSEd Schouten bufend = cp2; 4810bee4c2cSEd Schouten } 4820bee4c2cSEd Schouten } 4830bee4c2cSEd Schouten } 4840bee4c2cSEd Schouten *cp2 = '\0'; 4850bee4c2cSEd Schouten 4860bee4c2cSEd Schouten if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL) 4870bee4c2cSEd Schouten nbuf = cp; 4880bee4c2cSEd Schouten return (nbuf); 4890bee4c2cSEd Schouten } 4900bee4c2cSEd Schouten 4910bee4c2cSEd Schouten /* 4920bee4c2cSEd Schouten * Fetch the sender's name from the passed message. 4930bee4c2cSEd Schouten * Reptype can be 4940bee4c2cSEd Schouten * 0 -- get sender's name for display purposes 4950bee4c2cSEd Schouten * 1 -- get sender's name for reply 4960bee4c2cSEd Schouten * 2 -- get sender's name for Reply 4970bee4c2cSEd Schouten */ 4980bee4c2cSEd Schouten char * 4996d8484b0SPhilippe Charnier name1(struct message *mp, int reptype) 5000bee4c2cSEd Schouten { 5010bee4c2cSEd Schouten char namebuf[LINESIZE]; 5020bee4c2cSEd Schouten char linebuf[LINESIZE]; 5030bee4c2cSEd Schouten char *cp, *cp2; 5040bee4c2cSEd Schouten FILE *ibuf; 5050bee4c2cSEd Schouten int first = 1; 5060bee4c2cSEd Schouten 5070bee4c2cSEd Schouten if ((cp = hfield("from", mp)) != NULL) 5080bee4c2cSEd Schouten return (cp); 5090bee4c2cSEd Schouten if (reptype == 0 && (cp = hfield("sender", mp)) != NULL) 5100bee4c2cSEd Schouten return (cp); 5110bee4c2cSEd Schouten ibuf = setinput(mp); 5120bee4c2cSEd Schouten namebuf[0] = '\0'; 5130bee4c2cSEd Schouten if (readline(ibuf, linebuf, LINESIZE) < 0) 5140bee4c2cSEd Schouten return (savestr(namebuf)); 5150bee4c2cSEd Schouten newname: 5160bee4c2cSEd Schouten for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++) 5170bee4c2cSEd Schouten ; 5180bee4c2cSEd Schouten for (; *cp == ' ' || *cp == '\t'; cp++) 5190bee4c2cSEd Schouten ; 5200bee4c2cSEd Schouten for (cp2 = &namebuf[strlen(namebuf)]; 5210bee4c2cSEd Schouten *cp != '\0' && *cp != ' ' && *cp != '\t' && 5220bee4c2cSEd Schouten cp2 < namebuf + LINESIZE - 1;) 5230bee4c2cSEd Schouten *cp2++ = *cp++; 5240bee4c2cSEd Schouten *cp2 = '\0'; 5250bee4c2cSEd Schouten if (readline(ibuf, linebuf, LINESIZE) < 0) 5260bee4c2cSEd Schouten return (savestr(namebuf)); 5270bee4c2cSEd Schouten if ((cp = strchr(linebuf, 'F')) == NULL) 5280bee4c2cSEd Schouten return (savestr(namebuf)); 5290bee4c2cSEd Schouten if (strncmp(cp, "From", 4) != 0) 5300bee4c2cSEd Schouten return (savestr(namebuf)); 5310bee4c2cSEd Schouten while ((cp = strchr(cp, 'r')) != NULL) { 5320bee4c2cSEd Schouten if (strncmp(cp, "remote", 6) == 0) { 5330bee4c2cSEd Schouten if ((cp = strchr(cp, 'f')) == NULL) 5340bee4c2cSEd Schouten break; 5350bee4c2cSEd Schouten if (strncmp(cp, "from", 4) != 0) 5360bee4c2cSEd Schouten break; 5370bee4c2cSEd Schouten if ((cp = strchr(cp, ' ')) == NULL) 5380bee4c2cSEd Schouten break; 5390bee4c2cSEd Schouten cp++; 5400bee4c2cSEd Schouten if (first) { 5410bee4c2cSEd Schouten cp2 = namebuf; 5420bee4c2cSEd Schouten first = 0; 5430bee4c2cSEd Schouten } else 5440bee4c2cSEd Schouten cp2 = strrchr(namebuf, '!') + 1; 5450bee4c2cSEd Schouten strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1); 5460bee4c2cSEd Schouten strcat(namebuf, "!"); 5470bee4c2cSEd Schouten goto newname; 5480bee4c2cSEd Schouten } 5490bee4c2cSEd Schouten cp++; 5500bee4c2cSEd Schouten } 5510bee4c2cSEd Schouten return (savestr(namebuf)); 5520bee4c2cSEd Schouten } 5530bee4c2cSEd Schouten 5540bee4c2cSEd Schouten /* 555389ae6c6SUlrich Spörlein * Count the occurrences of c in str 5560bee4c2cSEd Schouten */ 5570bee4c2cSEd Schouten int 5586d8484b0SPhilippe Charnier charcount(char *str, int c) 5590bee4c2cSEd Schouten { 5600bee4c2cSEd Schouten char *cp; 5610bee4c2cSEd Schouten int i; 5620bee4c2cSEd Schouten 5630bee4c2cSEd Schouten for (i = 0, cp = str; *cp != '\0'; cp++) 5640bee4c2cSEd Schouten if (*cp == c) 5650bee4c2cSEd Schouten i++; 5660bee4c2cSEd Schouten return (i); 5670bee4c2cSEd Schouten } 5680bee4c2cSEd Schouten 5690bee4c2cSEd Schouten /* 5700bee4c2cSEd Schouten * See if the given header field is supposed to be ignored. 5710bee4c2cSEd Schouten */ 5720bee4c2cSEd Schouten int 5736d8484b0SPhilippe Charnier isign(const char *field, struct ignoretab ignore[2]) 5740bee4c2cSEd Schouten { 5750bee4c2cSEd Schouten char realfld[LINESIZE]; 5760bee4c2cSEd Schouten 5770bee4c2cSEd Schouten if (ignore == ignoreall) 5780bee4c2cSEd Schouten return (1); 5790bee4c2cSEd Schouten /* 5800bee4c2cSEd Schouten * Lower-case the string, so that "Status" and "status" 5810bee4c2cSEd Schouten * will hash to the same place. 5820bee4c2cSEd Schouten */ 5830bee4c2cSEd Schouten istrncpy(realfld, field, sizeof(realfld)); 5840bee4c2cSEd Schouten if (ignore[1].i_count > 0) 5850bee4c2cSEd Schouten return (!member(realfld, ignore + 1)); 5860bee4c2cSEd Schouten else 5870bee4c2cSEd Schouten return (member(realfld, ignore)); 5880bee4c2cSEd Schouten } 5890bee4c2cSEd Schouten 5900bee4c2cSEd Schouten int 5916d8484b0SPhilippe Charnier member(char *realfield, struct ignoretab *table) 5920bee4c2cSEd Schouten { 5930bee4c2cSEd Schouten struct ignore *igp; 5940bee4c2cSEd Schouten 5950bee4c2cSEd Schouten for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link) 5960bee4c2cSEd Schouten if (*igp->i_field == *realfield && 5970bee4c2cSEd Schouten equal(igp->i_field, realfield)) 5980bee4c2cSEd Schouten return (1); 5990bee4c2cSEd Schouten return (0); 6000bee4c2cSEd Schouten } 601