1 /* $OpenBSD: head.c,v 1.5 1996/06/08 19:48:26 christos Exp $ */
2 /* $NetBSD: head.c,v 1.5 1996/06/08 19:48:26 christos Exp $ */
3
4 /*
5 * Copyright (c) 1980, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 /*#include "def.h"*/
38 #include "head.h"
39
40 /*
41 * Mail -- a mail program
42 *
43 * Routines for processing and detecting headlines.
44 */
45
46 /*
47 * See if the passed line buffer is a mail header.
48 * Return true if yes. Note the extreme pains to
49 * accomodate all funny formats.
50 */
ishead(char * linebuf)51 int ishead(char *linebuf)
52 {
53 register char *cp;
54 struct headline hl;
55 char parbuf[BUFSIZ];
56
57 cp = linebuf;
58 if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' ||
59 *cp++ != ' ')
60 return (0);
61 parse(linebuf, &hl, parbuf);
62 if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
63 fail(linebuf, "No from or date field");
64 return (0);
65 }
66 if (!isdate(hl.l_date)) {
67 fail(linebuf, "Date field not legal date");
68 return (0);
69 }
70 /*
71 * I guess we got it!
72 */
73 return (1);
74 }
75
76 /*ARGSUSED*/
fail(char * linebuf,char * reason)77 void fail(char *linebuf, char *reason)
78 {
79
80 /*
81 if (value("debug") == NOSTR)
82 return;
83 fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
84 */
85 }
86
87 /*
88 * Split a headline into its useful components.
89 * Copy the line into dynamic string space, then set
90 * pointers into the copied line in the passed headline
91 * structure. Actually, it scans.
92 */
parse(char * line,register struct headline * hl,char * pbuf)93 void parse(char *line, register struct headline *hl, char *pbuf)
94 {
95 register char *cp;
96 char *sp;
97 char word[LINESIZE];
98
99 hl->l_from = NOSTR;
100 hl->l_tty = NOSTR;
101 hl->l_date = NOSTR;
102 cp = line;
103 sp = pbuf;
104 /*
105 * Skip over "From" first.
106 */
107 cp = nextword(cp, word);
108 cp = nextword(cp, word);
109 if (*word)
110 hl->l_from = copyin(word, &sp);
111 if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
112 cp = nextword(cp, word);
113 hl->l_tty = copyin(word, &sp);
114 }
115 if (cp != NOSTR)
116 hl->l_date = copyin(cp, &sp);
117 }
118
119 /*
120 * Copy the string on the left into the string on the right
121 * and bump the right (reference) string pointer by the length.
122 * Thus, dynamically allocate space in the right string, copying
123 * the left string into it.
124 */
copyin(register char * src,char ** space)125 char * copyin(register char *src, char **space)
126 {
127 register char *cp;
128 char *top;
129
130 top = cp = *space;
131 while ((*cp++ = *src++) != '\0')
132 ;
133 *space = cp;
134 return (top);
135 }
136
137 /*
138 * Test to see if the passed string is a ctime(3) generated
139 * date string as documented in the manual. The template
140 * below is used as the criterion of correctness.
141 * Also, we check for a possible trailing time zone using
142 * the tmztype template.
143 */
144
145 /*
146 * 'A' An upper case char
147 * 'a' A lower case char
148 * ' ' A space
149 * '0' A digit
150 * 'O' An optional digit or space
151 * ':' A colon
152 * 'N' A new line
153 */
154 char ctype[] = "Aaa Aaa O0 00:00:00 0000";
155 char ctype_without_secs[] = "Aaa Aaa O0 00:00 0000";
156 char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000";
157 char tmztype_without_secs[] = "Aaa Aaa O0 00:00 AAA 0000";
158
isdate(char * date)159 int isdate(char *date)
160 {
161 return cmatch(date, ctype_without_secs) ||
162 cmatch(date, tmztype_without_secs) ||
163 cmatch(date, ctype) || cmatch(date, tmztype);
164 }
165
166 /*
167 * Match the given string (cp) against the given template (tp).
168 * Return 1 if they match, 0 if they don't
169 */
cmatch(register char * cp,register char * tp)170 int cmatch(register char *cp, register char *tp)
171 {
172
173 while (*cp && *tp)
174 switch (*tp++) {
175 case 'a':
176 if (!islower(*cp++))
177 return 0;
178 break;
179 case 'A':
180 if (!isupper(*cp++))
181 return 0;
182 break;
183 case ' ':
184 if (*cp++ != ' ')
185 return 0;
186 break;
187 case '0':
188 if (!isdigit(*cp++))
189 return 0;
190 break;
191 case 'O':
192 if (*cp != ' ' && !isdigit(*cp))
193 return 0;
194 cp++;
195 break;
196 case ':':
197 if (*cp++ != ':')
198 return 0;
199 break;
200 case 'N':
201 if (*cp++ != '\n')
202 return 0;
203 break;
204 }
205 if (*cp || *tp)
206 return 0;
207 return (1);
208 }
209
210 /*
211 * Collect a liberal (space, tab delimited) word into the word buffer
212 * passed. Also, return a pointer to the next word following that,
213 * or NOSTR if none follow.
214 */
nextword(register char * wp,register char * wbuf)215 char *nextword(register char *wp, register char *wbuf)
216 {
217 register char c;
218
219 if (wp == NOSTR) {
220 *wbuf = 0;
221 return (NOSTR);
222 }
223 while ((c = *wp++) && c != ' ' && c != '\t') {
224 *wbuf++ = c;
225 if (c == '"') {
226 while ((c = *wp++) && c != '"')
227 *wbuf++ = c;
228 if (c == '"')
229 *wbuf++ = c;
230 else
231 wp--;
232 }
233 }
234 *wbuf = '\0';
235 for (; c == ' ' || c == '\t'; c = *wp++)
236 ;
237 if (c == 0)
238 return (NOSTR);
239 return (wp - 1);
240 }
241