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