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.2 3/3/83"; 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 (strncmp("From ", cp, 5) != 0) 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 (strncmp(dp, "tty", 3) == 0) { 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: * Test to see if the passed string is a ctime(3) generated 122: * date string as documented in the manual. The template 123: * below is used as the criterion of correctness. 124: * Also, we check for a possible trailing time zone using 125: * the auxtype template. 126: */ 127: 128: #define L 1 /* A lower case char */ 129: #define S 2 /* A space */ 130: #define D 3 /* A digit */ 131: #define O 4 /* An optional digit or space */ 132: #define C 5 /* A colon */ 133: #define N 6 /* A new line */ 134: #define U 7 /* An upper case char */ 135: 136: 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}; 137: 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}; 138: 139: isdate(date) 140: char date[]; 141: { 142: register char *cp; 143: 144: cp = date; 145: if (cmatch(cp, ctypes)) 146: return(1); 147: return(cmatch(cp, tmztypes)); 148: } 149: 150: /* 151: * Match the given string against the given template. 152: * Return 1 if they match, 0 if they don't 153: */ 154: 155: cmatch(str, temp) 156: char str[], temp[]; 157: { 158: register char *cp, *tp; 159: register int c; 160: 161: cp = str; 162: tp = temp; 163: while (*cp != '\0' && *tp != 0) { 164: c = *cp++; 165: switch (*tp++) { 166: case L: 167: if (c < 'a' || c > 'z') 168: return(0); 169: break; 170: 171: case U: 172: if (c < 'A' || c > 'Z') 173: return(0); 174: break; 175: 176: case S: 177: if (c != ' ') 178: return(0); 179: break; 180: 181: case D: 182: if (!isdigit(c)) 183: return(0); 184: break; 185: 186: case O: 187: if (c != ' ' && !isdigit(c)) 188: return(0); 189: break; 190: 191: case C: 192: if (c != ':') 193: return(0); 194: break; 195: 196: case N: 197: if (c != '\n') 198: return(0); 199: break; 200: } 201: } 202: if (*cp != '\0' || *tp != 0) 203: return(0); 204: return(1); 205: } 206: 207: /* 208: * Collect a liberal (space, tab delimited) word into the word buffer 209: * passed. Also, return a pointer to the next word following that, 210: * or NOSTR if none follow. 211: */ 212: 213: char * 214: nextword(wp, wbuf) 215: char wp[], wbuf[]; 216: { 217: register char *cp, *cp2; 218: 219: if ((cp = wp) == NOSTR) { 220: copy("", wbuf); 221: return(NOSTR); 222: } 223: cp2 = wbuf; 224: while (!any(*cp, " \t") && *cp != '\0') 225: if (*cp == '"') { 226: *cp2++ = *cp++; 227: while (*cp != '\0' && *cp != '"') 228: *cp2++ = *cp++; 229: if (*cp == '"') 230: *cp2++ = *cp++; 231: } else 232: *cp2++ = *cp++; 233: *cp2 = '\0'; 234: while (any(*cp, " \t")) 235: cp++; 236: if (*cp == '\0') 237: return(NOSTR); 238: return(cp); 239: } 240: 241: /* 242: * Test to see if the character is an ascii alphabetic. 243: */ 244: 245: isalpha(c) 246: { 247: register int ch; 248: 249: ch = raise(c); 250: return(ch >= 'A' && ch <= 'Z'); 251: } 252: 253: /* 254: * Test to see if the character is an ascii digit. 255: */ 256: 257: isdigit(c) 258: { 259: return(c >= '0' && c <= '9'); 260: } 261: 262: /* 263: * Copy str1 to str2, return pointer to null in str2. 264: */ 265: 266: char * 267: copy(str1, str2) 268: char *str1, *str2; 269: { 270: register char *s1, *s2; 271: 272: s1 = str1; 273: s2 = str2; 274: while (*s1) 275: *s2++ = *s1++; 276: *s2 = 0; 277: return(s2); 278: } 279: 280: /* 281: * Is ch any of the characters in str? 282: */ 283: 284: any(ch, str) 285: char *str; 286: { 287: register char *f; 288: register c; 289: 290: f = str; 291: c = ch; 292: while (*f) 293: if (c == *f++) 294: return(1); 295: return(0); 296: } 297: 298: /* 299: * Convert lower case letters to upper case. 300: */ 301: 302: raise(c) 303: register int c; 304: { 305: if (c >= 'a' && c <= 'z') 306: c += 'A' - 'a'; 307: return(c); 308: }