|
|
1.1 ! root 1: /* ! 2: ** message spooing, header and address parsing and completion ! 3: ** functions for smail/rmail ! 4: */ ! 5: ! 6: #ifndef lint ! 7: static char *sccsid="@(#)headers.c 2.5 (smail) 9/15/87"; ! 8: #endif ! 9: ! 10: # include <stdio.h> ! 11: # include <sys/types.h> ! 12: # include <time.h> ! 13: # include <ctype.h> ! 14: # include <pwd.h> ! 15: # include "defs.h" ! 16: ! 17: extern enum edebug debug; /* how verbose we are */ ! 18: extern char hostname[]; /* */ ! 19: extern char hostdomain[]; /* */ ! 20: extern char *spoolfile; /* file name of spooled message */ ! 21: extern FILE *spoolfp; /* file ptr to spooled message */ ! 22: extern int spoolmaster; /* set if creator of spoolfile */ ! 23: extern time_t now; /* time */ ! 24: extern char nows[], arpanows[]; /* time strings */ ! 25: extern struct tm *gmt, *loc; /* time structs */ ! 26: extern char *from_addr; /* replacement fromaddr with -F */ ! 27: ! 28: static char toline[SMLBUF]; ! 29: static char fromline[SMLBUF]; ! 30: static char dateline[SMLBUF]; ! 31: static char midline[SMLBUF]; ! 32: static char *ieof = "NOTNULL"; ! 33: ! 34: struct reqheaders { ! 35: char *name; ! 36: char *field; ! 37: char have; ! 38: }; ! 39: ! 40: static struct reqheaders reqtab[] = { ! 41: "Message-Id:" , midline , 'N' , ! 42: "Date:" , dateline , 'N' , ! 43: "From:" , fromline , 'N' , ! 44: "To:" , toline , 'N' , ! 45: NULL , NULL , 'N' ! 46: }; ! 47: ! 48: ! 49: /* ! 50: ** ! 51: ** parse(): parse <address> into <domain, user, form>. ! 52: ** ! 53: ** input form ! 54: ** ----- ---- ! 55: ** user LOCAL ! 56: ** domain!user DOMAIN ! 57: ** user@domain DOMAIN ! 58: ** @domain,address LOCAL (just for sendmail) ! 59: ** host!address UUCP ! 60: ** ! 61: */ ! 62: ! 63: enum eform ! 64: parse(address, domain, user) ! 65: char *address; /* input address */ ! 66: char *domain; /* output domain */ ! 67: char *user; /* output user */ ! 68: { ! 69: int parts; ! 70: char *partv[MAXPATH]; /* to crack address */ ! 71: ! 72: /* ! 73: ** If this is route address form @domain_a,@domain_b:user@domain_c, ... ! 74: */ ! 75: if(*address == '@') ! 76: #ifdef SENDMAIL ! 77: /* ! 78: ** hand it to sendmail ! 79: */ ! 80: { ! 81: goto local; ! 82: } ! 83: #else ! 84: /* ! 85: ** no sendmail, convert it into a bang path: domain_a!domain_b!domain_c!user ! 86: */ ! 87: { ! 88: char buf[SMLBUF], *p; ! 89: char t_dom[SMLBUF], t_user[SMLBUF]; ! 90: ! 91: (void) strcpy(buf, address+1); /* elide leading '@' */ ! 92: ! 93: for(p=buf; *p != '\0' ; p++) { /* search for ',' or ':' */ ! 94: if(*p == ':') { /* reached end of route */ ! 95: break; ! 96: } ! 97: if(*p == ',') { /* elide ','s */ ! 98: (void) strcpy(p, p+1); ! 99: } ! 100: if(*p == '@') { /* convert '@' to '!' */ ! 101: *p = '!'; ! 102: } ! 103: } ! 104: ! 105: if(*p != ':') { /* bad syntax - punt */ ! 106: goto local; ! 107: } ! 108: *p = '\0'; ! 109: ! 110: if(parse(p+1, t_dom, t_user) != LOCAL) { ! 111: (void) strcat(buf, "!"); ! 112: (void) strcat(buf, t_dom); ! 113: } ! 114: (void) strcat(buf, "!"); ! 115: (void) strcat(buf, t_user); ! 116: ! 117: /* munge the address (yuk) ! 118: ** it's OK to copy into 'address', because the machinations ! 119: ** above don't increase the string length of the address. ! 120: */ ! 121: ! 122: (void) strcpy(address, buf); ! 123: ! 124: /* re-parse the address */ ! 125: return(parse(address, domain, user)); ! 126: } ! 127: #endif ! 128: /* ! 129: ** Try splitting at @. If it works, this is user@domain, form DOMAIN. ! 130: ** Prefer the righthand @ in a@b@c. ! 131: */ ! 132: if ((parts = ssplit(address, '@', partv)) >= 2) { ! 133: (void) strcpy(domain, partv[parts-1]); ! 134: (void) strncpy(user, partv[0], partv[parts-1]-partv[0]-1); ! 135: user[partv[parts-1]-partv[0]-1] = '\0'; ! 136: return (DOMAIN); ! 137: } ! 138: /* ! 139: ** Try splitting at !. If it works, see if the piece before the ! has ! 140: ** a . in it (domain!user, form DOMAIN) or not (host!user, form UUCP). ! 141: */ ! 142: if (ssplit(address, '!', partv) > 1) { ! 143: (void) strcpy(user, partv[1]); ! 144: (void) strncpy(domain, partv[0], partv[1]-partv[0]-1); ! 145: domain[partv[1]-partv[0]-1] = '\0'; ! 146: ! 147: if((parts = ssplit(domain, '.', partv)) < 2) { ! 148: return(UUCP); ! 149: } ! 150: ! 151: if(partv[parts-1][0] == '\0') { ! 152: partv[parts-1][-1] = '\0'; /* strip trailing . */ ! 153: } ! 154: return (DOMAIN); ! 155: } ! 156: /* ! 157: ** Done trying. This must be just a user name, form LOCAL. ! 158: */ ! 159: local: ! 160: (void) strcpy(user, address); ! 161: (void) strcpy(domain, ""); ! 162: return(LOCAL); /* user */ ! 163: } ! 164: ! 165: build(domain, user, form, result) ! 166: char *domain; ! 167: char *user; ! 168: enum eform form; ! 169: char *result; ! 170: { ! 171: switch((int) form) { ! 172: case LOCAL: ! 173: (void) sprintf(result, "%s", user); ! 174: break; ! 175: case UUCP: ! 176: (void) sprintf(result, "%s!%s", domain, user); ! 177: break; ! 178: case DOMAIN: ! 179: (void) sprintf(result, "%s@%s", user, domain); ! 180: break; ! 181: } ! 182: } ! 183: ! 184: /* ! 185: ** ssplit(): split a line into array pointers. ! 186: ** ! 187: ** Each pointer wordv[i] points to the first character after the i'th ! 188: ** occurence of c in buf. Note that each wordv[i] includes wordv[i+1]. ! 189: ** ! 190: */ ! 191: ! 192: ssplit(buf, c, ptr) ! 193: register char *buf; /* line to split up */ ! 194: char c; /* character to split on */ ! 195: char **ptr; /* the resultant vector */ ! 196: { ! 197: int count = 0; ! 198: int wasword = 0; ! 199: ! 200: for(; *buf; buf++) { ! 201: if (!wasword) { ! 202: count++; ! 203: *ptr++ = buf; ! 204: } ! 205: wasword = (c != *buf); ! 206: } ! 207: if (!wasword) { ! 208: count++; ! 209: *ptr++ = buf; ! 210: } ! 211: *ptr = NULL; ! 212: return(count); ! 213: } ! 214: ! 215: /* ! 216: ** Determine whether an address is a local address ! 217: */ ! 218: ! 219: islocal(addr, domain, user) ! 220: char *addr, *domain, *user; ! 221: { ! 222: enum eform form, parse(); ! 223: extern char hostuucp[]; ! 224: ! 225: /* ! 226: ** parse the address ! 227: */ ! 228: ! 229: form = parse(addr, domain, user); ! 230: ! 231: if((form == LOCAL) /* user */ ! 232: ||(strcmpic(domain, hostdomain) == 0) /* user@hostdomain */ ! 233: ||(strcmpic(domain, hostname) == 0) /* user@hostname */ ! 234: #ifdef DOMGATE ! 235: ||(strcmpic(domain, &MYDOM[0]) == 0) /* user@MYDOM w/ dot */ ! 236: ||(strcmpic(domain, &MYDOM[1]) == 0) /* user@MYDOM no dot */ ! 237: #endif ! 238: ||(strcmpic(domain, hostuucp) == 0)) {/* user@hostuucp */ ! 239: return(1); ! 240: } ! 241: return(0); ! 242: } ! 243: ! 244: /* ! 245: ** spool - message spooling module ! 246: ** ! 247: ** (1) get dates for headers, etc. ! 248: ** (2) if the message is on the standard input (no '-f') ! 249: ** (a) create a temp file for spooling the message. ! 250: ** (b) collapse the From_ headers into a path. ! 251: ** (c) if the mail originated locally, then ! 252: ** (i) establish default headers ! 253: ** (ii) scan the message headers for required header fields ! 254: ** (iii) add any required message headers that are absent ! 255: ** (d) copy rest of the message to the spool file ! 256: ** (e) close the spool file ! 257: ** (3) open the spool file for reading ! 258: */ ! 259: ! 260: void ! 261: spool(argc, argv) ! 262: int argc; ! 263: char **argv; ! 264: { ! 265: static char *tmpf = "/tmp/rmXXXXXX"; /* temp file name */ ! 266: char *mktemp(); ! 267: char buf[SMLBUF]; ! 268: static char splbuf[SMLBUF]; ! 269: char from[SMLBUF], domain[SMLBUF], user[SMLBUF]; ! 270: void rline(), scanheaders(), compheaders(); ! 271: ! 272: /* ! 273: ** if the mail has already been spooled by ! 274: ** a previous invocation of smail don't respool. ! 275: ** check the file name to prevent things like ! 276: ** rmail -f /etc/passwd badguy@dreadfuldomain ! 277: */ ! 278: ! 279: if((spoolfile != NULL) ! 280: && (strncmp(spoolfile, tmpf, strlen(tmpf) - 6) != 0)) { ! 281: error(EX_TEMPFAIL, "spool: bad file name '%s'\n", spoolfile); ! 282: } ! 283: ! 284: /* ! 285: ** set dates in local, arpa, and gmt forms ! 286: */ ! 287: setdates(); ! 288: ! 289: /* ! 290: ** If necessary, copy stdin to a temp file. ! 291: */ ! 292: ! 293: if(spoolfile == NULL) { ! 294: spoolfile = strcpy(splbuf, tmpf); ! 295: (void) mktemp(spoolfile); ! 296: ! 297: if((spoolfp = fopen(spoolfile, "w")) == NULL) { ! 298: error(EX_CANTCREAT, "can't create %s.\n", spoolfile); ! 299: } ! 300: ! 301: spoolmaster = 1; ! 302: ! 303: /* ! 304: ** rline reads the standard input, ! 305: ** collapsing the From_ and >From_ ! 306: ** lines into a single uucp path. ! 307: ** first non-from_ line is in buf[]; ! 308: */ ! 309: ! 310: rline(from, buf); ! 311: ! 312: /* ! 313: ** if the mail originated here, we parse the header ! 314: ** and add any required headers that are missing. ! 315: */ ! 316: ! 317: if(islocal(from, domain, user) || (from_addr != NULL)) { ! 318: /* ! 319: ** initialize default headers ! 320: */ ! 321: def_headers(argc, argv, from); ! 322: ! 323: /* ! 324: ** buf has first, non-from_ line ! 325: */ ! 326: scanheaders(buf); ! 327: /* ! 328: ** buf has first, non-header line, ! 329: */ ! 330: ! 331: compheaders(); ! 332: ! 333: if(buf[0] != '\n') { ! 334: (void) fputs("\n", spoolfp); ! 335: fflush(spoolfp); ! 336: } ! 337: } ! 338: ! 339: /* ! 340: ** now, copy the rest of the letter into the spool file ! 341: ** terminate on either EOF or '^.$' ! 342: */ ! 343: ! 344: while(ieof != NULL) { ! 345: (void) fputs(buf, spoolfp); ! 346: fflush(spoolfp); ! 347: if((fgets(buf, SMLBUF, stdin) == NULL) ! 348: || (buf[0] == '.' && buf[1] == '\n')) { ! 349: ieof = NULL; ! 350: } ! 351: } ! 352: ! 353: /* ! 354: ** close the spool file, and the standard input. ! 355: */ ! 356: ! 357: (void) fclose(spoolfp); ! 358: (void) fclose(stdin); /* you don't see this too often! */ ! 359: } ! 360: ! 361: if((spoolfp = fopen(spoolfile, "r")) == NULL) { ! 362: error(EX_TEMPFAIL, "can't open %s.\n", spoolfile); ! 363: } ! 364: } ! 365: ! 366: /* ! 367: ** ! 368: ** rline(): collapse From_ and >From_ lines. ! 369: ** ! 370: ** Same idea as the old rmail, but also turns user@domain to domain!user. ! 371: ** ! 372: */ ! 373: ! 374: void ! 375: rline(from, retbuf) ! 376: char *from; ! 377: char *retbuf; ! 378: { ! 379: int parts; /* for cracking From_ lines ... */ ! 380: char *partv[16]; /* ... apart using ssplit() */ ! 381: char user[SMLBUF]; /* for rewriting user@host */ ! 382: char domain[SMLBUF]; /* " " " */ ! 383: char addr[SMLBUF]; /* " " " */ ! 384: enum eform form, parse(); /* " " " */ ! 385: extern build(); /* " " " */ ! 386: char *c; ! 387: int nhops, i; ! 388: char buf[SMLBUF], tmp[SMLBUF], *hop[128], *e, *b; ! 389: char *pwuid(); ! 390: ! 391: if(spoolmaster == 0) return; ! 392: ! 393: buf[0] = from[0] = addr[0] = '\0'; ! 394: /* ! 395: ** Read each line until we hit EOF or a line not beginning with "From " ! 396: ** or ">From " (called From_ lines), accumulating the new path in from ! 397: ** and stuffing the actual sending user (the user name on the last From_ ! 398: ** line) in addr. ! 399: */ ! 400: for(;;) { ! 401: (void) strcpy(retbuf, buf); ! 402: if(ieof == NULL) { ! 403: break; ! 404: } ! 405: if((fgets(buf, sizeof(buf), stdin) == NULL) ! 406: || (buf[0] == '.' && buf[1] == '\n')) { ! 407: ieof = NULL; ! 408: break; ! 409: } ! 410: if (strncmp("From ", buf, 5) ! 411: && strncmp(">From ", buf, 6)) { ! 412: break; ! 413: } ! 414: /* ! 415: ** Crack the line apart using ssplit. ! 416: */ ! 417: if(c = index(buf, '\n')) { ! 418: *c = '\0'; ! 419: } ! 420: parts = ssplit(buf, ' ', partv); ! 421: /* ! 422: ** Tack host! onto the from argument if "remote from host" is present. ! 423: */ ! 424: ! 425: if((parts > 3) ! 426: && (strncmp("remote from ", partv[parts-3], 12) == 0)) { ! 427: (void) strcat(from, partv[parts-1]); ! 428: (void) strcat(from, "!"); ! 429: } ! 430: /* ! 431: ** Stuff user name into addr, overwriting the user name from previous ! 432: ** From_ lines, since only the last one counts. Then rewrite user@host ! 433: ** into host!user, since @'s don't belong in the From_ argument. ! 434: */ ! 435: if(parts < 2) { ! 436: break; ! 437: } else { ! 438: char *x = partv[1]; ! 439: char *q = index(x, ' '); ! 440: if(q != NULL) { ! 441: *q = '\0'; ! 442: } ! 443: (void) strcpy(addr, x); ! 444: } ! 445: ! 446: (void) parse(addr, domain, user); ! 447: if(*domain == '\0') { ! 448: form = LOCAL; ! 449: } else { ! 450: form = UUCP; ! 451: } ! 452: ! 453: build(domain, user, form, addr); ! 454: } ! 455: /* ! 456: ** Now tack the user name onto the from argument. ! 457: */ ! 458: (void) strcat(from, addr); ! 459: /* ! 460: ** If we still have no from argument, we have junk headers, but we try ! 461: ** to get the user's name using /etc/passwd. ! 462: */ ! 463: ! 464: if (from[0] == '\0') { ! 465: char *login; ! 466: if ((login = pwuid(getuid())) == NULL) { ! 467: (void) strcpy(from, "nobody"); /* bad news */ ! 468: } else { ! 469: (void) strcpy(from, login); ! 470: } ! 471: } ! 472: ! 473: /* split the from line on '!'s */ ! 474: nhops = ssplit(from, '!', hop); ! 475: ! 476: for(i = 0; i < (nhops - 1); i++) { ! 477: b = hop[i]; ! 478: if(*b == '\0') { ! 479: continue; ! 480: } ! 481: e = hop[i+1]; ! 482: e-- ; ! 483: *e = '\0'; /* null terminate each path segment */ ! 484: e++; ! 485: ! 486: #ifdef HIDDENHOSTS ! 487: /* ! 488: ** Strip hidden hosts: anything.hostname.MYDOM -> hostname.MYDOM ! 489: */ ! 490: for(p = b;(p = index(p, '.')) != NULL; p++) { ! 491: if(strcmpic(hostdomain, p+1) == 0) { ! 492: (void) strcpy(b, hostdomain); ! 493: break; ! 494: } ! 495: } ! 496: #endif ! 497: ! 498: /* ! 499: ** Strip useless MYDOM: hostname.MYDOM -> hostname ! 500: */ ! 501: if(strcmpic(hop[i], hostdomain) == 0) { ! 502: (void) strcpy(hop[i], hostname); ! 503: } ! 504: } ! 505: ! 506: /* ! 507: ** Now strip out any redundant information in the From_ line ! 508: ** a!b!c!c!d => a!b!c!d ! 509: */ ! 510: ! 511: for(i = 0; i < (nhops - 2); i++) { ! 512: b = hop[i]; ! 513: e = hop[i+1]; ! 514: if(strcmpic(b, e) == 0) { ! 515: *b = '\0'; ! 516: } ! 517: } ! 518: /* ! 519: ** Reconstruct the From_ line ! 520: */ ! 521: tmp[0] = '\0'; /* empty the tmp buffer */ ! 522: ! 523: for(i = 0; i < (nhops - 1); i++) { ! 524: if((hop[i][0] == '\0') /* deleted this hop */ ! 525: ||((tmp[0] == '\0') /* first hop == hostname */ ! 526: &&(strcmpic(hop[i], hostname) == 0))) { ! 527: continue; ! 528: } ! 529: (void) strcat(tmp, hop[i]); ! 530: (void) strcat(tmp, "!"); ! 531: } ! 532: (void) strcat(tmp, hop[i]); ! 533: (void) strcpy(from, tmp); ! 534: (void) strcpy(retbuf, buf); ! 535: (void) fprintf(spoolfp, "%s\n", from); ! 536: } ! 537: ! 538: void ! 539: scanheaders(buf) ! 540: char *buf; ! 541: { ! 542: int inheader = 0; ! 543: ! 544: while(ieof != NULL) { ! 545: if(buf[0] == '\n') { ! 546: break; /* end of headers */ ! 547: } ! 548: ! 549: /* ! 550: ** header lines which begin with whitespace ! 551: ** are continuation lines ! 552: */ ! 553: if((inheader == 0) ! 554: || ((buf[0] != ' ' && buf[0] != '\t'))) { ! 555: /* not a continuation line ! 556: ** check for header ! 557: */ ! 558: if(isheader(buf) == 0) { ! 559: /* ! 560: ** not a header ! 561: */ ! 562: break; ! 563: } ! 564: inheader = 1; ! 565: haveheaders(buf); ! 566: } ! 567: (void) fputs(buf, spoolfp); ! 568: fflush(spoolfp); ! 569: if((fgets(buf, SMLBUF, stdin) == NULL) ! 570: || (buf[0] == '.' && buf[1] == '\n')) { ! 571: ieof = NULL; ! 572: } ! 573: } ! 574: ! 575: if(isheader(buf)) { ! 576: buf[0] = '\0'; ! 577: } ! 578: } ! 579: ! 580: /* ! 581: ** complete headers - add any required headers that are not in the message ! 582: */ ! 583: void ! 584: compheaders() ! 585: { ! 586: struct reqheaders *i; ! 587: ! 588: /* ! 589: ** look at the table of required headers and ! 590: ** add those that are missing to the spooled message. ! 591: */ ! 592: for(i = reqtab; i->name != NULL; i++) { ! 593: if(i->have != 'Y') { ! 594: (void) fprintf(spoolfp, "%s\n", i->field); ! 595: } ! 596: } ! 597: } ! 598: ! 599: /* ! 600: ** look at a string and determine ! 601: ** whether or not it is a valid header. ! 602: */ ! 603: isheader(s) ! 604: char *s; ! 605: { ! 606: char *p; ! 607: ! 608: /* ! 609: ** header field names must terminate with a colon ! 610: ** and may not be null. ! 611: */ ! 612: if(((p = index(s, ':')) == NULL) || (s == p)) { ! 613: return(0); ! 614: ! 615: } ! 616: /* ! 617: ** header field names must consist entirely of ! 618: ** printable ascii characters. ! 619: */ ! 620: while(s != p) { ! 621: if((*s < '!') || (*s > '~')) { ! 622: return(0); ! 623: } ! 624: s++; ! 625: } ! 626: /* ! 627: ** we hit the ':', so the field may be a header ! 628: */ ! 629: return(1); ! 630: } ! 631: ! 632: /* ! 633: ** compare the header field to those in the required header table. ! 634: ** if it matches, then mark the required header as being present ! 635: ** in the message. ! 636: */ ! 637: haveheaders(s) ! 638: char *s; ! 639: { ! 640: struct reqheaders *i; ! 641: ! 642: for(i = reqtab; i->name != NULL; i++) { ! 643: if(strncmpic(i->name, s, strlen(i->name)) == 0) { ! 644: if((strncmpic("From:", s, 5) == 0) ! 645: && (from_addr != NULL)) { ! 646: (void) sprintf(s, "From: %s\n", from_addr); ! 647: } ! 648: i->have = 'Y'; ! 649: break; ! 650: } ! 651: } ! 652: } ! 653: ! 654: /* ! 655: ** create default headers for the message. ! 656: */ ! 657: def_headers(argc, argv, from) ! 658: int argc; ! 659: char **argv; ! 660: char *from; ! 661: { ! 662: def_to(argc, argv); /* default To: */ ! 663: def_date(); /* default Date: */ ! 664: def_from(from); /* default From: */ ! 665: def_mid(); /* default Message-Id: */ ! 666: } ! 667: ! 668: /* ! 669: ** default Date: in arpa format ! 670: */ ! 671: def_date() ! 672: { ! 673: (void) strcpy(dateline, "Date: "); ! 674: (void) strcat(dateline, arpanows); ! 675: } ! 676: ! 677: /* ! 678: ** default Message-Id ! 679: ** Message-Id: <yymmddhhmm.AAppppp@hostdomain> ! 680: ** ! 681: ** yy year ! 682: ** mm month ! 683: ** dd day ! 684: ** hh hour ! 685: ** mm minute ! 686: ** ppppp process-id ! 687: ** ! 688: ** date and time are set by GMT ! 689: */ ! 690: def_mid() ! 691: { ! 692: (void) sprintf(midline, "Message-Id: <%02d%02d%02d%02d%02d.AA%05d@%s>", ! 693: gmt->tm_year, ! 694: gmt->tm_mon+1, ! 695: gmt->tm_mday, ! 696: gmt->tm_hour, ! 697: gmt->tm_min, ! 698: getpid(), ! 699: hostdomain); ! 700: } ! 701: ! 702: /* ! 703: ** default From: ! 704: ** From: user@hostdomain (Full Name) ! 705: */ ! 706: def_from(from) ! 707: char *from; ! 708: { ! 709: ! 710: char *nameptr; ! 711: char name[SMLBUF]; ! 712: char *getenv(), *login; ! 713: char *pwfnam(), *pwuid(); ! 714: ! 715: if (from_addr != NULL) { ! 716: (void) sprintf(fromline, "From: %s", from_addr); ! 717: return; ! 718: } ! 719: ! 720: name[0] = '\0'; ! 721: if((nameptr = getenv("NAME")) != NULL) { ! 722: (void) strcpy(name, nameptr); ! 723: } else if((login = pwuid(getuid())) != NULL) { ! 724: if((nameptr = pwfnam(login)) != NULL) { ! 725: (void) strcpy(name, nameptr); ! 726: } ! 727: } ! 728: if(name[0] != '\0') { ! 729: (void) sprintf(fromline, ! 730: "From: %s@%s (%s)", from, hostdomain, name); ! 731: } else { ! 732: (void) sprintf(fromline, ! 733: "From: %s@%s", from, hostdomain); ! 734: } ! 735: } ! 736: ! 737: /* ! 738: ** default To: ! 739: ** To: recip1, recip2, ... ! 740: ** ! 741: ** lines longer than 50 chars are continued on another line. ! 742: */ ! 743: def_to(argc, argv) ! 744: int argc; ! 745: char **argv; ! 746: { ! 747: int i, n; ! 748: char *bol; ! 749: ! 750: bol = toline; ! 751: (void) strcpy(bol, "To: "); ! 752: for(n = i = 0; i < argc; i++) { ! 753: (void) strcat(bol, argv[i]); ! 754: ! 755: if((index(argv[i], '!') == NULL) ! 756: && (index(argv[i], '@') == NULL)) { ! 757: (void) strcat(bol, "@"); ! 758: (void) strcat(bol, hostdomain); ! 759: } ! 760: if(i+1 < argc) { ! 761: n = strlen(bol); ! 762: if(n > 50) { ! 763: (void) strcat(bol, ",\n\t"); ! 764: bol = bol + strlen(bol); ! 765: *bol = '\0'; ! 766: n = 8; ! 767: } else { ! 768: (void) strcat(bol, ", "); ! 769: } ! 770: } ! 771: } ! 772: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.