Annotation of src/usr.bin/mail/head.c, Revision 1.8
1.8 ! todd 1: /* $OpenBSD: head.c,v 1.7 2001/11/21 15:26:39 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.7 millert 39: static const char sccsid[] = "@(#)head.c 8.2 (Berkeley) 4/20/95";
1.2 deraadt 40: #else
1.8 ! todd 41: static const char rcsid[] = "$OpenBSD: head.c,v 1.7 2001/11/21 15:26:39 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
1.8 ! todd 57: * accommodate all funny formats.
1.1 deraadt 58: */
59: int
1.7 millert 60: ishead(char *linebuf)
1.1 deraadt 61: {
1.5 millert 62: char *cp;
1.1 deraadt 63: struct headline hl;
64: char parbuf[BUFSIZ];
65:
66: cp = linebuf;
67: if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' ||
68: *cp++ != ' ')
1.3 millert 69: return(0);
1.1 deraadt 70: parse(linebuf, &hl, parbuf);
1.4 millert 71: if (hl.l_from == NULL || hl.l_date == NULL) {
1.1 deraadt 72: fail(linebuf, "No from or date field");
1.3 millert 73: return(0);
1.1 deraadt 74: }
75: if (!isdate(hl.l_date)) {
76: fail(linebuf, "Date field not legal date");
1.3 millert 77: return(0);
1.1 deraadt 78: }
79: /*
80: * I guess we got it!
81: */
1.3 millert 82: return(1);
1.1 deraadt 83: }
84:
85: /*ARGSUSED*/
86: void
1.7 millert 87: fail(char *linebuf, char *reason)
1.1 deraadt 88: {
89:
90: /*
1.4 millert 91: if (value("debug") == NULL)
1.1 deraadt 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
1.7 millert 104: parse(char *line, struct headline *hl, char *pbuf)
1.1 deraadt 105: {
1.5 millert 106: char *cp, *sp;
1.1 deraadt 107: char word[LINESIZE];
108:
1.4 millert 109: hl->l_from = NULL;
110: hl->l_tty = NULL;
111: hl->l_date = NULL;
1.1 deraadt 112: cp = line;
113: sp = pbuf;
114: /*
115: * Skip over "From" first.
116: */
117: cp = nextword(cp, word);
118: cp = nextword(cp, word);
119: if (*word)
120: hl->l_from = copyin(word, &sp);
1.4 millert 121: if (cp != NULL && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
1.1 deraadt 122: cp = nextword(cp, word);
123: hl->l_tty = copyin(word, &sp);
124: }
1.4 millert 125: if (cp != NULL)
1.1 deraadt 126: hl->l_date = copyin(cp, &sp);
127: }
128:
129: /*
130: * Copy the string on the left into the string on the right
131: * and bump the right (reference) string pointer by the length.
132: * Thus, dynamically allocate space in the right string, copying
133: * the left string into it.
134: */
135: char *
1.7 millert 136: copyin(char *src, char **space)
1.1 deraadt 137: {
1.5 millert 138: char *cp, *top;
1.1 deraadt 139:
140: top = cp = *space;
1.2 deraadt 141: while ((*cp++ = *src++) != '\0')
1.1 deraadt 142: ;
143: *space = cp;
1.3 millert 144: return(top);
1.1 deraadt 145: }
146:
147: /*
148: * Test to see if the passed string is a ctime(3) generated
149: * date string as documented in the manual. The template
150: * below is used as the criterion of correctness.
151: * Also, we check for a possible trailing time zone using
152: * the tmztype template.
153: */
154:
155: /*
156: * 'A' An upper case char
157: * 'a' A lower case char
158: * ' ' A space
159: * '0' A digit
1.6 millert 160: * 'O' A digit or space
161: * 'p' A punctuation char
162: * 'P' A punctuation char or space
1.1 deraadt 163: * ':' A colon
164: * 'N' A new line
165: */
1.6 millert 166:
1.3 millert 167: /*
168: * Yuck. If the mail file is created by Sys V (Solaris),
169: * there are no seconds in the time...
170: */
1.6 millert 171:
172: /*
173: * If the mail is created by another program such as imapd, it might
174: * have timezone as <-|+>nnnn (-0800 for instance) at the end.
175: */
176:
177: static char *date_formats[] = {
178: "Aaa Aaa O0 00:00:00 0000", /* Mon Jan 01 23:59:59 2001 */
179: "Aaa Aaa O0 00:00:00 AAA 0000", /* Mon Jan 01 23:59:59 PST 2001 */
180: "Aaa Aaa O0 00:00:00 0000 p0000", /* Mon Jan 01 23:59:59 2001 -0800 */
181: "Aaa Aaa O0 00:00 0000", /* Mon Jan 01 23:59 2001 */
182: "Aaa Aaa O0 00:00 AAA 0000", /* Mon Jan 01 23:59 PST 2001 */
183: "Aaa Aaa O0 00:00 0000 p0000", /* Mon Jan 01 23:59 2001 -0800 */
184: ""
185: };
1.1 deraadt 186:
187: int
1.7 millert 188: isdate(char *date)
1.1 deraadt 189: {
1.6 millert 190: int i;
1.1 deraadt 191:
1.6 millert 192: for(i = 0; *date_formats[i]; i++) {
193: if (cmatch(date, date_formats[i]))
194: return 1;
195: }
196: return 0;
1.1 deraadt 197: }
198:
199: /*
200: * Match the given string (cp) against the given template (tp).
201: * Return 1 if they match, 0 if they don't
202: */
203: int
1.7 millert 204: cmatch(char *cp, char *tp)
1.1 deraadt 205: {
206:
207: while (*cp && *tp)
208: switch (*tp++) {
209: case 'a':
210: if (!islower(*cp++))
1.3 millert 211: return(0);
1.1 deraadt 212: break;
213: case 'A':
214: if (!isupper(*cp++))
1.3 millert 215: return(0);
1.1 deraadt 216: break;
217: case ' ':
218: if (*cp++ != ' ')
1.3 millert 219: return(0);
1.1 deraadt 220: break;
221: case '0':
222: if (!isdigit(*cp++))
1.3 millert 223: return(0);
1.1 deraadt 224: break;
225: case 'O':
226: if (*cp != ' ' && !isdigit(*cp))
1.6 millert 227: return(0);
228: cp++;
229: break;
230: case 'p':
231: if (!ispunct(*cp++))
232: return(0);
233: break;
234: case 'P':
235: if (*cp != ' ' && !ispunct(*cp))
1.3 millert 236: return(0);
1.1 deraadt 237: cp++;
238: break;
239: case ':':
240: if (*cp++ != ':')
1.3 millert 241: return(0);
1.1 deraadt 242: break;
243: case 'N':
244: if (*cp++ != '\n')
1.3 millert 245: return(0);
1.1 deraadt 246: break;
247: }
248: if (*cp || *tp)
1.3 millert 249: return(0);
250: return(1);
1.1 deraadt 251: }
252:
253: /*
254: * Collect a liberal (space, tab delimited) word into the word buffer
255: * passed. Also, return a pointer to the next word following that,
1.4 millert 256: * or NULL if none follow.
1.1 deraadt 257: */
258: char *
1.7 millert 259: nextword(char *wp, char *wbuf)
1.1 deraadt 260: {
1.5 millert 261: int c;
1.1 deraadt 262:
1.4 millert 263: if (wp == NULL) {
1.1 deraadt 264: *wbuf = 0;
1.4 millert 265: return(NULL);
1.1 deraadt 266: }
267: while ((c = *wp++) && c != ' ' && c != '\t') {
268: *wbuf++ = c;
269: if (c == '"') {
270: while ((c = *wp++) && c != '"')
271: *wbuf++ = c;
272: if (c == '"')
273: *wbuf++ = c;
274: else
275: wp--;
276: }
277: }
278: *wbuf = '\0';
279: for (; c == ' ' || c == '\t'; c = *wp++)
280: ;
281: if (c == 0)
1.4 millert 282: return(NULL);
1.3 millert 283: return(wp - 1);
1.1 deraadt 284: }