xref: /original-bsd/usr.bin/mail/head.c (revision 2301fdfb)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)head.c	5.6 (Berkeley) 07/08/88";
20 #endif /* not lint */
21 
22 #include "rcv.h"
23 
24 /*
25  * Mail -- a mail program
26  *
27  * Routines for processing and detecting headlines.
28  */
29 
30 /*
31  * See if the passed line buffer is a mail header.
32  * Return true if yes.  Note the extreme pains to
33  * accomodate all funny formats.
34  */
35 ishead(linebuf)
36 	char linebuf[];
37 {
38 	register char *cp;
39 	struct headline hl;
40 	char parbuf[BUFSIZ];
41 
42 	cp = linebuf;
43 	if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' ||
44 	    *cp++ != ' ')
45 		return (0);
46 	parse(linebuf, &hl, parbuf);
47 	if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
48 		fail(linebuf, "No from or date field");
49 		return (0);
50 	}
51 	if (!isdate(hl.l_date)) {
52 		fail(linebuf, "Date field not legal date");
53 		return (0);
54 	}
55 	/*
56 	 * I guess we got it!
57 	 */
58 	return (1);
59 }
60 
61 /*ARGSUSED*/
62 fail(linebuf, reason)
63 	char linebuf[], reason[];
64 {
65 
66 	/*
67 	if (value("debug") == NOSTR)
68 		return;
69 	fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
70 	*/
71 }
72 
73 /*
74  * Split a headline into its useful components.
75  * Copy the line into dynamic string space, then set
76  * pointers into the copied line in the passed headline
77  * structure.  Actually, it scans.
78  */
79 parse(line, hl, pbuf)
80 	char line[], pbuf[];
81 	register struct headline *hl;
82 {
83 	register char *cp;
84 	char *sp;
85 	char word[LINESIZE];
86 
87 	hl->l_from = NOSTR;
88 	hl->l_tty = NOSTR;
89 	hl->l_date = NOSTR;
90 	cp = line;
91 	sp = pbuf;
92 	/*
93 	 * Skip over "From" first.
94 	 */
95 	cp = nextword(cp, word);
96 	cp = nextword(cp, word);
97 	if (*word)
98 		hl->l_from = copyin(word, &sp);
99 	if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
100 		cp = nextword(cp, word);
101 		hl->l_tty = copyin(word, &sp);
102 	}
103 	if (cp != NOSTR)
104 		hl->l_date = copyin(cp, &sp);
105 }
106 
107 /*
108  * Copy the string on the left into the string on the right
109  * and bump the right (reference) string pointer by the length.
110  * Thus, dynamically allocate space in the right string, copying
111  * the left string into it.
112  */
113 char *
114 copyin(src, space)
115 	register char *src;
116 	char **space;
117 {
118 	register char *cp;
119 	char *top;
120 
121 	top = cp = *space;
122 	while (*cp++ = *src++)
123 		;
124 	*space = cp;
125 	return (top);
126 }
127 
128 /*
129  * Test to see if the passed string is a ctime(3) generated
130  * date string as documented in the manual.  The template
131  * below is used as the criterion of correctness.
132  * Also, we check for a possible trailing time zone using
133  * the tmztype template.
134  */
135 
136 /*
137  * 'A'	An upper case char
138  * 'a'	A lower case char
139  * ' '	A space
140  * '0'	A digit
141  * 'O'	An optional digit or space
142  * ':'	A colon
143  * 'N'	A new line
144  */
145 char ctype[] = "Aaa Aaa O0 00:00:00 0000";
146 char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000";
147 
148 isdate(date)
149 	char date[];
150 {
151 
152 	return cmatch(date, ctype) || cmatch(date, tmztype);
153 }
154 
155 /*
156  * Match the given string (cp) against the given template (tp).
157  * Return 1 if they match, 0 if they don't
158  */
159 cmatch(cp, tp)
160 	register char *cp, *tp;
161 {
162 
163 	while (*cp && *tp)
164 		switch (*tp++) {
165 		case 'a':
166 			if (!islower(*cp++))
167 				return 0;
168 			break;
169 		case 'A':
170 			if (!isupper(*cp++))
171 				return 0;
172 			break;
173 		case ' ':
174 			if (*cp++ != ' ')
175 				return 0;
176 			break;
177 		case '0':
178 			if (!isdigit(*cp++))
179 				return 0;
180 			break;
181 		case 'O':
182 			if (*cp != ' ' && !isdigit(*cp))
183 				return 0;
184 			cp++;
185 			break;
186 		case ':':
187 			if (*cp++ != ':')
188 				return 0;
189 			break;
190 		case 'N':
191 			if (*cp++ != '\n')
192 				return 0;
193 			break;
194 		}
195 	if (*cp || *tp)
196 		return 0;
197 	return (1);
198 }
199 
200 /*
201  * Collect a liberal (space, tab delimited) word into the word buffer
202  * passed.  Also, return a pointer to the next word following that,
203  * or NOSTR if none follow.
204  */
205 char *
206 nextword(wp, wbuf)
207 	register char *wp, *wbuf;
208 {
209 	register c;
210 
211 	if (wp == NOSTR) {
212 		*wbuf = 0;
213 		return (NOSTR);
214 	}
215 	while ((c = *wp++) && c != ' ' && c != '\t') {
216 		*wbuf++ = c;
217 		if (c == '"') {
218  			while ((c = *wp++) && c != '"')
219  				*wbuf++ = c;
220  			if (c == '"')
221  				*wbuf++ = c;
222 			else
223 				wp--;
224  		}
225 	}
226 	*wbuf = '\0';
227 	for (; c == ' ' || c == '\t'; c = *wp++)
228 		;
229 	if (c == 0)
230 		return (NOSTR);
231 	return (wp - 1);
232 }
233