1 # include <errno.h> 2 # include "sendmail.h" 3 4 static char SccsId[] = "@(#)collect.c 3.29 11/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 ** sayok -- if set, give an ARPANET style message 23 ** to say we are ready to collect input. 24 ** 25 ** Returns: 26 ** none. 27 ** 28 ** Side Effects: 29 ** Temp file is created and filled. 30 ** The from person may be set. 31 */ 32 33 long MsgSize; /* size of message in bytes */ 34 35 collect(sayok) 36 bool sayok; 37 { 38 register FILE *tf; 39 char buf[MAXFIELD+1]; 40 register char *p; 41 char *xfrom; 42 extern char *hvalue(); 43 extern char *mktemp(); 44 static char tempfname[40]; 45 extern char *QueueDir; 46 47 /* 48 ** Create the temp file name and create the file. 49 */ 50 51 strcpy(tempfname, QueueDir); 52 strcat(tempfname, "/dfaXXXXXX"); 53 (void) mktemp(tempfname); 54 (void) close(creat(tempfname, 0600)); 55 if ((tf = fopen(tempfname, "w")) == NULL) 56 { 57 syserr("Cannot create %s", tempfname); 58 return; 59 } 60 InFileName = tempfname; 61 62 /* 63 ** Tell ARPANET to go ahead. 64 */ 65 66 if (sayok) 67 message("354", "Enter mail, end with \".\" on a line by itself"); 68 69 /* 70 ** Try to read a UNIX-style From line 71 */ 72 73 if (fgets(buf, sizeof buf, stdin) == NULL) 74 return; 75 fixcrlf(buf, FALSE); 76 # ifndef NOTUNIX 77 if (!SaveFrom && strncmp(buf, "From ", 5) == 0) 78 { 79 eatfrom(buf); 80 (void) fgets(buf, sizeof buf, stdin); 81 fixcrlf(buf, FALSE); 82 } 83 # endif NOTUNIX 84 85 /* 86 ** Copy stdin to temp file & do message editting. 87 ** To keep certain mailers from getting confused, 88 ** and to keep the output clean, lines that look 89 ** like UNIX "From" lines are deleted in the header, 90 ** and prepended with ">" in the body. 91 */ 92 93 for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL) 94 { 95 register char c; 96 extern bool isheader(); 97 98 fixcrlf(buf, FALSE); 99 100 /* see if the header is over */ 101 if (!isheader(buf)) 102 break; 103 104 /* get the rest of this field */ 105 while ((c = getc(stdin)) == ' ' || c == '\t') 106 { 107 p = &buf[strlen(buf)]; 108 *p++ = c; 109 if (fgets(p, sizeof buf - (p - buf), stdin) == NULL) 110 break; 111 fixcrlf(p, FALSE); 112 } 113 if (!feof(stdin)) 114 (void) ungetc(c, stdin); 115 116 MsgSize += strlen(buf); 117 118 /* 119 ** Snarf header away. 120 */ 121 122 if (bitset(H_EOH, chompheader(buf, FALSE))) 123 break; 124 } 125 126 # ifdef DEBUG 127 if (Debug) 128 printf("EOH\n"); 129 # endif DEBUG 130 131 /* throw away a blank line */ 132 if (buf[0] == '\n') 133 { 134 (void) fgets(buf, sizeof buf, stdin); 135 fixcrlf(buf, FALSE); 136 } 137 138 /* 139 ** Collect the body of the message. 140 */ 141 142 for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL) 143 { 144 register int i; 145 register char *bp = buf; 146 147 fixcrlf(buf, FALSE); 148 149 /* check for end-of-message */ 150 if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 151 break; 152 153 /* check for transparent dot */ 154 if (Smtp && *bp == '.') 155 bp++; 156 157 # ifndef NOTUNIX 158 /* Hide UNIX-like From lines */ 159 if (strncmp(bp, "From ", 5) == 0) 160 { 161 fputs(">", tf); 162 MsgSize++; 163 } 164 # endif NOTUNIX 165 166 /* 167 ** Figure message length, output the line to the temp 168 ** file, and insert a newline if missing. 169 */ 170 171 i = strlen(bp); 172 MsgSize += i; 173 fputs(bp, tf); 174 if (bp[i - 1] != '\n') 175 fputs("\n", tf); 176 if (ferror(tf)) 177 { 178 if (errno == ENOSPC) 179 { 180 (void) freopen(InFileName, "w", tf); 181 fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 182 usrerr("452 Out of disk space for temp file"); 183 } 184 else 185 syserr("collect: Cannot write %s", InFileName); 186 (void) freopen("/dev/null", "w", tf); 187 } 188 } 189 (void) fclose(tf); 190 191 /* 192 ** Find out some information from the headers. 193 ** Examples are who is the from person & the date. 194 */ 195 196 if (!QueueRun) 197 { 198 /* adjust total priority by message priority */ 199 MsgPriority = MsgSize; 200 p = hvalue("priority"); 201 if (p != NULL) 202 MsgPriority -= priencode(p) * WKPRIFACT; 203 } 204 205 /* from person */ 206 xfrom = hvalue("sender"); 207 if (xfrom == NULL) 208 xfrom = OrigFrom; 209 if (ArpaMode) 210 setfrom(xfrom, (char *) NULL); 211 212 /* full name of from person */ 213 p = hvalue("full-name"); 214 if (p != NULL) 215 define('x', p); 216 else 217 { 218 register char *q; 219 220 /* 221 ** Try to extract the full name from a general From: 222 ** field. We take anything which is a comment as a 223 ** first choice. Failing in that, we see if there is 224 ** a "machine readable" name (in <angle brackets>); if 225 ** so we take anything preceeding that clause. 226 ** 227 ** If we blow it here it's not all that serious. 228 */ 229 230 p = hvalue("original-from"); 231 if (p == NULL) 232 p = OrigFrom; 233 q = index(p, '('); 234 if (q != NULL) 235 { 236 int parenlev = 0; 237 238 for (p = q; *p != '\0'; p++) 239 { 240 if (*p == '(') 241 parenlev++; 242 else if (*p == ')' && --parenlev <= 0) 243 break; 244 } 245 if (*p == ')') 246 { 247 *p = '\0'; 248 if (*++q != '\0') 249 define('x', newstr(q)); 250 *p = ')'; 251 } 252 } 253 else if ((q = index(p, '<')) != NULL) 254 { 255 char savec; 256 257 while (*--q == ' ') 258 continue; 259 while (isspace(*p)) 260 p++; 261 savec = *++q; 262 *q = '\0'; 263 if (*p != '\0') 264 define('x', newstr(p)); 265 *q = savec; 266 } 267 } 268 269 /* date message originated */ 270 p = hvalue("posted-date"); 271 if (p == NULL) 272 p = hvalue("date"); 273 if (p != NULL) 274 { 275 define('a', p); 276 /* we don't have a good way to do canonical conversion .... 277 define('d', newstr(arpatounix(p))); 278 .... so we will ignore the problem for the time being */ 279 } 280 281 if ((TempFile = fopen(InFileName, "r")) == NULL) 282 syserr("Cannot reopen %s", InFileName); 283 284 # ifdef DEBUG 285 if (Debug) 286 { 287 HDR *h; 288 extern char *capitalize(); 289 290 printf("----- collected header -----\n"); 291 for (h = Header; h != NULL; h = h->h_link) 292 printf("%s: %s\n", capitalize(h->h_field), h->h_value); 293 printf("----------------------------\n"); 294 } 295 # endif DEBUG 296 return; 297 } 298 /* 299 ** EATFROM -- chew up a UNIX style from line and process 300 ** 301 ** This does indeed make some assumptions about the format 302 ** of UNIX messages. 303 ** 304 ** Parameters: 305 ** fm -- the from line. 306 ** 307 ** Returns: 308 ** none. 309 ** 310 ** Side Effects: 311 ** extracts what information it can from the header, 312 ** such as the date. 313 */ 314 315 # ifndef NOTUNIX 316 317 char *DowList[] = 318 { 319 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 320 }; 321 322 char *MonthList[] = 323 { 324 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 325 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 326 NULL 327 }; 328 329 eatfrom(fm) 330 char *fm; 331 { 332 register char *p; 333 register char **dt; 334 335 # ifdef DEBUG 336 if (Debug > 1) 337 printf("eatfrom(%s)\n", fm); 338 # endif DEBUG 339 340 /* find the date part */ 341 p = fm; 342 while (*p != '\0') 343 { 344 /* skip a word */ 345 while (*p != '\0' && *p != ' ') 346 *p++; 347 while (*p == ' ') 348 *p++; 349 if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 350 continue; 351 352 /* we have a possible date */ 353 for (dt = DowList; *dt != NULL; dt++) 354 if (strncmp(*dt, p, 3) == 0) 355 break; 356 if (*dt == NULL) 357 continue; 358 359 for (dt = MonthList; *dt != NULL; dt++) 360 if (strncmp(*dt, &p[4], 3) == 0) 361 break; 362 if (*dt != NULL) 363 break; 364 } 365 366 if (*p != NULL) 367 { 368 char *q; 369 370 /* we have found a date */ 371 q = xalloc(25); 372 strncpy(q, p, 25); 373 q[24] = '\0'; 374 define('d', q); 375 } 376 } 377 378 # endif NOTUNIX 379 /* 380 ** PRIENCODE -- encode external priority names into internal values. 381 ** 382 ** Parameters: 383 ** p -- priority in ascii. 384 ** 385 ** Returns: 386 ** priority as a numeric level. 387 ** 388 ** Side Effects: 389 ** none. 390 */ 391 392 struct prio 393 { 394 char *pri_name; /* external name of priority */ 395 int pri_val; /* internal value for same */ 396 }; 397 398 static struct prio Prio[] = 399 { 400 "alert", PRI_ALERT, 401 "quick", PRI_QUICK, 402 "first-class", PRI_FIRSTCL, 403 "normal", PRI_NORMAL, 404 "second-class", PRI_SECONDCL, 405 "third-class", PRI_THIRDCL, 406 NULL, PRI_NORMAL, 407 }; 408 409 priencode(p) 410 char *p; 411 { 412 register struct prio *pl; 413 extern bool sameword(); 414 415 for (pl = Prio; pl->pri_name != NULL; pl++) 416 { 417 if (sameword(p, pl->pri_name)) 418 break; 419 } 420 return (pl->pri_val); 421 } 422