|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Eric P. Allman ! 3: * Copyright (c) 1988 Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * Redistribution and use in source and binary forms are permitted provided ! 7: * that: (1) source distributions retain this entire copyright notice and ! 8: * comment, and (2) distributions including binaries display the following ! 9: * acknowledgement: ``This product includes software developed by the ! 10: * University of California, Berkeley and its contributors'' in the ! 11: * documentation or other materials provided with the distribution and in ! 12: * all advertising materials mentioning features or use of this software. ! 13: * Neither the name of the University nor the names of its contributors may ! 14: * be used to endorse or promote products derived from this software without ! 15: * specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: */ ! 20: ! 21: #ifndef lint ! 22: static char sccsid[] = "@(#)headers.c 5.15 (Berkeley) 6/1/90"; ! 23: #endif /* not lint */ ! 24: ! 25: # include <sys/param.h> ! 26: # include <errno.h> ! 27: # include "sendmail.h" ! 28: ! 29: /* ! 30: ** CHOMPHEADER -- process and save a header line. ! 31: ** ! 32: ** Called by collect and by readcf to deal with header lines. ! 33: ** ! 34: ** Parameters: ! 35: ** line -- header as a text line. ! 36: ** def -- if set, this is a default value. ! 37: ** ! 38: ** Returns: ! 39: ** flags for this header. ! 40: ** ! 41: ** Side Effects: ! 42: ** The header is saved on the header list. ! 43: ** Contents of 'line' are destroyed. ! 44: */ ! 45: ! 46: chompheader(line, def) ! 47: char *line; ! 48: bool def; ! 49: { ! 50: register char *p; ! 51: register HDR *h; ! 52: HDR **hp; ! 53: char *fname; ! 54: char *fvalue; ! 55: struct hdrinfo *hi; ! 56: bool cond = FALSE; ! 57: BITMAP mopts; ! 58: extern char *crackaddr(); ! 59: ! 60: if (tTd(31, 6)) ! 61: printf("chompheader: %s\n", line); ! 62: ! 63: /* strip off options */ ! 64: clrbitmap(mopts); ! 65: p = line; ! 66: if (*p == '?') ! 67: { ! 68: /* have some */ ! 69: register char *q = index(p + 1, *p); ! 70: ! 71: if (q != NULL) ! 72: { ! 73: *q++ = '\0'; ! 74: while (*++p != '\0') ! 75: setbitn(*p, mopts); ! 76: p = q; ! 77: } ! 78: else ! 79: usrerr("chompheader: syntax error, line \"%s\"", line); ! 80: cond = TRUE; ! 81: } ! 82: ! 83: /* find canonical name */ ! 84: fname = p; ! 85: p = index(p, ':'); ! 86: if (p == NULL) ! 87: { ! 88: syserr("chompheader: syntax error, line \"%s\"", line); ! 89: return (0); ! 90: } ! 91: fvalue = &p[1]; ! 92: while (isspace(*--p)) ! 93: continue; ! 94: *++p = '\0'; ! 95: makelower(fname); ! 96: ! 97: /* strip field value on front */ ! 98: if (*fvalue == ' ') ! 99: fvalue++; ! 100: ! 101: /* see if it is a known type */ ! 102: for (hi = HdrInfo; hi->hi_field != NULL; hi++) ! 103: { ! 104: if (strcmp(hi->hi_field, fname) == 0) ! 105: break; ! 106: } ! 107: ! 108: /* see if this is a resent message */ ! 109: if (!def && bitset(H_RESENT, hi->hi_flags)) ! 110: CurEnv->e_flags |= EF_RESENT; ! 111: ! 112: /* if this means "end of header" quit now */ ! 113: if (bitset(H_EOH, hi->hi_flags)) ! 114: return (hi->hi_flags); ! 115: ! 116: /* drop explicit From: if same as what we would generate -- for MH */ ! 117: p = "resent-from"; ! 118: if (!bitset(EF_RESENT, CurEnv->e_flags)) ! 119: p += 7; ! 120: if (!def && !QueueRun && strcmp(fname, p) == 0) ! 121: { ! 122: if (CurEnv->e_from.q_paddr != NULL && ! 123: strcmp(fvalue, CurEnv->e_from.q_paddr) == 0) ! 124: return (hi->hi_flags); ! 125: } ! 126: ! 127: /* delete default value for this header */ ! 128: for (hp = &CurEnv->e_header; (h = *hp) != NULL; hp = &h->h_link) ! 129: { ! 130: if (strcmp(fname, h->h_field) == 0 && ! 131: bitset(H_DEFAULT, h->h_flags) && ! 132: !bitset(H_FORCE, h->h_flags)) ! 133: h->h_value = NULL; ! 134: } ! 135: ! 136: /* create a new node */ ! 137: h = (HDR *) xalloc(sizeof *h); ! 138: h->h_field = newstr(fname); ! 139: h->h_value = NULL; ! 140: h->h_link = NULL; ! 141: bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts); ! 142: *hp = h; ! 143: h->h_flags = hi->hi_flags; ! 144: if (def) ! 145: h->h_flags |= H_DEFAULT; ! 146: if (cond) ! 147: h->h_flags |= H_CHECK; ! 148: if (h->h_value != NULL) ! 149: free((char *) h->h_value); ! 150: h->h_value = newstr(fvalue); ! 151: ! 152: /* hack to see if this is a new format message */ ! 153: if (!def && bitset(H_RCPT|H_FROM, h->h_flags) && ! 154: (index(fvalue, ',') != NULL || index(fvalue, '(') != NULL || ! 155: index(fvalue, '<') != NULL || index(fvalue, ';') != NULL)) ! 156: { ! 157: CurEnv->e_flags &= ~EF_OLDSTYLE; ! 158: } ! 159: ! 160: return (h->h_flags); ! 161: } ! 162: /* ! 163: ** ADDHEADER -- add a header entry to the end of the queue. ! 164: ** ! 165: ** This bypasses the special checking of chompheader. ! 166: ** ! 167: ** Parameters: ! 168: ** field -- the name of the header field. ! 169: ** value -- the value of the field. It must be lower-cased. ! 170: ** e -- the envelope to add them to. ! 171: ** ! 172: ** Returns: ! 173: ** none. ! 174: ** ! 175: ** Side Effects: ! 176: ** adds the field on the list of headers for this envelope. ! 177: */ ! 178: ! 179: addheader(field, value, e) ! 180: char *field; ! 181: char *value; ! 182: ENVELOPE *e; ! 183: { ! 184: register HDR *h; ! 185: register struct hdrinfo *hi; ! 186: HDR **hp; ! 187: ! 188: /* find info struct */ ! 189: for (hi = HdrInfo; hi->hi_field != NULL; hi++) ! 190: { ! 191: if (strcmp(field, hi->hi_field) == 0) ! 192: break; ! 193: } ! 194: ! 195: /* find current place in list -- keep back pointer? */ ! 196: for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) ! 197: { ! 198: if (strcmp(field, h->h_field) == 0) ! 199: break; ! 200: } ! 201: ! 202: /* allocate space for new header */ ! 203: h = (HDR *) xalloc(sizeof *h); ! 204: h->h_field = field; ! 205: h->h_value = newstr(value); ! 206: h->h_link = *hp; ! 207: h->h_flags = hi->hi_flags | H_DEFAULT; ! 208: clrbitmap(h->h_mflags); ! 209: *hp = h; ! 210: } ! 211: /* ! 212: ** HVALUE -- return value of a header. ! 213: ** ! 214: ** Only "real" fields (i.e., ones that have not been supplied ! 215: ** as a default) are used. ! 216: ** ! 217: ** Parameters: ! 218: ** field -- the field name. ! 219: ** ! 220: ** Returns: ! 221: ** pointer to the value part. ! 222: ** NULL if not found. ! 223: ** ! 224: ** Side Effects: ! 225: ** none. ! 226: */ ! 227: ! 228: char * ! 229: hvalue(field) ! 230: char *field; ! 231: { ! 232: register HDR *h; ! 233: ! 234: for (h = CurEnv->e_header; h != NULL; h = h->h_link) ! 235: { ! 236: if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0) ! 237: return (h->h_value); ! 238: } ! 239: return (NULL); ! 240: } ! 241: /* ! 242: ** ISHEADER -- predicate telling if argument is a header. ! 243: ** ! 244: ** A line is a header if it has a single word followed by ! 245: ** optional white space followed by a colon. ! 246: ** ! 247: ** Parameters: ! 248: ** s -- string to check for possible headerness. ! 249: ** ! 250: ** Returns: ! 251: ** TRUE if s is a header. ! 252: ** FALSE otherwise. ! 253: ** ! 254: ** Side Effects: ! 255: ** none. ! 256: */ ! 257: ! 258: bool ! 259: isheader(s) ! 260: register char *s; ! 261: { ! 262: while (*s > ' ' && *s != ':' && *s != '\0') ! 263: s++; ! 264: ! 265: /* following technically violates RFC822 */ ! 266: while (isspace(*s)) ! 267: s++; ! 268: ! 269: return (*s == ':'); ! 270: } ! 271: /* ! 272: ** EATHEADER -- run through the stored header and extract info. ! 273: ** ! 274: ** Parameters: ! 275: ** e -- the envelope to process. ! 276: ** ! 277: ** Returns: ! 278: ** none. ! 279: ** ! 280: ** Side Effects: ! 281: ** Sets a bunch of global variables from information ! 282: ** in the collected header. ! 283: ** Aborts the message if the hop count is exceeded. ! 284: */ ! 285: ! 286: eatheader(e) ! 287: register ENVELOPE *e; ! 288: { ! 289: register HDR *h; ! 290: register char *p; ! 291: int hopcnt = 0; ! 292: ! 293: if (tTd(32, 1)) ! 294: printf("----- collected header -----\n"); ! 295: for (h = e->e_header; h != NULL; h = h->h_link) ! 296: { ! 297: extern char *capitalize(); ! 298: ! 299: if (tTd(32, 1)) ! 300: printf("%s: %s\n", capitalize(h->h_field), h->h_value); ! 301: /* count the number of times it has been processed */ ! 302: if (bitset(H_TRACE, h->h_flags)) ! 303: hopcnt++; ! 304: ! 305: /* send to this person if we so desire */ ! 306: if (GrabTo && bitset(H_RCPT, h->h_flags) && ! 307: !bitset(H_DEFAULT, h->h_flags) && ! 308: (!bitset(EF_RESENT, CurEnv->e_flags) || bitset(H_RESENT, h->h_flags))) ! 309: { ! 310: sendtolist(h->h_value, (ADDRESS *) NULL, &CurEnv->e_sendqueue); ! 311: } ! 312: ! 313: /* log the message-id */ ! 314: #ifdef LOG ! 315: if (!QueueRun && LogLevel > 8 && h->h_value != NULL && ! 316: strcmp(h->h_field, "message-id") == 0) ! 317: { ! 318: char buf[MAXNAME]; ! 319: ! 320: p = h->h_value; ! 321: if (bitset(H_DEFAULT, h->h_flags)) ! 322: { ! 323: expand(p, buf, &buf[sizeof buf], e); ! 324: p = buf; ! 325: } ! 326: syslog(LOG_INFO, "%s: message-id=%s", e->e_id, p); ! 327: } ! 328: #endif LOG ! 329: } ! 330: if (tTd(32, 1)) ! 331: printf("----------------------------\n"); ! 332: ! 333: /* store hop count */ ! 334: if (hopcnt > e->e_hopcount) ! 335: e->e_hopcount = hopcnt; ! 336: ! 337: /* message priority */ ! 338: p = hvalue("precedence"); ! 339: if (p != NULL) ! 340: e->e_class = priencode(p); ! 341: if (!QueueRun) ! 342: e->e_msgpriority = e->e_msgsize ! 343: - e->e_class * WkClassFact ! 344: + e->e_nrcpts * WkRecipFact; ! 345: ! 346: /* return receipt to */ ! 347: p = hvalue("return-receipt-to"); ! 348: if (p != NULL) ! 349: e->e_receiptto = p; ! 350: ! 351: /* errors to */ ! 352: p = hvalue("errors-to"); ! 353: if (p != NULL) ! 354: sendtolist(p, (ADDRESS *) NULL, &e->e_errorqueue); ! 355: ! 356: /* from person */ ! 357: if (OpMode == MD_ARPAFTP) ! 358: { ! 359: register struct hdrinfo *hi = HdrInfo; ! 360: ! 361: for (p = NULL; p == NULL && hi->hi_field != NULL; hi++) ! 362: { ! 363: if (bitset(H_FROM, hi->hi_flags)) ! 364: p = hvalue(hi->hi_field); ! 365: } ! 366: if (p != NULL) ! 367: setsender(p); ! 368: } ! 369: ! 370: /* full name of from person */ ! 371: p = hvalue("full-name"); ! 372: if (p != NULL) ! 373: define('x', p, e); ! 374: ! 375: /* date message originated */ ! 376: p = hvalue("posted-date"); ! 377: if (p == NULL) ! 378: p = hvalue("date"); ! 379: if (p != NULL) ! 380: { ! 381: define('a', p, e); ! 382: /* we don't have a good way to do canonical conversion .... ! 383: define('d', newstr(arpatounix(p)), e); ! 384: .... so we will ignore the problem for the time being */ ! 385: } ! 386: ! 387: /* ! 388: ** Log collection information. ! 389: */ ! 390: ! 391: # ifdef LOG ! 392: if (!QueueRun && LogLevel > 1) ! 393: { ! 394: char hbuf[100], *name = hbuf; ! 395: ! 396: if (RealHostName == NULL) ! 397: name = "local"; ! 398: else if (RealHostName[0] == '[') ! 399: name = RealHostName; ! 400: else ! 401: (void)sprintf(hbuf, "%.90s (%s)", ! 402: RealHostName, inet_ntoa(RealHostAddr.sin_addr)); ! 403: syslog(LOG_INFO, ! 404: "%s: from=%s, size=%ld, class=%d, received from %s\n", ! 405: CurEnv->e_id, CurEnv->e_from.q_paddr, CurEnv->e_msgsize, ! 406: CurEnv->e_class, name); ! 407: } ! 408: # endif LOG ! 409: } ! 410: /* ! 411: ** PRIENCODE -- encode external priority names into internal values. ! 412: ** ! 413: ** Parameters: ! 414: ** p -- priority in ascii. ! 415: ** ! 416: ** Returns: ! 417: ** priority as a numeric level. ! 418: ** ! 419: ** Side Effects: ! 420: ** none. ! 421: */ ! 422: ! 423: priencode(p) ! 424: char *p; ! 425: { ! 426: register int i; ! 427: ! 428: for (i = 0; i < NumPriorities; i++) ! 429: { ! 430: if (!strcasecmp(p, Priorities[i].pri_name)) ! 431: return (Priorities[i].pri_val); ! 432: } ! 433: ! 434: /* unknown priority */ ! 435: return (0); ! 436: } ! 437: /* ! 438: ** CRACKADDR -- parse an address and turn it into a macro ! 439: ** ! 440: ** This doesn't actually parse the address -- it just extracts ! 441: ** it and replaces it with "$g". The parse is totally ad hoc ! 442: ** and isn't even guaranteed to leave something syntactically ! 443: ** identical to what it started with. However, it does leave ! 444: ** something semantically identical. ! 445: ** ! 446: ** The process is kind of strange. There are a number of ! 447: ** interesting cases: ! 448: ** 1. comment <address> comment ==> comment <$g> comment ! 449: ** 2. address ==> address ! 450: ** 3. address (comment) ==> $g (comment) ! 451: ** 4. (comment) address ==> (comment) $g ! 452: ** And then there are the hard cases.... ! 453: ** 5. add (comment) ress ==> $g (comment) ! 454: ** 6. comment <address (comment)> ==> comment <$g (comment)> ! 455: ** 7. .... etc .... ! 456: ** ! 457: ** Parameters: ! 458: ** addr -- the address to be cracked. ! 459: ** ! 460: ** Returns: ! 461: ** a pointer to the new version. ! 462: ** ! 463: ** Side Effects: ! 464: ** none. ! 465: ** ! 466: ** Warning: ! 467: ** The return value is saved in local storage and should ! 468: ** be copied if it is to be reused. ! 469: */ ! 470: ! 471: char * ! 472: crackaddr(addr) ! 473: register char *addr; ! 474: { ! 475: register char *p; ! 476: register int i; ! 477: static char buf[MAXNAME]; ! 478: char *rhs; ! 479: bool gotaddr; ! 480: register char *bp; ! 481: ! 482: if (tTd(33, 1)) ! 483: printf("crackaddr(%s)\n", addr); ! 484: ! 485: (void) strcpy(buf, ""); ! 486: rhs = NULL; ! 487: ! 488: /* strip leading spaces */ ! 489: while (*addr != '\0' && isspace(*addr)) ! 490: addr++; ! 491: ! 492: /* ! 493: ** See if we have anything in angle brackets. If so, that is ! 494: ** the address part, and the rest is the comment. ! 495: */ ! 496: ! 497: p = index(addr, '<'); ! 498: if (p != NULL) ! 499: { ! 500: /* copy the beginning of the addr field to the buffer */ ! 501: *p = '\0'; ! 502: (void) strcpy(buf, addr); ! 503: (void) strcat(buf, "<"); ! 504: *p++ = '<'; ! 505: ! 506: /* skip spaces */ ! 507: while (isspace(*p)) ! 508: p++; ! 509: ! 510: /* find the matching right angle bracket */ ! 511: addr = p; ! 512: for (i = 0; *p != '\0'; p++) ! 513: { ! 514: switch (*p) ! 515: { ! 516: case '<': ! 517: i++; ! 518: break; ! 519: ! 520: case '>': ! 521: i--; ! 522: break; ! 523: } ! 524: if (i < 0) ! 525: break; ! 526: } ! 527: ! 528: /* p now points to the closing quote (or a null byte) */ ! 529: if (*p != '\0') ! 530: { ! 531: /* make rhs point to the extra stuff at the end */ ! 532: rhs = p; ! 533: *p++ = '\0'; ! 534: } ! 535: } ! 536: ! 537: /* ! 538: ** Now parse the real address part. "addr" points to the (null ! 539: ** terminated) version of what we are inerested in; rhs points ! 540: ** to the extra stuff at the end of the line, if any. ! 541: */ ! 542: ! 543: p = addr; ! 544: ! 545: /* now strip out comments */ ! 546: bp = &buf[strlen(buf)]; ! 547: gotaddr = FALSE; ! 548: for (; *p != '\0'; p++) ! 549: { ! 550: if (*p == '(') ! 551: { ! 552: /* copy to matching close paren */ ! 553: *bp++ = *p++; ! 554: for (i = 0; *p != '\0'; p++) ! 555: { ! 556: *bp++ = *p; ! 557: switch (*p) ! 558: { ! 559: case '(': ! 560: i++; ! 561: break; ! 562: ! 563: case ')': ! 564: i--; ! 565: break; ! 566: } ! 567: if (i < 0) ! 568: break; ! 569: } ! 570: continue; ! 571: } ! 572: ! 573: /* ! 574: ** If this is the first "real" character we have seen, ! 575: ** then we put the "$g" in the buffer now. ! 576: */ ! 577: ! 578: if (isspace(*p)) ! 579: *bp++ = *p; ! 580: else if (!gotaddr) ! 581: { ! 582: (void) strcpy(bp, "\001g"); ! 583: bp += 2; ! 584: gotaddr = TRUE; ! 585: } ! 586: } ! 587: ! 588: /* hack, hack.... strip trailing blanks */ ! 589: do ! 590: { ! 591: *bp-- = '\0'; ! 592: } while (isspace(*bp)); ! 593: bp++; ! 594: ! 595: /* put any right hand side back on */ ! 596: if (rhs != NULL) ! 597: { ! 598: *rhs = '>'; ! 599: (void) strcpy(bp, rhs); ! 600: } ! 601: ! 602: if (tTd(33, 1)) ! 603: printf("crackaddr=>`%s'\n", buf); ! 604: ! 605: return (buf); ! 606: } ! 607: /* ! 608: ** PUTHEADER -- put the header part of a message from the in-core copy ! 609: ** ! 610: ** Parameters: ! 611: ** fp -- file to put it on. ! 612: ** m -- mailer to use. ! 613: ** e -- envelope to use. ! 614: ** ! 615: ** Returns: ! 616: ** none. ! 617: ** ! 618: ** Side Effects: ! 619: ** none. ! 620: */ ! 621: ! 622: putheader(fp, m, e) ! 623: register FILE *fp; ! 624: register MAILER *m; ! 625: register ENVELOPE *e; ! 626: { ! 627: char buf[MAX(MAXFIELD,BUFSIZ)]; ! 628: register HDR *h; ! 629: extern char *arpadate(); ! 630: extern char *capitalize(); ! 631: char obuf[MAX(MAXFIELD,MAXLINE)]; ! 632: ! 633: for (h = e->e_header; h != NULL; h = h->h_link) ! 634: { ! 635: register char *p; ! 636: extern bool bitintersect(); ! 637: ! 638: if (bitset(H_CHECK|H_ACHECK, h->h_flags) && ! 639: !bitintersect(h->h_mflags, m->m_flags)) ! 640: continue; ! 641: ! 642: /* handle Resent-... headers specially */ ! 643: if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) ! 644: continue; ! 645: ! 646: p = h->h_value; ! 647: if (bitset(H_DEFAULT, h->h_flags)) ! 648: { ! 649: /* macro expand value if generated internally */ ! 650: expand(p, buf, &buf[sizeof buf], e); ! 651: p = buf; ! 652: if (p == NULL || *p == '\0') ! 653: continue; ! 654: } ! 655: ! 656: if (bitset(H_FROM|H_RCPT, h->h_flags)) ! 657: { ! 658: /* address field */ ! 659: bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); ! 660: ! 661: if (bitset(H_FROM, h->h_flags)) ! 662: oldstyle = FALSE; ! 663: commaize(h, p, fp, oldstyle, m); ! 664: } ! 665: else ! 666: { ! 667: /* vanilla header line */ ! 668: register char *nlp; ! 669: ! 670: (void) sprintf(obuf, "%s: ", capitalize(h->h_field)); ! 671: while ((nlp = index(p, '\n')) != NULL) ! 672: { ! 673: *nlp = '\0'; ! 674: (void) strcat(obuf, p); ! 675: *nlp = '\n'; ! 676: putline(obuf, fp, m); ! 677: p = ++nlp; ! 678: obuf[0] = '\0'; ! 679: } ! 680: (void) strcat(obuf, p); ! 681: putline(obuf, fp, m); ! 682: } ! 683: } ! 684: } ! 685: /* ! 686: ** COMMAIZE -- output a header field, making a comma-translated list. ! 687: ** ! 688: ** Parameters: ! 689: ** h -- the header field to output. ! 690: ** p -- the value to put in it. ! 691: ** fp -- file to put it to. ! 692: ** oldstyle -- TRUE if this is an old style header. ! 693: ** m -- a pointer to the mailer descriptor. If NULL, ! 694: ** don't transform the name at all. ! 695: ** ! 696: ** Returns: ! 697: ** none. ! 698: ** ! 699: ** Side Effects: ! 700: ** outputs "p" to file "fp". ! 701: */ ! 702: ! 703: commaize(h, p, fp, oldstyle, m) ! 704: register HDR *h; ! 705: register char *p; ! 706: FILE *fp; ! 707: bool oldstyle; ! 708: register MAILER *m; ! 709: { ! 710: register char *obp; ! 711: int opos; ! 712: bool firstone = TRUE; ! 713: char obuf[MAXLINE + 3]; ! 714: ! 715: /* ! 716: ** Output the address list translated by the ! 717: ** mailer and with commas. ! 718: */ ! 719: ! 720: if (tTd(14, 2)) ! 721: printf("commaize(%s: %s)\n", h->h_field, p); ! 722: ! 723: obp = obuf; ! 724: (void) sprintf(obp, "%s: ", capitalize(h->h_field)); ! 725: opos = strlen(h->h_field) + 2; ! 726: obp += opos; ! 727: ! 728: /* ! 729: ** Run through the list of values. ! 730: */ ! 731: ! 732: while (*p != '\0') ! 733: { ! 734: register char *name; ! 735: char savechar; ! 736: extern char *remotename(); ! 737: extern char *DelimChar; /* defined in prescan */ ! 738: ! 739: /* ! 740: ** Find the end of the name. New style names ! 741: ** end with a comma, old style names end with ! 742: ** a space character. However, spaces do not ! 743: ** necessarily delimit an old-style name -- at ! 744: ** signs mean keep going. ! 745: */ ! 746: ! 747: /* find end of name */ ! 748: while (isspace(*p) || *p == ',') ! 749: p++; ! 750: name = p; ! 751: for (;;) ! 752: { ! 753: char *oldp; ! 754: char pvpbuf[PSBUFSIZE]; ! 755: extern bool isatword(); ! 756: extern char **prescan(); ! 757: ! 758: (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf); ! 759: p = DelimChar; ! 760: ! 761: /* look to see if we have an at sign */ ! 762: oldp = p; ! 763: while (*p != '\0' && isspace(*p)) ! 764: p++; ! 765: ! 766: if (*p != '@' && !isatword(p)) ! 767: { ! 768: p = oldp; ! 769: break; ! 770: } ! 771: p += *p == '@' ? 1 : 2; ! 772: while (*p != '\0' && isspace(*p)) ! 773: p++; ! 774: } ! 775: /* at the end of one complete name */ ! 776: ! 777: /* strip off trailing white space */ ! 778: while (p >= name && (isspace(*p) || *p == ',' || *p == '\0')) ! 779: p--; ! 780: if (++p == name) ! 781: continue; ! 782: savechar = *p; ! 783: *p = '\0'; ! 784: ! 785: /* translate the name to be relative */ ! 786: name = remotename(name, m, bitset(H_FROM, h->h_flags), FALSE); ! 787: if (*name == '\0') ! 788: { ! 789: *p = savechar; ! 790: continue; ! 791: } ! 792: ! 793: /* output the name with nice formatting */ ! 794: opos += qstrlen(name); ! 795: if (!firstone) ! 796: opos += 2; ! 797: if (opos > 78 && !firstone) ! 798: { ! 799: (void) strcpy(obp, ",\n"); ! 800: putline(obuf, fp, m); ! 801: obp = obuf; ! 802: (void) sprintf(obp, " "); ! 803: opos = strlen(obp); ! 804: obp += opos; ! 805: opos += qstrlen(name); ! 806: } ! 807: else if (!firstone) ! 808: { ! 809: (void) sprintf(obp, ", "); ! 810: obp += 2; ! 811: } ! 812: ! 813: /* strip off quote bits as we output */ ! 814: while (*name != '\0' && obp < &obuf[MAXLINE]) ! 815: { ! 816: if (bitset(0200, *name)) ! 817: *obp++ = '\\'; ! 818: *obp++ = *name++ & ~0200; ! 819: } ! 820: firstone = FALSE; ! 821: *p = savechar; ! 822: } ! 823: (void) strcpy(obp, "\n"); ! 824: putline(obuf, fp, m); ! 825: } ! 826: /* ! 827: ** ISATWORD -- tell if the word we are pointing to is "at". ! 828: ** ! 829: ** Parameters: ! 830: ** p -- word to check. ! 831: ** ! 832: ** Returns: ! 833: ** TRUE -- if p is the word at. ! 834: ** FALSE -- otherwise. ! 835: ** ! 836: ** Side Effects: ! 837: ** none. ! 838: */ ! 839: ! 840: bool ! 841: isatword(p) ! 842: register char *p; ! 843: { ! 844: extern char lower(); ! 845: ! 846: if (lower(p[0]) == 'a' && lower(p[1]) == 't' && ! 847: p[2] != '\0' && isspace(p[2])) ! 848: return (TRUE); ! 849: return (FALSE); ! 850: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.