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