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