1 #ifndef lint 2 static char sccsid[] = "@(#)head.c 2.3 (Berkeley) 08/11/83"; 3 #endif 4 5 #include "rcv.h" 6 7 /* 8 * Mail -- a mail program 9 * 10 * Routines for processing and detecting headlines. 11 */ 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 *cp2++ = *cp++; 226 *cp2 = '\0'; 227 while (any(*cp, " \t")) 228 cp++; 229 if (*cp == '\0') 230 return(NOSTR); 231 return(cp); 232 } 233 234 /* 235 * Test to see if the character is an ascii alphabetic. 236 */ 237 238 isalpha(c) 239 { 240 register int ch; 241 242 ch = raise(c); 243 return(ch >= 'A' && ch <= 'Z'); 244 } 245 246 /* 247 * Test to see if the character is an ascii digit. 248 */ 249 250 isdigit(c) 251 { 252 return(c >= '0' && c <= '9'); 253 } 254 255 /* 256 * Copy str1 to str2, return pointer to null in str2. 257 */ 258 259 char * 260 copy(str1, str2) 261 char *str1, *str2; 262 { 263 register char *s1, *s2; 264 265 s1 = str1; 266 s2 = str2; 267 while (*s1) 268 *s2++ = *s1++; 269 *s2 = 0; 270 return(s2); 271 } 272 273 /* 274 * Is ch any of the characters in str? 275 */ 276 277 any(ch, str) 278 char *str; 279 { 280 register char *f; 281 register c; 282 283 f = str; 284 c = ch; 285 while (*f) 286 if (c == *f++) 287 return(1); 288 return(0); 289 } 290 291 /* 292 * Convert lower case letters to upper case. 293 */ 294 295 raise(c) 296 register int c; 297 { 298 if (c >= 'a' && c <= 'z') 299 c += 'A' - 'a'; 300 return(c); 301 } 302