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