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.8 (Berkeley) 06/26/92"; 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 int 143 isdate(date) 144 char date[]; 145 { 146 147 return cmatch(date, ctype) || cmatch(date, tmztype); 148 } 149 150 /* 151 * Match the given string (cp) against the given template (tp). 152 * Return 1 if they match, 0 if they don't 153 */ 154 int 155 cmatch(cp, tp) 156 register char *cp, *tp; 157 { 158 159 while (*cp && *tp) 160 switch (*tp++) { 161 case 'a': 162 if (!islower(*cp++)) 163 return 0; 164 break; 165 case 'A': 166 if (!isupper(*cp++)) 167 return 0; 168 break; 169 case ' ': 170 if (*cp++ != ' ') 171 return 0; 172 break; 173 case '0': 174 if (!isdigit(*cp++)) 175 return 0; 176 break; 177 case 'O': 178 if (*cp != ' ' && !isdigit(*cp)) 179 return 0; 180 cp++; 181 break; 182 case ':': 183 if (*cp++ != ':') 184 return 0; 185 break; 186 case 'N': 187 if (*cp++ != '\n') 188 return 0; 189 break; 190 } 191 if (*cp || *tp) 192 return 0; 193 return (1); 194 } 195 196 /* 197 * Collect a liberal (space, tab delimited) word into the word buffer 198 * passed. Also, return a pointer to the next word following that, 199 * or NOSTR if none follow. 200 */ 201 char * 202 nextword(wp, wbuf) 203 register char *wp, *wbuf; 204 { 205 register c; 206 207 if (wp == NOSTR) { 208 *wbuf = 0; 209 return (NOSTR); 210 } 211 while ((c = *wp++) && c != ' ' && c != '\t') { 212 *wbuf++ = c; 213 if (c == '"') { 214 while ((c = *wp++) && c != '"') 215 *wbuf++ = c; 216 if (c == '"') 217 *wbuf++ = c; 218 else 219 wp--; 220 } 221 } 222 *wbuf = '\0'; 223 for (; c == ' ' || c == '\t'; c = *wp++) 224 ; 225 if (c == 0) 226 return (NOSTR); 227 return (wp - 1); 228 } 229