11590Srgrimes/*
21590Srgrimes * Copyright (c) 1980, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
301590Srgrimes#ifndef lint
3174769Smikeh#if 0
3288150Smikehstatic char sccsid[] = "@(#)head.c	8.2 (Berkeley) 4/20/95";
3374769Smikeh#endif
341590Srgrimes#endif /* not lint */
3599112Sobrien#include <sys/cdefs.h>
3699112Sobrien__FBSDID("$FreeBSD$");
371590Srgrimes
381590Srgrimes#include "rcv.h"
391590Srgrimes#include "extern.h"
401590Srgrimes
411590Srgrimes/*
421590Srgrimes * Mail -- a mail program
431590Srgrimes *
441590Srgrimes * Routines for processing and detecting headlines.
451590Srgrimes */
461590Srgrimes
471590Srgrimes/*
481590Srgrimes * See if the passed line buffer is a mail header.
491590Srgrimes * Return true if yes.  Note the extreme pains to
50228992Suqs * accommodate all funny formats.
511590Srgrimes */
521590Srgrimesint
53216564Scharnierishead(char linebuf[])
541590Srgrimes{
551590Srgrimes	struct headline hl;
561590Srgrimes	char parbuf[BUFSIZ];
571590Srgrimes
58108988Smikeh	if (strncmp(linebuf, "From ", 5) != 0)
591590Srgrimes		return (0);
601590Srgrimes	parse(linebuf, &hl, parbuf);
61108988Smikeh	if (hl.l_date == NULL) {
62108988Smikeh		fail(linebuf, "No date field");
631590Srgrimes		return (0);
641590Srgrimes	}
651590Srgrimes	if (!isdate(hl.l_date)) {
661590Srgrimes		fail(linebuf, "Date field not legal date");
671590Srgrimes		return (0);
681590Srgrimes	}
691590Srgrimes	/*
701590Srgrimes	 * I guess we got it!
711590Srgrimes	 */
721590Srgrimes	return (1);
731590Srgrimes}
741590Srgrimes
751590Srgrimesvoid
76216564Scharnierfail(const char *linebuf __unused, const char *reason __unused)
771590Srgrimes{
781590Srgrimes
791590Srgrimes	/*
8077274Smikeh	if (value("debug") == NULL)
811590Srgrimes		return;
821590Srgrimes	fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
831590Srgrimes	*/
841590Srgrimes}
851590Srgrimes
861590Srgrimes/*
871590Srgrimes * Split a headline into its useful components.
881590Srgrimes * Copy the line into dynamic string space, then set
891590Srgrimes * pointers into the copied line in the passed headline
901590Srgrimes * structure.  Actually, it scans.
911590Srgrimes */
921590Srgrimesvoid
93216564Scharnierparse(char line[], struct headline *hl, char pbuf[])
941590Srgrimes{
9577274Smikeh	char *cp, *sp;
961590Srgrimes	char word[LINESIZE];
971590Srgrimes
9877274Smikeh	hl->l_from = NULL;
9977274Smikeh	hl->l_tty = NULL;
10077274Smikeh	hl->l_date = NULL;
1011590Srgrimes	cp = line;
1021590Srgrimes	sp = pbuf;
1031590Srgrimes	/*
1041590Srgrimes	 * Skip over "From" first.
1051590Srgrimes	 */
1061590Srgrimes	cp = nextword(cp, word);
107108988Smikeh	/*
108108988Smikeh	 * Check for missing return-path.
109108988Smikeh	 */
110108988Smikeh	if (isdate(cp)) {
111108988Smikeh		hl->l_date = copyin(cp, &sp);
112108988Smikeh		return;
113108988Smikeh	}
1141590Srgrimes	cp = nextword(cp, word);
115108988Smikeh	if (strlen(word) > 0)
1161590Srgrimes		hl->l_from = copyin(word, &sp);
117108988Smikeh	if (cp != NULL && strncmp(cp, "tty", 3) == 0) {
1181590Srgrimes		cp = nextword(cp, word);
1191590Srgrimes		hl->l_tty = copyin(word, &sp);
1201590Srgrimes	}
12177274Smikeh	if (cp != NULL)
1221590Srgrimes		hl->l_date = copyin(cp, &sp);
1231590Srgrimes}
1241590Srgrimes
1251590Srgrimes/*
1261590Srgrimes * Copy the string on the left into the string on the right
1271590Srgrimes * and bump the right (reference) string pointer by the length.
1281590Srgrimes * Thus, dynamically allocate space in the right string, copying
1291590Srgrimes * the left string into it.
1301590Srgrimes */
1311590Srgrimeschar *
132216564Scharniercopyin(char *src, char **space)
1331590Srgrimes{
13477274Smikeh	char *cp, *top;
1351590Srgrimes
1361590Srgrimes	top = cp = *space;
13777274Smikeh	while ((*cp++ = *src++) != '\0')
1381590Srgrimes		;
1391590Srgrimes	*space = cp;
1401590Srgrimes	return (top);
1411590Srgrimes}
1421590Srgrimes
1431590Srgrimes/*
1441590Srgrimes * Test to see if the passed string is a ctime(3) generated
1451590Srgrimes * date string as documented in the manual.  The template
1461590Srgrimes * below is used as the criterion of correctness.
1471590Srgrimes * Also, we check for a possible trailing time zone using
1481590Srgrimes * the tmztype template.
14978398Smikeh *
15078398Smikeh * If the mail file is created by Sys V (Solaris), there are
15178398Smikeh * no seconds in the time. If the mail is created by another
15278398Smikeh * program such as imapd, it might have timezone as
15378398Smikeh * <-|+>nnnn (-0800 for instance) at the end.
1541590Srgrimes */
1551590Srgrimes
1561590Srgrimes/*
1571590Srgrimes * 'A'	An upper case char
1581590Srgrimes * 'a'	A lower case char
1591590Srgrimes * ' '	A space
1601590Srgrimes * '0'	A digit
16178398Smikeh * 'O'	A digit or space
16278398Smikeh * 'p'	A punctuation char
16378398Smikeh * 'P'	A punctuation char or space
1641590Srgrimes * ':'	A colon
1651590Srgrimes * 'N'	A new line
1661590Srgrimes */
1671590Srgrimes
16878398Smikehstatic char *date_formats[] = {
16978398Smikeh	"Aaa Aaa O0 00:00:00 0000",	   /* Mon Jan 01 23:59:59 2001 */
17078398Smikeh	"Aaa Aaa O0 00:00:00 AAA 0000",	   /* Mon Jan 01 23:59:59 PST 2001 */
17178398Smikeh	"Aaa Aaa O0 00:00:00 0000 p0000",  /* Mon Jan 01 23:59:59 2001 -0800 */
17278398Smikeh	"Aaa Aaa O0 00:00 0000",	   /* Mon Jan 01 23:59 2001 */
17378398Smikeh	"Aaa Aaa O0 00:00 AAA 0000",	   /* Mon Jan 01 23:59 PST 2001 */
17478398Smikeh	"Aaa Aaa O0 00:00 0000 p0000",	   /* Mon Jan 01 23:59 2001 -0800 */
17578398Smikeh	NULL
17678398Smikeh};
17778398Smikeh
1781590Srgrimesint
179216564Scharnierisdate(char date[])
1801590Srgrimes{
18178398Smikeh	int i;
1821590Srgrimes
18378398Smikeh	for(i = 0; date_formats[i] != NULL; i++) {
18478398Smikeh		if (cmatch(date, date_formats[i]))
18578398Smikeh			return (1);
18678398Smikeh	}
18778398Smikeh	return (0);
1881590Srgrimes}
1891590Srgrimes
1901590Srgrimes/*
1911590Srgrimes * Match the given string (cp) against the given template (tp).
1921590Srgrimes * Return 1 if they match, 0 if they don't
1931590Srgrimes */
1941590Srgrimesint
195216564Scharniercmatch(char *cp, char *tp)
1961590Srgrimes{
1971590Srgrimes
19877274Smikeh	while (*cp != '\0' && *tp != '\0')
1991590Srgrimes		switch (*tp++) {
2001590Srgrimes		case 'a':
20188227Sache			if (!islower((unsigned char)*cp++))
20277274Smikeh				return (0);
2031590Srgrimes			break;
2041590Srgrimes		case 'A':
20588227Sache			if (!isupper((unsigned char)*cp++))
20677274Smikeh				return (0);
2071590Srgrimes			break;
2081590Srgrimes		case ' ':
2091590Srgrimes			if (*cp++ != ' ')
21077274Smikeh				return (0);
2111590Srgrimes			break;
2121590Srgrimes		case '0':
21388227Sache			if (!isdigit((unsigned char)*cp++))
21477274Smikeh				return (0);
2151590Srgrimes			break;
2161590Srgrimes		case 'O':
21788227Sache			if (*cp != ' ' && !isdigit((unsigned char)*cp))
21877274Smikeh				return (0);
2191590Srgrimes			cp++;
2201590Srgrimes			break;
22178398Smikeh		case 'p':
22288227Sache			if (!ispunct((unsigned char)*cp++))
22378398Smikeh				return (0);
22478398Smikeh			break;
22578398Smikeh		case 'P':
22688227Sache			if (*cp != ' ' && !ispunct((unsigned char)*cp))
22778398Smikeh				return (0);
22878398Smikeh			cp++;
22978398Smikeh			break;
2301590Srgrimes		case ':':
2311590Srgrimes			if (*cp++ != ':')
23277274Smikeh				return (0);
2331590Srgrimes			break;
2341590Srgrimes		case 'N':
2351590Srgrimes			if (*cp++ != '\n')
23677274Smikeh				return (0);
2371590Srgrimes			break;
2381590Srgrimes		}
23977274Smikeh	if (*cp != '\0' || *tp != '\0')
24077274Smikeh		return (0);
2411590Srgrimes	return (1);
2421590Srgrimes}
2431590Srgrimes
2441590Srgrimes/*
2451590Srgrimes * Collect a liberal (space, tab delimited) word into the word buffer
2461590Srgrimes * passed.  Also, return a pointer to the next word following that,
24777274Smikeh * or NULL if none follow.
2481590Srgrimes */
2491590Srgrimeschar *
250216564Scharniernextword(char *wp, char *wbuf)
2511590Srgrimes{
25277274Smikeh	int c;
2531590Srgrimes
25477274Smikeh	if (wp == NULL) {
25577274Smikeh		*wbuf = '\0';
25677274Smikeh		return (NULL);
2571590Srgrimes	}
25877274Smikeh	while ((c = *wp++) != '\0' && c != ' ' && c != '\t') {
2591590Srgrimes		*wbuf++ = c;
2601590Srgrimes		if (c == '"') {
26177274Smikeh 			while ((c = *wp++) != '\0' && c != '"')
2621590Srgrimes 				*wbuf++ = c;
2631590Srgrimes 			if (c == '"')
2641590Srgrimes 				*wbuf++ = c;
2651590Srgrimes			else
2661590Srgrimes				wp--;
2671590Srgrimes 		}
2681590Srgrimes	}
2691590Srgrimes	*wbuf = '\0';
2701590Srgrimes	for (; c == ' ' || c == '\t'; c = *wp++)
2711590Srgrimes		;
27277274Smikeh	if (c == '\0')
27377274Smikeh		return (NULL);
2741590Srgrimes	return (wp - 1);
2751590Srgrimes}
276