1 /*
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)head.c 8.2 (Berkeley) 04/20/95";
10 #endif /* not lint */
11
12 #include "rcv.h"
13 #include "extern.h"
14
15 /*
16 * Mail -- a mail program
17 *
18 * Routines for processing and detecting headlines.
19 */
20
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 */
26 int
ishead(linebuf)27 ishead(linebuf)
28 char linebuf[];
29 {
30 register char *cp;
31 struct headline hl;
32 char parbuf[BUFSIZ];
33
34 cp = linebuf;
35 if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' ||
36 *cp++ != ' ')
37 return (0);
38 parse(linebuf, &hl, parbuf);
39 if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
40 fail(linebuf, "No from or date field");
41 return (0);
42 }
43 if (!isdate(hl.l_date)) {
44 fail(linebuf, "Date field not legal date");
45 return (0);
46 }
47 /*
48 * I guess we got it!
49 */
50 return (1);
51 }
52
53 /*ARGSUSED*/
54 void
fail(linebuf,reason)55 fail(linebuf, reason)
56 char linebuf[], reason[];
57 {
58
59 /*
60 if (value("debug") == NOSTR)
61 return;
62 fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
63 */
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 */
72 void
parse(line,hl,pbuf)73 parse(line, hl, pbuf)
74 char line[], pbuf[];
75 register struct headline *hl;
76 {
77 register char *cp;
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;
86 /*
87 * Skip over "From" first.
88 */
89 cp = nextword(cp, word);
90 cp = nextword(cp, word);
91 if (*word)
92 hl->l_from = copyin(word, &sp);
93 if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
94 cp = nextword(cp, word);
95 hl->l_tty = copyin(word, &sp);
96 }
97 if (cp != NOSTR)
98 hl->l_date = copyin(cp, &sp);
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 */
107 char *
copyin(src,space)108 copyin(src, space)
109 register char *src;
110 char **space;
111 {
112 register char *cp;
113 char *top;
114
115 top = cp = *space;
116 while (*cp++ = *src++)
117 ;
118 *space = cp;
119 return (top);
120 }
121
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
127 * the tmztype template.
128 */
129
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 */
139 char ctype[] = "Aaa Aaa O0 00:00:00 0000";
140 char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000";
141 /*
142 * Yuck. If the mail file is created by Sys V (Solaris),
143 * there are no seconds in the time...
144 */
145 char SysV_ctype[] = "Aaa Aaa O0 00:00 0000";
146 char SysV_tmztype[] = "Aaa Aaa O0 00:00 AAA 0000";
147
148 int
isdate(date)149 isdate(date)
150 char date[];
151 {
152
153 return cmatch(date, ctype) || cmatch(date, tmztype)
154 || cmatch(date, SysV_tmztype) || cmatch(date, SysV_ctype);
155 }
156
157 /*
158 * Match the given string (cp) against the given template (tp).
159 * Return 1 if they match, 0 if they don't
160 */
161 int
cmatch(cp,tp)162 cmatch(cp, tp)
163 register char *cp, *tp;
164 {
165
166 while (*cp && *tp)
167 switch (*tp++) {
168 case 'a':
169 if (!islower(*cp++))
170 return 0;
171 break;
172 case 'A':
173 if (!isupper(*cp++))
174 return 0;
175 break;
176 case ' ':
177 if (*cp++ != ' ')
178 return 0;
179 break;
180 case '0':
181 if (!isdigit(*cp++))
182 return 0;
183 break;
184 case 'O':
185 if (*cp != ' ' && !isdigit(*cp))
186 return 0;
187 cp++;
188 break;
189 case ':':
190 if (*cp++ != ':')
191 return 0;
192 break;
193 case 'N':
194 if (*cp++ != '\n')
195 return 0;
196 break;
197 }
198 if (*cp || *tp)
199 return 0;
200 return (1);
201 }
202
203 /*
204 * Collect a liberal (space, tab delimited) word into the word buffer
205 * passed. Also, return a pointer to the next word following that,
206 * or NOSTR if none follow.
207 */
208 char *
nextword(wp,wbuf)209 nextword(wp, wbuf)
210 register char *wp, *wbuf;
211 {
212 register c;
213
214 if (wp == NOSTR) {
215 *wbuf = 0;
216 return (NOSTR);
217 }
218 while ((c = *wp++) && c != ' ' && c != '\t') {
219 *wbuf++ = c;
220 if (c == '"') {
221 while ((c = *wp++) && c != '"')
222 *wbuf++ = c;
223 if (c == '"')
224 *wbuf++ = c;
225 else
226 wp--;
227 }
228 }
229 *wbuf = '\0';
230 for (; c == ' ' || c == '\t'; c = *wp++)
231 ;
232 if (c == 0)
233 return (NOSTR);
234 return (wp - 1);
235 }
236