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