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