Commit | Line | Data |
---|---|---|
9552e6b8 DF |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
0c5f72fb KB |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
acfc7e9b KB |
6 | * provided that the above copyright notice and this paragraph are |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
9552e6b8 DF |
16 | */ |
17 | ||
acfc7e9b | 18 | #ifndef lint |
470c33f3 | 19 | static char sccsid[] = "@(#)head.c 5.6 (Berkeley) %G%"; |
acfc7e9b | 20 | #endif /* not lint */ |
6a550447 KS |
21 | |
22 | #include "rcv.h" | |
23 | ||
24 | /* | |
25 | * Mail -- a mail program | |
26 | * | |
27 | * Routines for processing and detecting headlines. | |
28 | */ | |
29 | ||
6a550447 KS |
30 | /* |
31 | * See if the passed line buffer is a mail header. | |
32 | * Return true if yes. Note the extreme pains to | |
33 | * accomodate all funny formats. | |
34 | */ | |
6a550447 KS |
35 | ishead(linebuf) |
36 | char linebuf[]; | |
37 | { | |
38 | register char *cp; | |
39 | struct headline hl; | |
40 | char parbuf[BUFSIZ]; | |
41 | ||
42 | cp = linebuf; | |
828615a1 EW |
43 | if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' || |
44 | *cp++ != ' ') | |
45 | return (0); | |
46 | parse(linebuf, &hl, parbuf); | |
6a550447 KS |
47 | if (hl.l_from == NOSTR || hl.l_date == NOSTR) { |
48 | fail(linebuf, "No from or date field"); | |
828615a1 | 49 | return (0); |
6a550447 KS |
50 | } |
51 | if (!isdate(hl.l_date)) { | |
52 | fail(linebuf, "Date field not legal date"); | |
828615a1 | 53 | return (0); |
6a550447 | 54 | } |
6a550447 KS |
55 | /* |
56 | * I guess we got it! | |
57 | */ | |
828615a1 | 58 | return (1); |
6a550447 KS |
59 | } |
60 | ||
828615a1 | 61 | /*ARGSUSED*/ |
6a550447 KS |
62 | fail(linebuf, reason) |
63 | char linebuf[], reason[]; | |
64 | { | |
65 | ||
828615a1 EW |
66 | /* |
67 | if (value("debug") == NOSTR) | |
6a550447 KS |
68 | return; |
69 | fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason); | |
828615a1 | 70 | */ |
6a550447 KS |
71 | } |
72 | ||
73 | /* | |
74 | * Split a headline into its useful components. | |
75 | * Copy the line into dynamic string space, then set | |
76 | * pointers into the copied line in the passed headline | |
77 | * structure. Actually, it scans. | |
78 | */ | |
6a550447 KS |
79 | parse(line, hl, pbuf) |
80 | char line[], pbuf[]; | |
828615a1 | 81 | register struct headline *hl; |
6a550447 | 82 | { |
828615a1 | 83 | register char *cp; |
6a550447 KS |
84 | char *sp; |
85 | char word[LINESIZE]; | |
86 | ||
87 | hl->l_from = NOSTR; | |
88 | hl->l_tty = NOSTR; | |
89 | hl->l_date = NOSTR; | |
90 | cp = line; | |
91 | sp = pbuf; | |
6a550447 | 92 | /* |
828615a1 | 93 | * Skip over "From" first. |
6a550447 | 94 | */ |
6a550447 | 95 | cp = nextword(cp, word); |
828615a1 EW |
96 | cp = nextword(cp, word); |
97 | if (*word) | |
6a550447 | 98 | hl->l_from = copyin(word, &sp); |
828615a1 EW |
99 | if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') { |
100 | cp = nextword(cp, word); | |
6a550447 | 101 | hl->l_tty = copyin(word, &sp); |
6a550447 | 102 | } |
828615a1 EW |
103 | if (cp != NOSTR) |
104 | hl->l_date = copyin(cp, &sp); | |
6a550447 KS |
105 | } |
106 | ||
107 | /* | |
108 | * Copy the string on the left into the string on the right | |
109 | * and bump the right (reference) string pointer by the length. | |
110 | * Thus, dynamically allocate space in the right string, copying | |
111 | * the left string into it. | |
112 | */ | |
6a550447 KS |
113 | char * |
114 | copyin(src, space) | |
828615a1 | 115 | register char *src; |
6a550447 KS |
116 | char **space; |
117 | { | |
828615a1 EW |
118 | register char *cp; |
119 | char *top; | |
6a550447 | 120 | |
828615a1 EW |
121 | top = cp = *space; |
122 | while (*cp++ = *src++) | |
123 | ; | |
6a550447 | 124 | *space = cp; |
828615a1 | 125 | return (top); |
6a550447 KS |
126 | } |
127 | ||
6a550447 KS |
128 | /* |
129 | * Test to see if the passed string is a ctime(3) generated | |
130 | * date string as documented in the manual. The template | |
131 | * below is used as the criterion of correctness. | |
132 | * Also, we check for a possible trailing time zone using | |
470c33f3 | 133 | * the tmztype template. |
6a550447 KS |
134 | */ |
135 | ||
470c33f3 EW |
136 | /* |
137 | * 'A' An upper case char | |
138 | * 'a' A lower case char | |
139 | * ' ' A space | |
140 | * '0' A digit | |
141 | * 'O' An optional digit or space | |
142 | * ':' A colon | |
143 | * 'N' A new line | |
144 | */ | |
145 | char ctype[] = "Aaa Aaa O0 00:00:00 0000"; | |
146 | char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000"; | |
6a550447 KS |
147 | |
148 | isdate(date) | |
149 | char date[]; | |
150 | { | |
6a550447 | 151 | |
470c33f3 | 152 | return cmatch(date, ctype) || cmatch(date, tmztype); |
6a550447 KS |
153 | } |
154 | ||
155 | /* | |
828615a1 | 156 | * Match the given string (cp) against the given template (tp). |
6a550447 KS |
157 | * Return 1 if they match, 0 if they don't |
158 | */ | |
828615a1 | 159 | cmatch(cp, tp) |
6a550447 | 160 | register char *cp, *tp; |
828615a1 | 161 | { |
6a550447 | 162 | |
828615a1 | 163 | while (*cp && *tp) |
6a550447 | 164 | switch (*tp++) { |
470c33f3 | 165 | case 'a': |
828615a1 EW |
166 | if (!islower(*cp++)) |
167 | return 0; | |
6a550447 | 168 | break; |
470c33f3 | 169 | case 'A': |
828615a1 EW |
170 | if (!isupper(*cp++)) |
171 | return 0; | |
6a550447 | 172 | break; |
470c33f3 | 173 | case ' ': |
828615a1 EW |
174 | if (*cp++ != ' ') |
175 | return 0; | |
6a550447 | 176 | break; |
470c33f3 | 177 | case '0': |
828615a1 EW |
178 | if (!isdigit(*cp++)) |
179 | return 0; | |
6a550447 | 180 | break; |
470c33f3 | 181 | case 'O': |
828615a1 EW |
182 | if (*cp != ' ' && !isdigit(*cp)) |
183 | return 0; | |
184 | cp++; | |
6a550447 | 185 | break; |
470c33f3 | 186 | case ':': |
828615a1 EW |
187 | if (*cp++ != ':') |
188 | return 0; | |
6a550447 | 189 | break; |
470c33f3 | 190 | case 'N': |
828615a1 EW |
191 | if (*cp++ != '\n') |
192 | return 0; | |
6a550447 KS |
193 | break; |
194 | } | |
828615a1 EW |
195 | if (*cp || *tp) |
196 | return 0; | |
197 | return (1); | |
6a550447 KS |
198 | } |
199 | ||
200 | /* | |
201 | * Collect a liberal (space, tab delimited) word into the word buffer | |
202 | * passed. Also, return a pointer to the next word following that, | |
203 | * or NOSTR if none follow. | |
204 | */ | |
6a550447 KS |
205 | char * |
206 | nextword(wp, wbuf) | |
828615a1 | 207 | register char *wp, *wbuf; |
6a550447 | 208 | { |
828615a1 | 209 | register c; |
6a550447 | 210 | |
828615a1 EW |
211 | if (wp == NOSTR) { |
212 | *wbuf = 0; | |
213 | return (NOSTR); | |
6a550447 | 214 | } |
828615a1 EW |
215 | while ((c = *wp++) && c != ' ' && c != '\t') { |
216 | *wbuf++ = c; | |
217 | if (c == '"') { | |
218 | while ((c = *wp++) && c != '"') | |
219 | *wbuf++ = c; | |
220 | if (c == '"') | |
221 | *wbuf++ = c; | |
222 | else | |
223 | wp--; | |
224 | } | |
225 | } | |
226 | *wbuf = '\0'; | |
227 | for (; c == ' ' || c == '\t'; c = *wp++) | |
228 | ; | |
229 | if (c == 0) | |
230 | return (NOSTR); | |
231 | return (wp - 1); | |
6a550447 | 232 | } |