122455Sdist /*
262083Sbostic * Copyright (c) 1980, 1993
362083Sbostic * The Regents of the University of California. All rights reserved.
433499Sbostic *
542741Sbostic * %sccs.include.redist.c%
622455Sdist */
722455Sdist
834905Sbostic #ifndef lint
9*68818Sdab static char sccsid[] = "@(#)head.c 8.2 (Berkeley) 04/20/95";
1034905Sbostic #endif /* not lint */
111234Skas
121234Skas #include "rcv.h"
1354505Sbostic #include "extern.h"
141234Skas
151234Skas /*
161234Skas * Mail -- a mail program
171234Skas *
181234Skas * Routines for processing and detecting headlines.
191234Skas */
201234Skas
211234Skas /*
221234Skas * See if the passed line buffer is a mail header.
231234Skas * Return true if yes. Note the extreme pains to
241234Skas * accomodate all funny formats.
251234Skas */
2654505Sbostic int
ishead(linebuf)271234Skas ishead(linebuf)
281234Skas char linebuf[];
291234Skas {
301234Skas register char *cp;
311234Skas struct headline hl;
321234Skas char parbuf[BUFSIZ];
331234Skas
341234Skas cp = linebuf;
3531142Sedward if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' ||
3631142Sedward *cp++ != ' ')
3731142Sedward return (0);
3831142Sedward parse(linebuf, &hl, parbuf);
391234Skas if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
401234Skas fail(linebuf, "No from or date field");
4131142Sedward return (0);
421234Skas }
431234Skas if (!isdate(hl.l_date)) {
441234Skas fail(linebuf, "Date field not legal date");
4531142Sedward return (0);
461234Skas }
471234Skas /*
481234Skas * I guess we got it!
491234Skas */
5031142Sedward return (1);
511234Skas }
521234Skas
5331142Sedward /*ARGSUSED*/
5454505Sbostic void
fail(linebuf,reason)551234Skas fail(linebuf, reason)
561234Skas char linebuf[], reason[];
571234Skas {
581234Skas
5931142Sedward /*
6031142Sedward if (value("debug") == NOSTR)
611234Skas return;
621234Skas fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
6331142Sedward */
641234Skas }
651234Skas
661234Skas /*
671234Skas * Split a headline into its useful components.
681234Skas * Copy the line into dynamic string space, then set
691234Skas * pointers into the copied line in the passed headline
701234Skas * structure. Actually, it scans.
711234Skas */
7254505Sbostic void
parse(line,hl,pbuf)731234Skas parse(line, hl, pbuf)
741234Skas char line[], pbuf[];
7531142Sedward register struct headline *hl;
761234Skas {
7731142Sedward register char *cp;
781234Skas char *sp;
791234Skas char word[LINESIZE];
801234Skas
811234Skas hl->l_from = NOSTR;
821234Skas hl->l_tty = NOSTR;
831234Skas hl->l_date = NOSTR;
841234Skas cp = line;
851234Skas sp = pbuf;
861234Skas /*
8731142Sedward * Skip over "From" first.
881234Skas */
891234Skas cp = nextword(cp, word);
9031142Sedward cp = nextword(cp, word);
9131142Sedward if (*word)
921234Skas hl->l_from = copyin(word, &sp);
9331142Sedward if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
9431142Sedward cp = nextword(cp, word);
951234Skas hl->l_tty = copyin(word, &sp);
961234Skas }
9731142Sedward if (cp != NOSTR)
9831142Sedward hl->l_date = copyin(cp, &sp);
991234Skas }
1001234Skas
1011234Skas /*
1021234Skas * Copy the string on the left into the string on the right
1031234Skas * and bump the right (reference) string pointer by the length.
1041234Skas * Thus, dynamically allocate space in the right string, copying
1051234Skas * the left string into it.
1061234Skas */
1071234Skas char *
copyin(src,space)1081234Skas copyin(src, space)
10931142Sedward register char *src;
1101234Skas char **space;
1111234Skas {
11231142Sedward register char *cp;
11331142Sedward char *top;
1141234Skas
11531142Sedward top = cp = *space;
11631142Sedward while (*cp++ = *src++)
11731142Sedward ;
1181234Skas *space = cp;
11931142Sedward return (top);
1201234Skas }
1211234Skas
1221234Skas /*
1231234Skas * Test to see if the passed string is a ctime(3) generated
1241234Skas * date string as documented in the manual. The template
1251234Skas * below is used as the criterion of correctness.
1261234Skas * Also, we check for a possible trailing time zone using
12734987Sedward * the tmztype template.
1281234Skas */
1291234Skas
13034987Sedward /*
13134987Sedward * 'A' An upper case char
13234987Sedward * 'a' A lower case char
13334987Sedward * ' ' A space
13434987Sedward * '0' A digit
13534987Sedward * 'O' An optional digit or space
13634987Sedward * ':' A colon
13734987Sedward * 'N' A new line
13834987Sedward */
13934987Sedward char ctype[] = "Aaa Aaa O0 00:00:00 0000";
14034987Sedward char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000";
141*68818Sdab /*
142*68818Sdab * Yuck. If the mail file is created by Sys V (Solaris),
143*68818Sdab * there are no seconds in the time...
144*68818Sdab */
145*68818Sdab char SysV_ctype[] = "Aaa Aaa O0 00:00 0000";
146*68818Sdab char SysV_tmztype[] = "Aaa Aaa O0 00:00 AAA 0000";
1471234Skas
14854505Sbostic int
isdate(date)1491234Skas isdate(date)
1501234Skas char date[];
1511234Skas {
1521234Skas
153*68818Sdab return cmatch(date, ctype) || cmatch(date, tmztype)
154*68818Sdab || cmatch(date, SysV_tmztype) || cmatch(date, SysV_ctype);
1551234Skas }
1561234Skas
1571234Skas /*
15831142Sedward * Match the given string (cp) against the given template (tp).
1591234Skas * Return 1 if they match, 0 if they don't
1601234Skas */
16154505Sbostic int
cmatch(cp,tp)16231142Sedward cmatch(cp, tp)
16331142Sedward register char *cp, *tp;
1641234Skas {
1651234Skas
16631142Sedward while (*cp && *tp)
1671234Skas switch (*tp++) {
16834987Sedward case 'a':
16931142Sedward if (!islower(*cp++))
17031142Sedward return 0;
1711234Skas break;
17234987Sedward case 'A':
17331142Sedward if (!isupper(*cp++))
17431142Sedward return 0;
1751234Skas break;
17634987Sedward case ' ':
17731142Sedward if (*cp++ != ' ')
17831142Sedward return 0;
1791234Skas break;
18034987Sedward case '0':
18131142Sedward if (!isdigit(*cp++))
18231142Sedward return 0;
1831234Skas break;
18434987Sedward case 'O':
18531142Sedward if (*cp != ' ' && !isdigit(*cp))
18631142Sedward return 0;
18731142Sedward cp++;
1881234Skas break;
18934987Sedward case ':':
19031142Sedward if (*cp++ != ':')
19131142Sedward return 0;
1921234Skas break;
19334987Sedward case 'N':
19431142Sedward if (*cp++ != '\n')
19531142Sedward return 0;
1961234Skas break;
1971234Skas }
19831142Sedward if (*cp || *tp)
19931142Sedward return 0;
20031142Sedward return (1);
2011234Skas }
2021234Skas
2031234Skas /*
2041234Skas * Collect a liberal (space, tab delimited) word into the word buffer
2051234Skas * passed. Also, return a pointer to the next word following that,
2061234Skas * or NOSTR if none follow.
2071234Skas */
2081234Skas char *
nextword(wp,wbuf)2091234Skas nextword(wp, wbuf)
21031142Sedward register char *wp, *wbuf;
2111234Skas {
21231142Sedward register c;
2131234Skas
21431142Sedward if (wp == NOSTR) {
21531142Sedward *wbuf = 0;
21631142Sedward return (NOSTR);
2171234Skas }
21831142Sedward while ((c = *wp++) && c != ' ' && c != '\t') {
21931142Sedward *wbuf++ = c;
22031142Sedward if (c == '"') {
22131142Sedward while ((c = *wp++) && c != '"')
22231142Sedward *wbuf++ = c;
22331142Sedward if (c == '"')
22431142Sedward *wbuf++ = c;
22531142Sedward else
22631142Sedward wp--;
22731142Sedward }
22831142Sedward }
22931142Sedward *wbuf = '\0';
23031142Sedward for (; c == ' ' || c == '\t'; c = *wp++)
23131142Sedward ;
23231142Sedward if (c == 0)
23331142Sedward return (NOSTR);
23431142Sedward return (wp - 1);
2351234Skas }
236