xref: /original-bsd/usr.bin/mail/head.c (revision 1f3a482a)
1 #
2 
3 #include "rcv.h"
4 
5 /*
6  * Mail -- a mail program
7  *
8  * Routines for processing and detecting headlines.
9  */
10 
11 static char *SccsId = "@(#)head.c	2.1 07/01/81";
12 
13 /*
14  * See if the passed line buffer is a mail header.
15  * Return true if yes.  Note the extreme pains to
16  * accomodate all funny formats.
17  */
18 
19 ishead(linebuf)
20 	char linebuf[];
21 {
22 	register char *cp;
23 	struct headline hl;
24 	char parbuf[BUFSIZ];
25 
26 	cp = linebuf;
27 	if (!isname("From ", cp, 5))
28 		return(0);
29 	parse(cp, &hl, parbuf);
30 	if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
31 		fail(linebuf, "No from or date field");
32 		return(0);
33 	}
34 	if (!isdate(hl.l_date)) {
35 		fail(linebuf, "Date field not legal date");
36 		return(0);
37 	}
38 
39 	/*
40 	 * I guess we got it!
41 	 */
42 
43 	return(1);
44 }
45 
46 fail(linebuf, reason)
47 	char linebuf[], reason[];
48 {
49 
50 	if (1 /*value("debug") == NOSTR*/)
51 		return;
52 	fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
53 }
54 
55 /*
56  * Split a headline into its useful components.
57  * Copy the line into dynamic string space, then set
58  * pointers into the copied line in the passed headline
59  * structure.  Actually, it scans.
60  */
61 
62 parse(line, hl, pbuf)
63 	char line[], pbuf[];
64 	struct headline *hl;
65 {
66 	register char *cp, *dp;
67 	char *sp;
68 	char word[LINESIZE];
69 
70 	hl->l_from = NOSTR;
71 	hl->l_tty = NOSTR;
72 	hl->l_date = NOSTR;
73 	cp = line;
74 	sp = pbuf;
75 
76 	/*
77 	 * Skip the first "word" of the line, which should be "From"
78 	 * anyway.
79 	 */
80 
81 	cp = nextword(cp, word);
82 	dp = nextword(cp, word);
83 	if (!equal(word, ""))
84 		hl->l_from = copyin(word, &sp);
85 	if (isname(dp, "tty", 3)) {
86 		cp = nextword(dp, word);
87 		hl->l_tty = copyin(word, &sp);
88 		if (cp != NOSTR)
89 			hl->l_date = copyin(cp, &sp);
90 	}
91 	else
92 		if (dp != NOSTR)
93 			hl->l_date = copyin(dp, &sp);
94 }
95 
96 /*
97  * Copy the string on the left into the string on the right
98  * and bump the right (reference) string pointer by the length.
99  * Thus, dynamically allocate space in the right string, copying
100  * the left string into it.
101  */
102 
103 char *
104 copyin(src, space)
105 	char src[];
106 	char **space;
107 {
108 	register char *cp, *top;
109 	register int s;
110 
111 	s = strlen(src);
112 	cp = *space;
113 	top = cp;
114 	strcpy(cp, src);
115 	cp += s + 1;
116 	*space = cp;
117 	return(top);
118 }
119 
120 /*
121  * See if the two passed strings agree in the first n characters.
122  * Return true if they do, gnu.
123  */
124 
125 isname(as1, as2, acount)
126 	char *as1, *as2;
127 {
128 	register char *s1, *s2;
129 	register count;
130 
131 	s1 = as1;
132 	s2 = as2;
133 	count = acount;
134 	if (count > 0)
135 		do
136 			if (*s1++ != *s2++)
137 				return(0);
138 		while (--count);
139 	return(1);
140 }
141 
142 /*
143  * See if the two passed strings agree in the first n characters.
144  * Return true if they do, ignoring case.
145  */
146 
147 icisname(as1, as2, acount)
148 	char *as1, *as2;
149 {
150 	register char *s1, *s2;
151 	register count;
152 
153 	s1 = as1;
154 	s2 = as2;
155 	count = acount;
156 	if (count > 0)
157 		do
158 			if (raise(*s1++) != raise(*s2++))
159 				return(0);
160 		while (--count);
161 	return(1);
162 }
163 
164 /*
165  * Test to see if the passed string is a ctime(3) generated
166  * date string as documented in the manual.  The template
167  * below is used as the criterion of correctness.
168  * Also, we check for a possible trailing time zone using
169  * the auxtype template.
170  */
171 
172 #define	L	1		/* A lower case char */
173 #define	S	2		/* A space */
174 #define	D	3		/* A digit */
175 #define	O	4		/* An optional digit or space */
176 #define	C	5		/* A colon */
177 #define	N	6		/* A new line */
178 #define U	7		/* An upper case char */
179 
180 char ctypes[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,D,D,D,D,0};
181 char tmztypes[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,U,U,U,S,D,D,D,D,0};
182 
183 isdate(date)
184 	char date[];
185 {
186 	register char *cp;
187 
188 	cp = date;
189 	if (cmatch(cp, ctypes))
190 		return(1);
191 	return(cmatch(cp, tmztypes));
192 }
193 
194 /*
195  * Match the given string against the given template.
196  * Return 1 if they match, 0 if they don't
197  */
198 
199 cmatch(str, temp)
200 	char str[], temp[];
201 {
202 	register char *cp, *tp;
203 	register int c;
204 
205 	cp = str;
206 	tp = temp;
207 	while (*cp != '\0' && *tp != 0) {
208 		c = *cp++;
209 		switch (*tp++) {
210 		case L:
211 			if (c < 'a' || c > 'z')
212 				return(0);
213 			break;
214 
215 		case U:
216 			if (c < 'A' || c > 'Z')
217 				return(0);
218 			break;
219 
220 		case S:
221 			if (c != ' ')
222 				return(0);
223 			break;
224 
225 		case D:
226 			if (!isdigit(c))
227 				return(0);
228 			break;
229 
230 		case O:
231 			if (c != ' ' && !isdigit(c))
232 				return(0);
233 			break;
234 
235 		case C:
236 			if (c != ':')
237 				return(0);
238 			break;
239 
240 		case N:
241 			if (c != '\n')
242 				return(0);
243 			break;
244 		}
245 	}
246 	if (*cp != '\0' || *tp != 0)
247 		return(0);
248 	return(1);
249 }
250 
251 /*
252  * Collect a liberal (space, tab delimited) word into the word buffer
253  * passed.  Also, return a pointer to the next word following that,
254  * or NOSTR if none follow.
255  */
256 
257 char *
258 nextword(wp, wbuf)
259 	char wp[], wbuf[];
260 {
261 	register char *cp, *cp2;
262 
263 	if ((cp = wp) == NOSTR) {
264 		copy("", wbuf);
265 		return(NOSTR);
266 	}
267 	cp2 = wbuf;
268 	while (!any(*cp, " \t") && *cp != '\0')
269 		*cp2++ = *cp++;
270 	*cp2 = '\0';
271 	while (any(*cp, " \t"))
272 		cp++;
273 	if (*cp == '\0')
274 		return(NOSTR);
275 	return(cp);
276 }
277 
278 /*
279  * Test to see if the character is an ascii alphabetic.
280  */
281 
282 isalpha(c)
283 {
284 	register int ch;
285 
286 	ch = raise(c);
287 	return(ch >= 'A' && ch <= 'Z');
288 }
289 
290 /*
291  * Test to see if the character is an ascii digit.
292  */
293 
294 isdigit(c)
295 {
296 	return(c >= '0' && c <= '9');
297 }
298 
299 /*
300  * Copy str1 to str2, return pointer to null in str2.
301  */
302 
303 char *
304 copy(str1, str2)
305 	char *str1, *str2;
306 {
307 	register char *s1, *s2;
308 
309 	s1 = str1;
310 	s2 = str2;
311 	while (*s1)
312 		*s2++ = *s1++;
313 	*s2 = 0;
314 	return(s2);
315 }
316 
317 /*
318  * Is ch any of the characters in str?
319  */
320 
321 any(ch, str)
322 	char *str;
323 {
324 	register char *f;
325 	register c;
326 
327 	f = str;
328 	c = ch;
329 	while (*f)
330 		if (c == *f++)
331 			return(1);
332 	return(0);
333 }
334 
335 /*
336  * Convert lower case letters to upper case.
337  */
338 
339 raise(c)
340 	register int c;
341 {
342 	if (c >= 'a' && c <= 'z')
343 		c += 'A' - 'a';
344 	return(c);
345 }
346