1 # include <errno.h> 2 # include "sendmail.h" 3 4 SCCSID(@(#)headers.c 3.34 09/06/82); 5 6 /* 7 ** CHOMPHEADER -- process and save a header line. 8 ** 9 ** Called by collect and by readcf to deal with header lines. 10 ** 11 ** Parameters: 12 ** line -- header as a text line. 13 ** def -- if set, this is a default value. 14 ** 15 ** Returns: 16 ** flags for this header. 17 ** 18 ** Side Effects: 19 ** The header is saved on the header list. 20 ** Contents of 'line' are destroyed. 21 */ 22 23 chompheader(line, def) 24 char *line; 25 bool def; 26 { 27 register char *p; 28 register HDR *h; 29 HDR **hp; 30 char *fname; 31 char *fvalue; 32 struct hdrinfo *hi; 33 u_long mopts; 34 extern u_long mfencode(); 35 extern char *crackaddr(); 36 37 # ifdef DEBUG 38 if (tTd(31, 6)) 39 printf("chompheader: %s\n", line); 40 # endif DEBUG 41 42 /* strip off options */ 43 mopts = 0; 44 p = line; 45 if (*p == '?') 46 { 47 /* have some */ 48 register char *q = index(p + 1, *p); 49 50 if (q != NULL) 51 { 52 *q++ = '\0'; 53 mopts = mfencode(p + 1); 54 p = q; 55 } 56 else 57 syserr("chompheader: syntax error, line \"%s\"", line); 58 } 59 60 /* find canonical name */ 61 fname = p; 62 p = index(p, ':'); 63 fvalue = &p[1]; 64 while (isspace(*--p)) 65 continue; 66 *++p = '\0'; 67 makelower(fname); 68 69 /* strip field value on front */ 70 if (*fvalue == ' ') 71 fvalue++; 72 73 /* search header list for this header */ 74 for (hp = &CurEnv->e_header, h = CurEnv->e_header; h != NULL; hp = &h->h_link, h = h->h_link) 75 { 76 if (strcmp(fname, h->h_field) == 0 && bitset(H_DEFAULT, h->h_flags)) 77 break; 78 } 79 80 /* see if it is a known type */ 81 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 82 { 83 if (strcmp(hi->hi_field, fname) == 0) 84 break; 85 } 86 87 /* if this means "end of header" quit now */ 88 if (bitset(H_EOH, hi->hi_flags)) 89 return (hi->hi_flags); 90 91 /* count Received: lines to avoid loops (simulate hop counts) */ 92 if (bitset(H_TRACE, hi->hi_flags)) 93 HopCount++; 94 95 /* create/fill in a new node */ 96 if (h == NULL || bitset(H_FORCE, h->h_flags)) 97 { 98 /* create a new node */ 99 h = (HDR *) xalloc(sizeof *h); 100 h->h_field = newstr(fname); 101 h->h_value = NULL; 102 h->h_link = *hp; 103 h->h_mflags = mopts | hi->hi_mflags; 104 *hp = h; 105 } 106 h->h_flags = hi->hi_flags; 107 if (def) 108 h->h_flags |= H_DEFAULT; 109 else if (mopts == 0) 110 h->h_flags &= ~H_CHECK; 111 if (h->h_value != NULL) 112 free(h->h_value); 113 h->h_value = newstr(fvalue); 114 115 /* hack to see if this is a new format message */ 116 if (!def && bitset(H_RCPT|H_FROM, h->h_flags) && 117 (index(fvalue, ',') != NULL || index(fvalue, '(') != NULL || 118 index(fvalue, '<') != NULL || index(fvalue, ';') != NULL)) 119 { 120 CurEnv->e_oldstyle = FALSE; 121 } 122 123 /* send to this person if we so desire */ 124 if (!def && GrabTo && bitset(H_RCPT, h->h_flags)) 125 sendto(h->h_value, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 126 127 return (h->h_flags); 128 } 129 /* 130 ** ADDHEADER -- add a header entry to the end of the queue. 131 ** 132 ** This bypasses the special checking of chompheader. 133 ** 134 ** Parameters: 135 ** field -- the name of the header field. 136 ** value -- the value of the field. It must be lower-cased. 137 ** e -- the envelope to add them to. 138 ** 139 ** Returns: 140 ** none. 141 ** 142 ** Side Effects: 143 ** adds the field on the list of headers for this envelope. 144 */ 145 146 addheader(field, value, e) 147 char *field; 148 char *value; 149 ENVELOPE *e; 150 { 151 register HDR *h; 152 register struct hdrinfo *hi; 153 HDR **hp; 154 155 /* find info struct */ 156 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 157 { 158 if (strcmp(field, hi->hi_field) == 0) 159 break; 160 } 161 162 /* find current place in list -- keep back pointer? */ 163 for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 164 { 165 if (strcmp(field, h->h_field) == 0) 166 break; 167 } 168 169 /* allocate space for new header */ 170 h = (HDR *) xalloc(sizeof *h); 171 h->h_field = field; 172 h->h_value = newstr(value); 173 h->h_link = *hp; 174 h->h_flags = hi->hi_flags | H_DEFAULT; 175 h->h_mflags = hi->hi_mflags; 176 *hp = h; 177 } 178 /* 179 ** HVALUE -- return value of a header. 180 ** 181 ** Only "real" fields (i.e., ones that have not been supplied 182 ** as a default) are used. 183 ** 184 ** Parameters: 185 ** field -- the field name. 186 ** 187 ** Returns: 188 ** pointer to the value part. 189 ** NULL if not found. 190 ** 191 ** Side Effects: 192 ** sets the H_USED bit in the header if found. 193 */ 194 195 char * 196 hvalue(field) 197 char *field; 198 { 199 register HDR *h; 200 201 for (h = CurEnv->e_header; h != NULL; h = h->h_link) 202 { 203 if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0) 204 { 205 h->h_flags |= H_USED; 206 return (h->h_value); 207 } 208 } 209 return (NULL); 210 } 211 /* 212 ** HRVALUE -- return pointer to header descriptor. 213 ** 214 ** Like hvalue except returns header descriptor block and isn't 215 ** picky about "real" headers. 216 ** 217 ** Parameters: 218 ** field -- name of field we are interested in. 219 ** 220 ** Returns: 221 ** pointer to header descriptor. 222 ** 223 ** Side Effects: 224 ** none. 225 */ 226 227 HDR * 228 hrvalue(field) 229 char *field; 230 { 231 register HDR *h; 232 233 for (h = CurEnv->e_header; h != NULL; h = h->h_link) 234 { 235 if (strcmp(h->h_field, field) == 0) 236 return (h); 237 } 238 return (NULL); 239 } 240 /* 241 ** ISHEADER -- predicate telling if argument is a header. 242 ** 243 ** A line is a header if it has a single word followed by 244 ** optional white space followed by a colon. 245 ** 246 ** Parameters: 247 ** s -- string to check for possible headerness. 248 ** 249 ** Returns: 250 ** TRUE if s is a header. 251 ** FALSE otherwise. 252 ** 253 ** Side Effects: 254 ** none. 255 */ 256 257 bool 258 isheader(s) 259 register char *s; 260 { 261 if (!isalnum(*s)) 262 return (FALSE); 263 while (!isspace(*s) && *s != ':' && *s != '\0') 264 s++; 265 while (isspace(*s)) 266 s++; 267 return (*s == ':'); 268 } 269 /* 270 ** GETXPART -- extract the "signature" part of an address line. 271 ** 272 ** Try to extract the full name from a general address 273 ** field. We take anything which is a comment as a 274 ** first choice. Failing in that, we see if there is 275 ** a "machine readable" name (in <angle brackets>); if 276 ** so we take anything preceeding that clause. 277 ** 278 ** If we blow it here it's not all that serious. 279 ** 280 ** Parameters: 281 ** p -- line to crack. 282 ** 283 ** Returns: 284 ** signature part. 285 ** NULL if no signature part. 286 ** 287 ** Side Effects: 288 ** none. 289 */ 290 291 char * 292 getxpart(p) 293 register char *p; 294 { 295 register char *q; 296 register char *rval = NULL; 297 298 q = index(p, '('); 299 if (q != NULL) 300 { 301 int parenlev = 0; 302 303 for (p = q; *p != '\0'; p++) 304 { 305 if (*p == '(') 306 parenlev++; 307 else if (*p == ')' && --parenlev <= 0) 308 break; 309 } 310 if (*p == ')') 311 { 312 *p = '\0'; 313 if (*++q != '\0') 314 rval = newstr(q); 315 *p = ')'; 316 } 317 } 318 else if ((q = index(p, '<')) != NULL) 319 { 320 char savec; 321 322 while (*--q == ' ') 323 continue; 324 while (isspace(*p)) 325 p++; 326 savec = *++q; 327 *q = '\0'; 328 if (*p != '\0') 329 rval = newstr(p); 330 *q = savec; 331 } 332 333 return (rval); 334 } 335 /* 336 ** EATHEADER -- run through the stored header and extract info. 337 ** 338 ** Parameters: 339 ** none. 340 ** 341 ** Returns: 342 ** none. 343 ** 344 ** Side Effects: 345 ** Sets a bunch of global variables from information 346 ** in the collected header. 347 */ 348 349 eatheader() 350 { 351 register HDR *h; 352 register char *p; 353 char buf[MAXLINE]; 354 355 # ifdef DEBUG 356 if (tTd(32, 2)) 357 { 358 extern char *capitalize(); 359 360 printf("----- collected header -----\n"); 361 for (h = CurEnv->e_header; h != NULL; h = h->h_link) 362 printf("%s: %s\n", capitalize(h->h_field), h->h_value); 363 printf("----------------------------\n"); 364 } 365 # endif DEBUG 366 367 /* message priority */ 368 if (!QueueRun) 369 { 370 /* adjust total priority by message priority */ 371 CurEnv->e_msgpriority = CurEnv->e_msgsize; 372 p = hvalue("precedence"); 373 if (p != NULL) 374 CurEnv->e_class = priencode(p); 375 else 376 CurEnv->e_class = PRI_NORMAL; 377 CurEnv->e_msgpriority -= CurEnv->e_class * WKPRIFACT; 378 } 379 380 /* return receipt to */ 381 p = hvalue("return-receipt-to"); 382 if (p != NULL) 383 CurEnv->e_receiptto = p; 384 385 /* from person */ 386 if (ArpaMode) 387 { 388 register struct hdrinfo *hi = HdrInfo; 389 390 for (p = NULL; p == NULL && hi->hi_field != NULL; hi++) 391 { 392 if (bitset(H_FROM, hi->hi_flags)) 393 p = hvalue(hi->hi_field); 394 } 395 if (p != NULL) 396 setfrom(p, (char *) NULL); 397 } 398 399 /* full name of from person */ 400 p = hvalue("full-name"); 401 if (p != NULL) 402 define('x', p); 403 404 /* date message originated */ 405 p = hvalue("posted-date"); 406 if (p == NULL) 407 p = hvalue("date"); 408 if (p != NULL) 409 { 410 define('a', p); 411 /* we don't have a good way to do canonical conversion .... 412 define('d', newstr(arpatounix(p))); 413 .... so we will ignore the problem for the time being */ 414 } 415 } 416 /* 417 ** PRIENCODE -- encode external priority names into internal values. 418 ** 419 ** Parameters: 420 ** p -- priority in ascii. 421 ** 422 ** Returns: 423 ** priority as a numeric level. 424 ** 425 ** Side Effects: 426 ** none. 427 */ 428 429 struct prio 430 { 431 char *pri_name; /* external name of priority */ 432 int pri_val; /* internal value for same */ 433 }; 434 435 static struct prio Prio[] = 436 { 437 "alert", PRI_ALERT, 438 "quick", PRI_QUICK, 439 "first-class", PRI_FIRSTCL, 440 "normal", PRI_NORMAL, 441 "second-class", PRI_SECONDCL, 442 "third-class", PRI_THIRDCL, 443 "junk", PRI_JUNK, 444 NULL, PRI_NORMAL, 445 }; 446 447 priencode(p) 448 char *p; 449 { 450 register struct prio *pl; 451 extern bool sameword(); 452 453 for (pl = Prio; pl->pri_name != NULL; pl++) 454 { 455 if (sameword(p, pl->pri_name)) 456 break; 457 } 458 return (pl->pri_val); 459 } 460 /* 461 ** CRACKADDR -- parse an address and turn it into a macro 462 ** 463 ** This doesn't actually parse the address -- it just extracts 464 ** it and replaces it with "$g". The parse is totally ad hoc 465 ** and isn't even guaranteed to leave something syntactically 466 ** identical to what it started with. However, it does leave 467 ** something semantically identical. 468 ** 469 ** The process is kind of strange. There are a number of 470 ** interesting cases: 471 ** 1. comment <address> comment ==> comment <$g> comment 472 ** 2. address ==> address 473 ** 3. address (comment) ==> $g (comment) 474 ** 4. (comment) address ==> (comment) $g 475 ** And then there are the hard cases.... 476 ** 5. add (comment) ress ==> $g (comment) 477 ** 6. comment <address (comment)> ==> comment <$g (comment)> 478 ** 7. .... etc .... 479 ** 480 ** Parameters: 481 ** addr -- the address to be cracked. 482 ** 483 ** Returns: 484 ** a pointer to the new version. 485 ** 486 ** Side Effects: 487 ** none. 488 ** 489 ** Warning: 490 ** The return value is saved in local storage and should 491 ** be copied if it is to be reused. 492 */ 493 494 char * 495 crackaddr(addr) 496 register char *addr; 497 { 498 register char *p; 499 register int i; 500 static char buf[MAXNAME]; 501 char *rhs; 502 bool gotaddr; 503 register char *bp; 504 505 # ifdef DEBUG 506 if (tTd(33, 1)) 507 printf("crackaddr(%s)\n", addr); 508 # endif DEBUG 509 510 strcpy(buf, ""); 511 rhs = NULL; 512 513 /* strip leading spaces */ 514 while (*addr != '\0' && isspace(*addr)) 515 addr++; 516 517 /* 518 ** See if we have anything in angle brackets. If so, that is 519 ** the address part, and the rest is the comment. 520 */ 521 522 p = index(addr, '<'); 523 if (p != NULL) 524 { 525 /* copy the beginning of the addr field to the buffer */ 526 *p = '\0'; 527 strcpy(buf, addr); 528 strcat(buf, "<"); 529 *p++ = '<'; 530 531 /* skip spaces */ 532 while (isspace(*p)) 533 p++; 534 535 /* find the matching right angle bracket */ 536 addr = p; 537 for (i = 0; *p != '\0'; p++) 538 { 539 switch (*p) 540 { 541 case '<': 542 i++; 543 break; 544 545 case '>': 546 i--; 547 break; 548 } 549 if (i < 0) 550 break; 551 } 552 553 /* p now points to the closing quote (or a null byte) */ 554 if (*p != '\0') 555 { 556 /* make rhs point to the extra stuff at the end */ 557 rhs = p; 558 *p++ = '\0'; 559 } 560 } 561 562 /* 563 ** Now parse the real address part. "addr" points to the (null 564 ** terminated) version of what we are inerested in; rhs points 565 ** to the extra stuff at the end of the line, if any. 566 */ 567 568 p = addr; 569 570 /* now strip out comments */ 571 bp = &buf[strlen(buf)]; 572 gotaddr = FALSE; 573 for (; *p != '\0'; p++) 574 { 575 if (*p == '(') 576 { 577 /* copy to matching close paren */ 578 *bp++ = *p++; 579 for (i = 0; *p != '\0'; p++) 580 { 581 *bp++ = *p; 582 switch (*p) 583 { 584 case '(': 585 i++; 586 break; 587 588 case ')': 589 i--; 590 break; 591 } 592 if (i < 0) 593 break; 594 } 595 continue; 596 } 597 598 /* 599 ** If this is the first "real" character we have seen, 600 ** then we put the "$g" in the buffer now. 601 */ 602 603 if (isspace(*p)) 604 *bp++ = *p; 605 else if (!gotaddr) 606 { 607 strcpy(bp, "$g"); 608 bp += 2; 609 gotaddr = TRUE; 610 } 611 } 612 613 /* hack, hack.... strip trailing blanks */ 614 do 615 { 616 *bp-- = '\0'; 617 } while (isspace(*bp)); 618 bp++; 619 620 /* put any right hand side back on */ 621 if (rhs != NULL) 622 { 623 *rhs = '>'; 624 strcpy(bp, rhs); 625 } 626 627 # ifdef DEBUG 628 if (tTd(33, 1)) 629 printf("crackaddr=>`%s'\n", buf); 630 # endif DEBUG 631 632 return (buf); 633 } 634