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