1ef77d8e9Sdist /*
266f7b1b4Sbostic * Copyright (c) 1980, 1993
366f7b1b4Sbostic * The Regents of the University of California. All rights reserved.
413f94090Sbostic *
52b713f00Sbostic * %sccs.include.redist.c%
6ef77d8e9Sdist */
7ef77d8e9Sdist
88cab6285Sbostic #ifndef lint
9*6bd4f036Sdab static char sccsid[] = "@(#)head.c 8.2 (Berkeley) 04/20/95";
108cab6285Sbostic #endif /* not lint */
11068bc5fdSkas
12068bc5fdSkas #include "rcv.h"
1338ba7095Sbostic #include "extern.h"
14068bc5fdSkas
15068bc5fdSkas /*
16068bc5fdSkas * Mail -- a mail program
17068bc5fdSkas *
18068bc5fdSkas * Routines for processing and detecting headlines.
19068bc5fdSkas */
20068bc5fdSkas
21068bc5fdSkas /*
22068bc5fdSkas * See if the passed line buffer is a mail header.
23068bc5fdSkas * Return true if yes. Note the extreme pains to
24068bc5fdSkas * accomodate all funny formats.
25068bc5fdSkas */
2638ba7095Sbostic int
ishead(linebuf)27068bc5fdSkas ishead(linebuf)
28068bc5fdSkas char linebuf[];
29068bc5fdSkas {
30068bc5fdSkas register char *cp;
31068bc5fdSkas struct headline hl;
32068bc5fdSkas char parbuf[BUFSIZ];
33068bc5fdSkas
34068bc5fdSkas cp = linebuf;
35a1e0f4b8Sedward if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' ||
36a1e0f4b8Sedward *cp++ != ' ')
37068bc5fdSkas return (0);
38a1e0f4b8Sedward parse(linebuf, &hl, parbuf);
39068bc5fdSkas if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
40068bc5fdSkas fail(linebuf, "No from or date field");
41068bc5fdSkas return (0);
42068bc5fdSkas }
43068bc5fdSkas if (!isdate(hl.l_date)) {
44068bc5fdSkas fail(linebuf, "Date field not legal date");
45068bc5fdSkas return (0);
46068bc5fdSkas }
47068bc5fdSkas /*
48068bc5fdSkas * I guess we got it!
49068bc5fdSkas */
50068bc5fdSkas return (1);
51068bc5fdSkas }
52068bc5fdSkas
53a1e0f4b8Sedward /*ARGSUSED*/
5438ba7095Sbostic void
fail(linebuf,reason)55068bc5fdSkas fail(linebuf, reason)
56068bc5fdSkas char linebuf[], reason[];
57068bc5fdSkas {
58068bc5fdSkas
59a1e0f4b8Sedward /*
60a1e0f4b8Sedward if (value("debug") == NOSTR)
61068bc5fdSkas return;
62068bc5fdSkas fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
63a1e0f4b8Sedward */
64068bc5fdSkas }
65068bc5fdSkas
66068bc5fdSkas /*
67068bc5fdSkas * Split a headline into its useful components.
68068bc5fdSkas * Copy the line into dynamic string space, then set
69068bc5fdSkas * pointers into the copied line in the passed headline
70068bc5fdSkas * structure. Actually, it scans.
71068bc5fdSkas */
7238ba7095Sbostic void
parse(line,hl,pbuf)73068bc5fdSkas parse(line, hl, pbuf)
74068bc5fdSkas char line[], pbuf[];
75a1e0f4b8Sedward register struct headline *hl;
76068bc5fdSkas {
77a1e0f4b8Sedward register char *cp;
78068bc5fdSkas char *sp;
79068bc5fdSkas char word[LINESIZE];
80068bc5fdSkas
81068bc5fdSkas hl->l_from = NOSTR;
82068bc5fdSkas hl->l_tty = NOSTR;
83068bc5fdSkas hl->l_date = NOSTR;
84068bc5fdSkas cp = line;
85068bc5fdSkas sp = pbuf;
86068bc5fdSkas /*
87a1e0f4b8Sedward * Skip over "From" first.
88068bc5fdSkas */
89068bc5fdSkas cp = nextword(cp, word);
90a1e0f4b8Sedward cp = nextword(cp, word);
91a1e0f4b8Sedward if (*word)
92068bc5fdSkas hl->l_from = copyin(word, &sp);
93a1e0f4b8Sedward if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
94a1e0f4b8Sedward cp = nextword(cp, word);
95068bc5fdSkas hl->l_tty = copyin(word, &sp);
96a1e0f4b8Sedward }
97068bc5fdSkas if (cp != NOSTR)
98068bc5fdSkas hl->l_date = copyin(cp, &sp);
99068bc5fdSkas }
100068bc5fdSkas
101068bc5fdSkas /*
102068bc5fdSkas * Copy the string on the left into the string on the right
103068bc5fdSkas * and bump the right (reference) string pointer by the length.
104068bc5fdSkas * Thus, dynamically allocate space in the right string, copying
105068bc5fdSkas * the left string into it.
106068bc5fdSkas */
107068bc5fdSkas char *
copyin(src,space)108068bc5fdSkas copyin(src, space)
109a1e0f4b8Sedward register char *src;
110068bc5fdSkas char **space;
111068bc5fdSkas {
112a1e0f4b8Sedward register char *cp;
113a1e0f4b8Sedward char *top;
114068bc5fdSkas
115a1e0f4b8Sedward top = cp = *space;
116a1e0f4b8Sedward while (*cp++ = *src++)
117a1e0f4b8Sedward ;
118068bc5fdSkas *space = cp;
119068bc5fdSkas return (top);
120068bc5fdSkas }
121068bc5fdSkas
122068bc5fdSkas /*
123068bc5fdSkas * Test to see if the passed string is a ctime(3) generated
124068bc5fdSkas * date string as documented in the manual. The template
125068bc5fdSkas * below is used as the criterion of correctness.
126068bc5fdSkas * Also, we check for a possible trailing time zone using
127552a793fSedward * the tmztype template.
128068bc5fdSkas */
129068bc5fdSkas
130552a793fSedward /*
131552a793fSedward * 'A' An upper case char
132552a793fSedward * 'a' A lower case char
133552a793fSedward * ' ' A space
134552a793fSedward * '0' A digit
135552a793fSedward * 'O' An optional digit or space
136552a793fSedward * ':' A colon
137552a793fSedward * 'N' A new line
138552a793fSedward */
139552a793fSedward char ctype[] = "Aaa Aaa O0 00:00:00 0000";
140552a793fSedward char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000";
141*6bd4f036Sdab /*
142*6bd4f036Sdab * Yuck. If the mail file is created by Sys V (Solaris),
143*6bd4f036Sdab * there are no seconds in the time...
144*6bd4f036Sdab */
145*6bd4f036Sdab char SysV_ctype[] = "Aaa Aaa O0 00:00 0000";
146*6bd4f036Sdab char SysV_tmztype[] = "Aaa Aaa O0 00:00 AAA 0000";
147068bc5fdSkas
14838ba7095Sbostic int
isdate(date)149068bc5fdSkas isdate(date)
150068bc5fdSkas char date[];
151068bc5fdSkas {
152068bc5fdSkas
153*6bd4f036Sdab return cmatch(date, ctype) || cmatch(date, tmztype)
154*6bd4f036Sdab || cmatch(date, SysV_tmztype) || cmatch(date, SysV_ctype);
155068bc5fdSkas }
156068bc5fdSkas
157068bc5fdSkas /*
158a1e0f4b8Sedward * Match the given string (cp) against the given template (tp).
159068bc5fdSkas * Return 1 if they match, 0 if they don't
160068bc5fdSkas */
16138ba7095Sbostic int
cmatch(cp,tp)162a1e0f4b8Sedward cmatch(cp, tp)
163068bc5fdSkas register char *cp, *tp;
164a1e0f4b8Sedward {
165068bc5fdSkas
166a1e0f4b8Sedward while (*cp && *tp)
167068bc5fdSkas switch (*tp++) {
168552a793fSedward case 'a':
169a1e0f4b8Sedward if (!islower(*cp++))
170a1e0f4b8Sedward return 0;
171068bc5fdSkas break;
172552a793fSedward case 'A':
173a1e0f4b8Sedward if (!isupper(*cp++))
174a1e0f4b8Sedward return 0;
175068bc5fdSkas break;
176552a793fSedward case ' ':
177a1e0f4b8Sedward if (*cp++ != ' ')
178a1e0f4b8Sedward return 0;
179068bc5fdSkas break;
180552a793fSedward case '0':
181a1e0f4b8Sedward if (!isdigit(*cp++))
182a1e0f4b8Sedward return 0;
183068bc5fdSkas break;
184552a793fSedward case 'O':
185a1e0f4b8Sedward if (*cp != ' ' && !isdigit(*cp))
186a1e0f4b8Sedward return 0;
187a1e0f4b8Sedward cp++;
188068bc5fdSkas break;
189552a793fSedward case ':':
190a1e0f4b8Sedward if (*cp++ != ':')
191a1e0f4b8Sedward return 0;
192068bc5fdSkas break;
193552a793fSedward case 'N':
194a1e0f4b8Sedward if (*cp++ != '\n')
195a1e0f4b8Sedward return 0;
196068bc5fdSkas break;
197068bc5fdSkas }
198a1e0f4b8Sedward if (*cp || *tp)
199a1e0f4b8Sedward return 0;
200068bc5fdSkas return (1);
201068bc5fdSkas }
202068bc5fdSkas
203068bc5fdSkas /*
204068bc5fdSkas * Collect a liberal (space, tab delimited) word into the word buffer
205068bc5fdSkas * passed. Also, return a pointer to the next word following that,
206068bc5fdSkas * or NOSTR if none follow.
207068bc5fdSkas */
208068bc5fdSkas char *
nextword(wp,wbuf)209068bc5fdSkas nextword(wp, wbuf)
210a1e0f4b8Sedward register char *wp, *wbuf;
211068bc5fdSkas {
212068bc5fdSkas register c;
213068bc5fdSkas
214a1e0f4b8Sedward if (wp == NOSTR) {
215a1e0f4b8Sedward *wbuf = 0;
216a1e0f4b8Sedward return (NOSTR);
217a1e0f4b8Sedward }
218a1e0f4b8Sedward while ((c = *wp++) && c != ' ' && c != '\t') {
219a1e0f4b8Sedward *wbuf++ = c;
220a1e0f4b8Sedward if (c == '"') {
221a1e0f4b8Sedward while ((c = *wp++) && c != '"')
222a1e0f4b8Sedward *wbuf++ = c;
223a1e0f4b8Sedward if (c == '"')
224a1e0f4b8Sedward *wbuf++ = c;
225a1e0f4b8Sedward else
226a1e0f4b8Sedward wp--;
227a1e0f4b8Sedward }
228a1e0f4b8Sedward }
229a1e0f4b8Sedward *wbuf = '\0';
230a1e0f4b8Sedward for (; c == ' ' || c == '\t'; c = *wp++)
231a1e0f4b8Sedward ;
232a1e0f4b8Sedward if (c == 0)
233a1e0f4b8Sedward return (NOSTR);
234a1e0f4b8Sedward return (wp - 1);
235068bc5fdSkas }
236