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