1 # 2 3 #include "rcv.h" 4 5 /* 6 * Mail -- a mail program 7 * 8 * Routines for processing and detecting headlines. 9 */ 10 11 static char *SccsId = "@(#)head.c 2.1 07/01/81"; 12 13 /* 14 * See if the passed line buffer is a mail header. 15 * Return true if yes. Note the extreme pains to 16 * accomodate all funny formats. 17 */ 18 19 ishead(linebuf) 20 char linebuf[]; 21 { 22 register char *cp; 23 struct headline hl; 24 char parbuf[BUFSIZ]; 25 26 cp = linebuf; 27 if (!isname("From ", cp, 5)) 28 return(0); 29 parse(cp, &hl, parbuf); 30 if (hl.l_from == NOSTR || hl.l_date == NOSTR) { 31 fail(linebuf, "No from or date field"); 32 return(0); 33 } 34 if (!isdate(hl.l_date)) { 35 fail(linebuf, "Date field not legal date"); 36 return(0); 37 } 38 39 /* 40 * I guess we got it! 41 */ 42 43 return(1); 44 } 45 46 fail(linebuf, reason) 47 char linebuf[], reason[]; 48 { 49 50 if (1 /*value("debug") == NOSTR*/) 51 return; 52 fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason); 53 } 54 55 /* 56 * Split a headline into its useful components. 57 * Copy the line into dynamic string space, then set 58 * pointers into the copied line in the passed headline 59 * structure. Actually, it scans. 60 */ 61 62 parse(line, hl, pbuf) 63 char line[], pbuf[]; 64 struct headline *hl; 65 { 66 register char *cp, *dp; 67 char *sp; 68 char word[LINESIZE]; 69 70 hl->l_from = NOSTR; 71 hl->l_tty = NOSTR; 72 hl->l_date = NOSTR; 73 cp = line; 74 sp = pbuf; 75 76 /* 77 * Skip the first "word" of the line, which should be "From" 78 * anyway. 79 */ 80 81 cp = nextword(cp, word); 82 dp = nextword(cp, word); 83 if (!equal(word, "")) 84 hl->l_from = copyin(word, &sp); 85 if (isname(dp, "tty", 3)) { 86 cp = nextword(dp, word); 87 hl->l_tty = copyin(word, &sp); 88 if (cp != NOSTR) 89 hl->l_date = copyin(cp, &sp); 90 } 91 else 92 if (dp != NOSTR) 93 hl->l_date = copyin(dp, &sp); 94 } 95 96 /* 97 * Copy the string on the left into the string on the right 98 * and bump the right (reference) string pointer by the length. 99 * Thus, dynamically allocate space in the right string, copying 100 * the left string into it. 101 */ 102 103 char * 104 copyin(src, space) 105 char src[]; 106 char **space; 107 { 108 register char *cp, *top; 109 register int s; 110 111 s = strlen(src); 112 cp = *space; 113 top = cp; 114 strcpy(cp, src); 115 cp += s + 1; 116 *space = cp; 117 return(top); 118 } 119 120 /* 121 * See if the two passed strings agree in the first n characters. 122 * Return true if they do, gnu. 123 */ 124 125 isname(as1, as2, acount) 126 char *as1, *as2; 127 { 128 register char *s1, *s2; 129 register count; 130 131 s1 = as1; 132 s2 = as2; 133 count = acount; 134 if (count > 0) 135 do 136 if (*s1++ != *s2++) 137 return(0); 138 while (--count); 139 return(1); 140 } 141 142 /* 143 * See if the two passed strings agree in the first n characters. 144 * Return true if they do, ignoring case. 145 */ 146 147 icisname(as1, as2, acount) 148 char *as1, *as2; 149 { 150 register char *s1, *s2; 151 register count; 152 153 s1 = as1; 154 s2 = as2; 155 count = acount; 156 if (count > 0) 157 do 158 if (raise(*s1++) != raise(*s2++)) 159 return(0); 160 while (--count); 161 return(1); 162 } 163 164 /* 165 * Test to see if the passed string is a ctime(3) generated 166 * date string as documented in the manual. The template 167 * below is used as the criterion of correctness. 168 * Also, we check for a possible trailing time zone using 169 * the auxtype template. 170 */ 171 172 #define L 1 /* A lower case char */ 173 #define S 2 /* A space */ 174 #define D 3 /* A digit */ 175 #define O 4 /* An optional digit or space */ 176 #define C 5 /* A colon */ 177 #define N 6 /* A new line */ 178 #define U 7 /* An upper case char */ 179 180 char ctypes[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,D,D,D,D,0}; 181 char tmztypes[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,U,U,U,S,D,D,D,D,0}; 182 183 isdate(date) 184 char date[]; 185 { 186 register char *cp; 187 188 cp = date; 189 if (cmatch(cp, ctypes)) 190 return(1); 191 return(cmatch(cp, tmztypes)); 192 } 193 194 /* 195 * Match the given string against the given template. 196 * Return 1 if they match, 0 if they don't 197 */ 198 199 cmatch(str, temp) 200 char str[], temp[]; 201 { 202 register char *cp, *tp; 203 register int c; 204 205 cp = str; 206 tp = temp; 207 while (*cp != '\0' && *tp != 0) { 208 c = *cp++; 209 switch (*tp++) { 210 case L: 211 if (c < 'a' || c > 'z') 212 return(0); 213 break; 214 215 case U: 216 if (c < 'A' || c > 'Z') 217 return(0); 218 break; 219 220 case S: 221 if (c != ' ') 222 return(0); 223 break; 224 225 case D: 226 if (!isdigit(c)) 227 return(0); 228 break; 229 230 case O: 231 if (c != ' ' && !isdigit(c)) 232 return(0); 233 break; 234 235 case C: 236 if (c != ':') 237 return(0); 238 break; 239 240 case N: 241 if (c != '\n') 242 return(0); 243 break; 244 } 245 } 246 if (*cp != '\0' || *tp != 0) 247 return(0); 248 return(1); 249 } 250 251 /* 252 * Collect a liberal (space, tab delimited) word into the word buffer 253 * passed. Also, return a pointer to the next word following that, 254 * or NOSTR if none follow. 255 */ 256 257 char * 258 nextword(wp, wbuf) 259 char wp[], wbuf[]; 260 { 261 register char *cp, *cp2; 262 263 if ((cp = wp) == NOSTR) { 264 copy("", wbuf); 265 return(NOSTR); 266 } 267 cp2 = wbuf; 268 while (!any(*cp, " \t") && *cp != '\0') 269 *cp2++ = *cp++; 270 *cp2 = '\0'; 271 while (any(*cp, " \t")) 272 cp++; 273 if (*cp == '\0') 274 return(NOSTR); 275 return(cp); 276 } 277 278 /* 279 * Test to see if the character is an ascii alphabetic. 280 */ 281 282 isalpha(c) 283 { 284 register int ch; 285 286 ch = raise(c); 287 return(ch >= 'A' && ch <= 'Z'); 288 } 289 290 /* 291 * Test to see if the character is an ascii digit. 292 */ 293 294 isdigit(c) 295 { 296 return(c >= '0' && c <= '9'); 297 } 298 299 /* 300 * Copy str1 to str2, return pointer to null in str2. 301 */ 302 303 char * 304 copy(str1, str2) 305 char *str1, *str2; 306 { 307 register char *s1, *s2; 308 309 s1 = str1; 310 s2 = str2; 311 while (*s1) 312 *s2++ = *s1++; 313 *s2 = 0; 314 return(s2); 315 } 316 317 /* 318 * Is ch any of the characters in str? 319 */ 320 321 any(ch, str) 322 char *str; 323 { 324 register char *f; 325 register c; 326 327 f = str; 328 c = ch; 329 while (*f) 330 if (c == *f++) 331 return(1); 332 return(0); 333 } 334 335 /* 336 * Convert lower case letters to upper case. 337 */ 338 339 raise(c) 340 register int c; 341 { 342 if (c >= 'a' && c <= 'z') 343 c += 'A' - 'a'; 344 return(c); 345 } 346