19b50d902SRodney W. Grimes /* 29b50d902SRodney W. Grimes * Copyright (c) 1980, 1993 39b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 49b50d902SRodney W. Grimes * 59b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 69b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 79b50d902SRodney W. Grimes * are met: 89b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 99b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 109b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 129b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 139b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 149b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 159b50d902SRodney W. Grimes * without specific prior written permission. 169b50d902SRodney W. Grimes * 179b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 189b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 199b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 209b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 219b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 229b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 239b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 249b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 259b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 269b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 279b50d902SRodney W. Grimes * SUCH DAMAGE. 289b50d902SRodney W. Grimes */ 299b50d902SRodney W. Grimes 309b50d902SRodney W. Grimes #ifndef lint 310c3a8314SMike Heffner #if 0 32856f23edSMike Heffner static char sccsid[] = "@(#)head.c 8.2 (Berkeley) 4/20/95"; 330c3a8314SMike Heffner #endif 349b50d902SRodney W. Grimes #endif /* not lint */ 35e026a48cSDavid E. O'Brien #include <sys/cdefs.h> 36e026a48cSDavid E. O'Brien __FBSDID("$FreeBSD$"); 379b50d902SRodney W. Grimes 389b50d902SRodney W. Grimes #include "rcv.h" 399b50d902SRodney W. Grimes #include "extern.h" 409b50d902SRodney W. Grimes 419b50d902SRodney W. Grimes /* 429b50d902SRodney W. Grimes * Mail -- a mail program 439b50d902SRodney W. Grimes * 449b50d902SRodney W. Grimes * Routines for processing and detecting headlines. 459b50d902SRodney W. Grimes */ 469b50d902SRodney W. Grimes 479b50d902SRodney W. Grimes /* 489b50d902SRodney W. Grimes * See if the passed line buffer is a mail header. 499b50d902SRodney W. Grimes * Return true if yes. Note the extreme pains to 509b50d902SRodney W. Grimes * accomodate all funny formats. 519b50d902SRodney W. Grimes */ 529b50d902SRodney W. Grimes int 53*6d8484b0SPhilippe Charnier ishead(char linebuf[]) 549b50d902SRodney W. Grimes { 559b50d902SRodney W. Grimes struct headline hl; 569b50d902SRodney W. Grimes char parbuf[BUFSIZ]; 579b50d902SRodney W. Grimes 582e99d1d5SMike Heffner if (strncmp(linebuf, "From ", 5) != 0) 599b50d902SRodney W. Grimes return (0); 609b50d902SRodney W. Grimes parse(linebuf, &hl, parbuf); 612e99d1d5SMike Heffner if (hl.l_date == NULL) { 622e99d1d5SMike Heffner fail(linebuf, "No date field"); 639b50d902SRodney W. Grimes return (0); 649b50d902SRodney W. Grimes } 659b50d902SRodney W. Grimes if (!isdate(hl.l_date)) { 669b50d902SRodney W. Grimes fail(linebuf, "Date field not legal date"); 679b50d902SRodney W. Grimes return (0); 689b50d902SRodney W. Grimes } 699b50d902SRodney W. Grimes /* 709b50d902SRodney W. Grimes * I guess we got it! 719b50d902SRodney W. Grimes */ 729b50d902SRodney W. Grimes return (1); 739b50d902SRodney W. Grimes } 749b50d902SRodney W. Grimes 759b50d902SRodney W. Grimes void 76*6d8484b0SPhilippe Charnier fail(const char *linebuf __unused, const char *reason __unused) 779b50d902SRodney W. Grimes { 789b50d902SRodney W. Grimes 799b50d902SRodney W. Grimes /* 809ce73e90SMike Heffner if (value("debug") == NULL) 819b50d902SRodney W. Grimes return; 829b50d902SRodney W. Grimes fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason); 839b50d902SRodney W. Grimes */ 849b50d902SRodney W. Grimes } 859b50d902SRodney W. Grimes 869b50d902SRodney W. Grimes /* 879b50d902SRodney W. Grimes * Split a headline into its useful components. 889b50d902SRodney W. Grimes * Copy the line into dynamic string space, then set 899b50d902SRodney W. Grimes * pointers into the copied line in the passed headline 909b50d902SRodney W. Grimes * structure. Actually, it scans. 919b50d902SRodney W. Grimes */ 929b50d902SRodney W. Grimes void 93*6d8484b0SPhilippe Charnier parse(char line[], struct headline *hl, char pbuf[]) 949b50d902SRodney W. Grimes { 959ce73e90SMike Heffner char *cp, *sp; 969b50d902SRodney W. Grimes char word[LINESIZE]; 979b50d902SRodney W. Grimes 989ce73e90SMike Heffner hl->l_from = NULL; 999ce73e90SMike Heffner hl->l_tty = NULL; 1009ce73e90SMike Heffner hl->l_date = NULL; 1019b50d902SRodney W. Grimes cp = line; 1029b50d902SRodney W. Grimes sp = pbuf; 1039b50d902SRodney W. Grimes /* 1049b50d902SRodney W. Grimes * Skip over "From" first. 1059b50d902SRodney W. Grimes */ 1069b50d902SRodney W. Grimes cp = nextword(cp, word); 1072e99d1d5SMike Heffner /* 1082e99d1d5SMike Heffner * Check for missing return-path. 1092e99d1d5SMike Heffner */ 1102e99d1d5SMike Heffner if (isdate(cp)) { 1112e99d1d5SMike Heffner hl->l_date = copyin(cp, &sp); 1122e99d1d5SMike Heffner return; 1132e99d1d5SMike Heffner } 1149b50d902SRodney W. Grimes cp = nextword(cp, word); 1152e99d1d5SMike Heffner if (strlen(word) > 0) 1169b50d902SRodney W. Grimes hl->l_from = copyin(word, &sp); 1172e99d1d5SMike Heffner if (cp != NULL && strncmp(cp, "tty", 3) == 0) { 1189b50d902SRodney W. Grimes cp = nextword(cp, word); 1199b50d902SRodney W. Grimes hl->l_tty = copyin(word, &sp); 1209b50d902SRodney W. Grimes } 1219ce73e90SMike Heffner if (cp != NULL) 1229b50d902SRodney W. Grimes hl->l_date = copyin(cp, &sp); 1239b50d902SRodney W. Grimes } 1249b50d902SRodney W. Grimes 1259b50d902SRodney W. Grimes /* 1269b50d902SRodney W. Grimes * Copy the string on the left into the string on the right 1279b50d902SRodney W. Grimes * and bump the right (reference) string pointer by the length. 1289b50d902SRodney W. Grimes * Thus, dynamically allocate space in the right string, copying 1299b50d902SRodney W. Grimes * the left string into it. 1309b50d902SRodney W. Grimes */ 1319b50d902SRodney W. Grimes char * 132*6d8484b0SPhilippe Charnier copyin(char *src, char **space) 1339b50d902SRodney W. Grimes { 1349ce73e90SMike Heffner char *cp, *top; 1359b50d902SRodney W. Grimes 1369b50d902SRodney W. Grimes top = cp = *space; 1379ce73e90SMike Heffner while ((*cp++ = *src++) != '\0') 1389b50d902SRodney W. Grimes ; 1399b50d902SRodney W. Grimes *space = cp; 1409b50d902SRodney W. Grimes return (top); 1419b50d902SRodney W. Grimes } 1429b50d902SRodney W. Grimes 1439b50d902SRodney W. Grimes /* 1449b50d902SRodney W. Grimes * Test to see if the passed string is a ctime(3) generated 1459b50d902SRodney W. Grimes * date string as documented in the manual. The template 1469b50d902SRodney W. Grimes * below is used as the criterion of correctness. 1479b50d902SRodney W. Grimes * Also, we check for a possible trailing time zone using 1489b50d902SRodney W. Grimes * the tmztype template. 149a9992a76SMike Heffner * 150a9992a76SMike Heffner * If the mail file is created by Sys V (Solaris), there are 151a9992a76SMike Heffner * no seconds in the time. If the mail is created by another 152a9992a76SMike Heffner * program such as imapd, it might have timezone as 153a9992a76SMike Heffner * <-|+>nnnn (-0800 for instance) at the end. 1549b50d902SRodney W. Grimes */ 1559b50d902SRodney W. Grimes 1569b50d902SRodney W. Grimes /* 1579b50d902SRodney W. Grimes * 'A' An upper case char 1589b50d902SRodney W. Grimes * 'a' A lower case char 1599b50d902SRodney W. Grimes * ' ' A space 1609b50d902SRodney W. Grimes * '0' A digit 161a9992a76SMike Heffner * 'O' A digit or space 162a9992a76SMike Heffner * 'p' A punctuation char 163a9992a76SMike Heffner * 'P' A punctuation char or space 1649b50d902SRodney W. Grimes * ':' A colon 1659b50d902SRodney W. Grimes * 'N' A new line 1669b50d902SRodney W. Grimes */ 167a9992a76SMike Heffner 168a9992a76SMike Heffner static char *date_formats[] = { 169a9992a76SMike Heffner "Aaa Aaa O0 00:00:00 0000", /* Mon Jan 01 23:59:59 2001 */ 170a9992a76SMike Heffner "Aaa Aaa O0 00:00:00 AAA 0000", /* Mon Jan 01 23:59:59 PST 2001 */ 171a9992a76SMike Heffner "Aaa Aaa O0 00:00:00 0000 p0000", /* Mon Jan 01 23:59:59 2001 -0800 */ 172a9992a76SMike Heffner "Aaa Aaa O0 00:00 0000", /* Mon Jan 01 23:59 2001 */ 173a9992a76SMike Heffner "Aaa Aaa O0 00:00 AAA 0000", /* Mon Jan 01 23:59 PST 2001 */ 174a9992a76SMike Heffner "Aaa Aaa O0 00:00 0000 p0000", /* Mon Jan 01 23:59 2001 -0800 */ 175a9992a76SMike Heffner NULL 176a9992a76SMike Heffner }; 1779b50d902SRodney W. Grimes 1789b50d902SRodney W. Grimes int 179*6d8484b0SPhilippe Charnier isdate(char date[]) 1809b50d902SRodney W. Grimes { 181a9992a76SMike Heffner int i; 1829b50d902SRodney W. Grimes 183a9992a76SMike Heffner for(i = 0; date_formats[i] != NULL; i++) { 184a9992a76SMike Heffner if (cmatch(date, date_formats[i])) 185a9992a76SMike Heffner return (1); 186a9992a76SMike Heffner } 187a9992a76SMike Heffner return (0); 1889b50d902SRodney W. Grimes } 1899b50d902SRodney W. Grimes 1909b50d902SRodney W. Grimes /* 1919b50d902SRodney W. Grimes * Match the given string (cp) against the given template (tp). 1929b50d902SRodney W. Grimes * Return 1 if they match, 0 if they don't 1939b50d902SRodney W. Grimes */ 1949b50d902SRodney W. Grimes int 195*6d8484b0SPhilippe Charnier cmatch(char *cp, char *tp) 1969b50d902SRodney W. Grimes { 1979b50d902SRodney W. Grimes 1989ce73e90SMike Heffner while (*cp != '\0' && *tp != '\0') 1999b50d902SRodney W. Grimes switch (*tp++) { 2009b50d902SRodney W. Grimes case 'a': 2016d48fa43SAndrey A. Chernov if (!islower((unsigned char)*cp++)) 2029ce73e90SMike Heffner return (0); 2039b50d902SRodney W. Grimes break; 2049b50d902SRodney W. Grimes case 'A': 2056d48fa43SAndrey A. Chernov if (!isupper((unsigned char)*cp++)) 2069ce73e90SMike Heffner return (0); 2079b50d902SRodney W. Grimes break; 2089b50d902SRodney W. Grimes case ' ': 2099b50d902SRodney W. Grimes if (*cp++ != ' ') 2109ce73e90SMike Heffner return (0); 2119b50d902SRodney W. Grimes break; 2129b50d902SRodney W. Grimes case '0': 2136d48fa43SAndrey A. Chernov if (!isdigit((unsigned char)*cp++)) 2149ce73e90SMike Heffner return (0); 2159b50d902SRodney W. Grimes break; 2169b50d902SRodney W. Grimes case 'O': 2176d48fa43SAndrey A. Chernov if (*cp != ' ' && !isdigit((unsigned char)*cp)) 2189ce73e90SMike Heffner return (0); 2199b50d902SRodney W. Grimes cp++; 2209b50d902SRodney W. Grimes break; 221a9992a76SMike Heffner case 'p': 2226d48fa43SAndrey A. Chernov if (!ispunct((unsigned char)*cp++)) 223a9992a76SMike Heffner return (0); 224a9992a76SMike Heffner break; 225a9992a76SMike Heffner case 'P': 2266d48fa43SAndrey A. Chernov if (*cp != ' ' && !ispunct((unsigned char)*cp)) 227a9992a76SMike Heffner return (0); 228a9992a76SMike Heffner cp++; 229a9992a76SMike Heffner break; 2309b50d902SRodney W. Grimes case ':': 2319b50d902SRodney W. Grimes if (*cp++ != ':') 2329ce73e90SMike Heffner return (0); 2339b50d902SRodney W. Grimes break; 2349b50d902SRodney W. Grimes case 'N': 2359b50d902SRodney W. Grimes if (*cp++ != '\n') 2369ce73e90SMike Heffner return (0); 2379b50d902SRodney W. Grimes break; 2389b50d902SRodney W. Grimes } 2399ce73e90SMike Heffner if (*cp != '\0' || *tp != '\0') 2409ce73e90SMike Heffner return (0); 2419b50d902SRodney W. Grimes return (1); 2429b50d902SRodney W. Grimes } 2439b50d902SRodney W. Grimes 2449b50d902SRodney W. Grimes /* 2459b50d902SRodney W. Grimes * Collect a liberal (space, tab delimited) word into the word buffer 2469b50d902SRodney W. Grimes * passed. Also, return a pointer to the next word following that, 2479ce73e90SMike Heffner * or NULL if none follow. 2489b50d902SRodney W. Grimes */ 2499b50d902SRodney W. Grimes char * 250*6d8484b0SPhilippe Charnier nextword(char *wp, char *wbuf) 2519b50d902SRodney W. Grimes { 2529ce73e90SMike Heffner int c; 2539b50d902SRodney W. Grimes 2549ce73e90SMike Heffner if (wp == NULL) { 2559ce73e90SMike Heffner *wbuf = '\0'; 2569ce73e90SMike Heffner return (NULL); 2579b50d902SRodney W. Grimes } 2589ce73e90SMike Heffner while ((c = *wp++) != '\0' && c != ' ' && c != '\t') { 2599b50d902SRodney W. Grimes *wbuf++ = c; 2609b50d902SRodney W. Grimes if (c == '"') { 2619ce73e90SMike Heffner while ((c = *wp++) != '\0' && c != '"') 2629b50d902SRodney W. Grimes *wbuf++ = c; 2639b50d902SRodney W. Grimes if (c == '"') 2649b50d902SRodney W. Grimes *wbuf++ = c; 2659b50d902SRodney W. Grimes else 2669b50d902SRodney W. Grimes wp--; 2679b50d902SRodney W. Grimes } 2689b50d902SRodney W. Grimes } 2699b50d902SRodney W. Grimes *wbuf = '\0'; 2709b50d902SRodney W. Grimes for (; c == ' ' || c == '\t'; c = *wp++) 2719b50d902SRodney W. Grimes ; 2729ce73e90SMike Heffner if (c == '\0') 2739ce73e90SMike Heffner return (NULL); 2749b50d902SRodney W. Grimes return (wp - 1); 2759b50d902SRodney W. Grimes } 276