xref: /original-bsd/usr.bin/mail/head.c (revision 6bd4f036)
1ef77d8e9Sdist /*
266f7b1b4Sbostic  * Copyright (c) 1980, 1993
366f7b1b4Sbostic  *	The Regents of the University of California.  All rights reserved.
413f94090Sbostic  *
52b713f00Sbostic  * %sccs.include.redist.c%
6ef77d8e9Sdist  */
7ef77d8e9Sdist 
88cab6285Sbostic #ifndef lint
9*6bd4f036Sdab static char sccsid[] = "@(#)head.c	8.2 (Berkeley) 04/20/95";
108cab6285Sbostic #endif /* not lint */
11068bc5fdSkas 
12068bc5fdSkas #include "rcv.h"
1338ba7095Sbostic #include "extern.h"
14068bc5fdSkas 
15068bc5fdSkas /*
16068bc5fdSkas  * Mail -- a mail program
17068bc5fdSkas  *
18068bc5fdSkas  * Routines for processing and detecting headlines.
19068bc5fdSkas  */
20068bc5fdSkas 
21068bc5fdSkas /*
22068bc5fdSkas  * See if the passed line buffer is a mail header.
23068bc5fdSkas  * Return true if yes.  Note the extreme pains to
24068bc5fdSkas  * accomodate all funny formats.
25068bc5fdSkas  */
2638ba7095Sbostic int
ishead(linebuf)27068bc5fdSkas ishead(linebuf)
28068bc5fdSkas 	char linebuf[];
29068bc5fdSkas {
30068bc5fdSkas 	register char *cp;
31068bc5fdSkas 	struct headline hl;
32068bc5fdSkas 	char parbuf[BUFSIZ];
33068bc5fdSkas 
34068bc5fdSkas 	cp = linebuf;
35a1e0f4b8Sedward 	if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' ||
36a1e0f4b8Sedward 	    *cp++ != ' ')
37068bc5fdSkas 		return (0);
38a1e0f4b8Sedward 	parse(linebuf, &hl, parbuf);
39068bc5fdSkas 	if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
40068bc5fdSkas 		fail(linebuf, "No from or date field");
41068bc5fdSkas 		return (0);
42068bc5fdSkas 	}
43068bc5fdSkas 	if (!isdate(hl.l_date)) {
44068bc5fdSkas 		fail(linebuf, "Date field not legal date");
45068bc5fdSkas 		return (0);
46068bc5fdSkas 	}
47068bc5fdSkas 	/*
48068bc5fdSkas 	 * I guess we got it!
49068bc5fdSkas 	 */
50068bc5fdSkas 	return (1);
51068bc5fdSkas }
52068bc5fdSkas 
53a1e0f4b8Sedward /*ARGSUSED*/
5438ba7095Sbostic void
fail(linebuf,reason)55068bc5fdSkas fail(linebuf, reason)
56068bc5fdSkas 	char linebuf[], reason[];
57068bc5fdSkas {
58068bc5fdSkas 
59a1e0f4b8Sedward 	/*
60a1e0f4b8Sedward 	if (value("debug") == NOSTR)
61068bc5fdSkas 		return;
62068bc5fdSkas 	fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
63a1e0f4b8Sedward 	*/
64068bc5fdSkas }
65068bc5fdSkas 
66068bc5fdSkas /*
67068bc5fdSkas  * Split a headline into its useful components.
68068bc5fdSkas  * Copy the line into dynamic string space, then set
69068bc5fdSkas  * pointers into the copied line in the passed headline
70068bc5fdSkas  * structure.  Actually, it scans.
71068bc5fdSkas  */
7238ba7095Sbostic void
parse(line,hl,pbuf)73068bc5fdSkas parse(line, hl, pbuf)
74068bc5fdSkas 	char line[], pbuf[];
75a1e0f4b8Sedward 	register struct headline *hl;
76068bc5fdSkas {
77a1e0f4b8Sedward 	register char *cp;
78068bc5fdSkas 	char *sp;
79068bc5fdSkas 	char word[LINESIZE];
80068bc5fdSkas 
81068bc5fdSkas 	hl->l_from = NOSTR;
82068bc5fdSkas 	hl->l_tty = NOSTR;
83068bc5fdSkas 	hl->l_date = NOSTR;
84068bc5fdSkas 	cp = line;
85068bc5fdSkas 	sp = pbuf;
86068bc5fdSkas 	/*
87a1e0f4b8Sedward 	 * Skip over "From" first.
88068bc5fdSkas 	 */
89068bc5fdSkas 	cp = nextword(cp, word);
90a1e0f4b8Sedward 	cp = nextword(cp, word);
91a1e0f4b8Sedward 	if (*word)
92068bc5fdSkas 		hl->l_from = copyin(word, &sp);
93a1e0f4b8Sedward 	if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
94a1e0f4b8Sedward 		cp = nextword(cp, word);
95068bc5fdSkas 		hl->l_tty = copyin(word, &sp);
96a1e0f4b8Sedward 	}
97068bc5fdSkas 	if (cp != NOSTR)
98068bc5fdSkas 		hl->l_date = copyin(cp, &sp);
99068bc5fdSkas }
100068bc5fdSkas 
101068bc5fdSkas /*
102068bc5fdSkas  * Copy the string on the left into the string on the right
103068bc5fdSkas  * and bump the right (reference) string pointer by the length.
104068bc5fdSkas  * Thus, dynamically allocate space in the right string, copying
105068bc5fdSkas  * the left string into it.
106068bc5fdSkas  */
107068bc5fdSkas char *
copyin(src,space)108068bc5fdSkas copyin(src, space)
109a1e0f4b8Sedward 	register char *src;
110068bc5fdSkas 	char **space;
111068bc5fdSkas {
112a1e0f4b8Sedward 	register char *cp;
113a1e0f4b8Sedward 	char *top;
114068bc5fdSkas 
115a1e0f4b8Sedward 	top = cp = *space;
116a1e0f4b8Sedward 	while (*cp++ = *src++)
117a1e0f4b8Sedward 		;
118068bc5fdSkas 	*space = cp;
119068bc5fdSkas 	return (top);
120068bc5fdSkas }
121068bc5fdSkas 
122068bc5fdSkas /*
123068bc5fdSkas  * Test to see if the passed string is a ctime(3) generated
124068bc5fdSkas  * date string as documented in the manual.  The template
125068bc5fdSkas  * below is used as the criterion of correctness.
126068bc5fdSkas  * Also, we check for a possible trailing time zone using
127552a793fSedward  * the tmztype template.
128068bc5fdSkas  */
129068bc5fdSkas 
130552a793fSedward /*
131552a793fSedward  * 'A'	An upper case char
132552a793fSedward  * 'a'	A lower case char
133552a793fSedward  * ' '	A space
134552a793fSedward  * '0'	A digit
135552a793fSedward  * 'O'	An optional digit or space
136552a793fSedward  * ':'	A colon
137552a793fSedward  * 'N'	A new line
138552a793fSedward  */
139552a793fSedward char ctype[] = "Aaa Aaa O0 00:00:00 0000";
140552a793fSedward char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000";
141*6bd4f036Sdab /*
142*6bd4f036Sdab  * Yuck.  If the mail file is created by Sys V (Solaris),
143*6bd4f036Sdab  * there are no seconds in the time...
144*6bd4f036Sdab  */
145*6bd4f036Sdab char SysV_ctype[] = "Aaa Aaa O0 00:00 0000";
146*6bd4f036Sdab char SysV_tmztype[] = "Aaa Aaa O0 00:00 AAA 0000";
147068bc5fdSkas 
14838ba7095Sbostic int
isdate(date)149068bc5fdSkas isdate(date)
150068bc5fdSkas 	char date[];
151068bc5fdSkas {
152068bc5fdSkas 
153*6bd4f036Sdab 	return cmatch(date, ctype) || cmatch(date, tmztype)
154*6bd4f036Sdab 	    || cmatch(date, SysV_tmztype) || cmatch(date, SysV_ctype);
155068bc5fdSkas }
156068bc5fdSkas 
157068bc5fdSkas /*
158a1e0f4b8Sedward  * Match the given string (cp) against the given template (tp).
159068bc5fdSkas  * Return 1 if they match, 0 if they don't
160068bc5fdSkas  */
16138ba7095Sbostic int
cmatch(cp,tp)162a1e0f4b8Sedward cmatch(cp, tp)
163068bc5fdSkas 	register char *cp, *tp;
164a1e0f4b8Sedward {
165068bc5fdSkas 
166a1e0f4b8Sedward 	while (*cp && *tp)
167068bc5fdSkas 		switch (*tp++) {
168552a793fSedward 		case 'a':
169a1e0f4b8Sedward 			if (!islower(*cp++))
170a1e0f4b8Sedward 				return 0;
171068bc5fdSkas 			break;
172552a793fSedward 		case 'A':
173a1e0f4b8Sedward 			if (!isupper(*cp++))
174a1e0f4b8Sedward 				return 0;
175068bc5fdSkas 			break;
176552a793fSedward 		case ' ':
177a1e0f4b8Sedward 			if (*cp++ != ' ')
178a1e0f4b8Sedward 				return 0;
179068bc5fdSkas 			break;
180552a793fSedward 		case '0':
181a1e0f4b8Sedward 			if (!isdigit(*cp++))
182a1e0f4b8Sedward 				return 0;
183068bc5fdSkas 			break;
184552a793fSedward 		case 'O':
185a1e0f4b8Sedward 			if (*cp != ' ' && !isdigit(*cp))
186a1e0f4b8Sedward 				return 0;
187a1e0f4b8Sedward 			cp++;
188068bc5fdSkas 			break;
189552a793fSedward 		case ':':
190a1e0f4b8Sedward 			if (*cp++ != ':')
191a1e0f4b8Sedward 				return 0;
192068bc5fdSkas 			break;
193552a793fSedward 		case 'N':
194a1e0f4b8Sedward 			if (*cp++ != '\n')
195a1e0f4b8Sedward 				return 0;
196068bc5fdSkas 			break;
197068bc5fdSkas 		}
198a1e0f4b8Sedward 	if (*cp || *tp)
199a1e0f4b8Sedward 		return 0;
200068bc5fdSkas 	return (1);
201068bc5fdSkas }
202068bc5fdSkas 
203068bc5fdSkas /*
204068bc5fdSkas  * Collect a liberal (space, tab delimited) word into the word buffer
205068bc5fdSkas  * passed.  Also, return a pointer to the next word following that,
206068bc5fdSkas  * or NOSTR if none follow.
207068bc5fdSkas  */
208068bc5fdSkas char *
nextword(wp,wbuf)209068bc5fdSkas nextword(wp, wbuf)
210a1e0f4b8Sedward 	register char *wp, *wbuf;
211068bc5fdSkas {
212068bc5fdSkas 	register c;
213068bc5fdSkas 
214a1e0f4b8Sedward 	if (wp == NOSTR) {
215a1e0f4b8Sedward 		*wbuf = 0;
216a1e0f4b8Sedward 		return (NOSTR);
217a1e0f4b8Sedward 	}
218a1e0f4b8Sedward 	while ((c = *wp++) && c != ' ' && c != '\t') {
219a1e0f4b8Sedward 		*wbuf++ = c;
220a1e0f4b8Sedward 		if (c == '"') {
221a1e0f4b8Sedward  			while ((c = *wp++) && c != '"')
222a1e0f4b8Sedward  				*wbuf++ = c;
223a1e0f4b8Sedward  			if (c == '"')
224a1e0f4b8Sedward  				*wbuf++ = c;
225a1e0f4b8Sedward 			else
226a1e0f4b8Sedward 				wp--;
227a1e0f4b8Sedward  		}
228a1e0f4b8Sedward 	}
229a1e0f4b8Sedward 	*wbuf = '\0';
230a1e0f4b8Sedward 	for (; c == ' ' || c == '\t'; c = *wp++)
231a1e0f4b8Sedward 		;
232a1e0f4b8Sedward 	if (c == 0)
233a1e0f4b8Sedward 		return (NOSTR);
234a1e0f4b8Sedward 	return (wp - 1);
235068bc5fdSkas }
236