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