|
|
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: } ! 336: } ! 337: ! 338: /* ! 339: ** now, copy the rest of the letter into the spool file ! 340: ** terminate on either EOF or '^.$' ! 341: */ ! 342: ! 343: while(ieof != NULL) { ! 344: (void) fputs(buf, spoolfp); ! 345: if((fgets(buf, SMLBUF, stdin) == NULL) ! 346: || (buf[0] == '.' && buf[1] == '\n')) { ! 347: ieof = NULL; ! 348: } ! 349: } ! 350: ! 351: /* ! 352: ** close the spool file, and the standard input. ! 353: */ ! 354: ! 355: (void) fclose(spoolfp); ! 356: (void) fclose(stdin); /* you don't see this too often! */ ! 357: } ! 358: ! 359: if((spoolfp = fopen(spoolfile, "r")) == NULL) { ! 360: error(EX_TEMPFAIL, "can't open %s.\n", spoolfile); ! 361: } ! 362: } ! 363: ! 364: /* ! 365: ** ! 366: ** rline(): collapse From_ and >From_ lines. ! 367: ** ! 368: ** Same idea as the old rmail, but also turns user@domain to domain!user. ! 369: ** ! 370: */ ! 371: ! 372: void ! 373: rline(from, retbuf) ! 374: char *from; ! 375: char *retbuf; ! 376: { ! 377: int parts; /* for cracking From_ lines ... */ ! 378: char *partv[16]; /* ... apart using ssplit() */ ! 379: char user[SMLBUF]; /* for rewriting user@host */ ! 380: char domain[SMLBUF]; /* " " " */ ! 381: char addr[SMLBUF]; /* " " " */ ! 382: enum eform form, parse(); /* " " " */ ! 383: extern build(); /* " " " */ ! 384: char *c; ! 385: int nhops, i; ! 386: char buf[SMLBUF], tmp[SMLBUF], *hop[128], *e, *b; ! 387: char *pwuid(); ! 388: ! 389: if(spoolmaster == 0) return; ! 390: ! 391: buf[0] = from[0] = addr[0] = '\0'; ! 392: /* ! 393: ** Read each line until we hit EOF or a line not beginning with "From " ! 394: ** or ">From " (called From_ lines), accumulating the new path in from ! 395: ** and stuffing the actual sending user (the user name on the last From_ ! 396: ** line) in addr. ! 397: */ ! 398: for(;;) { ! 399: (void) strcpy(retbuf, buf); ! 400: if(ieof == NULL) { ! 401: break; ! 402: } ! 403: if((fgets(buf, sizeof(buf), stdin) == NULL) ! 404: || (buf[0] == '.' && buf[1] == '\n')) { ! 405: ieof = NULL; ! 406: break; ! 407: } ! 408: if (strncmp("From ", buf, 5) ! 409: && strncmp(">From ", buf, 6)) { ! 410: break; ! 411: } ! 412: /* ! 413: ** Crack the line apart using ssplit. ! 414: */ ! 415: if(c = index(buf, '\n')) { ! 416: *c = '\0'; ! 417: } ! 418: parts = ssplit(buf, ' ', partv); ! 419: /* ! 420: ** Tack host! onto the from argument if "remote from host" is present. ! 421: */ ! 422: ! 423: if((parts > 3) ! 424: && (strncmp("remote from ", partv[parts-3], 12) == 0)) { ! 425: (void) strcat(from, partv[parts-1]); ! 426: (void) strcat(from, "!"); ! 427: } ! 428: /* ! 429: ** Stuff user name into addr, overwriting the user name from previous ! 430: ** From_ lines, since only the last one counts. Then rewrite user@host ! 431: ** into host!user, since @'s don't belong in the From_ argument. ! 432: */ ! 433: if(parts < 2) { ! 434: break; ! 435: } else { ! 436: char *x = partv[1]; ! 437: char *q = index(x, ' '); ! 438: if(q != NULL) { ! 439: *q = '\0'; ! 440: } ! 441: (void) strcpy(addr, x); ! 442: } ! 443: ! 444: (void) parse(addr, domain, user); ! 445: if(*domain == '\0') { ! 446: form = LOCAL; ! 447: } else { ! 448: form = UUCP; ! 449: } ! 450: ! 451: build(domain, user, form, addr); ! 452: } ! 453: /* ! 454: ** Now tack the user name onto the from argument. ! 455: */ ! 456: (void) strcat(from, addr); ! 457: /* ! 458: ** If we still have no from argument, we have junk headers, but we try ! 459: ** to get the user's name using /etc/passwd. ! 460: */ ! 461: ! 462: if (from[0] == '\0') { ! 463: char *login; ! 464: if ((login = pwuid(getuid())) == NULL) { ! 465: (void) strcpy(from, "nobody"); /* bad news */ ! 466: } else { ! 467: (void) strcpy(from, login); ! 468: } ! 469: } ! 470: ! 471: /* split the from line on '!'s */ ! 472: nhops = ssplit(from, '!', hop); ! 473: ! 474: for(i = 0; i < (nhops - 1); i++) { ! 475: b = hop[i]; ! 476: if(*b == '\0') { ! 477: continue; ! 478: } ! 479: e = hop[i+1]; ! 480: e-- ; ! 481: *e = '\0'; /* null terminate each path segment */ ! 482: e++; ! 483: ! 484: #ifdef HIDDENHOSTS ! 485: /* ! 486: ** Strip hidden hosts: anything.hostname.MYDOM -> hostname.MYDOM ! 487: */ ! 488: for(p = b;(p = index(p, '.')) != NULL; p++) { ! 489: if(strcmpic(hostdomain, p+1) == 0) { ! 490: (void) strcpy(b, hostdomain); ! 491: break; ! 492: } ! 493: } ! 494: #endif ! 495: ! 496: /* ! 497: ** Strip useless MYDOM: hostname.MYDOM -> hostname ! 498: */ ! 499: if(strcmpic(hop[i], hostdomain) == 0) { ! 500: (void) strcpy(hop[i], hostname); ! 501: } ! 502: } ! 503: ! 504: /* ! 505: ** Now strip out any redundant information in the From_ line ! 506: ** a!b!c!c!d => a!b!c!d ! 507: */ ! 508: ! 509: for(i = 0; i < (nhops - 2); i++) { ! 510: b = hop[i]; ! 511: e = hop[i+1]; ! 512: if(strcmpic(b, e) == 0) { ! 513: *b = '\0'; ! 514: } ! 515: } ! 516: /* ! 517: ** Reconstruct the From_ line ! 518: */ ! 519: tmp[0] = '\0'; /* empty the tmp buffer */ ! 520: ! 521: for(i = 0; i < (nhops - 1); i++) { ! 522: if((hop[i][0] == '\0') /* deleted this hop */ ! 523: ||((tmp[0] == '\0') /* first hop == hostname */ ! 524: &&(strcmpic(hop[i], hostname) == 0))) { ! 525: continue; ! 526: } ! 527: (void) strcat(tmp, hop[i]); ! 528: (void) strcat(tmp, "!"); ! 529: } ! 530: (void) strcat(tmp, hop[i]); ! 531: (void) strcpy(from, tmp); ! 532: (void) strcpy(retbuf, buf); ! 533: (void) fprintf(spoolfp, "%s\n", from); ! 534: } ! 535: ! 536: void ! 537: scanheaders(buf) ! 538: char *buf; ! 539: { ! 540: int inheader = 0; ! 541: ! 542: while(ieof != NULL) { ! 543: if(buf[0] == '\n') { ! 544: break; /* end of headers */ ! 545: } ! 546: ! 547: /* ! 548: ** header lines which begin with whitespace ! 549: ** are continuation lines ! 550: */ ! 551: if((inheader == 0) ! 552: || ((buf[0] != ' ' && buf[0] != '\t'))) { ! 553: /* not a continuation line ! 554: ** check for header ! 555: */ ! 556: if(isheader(buf) == 0) { ! 557: /* ! 558: ** not a header ! 559: */ ! 560: break; ! 561: } ! 562: inheader = 1; ! 563: haveheaders(buf); ! 564: } ! 565: (void) fputs(buf, spoolfp); ! 566: if((fgets(buf, SMLBUF, stdin) == NULL) ! 567: || (buf[0] == '.' && buf[1] == '\n')) { ! 568: ieof = NULL; ! 569: } ! 570: } ! 571: ! 572: if(isheader(buf)) { ! 573: buf[0] = '\0'; ! 574: } ! 575: } ! 576: ! 577: /* ! 578: ** complete headers - add any required headers that are not in the message ! 579: */ ! 580: void ! 581: compheaders() ! 582: { ! 583: struct reqheaders *i; ! 584: ! 585: /* ! 586: ** look at the table of required headers and ! 587: ** add those that are missing to the spooled message. ! 588: */ ! 589: for(i = reqtab; i->name != NULL; i++) { ! 590: if(i->have != 'Y') { ! 591: (void) fprintf(spoolfp, "%s\n", i->field); ! 592: } ! 593: } ! 594: } ! 595: ! 596: /* ! 597: ** look at a string and determine ! 598: ** whether or not it is a valid header. ! 599: */ ! 600: isheader(s) ! 601: char *s; ! 602: { ! 603: char *p; ! 604: ! 605: /* ! 606: ** header field names must terminate with a colon ! 607: ** and may not be null. ! 608: */ ! 609: if(((p = index(s, ':')) == NULL) || (s == p)) { ! 610: return(0); ! 611: ! 612: } ! 613: /* ! 614: ** header field names must consist entirely of ! 615: ** printable ascii characters. ! 616: */ ! 617: while(s != p) { ! 618: if((*s < '!') || (*s > '~')) { ! 619: return(0); ! 620: } ! 621: s++; ! 622: } ! 623: /* ! 624: ** we hit the ':', so the field may be a header ! 625: */ ! 626: return(1); ! 627: } ! 628: ! 629: /* ! 630: ** compare the header field to those in the required header table. ! 631: ** if it matches, then mark the required header as being present ! 632: ** in the message. ! 633: */ ! 634: haveheaders(s) ! 635: char *s; ! 636: { ! 637: struct reqheaders *i; ! 638: ! 639: for(i = reqtab; i->name != NULL; i++) { ! 640: if(strncmpic(i->name, s, strlen(i->name)) == 0) { ! 641: if((strncmpic("From:", s, 5) == 0) ! 642: && (from_addr != NULL)) { ! 643: (void) sprintf(s, "From: %s\n", from_addr); ! 644: } ! 645: i->have = 'Y'; ! 646: break; ! 647: } ! 648: } ! 649: } ! 650: ! 651: /* ! 652: ** create default headers for the message. ! 653: */ ! 654: def_headers(argc, argv, from) ! 655: int argc; ! 656: char **argv; ! 657: char *from; ! 658: { ! 659: def_to(argc, argv); /* default To: */ ! 660: def_date(); /* default Date: */ ! 661: def_from(from); /* default From: */ ! 662: def_mid(); /* default Message-Id: */ ! 663: } ! 664: ! 665: /* ! 666: ** default Date: in arpa format ! 667: */ ! 668: def_date() ! 669: { ! 670: (void) strcpy(dateline, "Date: "); ! 671: (void) strcat(dateline, arpanows); ! 672: } ! 673: ! 674: /* ! 675: ** default Message-Id ! 676: ** Message-Id: <yymmddhhmm.AAppppp@hostdomain> ! 677: ** ! 678: ** yy year ! 679: ** mm month ! 680: ** dd day ! 681: ** hh hour ! 682: ** mm minute ! 683: ** ppppp process-id ! 684: ** ! 685: ** date and time are set by GMT ! 686: */ ! 687: def_mid() ! 688: { ! 689: (void) sprintf(midline, "Message-Id: <%02d%02d%02d%02d%02d.AA%05d@%s>", ! 690: gmt->tm_year, ! 691: gmt->tm_mon+1, ! 692: gmt->tm_mday, ! 693: gmt->tm_hour, ! 694: gmt->tm_min, ! 695: getpid(), ! 696: hostdomain); ! 697: } ! 698: ! 699: /* ! 700: ** default From: ! 701: ** From: user@hostdomain (Full Name) ! 702: */ ! 703: def_from(from) ! 704: char *from; ! 705: { ! 706: ! 707: char *nameptr; ! 708: char name[SMLBUF]; ! 709: char *getenv(), *login; ! 710: char *pwfnam(), *pwuid(); ! 711: ! 712: if (from_addr != NULL) { ! 713: (void) sprintf(fromline, "From: %s", from_addr); ! 714: return; ! 715: } ! 716: ! 717: name[0] = '\0'; ! 718: if((nameptr = getenv("NAME")) != NULL) { ! 719: (void) strcpy(name, nameptr); ! 720: } else if((login = pwuid(getuid())) != NULL) { ! 721: if((nameptr = pwfnam(login)) != NULL) { ! 722: (void) strcpy(name, nameptr); ! 723: } ! 724: } ! 725: if(name[0] != '\0') { ! 726: (void) sprintf(fromline, ! 727: "From: %s@%s (%s)", from, hostdomain, name); ! 728: } else { ! 729: (void) sprintf(fromline, ! 730: "From: %s@%s", from, hostdomain); ! 731: } ! 732: } ! 733: ! 734: /* ! 735: ** default To: ! 736: ** To: recip1, recip2, ... ! 737: ** ! 738: ** lines longer than 50 chars are continued on another line. ! 739: */ ! 740: def_to(argc, argv) ! 741: int argc; ! 742: char **argv; ! 743: { ! 744: int i, n; ! 745: char *bol; ! 746: ! 747: bol = toline; ! 748: (void) strcpy(bol, "To: "); ! 749: for(n = i = 0; i < argc; i++) { ! 750: (void) strcat(bol, argv[i]); ! 751: ! 752: if((index(argv[i], '!') == NULL) ! 753: && (index(argv[i], '@') == NULL)) { ! 754: (void) strcat(bol, "@"); ! 755: (void) strcat(bol, hostdomain); ! 756: } ! 757: if(i+1 < argc) { ! 758: n = strlen(bol); ! 759: if(n > 50) { ! 760: (void) strcat(bol, ",\n\t"); ! 761: bol = bol + strlen(bol); ! 762: *bol = '\0'; ! 763: n = 8; ! 764: } else { ! 765: (void) strcat(bol, ", "); ! 766: } ! 767: } ! 768: } ! 769: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.