Annotation of src/usr.bin/mail/head.c, Revision 1.6
1.6 ! millert 1: /* $OpenBSD: head.c,v 1.5 1997/11/14 00:23:48 millert 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.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
1.2 deraadt 38: #if 0
1.3 millert 39: static char sccsid[] = "@(#)head.c 8.2 (Berkeley) 4/20/95";
1.2 deraadt 40: #else
1.6 ! millert 41: static char rcsid[] = "$OpenBSD: head.c,v 1.5 1997/11/14 00:23:48 millert Exp $";
1.2 deraadt 42: #endif
1.1 deraadt 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(linebuf)
61: char linebuf[];
62: {
1.5 millert 63: char *cp;
1.1 deraadt 64: struct headline hl;
65: char parbuf[BUFSIZ];
66:
67: cp = linebuf;
68: if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' ||
69: *cp++ != ' ')
1.3 millert 70: return(0);
1.1 deraadt 71: parse(linebuf, &hl, parbuf);
1.4 millert 72: if (hl.l_from == NULL || hl.l_date == NULL) {
1.1 deraadt 73: fail(linebuf, "No from or date field");
1.3 millert 74: return(0);
1.1 deraadt 75: }
76: if (!isdate(hl.l_date)) {
77: fail(linebuf, "Date field not legal date");
1.3 millert 78: return(0);
1.1 deraadt 79: }
80: /*
81: * I guess we got it!
82: */
1.3 millert 83: return(1);
1.1 deraadt 84: }
85:
86: /*ARGSUSED*/
87: void
88: fail(linebuf, reason)
89: char linebuf[], reason[];
90: {
91:
92: /*
1.4 millert 93: if (value("debug") == NULL)
1.1 deraadt 94: return;
95: fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
96: */
97: }
98:
99: /*
100: * Split a headline into its useful components.
101: * Copy the line into dynamic string space, then set
102: * pointers into the copied line in the passed headline
103: * structure. Actually, it scans.
104: */
105: void
106: parse(line, hl, pbuf)
107: char line[], pbuf[];
1.5 millert 108: struct headline *hl;
1.1 deraadt 109: {
1.5 millert 110: char *cp, *sp;
1.1 deraadt 111: char word[LINESIZE];
112:
1.4 millert 113: hl->l_from = NULL;
114: hl->l_tty = NULL;
115: hl->l_date = NULL;
1.1 deraadt 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);
1.4 millert 125: if (cp != NULL && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
1.1 deraadt 126: cp = nextword(cp, word);
127: hl->l_tty = copyin(word, &sp);
128: }
1.4 millert 129: if (cp != NULL)
1.1 deraadt 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)
1.5 millert 141: char *src;
1.1 deraadt 142: char **space;
143: {
1.5 millert 144: char *cp, *top;
1.1 deraadt 145:
146: top = cp = *space;
1.2 deraadt 147: while ((*cp++ = *src++) != '\0')
1.1 deraadt 148: ;
149: *space = cp;
1.3 millert 150: return(top);
1.1 deraadt 151: }
152:
153: /*
154: * Test to see if the passed string is a ctime(3) generated
155: * date string as documented in the manual. The template
156: * below is used as the criterion of correctness.
157: * Also, we check for a possible trailing time zone using
158: * the tmztype template.
159: */
160:
161: /*
162: * 'A' An upper case char
163: * 'a' A lower case char
164: * ' ' A space
165: * '0' A digit
1.6 ! millert 166: * 'O' A digit or space
! 167: * 'p' A punctuation char
! 168: * 'P' A punctuation char or space
1.1 deraadt 169: * ':' A colon
170: * 'N' A new line
171: */
1.6 ! millert 172:
1.3 millert 173: /*
174: * Yuck. If the mail file is created by Sys V (Solaris),
175: * there are no seconds in the time...
176: */
1.6 ! millert 177:
! 178: /*
! 179: * If the mail is created by another program such as imapd, it might
! 180: * have timezone as <-|+>nnnn (-0800 for instance) at the end.
! 181: */
! 182:
! 183: static char *date_formats[] = {
! 184: "Aaa Aaa O0 00:00:00 0000", /* Mon Jan 01 23:59:59 2001 */
! 185: "Aaa Aaa O0 00:00:00 AAA 0000", /* Mon Jan 01 23:59:59 PST 2001 */
! 186: "Aaa Aaa O0 00:00:00 0000 p0000", /* Mon Jan 01 23:59:59 2001 -0800 */
! 187: "Aaa Aaa O0 00:00 0000", /* Mon Jan 01 23:59 2001 */
! 188: "Aaa Aaa O0 00:00 AAA 0000", /* Mon Jan 01 23:59 PST 2001 */
! 189: "Aaa Aaa O0 00:00 0000 p0000", /* Mon Jan 01 23:59 2001 -0800 */
! 190: ""
! 191: };
1.1 deraadt 192:
193: int
194: isdate(date)
195: char date[];
196: {
1.6 ! millert 197: int i;
1.1 deraadt 198:
1.6 ! millert 199: for(i = 0; *date_formats[i]; i++) {
! 200: if (cmatch(date, date_formats[i]))
! 201: return 1;
! 202: }
! 203: return 0;
1.1 deraadt 204: }
205:
206: /*
207: * Match the given string (cp) against the given template (tp).
208: * Return 1 if they match, 0 if they don't
209: */
210: int
211: cmatch(cp, tp)
1.5 millert 212: char *cp, *tp;
1.1 deraadt 213: {
214:
215: while (*cp && *tp)
216: switch (*tp++) {
217: case 'a':
218: if (!islower(*cp++))
1.3 millert 219: return(0);
1.1 deraadt 220: break;
221: case 'A':
222: if (!isupper(*cp++))
1.3 millert 223: return(0);
1.1 deraadt 224: break;
225: case ' ':
226: if (*cp++ != ' ')
1.3 millert 227: return(0);
1.1 deraadt 228: break;
229: case '0':
230: if (!isdigit(*cp++))
1.3 millert 231: return(0);
1.1 deraadt 232: break;
233: case 'O':
234: if (*cp != ' ' && !isdigit(*cp))
1.6 ! millert 235: return(0);
! 236: cp++;
! 237: break;
! 238: case 'p':
! 239: if (!ispunct(*cp++))
! 240: return(0);
! 241: break;
! 242: case 'P':
! 243: if (*cp != ' ' && !ispunct(*cp))
1.3 millert 244: return(0);
1.1 deraadt 245: cp++;
246: break;
247: case ':':
248: if (*cp++ != ':')
1.3 millert 249: return(0);
1.1 deraadt 250: break;
251: case 'N':
252: if (*cp++ != '\n')
1.3 millert 253: return(0);
1.1 deraadt 254: break;
255: }
256: if (*cp || *tp)
1.3 millert 257: return(0);
258: return(1);
1.1 deraadt 259: }
260:
261: /*
262: * Collect a liberal (space, tab delimited) word into the word buffer
263: * passed. Also, return a pointer to the next word following that,
1.4 millert 264: * or NULL if none follow.
1.1 deraadt 265: */
266: char *
267: nextword(wp, wbuf)
1.5 millert 268: char *wp, *wbuf;
1.1 deraadt 269: {
1.5 millert 270: int c;
1.1 deraadt 271:
1.4 millert 272: if (wp == NULL) {
1.1 deraadt 273: *wbuf = 0;
1.4 millert 274: return(NULL);
1.1 deraadt 275: }
276: while ((c = *wp++) && c != ' ' && c != '\t') {
277: *wbuf++ = c;
278: if (c == '"') {
279: while ((c = *wp++) && c != '"')
280: *wbuf++ = c;
281: if (c == '"')
282: *wbuf++ = c;
283: else
284: wp--;
285: }
286: }
287: *wbuf = '\0';
288: for (; c == ' ' || c == '\t'; c = *wp++)
289: ;
290: if (c == 0)
1.4 millert 291: return(NULL);
1.3 millert 292: return(wp - 1);
1.1 deraadt 293: }