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