head.c revision 1.9 1 /* $NetBSD: head.c,v 1.9 2002/03/02 13:57:28 wiz 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 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)head.c 8.2 (Berkeley) 4/20/95";
40 #else
41 __RCSID("$NetBSD: head.c,v 1.9 2002/03/02 13:57:28 wiz Exp $");
42 #endif
43 #endif /* not lint */
44
45 #include "rcv.h"
46 #include "extern.h"
47
48 /*
49 * Mail -- a mail program
50 *
51 * Routines for processing and detecting headlines.
52 */
53
54 /*
55 * See if the passed line buffer is a mail header.
56 * Return true if yes. Note the extreme pains to
57 * accomodate all funny formats.
58 */
59 int
60 ishead(char linebuf[])
61 {
62 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(char linebuf[], char reason[])
88 {
89
90 /*
91 if (value("debug") == NOSTR)
92 return;
93 fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
94 */
95 }
96
97 /*
98 * Split a headline into its useful components.
99 * Copy the line into dynamic string space, then set
100 * pointers into the copied line in the passed headline
101 * structure. Actually, it scans.
102 */
103 void
104 parse(char line[], struct headline *hl, char pbuf[])
105 {
106 char *cp;
107 char *sp;
108 char word[LINESIZE];
109
110 hl->l_from = NOSTR;
111 hl->l_tty = NOSTR;
112 hl->l_date = NOSTR;
113 cp = line;
114 sp = pbuf;
115 /*
116 * Skip over "From" first.
117 */
118 cp = nextword(cp, word);
119 cp = nextword(cp, word);
120 if (*word)
121 hl->l_from = copyin(word, &sp);
122 if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
123 cp = nextword(cp, word);
124 hl->l_tty = copyin(word, &sp);
125 }
126 if (cp != NOSTR)
127 hl->l_date = copyin(cp, &sp);
128 }
129
130 /*
131 * Copy the string on the left into the string on the right
132 * and bump the right (reference) string pointer by the length.
133 * Thus, dynamically allocate space in the right string, copying
134 * the left string into it.
135 */
136 char *
137 copyin(char *src, char **space)
138 {
139 char *cp;
140 char *top;
141
142 top = cp = *space;
143 while ((*cp++ = *src++) != '\0')
144 ;
145 *space = cp;
146 return (top);
147 }
148
149 /*
150 * Test to see if the passed string is a ctime(3) generated
151 * date string as documented in the manual. The template
152 * below is used as the criterion of correctness.
153 * Also, we check for a possible trailing time zone using
154 * the tmztype template.
155 */
156
157 /*
158 * 'A' An upper case char
159 * 'a' A lower case char
160 * ' ' A space
161 * '0' A digit
162 * 'O' An optional digit or space
163 * ':' A colon
164 * 'N' A new line
165 */
166 char ctype[] = "Aaa Aaa O0 00:00:00 0000";
167 char SysV_ctype[] = "Aaa Aaa O0 00:00 0000";
168 char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000";
169 char SysV_tmztype[] = "Aaa Aaa O0 00:00 AAA 0000";
170
171 int
172 isdate(char date[])
173 {
174
175 return cmatch(date, ctype) ||
176 cmatch(date, tmztype) ||
177 cmatch(date, SysV_tmztype) || cmatch(date, SysV_ctype);
178 }
179
180 /*
181 * Match the given string (cp) against the given template (tp).
182 * Return 1 if they match, 0 if they don't
183 */
184 int
185 cmatch(char *cp, char *tp)
186 {
187
188 while (*cp && *tp)
189 switch (*tp++) {
190 case 'a':
191 if (!islower((unsigned char)*cp++))
192 return 0;
193 break;
194 case 'A':
195 if (!isupper((unsigned char)*cp++))
196 return 0;
197 break;
198 case ' ':
199 if (*cp++ != ' ')
200 return 0;
201 break;
202 case '0':
203 if (!isdigit((unsigned char)*cp++))
204 return 0;
205 break;
206 case 'O':
207 if (*cp != ' ' && !isdigit((unsigned char)*cp))
208 return 0;
209 cp++;
210 break;
211 case ':':
212 if (*cp++ != ':')
213 return 0;
214 break;
215 case 'N':
216 if (*cp++ != '\n')
217 return 0;
218 break;
219 }
220 if (*cp || *tp)
221 return 0;
222 return (1);
223 }
224
225 /*
226 * Collect a liberal (space, tab delimited) word into the word buffer
227 * passed. Also, return a pointer to the next word following that,
228 * or NOSTR if none follow.
229 */
230 char *
231 nextword(char *wp, char *wbuf)
232 {
233 int c;
234
235 if (wp == NOSTR) {
236 *wbuf = 0;
237 return (NOSTR);
238 }
239 while ((c = *wp++) && c != ' ' && c != '\t') {
240 *wbuf++ = c;
241 if (c == '"') {
242 while ((c = *wp++) && c != '"')
243 *wbuf++ = c;
244 if (c == '"')
245 *wbuf++ = c;
246 else
247 wp--;
248 }
249 }
250 *wbuf = '\0';
251 for (; c == ' ' || c == '\t'; c = *wp++)
252 ;
253 if (c == 0)
254 return (NOSTR);
255 return (wp - 1);
256 }
257