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