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