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