1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 static char sccsid[] = "@(#)head.c 5.6 (Berkeley) 07/08/88"; 20 #endif /* not lint */ 21 22 #include "rcv.h" 23 24 /* 25 * Mail -- a mail program 26 * 27 * Routines for processing and detecting headlines. 28 */ 29 30 /* 31 * See if the passed line buffer is a mail header. 32 * Return true if yes. Note the extreme pains to 33 * accomodate all funny formats. 34 */ 35 ishead(linebuf) 36 char linebuf[]; 37 { 38 register char *cp; 39 struct headline hl; 40 char parbuf[BUFSIZ]; 41 42 cp = linebuf; 43 if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' || 44 *cp++ != ' ') 45 return (0); 46 parse(linebuf, &hl, parbuf); 47 if (hl.l_from == NOSTR || hl.l_date == NOSTR) { 48 fail(linebuf, "No from or date field"); 49 return (0); 50 } 51 if (!isdate(hl.l_date)) { 52 fail(linebuf, "Date field not legal date"); 53 return (0); 54 } 55 /* 56 * I guess we got it! 57 */ 58 return (1); 59 } 60 61 /*ARGSUSED*/ 62 fail(linebuf, reason) 63 char linebuf[], reason[]; 64 { 65 66 /* 67 if (value("debug") == NOSTR) 68 return; 69 fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason); 70 */ 71 } 72 73 /* 74 * Split a headline into its useful components. 75 * Copy the line into dynamic string space, then set 76 * pointers into the copied line in the passed headline 77 * structure. Actually, it scans. 78 */ 79 parse(line, hl, pbuf) 80 char line[], pbuf[]; 81 register struct headline *hl; 82 { 83 register char *cp; 84 char *sp; 85 char word[LINESIZE]; 86 87 hl->l_from = NOSTR; 88 hl->l_tty = NOSTR; 89 hl->l_date = NOSTR; 90 cp = line; 91 sp = pbuf; 92 /* 93 * Skip over "From" first. 94 */ 95 cp = nextword(cp, word); 96 cp = nextword(cp, word); 97 if (*word) 98 hl->l_from = copyin(word, &sp); 99 if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') { 100 cp = nextword(cp, word); 101 hl->l_tty = copyin(word, &sp); 102 } 103 if (cp != NOSTR) 104 hl->l_date = copyin(cp, &sp); 105 } 106 107 /* 108 * Copy the string on the left into the string on the right 109 * and bump the right (reference) string pointer by the length. 110 * Thus, dynamically allocate space in the right string, copying 111 * the left string into it. 112 */ 113 char * 114 copyin(src, space) 115 register char *src; 116 char **space; 117 { 118 register char *cp; 119 char *top; 120 121 top = cp = *space; 122 while (*cp++ = *src++) 123 ; 124 *space = cp; 125 return (top); 126 } 127 128 /* 129 * Test to see if the passed string is a ctime(3) generated 130 * date string as documented in the manual. The template 131 * below is used as the criterion of correctness. 132 * Also, we check for a possible trailing time zone using 133 * the tmztype template. 134 */ 135 136 /* 137 * 'A' An upper case char 138 * 'a' A lower case char 139 * ' ' A space 140 * '0' A digit 141 * 'O' An optional digit or space 142 * ':' A colon 143 * 'N' A new line 144 */ 145 char ctype[] = "Aaa Aaa O0 00:00:00 0000"; 146 char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000"; 147 148 isdate(date) 149 char date[]; 150 { 151 152 return cmatch(date, ctype) || cmatch(date, tmztype); 153 } 154 155 /* 156 * Match the given string (cp) against the given template (tp). 157 * Return 1 if they match, 0 if they don't 158 */ 159 cmatch(cp, tp) 160 register char *cp, *tp; 161 { 162 163 while (*cp && *tp) 164 switch (*tp++) { 165 case 'a': 166 if (!islower(*cp++)) 167 return 0; 168 break; 169 case 'A': 170 if (!isupper(*cp++)) 171 return 0; 172 break; 173 case ' ': 174 if (*cp++ != ' ') 175 return 0; 176 break; 177 case '0': 178 if (!isdigit(*cp++)) 179 return 0; 180 break; 181 case 'O': 182 if (*cp != ' ' && !isdigit(*cp)) 183 return 0; 184 cp++; 185 break; 186 case ':': 187 if (*cp++ != ':') 188 return 0; 189 break; 190 case 'N': 191 if (*cp++ != '\n') 192 return 0; 193 break; 194 } 195 if (*cp || *tp) 196 return 0; 197 return (1); 198 } 199 200 /* 201 * Collect a liberal (space, tab delimited) word into the word buffer 202 * passed. Also, return a pointer to the next word following that, 203 * or NOSTR if none follow. 204 */ 205 char * 206 nextword(wp, wbuf) 207 register char *wp, *wbuf; 208 { 209 register c; 210 211 if (wp == NOSTR) { 212 *wbuf = 0; 213 return (NOSTR); 214 } 215 while ((c = *wp++) && c != ' ' && c != '\t') { 216 *wbuf++ = c; 217 if (c == '"') { 218 while ((c = *wp++) && c != '"') 219 *wbuf++ = c; 220 if (c == '"') 221 *wbuf++ = c; 222 else 223 wp--; 224 } 225 } 226 *wbuf = '\0'; 227 for (; c == ' ' || c == '\t'; c = *wp++) 228 ; 229 if (c == 0) 230 return (NOSTR); 231 return (wp - 1); 232 } 233