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