18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro 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 #include <sys/time.h>
330bee4c2cSEd Schouten
34ae7d5745SJilles Tjoelker #include <fcntl.h>
35ae7d5745SJilles Tjoelker
360bee4c2cSEd Schouten #include "rcv.h"
370bee4c2cSEd Schouten #include "extern.h"
380bee4c2cSEd Schouten
390bee4c2cSEd Schouten /*
400bee4c2cSEd Schouten * Mail -- a mail program
410bee4c2cSEd Schouten *
420bee4c2cSEd Schouten * Auxiliary functions.
430bee4c2cSEd Schouten */
440bee4c2cSEd Schouten
450bee4c2cSEd Schouten static char *save2str(char *, char *);
460bee4c2cSEd Schouten
470bee4c2cSEd Schouten /*
480bee4c2cSEd Schouten * Return a pointer to a dynamic copy of the argument.
490bee4c2cSEd Schouten */
500bee4c2cSEd Schouten char *
savestr(char * str)516d8484b0SPhilippe Charnier savestr(char *str)
520bee4c2cSEd Schouten {
530bee4c2cSEd Schouten char *new;
540bee4c2cSEd Schouten int size = strlen(str) + 1;
550bee4c2cSEd Schouten
560bee4c2cSEd Schouten if ((new = salloc(size)) != NULL)
570bee4c2cSEd Schouten bcopy(str, new, size);
580bee4c2cSEd Schouten return (new);
590bee4c2cSEd Schouten }
600bee4c2cSEd Schouten
610bee4c2cSEd Schouten /*
620bee4c2cSEd Schouten * Make a copy of new argument incorporating old one.
630bee4c2cSEd Schouten */
640bee4c2cSEd Schouten static char *
save2str(char * str,char * old)656d8484b0SPhilippe Charnier save2str(char *str, char *old)
660bee4c2cSEd Schouten {
670bee4c2cSEd Schouten char *new;
680bee4c2cSEd Schouten int newsize = strlen(str) + 1;
690bee4c2cSEd Schouten int oldsize = old ? strlen(old) + 1 : 0;
700bee4c2cSEd Schouten
710bee4c2cSEd Schouten if ((new = salloc(newsize + oldsize)) != NULL) {
720bee4c2cSEd Schouten if (oldsize) {
730bee4c2cSEd Schouten bcopy(old, new, oldsize);
740bee4c2cSEd Schouten new[oldsize - 1] = ' ';
750bee4c2cSEd Schouten }
760bee4c2cSEd Schouten bcopy(str, new + oldsize, newsize);
770bee4c2cSEd Schouten }
780bee4c2cSEd Schouten return (new);
790bee4c2cSEd Schouten }
800bee4c2cSEd Schouten
810bee4c2cSEd Schouten /*
820bee4c2cSEd Schouten * Touch the named message by setting its MTOUCH flag.
830bee4c2cSEd Schouten * Touched messages have the effect of not being sent
840bee4c2cSEd Schouten * back to the system mailbox on exit.
850bee4c2cSEd Schouten */
860bee4c2cSEd Schouten void
touch(struct message * mp)876d8484b0SPhilippe Charnier touch(struct message *mp)
880bee4c2cSEd Schouten {
890bee4c2cSEd Schouten
900bee4c2cSEd Schouten mp->m_flag |= MTOUCH;
910bee4c2cSEd Schouten if ((mp->m_flag & MREAD) == 0)
920bee4c2cSEd Schouten mp->m_flag |= MREAD|MSTATUS;
930bee4c2cSEd Schouten }
940bee4c2cSEd Schouten
950bee4c2cSEd Schouten /*
960bee4c2cSEd Schouten * Test to see if the passed file name is a directory.
970bee4c2cSEd Schouten * Return true if it is.
980bee4c2cSEd Schouten */
990bee4c2cSEd Schouten int
isdir(char name[])1006d8484b0SPhilippe Charnier isdir(char name[])
1010bee4c2cSEd Schouten {
1020bee4c2cSEd Schouten struct stat sbuf;
1030bee4c2cSEd Schouten
1040bee4c2cSEd Schouten if (stat(name, &sbuf) < 0)
1050bee4c2cSEd Schouten return (0);
1060bee4c2cSEd Schouten return (S_ISDIR(sbuf.st_mode));
1070bee4c2cSEd Schouten }
1080bee4c2cSEd Schouten
1090bee4c2cSEd Schouten /*
1100bee4c2cSEd Schouten * Count the number of arguments in the given string raw list.
1110bee4c2cSEd Schouten */
1120bee4c2cSEd Schouten int
argcount(char ** argv)1136d8484b0SPhilippe Charnier argcount(char **argv)
1140bee4c2cSEd Schouten {
1150bee4c2cSEd Schouten char **ap;
1160bee4c2cSEd Schouten
1170bee4c2cSEd Schouten for (ap = argv; *ap++ != NULL;)
1180bee4c2cSEd Schouten ;
1190bee4c2cSEd Schouten return (ap - argv - 1);
1200bee4c2cSEd Schouten }
1210bee4c2cSEd Schouten
1220bee4c2cSEd Schouten /*
1230bee4c2cSEd Schouten * Return the desired header line from the passed message
1240bee4c2cSEd Schouten * pointer (or NULL if the desired header field is not available).
1250bee4c2cSEd Schouten */
1260bee4c2cSEd Schouten char *
hfield(const char * field,struct message * mp)1276d8484b0SPhilippe Charnier hfield(const char *field, struct message *mp)
1280bee4c2cSEd Schouten {
1290bee4c2cSEd Schouten FILE *ibuf;
1300bee4c2cSEd Schouten char linebuf[LINESIZE];
1310bee4c2cSEd Schouten int lc;
1320bee4c2cSEd Schouten char *hfield;
1330bee4c2cSEd Schouten char *colon, *oldhfield = NULL;
1340bee4c2cSEd Schouten
1350bee4c2cSEd Schouten ibuf = setinput(mp);
1360bee4c2cSEd Schouten if ((lc = mp->m_lines - 1) < 0)
1370bee4c2cSEd Schouten return (NULL);
1380bee4c2cSEd Schouten if (readline(ibuf, linebuf, LINESIZE) < 0)
1390bee4c2cSEd Schouten return (NULL);
1400bee4c2cSEd Schouten while (lc > 0) {
1410bee4c2cSEd Schouten if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
1420bee4c2cSEd Schouten return (oldhfield);
1430bee4c2cSEd Schouten if ((hfield = ishfield(linebuf, colon, field)) != NULL)
1440bee4c2cSEd Schouten oldhfield = save2str(hfield, oldhfield);
1450bee4c2cSEd Schouten }
1460bee4c2cSEd Schouten return (oldhfield);
1470bee4c2cSEd Schouten }
1480bee4c2cSEd Schouten
1490bee4c2cSEd Schouten /*
1500bee4c2cSEd Schouten * Return the next header field found in the given message.
1510bee4c2cSEd Schouten * Return >= 0 if something found, < 0 elsewise.
1520bee4c2cSEd Schouten * "colon" is set to point to the colon in the header.
1530bee4c2cSEd Schouten * Must deal with \ continuations & other such fraud.
1540bee4c2cSEd Schouten */
1550bee4c2cSEd Schouten int
gethfield(FILE * f,char linebuf[],int rem,char ** colon)1566d8484b0SPhilippe Charnier gethfield(FILE *f, char linebuf[], int rem, char **colon)
1570bee4c2cSEd Schouten {
1580bee4c2cSEd Schouten char line2[LINESIZE];
1590bee4c2cSEd Schouten char *cp, *cp2;
1600bee4c2cSEd Schouten int c;
1610bee4c2cSEd Schouten
1620bee4c2cSEd Schouten for (;;) {
1630bee4c2cSEd Schouten if (--rem < 0)
1640bee4c2cSEd Schouten return (-1);
1650bee4c2cSEd Schouten if ((c = readline(f, linebuf, LINESIZE)) <= 0)
1660bee4c2cSEd Schouten return (-1);
1670bee4c2cSEd Schouten for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':';
1680bee4c2cSEd Schouten cp++)
1690bee4c2cSEd Schouten ;
1700bee4c2cSEd Schouten if (*cp != ':' || cp == linebuf)
1710bee4c2cSEd Schouten continue;
1720bee4c2cSEd Schouten /*
1730bee4c2cSEd Schouten * I guess we got a headline.
1740bee4c2cSEd Schouten * Handle wraparounding
1750bee4c2cSEd Schouten */
1760bee4c2cSEd Schouten *colon = cp;
1770bee4c2cSEd Schouten cp = linebuf + c;
1780bee4c2cSEd Schouten for (;;) {
1790bee4c2cSEd Schouten while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
1800bee4c2cSEd Schouten ;
1810bee4c2cSEd Schouten cp++;
1820bee4c2cSEd Schouten if (rem <= 0)
1830bee4c2cSEd Schouten break;
1840bee4c2cSEd Schouten ungetc(c = getc(f), f);
1850bee4c2cSEd Schouten if (c != ' ' && c != '\t')
1860bee4c2cSEd Schouten break;
1870bee4c2cSEd Schouten if ((c = readline(f, line2, LINESIZE)) < 0)
1880bee4c2cSEd Schouten break;
1890bee4c2cSEd Schouten rem--;
1900bee4c2cSEd Schouten for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
1910bee4c2cSEd Schouten ;
1920bee4c2cSEd Schouten c -= cp2 - line2;
1930bee4c2cSEd Schouten if (cp + c >= linebuf + LINESIZE - 2)
1940bee4c2cSEd Schouten break;
1950bee4c2cSEd Schouten *cp++ = ' ';
1960bee4c2cSEd Schouten bcopy(cp2, cp, c);
1970bee4c2cSEd Schouten cp += c;
1980bee4c2cSEd Schouten }
1990bee4c2cSEd Schouten *cp = 0;
2000bee4c2cSEd Schouten return (rem);
2010bee4c2cSEd Schouten }
2020bee4c2cSEd Schouten /* NOTREACHED */
2030bee4c2cSEd Schouten }
2040bee4c2cSEd Schouten
2050bee4c2cSEd Schouten /*
2060bee4c2cSEd Schouten * Check whether the passed line is a header line of
2070bee4c2cSEd Schouten * the desired breed. Return the field body, or 0.
2080bee4c2cSEd Schouten */
2090bee4c2cSEd Schouten
2100bee4c2cSEd Schouten char*
ishfield(char * linebuf,char * colon,const char * field)211eeb341a9SPedro F. Giffuni ishfield(char *linebuf, char *colon, const char *field)
2120bee4c2cSEd Schouten {
2130bee4c2cSEd Schouten char *cp = colon;
2140bee4c2cSEd Schouten
2150bee4c2cSEd Schouten *cp = 0;
2160bee4c2cSEd Schouten if (strcasecmp(linebuf, field) != 0) {
2170bee4c2cSEd Schouten *cp = ':';
2180bee4c2cSEd Schouten return (0);
2190bee4c2cSEd Schouten }
2200bee4c2cSEd Schouten *cp = ':';
2210bee4c2cSEd Schouten for (cp++; *cp == ' ' || *cp == '\t'; cp++)
2220bee4c2cSEd Schouten ;
2230bee4c2cSEd Schouten return (cp);
2240bee4c2cSEd Schouten }
2250bee4c2cSEd Schouten
2260bee4c2cSEd Schouten /*
2270bee4c2cSEd Schouten * Copy a string and lowercase the result.
2280bee4c2cSEd Schouten * dsize: space left in buffer (including space for NULL)
2290bee4c2cSEd Schouten */
2300bee4c2cSEd Schouten void
istrncpy(char * dest,const char * src,size_t dsize)2316d8484b0SPhilippe Charnier istrncpy(char *dest, const char *src, size_t dsize)
2320bee4c2cSEd Schouten {
2330bee4c2cSEd Schouten
2340bee4c2cSEd Schouten strlcpy(dest, src, dsize);
235ca83b975SDimitry Andric for (; *dest; dest++)
236ca83b975SDimitry Andric *dest = tolower((unsigned char)*dest);
2370bee4c2cSEd Schouten }
2380bee4c2cSEd Schouten
2390bee4c2cSEd Schouten /*
2400bee4c2cSEd Schouten * The following code deals with input stacking to do source
2410bee4c2cSEd Schouten * commands. All but the current file pointer are saved on
2420bee4c2cSEd Schouten * the stack.
2430bee4c2cSEd Schouten */
2440bee4c2cSEd Schouten
2450bee4c2cSEd Schouten static int ssp; /* Top of file stack */
2460bee4c2cSEd Schouten struct sstack {
2470bee4c2cSEd Schouten FILE *s_file; /* File we were in. */
2480bee4c2cSEd Schouten int s_cond; /* Saved state of conditionals */
2490bee4c2cSEd Schouten int s_loading; /* Loading .mailrc, etc. */
2500bee4c2cSEd Schouten };
2510bee4c2cSEd Schouten #define SSTACK_SIZE 64 /* XXX was NOFILE. */
2520bee4c2cSEd Schouten static struct sstack sstack[SSTACK_SIZE];
2530bee4c2cSEd Schouten
2540bee4c2cSEd Schouten /*
2550bee4c2cSEd Schouten * Pushdown current input file and switch to a new one.
2560bee4c2cSEd Schouten * Set the global flag "sourcing" so that others will realize
2570bee4c2cSEd Schouten * that they are no longer reading from a tty (in all probability).
2580bee4c2cSEd Schouten */
2590bee4c2cSEd Schouten int
source(void * arg)260*d28a9551SJohn Baldwin source(void *arg)
2610bee4c2cSEd Schouten {
262*d28a9551SJohn Baldwin char **arglist = arg;
2630bee4c2cSEd Schouten FILE *fi;
2640bee4c2cSEd Schouten char *cp;
2650bee4c2cSEd Schouten
2660bee4c2cSEd Schouten if ((cp = expand(*arglist)) == NULL)
2670bee4c2cSEd Schouten return (1);
2680bee4c2cSEd Schouten if ((fi = Fopen(cp, "r")) == NULL) {
2690bee4c2cSEd Schouten warn("%s", cp);
2700bee4c2cSEd Schouten return (1);
2710bee4c2cSEd Schouten }
2720bee4c2cSEd Schouten if (ssp >= SSTACK_SIZE - 1) {
2730bee4c2cSEd Schouten printf("Too much \"sourcing\" going on.\n");
2740bee4c2cSEd Schouten (void)Fclose(fi);
2750bee4c2cSEd Schouten return (1);
2760bee4c2cSEd Schouten }
2770bee4c2cSEd Schouten sstack[ssp].s_file = input;
2780bee4c2cSEd Schouten sstack[ssp].s_cond = cond;
2790bee4c2cSEd Schouten sstack[ssp].s_loading = loading;
2800bee4c2cSEd Schouten ssp++;
2810bee4c2cSEd Schouten loading = 0;
2820bee4c2cSEd Schouten cond = CANY;
2830bee4c2cSEd Schouten input = fi;
2840bee4c2cSEd Schouten sourcing++;
2850bee4c2cSEd Schouten return (0);
2860bee4c2cSEd Schouten }
2870bee4c2cSEd Schouten
2880bee4c2cSEd Schouten /*
2890bee4c2cSEd Schouten * Pop the current input back to the previous level.
2900bee4c2cSEd Schouten * Update the "sourcing" flag as appropriate.
2910bee4c2cSEd Schouten */
2920bee4c2cSEd Schouten int
unstack(void)2936d8484b0SPhilippe Charnier unstack(void)
2940bee4c2cSEd Schouten {
2950bee4c2cSEd Schouten if (ssp <= 0) {
2960bee4c2cSEd Schouten printf("\"Source\" stack over-pop.\n");
2970bee4c2cSEd Schouten sourcing = 0;
2980bee4c2cSEd Schouten return (1);
2990bee4c2cSEd Schouten }
3000bee4c2cSEd Schouten (void)Fclose(input);
3010bee4c2cSEd Schouten if (cond != CANY)
3020bee4c2cSEd Schouten printf("Unmatched \"if\"\n");
3030bee4c2cSEd Schouten ssp--;
3040bee4c2cSEd Schouten cond = sstack[ssp].s_cond;
3050bee4c2cSEd Schouten loading = sstack[ssp].s_loading;
3060bee4c2cSEd Schouten input = sstack[ssp].s_file;
3070bee4c2cSEd Schouten if (ssp == 0)
3080bee4c2cSEd Schouten sourcing = loading;
3090bee4c2cSEd Schouten return (0);
3100bee4c2cSEd Schouten }
3110bee4c2cSEd Schouten
3120bee4c2cSEd Schouten /*
3130bee4c2cSEd Schouten * Touch the indicated file.
3140bee4c2cSEd Schouten * This is nifty for the shell.
3150bee4c2cSEd Schouten */
3160bee4c2cSEd Schouten void
alter(char * name)3176d8484b0SPhilippe Charnier alter(char *name)
3180bee4c2cSEd Schouten {
319ae7d5745SJilles Tjoelker struct timespec ts[2];
3200bee4c2cSEd Schouten
321ae7d5745SJilles Tjoelker (void)clock_gettime(CLOCK_REALTIME, &ts[0]);
322ae7d5745SJilles Tjoelker ts[0].tv_sec++;
323ae7d5745SJilles Tjoelker ts[1].tv_sec = 0;
324ae7d5745SJilles Tjoelker ts[1].tv_nsec = UTIME_OMIT;
325ae7d5745SJilles Tjoelker (void)utimensat(AT_FDCWD, name, ts, 0);
3260bee4c2cSEd Schouten }
3270bee4c2cSEd Schouten
3280bee4c2cSEd Schouten /*
3290bee4c2cSEd Schouten * Get sender's name from this message. If the message has
3300bee4c2cSEd Schouten * a bunch of arpanet stuff in it, we may have to skin the name
3310bee4c2cSEd Schouten * before returning it.
3320bee4c2cSEd Schouten */
3330bee4c2cSEd Schouten char *
nameof(struct message * mp,int reptype)3346d8484b0SPhilippe Charnier nameof(struct message *mp, int reptype)
3350bee4c2cSEd Schouten {
3360bee4c2cSEd Schouten char *cp, *cp2;
3370bee4c2cSEd Schouten
3380bee4c2cSEd Schouten cp = skin(name1(mp, reptype));
3390bee4c2cSEd Schouten if (reptype != 0 || charcount(cp, '!') < 2)
3400bee4c2cSEd Schouten return (cp);
3410bee4c2cSEd Schouten cp2 = strrchr(cp, '!');
3420bee4c2cSEd Schouten cp2--;
3430bee4c2cSEd Schouten while (cp2 > cp && *cp2 != '!')
3440bee4c2cSEd Schouten cp2--;
3450bee4c2cSEd Schouten if (*cp2 == '!')
3460bee4c2cSEd Schouten return (cp2 + 1);
3470bee4c2cSEd Schouten return (cp);
3480bee4c2cSEd Schouten }
3490bee4c2cSEd Schouten
3500bee4c2cSEd Schouten /*
3510bee4c2cSEd Schouten * Start of a "comment".
3520bee4c2cSEd Schouten * Ignore it.
3530bee4c2cSEd Schouten */
3540bee4c2cSEd Schouten char *
skip_comment(char * cp)3556d8484b0SPhilippe Charnier skip_comment(char *cp)
3560bee4c2cSEd Schouten {
3570bee4c2cSEd Schouten int nesting = 1;
3580bee4c2cSEd Schouten
3590bee4c2cSEd Schouten for (; nesting > 0 && *cp; cp++) {
3600bee4c2cSEd Schouten switch (*cp) {
3610bee4c2cSEd Schouten case '\\':
3620bee4c2cSEd Schouten if (cp[1])
3630bee4c2cSEd Schouten cp++;
3640bee4c2cSEd Schouten break;
3650bee4c2cSEd Schouten case '(':
3660bee4c2cSEd Schouten nesting++;
3670bee4c2cSEd Schouten break;
3680bee4c2cSEd Schouten case ')':
3690bee4c2cSEd Schouten nesting--;
3700bee4c2cSEd Schouten break;
3710bee4c2cSEd Schouten }
3720bee4c2cSEd Schouten }
3730bee4c2cSEd Schouten return (cp);
3740bee4c2cSEd Schouten }
3750bee4c2cSEd Schouten
3760bee4c2cSEd Schouten /*
3770bee4c2cSEd Schouten * Skin an arpa net address according to the RFC 822 interpretation
3780bee4c2cSEd Schouten * of "host-phrase."
3790bee4c2cSEd Schouten */
3800bee4c2cSEd Schouten char *
skin(char * name)3816d8484b0SPhilippe Charnier skin(char *name)
3820bee4c2cSEd Schouten {
3830bee4c2cSEd Schouten char *nbuf, *bufend, *cp, *cp2;
3840bee4c2cSEd Schouten int c, gotlt, lastsp;
3850bee4c2cSEd Schouten
3860bee4c2cSEd Schouten if (name == NULL)
3870bee4c2cSEd Schouten return (NULL);
3880bee4c2cSEd Schouten if (strchr(name, '(') == NULL && strchr(name, '<') == NULL
3890bee4c2cSEd Schouten && strchr(name, ' ') == NULL)
3900bee4c2cSEd Schouten return (name);
3910bee4c2cSEd Schouten
3920bee4c2cSEd Schouten /* We assume that length(input) <= length(output) */
3930bee4c2cSEd Schouten if ((nbuf = malloc(strlen(name) + 1)) == NULL)
3940bee4c2cSEd Schouten err(1, "Out of memory");
3950bee4c2cSEd Schouten gotlt = 0;
3960bee4c2cSEd Schouten lastsp = 0;
3970bee4c2cSEd Schouten bufend = nbuf;
3980bee4c2cSEd Schouten for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) {
3990bee4c2cSEd Schouten switch (c) {
4000bee4c2cSEd Schouten case '(':
4010bee4c2cSEd Schouten cp = skip_comment(cp);
4020bee4c2cSEd Schouten lastsp = 0;
4030bee4c2cSEd Schouten break;
4040bee4c2cSEd Schouten
4050bee4c2cSEd Schouten case '"':
4060bee4c2cSEd Schouten /*
4070bee4c2cSEd Schouten * Start of a "quoted-string".
4080bee4c2cSEd Schouten * Copy it in its entirety.
4090bee4c2cSEd Schouten */
4100bee4c2cSEd Schouten while ((c = *cp) != '\0') {
4110bee4c2cSEd Schouten cp++;
4120bee4c2cSEd Schouten if (c == '"')
4130bee4c2cSEd Schouten break;
4140bee4c2cSEd Schouten if (c != '\\')
4150bee4c2cSEd Schouten *cp2++ = c;
4160bee4c2cSEd Schouten else if ((c = *cp) != '\0') {
4170bee4c2cSEd Schouten *cp2++ = c;
4180bee4c2cSEd Schouten cp++;
4190bee4c2cSEd Schouten }
4200bee4c2cSEd Schouten }
4210bee4c2cSEd Schouten lastsp = 0;
4220bee4c2cSEd Schouten break;
4230bee4c2cSEd Schouten
4240bee4c2cSEd Schouten case ' ':
4250bee4c2cSEd Schouten if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
4260bee4c2cSEd Schouten cp += 3, *cp2++ = '@';
4270bee4c2cSEd Schouten else
4280bee4c2cSEd Schouten if (cp[0] == '@' && cp[1] == ' ')
4290bee4c2cSEd Schouten cp += 2, *cp2++ = '@';
4300bee4c2cSEd Schouten else
4310bee4c2cSEd Schouten lastsp = 1;
4320bee4c2cSEd Schouten break;
4330bee4c2cSEd Schouten
4340bee4c2cSEd Schouten case '<':
4350bee4c2cSEd Schouten cp2 = bufend;
4360bee4c2cSEd Schouten gotlt++;
4370bee4c2cSEd Schouten lastsp = 0;
4380bee4c2cSEd Schouten break;
4390bee4c2cSEd Schouten
4400bee4c2cSEd Schouten case '>':
4410bee4c2cSEd Schouten if (gotlt) {
4420bee4c2cSEd Schouten gotlt = 0;
4430bee4c2cSEd Schouten while ((c = *cp) != '\0' && c != ',') {
4440bee4c2cSEd Schouten cp++;
4450bee4c2cSEd Schouten if (c == '(')
4460bee4c2cSEd Schouten cp = skip_comment(cp);
4470bee4c2cSEd Schouten else if (c == '"')
4480bee4c2cSEd Schouten while ((c = *cp) != '\0') {
4490bee4c2cSEd Schouten cp++;
4500bee4c2cSEd Schouten if (c == '"')
4510bee4c2cSEd Schouten break;
4520bee4c2cSEd Schouten if (c == '\\' && *cp != '\0')
4530bee4c2cSEd Schouten cp++;
4540bee4c2cSEd Schouten }
4550bee4c2cSEd Schouten }
4560bee4c2cSEd Schouten lastsp = 0;
4570bee4c2cSEd Schouten break;
4580bee4c2cSEd Schouten }
4590bee4c2cSEd Schouten /* FALLTHROUGH */
4600bee4c2cSEd Schouten
4610bee4c2cSEd Schouten default:
4620bee4c2cSEd Schouten if (lastsp) {
4630bee4c2cSEd Schouten lastsp = 0;
4640bee4c2cSEd Schouten *cp2++ = ' ';
4650bee4c2cSEd Schouten }
4660bee4c2cSEd Schouten *cp2++ = c;
467a1d170a0SUlrich Spörlein if (c == ',' && !gotlt &&
468a1d170a0SUlrich Spörlein (*cp == ' ' || *cp == '"' || *cp == '<')) {
4690bee4c2cSEd Schouten *cp2++ = ' ';
470a1d170a0SUlrich Spörlein while (*cp == ' ')
471a1d170a0SUlrich Spörlein cp++;
4720bee4c2cSEd Schouten lastsp = 0;
4730bee4c2cSEd Schouten bufend = cp2;
4740bee4c2cSEd Schouten }
4750bee4c2cSEd Schouten }
4760bee4c2cSEd Schouten }
4770bee4c2cSEd Schouten *cp2 = '\0';
4780bee4c2cSEd Schouten
4790bee4c2cSEd Schouten if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL)
4800bee4c2cSEd Schouten nbuf = cp;
4810bee4c2cSEd Schouten return (nbuf);
4820bee4c2cSEd Schouten }
4830bee4c2cSEd Schouten
4840bee4c2cSEd Schouten /*
4850bee4c2cSEd Schouten * Fetch the sender's name from the passed message.
4860bee4c2cSEd Schouten * Reptype can be
4870bee4c2cSEd Schouten * 0 -- get sender's name for display purposes
4880bee4c2cSEd Schouten * 1 -- get sender's name for reply
4890bee4c2cSEd Schouten * 2 -- get sender's name for Reply
4900bee4c2cSEd Schouten */
4910bee4c2cSEd Schouten char *
name1(struct message * mp,int reptype)4926d8484b0SPhilippe Charnier name1(struct message *mp, int reptype)
4930bee4c2cSEd Schouten {
4940bee4c2cSEd Schouten char namebuf[LINESIZE];
4950bee4c2cSEd Schouten char linebuf[LINESIZE];
4960bee4c2cSEd Schouten char *cp, *cp2;
4970bee4c2cSEd Schouten FILE *ibuf;
4980bee4c2cSEd Schouten int first = 1;
4990bee4c2cSEd Schouten
5000bee4c2cSEd Schouten if ((cp = hfield("from", mp)) != NULL)
5010bee4c2cSEd Schouten return (cp);
5020bee4c2cSEd Schouten if (reptype == 0 && (cp = hfield("sender", mp)) != NULL)
5030bee4c2cSEd Schouten return (cp);
5040bee4c2cSEd Schouten ibuf = setinput(mp);
5050bee4c2cSEd Schouten namebuf[0] = '\0';
5060bee4c2cSEd Schouten if (readline(ibuf, linebuf, LINESIZE) < 0)
5070bee4c2cSEd Schouten return (savestr(namebuf));
5080bee4c2cSEd Schouten newname:
5090bee4c2cSEd Schouten for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++)
5100bee4c2cSEd Schouten ;
5110bee4c2cSEd Schouten for (; *cp == ' ' || *cp == '\t'; cp++)
5120bee4c2cSEd Schouten ;
5130bee4c2cSEd Schouten for (cp2 = &namebuf[strlen(namebuf)];
5140bee4c2cSEd Schouten *cp != '\0' && *cp != ' ' && *cp != '\t' &&
5150bee4c2cSEd Schouten cp2 < namebuf + LINESIZE - 1;)
5160bee4c2cSEd Schouten *cp2++ = *cp++;
5170bee4c2cSEd Schouten *cp2 = '\0';
5180bee4c2cSEd Schouten if (readline(ibuf, linebuf, LINESIZE) < 0)
5190bee4c2cSEd Schouten return (savestr(namebuf));
5200bee4c2cSEd Schouten if ((cp = strchr(linebuf, 'F')) == NULL)
5210bee4c2cSEd Schouten return (savestr(namebuf));
5220bee4c2cSEd Schouten if (strncmp(cp, "From", 4) != 0)
5230bee4c2cSEd Schouten return (savestr(namebuf));
5240bee4c2cSEd Schouten while ((cp = strchr(cp, 'r')) != NULL) {
5250bee4c2cSEd Schouten if (strncmp(cp, "remote", 6) == 0) {
5260bee4c2cSEd Schouten if ((cp = strchr(cp, 'f')) == NULL)
5270bee4c2cSEd Schouten break;
5280bee4c2cSEd Schouten if (strncmp(cp, "from", 4) != 0)
5290bee4c2cSEd Schouten break;
5300bee4c2cSEd Schouten if ((cp = strchr(cp, ' ')) == NULL)
5310bee4c2cSEd Schouten break;
5320bee4c2cSEd Schouten cp++;
5330bee4c2cSEd Schouten if (first) {
5340bee4c2cSEd Schouten cp2 = namebuf;
5350bee4c2cSEd Schouten first = 0;
5360bee4c2cSEd Schouten } else
5370bee4c2cSEd Schouten cp2 = strrchr(namebuf, '!') + 1;
5380bee4c2cSEd Schouten strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1);
5390bee4c2cSEd Schouten strcat(namebuf, "!");
5400bee4c2cSEd Schouten goto newname;
5410bee4c2cSEd Schouten }
5420bee4c2cSEd Schouten cp++;
5430bee4c2cSEd Schouten }
5440bee4c2cSEd Schouten return (savestr(namebuf));
5450bee4c2cSEd Schouten }
5460bee4c2cSEd Schouten
5470bee4c2cSEd Schouten /*
548389ae6c6SUlrich Spörlein * Count the occurrences of c in str
5490bee4c2cSEd Schouten */
5500bee4c2cSEd Schouten int
charcount(char * str,int c)5516d8484b0SPhilippe Charnier charcount(char *str, int c)
5520bee4c2cSEd Schouten {
5530bee4c2cSEd Schouten char *cp;
5540bee4c2cSEd Schouten int i;
5550bee4c2cSEd Schouten
5560bee4c2cSEd Schouten for (i = 0, cp = str; *cp != '\0'; cp++)
5570bee4c2cSEd Schouten if (*cp == c)
5580bee4c2cSEd Schouten i++;
5590bee4c2cSEd Schouten return (i);
5600bee4c2cSEd Schouten }
5610bee4c2cSEd Schouten
5620bee4c2cSEd Schouten /*
5630bee4c2cSEd Schouten * See if the given header field is supposed to be ignored.
5640bee4c2cSEd Schouten */
5650bee4c2cSEd Schouten int
isign(const char * field,struct ignoretab ignore[2])5666d8484b0SPhilippe Charnier isign(const char *field, struct ignoretab ignore[2])
5670bee4c2cSEd Schouten {
5680bee4c2cSEd Schouten char realfld[LINESIZE];
5690bee4c2cSEd Schouten
5700bee4c2cSEd Schouten if (ignore == ignoreall)
5710bee4c2cSEd Schouten return (1);
5720bee4c2cSEd Schouten /*
5730bee4c2cSEd Schouten * Lower-case the string, so that "Status" and "status"
5740bee4c2cSEd Schouten * will hash to the same place.
5750bee4c2cSEd Schouten */
5760bee4c2cSEd Schouten istrncpy(realfld, field, sizeof(realfld));
5770bee4c2cSEd Schouten if (ignore[1].i_count > 0)
5780bee4c2cSEd Schouten return (!member(realfld, ignore + 1));
5790bee4c2cSEd Schouten else
5800bee4c2cSEd Schouten return (member(realfld, ignore));
5810bee4c2cSEd Schouten }
5820bee4c2cSEd Schouten
5830bee4c2cSEd Schouten int
member(char * realfield,struct ignoretab * table)5846d8484b0SPhilippe Charnier member(char *realfield, struct ignoretab *table)
5850bee4c2cSEd Schouten {
5860bee4c2cSEd Schouten struct ignore *igp;
5870bee4c2cSEd Schouten
5880bee4c2cSEd Schouten for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link)
5890bee4c2cSEd Schouten if (*igp->i_field == *realfield &&
5900bee4c2cSEd Schouten equal(igp->i_field, realfield))
5910bee4c2cSEd Schouten return (1);
5920bee4c2cSEd Schouten return (0);
5930bee4c2cSEd Schouten }
594