head.c revision 216564
160812Sps/* 260786Sps * Copyright (c) 1980, 1993 3161478Sdelphij * The Regents of the University of California. All rights reserved. 460786Sps * 560786Sps * Redistribution and use in source and binary forms, with or without 660786Sps * modification, are permitted provided that the following conditions 760786Sps * are met: 860786Sps * 1. Redistributions of source code must retain the above copyright 960786Sps * notice, this list of conditions and the following disclaimer. 1060786Sps * 2. Redistributions in binary form must reproduce the above copyright 1160786Sps * notice, this list of conditions and the following disclaimer in the 1260786Sps * documentation and/or other materials provided with the distribution. 1360786Sps * 4. Neither the name of the University nor the names of its contributors 1460786Sps * may be used to endorse or promote products derived from this software 1560786Sps * without specific prior written permission. 1660786Sps * 1760786Sps * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1889022Sps * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1989022Sps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2089022Sps * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2160786Sps * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2260786Sps * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2360786Sps * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2460786Sps * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25161478Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2660786Sps * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2760786Sps * SUCH DAMAGE. 2860786Sps */ 2960786Sps 3060786Sps#ifndef lint 3160786Sps#if 0 3260786Spsstatic char sccsid[] = "@(#)head.c 8.2 (Berkeley) 4/20/95"; 3360786Sps#endif 3460786Sps#endif /* not lint */ 3560786Sps#include <sys/cdefs.h> 3660786Sps__FBSDID("$FreeBSD: head/usr.bin/mail/head.c 216564 2010-12-19 16:25:23Z charnier $"); 3760786Sps 3860786Sps#include "rcv.h" 3960786Sps#include "extern.h" 4060786Sps 4160786Sps/* 4260812Sps * Mail -- a mail program 4360786Sps * 4460786Sps * Routines for processing and detecting headlines. 4560786Sps */ 4660786Sps 4760786Sps/* 4860786Sps * See if the passed line buffer is a mail header. 4960786Sps * Return true if yes. Note the extreme pains to 5060786Sps * accomodate all funny formats. 5160786Sps */ 5260786Spsint 5360786Spsishead(char linebuf[]) 5460786Sps{ 5560786Sps struct headline hl; 5660786Sps char parbuf[BUFSIZ]; 5760786Sps 5863131Sps if (strncmp(linebuf, "From ", 5) != 0) 5960786Sps return (0); 6060786Sps parse(linebuf, &hl, parbuf); 6160786Sps if (hl.l_date == NULL) { 6260786Sps fail(linebuf, "No date field"); 6360786Sps return (0); 6460786Sps } 6560786Sps if (!isdate(hl.l_date)) { 6660786Sps fail(linebuf, "Date field not legal date"); 67128348Stjr return (0); 6860786Sps } 6960786Sps /* 7060786Sps * I guess we got it! 7160786Sps */ 72161478Sdelphij return (1); 7360786Sps} 7460786Sps 7560786Spsvoid 7660786Spsfail(const char *linebuf __unused, const char *reason __unused) 7760786Sps{ 7860786Sps 7960786Sps /* 8060786Sps if (value("debug") == NULL) 8160786Sps return; 8260786Sps fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason); 8360786Sps */ 8460786Sps} 8560786Sps 8660786Sps/* 8760786Sps * Split a headline into its useful components. 8860786Sps * Copy the line into dynamic string space, then set 8960786Sps * pointers into the copied line in the passed headline 9060786Sps * structure. Actually, it scans. 9160786Sps */ 9260786Spsvoid 9360786Spsparse(char line[], struct headline *hl, char pbuf[]) 9460786Sps{ 9560786Sps char *cp, *sp; 9660786Sps char word[LINESIZE]; 9760786Sps 9860786Sps hl->l_from = NULL; 9960786Sps hl->l_tty = NULL; 10060786Sps hl->l_date = NULL; 10160786Sps cp = line; 10260786Sps sp = pbuf; 10360786Sps /* 10460786Sps * Skip over "From" first. 10560786Sps */ 10660786Sps cp = nextword(cp, word); 10760786Sps /* 10860786Sps * Check for missing return-path. 10960786Sps */ 11060786Sps if (isdate(cp)) { 11160786Sps hl->l_date = copyin(cp, &sp); 11260786Sps return; 11360786Sps } 11460786Sps cp = nextword(cp, word); 11560786Sps if (strlen(word) > 0) 11660786Sps hl->l_from = copyin(word, &sp); 11760786Sps if (cp != NULL && strncmp(cp, "tty", 3) == 0) { 11860786Sps cp = nextword(cp, word); 11960786Sps hl->l_tty = copyin(word, &sp); 12060786Sps } 12160786Sps if (cp != NULL) 12260786Sps hl->l_date = copyin(cp, &sp); 12360786Sps} 12460786Sps 12560786Sps/* 12660786Sps * Copy the string on the left into the string on the right 12760786Sps * and bump the right (reference) string pointer by the length. 12860786Sps * Thus, dynamically allocate space in the right string, copying 12960786Sps * the left string into it. 13060786Sps */ 13160786Spschar * 13260786Spscopyin(char *src, char **space) 13360786Sps{ 13460786Sps char *cp, *top; 13560786Sps 13660786Sps top = cp = *space; 13760786Sps while ((*cp++ = *src++) != '\0') 13860786Sps ; 13960786Sps *space = cp; 14060786Sps return (top); 14160786Sps} 14260786Sps 14360786Sps/* 14460786Sps * Test to see if the passed string is a ctime(3) generated 14560786Sps * date string as documented in the manual. The template 14660786Sps * below is used as the criterion of correctness. 14760786Sps * Also, we check for a possible trailing time zone using 14860786Sps * the tmztype template. 14960786Sps * 15060786Sps * If the mail file is created by Sys V (Solaris), there are 15160786Sps * no seconds in the time. If the mail is created by another 15260786Sps * program such as imapd, it might have timezone as 15360786Sps * <-|+>nnnn (-0800 for instance) at the end. 15460786Sps */ 15560786Sps 15660786Sps/* 15760786Sps * 'A' An upper case char 15860786Sps * 'a' A lower case char 15960786Sps * ' ' A space 16060786Sps * '0' A digit 16160786Sps * 'O' A digit or space 16260786Sps * 'p' A punctuation char 16360786Sps * 'P' A punctuation char or space 16460786Sps * ':' A colon 16560786Sps * 'N' A new line 16660786Sps */ 16760786Sps 16860786Spsstatic char *date_formats[] = { 16960786Sps "Aaa Aaa O0 00:00:00 0000", /* Mon Jan 01 23:59:59 2001 */ 17060786Sps "Aaa Aaa O0 00:00:00 AAA 0000", /* Mon Jan 01 23:59:59 PST 2001 */ 17160786Sps "Aaa Aaa O0 00:00:00 0000 p0000", /* Mon Jan 01 23:59:59 2001 -0800 */ 17260786Sps "Aaa Aaa O0 00:00 0000", /* Mon Jan 01 23:59 2001 */ 17360786Sps "Aaa Aaa O0 00:00 AAA 0000", /* Mon Jan 01 23:59 PST 2001 */ 17460786Sps "Aaa Aaa O0 00:00 0000 p0000", /* Mon Jan 01 23:59 2001 -0800 */ 17560786Sps NULL 17660786Sps}; 17760786Sps 17860786Spsint 17960786Spsisdate(char date[]) 18060786Sps{ 18160786Sps int i; 18260786Sps 18360786Sps for(i = 0; date_formats[i] != NULL; i++) { 18460786Sps if (cmatch(date, date_formats[i])) 18560786Sps return (1); 18660786Sps } 18760786Sps return (0); 18860786Sps} 18960786Sps 19060786Sps/* 19160786Sps * Match the given string (cp) against the given template (tp). 19260786Sps * Return 1 if they match, 0 if they don't 193128348Stjr */ 19460786Spsint 19560786Spscmatch(char *cp, char *tp) 19660786Sps{ 19760786Sps 19860786Sps while (*cp != '\0' && *tp != '\0') 19960786Sps switch (*tp++) { 20060786Sps case 'a': 20160786Sps if (!islower((unsigned char)*cp++)) 20260786Sps return (0); 20360786Sps break; 20460786Sps case 'A': 20560786Sps if (!isupper((unsigned char)*cp++)) 20660786Sps return (0); 20760786Sps break; 20860786Sps case ' ': 20960786Sps if (*cp++ != ' ') 21060786Sps return (0); 21160786Sps break; 21260786Sps case '0': 213128348Stjr if (!isdigit((unsigned char)*cp++)) 21460786Sps return (0); 21560786Sps break; 216128348Stjr case 'O': 21760786Sps if (*cp != ' ' && !isdigit((unsigned char)*cp)) 21860786Sps return (0); 21960786Sps cp++; 22060786Sps break; 22160786Sps case 'p': 22260786Sps if (!ispunct((unsigned char)*cp++)) 223128348Stjr return (0); 22489022Sps break; 22589022Sps case 'P': 226128348Stjr if (*cp != ' ' && !ispunct((unsigned char)*cp)) 22760786Sps return (0); 22860786Sps cp++; 22960786Sps break; 23060786Sps case ':': 23160786Sps if (*cp++ != ':') 23260786Sps return (0); 23360786Sps break; 23460786Sps case 'N': 23560786Sps if (*cp++ != '\n') 23660786Sps return (0); 23760786Sps break; 23860786Sps } 23960786Sps if (*cp != '\0' || *tp != '\0') 24060786Sps return (0); 24160786Sps return (1); 24260786Sps} 24360786Sps 24460786Sps/* 24560786Sps * Collect a liberal (space, tab delimited) word into the word buffer 24660786Sps * passed. Also, return a pointer to the next word following that, 24760786Sps * or NULL if none follow. 24860786Sps */ 24960786Spschar * 25060786Spsnextword(char *wp, char *wbuf) 25160786Sps{ 25260786Sps int c; 25360786Sps 25460786Sps if (wp == NULL) { 25560786Sps *wbuf = '\0'; 25660786Sps return (NULL); 25760786Sps } 25860786Sps while ((c = *wp++) != '\0' && c != ' ' && c != '\t') { 25960786Sps *wbuf++ = c; 26060786Sps if (c == '"') { 26160786Sps while ((c = *wp++) != '\0' && c != '"') 26260786Sps *wbuf++ = c; 26360786Sps if (c == '"') 26460786Sps *wbuf++ = c; 26560786Sps else 26660786Sps wp--; 26760786Sps } 26860786Sps } 26960786Sps *wbuf = '\0'; 27060786Sps for (; c == ' ' || c == '\t'; c = *wp++) 27160786Sps ; 27260786Sps if (c == '\0') 27360786Sps return (NULL); 27460786Sps return (wp - 1); 27560786Sps} 27660786Sps