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