Commit | Line | Data |
---|---|---|
2ae9f53f | 1 | #ifndef lint |
3c5eb507 | 2 | static char sccsid[] = "@(#)head.c 2.4 (Berkeley) %G%"; |
2ae9f53f | 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 | ||
19 | ishead(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 | ||
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); | |
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 | ||
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 | ||
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 | ||
136 | 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}; | |
137 | 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}; | |
138 | ||
139 | isdate(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 | ||
155 | cmatch(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 | ||
213 | char * | |
214 | nextword(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') | |
3c5eb507 CL |
225 | if (*cp == '"') { |
226 | *cp2++ = *cp++; | |
227 | while (*cp != '\0' && *cp != '"') | |
228 | *cp2++ = *cp++; | |
229 | if (*cp == '"') | |
230 | *cp2++ = *cp++; | |
231 | } else | |
232 | *cp2++ = *cp++; | |
6a550447 KS |
233 | *cp2 = '\0'; |
234 | while (any(*cp, " \t")) | |
235 | cp++; | |
236 | if (*cp == '\0') | |
237 | return(NOSTR); | |
238 | return(cp); | |
239 | } | |
240 | ||
241 | /* | |
242 | * Test to see if the character is an ascii alphabetic. | |
243 | */ | |
244 | ||
245 | isalpha(c) | |
246 | { | |
247 | register int ch; | |
248 | ||
249 | ch = raise(c); | |
250 | return(ch >= 'A' && ch <= 'Z'); | |
251 | } | |
252 | ||
253 | /* | |
254 | * Test to see if the character is an ascii digit. | |
255 | */ | |
256 | ||
257 | isdigit(c) | |
258 | { | |
259 | return(c >= '0' && c <= '9'); | |
260 | } | |
261 | ||
262 | /* | |
263 | * Copy str1 to str2, return pointer to null in str2. | |
264 | */ | |
265 | ||
266 | char * | |
267 | copy(str1, str2) | |
268 | char *str1, *str2; | |
269 | { | |
270 | register char *s1, *s2; | |
271 | ||
272 | s1 = str1; | |
273 | s2 = str2; | |
274 | while (*s1) | |
275 | *s2++ = *s1++; | |
276 | *s2 = 0; | |
277 | return(s2); | |
278 | } | |
279 | ||
280 | /* | |
281 | * Is ch any of the characters in str? | |
282 | */ | |
283 | ||
284 | any(ch, str) | |
285 | char *str; | |
286 | { | |
287 | register char *f; | |
288 | register c; | |
289 | ||
290 | f = str; | |
291 | c = ch; | |
292 | while (*f) | |
293 | if (c == *f++) | |
294 | return(1); | |
295 | return(0); | |
296 | } | |
297 | ||
298 | /* | |
299 | * Convert lower case letters to upper case. | |
300 | */ | |
301 | ||
302 | raise(c) | |
303 | register int c; | |
304 | { | |
305 | if (c >= 'a' && c <= 'z') | |
306 | c += 'A' - 'a'; | |
307 | return(c); | |
308 | } |