xref: /csrg-svn/usr.bin/mail/head.c (revision 68818)
122455Sdist /*
262083Sbostic  * Copyright (c) 1980, 1993
362083Sbostic  *	The Regents of the University of California.  All rights reserved.
433499Sbostic  *
542741Sbostic  * %sccs.include.redist.c%
622455Sdist  */
722455Sdist 
834905Sbostic #ifndef lint
9*68818Sdab static char sccsid[] = "@(#)head.c	8.2 (Berkeley) 04/20/95";
1034905Sbostic #endif /* not lint */
111234Skas 
121234Skas #include "rcv.h"
1354505Sbostic #include "extern.h"
141234Skas 
151234Skas /*
161234Skas  * Mail -- a mail program
171234Skas  *
181234Skas  * Routines for processing and detecting headlines.
191234Skas  */
201234Skas 
211234Skas /*
221234Skas  * See if the passed line buffer is a mail header.
231234Skas  * Return true if yes.  Note the extreme pains to
241234Skas  * accomodate all funny formats.
251234Skas  */
2654505Sbostic int
ishead(linebuf)271234Skas ishead(linebuf)
281234Skas 	char linebuf[];
291234Skas {
301234Skas 	register char *cp;
311234Skas 	struct headline hl;
321234Skas 	char parbuf[BUFSIZ];
331234Skas 
341234Skas 	cp = linebuf;
3531142Sedward 	if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' ||
3631142Sedward 	    *cp++ != ' ')
3731142Sedward 		return (0);
3831142Sedward 	parse(linebuf, &hl, parbuf);
391234Skas 	if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
401234Skas 		fail(linebuf, "No from or date field");
4131142Sedward 		return (0);
421234Skas 	}
431234Skas 	if (!isdate(hl.l_date)) {
441234Skas 		fail(linebuf, "Date field not legal date");
4531142Sedward 		return (0);
461234Skas 	}
471234Skas 	/*
481234Skas 	 * I guess we got it!
491234Skas 	 */
5031142Sedward 	return (1);
511234Skas }
521234Skas 
5331142Sedward /*ARGSUSED*/
5454505Sbostic void
fail(linebuf,reason)551234Skas fail(linebuf, reason)
561234Skas 	char linebuf[], reason[];
571234Skas {
581234Skas 
5931142Sedward 	/*
6031142Sedward 	if (value("debug") == NOSTR)
611234Skas 		return;
621234Skas 	fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
6331142Sedward 	*/
641234Skas }
651234Skas 
661234Skas /*
671234Skas  * Split a headline into its useful components.
681234Skas  * Copy the line into dynamic string space, then set
691234Skas  * pointers into the copied line in the passed headline
701234Skas  * structure.  Actually, it scans.
711234Skas  */
7254505Sbostic void
parse(line,hl,pbuf)731234Skas parse(line, hl, pbuf)
741234Skas 	char line[], pbuf[];
7531142Sedward 	register struct headline *hl;
761234Skas {
7731142Sedward 	register char *cp;
781234Skas 	char *sp;
791234Skas 	char word[LINESIZE];
801234Skas 
811234Skas 	hl->l_from = NOSTR;
821234Skas 	hl->l_tty = NOSTR;
831234Skas 	hl->l_date = NOSTR;
841234Skas 	cp = line;
851234Skas 	sp = pbuf;
861234Skas 	/*
8731142Sedward 	 * Skip over "From" first.
881234Skas 	 */
891234Skas 	cp = nextword(cp, word);
9031142Sedward 	cp = nextword(cp, word);
9131142Sedward 	if (*word)
921234Skas 		hl->l_from = copyin(word, &sp);
9331142Sedward 	if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
9431142Sedward 		cp = nextword(cp, word);
951234Skas 		hl->l_tty = copyin(word, &sp);
961234Skas 	}
9731142Sedward 	if (cp != NOSTR)
9831142Sedward 		hl->l_date = copyin(cp, &sp);
991234Skas }
1001234Skas 
1011234Skas /*
1021234Skas  * Copy the string on the left into the string on the right
1031234Skas  * and bump the right (reference) string pointer by the length.
1041234Skas  * Thus, dynamically allocate space in the right string, copying
1051234Skas  * the left string into it.
1061234Skas  */
1071234Skas char *
copyin(src,space)1081234Skas copyin(src, space)
10931142Sedward 	register char *src;
1101234Skas 	char **space;
1111234Skas {
11231142Sedward 	register char *cp;
11331142Sedward 	char *top;
1141234Skas 
11531142Sedward 	top = cp = *space;
11631142Sedward 	while (*cp++ = *src++)
11731142Sedward 		;
1181234Skas 	*space = cp;
11931142Sedward 	return (top);
1201234Skas }
1211234Skas 
1221234Skas /*
1231234Skas  * Test to see if the passed string is a ctime(3) generated
1241234Skas  * date string as documented in the manual.  The template
1251234Skas  * below is used as the criterion of correctness.
1261234Skas  * Also, we check for a possible trailing time zone using
12734987Sedward  * the tmztype template.
1281234Skas  */
1291234Skas 
13034987Sedward /*
13134987Sedward  * 'A'	An upper case char
13234987Sedward  * 'a'	A lower case char
13334987Sedward  * ' '	A space
13434987Sedward  * '0'	A digit
13534987Sedward  * 'O'	An optional digit or space
13634987Sedward  * ':'	A colon
13734987Sedward  * 'N'	A new line
13834987Sedward  */
13934987Sedward char ctype[] = "Aaa Aaa O0 00:00:00 0000";
14034987Sedward char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000";
141*68818Sdab /*
142*68818Sdab  * Yuck.  If the mail file is created by Sys V (Solaris),
143*68818Sdab  * there are no seconds in the time...
144*68818Sdab  */
145*68818Sdab char SysV_ctype[] = "Aaa Aaa O0 00:00 0000";
146*68818Sdab char SysV_tmztype[] = "Aaa Aaa O0 00:00 AAA 0000";
1471234Skas 
14854505Sbostic int
isdate(date)1491234Skas isdate(date)
1501234Skas 	char date[];
1511234Skas {
1521234Skas 
153*68818Sdab 	return cmatch(date, ctype) || cmatch(date, tmztype)
154*68818Sdab 	    || cmatch(date, SysV_tmztype) || cmatch(date, SysV_ctype);
1551234Skas }
1561234Skas 
1571234Skas /*
15831142Sedward  * Match the given string (cp) against the given template (tp).
1591234Skas  * Return 1 if they match, 0 if they don't
1601234Skas  */
16154505Sbostic int
cmatch(cp,tp)16231142Sedward cmatch(cp, tp)
16331142Sedward 	register char *cp, *tp;
1641234Skas {
1651234Skas 
16631142Sedward 	while (*cp && *tp)
1671234Skas 		switch (*tp++) {
16834987Sedward 		case 'a':
16931142Sedward 			if (!islower(*cp++))
17031142Sedward 				return 0;
1711234Skas 			break;
17234987Sedward 		case 'A':
17331142Sedward 			if (!isupper(*cp++))
17431142Sedward 				return 0;
1751234Skas 			break;
17634987Sedward 		case ' ':
17731142Sedward 			if (*cp++ != ' ')
17831142Sedward 				return 0;
1791234Skas 			break;
18034987Sedward 		case '0':
18131142Sedward 			if (!isdigit(*cp++))
18231142Sedward 				return 0;
1831234Skas 			break;
18434987Sedward 		case 'O':
18531142Sedward 			if (*cp != ' ' && !isdigit(*cp))
18631142Sedward 				return 0;
18731142Sedward 			cp++;
1881234Skas 			break;
18934987Sedward 		case ':':
19031142Sedward 			if (*cp++ != ':')
19131142Sedward 				return 0;
1921234Skas 			break;
19334987Sedward 		case 'N':
19431142Sedward 			if (*cp++ != '\n')
19531142Sedward 				return 0;
1961234Skas 			break;
1971234Skas 		}
19831142Sedward 	if (*cp || *tp)
19931142Sedward 		return 0;
20031142Sedward 	return (1);
2011234Skas }
2021234Skas 
2031234Skas /*
2041234Skas  * Collect a liberal (space, tab delimited) word into the word buffer
2051234Skas  * passed.  Also, return a pointer to the next word following that,
2061234Skas  * or NOSTR if none follow.
2071234Skas  */
2081234Skas char *
nextword(wp,wbuf)2091234Skas nextword(wp, wbuf)
21031142Sedward 	register char *wp, *wbuf;
2111234Skas {
21231142Sedward 	register c;
2131234Skas 
21431142Sedward 	if (wp == NOSTR) {
21531142Sedward 		*wbuf = 0;
21631142Sedward 		return (NOSTR);
2171234Skas 	}
21831142Sedward 	while ((c = *wp++) && c != ' ' && c != '\t') {
21931142Sedward 		*wbuf++ = c;
22031142Sedward 		if (c == '"') {
22131142Sedward  			while ((c = *wp++) && c != '"')
22231142Sedward  				*wbuf++ = c;
22331142Sedward  			if (c == '"')
22431142Sedward  				*wbuf++ = c;
22531142Sedward 			else
22631142Sedward 				wp--;
22731142Sedward  		}
22831142Sedward 	}
22931142Sedward 	*wbuf = '\0';
23031142Sedward 	for (; c == ' ' || c == '\t'; c = *wp++)
23131142Sedward 		;
23231142Sedward 	if (c == 0)
23331142Sedward 		return (NOSTR);
23431142Sedward 	return (wp - 1);
2351234Skas }
236