|
|
1.1 ! root 1: # ! 2: ! 3: /* ! 4: * Mail -- a mail program ! 5: * ! 6: * Collect input from standard input, handling ! 7: * ~ escapes. ! 8: */ ! 9: ! 10: #include "rcv.h" ! 11: #include <sys/stat.h> ! 12: ! 13: /* ! 14: * Read a message from standard output and return a read file to it ! 15: * or NULL on error. ! 16: */ ! 17: ! 18: /* ! 19: * The following hokiness with global variables is so that on ! 20: * receipt of an interrupt signal, the partial message can be salted ! 21: * away on dead.letter. The output file must be available to flush, ! 22: * and the input to read. Several open files could be saved all through ! 23: * Mail if stdio allowed simultaneous read/write access. ! 24: */ ! 25: ! 26: static int (*savesig)(); /* Previous SIGINT value */ ! 27: static FILE *newi; /* File for saving away */ ! 28: static FILE *newo; /* Output side of same */ ! 29: static int hf; /* Ignore interrups */ ! 30: static int nofault; /* Soft signal if set */ ! 31: static int hadintr; /* Have seen one SIGINT so far */ ! 32: ! 33: static jmp_buf coljmp; /* To get back to work */ ! 34: ! 35: FILE * ! 36: collect(hp) ! 37: struct header *hp; ! 38: { ! 39: FILE *ibuf, *fbuf, *obuf; ! 40: int lc, cc, escape, collrub(), intack(), stopdot; ! 41: register int c, t; ! 42: char linebuf[LINESIZE], *cp; ! 43: extern char tempMail[]; ! 44: ! 45: noreset++; ! 46: stopdot = (value("dot") != NOSTR) && intty; ! 47: ibuf = obuf = NULL; ! 48: if (value("ignore") != NOSTR) ! 49: hf = 1; ! 50: else ! 51: hf = 0; ! 52: nofault = 1; ! 53: hadintr = 0; ! 54: if ((savesig = signal(SIGINT, SIG_IGN)) != SIG_IGN) ! 55: signal(SIGINT, hf ? intack : collrub); ! 56: newi = NULL; ! 57: newo = NULL; ! 58: if ((obuf = fopen(tempMail, "w")) == NULL) { ! 59: perror(tempMail); ! 60: goto err; ! 61: } ! 62: newo = obuf; ! 63: if ((ibuf = fopen(tempMail, "r")) == NULL) { ! 64: perror(tempMail); ! 65: newo = NULL; ! 66: fclose(obuf); ! 67: goto err; ! 68: } ! 69: newi = ibuf; ! 70: remove(tempMail); ! 71: ! 72: /* ! 73: * If we are going to prompt for a subject, ! 74: * refrain from printing a newline after ! 75: * the headers (since some people mind). ! 76: */ ! 77: ! 78: t = GTO|GSUBJECT|GCC|GNL; ! 79: c = 0; ! 80: if (intty && sflag == NOSTR && hp->h_subject == NOSTR && value("ask")) ! 81: t &= ~GNL, c++; ! 82: if (hp->h_seq != 0) { ! 83: puthead(hp, stdout, t); ! 84: fflush(stdout); ! 85: } ! 86: if (c) ! 87: grabh(hp, GSUBJECT); ! 88: escape = ESCAPE; ! 89: if ((cp = value("escape")) != NOSTR) ! 90: escape = *cp; ! 91: for (;;) { ! 92: setjmp(coljmp); ! 93: nofault = 0; ! 94: flush(); ! 95: if (readline(stdin, linebuf) <= 0) ! 96: break; ! 97: hadintr = 0; ! 98: if (stopdot && equal(".", linebuf)) ! 99: break; ! 100: if (linebuf[0] != escape || ! 101: (!intty && value("henry") == NOSTR)) { ! 102: if ((t = putline(obuf, linebuf)) < 0) ! 103: goto err; ! 104: continue; ! 105: } ! 106: c = linebuf[1]; ! 107: nofault= 0; ! 108: switch (c) { ! 109: default: ! 110: /* ! 111: * On double escape, just send the single one. ! 112: * Otherwise, it's an error. ! 113: */ ! 114: ! 115: if (c == escape) { ! 116: if (putline(obuf, &linebuf[1]) < 0) ! 117: goto err; ! 118: else ! 119: break; ! 120: } ! 121: printf("Unknown tilde escape.\n"); ! 122: break; ! 123: ! 124: case 'C': ! 125: /* ! 126: * Dump core. ! 127: */ ! 128: ! 129: core(); ! 130: break; ! 131: ! 132: case '!': ! 133: /* ! 134: * Shell escape, send the balance of the ! 135: * line to sh -c. ! 136: */ ! 137: ! 138: shell(&linebuf[2]); ! 139: break; ! 140: ! 141: case ':': ! 142: case '_': ! 143: /* ! 144: * Escape to command mode, but be nice! ! 145: */ ! 146: ! 147: nofault = 0; ! 148: execute(&linebuf[2]); ! 149: break; ! 150: ! 151: case '.': ! 152: /* ! 153: * Simulate end of file on input. ! 154: */ ! 155: goto eof; ! 156: ! 157: case 'q': ! 158: case 'Q': ! 159: /* ! 160: * Force a quit of sending mail. ! 161: * Act like an interrupt happened. ! 162: */ ! 163: ! 164: nofault = 0; ! 165: hadintr++; ! 166: collrub(SIGINT); ! 167: exit(1); ! 168: ! 169: case 'h': ! 170: /* ! 171: * Grab a bunch of headers. ! 172: */ ! 173: if (!intty || !outtty) { ! 174: printf("~h: no can do!?\n"); ! 175: break; ! 176: } ! 177: grabh(hp, GTO|GSUBJECT|GCC|GBCC); ! 178: printf("(continue)\n"); ! 179: break; ! 180: ! 181: case 't': ! 182: /* ! 183: * Add to the To list. ! 184: */ ! 185: ! 186: hp->h_to = addto(hp->h_to, &linebuf[2]); ! 187: hp->h_seq++; ! 188: break; ! 189: ! 190: case 's': ! 191: /* ! 192: * Set the Subject list. ! 193: */ ! 194: ! 195: cp = &linebuf[2]; ! 196: while (any(*cp, " \t")) ! 197: cp++; ! 198: hp->h_subject = savestr(cp); ! 199: hp->h_seq++; ! 200: break; ! 201: ! 202: case 'c': ! 203: /* ! 204: * Add to the CC list. ! 205: */ ! 206: ! 207: hp->h_cc = addto(hp->h_cc, &linebuf[2]); ! 208: hp->h_seq++; ! 209: break; ! 210: ! 211: case 'b': ! 212: /* ! 213: * Add stuff to blind carbon copies list. ! 214: */ ! 215: hp->h_bcc = addto(hp->h_bcc, &linebuf[2]); ! 216: hp->h_seq++; ! 217: break; ! 218: ! 219: case 'd': ! 220: copy(deadletter, &linebuf[2]); ! 221: /* fall into . . . */ ! 222: ! 223: case 'r': ! 224: /* ! 225: * Invoke a file: ! 226: * Search for the file name, ! 227: * then open it and copy the contents to obuf. ! 228: */ ! 229: ! 230: cp = &linebuf[2]; ! 231: while (any(*cp, " \t")) ! 232: cp++; ! 233: if (*cp == '\0') { ! 234: printf("Interpolate what file?\n"); ! 235: break; ! 236: } ! 237: cp = expand(cp); ! 238: if (cp == NOSTR) ! 239: break; ! 240: if (isdir(cp)) { ! 241: printf("%s: directory\n"); ! 242: break; ! 243: } ! 244: if ((fbuf = fopen(cp, "r")) == NULL) { ! 245: perror(cp); ! 246: break; ! 247: } ! 248: printf("\"%s\" ", cp); ! 249: flush(); ! 250: lc = 0; ! 251: cc = 0; ! 252: while (readline(fbuf, linebuf) > 0) { ! 253: lc++; ! 254: if ((t = putline(obuf, linebuf)) < 0) { ! 255: fclose(fbuf); ! 256: goto err; ! 257: } ! 258: cc += t; ! 259: } ! 260: fclose(fbuf); ! 261: printf("%d/%d\n", lc, cc); ! 262: break; ! 263: ! 264: case 'w': ! 265: /* ! 266: * Write the message on a file. ! 267: */ ! 268: ! 269: cp = &linebuf[2]; ! 270: while (any(*cp, " \t")) ! 271: cp++; ! 272: if (*cp == '\0') { ! 273: fprintf(stderr, "Write what file!?\n"); ! 274: break; ! 275: } ! 276: if ((cp = expand(cp)) == NOSTR) ! 277: break; ! 278: fflush(obuf); ! 279: rewind(ibuf); ! 280: exwrite(cp, ibuf, 1); ! 281: break; ! 282: ! 283: case 'm': ! 284: case 'f': ! 285: /* ! 286: * Interpolate the named messages, if we ! 287: * are in receiving mail mode. Does the ! 288: * standard list processing garbage. ! 289: * If ~f is given, we don't shift over. ! 290: */ ! 291: ! 292: if (!rcvmode) { ! 293: printf("No messages to send from!?!\n"); ! 294: break; ! 295: } ! 296: cp = &linebuf[2]; ! 297: while (any(*cp, " \t")) ! 298: cp++; ! 299: if (forward(cp, obuf, c) < 0) ! 300: goto err; ! 301: printf("(continue)\n"); ! 302: break; ! 303: ! 304: case '?': ! 305: nofault = 0; ! 306: if ((fbuf = fopen(THELPFILE, "r")) == NULL) { ! 307: printf("No help just now.\n"); ! 308: break; ! 309: } ! 310: t = getc(fbuf); ! 311: while (t != -1) { ! 312: putchar(t); ! 313: t = getc(fbuf); ! 314: } ! 315: fclose(fbuf); ! 316: break; ! 317: ! 318: case 'p': ! 319: /* ! 320: * Print out the current state of the ! 321: * message without altering anything. ! 322: */ ! 323: ! 324: fflush(obuf); ! 325: rewind(ibuf); ! 326: nofault = 0; ! 327: printf("-------\nMessage contains:\n"); ! 328: puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); ! 329: t = getc(ibuf); ! 330: while (t != EOF) { ! 331: putchar(t); ! 332: t = getc(ibuf); ! 333: } ! 334: printf("(continue)\n"); ! 335: break; ! 336: ! 337: case '^': ! 338: case '|': ! 339: /* ! 340: * Pipe message through command. ! 341: * Collect output as new message. ! 342: */ ! 343: ! 344: obuf = mespipe(ibuf, obuf, &linebuf[2]); ! 345: newo = obuf; ! 346: ibuf = newi; ! 347: newi = ibuf; ! 348: printf("(continue)\n"); ! 349: break; ! 350: ! 351: case 'v': ! 352: case 'e': ! 353: /* ! 354: * Edit the current message. ! 355: * 'e' means to use EDITOR ! 356: * 'v' means to use VISUAL ! 357: */ ! 358: ! 359: if ((obuf = mesedit(ibuf, obuf, c)) == NULL) ! 360: goto err; ! 361: newo = obuf; ! 362: ibuf = newi; ! 363: printf("(continue)\n"); ! 364: break; ! 365: break; ! 366: } ! 367: } ! 368: eof: ! 369: fclose(obuf); ! 370: rewind(ibuf); ! 371: signal(SIGINT, savesig); ! 372: noreset = 0; ! 373: return(ibuf); ! 374: ! 375: err: ! 376: if (ibuf != NULL) ! 377: fclose(ibuf); ! 378: if (obuf != NULL) ! 379: fclose(obuf); ! 380: signal(SIGINT, savesig); ! 381: noreset = 0; ! 382: return(NULL); ! 383: } ! 384: ! 385: /* ! 386: * Non destructively interrogate the value of the given signal. ! 387: */ ! 388: ! 389: psig(n) ! 390: { ! 391: register (*wassig)(); ! 392: ! 393: wassig = signal(n, SIG_IGN); ! 394: signal(n, wassig); ! 395: return((int) wassig); ! 396: } ! 397: ! 398: /* ! 399: * Write a file, ex-like if f set. ! 400: */ ! 401: ! 402: exwrite(name, ibuf, f) ! 403: char name[]; ! 404: FILE *ibuf; ! 405: { ! 406: register FILE *of; ! 407: register int c; ! 408: long cc; ! 409: int lc; ! 410: struct stat junk; ! 411: ! 412: if (f) { ! 413: printf("\"%s\" ", name); ! 414: fflush(stdout); ! 415: } ! 416: if (stat(name, &junk) >= 0) { ! 417: if (!f) ! 418: fprintf(stderr, "%s: ", name); ! 419: fprintf(stderr, "File exists\n", name); ! 420: return(-1); ! 421: } ! 422: if ((of = fopen(name, "w")) == NULL) { ! 423: perror(NOSTR); ! 424: return(-1); ! 425: } ! 426: lc = 0; ! 427: cc = 0; ! 428: while ((c = getc(ibuf)) != EOF) { ! 429: cc++; ! 430: if (c == '\n') ! 431: lc++; ! 432: putc(c, of); ! 433: if (ferror(of)) { ! 434: perror(name); ! 435: fclose(of); ! 436: return(-1); ! 437: } ! 438: } ! 439: fclose(of); ! 440: printf("%d/%ld\n", lc, cc); ! 441: fflush(stdout); ! 442: return(0); ! 443: } ! 444: ! 445: /* ! 446: * Edit the message being collected on ibuf and obuf. ! 447: * Write the message out onto some poorly-named temp file ! 448: * and point an editor at it. ! 449: * ! 450: * On return, make the edit file the new temp file. ! 451: */ ! 452: ! 453: FILE * ! 454: mesedit(ibuf, obuf, c) ! 455: FILE *ibuf, *obuf; ! 456: { ! 457: int pid, s; ! 458: FILE *fbuf; ! 459: register int t; ! 460: int (*sig)(); ! 461: struct stat sbuf; ! 462: extern char tempMail[], tempEdit[]; ! 463: register char *edit; ! 464: ! 465: sig = signal(SIGINT, SIG_IGN); ! 466: if (stat(tempEdit, &sbuf) >= 0) { ! 467: printf("%s: file exists\n", tempEdit); ! 468: goto out; ! 469: } ! 470: close(creat(tempEdit, 0600)); ! 471: if ((fbuf = fopen(tempEdit, "w")) == NULL) { ! 472: perror(tempEdit); ! 473: goto out; ! 474: } ! 475: fflush(obuf); ! 476: rewind(ibuf); ! 477: t = getc(ibuf); ! 478: while (t != EOF) { ! 479: putc(t, fbuf); ! 480: t = getc(ibuf); ! 481: } ! 482: fflush(fbuf); ! 483: if (ferror(fbuf)) { ! 484: perror(tempEdit); ! 485: remove(tempEdit); ! 486: goto fix; ! 487: } ! 488: fclose(fbuf); ! 489: if ((edit = value(c == 'e' ? "EDITOR" : "VISUAL")) == NOSTR) ! 490: edit = c == 'e' ? EDITOR : VISUAL; ! 491: pid = vfork(); ! 492: if (pid == 0) { ! 493: if (sig != SIG_IGN) ! 494: signal(SIGINT, SIG_DFL); ! 495: execl(edit, edit, tempEdit, 0); ! 496: perror(edit); ! 497: _exit(1); ! 498: } ! 499: if (pid == -1) { ! 500: perror("fork"); ! 501: remove(tempEdit); ! 502: goto out; ! 503: } ! 504: while (wait(&s) != pid) ! 505: ; ! 506: if (s != 0) { ! 507: printf("Fatal error in \"%s\"\n", edit); ! 508: remove(tempEdit); ! 509: goto out; ! 510: } ! 511: ! 512: /* ! 513: * Now switch to new file. ! 514: */ ! 515: ! 516: if ((fbuf = fopen(tempEdit, "a")) == NULL) { ! 517: perror(tempEdit); ! 518: remove(tempEdit); ! 519: goto out; ! 520: } ! 521: if ((ibuf = fopen(tempEdit, "r")) == NULL) { ! 522: perror(tempEdit); ! 523: fclose(fbuf); ! 524: remove(tempEdit); ! 525: goto out; ! 526: } ! 527: remove(tempEdit); ! 528: fclose(obuf); ! 529: fclose(newi); ! 530: obuf = fbuf; ! 531: goto out; ! 532: fix: ! 533: perror(tempEdit); ! 534: out: ! 535: signal(SIGINT, sig); ! 536: newi = ibuf; ! 537: return(obuf); ! 538: } ! 539: ! 540: /* ! 541: * Pipe the message through the command. ! 542: * Old message is on stdin of command; ! 543: * New message collected from stdout. ! 544: * Sh -c must return 0 to accept the new message. ! 545: */ ! 546: ! 547: FILE * ! 548: mespipe(ibuf, obuf, cmd) ! 549: FILE *ibuf, *obuf; ! 550: char cmd[]; ! 551: { ! 552: register FILE *ni, *no; ! 553: int pid, s; ! 554: int (*savesig)(); ! 555: char *Shell; ! 556: ! 557: newi = ibuf; ! 558: if ((no = fopen(tempEdit, "w")) == NULL) { ! 559: perror(tempEdit); ! 560: return(obuf); ! 561: } ! 562: if ((ni = fopen(tempEdit, "r")) == NULL) { ! 563: perror(tempEdit); ! 564: fclose(no); ! 565: remove(tempEdit); ! 566: return(obuf); ! 567: } ! 568: remove(tempEdit); ! 569: savesig = signal(SIGINT, SIG_IGN); ! 570: fflush(obuf); ! 571: rewind(ibuf); ! 572: if ((Shell = value("SHELL")) == NULL) ! 573: Shell = "/bin/sh"; ! 574: if ((pid = vfork()) == -1) { ! 575: perror("fork"); ! 576: goto err; ! 577: } ! 578: if (pid == 0) { ! 579: /* ! 580: * stdin = current message. ! 581: * stdout = new message. ! 582: */ ! 583: ! 584: close(0); ! 585: dup(fileno(ibuf)); ! 586: close(1); ! 587: dup(fileno(no)); ! 588: for (s = 4; s < 15; s++) ! 589: close(s); ! 590: execl(Shell, Shell, "-c", cmd, 0); ! 591: perror(Shell); ! 592: _exit(1); ! 593: } ! 594: while (wait(&s) != pid) ! 595: ; ! 596: if (s != 0 || pid == -1) { ! 597: fprintf(stderr, "\"%s\" failed!?\n", cmd); ! 598: goto err; ! 599: } ! 600: if (fsize(ni) == 0) { ! 601: fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); ! 602: goto err; ! 603: } ! 604: ! 605: /* ! 606: * Take new files. ! 607: */ ! 608: ! 609: newi = ni; ! 610: fclose(ibuf); ! 611: fclose(obuf); ! 612: signal(SIGINT, savesig); ! 613: return(no); ! 614: ! 615: err: ! 616: fclose(no); ! 617: fclose(ni); ! 618: signal(SIGINT, savesig); ! 619: return(obuf); ! 620: } ! 621: ! 622: /* ! 623: * Interpolate the named messages into the current ! 624: * message, preceding each line with a tab. ! 625: * Return a count of the number of characters now in ! 626: * the message, or -1 if an error is encountered writing ! 627: * the message temporary. The flag argument is 'm' if we ! 628: * should shift over and 'f' if not. ! 629: */ ! 630: ! 631: forward(ms, obuf, f) ! 632: char ms[]; ! 633: FILE *obuf; ! 634: { ! 635: register int *msgvec, *ip; ! 636: extern char tempMail[]; ! 637: ! 638: msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec); ! 639: if (msgvec == (int *) NOSTR) ! 640: return(0); ! 641: if (getmsglist(ms, msgvec, 0) < 0) ! 642: return(0); ! 643: if (*msgvec == NULL) { ! 644: *msgvec = first(0, MMNORM); ! 645: if (*msgvec == NULL) { ! 646: printf("No appropriate messages\n"); ! 647: return(0); ! 648: } ! 649: msgvec[1] = NULL; ! 650: } ! 651: printf("Interpolating:"); ! 652: for (ip = msgvec; *ip != NULL; ip++) { ! 653: touch(*ip); ! 654: printf(" %d", *ip); ! 655: if (f == 'm') { ! 656: if (transmit(&message[*ip-1], obuf) < 0) { ! 657: perror(tempMail); ! 658: return(-1); ! 659: } ! 660: } else ! 661: if (send(&message[*ip-1], obuf) < 0) { ! 662: perror(tempMail); ! 663: return(-1); ! 664: } ! 665: } ! 666: printf("\n"); ! 667: return(0); ! 668: } ! 669: ! 670: /* ! 671: * Send message described by the passed pointer to the ! 672: * passed output buffer. Insert a tab in front of each ! 673: * line. Return a count of the characters sent, or -1 ! 674: * on error. ! 675: */ ! 676: ! 677: transmit(mailp, obuf) ! 678: struct message *mailp; ! 679: FILE *obuf; ! 680: { ! 681: register struct message *mp; ! 682: register int c, ch; ! 683: int n, bol; ! 684: FILE *ibuf; ! 685: ! 686: mp = mailp; ! 687: ibuf = setinput(mp); ! 688: c = msize(mp); ! 689: n = c; ! 690: bol = 1; ! 691: while (c-- > 0) { ! 692: if (bol) { ! 693: bol = 0; ! 694: putc('\t', obuf); ! 695: n++; ! 696: if (ferror(obuf)) { ! 697: perror("/tmp"); ! 698: return(-1); ! 699: } ! 700: } ! 701: ch = getc(ibuf); ! 702: if (ch == '\n') ! 703: bol++; ! 704: putc(ch, obuf); ! 705: if (ferror(obuf)) { ! 706: perror("/tmp"); ! 707: return(-1); ! 708: } ! 709: } ! 710: return(n); ! 711: } ! 712: ! 713: /* ! 714: * On interrupt, go here to save the partial ! 715: * message on #/dead.letter. ! 716: * Then restore signals and execute the normal ! 717: * signal routine. We only come here if signals ! 718: * were previously set anyway. ! 719: */ ! 720: ! 721: collrub(s) ! 722: { ! 723: register FILE *dbuf; ! 724: register int c; ! 725: ! 726: #ifdef V7 ! 727: signal(s, SIG_IGN); ! 728: #else ! 729: signal(SIGINT, SIG_IGN); ! 730: #endif ! 731: if (nofault) { ! 732: #ifdef V7 ! 733: signal(s, collrub); ! 734: #else ! 735: signal(SIGINT, collrub); ! 736: #endif ! 737: return; ! 738: } ! 739: if (hadintr == 0) { ! 740: hadintr++; ! 741: clrbuf(stdout); ! 742: printf("\n(Interrupt -- one more to kill letter)\n"); ! 743: #ifdef V7 ! 744: signal(s, collrub); ! 745: #else ! 746: signal(SIGINT, collrub); ! 747: #endif ! 748: longjmp(coljmp, 1); ! 749: } ! 750: fclose(newo); ! 751: rewind(newi); ! 752: if (value("nosave") != NOSTR || fsize(newi) == 0) ! 753: goto done; ! 754: if ((dbuf = fopen(deadletter, "w")) == NULL) ! 755: goto done; ! 756: chmod(deadletter, 0600); ! 757: while ((c = getc(newi)) != EOF) ! 758: putc(c, dbuf); ! 759: fclose(dbuf); ! 760: ! 761: done: ! 762: fclose(newi); ! 763: signal(SIGINT, savesig); ! 764: if (rcvmode) ! 765: stop(); ! 766: else ! 767: exit(1); ! 768: } ! 769: ! 770: /* ! 771: * Acknowledge an interrupt signal from the tty by typing an @ ! 772: */ ! 773: ! 774: intack(s) ! 775: { ! 776: ! 777: signal(SIGINT, SIG_IGN); ! 778: puts("@"); ! 779: fflush(stdout); ! 780: clearerr(stdin); ! 781: signal(SIGINT, intack); ! 782: } ! 783: ! 784: /* ! 785: * Add a string to the end of a header entry field. ! 786: */ ! 787: ! 788: char * ! 789: addto(hf, news) ! 790: char hf[], news[]; ! 791: { ! 792: register char *cp, *cp2, *linebuf; ! 793: ! 794: if (hf == NOSTR) ! 795: hf = ""; ! 796: if (*news == '\0') ! 797: return(hf); ! 798: linebuf = salloc(strlen(hf) + strlen(news) + 2); ! 799: for (cp = hf; any(*cp, " \t"); cp++) ! 800: ; ! 801: for (cp2 = linebuf; *cp;) ! 802: *cp2++ = *cp++; ! 803: *cp2++ = ' '; ! 804: for (cp = news; any(*cp, " \t"); cp++) ! 805: ; ! 806: while (*cp != '\0') ! 807: *cp2++ = *cp++; ! 808: *cp2 = '\0'; ! 809: return(linebuf); ! 810: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.