xref: /original-bsd/usr.bin/mail/head.c (revision ba72ef4c)
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	1.1 10/08/80";
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  * Test to see if the passed string is a ctime(3) generated
144  * date string as documented in the manual.  The template
145  * below is used as the criterion of correctness.
146  * Also, we check for a possible trailing time zone using
147  * the auxtype template.
148  */
149 
150 #define	L	1		/* A lower case char */
151 #define	S	2		/* A space */
152 #define	D	3		/* A digit */
153 #define	O	4		/* An optional digit or space */
154 #define	C	5		/* A colon */
155 #define	N	6		/* A new line */
156 #define U	7		/* An upper case char */
157 
158 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};
159 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};
160 
161 isdate(date)
162 	char date[];
163 {
164 	register char *cp;
165 
166 	cp = date;
167 	if (cmatch(cp, ctypes))
168 		return(1);
169 	return(cmatch(cp, tmztypes));
170 }
171 
172 /*
173  * Match the given string against the given template.
174  * Return 1 if they match, 0 if they don't
175  */
176 
177 cmatch(str, temp)
178 	char str[], temp[];
179 {
180 	register char *cp, *tp;
181 	register int c;
182 
183 	cp = str;
184 	tp = temp;
185 	while (*cp != '\0' && *tp != 0) {
186 		c = *cp++;
187 		switch (*tp++) {
188 		case L:
189 			if (c < 'a' || c > 'z')
190 				return(0);
191 			break;
192 
193 		case U:
194 			if (c < 'A' || c > 'Z')
195 				return(0);
196 			break;
197 
198 		case S:
199 			if (c != ' ')
200 				return(0);
201 			break;
202 
203 		case D:
204 			if (!isdigit(c))
205 				return(0);
206 			break;
207 
208 		case O:
209 			if (c != ' ' && !isdigit(c))
210 				return(0);
211 			break;
212 
213 		case C:
214 			if (c != ':')
215 				return(0);
216 			break;
217 
218 		case N:
219 			if (c != '\n')
220 				return(0);
221 			break;
222 		}
223 	}
224 	if (*cp != '\0' || *tp != 0)
225 		return(0);
226 	return(1);
227 }
228 
229 /*
230  * Collect a liberal (space, tab delimited) word into the word buffer
231  * passed.  Also, return a pointer to the next word following that,
232  * or NOSTR if none follow.
233  */
234 
235 char *
236 nextword(wp, wbuf)
237 	char wp[], wbuf[];
238 {
239 	register char *cp, *cp2;
240 
241 	if ((cp = wp) == NOSTR) {
242 		copy("", wbuf);
243 		return(NOSTR);
244 	}
245 	cp2 = wbuf;
246 	while (!any(*cp, " \t") && *cp != '\0')
247 		*cp2++ = *cp++;
248 	*cp2 = '\0';
249 	while (any(*cp, " \t"))
250 		cp++;
251 	if (*cp == '\0')
252 		return(NOSTR);
253 	return(cp);
254 }
255 
256 /*
257  * Test to see if the character is an ascii alphabetic.
258  */
259 
260 isalpha(c)
261 {
262 	register int ch;
263 
264 	ch = raise(c);
265 	return(ch >= 'A' && ch <= 'Z');
266 }
267 
268 /*
269  * Test to see if the character is an ascii digit.
270  */
271 
272 isdigit(c)
273 {
274 	return(c >= '0' && c <= '9');
275 }
276 
277 /*
278  * Copy str1 to str2, return pointer to null in str2.
279  */
280 
281 char *
282 copy(str1, str2)
283 	char *str1, *str2;
284 {
285 	register char *s1, *s2;
286 
287 	s1 = str1;
288 	s2 = str2;
289 	while (*s1)
290 		*s2++ = *s1++;
291 	*s2 = 0;
292 	return(s2);
293 }
294 
295 /*
296  * Is ch any of the characters in str?
297  */
298 
299 any(ch, str)
300 	char *str;
301 {
302 	register char *f;
303 	register c;
304 
305 	f = str;
306 	c = ch;
307 	while (*f)
308 		if (c == *f++)
309 			return(1);
310 	return(0);
311 }
312 
313 /*
314  * Convert lower case letters to upper case.
315  */
316 
317 raise(c)
318 	register int c;
319 {
320 	if (c >= 'a' && c <= 'z')
321 		c += 'A' - 'a';
322 	return(c);
323 }
324