1ef77d8e9Sdist /* 2ef77d8e9Sdist * Copyright (c) 1980 Regents of the University of California. 313f94090Sbostic * All rights reserved. 413f94090Sbostic * 5*2b713f00Sbostic * %sccs.include.redist.c% 6ef77d8e9Sdist */ 7ef77d8e9Sdist 88cab6285Sbostic #ifndef lint 9*2b713f00Sbostic static char sccsid[] = "@(#)head.c 5.7 (Berkeley) 06/01/90"; 108cab6285Sbostic #endif /* not lint */ 11068bc5fdSkas 12068bc5fdSkas #include "rcv.h" 13068bc5fdSkas 14068bc5fdSkas /* 15068bc5fdSkas * Mail -- a mail program 16068bc5fdSkas * 17068bc5fdSkas * Routines for processing and detecting headlines. 18068bc5fdSkas */ 19068bc5fdSkas 20068bc5fdSkas /* 21068bc5fdSkas * See if the passed line buffer is a mail header. 22068bc5fdSkas * Return true if yes. Note the extreme pains to 23068bc5fdSkas * accomodate all funny formats. 24068bc5fdSkas */ 25068bc5fdSkas ishead(linebuf) 26068bc5fdSkas char linebuf[]; 27068bc5fdSkas { 28068bc5fdSkas register char *cp; 29068bc5fdSkas struct headline hl; 30068bc5fdSkas char parbuf[BUFSIZ]; 31068bc5fdSkas 32068bc5fdSkas cp = linebuf; 33a1e0f4b8Sedward if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' || 34a1e0f4b8Sedward *cp++ != ' ') 35068bc5fdSkas return (0); 36a1e0f4b8Sedward parse(linebuf, &hl, parbuf); 37068bc5fdSkas if (hl.l_from == NOSTR || hl.l_date == NOSTR) { 38068bc5fdSkas fail(linebuf, "No from or date field"); 39068bc5fdSkas return (0); 40068bc5fdSkas } 41068bc5fdSkas if (!isdate(hl.l_date)) { 42068bc5fdSkas fail(linebuf, "Date field not legal date"); 43068bc5fdSkas return (0); 44068bc5fdSkas } 45068bc5fdSkas /* 46068bc5fdSkas * I guess we got it! 47068bc5fdSkas */ 48068bc5fdSkas return (1); 49068bc5fdSkas } 50068bc5fdSkas 51a1e0f4b8Sedward /*ARGSUSED*/ 52068bc5fdSkas fail(linebuf, reason) 53068bc5fdSkas char linebuf[], reason[]; 54068bc5fdSkas { 55068bc5fdSkas 56a1e0f4b8Sedward /* 57a1e0f4b8Sedward if (value("debug") == NOSTR) 58068bc5fdSkas return; 59068bc5fdSkas fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason); 60a1e0f4b8Sedward */ 61068bc5fdSkas } 62068bc5fdSkas 63068bc5fdSkas /* 64068bc5fdSkas * Split a headline into its useful components. 65068bc5fdSkas * Copy the line into dynamic string space, then set 66068bc5fdSkas * pointers into the copied line in the passed headline 67068bc5fdSkas * structure. Actually, it scans. 68068bc5fdSkas */ 69068bc5fdSkas parse(line, hl, pbuf) 70068bc5fdSkas char line[], pbuf[]; 71a1e0f4b8Sedward register struct headline *hl; 72068bc5fdSkas { 73a1e0f4b8Sedward register char *cp; 74068bc5fdSkas char *sp; 75068bc5fdSkas char word[LINESIZE]; 76068bc5fdSkas 77068bc5fdSkas hl->l_from = NOSTR; 78068bc5fdSkas hl->l_tty = NOSTR; 79068bc5fdSkas hl->l_date = NOSTR; 80068bc5fdSkas cp = line; 81068bc5fdSkas sp = pbuf; 82068bc5fdSkas /* 83a1e0f4b8Sedward * Skip over "From" first. 84068bc5fdSkas */ 85068bc5fdSkas cp = nextword(cp, word); 86a1e0f4b8Sedward cp = nextword(cp, word); 87a1e0f4b8Sedward if (*word) 88068bc5fdSkas hl->l_from = copyin(word, &sp); 89a1e0f4b8Sedward if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') { 90a1e0f4b8Sedward cp = nextword(cp, word); 91068bc5fdSkas hl->l_tty = copyin(word, &sp); 92a1e0f4b8Sedward } 93068bc5fdSkas if (cp != NOSTR) 94068bc5fdSkas hl->l_date = copyin(cp, &sp); 95068bc5fdSkas } 96068bc5fdSkas 97068bc5fdSkas /* 98068bc5fdSkas * Copy the string on the left into the string on the right 99068bc5fdSkas * and bump the right (reference) string pointer by the length. 100068bc5fdSkas * Thus, dynamically allocate space in the right string, copying 101068bc5fdSkas * the left string into it. 102068bc5fdSkas */ 103068bc5fdSkas char * 104068bc5fdSkas copyin(src, space) 105a1e0f4b8Sedward register char *src; 106068bc5fdSkas char **space; 107068bc5fdSkas { 108a1e0f4b8Sedward register char *cp; 109a1e0f4b8Sedward char *top; 110068bc5fdSkas 111a1e0f4b8Sedward top = cp = *space; 112a1e0f4b8Sedward while (*cp++ = *src++) 113a1e0f4b8Sedward ; 114068bc5fdSkas *space = cp; 115068bc5fdSkas return (top); 116068bc5fdSkas } 117068bc5fdSkas 118068bc5fdSkas /* 119068bc5fdSkas * Test to see if the passed string is a ctime(3) generated 120068bc5fdSkas * date string as documented in the manual. The template 121068bc5fdSkas * below is used as the criterion of correctness. 122068bc5fdSkas * Also, we check for a possible trailing time zone using 123552a793fSedward * the tmztype template. 124068bc5fdSkas */ 125068bc5fdSkas 126552a793fSedward /* 127552a793fSedward * 'A' An upper case char 128552a793fSedward * 'a' A lower case char 129552a793fSedward * ' ' A space 130552a793fSedward * '0' A digit 131552a793fSedward * 'O' An optional digit or space 132552a793fSedward * ':' A colon 133552a793fSedward * 'N' A new line 134552a793fSedward */ 135552a793fSedward char ctype[] = "Aaa Aaa O0 00:00:00 0000"; 136552a793fSedward char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000"; 137068bc5fdSkas 138068bc5fdSkas isdate(date) 139068bc5fdSkas char date[]; 140068bc5fdSkas { 141068bc5fdSkas 142552a793fSedward return cmatch(date, ctype) || cmatch(date, tmztype); 143068bc5fdSkas } 144068bc5fdSkas 145068bc5fdSkas /* 146a1e0f4b8Sedward * Match the given string (cp) against the given template (tp). 147068bc5fdSkas * Return 1 if they match, 0 if they don't 148068bc5fdSkas */ 149a1e0f4b8Sedward cmatch(cp, tp) 150068bc5fdSkas register char *cp, *tp; 151a1e0f4b8Sedward { 152068bc5fdSkas 153a1e0f4b8Sedward while (*cp && *tp) 154068bc5fdSkas switch (*tp++) { 155552a793fSedward case 'a': 156a1e0f4b8Sedward if (!islower(*cp++)) 157a1e0f4b8Sedward return 0; 158068bc5fdSkas break; 159552a793fSedward case 'A': 160a1e0f4b8Sedward if (!isupper(*cp++)) 161a1e0f4b8Sedward return 0; 162068bc5fdSkas break; 163552a793fSedward case ' ': 164a1e0f4b8Sedward if (*cp++ != ' ') 165a1e0f4b8Sedward return 0; 166068bc5fdSkas break; 167552a793fSedward case '0': 168a1e0f4b8Sedward if (!isdigit(*cp++)) 169a1e0f4b8Sedward return 0; 170068bc5fdSkas break; 171552a793fSedward case 'O': 172a1e0f4b8Sedward if (*cp != ' ' && !isdigit(*cp)) 173a1e0f4b8Sedward return 0; 174a1e0f4b8Sedward cp++; 175068bc5fdSkas break; 176552a793fSedward case ':': 177a1e0f4b8Sedward if (*cp++ != ':') 178a1e0f4b8Sedward return 0; 179068bc5fdSkas break; 180552a793fSedward case 'N': 181a1e0f4b8Sedward if (*cp++ != '\n') 182a1e0f4b8Sedward return 0; 183068bc5fdSkas break; 184068bc5fdSkas } 185a1e0f4b8Sedward if (*cp || *tp) 186a1e0f4b8Sedward return 0; 187068bc5fdSkas return (1); 188068bc5fdSkas } 189068bc5fdSkas 190068bc5fdSkas /* 191068bc5fdSkas * Collect a liberal (space, tab delimited) word into the word buffer 192068bc5fdSkas * passed. Also, return a pointer to the next word following that, 193068bc5fdSkas * or NOSTR if none follow. 194068bc5fdSkas */ 195068bc5fdSkas char * 196068bc5fdSkas nextword(wp, wbuf) 197a1e0f4b8Sedward register char *wp, *wbuf; 198068bc5fdSkas { 199068bc5fdSkas register c; 200068bc5fdSkas 201a1e0f4b8Sedward if (wp == NOSTR) { 202a1e0f4b8Sedward *wbuf = 0; 203a1e0f4b8Sedward return (NOSTR); 204a1e0f4b8Sedward } 205a1e0f4b8Sedward while ((c = *wp++) && c != ' ' && c != '\t') { 206a1e0f4b8Sedward *wbuf++ = c; 207a1e0f4b8Sedward if (c == '"') { 208a1e0f4b8Sedward while ((c = *wp++) && c != '"') 209a1e0f4b8Sedward *wbuf++ = c; 210a1e0f4b8Sedward if (c == '"') 211a1e0f4b8Sedward *wbuf++ = c; 212a1e0f4b8Sedward else 213a1e0f4b8Sedward wp--; 214a1e0f4b8Sedward } 215a1e0f4b8Sedward } 216a1e0f4b8Sedward *wbuf = '\0'; 217a1e0f4b8Sedward for (; c == ' ' || c == '\t'; c = *wp++) 218a1e0f4b8Sedward ; 219a1e0f4b8Sedward if (c == 0) 220a1e0f4b8Sedward return (NOSTR); 221a1e0f4b8Sedward return (wp - 1); 222068bc5fdSkas } 223