1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)head.c 5.7 (Berkeley) 06/01/90"; 10 #endif /* not lint */ 11 12 #include "rcv.h" 13 14 /* 15 * Mail -- a mail program 16 * 17 * Routines for processing and detecting headlines. 18 */ 19 20 /* 21 * See if the passed line buffer is a mail header. 22 * Return true if yes. Note the extreme pains to 23 * accomodate all funny formats. 24 */ 25 ishead(linebuf) 26 char linebuf[]; 27 { 28 register char *cp; 29 struct headline hl; 30 char parbuf[BUFSIZ]; 31 32 cp = linebuf; 33 if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' || 34 *cp++ != ' ') 35 return (0); 36 parse(linebuf, &hl, parbuf); 37 if (hl.l_from == NOSTR || hl.l_date == NOSTR) { 38 fail(linebuf, "No from or date field"); 39 return (0); 40 } 41 if (!isdate(hl.l_date)) { 42 fail(linebuf, "Date field not legal date"); 43 return (0); 44 } 45 /* 46 * I guess we got it! 47 */ 48 return (1); 49 } 50 51 /*ARGSUSED*/ 52 fail(linebuf, reason) 53 char linebuf[], reason[]; 54 { 55 56 /* 57 if (value("debug") == NOSTR) 58 return; 59 fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason); 60 */ 61 } 62 63 /* 64 * Split a headline into its useful components. 65 * Copy the line into dynamic string space, then set 66 * pointers into the copied line in the passed headline 67 * structure. Actually, it scans. 68 */ 69 parse(line, hl, pbuf) 70 char line[], pbuf[]; 71 register struct headline *hl; 72 { 73 register char *cp; 74 char *sp; 75 char word[LINESIZE]; 76 77 hl->l_from = NOSTR; 78 hl->l_tty = NOSTR; 79 hl->l_date = NOSTR; 80 cp = line; 81 sp = pbuf; 82 /* 83 * Skip over "From" first. 84 */ 85 cp = nextword(cp, word); 86 cp = nextword(cp, word); 87 if (*word) 88 hl->l_from = copyin(word, &sp); 89 if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') { 90 cp = nextword(cp, word); 91 hl->l_tty = copyin(word, &sp); 92 } 93 if (cp != NOSTR) 94 hl->l_date = copyin(cp, &sp); 95 } 96 97 /* 98 * Copy the string on the left into the string on the right 99 * and bump the right (reference) string pointer by the length. 100 * Thus, dynamically allocate space in the right string, copying 101 * the left string into it. 102 */ 103 char * 104 copyin(src, space) 105 register char *src; 106 char **space; 107 { 108 register char *cp; 109 char *top; 110 111 top = cp = *space; 112 while (*cp++ = *src++) 113 ; 114 *space = cp; 115 return (top); 116 } 117 118 /* 119 * Test to see if the passed string is a ctime(3) generated 120 * date string as documented in the manual. The template 121 * below is used as the criterion of correctness. 122 * Also, we check for a possible trailing time zone using 123 * the tmztype template. 124 */ 125 126 /* 127 * 'A' An upper case char 128 * 'a' A lower case char 129 * ' ' A space 130 * '0' A digit 131 * 'O' An optional digit or space 132 * ':' A colon 133 * 'N' A new line 134 */ 135 char ctype[] = "Aaa Aaa O0 00:00:00 0000"; 136 char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000"; 137 138 isdate(date) 139 char date[]; 140 { 141 142 return cmatch(date, ctype) || cmatch(date, tmztype); 143 } 144 145 /* 146 * Match the given string (cp) against the given template (tp). 147 * Return 1 if they match, 0 if they don't 148 */ 149 cmatch(cp, tp) 150 register char *cp, *tp; 151 { 152 153 while (*cp && *tp) 154 switch (*tp++) { 155 case 'a': 156 if (!islower(*cp++)) 157 return 0; 158 break; 159 case 'A': 160 if (!isupper(*cp++)) 161 return 0; 162 break; 163 case ' ': 164 if (*cp++ != ' ') 165 return 0; 166 break; 167 case '0': 168 if (!isdigit(*cp++)) 169 return 0; 170 break; 171 case 'O': 172 if (*cp != ' ' && !isdigit(*cp)) 173 return 0; 174 cp++; 175 break; 176 case ':': 177 if (*cp++ != ':') 178 return 0; 179 break; 180 case 'N': 181 if (*cp++ != '\n') 182 return 0; 183 break; 184 } 185 if (*cp || *tp) 186 return 0; 187 return (1); 188 } 189 190 /* 191 * Collect a liberal (space, tab delimited) word into the word buffer 192 * passed. Also, return a pointer to the next word following that, 193 * or NOSTR if none follow. 194 */ 195 char * 196 nextword(wp, wbuf) 197 register char *wp, *wbuf; 198 { 199 register c; 200 201 if (wp == NOSTR) { 202 *wbuf = 0; 203 return (NOSTR); 204 } 205 while ((c = *wp++) && c != ' ' && c != '\t') { 206 *wbuf++ = c; 207 if (c == '"') { 208 while ((c = *wp++) && c != '"') 209 *wbuf++ = c; 210 if (c == '"') 211 *wbuf++ = c; 212 else 213 wp--; 214 } 215 } 216 *wbuf = '\0'; 217 for (; c == ' ' || c == '\t'; c = *wp++) 218 ; 219 if (c == 0) 220 return (NOSTR); 221 return (wp - 1); 222 } 223