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