4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / usr.bin / mail / head.c
CommitLineData
9552e6b8 1/*
a12ff486
KB
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
0c5f72fb 4 *
f15db449 5 * %sccs.include.redist.c%
9552e6b8
DF
6 */
7
acfc7e9b 8#ifndef lint
a12ff486 9static char sccsid[] = "@(#)head.c 8.1 (Berkeley) %G%";
acfc7e9b 10#endif /* not lint */
6a550447
KS
11
12#include "rcv.h"
a0d23834 13#include "extern.h"
6a550447
KS
14
15/*
16 * Mail -- a mail program
17 *
18 * Routines for processing and detecting headlines.
19 */
20
6a550447
KS
21/*
22 * See if the passed line buffer is a mail header.
23 * Return true if yes. Note the extreme pains to
24 * accomodate all funny formats.
25 */
a0d23834 26int
6a550447
KS
27ishead(linebuf)
28 char linebuf[];
29{
30 register char *cp;
31 struct headline hl;
32 char parbuf[BUFSIZ];
33
34 cp = linebuf;
828615a1
EW
35 if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' ||
36 *cp++ != ' ')
37 return (0);
38 parse(linebuf, &hl, parbuf);
6a550447
KS
39 if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
40 fail(linebuf, "No from or date field");
828615a1 41 return (0);
6a550447
KS
42 }
43 if (!isdate(hl.l_date)) {
44 fail(linebuf, "Date field not legal date");
828615a1 45 return (0);
6a550447 46 }
6a550447
KS
47 /*
48 * I guess we got it!
49 */
828615a1 50 return (1);
6a550447
KS
51}
52
828615a1 53/*ARGSUSED*/
a0d23834 54void
6a550447
KS
55fail(linebuf, reason)
56 char linebuf[], reason[];
57{
58
828615a1
EW
59 /*
60 if (value("debug") == NOSTR)
6a550447
KS
61 return;
62 fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
828615a1 63 */
6a550447
KS
64}
65
66/*
67 * Split a headline into its useful components.
68 * Copy the line into dynamic string space, then set
69 * pointers into the copied line in the passed headline
70 * structure. Actually, it scans.
71 */
a0d23834 72void
6a550447
KS
73parse(line, hl, pbuf)
74 char line[], pbuf[];
828615a1 75 register struct headline *hl;
6a550447 76{
828615a1 77 register char *cp;
6a550447
KS
78 char *sp;
79 char word[LINESIZE];
80
81 hl->l_from = NOSTR;
82 hl->l_tty = NOSTR;
83 hl->l_date = NOSTR;
84 cp = line;
85 sp = pbuf;
6a550447 86 /*
828615a1 87 * Skip over "From" first.
6a550447 88 */
6a550447 89 cp = nextword(cp, word);
828615a1
EW
90 cp = nextword(cp, word);
91 if (*word)
6a550447 92 hl->l_from = copyin(word, &sp);
828615a1
EW
93 if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
94 cp = nextword(cp, word);
6a550447 95 hl->l_tty = copyin(word, &sp);
6a550447 96 }
828615a1
EW
97 if (cp != NOSTR)
98 hl->l_date = copyin(cp, &sp);
6a550447
KS
99}
100
101/*
102 * Copy the string on the left into the string on the right
103 * and bump the right (reference) string pointer by the length.
104 * Thus, dynamically allocate space in the right string, copying
105 * the left string into it.
106 */
6a550447
KS
107char *
108copyin(src, space)
828615a1 109 register char *src;
6a550447
KS
110 char **space;
111{
828615a1
EW
112 register char *cp;
113 char *top;
6a550447 114
828615a1
EW
115 top = cp = *space;
116 while (*cp++ = *src++)
117 ;
6a550447 118 *space = cp;
828615a1 119 return (top);
6a550447
KS
120}
121
6a550447
KS
122/*
123 * Test to see if the passed string is a ctime(3) generated
124 * date string as documented in the manual. The template
125 * below is used as the criterion of correctness.
126 * Also, we check for a possible trailing time zone using
470c33f3 127 * the tmztype template.
6a550447
KS
128 */
129
470c33f3
EW
130/*
131 * 'A' An upper case char
132 * 'a' A lower case char
133 * ' ' A space
134 * '0' A digit
135 * 'O' An optional digit or space
136 * ':' A colon
137 * 'N' A new line
138 */
139char ctype[] = "Aaa Aaa O0 00:00:00 0000";
140char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000";
6a550447 141
a0d23834 142int
6a550447
KS
143isdate(date)
144 char date[];
145{
6a550447 146
470c33f3 147 return cmatch(date, ctype) || cmatch(date, tmztype);
6a550447
KS
148}
149
150/*
828615a1 151 * Match the given string (cp) against the given template (tp).
6a550447
KS
152 * Return 1 if they match, 0 if they don't
153 */
a0d23834 154int
828615a1 155cmatch(cp, tp)
6a550447 156 register char *cp, *tp;
828615a1 157{
6a550447 158
828615a1 159 while (*cp && *tp)
6a550447 160 switch (*tp++) {
470c33f3 161 case 'a':
828615a1
EW
162 if (!islower(*cp++))
163 return 0;
6a550447 164 break;
470c33f3 165 case 'A':
828615a1
EW
166 if (!isupper(*cp++))
167 return 0;
6a550447 168 break;
470c33f3 169 case ' ':
828615a1
EW
170 if (*cp++ != ' ')
171 return 0;
6a550447 172 break;
470c33f3 173 case '0':
828615a1
EW
174 if (!isdigit(*cp++))
175 return 0;
6a550447 176 break;
470c33f3 177 case 'O':
828615a1
EW
178 if (*cp != ' ' && !isdigit(*cp))
179 return 0;
180 cp++;
6a550447 181 break;
470c33f3 182 case ':':
828615a1
EW
183 if (*cp++ != ':')
184 return 0;
6a550447 185 break;
470c33f3 186 case 'N':
828615a1
EW
187 if (*cp++ != '\n')
188 return 0;
6a550447
KS
189 break;
190 }
828615a1
EW
191 if (*cp || *tp)
192 return 0;
193 return (1);
6a550447
KS
194}
195
196/*
197 * Collect a liberal (space, tab delimited) word into the word buffer
198 * passed. Also, return a pointer to the next word following that,
199 * or NOSTR if none follow.
200 */
6a550447
KS
201char *
202nextword(wp, wbuf)
828615a1 203 register char *wp, *wbuf;
6a550447 204{
828615a1 205 register c;
6a550447 206
828615a1
EW
207 if (wp == NOSTR) {
208 *wbuf = 0;
209 return (NOSTR);
6a550447 210 }
828615a1
EW
211 while ((c = *wp++) && c != ' ' && c != '\t') {
212 *wbuf++ = c;
213 if (c == '"') {
214 while ((c = *wp++) && c != '"')
215 *wbuf++ = c;
216 if (c == '"')
217 *wbuf++ = c;
218 else
219 wp--;
220 }
221 }
222 *wbuf = '\0';
223 for (; c == ' ' || c == '\t'; c = *wp++)
224 ;
225 if (c == 0)
226 return (NOSTR);
227 return (wp - 1);
6a550447 228}