1 # include <errno.h> 2 # include "sendmail.h" 3 4 static char SccsId[] = "@(#)collect.c 3.18 08/22/81"; 5 6 /* 7 ** COLLECT -- read & parse message header & make temp file. 8 ** 9 ** Creates a temporary file name and copies the standard 10 ** input to that file. While it is doing it, it looks for 11 ** "From:" and "Sender:" fields to use as the from-person 12 ** (but only if the -a flag is specified). It prefers to 13 ** to use the "Sender:" field. 14 ** 15 ** MIT seems to like to produce "Sent-By:" fields instead 16 ** of "Sender:" fields. We used to catch this, but it turns 17 ** out that the "Sent-By:" field doesn't always correspond 18 ** to someone real ("___057", for instance), as required by 19 ** the protocol. So we limp by..... 20 ** 21 ** Parameters: 22 ** none 23 ** 24 ** Returns: 25 ** none. 26 ** 27 ** Side Effects: 28 ** Temp file is created and filled. 29 ** The from person may be set. 30 */ 31 32 long MsgSize; /* size of message in bytes */ 33 FILE *TempFile; /* the tempfile (after creation) */ 34 35 collect() 36 { 37 register FILE *tf; 38 char buf[MAXFIELD+1]; 39 register char *p; 40 char c; 41 extern bool isheader(); 42 char *xfrom; 43 extern char *hvalue(); 44 extern char *mktemp(); 45 extern char *capitalize(); 46 # ifdef DEBUG 47 HDR *h; 48 # endif 49 50 /* 51 ** Create the temp file name and create the file. 52 */ 53 54 (void) mktemp(InFileName); 55 (void) close(creat(InFileName, 0600)); 56 if ((tf = fopen(InFileName, "w")) == NULL) 57 { 58 syserr("Cannot create %s", InFileName); 59 return; 60 } 61 62 /* try to read a UNIX-style From line */ 63 if (fgets(buf, sizeof buf, stdin) == NULL) 64 return; 65 if (strncmp(buf, "From ", 5) == 0) 66 { 67 eatfrom(buf); 68 (void) fgets(buf, sizeof buf, stdin); 69 } 70 71 /* 72 ** Copy stdin to temp file & do message editting. 73 ** To keep certain mailers from getting confused, 74 ** and to keep the output clean, lines that look 75 ** like UNIX "From" lines are deleted in the header, 76 ** and prepended with ">" in the body. 77 */ 78 79 for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin)) 80 { 81 /* see if the header is over */ 82 if (!isheader(buf)) 83 break; 84 85 /* get the rest of this field */ 86 while ((c = getc(stdin)) == ' ' || c == '\t') 87 { 88 p = &buf[strlen(buf)]; 89 *p++ = c; 90 if (fgets(p, sizeof buf - (p - buf), stdin) == NULL) 91 break; 92 } 93 if (!feof(stdin)) 94 (void) ungetc(c, stdin); 95 96 MsgSize += strlen(buf); 97 98 /* 99 ** Snarf header away. 100 */ 101 102 if (bitset(H_EOH, chompheader(buf, FALSE))) 103 break; 104 } 105 106 # ifdef DEBUG 107 if (Debug) 108 printf("EOH\n"); 109 # endif DEBUG 110 111 /* throw away a blank line */ 112 if (buf[0] == '\n') 113 (void) fgets(buf, sizeof buf, stdin); 114 115 /* 116 ** Collect the body of the message. 117 */ 118 119 for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL) 120 { 121 register int i; 122 123 /* check for end-of-message */ 124 if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 125 break; 126 127 /* Hide UNIX-like From lines */ 128 if (strncmp(buf, "From ", 5) == 0) 129 { 130 fputs(">", tf); 131 MsgSize++; 132 } 133 134 /* 135 ** Figure message length, output the line to the temp 136 ** file, and insert a newline if missing. 137 */ 138 139 i = strlen(buf); 140 MsgSize += i; 141 fputs(buf, tf); 142 if (buf[i - 1] != '\n') 143 fputs("\n", tf); 144 if (ferror(tf)) 145 { 146 if (errno == ENOSPC) 147 { 148 (void) freopen(InFileName, "w", tf); 149 fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 150 syserr("Out of disk space for temp file"); 151 } 152 else 153 syserr("Cannot write %s", InFileName); 154 (void) freopen("/dev/null", "w", tf); 155 } 156 } 157 (void) fclose(tf); 158 159 /* 160 ** Find out some information from the headers. 161 ** Examples are who is the from person & the date. 162 */ 163 164 /* from person */ 165 xfrom = hvalue("sender"); 166 if (xfrom == NULL) 167 xfrom = hvalue("original-from"); 168 if (ArpaMode != ARPA_NONE) 169 setfrom(xfrom, NULL); 170 171 /* full name of from person */ 172 p = hvalue("full-name"); 173 if (p != NULL) 174 define('x', p); 175 else 176 { 177 register char *q; 178 179 /* 180 ** Try to extract the full name from a general From: 181 ** field. We take anything which is a comment as a 182 ** first choice. Failing in that, we see if there is 183 ** a "machine readable" name (in <angle brackets>); if 184 ** so we take anything preceeding that clause. 185 ** 186 ** If we blow it here it's not all that serious. 187 */ 188 189 p = hvalue("original-from"); 190 q = index(p, '('); 191 if (q != NULL) 192 { 193 int parenlev = 0; 194 195 for (p = q; *p != '\0'; p++) 196 { 197 if (*p == '(') 198 parenlev++; 199 else if (*p == ')' && --parenlev <= 0) 200 break; 201 } 202 if (*p == ')') 203 { 204 *p = '\0'; 205 if (*++q != '\0') 206 define('x', newstr(q)); 207 *p = ')'; 208 } 209 } 210 else if ((q = index(p, '<')) != NULL) 211 { 212 char savec; 213 214 while (*--q == ' ') 215 continue; 216 while (isspace(*p)) 217 p++; 218 savec = *++q; 219 *q = '\0'; 220 if (*p != '\0') 221 define('x', newstr(p)); 222 *q = savec; 223 } 224 } 225 226 /* date message originated */ 227 p = hvalue("posted-date"); 228 if (p == NULL) 229 p = hvalue("date"); 230 if (p != NULL) 231 { 232 define('a', p); 233 /* we don't have a good way to do canonical conversion .... 234 define('d', newstr(arpatounix(p))); 235 .... so we will ignore the problem for the time being */ 236 } 237 238 if ((TempFile = fopen(InFileName, "r")) == NULL) 239 syserr("Cannot reopen %s", InFileName); 240 241 # ifdef DEBUG 242 if (Debug) 243 { 244 printf("----- collected header -----\n"); 245 for (h = Header; h != NULL; h = h->h_link) 246 printf("%s: %s\n", capitalize(h->h_field), h->h_value); 247 printf("----------------------------\n"); 248 } 249 # endif DEBUG 250 return; 251 } 252 /* 253 ** EATFROM -- chew up a UNIX style from line and process 254 ** 255 ** This does indeed make some assumptions about the format 256 ** of UNIX messages. 257 ** 258 ** Parameters: 259 ** fm -- the from line. 260 ** 261 ** Returns: 262 ** none. 263 ** 264 ** Side Effects: 265 ** extracts what information it can from the header, 266 ** such as the date. 267 */ 268 269 char *DowList[] = 270 { 271 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 272 }; 273 274 char *MonthList[] = 275 { 276 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 277 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 278 NULL 279 }; 280 281 eatfrom(fm) 282 char *fm; 283 { 284 register char *p; 285 register char **dt; 286 287 # ifdef DEBUG 288 if (Debug > 1) 289 printf("eatfrom(%s)\n", fm); 290 # endif DEBUG 291 292 /* find the date part */ 293 p = fm; 294 while (*p != '\0') 295 { 296 /* skip a word */ 297 while (*p != '\0' && *p != ' ') 298 *p++; 299 while (*p == ' ') 300 *p++; 301 if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 302 continue; 303 304 /* we have a possible date */ 305 for (dt = DowList; *dt != NULL; dt++) 306 if (strncmp(*dt, p, 3) == 0) 307 break; 308 if (*dt == NULL) 309 continue; 310 311 for (dt = MonthList; *dt != NULL; dt++) 312 if (strncmp(*dt, &p[4], 3) == 0) 313 break; 314 if (*dt != NULL) 315 break; 316 } 317 318 if (*p != NULL) 319 { 320 char *q; 321 322 /* we have found a date */ 323 q = xalloc(25); 324 strncpy(q, p, 25); 325 q[24] = '\0'; 326 define('d', q); 327 } 328 } 329