add imagen
[unix-history] / usr / src / usr.bin / mail / head.c
CommitLineData
9552e6b8
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
2ae9f53f 7#ifndef lint
2fd8b883 8static char *sccsid = "@(#)head.c 5.2 (Berkeley) %G%";
9552e6b8 9#endif not lint
6a550447
KS
10
11#include "rcv.h"
12
13/*
14 * Mail -- a mail program
15 *
16 * Routines for processing and detecting headlines.
17 */
18
6a550447
KS
19/*
20 * See if the passed line buffer is a mail header.
21 * Return true if yes. Note the extreme pains to
22 * accomodate all funny formats.
23 */
24
25ishead(linebuf)
26 char linebuf[];
27{
28 register char *cp;
29 struct headline hl;
30 char parbuf[BUFSIZ];
31
32 cp = linebuf;
18215574 33 if (strncmp("From ", cp, 5) != 0)
6a550447
KS
34 return(0);
35 parse(cp, &hl, parbuf);
36 if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
37 fail(linebuf, "No from or date field");
38 return(0);
39 }
40 if (!isdate(hl.l_date)) {
41 fail(linebuf, "Date field not legal date");
42 return(0);
43 }
44
45 /*
46 * I guess we got it!
47 */
48
49 return(1);
50}
51
52fail(linebuf, reason)
53 char linebuf[], reason[];
54{
55
56 if (1 /*value("debug") == NOSTR*/)
57 return;
58 fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
59}
60
61/*
62 * Split a headline into its useful components.
63 * Copy the line into dynamic string space, then set
64 * pointers into the copied line in the passed headline
65 * structure. Actually, it scans.
66 */
67
68parse(line, hl, pbuf)
69 char line[], pbuf[];
70 struct headline *hl;
71{
72 register char *cp, *dp;
73 char *sp;
74 char word[LINESIZE];
75
76 hl->l_from = NOSTR;
77 hl->l_tty = NOSTR;
78 hl->l_date = NOSTR;
79 cp = line;
80 sp = pbuf;
81
82 /*
83 * Skip the first "word" of the line, which should be "From"
84 * anyway.
85 */
86
87 cp = nextword(cp, word);
88 dp = nextword(cp, word);
89 if (!equal(word, ""))
90 hl->l_from = copyin(word, &sp);
18215574 91 if (strncmp(dp, "tty", 3) == 0) {
6a550447
KS
92 cp = nextword(dp, word);
93 hl->l_tty = copyin(word, &sp);
94 if (cp != NOSTR)
95 hl->l_date = copyin(cp, &sp);
96 }
97 else
98 if (dp != NOSTR)
99 hl->l_date = copyin(dp, &sp);
100}
101
102/*
103 * Copy the string on the left into the string on the right
104 * and bump the right (reference) string pointer by the length.
105 * Thus, dynamically allocate space in the right string, copying
106 * the left string into it.
107 */
108
109char *
110copyin(src, space)
111 char src[];
112 char **space;
113{
114 register char *cp, *top;
115 register int s;
116
117 s = strlen(src);
118 cp = *space;
119 top = cp;
120 strcpy(cp, src);
121 cp += s + 1;
122 *space = cp;
123 return(top);
124}
125
6a550447
KS
126/*
127 * Test to see if the passed string is a ctime(3) generated
128 * date string as documented in the manual. The template
129 * below is used as the criterion of correctness.
130 * Also, we check for a possible trailing time zone using
131 * the auxtype template.
132 */
133
134#define L 1 /* A lower case char */
135#define S 2 /* A space */
136#define D 3 /* A digit */
137#define O 4 /* An optional digit or space */
138#define C 5 /* A colon */
139#define N 6 /* A new line */
140#define U 7 /* An upper case char */
141
142char ctypes[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,D,D,D,D,0};
143char tmztypes[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,U,U,U,S,D,D,D,D,0};
144
145isdate(date)
146 char date[];
147{
148 register char *cp;
149
150 cp = date;
151 if (cmatch(cp, ctypes))
152 return(1);
153 return(cmatch(cp, tmztypes));
154}
155
156/*
157 * Match the given string against the given template.
158 * Return 1 if they match, 0 if they don't
159 */
160
161cmatch(str, temp)
162 char str[], temp[];
163{
164 register char *cp, *tp;
165 register int c;
166
167 cp = str;
168 tp = temp;
169 while (*cp != '\0' && *tp != 0) {
170 c = *cp++;
171 switch (*tp++) {
172 case L:
173 if (c < 'a' || c > 'z')
174 return(0);
175 break;
176
177 case U:
178 if (c < 'A' || c > 'Z')
179 return(0);
180 break;
181
182 case S:
183 if (c != ' ')
184 return(0);
185 break;
186
187 case D:
188 if (!isdigit(c))
189 return(0);
190 break;
191
192 case O:
193 if (c != ' ' && !isdigit(c))
194 return(0);
195 break;
196
197 case C:
198 if (c != ':')
199 return(0);
200 break;
201
202 case N:
203 if (c != '\n')
204 return(0);
205 break;
206 }
207 }
208 if (*cp != '\0' || *tp != 0)
209 return(0);
210 return(1);
211}
212
213/*
214 * Collect a liberal (space, tab delimited) word into the word buffer
215 * passed. Also, return a pointer to the next word following that,
216 * or NOSTR if none follow.
217 */
218
219char *
220nextword(wp, wbuf)
221 char wp[], wbuf[];
222{
223 register char *cp, *cp2;
224
225 if ((cp = wp) == NOSTR) {
226 copy("", wbuf);
227 return(NOSTR);
228 }
229 cp2 = wbuf;
230 while (!any(*cp, " \t") && *cp != '\0')
3c5eb507
CL
231 if (*cp == '"') {
232 *cp2++ = *cp++;
233 while (*cp != '\0' && *cp != '"')
234 *cp2++ = *cp++;
235 if (*cp == '"')
236 *cp2++ = *cp++;
237 } else
238 *cp2++ = *cp++;
6a550447
KS
239 *cp2 = '\0';
240 while (any(*cp, " \t"))
241 cp++;
242 if (*cp == '\0')
243 return(NOSTR);
244 return(cp);
245}
246
247/*
248 * Test to see if the character is an ascii alphabetic.
249 */
250
251isalpha(c)
252{
253 register int ch;
254
255 ch = raise(c);
256 return(ch >= 'A' && ch <= 'Z');
257}
258
259/*
260 * Test to see if the character is an ascii digit.
261 */
262
263isdigit(c)
264{
265 return(c >= '0' && c <= '9');
266}
267
268/*
269 * Copy str1 to str2, return pointer to null in str2.
270 */
271
272char *
273copy(str1, str2)
274 char *str1, *str2;
275{
276 register char *s1, *s2;
277
278 s1 = str1;
279 s2 = str2;
280 while (*s1)
281 *s2++ = *s1++;
282 *s2 = 0;
283 return(s2);
284}
285
286/*
287 * Is ch any of the characters in str?
288 */
289
290any(ch, str)
291 char *str;
292{
293 register char *f;
294 register c;
295
296 f = str;
297 c = ch;
298 while (*f)
299 if (c == *f++)
300 return(1);
301 return(0);
302}
303
304/*
305 * Convert lower case letters to upper case.
306 */
307
308raise(c)
309 register int c;
310{
311 if (c >= 'a' && c <= 'z')
312 c += 'A' - 'a';
313 return(c);
314}