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