head.c revision 1.5 1 /* $NetBSD: head.c,v 1.5 1996/06/08 19:48:26 christos Exp $ */
2
3 /*
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)head.c 8.1 (Berkeley) 6/6/93";
39 #else
40 static char rcsid[] = "$NetBSD: head.c,v 1.5 1996/06/08 19:48:26 christos Exp $";
41 #endif
42 #endif /* not lint */
43
44 #include "rcv.h"
45 #include "extern.h"
46
47 /*
48 * Mail -- a mail program
49 *
50 * Routines for processing and detecting headlines.
51 */
52
53 /*
54 * See if the passed line buffer is a mail header.
55 * Return true if yes. Note the extreme pains to
56 * accomodate all funny formats.
57 */
58 int
59 ishead(linebuf)
60 char linebuf[];
61 {
62 register char *cp;
63 struct headline hl;
64 char parbuf[BUFSIZ];
65
66 cp = linebuf;
67 if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' ||
68 *cp++ != ' ')
69 return (0);
70 parse(linebuf, &hl, parbuf);
71 if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
72 fail(linebuf, "No from or date field");
73 return (0);
74 }
75 if (!isdate(hl.l_date)) {
76 fail(linebuf, "Date field not legal date");
77 return (0);
78 }
79 /*
80 * I guess we got it!
81 */
82 return (1);
83 }
84
85 /*ARGSUSED*/
86 void
87 fail(linebuf, reason)
88 char linebuf[], reason[];
89 {
90
91 /*
92 if (value("debug") == NOSTR)
93 return;
94 fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
95 */
96 }
97
98 /*
99 * Split a headline into its useful components.
100 * Copy the line into dynamic string space, then set
101 * pointers into the copied line in the passed headline
102 * structure. Actually, it scans.
103 */
104 void
105 parse(line, hl, pbuf)
106 char line[], pbuf[];
107 register struct headline *hl;
108 {
109 register char *cp;
110 char *sp;
111 char word[LINESIZE];
112
113 hl->l_from = NOSTR;
114 hl->l_tty = NOSTR;
115 hl->l_date = NOSTR;
116 cp = line;
117 sp = pbuf;
118 /*
119 * Skip over "From" first.
120 */
121 cp = nextword(cp, word);
122 cp = nextword(cp, word);
123 if (*word)
124 hl->l_from = copyin(word, &sp);
125 if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
126 cp = nextword(cp, word);
127 hl->l_tty = copyin(word, &sp);
128 }
129 if (cp != NOSTR)
130 hl->l_date = copyin(cp, &sp);
131 }
132
133 /*
134 * Copy the string on the left into the string on the right
135 * and bump the right (reference) string pointer by the length.
136 * Thus, dynamically allocate space in the right string, copying
137 * the left string into it.
138 */
139 char *
140 copyin(src, space)
141 register char *src;
142 char **space;
143 {
144 register char *cp;
145 char *top;
146
147 top = cp = *space;
148 while ((*cp++ = *src++) != '\0')
149 ;
150 *space = cp;
151 return (top);
152 }
153
154 /*
155 * Test to see if the passed string is a ctime(3) generated
156 * date string as documented in the manual. The template
157 * below is used as the criterion of correctness.
158 * Also, we check for a possible trailing time zone using
159 * the tmztype template.
160 */
161
162 /*
163 * 'A' An upper case char
164 * 'a' A lower case char
165 * ' ' A space
166 * '0' A digit
167 * 'O' An optional digit or space
168 * ':' A colon
169 * 'N' A new line
170 */
171 char ctype[] = "Aaa Aaa O0 00:00:00 0000";
172 char ctype_without_secs[] = "Aaa Aaa O0 00:00 0000";
173 char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000";
174 char tmztype_without_secs[] = "Aaa Aaa O0 00:00 AAA 0000";
175
176 int
177 isdate(date)
178 char date[];
179 {
180
181 return cmatch(date, ctype_without_secs) ||
182 cmatch(date, tmztype_without_secs) ||
183 cmatch(date, ctype) || cmatch(date, tmztype);
184 }
185
186 /*
187 * Match the given string (cp) against the given template (tp).
188 * Return 1 if they match, 0 if they don't
189 */
190 int
191 cmatch(cp, tp)
192 register char *cp, *tp;
193 {
194
195 while (*cp && *tp)
196 switch (*tp++) {
197 case 'a':
198 if (!islower(*cp++))
199 return 0;
200 break;
201 case 'A':
202 if (!isupper(*cp++))
203 return 0;
204 break;
205 case ' ':
206 if (*cp++ != ' ')
207 return 0;
208 break;
209 case '0':
210 if (!isdigit(*cp++))
211 return 0;
212 break;
213 case 'O':
214 if (*cp != ' ' && !isdigit(*cp))
215 return 0;
216 cp++;
217 break;
218 case ':':
219 if (*cp++ != ':')
220 return 0;
221 break;
222 case 'N':
223 if (*cp++ != '\n')
224 return 0;
225 break;
226 }
227 if (*cp || *tp)
228 return 0;
229 return (1);
230 }
231
232 /*
233 * Collect a liberal (space, tab delimited) word into the word buffer
234 * passed. Also, return a pointer to the next word following that,
235 * or NOSTR if none follow.
236 */
237 char *
238 nextword(wp, wbuf)
239 register char *wp, *wbuf;
240 {
241 register c;
242
243 if (wp == NOSTR) {
244 *wbuf = 0;
245 return (NOSTR);
246 }
247 while ((c = *wp++) && c != ' ' && c != '\t') {
248 *wbuf++ = c;
249 if (c == '"') {
250 while ((c = *wp++) && c != '"')
251 *wbuf++ = c;
252 if (c == '"')
253 *wbuf++ = c;
254 else
255 wp--;
256 }
257 }
258 *wbuf = '\0';
259 for (; c == ' ' || c == '\t'; c = *wp++)
260 ;
261 if (c == 0)
262 return (NOSTR);
263 return (wp - 1);
264 }
265