Home | History | Annotate | Line # | Download | only in mail
head.c revision 1.21
      1 /*	$NetBSD: head.c,v 1.21 2007/10/23 14:58:44 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1980, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 #if 0
     35 static char sccsid[] = "@(#)head.c	8.2 (Berkeley) 4/20/95";
     36 #else
     37 __RCSID("$NetBSD: head.c,v 1.21 2007/10/23 14:58:44 christos Exp $");
     38 #endif
     39 #endif /* not lint */
     40 
     41 #include "rcv.h"
     42 #include "extern.h"
     43 
     44 /*
     45  * Mail -- a mail program
     46  *
     47  * Routines for processing and detecting headlines.
     48  */
     49 
     50 /*
     51  * Match the given string (cp) against the given template (tp).
     52  * Return 1 if they match, 0 if they don't
     53  */
     54 static int
     55 cmatch(const char *cp, char *tp)
     56 {
     57 
     58 	while (*cp && *tp)
     59 		switch (*tp++) {
     60 		case 'a':
     61 			if (!islower((unsigned char)*cp++))
     62 				return 0;
     63 			break;
     64 		case 'A':
     65 			if (!isupper((unsigned char)*cp++))
     66 				return 0;
     67 			break;
     68 		case ' ':
     69 			if (*cp++ != ' ')
     70 				return 0;
     71 			break;
     72 		case '0':
     73 			if (!isdigit((unsigned char)*cp++))
     74 				return 0;
     75 			break;
     76 		case 'O':
     77 			if (*cp != ' ' && !isdigit((unsigned char)*cp))
     78 				return 0;
     79 			cp++;
     80 			break;
     81 		case ':':
     82 			if (*cp++ != ':')
     83 				return 0;
     84 			break;
     85 		case 'N':
     86 			if (*cp++ != '\n')
     87 				return 0;
     88 			break;
     89 		}
     90 	if (*cp || *tp)
     91 		return 0;
     92 	return 1;
     93 }
     94 
     95 /*
     96  * Test to see if the passed string is a ctime(3) generated
     97  * date string as documented in the manual.  The template
     98  * below is used as the criterion of correctness.
     99  * Also, we check for a possible trailing time zone using
    100  * the tmztype template.
    101  */
    102 
    103 /*
    104  * 'A'	An upper case char
    105  * 'a'	A lower case char
    106  * ' '	A space
    107  * '0'	A digit
    108  * 'O'	An optional digit or space
    109  * ':'	A colon
    110  * 'N'	A new line
    111  */
    112 static char ctype[] = "Aaa Aaa O0 00:00:00 0000";
    113 static char SysV_ctype[] = "Aaa Aaa O0 00:00 0000";
    114 static char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000";
    115 static char SysV_tmztype[] = "Aaa Aaa O0 00:00 AAA 0000";
    116 
    117 static int
    118 isdate(const char date[])
    119 {
    120 
    121 	return cmatch(date, ctype) ||
    122 	       cmatch(date, tmztype) ||
    123 	       cmatch(date, SysV_tmztype) || cmatch(date, SysV_ctype);
    124 }
    125 
    126 static void
    127 fail(const char linebuf[], const char reason[])
    128 {
    129 #ifndef FMT_PROG
    130 	if (debug)
    131 		(void)fprintf(stderr, "\"%s\"\nnot a header because %s\n",
    132 		    linebuf, reason);
    133 #endif
    134 }
    135 
    136 /*
    137  * Collect a liberal (space, tab delimited) word into the word buffer
    138  * passed.  Also, return a pointer to the next word following that,
    139  * or NULL if none follow.
    140  */
    141 static const char *
    142 nextword(const char *wp, char *wbuf)
    143 {
    144 	if (wp == NULL) {
    145 		*wbuf = 0;
    146 		return NULL;
    147 	}
    148 	while (*wp && !is_WSP(*wp)) {
    149 		*wbuf++ = *wp;
    150 		if (*wp++ == '"') {
    151  			while (*wp && *wp != '"')
    152  				*wbuf++ = *wp++;
    153  			if (*wp == '"')
    154  				*wbuf++ = *wp++;
    155 		}
    156 	}
    157 	*wbuf = '\0';
    158 	wp = skip_WSP(wp);
    159 	if (*wp == '\0')
    160 		return NULL;
    161 	return wp;
    162 }
    163 
    164 /*
    165  * Copy the string on the left into the string on the right
    166  * and bump the right (reference) string pointer by the length.
    167  * Thus, dynamically allocate space in the right string, copying
    168  * the left string into it.
    169  */
    170 static char *
    171 copyin(const char *src, char **space)
    172 {
    173 	char *cp;
    174 	char *begin;
    175 
    176 	begin = cp = *space;
    177 	while ((*cp++ = *src++) != '\0')
    178 		continue;
    179 	*space = cp;
    180 	return begin;
    181 }
    182 
    183 /*
    184  * Split a headline into its useful components.
    185  * Copy the line into dynamic string space, then set
    186  * pointers into the copied line in the passed headline
    187  * structure.  Actually, it scans.
    188  *
    189  * XXX - line[], pbuf[], and word[] must be LINESIZE in length or
    190  * overflow can occur in nextword() or copyin().
    191  */
    192 PUBLIC void
    193 parse(const char line[], struct headline *hl, char pbuf[])
    194 {
    195 	const char *cp;
    196 	char *sp;
    197 	char word[LINESIZE];
    198 
    199 	hl->l_from = NULL;
    200 	hl->l_tty = NULL;
    201 	hl->l_date = NULL;
    202 	cp = line;
    203 	sp = pbuf;
    204 	/*
    205 	 * Skip over "From" first.
    206 	 */
    207 	cp = nextword(cp, word);
    208 	cp = nextword(cp, word);
    209 	if (*word)
    210 		hl->l_from = copyin(word, &sp);
    211 	if (cp != NULL && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
    212 		cp = nextword(cp, word);
    213 		hl->l_tty = copyin(word, &sp);
    214 	}
    215 	if (cp != NULL)
    216 		hl->l_date = copyin(cp, &sp);
    217 }
    218 
    219 /*
    220  * See if the passed line buffer is a mail header.
    221  * Return true if yes.  Note the extreme pains to
    222  * accomodate all funny formats.
    223  */
    224 PUBLIC int
    225 ishead(const char linebuf[])
    226 {
    227 	const char *cp;
    228 	struct headline hl;
    229 	char parbuf[LINESIZE];
    230 
    231 	cp = linebuf;
    232 	if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' ||
    233 	    *cp++ != ' ')
    234 		return 0;
    235 	parse(linebuf, &hl, parbuf);
    236 	if (hl.l_from == NULL || hl.l_date == NULL) {
    237 		fail(linebuf, "No from or date field");
    238 		return 0;
    239 	}
    240 	if (!isdate(hl.l_date)) {
    241 		fail(linebuf, "Date field not legal date");
    242 		return 0;
    243 	}
    244 	/*
    245 	 * I guess we got it!
    246 	 */
    247 	return 1;
    248 }
    249