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