standardize sccs keyword lines
[unix-history] / usr / src / usr.bin / mail / head.c
CommitLineData
2ae9f53f
SL
1#ifndef lint
2static char sccsid[] = "@(#)head.c 2.3 (Berkeley) %G%";
3#endif
6a550447
KS
4
5#include "rcv.h"
6
7/*
8 * Mail -- a mail program
9 *
10 * Routines for processing and detecting headlines.
11 */
12
6a550447
KS
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
19ishead(linebuf)
20 char linebuf[];
21{
22 register char *cp;
23 struct headline hl;
24 char parbuf[BUFSIZ];
25
26 cp = linebuf;
18215574 27 if (strncmp("From ", cp, 5) != 0)
6a550447
KS
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
46fail(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
62parse(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);
18215574 85 if (strncmp(dp, "tty", 3) == 0) {
6a550447
KS
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
103char *
104copyin(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
6a550447
KS
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
136char 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};
137char 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
139isdate(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
155cmatch(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
213char *
214nextword(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
238isalpha(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
250isdigit(c)
251{
252 return(c >= '0' && c <= '9');
253}
254
255/*
256 * Copy str1 to str2, return pointer to null in str2.
257 */
258
259char *
260copy(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
277any(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
295raise(c)
296 register int c;
297{
298 if (c >= 'a' && c <= 'z')
299 c += 'A' - 'a';
300 return(c);
301}