|
|
1.1 ! root 1: #ident "@(#)tty.c 1.4 'attmail mail(1) command'" ! 2: #ident "@(#)mailx:tty.c 1.9.2.1" ! 3: /* Copyright (c) 1984 AT&T */ ! 4: /* All Rights Reserved */ ! 5: ! 6: /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */ ! 7: /* The copyright notice above does not evidence any */ ! 8: /* actual or intended publication of such source code. */ ! 9: ! 10: #ident "@(#)mailx:tty.c 1.9" ! 11: /* ! 12: * mailx -- a modified version of a University of California at Berkeley ! 13: * mail program ! 14: * ! 15: * Generally useful tty stuff. ! 16: */ ! 17: ! 18: #include "rcv.h" ! 19: ! 20: #ifdef USG_TTY ! 21: #include <sys/termio.h> ! 22: ! 23: static void Echo(); ! 24: static int countcol(); ! 25: static void outstr(); ! 26: static char *readtty(); ! 27: static void resetty(); ! 28: static void rubout(); ! 29: static int savetty(); ! 30: static int setty(); ! 31: ! 32: static int c_erase; /* Current erase char */ ! 33: static int c_kill; /* Current kill char */ ! 34: static int c_intr; /* interrupt char */ ! 35: static int c_quit; /* quit character */ ! 36: static int c_word; /* Current word erase char */ ! 37: static int Col; /* current output column */ ! 38: static int Pcol; /* end column of prompt string */ ! 39: static int Out; /* file descriptor of stdout */ ! 40: static struct termio savtty, ttybuf; ! 41: static char canonb[LINESIZE]; /* canonical buffer for input */ ! 42: /* processing */ ! 43: static int erasing; /* we are erasing characters */ ! 44: ! 45: #ifdef SIGCONT ! 46: # ifdef preSVr4 ! 47: typedef int sig_atomic_t; /* syntax, please -- adb */ ! 48: # endif ! 49: static sig_atomic_t hadcont; /* Saw continue signal */ ! 50: /*ARGSUSED*/ ! 51: static void ! 52: ttycont(s) ! 53: { ! 54: hadcont++; ! 55: } ! 56: ! 57: /*ARGSUSED*/ ! 58: static void ! 59: ttystop(s) ! 60: { ! 61: resetty(); ! 62: kill(mypid, SIGSTOP); ! 63: } ! 64: #endif ! 65: ! 66: /* ! 67: * Read all relevant header fields. ! 68: */ ! 69: ! 70: grabh(hp, gflags, subjtop) ! 71: register struct header *hp; ! 72: { ! 73: #ifdef SIGCONT ! 74: void (*savecont)(); ! 75: void (*savestop)(); ! 76: #endif ! 77: if (savetty()) ! 78: return -1; ! 79: #ifdef SIGCONT ! 80: # ifdef preSVr4 ! 81: savecont = sigset(SIGCONT, ttycont); ! 82: savestop = sigset(SIGTSTP, ttycont); ! 83: # else ! 84: { ! 85: struct sigaction nsig, osig; ! 86: nsig.sa_handler = ttycont; ! 87: sigemptyset(&nsig.sa_mask); ! 88: nsig.sa_flags = 0; ! 89: (void) sigaction(SIGCONT, &nsig, &osig); ! 90: savecont = osig.sa_handler; ! 91: nsig.sa_handler = ttystop; ! 92: sigemptyset(&nsig.sa_mask); ! 93: nsig.sa_flags = 0; ! 94: (void) sigaction(SIGTSTP, &nsig, &osig); ! 95: savestop = osig.sa_handler; ! 96: } ! 97: # endif ! 98: #endif ! 99: if (gflags & GSUBJECT && subjtop) { ! 100: hp->h_subject = readtty("Subject: ", hp->h_subject); ! 101: if (hp->h_subject != NOSTR) ! 102: hp->h_seq++; ! 103: } ! 104: if (gflags & GTO) { ! 105: hp->h_to = addto(NOSTR, readtty("To: ", hp->h_to)); ! 106: if (hp->h_to != NOSTR) ! 107: hp->h_seq++; ! 108: } ! 109: if (gflags & GCC) { ! 110: hp->h_cc = addto(NOSTR, readtty("Cc: ", hp->h_cc)); ! 111: if (hp->h_cc != NOSTR) ! 112: hp->h_seq++; ! 113: } ! 114: if (gflags & GBCC) { ! 115: hp->h_bcc = addto(NOSTR, readtty("Bcc: ", hp->h_bcc)); ! 116: if (hp->h_bcc != NOSTR) ! 117: hp->h_seq++; ! 118: } ! 119: if (gflags & GSUBJECT && !subjtop) { ! 120: hp->h_subject = readtty("Subject: ", hp->h_subject); ! 121: if (hp->h_subject != NOSTR) ! 122: hp->h_seq++; ! 123: } ! 124: #ifdef SIGCONT ! 125: # ifdef preSVr4 ! 126: (void) sigset(SIGCONT, savecont); ! 127: (void) sigset(SIGTSTP, savestop); ! 128: # else ! 129: { ! 130: struct sigaction nsig; ! 131: nsig.sa_handler = savecont; ! 132: sigemptyset(&nsig.sa_mask); ! 133: nsig.sa_flags = SA_RESTART; ! 134: (void) sigaction(SIGCONT, &nsig, (struct sigaction*)0); ! 135: nsig.sa_handler = savestop; ! 136: (void) sigaction(SIGTSTP, &nsig, (struct sigaction*)0); ! 137: } ! 138: # endif ! 139: #endif ! 140: return(0); ! 141: } ! 142: ! 143: /* ! 144: * Read up a header from standard input. ! 145: * The source string has the preliminary contents to ! 146: * be read. ! 147: * ! 148: */ ! 149: ! 150: static char * ! 151: readtty(pr, src) ! 152: char pr[], src[]; ! 153: { ! 154: int c; ! 155: register char *cp, *cp2; ! 156: ! 157: erasing = 0; ! 158: fflush(stdout); ! 159: Col = 0; ! 160: outstr(pr); ! 161: Pcol = Col; ! 162: if (src != NOSTR && strlen(src) > LINESIZE - 2) { ! 163: printf("too long to edit\n"); ! 164: return(src); ! 165: } ! 166: if (setty()) ! 167: return(src); ! 168: cp2 = src==NOSTR ? "" : src; ! 169: for (cp=canonb; *cp2; cp++, cp2++) ! 170: *cp = *cp2; ! 171: *cp = '\0'; ! 172: outstr(canonb); ! 173: ! 174: for (;;) { ! 175: fflush(stdout); ! 176: #ifdef SIGCONT ! 177: hadcont = 0; ! 178: #endif ! 179: c = getc(stdin); ! 180: ! 181: if (c==c_erase) { ! 182: if (cp > canonb) ! 183: if (cp[-1]=='\\' && !erasing) { ! 184: *cp++ = (char)c; ! 185: Echo(c); ! 186: } else { ! 187: rubout(--cp); ! 188: } ! 189: } else if (c==c_kill) { ! 190: if (cp > canonb && cp[-1]=='\\') { ! 191: *cp++ = (char)c; ! 192: Echo(c); ! 193: } else while (cp > canonb) { ! 194: rubout(--cp); ! 195: } ! 196: } else if (c==c_word) { ! 197: if (cp > canonb) ! 198: if (cp[-1]=='\\' && !erasing) { ! 199: *cp++ = (char)c; ! 200: Echo(c); ! 201: } else { ! 202: while (--cp >= canonb) ! 203: if (!isspace(*cp)) ! 204: break; ! 205: else ! 206: rubout(cp); ! 207: while (cp >= canonb) ! 208: if (!isspace(*cp)) ! 209: rubout(cp--); ! 210: else ! 211: break; ! 212: if (cp < canonb) ! 213: cp = canonb; ! 214: else if (*cp) ! 215: cp++; ! 216: } ! 217: } else if (c==EOF || ferror(stdin) || c==c_intr || c==c_quit) { ! 218: #ifdef SIGCONT ! 219: if (hadcont) { ! 220: (void) setty(); ! 221: outstr("(continue)\n"); ! 222: Col = 0; ! 223: outstr(pr); ! 224: *cp = '\0'; ! 225: outstr(canonb); ! 226: clearerr(stdin); ! 227: continue; ! 228: } ! 229: #endif ! 230: resetty(); ! 231: savedead(c==c_quit? SIGQUIT: SIGINT); ! 232: } else switch (c) { ! 233: case '\n': ! 234: case '\r': ! 235: resetty(); ! 236: putchar('\n'); ! 237: fflush(stdout); ! 238: if (canonb[0]=='\0') ! 239: return(NOSTR); ! 240: return(savestr(canonb)); ! 241: default: ! 242: erasing = 0; ! 243: *cp++ = (char)c; ! 244: *cp = '\0'; ! 245: Echo(c); ! 246: } ! 247: } ! 248: } ! 249: ! 250: static int ! 251: savetty() ! 252: { ! 253: Out = fileno(stdout); ! 254: if (ioctl(Out, TCGETA, &savtty) < 0) ! 255: { perror("ioctl"); ! 256: return(-1); ! 257: } ! 258: c_erase = savtty.c_cc[VERASE]; ! 259: c_kill = savtty.c_cc[VKILL]; ! 260: c_intr = savtty.c_cc[VINTR]; ! 261: c_quit = savtty.c_cc[VQUIT]; ! 262: c_word = 'W' & 037; /* erase word character */ ! 263: ttybuf = savtty; ! 264: #ifdef u370 ! 265: ttybuf.c_cflag &= ~PARENB; /* disable parity */ ! 266: ttybuf.c_cflag |= CS8; /* character size = 8 */ ! 267: #endif /* u370 */ ! 268: ttybuf.c_cc[VTIME] = 0; ! 269: ttybuf.c_cc[VMIN] = 1; ! 270: ttybuf.c_iflag &= ~(BRKINT); ! 271: ttybuf.c_lflag &= ~(ICANON|ISIG|ECHO); ! 272: return 0; ! 273: } ! 274: ! 275: static int ! 276: setty() ! 277: { ! 278: if (ioctl(Out, TCSETAW, &ttybuf) < 0) { ! 279: perror("ioctl"); ! 280: return(-1); ! 281: } ! 282: return(0); ! 283: } ! 284: ! 285: static void ! 286: resetty() ! 287: { ! 288: if (ioctl(Out, TCSETAW, &savtty) < 0) ! 289: perror("ioctl"); ! 290: } ! 291: ! 292: static void ! 293: outstr(s) ! 294: register char *s; ! 295: { ! 296: while (*s) ! 297: Echo(*s++); ! 298: } ! 299: ! 300: static void ! 301: rubout(cp) ! 302: register char *cp; ! 303: { ! 304: register int oldcol; ! 305: register int c = *cp; ! 306: ! 307: erasing = 1; ! 308: *cp = '\0'; ! 309: switch (c) { ! 310: case '\t': ! 311: oldcol = countcol(); ! 312: do ! 313: putchar('\b'); ! 314: while (--Col > oldcol); ! 315: break; ! 316: case '\b': ! 317: if (isprint(cp[-1])) ! 318: putchar(*(cp-1)); ! 319: else ! 320: putchar(' '); ! 321: Col++; ! 322: break; ! 323: default: ! 324: if (isprint(c)) { ! 325: fputs("\b \b", stdout); ! 326: Col--; ! 327: } ! 328: } ! 329: } ! 330: ! 331: static int ! 332: countcol() ! 333: { ! 334: register int col; ! 335: register char *s; ! 336: ! 337: for (col=Pcol, s=canonb; *s; s++) ! 338: switch (*s) { ! 339: case '\t': ! 340: while (++col % 8) ! 341: ; ! 342: break; ! 343: case '\b': ! 344: col--; ! 345: break; ! 346: default: ! 347: if (isprint(*s)) ! 348: col++; ! 349: } ! 350: return(col); ! 351: } ! 352: ! 353: static void ! 354: Echo(cc) ! 355: { ! 356: char c = (char)cc; ! 357: ! 358: switch (c) { ! 359: case '\t': ! 360: do ! 361: putchar(' '); ! 362: while (++Col % 8); ! 363: break; ! 364: case '\b': ! 365: if (Col > 0) { ! 366: putchar('\b'); ! 367: Col--; ! 368: } ! 369: break; ! 370: case '\r': ! 371: case '\n': ! 372: Col = 0; ! 373: fputs("\r\n", stdout); ! 374: break; ! 375: default: ! 376: if (isprint(c)) { ! 377: Col++; ! 378: putchar(c); ! 379: } ! 380: } ! 381: } ! 382: ! 383: getbaud() /* for compatibility with V9 -- adb */ ! 384: { ! 385: struct termio tbuf; ! 386: int baud; ! 387: ! 388: outtty = isatty(1); ! 389: if (ioctl(1, TCGETA, &tbuf)==0) ! 390: baud = tbuf.c_cflag & CBAUD; ! 391: else ! 392: baud = B9600; ! 393: if( baud < B1200 ) return(5); ! 394: else if (baud == B1200) return(10); ! 395: else return(20); ! 396: } ! 397: ! 398: /* end USG_TTY */ ! 399: #else ! 400: #include <sys/ttyio.h> ! 401: static int c_erase; /* Current erase char */ ! 402: static int c_kill; /* Current kill char */ ! 403: static int hadcont; /* Saw continue signal */ ! 404: static jmp_buf rewrite; /* Place to go when continued */ ! 405: #ifndef TIOCSTI ! 406: static int ttyset; /* We must now do erase/kill */ ! 407: #endif ! 408: static char *readtty(); /* adb */ ! 409: ! 410: /* ! 411: * Read all relevant header fields. ! 412: */ ! 413: ! 414: grabh(hp, gflags, subjtop) ! 415: struct header *hp; ! 416: { ! 417: struct sgttyb ttybuf; ! 418: void ttycont(), signull(); ! 419: void (*savecont)(); ! 420: register int s; ! 421: int errs; ! 422: #ifndef TIOCSTI ! 423: void (*savesigs[2])(); ! 424: #endif ! 425: ! 426: #ifdef SIGCONT ! 427: savecont = sigset(SIGCONT, signull); ! 428: #endif ! 429: errs = 0; ! 430: #ifndef TIOCSTI ! 431: ttyset = 0; ! 432: #endif ! 433: if (gtty(fileno(stdin), &ttybuf) < 0) { ! 434: perror("gtty"); ! 435: return(-1); ! 436: } ! 437: c_erase = ttybuf.sg_erase; ! 438: c_kill = ttybuf.sg_kill; ! 439: #ifndef TIOCSTI ! 440: ttybuf.sg_erase = 0; ! 441: ttybuf.sg_kill = 0; ! 442: for (s = SIGINT; s <= SIGQUIT; s++) ! 443: if ((savesigs[s-SIGINT] = sigset(s, SIG_IGN)) == (void (*)())SIG_DFL) /* adb */ ! 444: sigset(s, SIG_DFL); ! 445: #endif ! 446: if (gflags & GSUBJECT && subjtop) { ! 447: #ifndef TIOCSTI ! 448: if (!ttyset && hp->h_subject != NOSTR) ! 449: ttyset++, stty(fileno(stdin), &ttybuf); ! 450: #endif ! 451: hp->h_subject = readtty("Subject: ", hp->h_subject); ! 452: if (hp->h_subject != NOSTR) ! 453: hp->h_seq++; ! 454: } ! 455: if (gflags & GTO) { ! 456: #ifndef TIOCSTI ! 457: if (!ttyset && hp->h_to != NOSTR) ! 458: ttyset++, stty(fileno(stdin), &ttybuf); ! 459: #endif ! 460: hp->h_to = addto(NOSTR, readtty("To: ", hp->h_to)); ! 461: if (hp->h_to != NOSTR) ! 462: hp->h_seq++; ! 463: } ! 464: if (gflags & GCC) { ! 465: #ifndef TIOCSTI ! 466: if (!ttyset && hp->h_cc != NOSTR) ! 467: ttyset++, stty(fileno(stdin), &ttybuf); ! 468: #endif ! 469: hp->h_cc = addto(NOSTR, readtty("Cc: ", hp->h_cc)); ! 470: if (hp->h_cc != NOSTR) ! 471: hp->h_seq++; ! 472: } ! 473: if (gflags & GBCC) { ! 474: #ifndef TIOCSTI ! 475: if (!ttyset && hp->h_bcc != NOSTR) ! 476: ttyset++, stty(fileno(stdin), &ttybuf); ! 477: #endif ! 478: hp->h_bcc = addto(NOSTR, readtty("Bcc: ", hp->h_bcc)); ! 479: if (hp->h_bcc != NOSTR) ! 480: hp->h_seq++; ! 481: } ! 482: if (gflags & GSUBJECT && !subjtop) { ! 483: #ifndef TIOCSTI ! 484: if (!ttyset && hp->h_subject != NOSTR) ! 485: ttyset++, stty(fileno(stdin), &ttybuf); ! 486: #endif ! 487: hp->h_subject = readtty("Subject: ", hp->h_subject); ! 488: if (hp->h_subject != NOSTR) ! 489: hp->h_seq++; ! 490: } ! 491: #ifdef SIGCONT ! 492: sigset(SIGCONT, savecont); ! 493: #endif ! 494: #ifndef TIOCSTI ! 495: ttybuf.sg_erase = c_erase; ! 496: ttybuf.sg_kill = c_kill; ! 497: if (ttyset) ! 498: stty(fileno(stdin), &ttybuf); ! 499: for (s = SIGINT; s <= SIGQUIT; s++) ! 500: sigset(s, savesigs[s-SIGINT]); ! 501: #endif ! 502: return(errs); ! 503: } ! 504: ! 505: /* ! 506: * Read up a header from standard input. ! 507: * The source string has the preliminary contents to ! 508: * be read. ! 509: * ! 510: */ ! 511: ! 512: static char * ! 513: readtty(pr, src) ! 514: char pr[], src[]; ! 515: { ! 516: char canonb[LINESIZE]; ! 517: int c, ch; /* adb */ ! 518: void signull(); /* adb */ ! 519: register char *cp, *cp2; ! 520: ! 521: fputs(pr, stdout); ! 522: fflush(stdout); ! 523: if (src != NOSTR && strlen(src) > LINESIZE - 2) { ! 524: printf("too long to edit\n"); ! 525: return(src); ! 526: } ! 527: #ifndef TIOCSTI ! 528: if (src != NOSTR) ! 529: cp = copy(src, canonb); ! 530: else ! 531: cp = copy("", canonb); ! 532: fputs(canonb, stdout); ! 533: fflush(stdout); ! 534: #else ! 535: cp = src == NOSTR ? "" : src; ! 536: while (c = *cp++) { ! 537: if (c == c_erase || c == c_kill) { ! 538: ch = '\\'; ! 539: ioctl(0, TIOCSTI, &ch); ! 540: } ! 541: ioctl(0, TIOCSTI, &c); ! 542: } ! 543: cp = canonb; ! 544: *cp = 0; ! 545: #endif ! 546: cp2 = cp; ! 547: while (cp2 < canonb + LINESIZE) ! 548: *cp2++ = 0; ! 549: cp2 = cp; ! 550: if (setjmp(rewrite)) ! 551: goto redo; ! 552: #ifdef SIGCONT ! 553: sigset(SIGCONT, ttycont); ! 554: #endif ! 555: while (cp2 < canonb + LINESIZE) { ! 556: c = getc(stdin); ! 557: if (c == EOF || c == '\n') ! 558: break; ! 559: *cp2++ = c; ! 560: } ! 561: *cp2 = 0; ! 562: #ifdef SIGCONT ! 563: sigset(SIGCONT, signull); ! 564: #endif ! 565: if (c == EOF && ferror(stdin) && hadcont) { ! 566: redo: ! 567: hadcont = 0; ! 568: cp = strlen(canonb) > 0 ? canonb : NOSTR; ! 569: clearerr(stdin); ! 570: return(readtty(pr, cp)); ! 571: } ! 572: #ifndef TIOCSTI ! 573: if (cp == NOSTR || *cp == '\0') ! 574: return(src); ! 575: cp2 = cp; ! 576: if (!ttyset) ! 577: return(strlen(canonb) > 0 ? savestr(canonb) : NOSTR); ! 578: while (*cp != '\0') { ! 579: c = *cp++; ! 580: if (c == c_erase) { ! 581: if (cp2 == canonb) ! 582: continue; ! 583: if (cp2[-1] == '\\') { ! 584: cp2[-1] = c; ! 585: continue; ! 586: } ! 587: cp2--; ! 588: continue; ! 589: } ! 590: if (c == c_kill) { ! 591: if (cp2 == canonb) ! 592: continue; ! 593: if (cp2[-1] == '\\') { ! 594: cp2[-1] = c; ! 595: continue; ! 596: } ! 597: cp2 = canonb; ! 598: continue; ! 599: } ! 600: *cp2++ = c; ! 601: } ! 602: *cp2 = '\0'; ! 603: #endif ! 604: if (equal("", canonb)) ! 605: return(NOSTR); ! 606: return(savestr(canonb)); ! 607: } ! 608: ! 609: #ifdef SIGCONT ! 610: /* ! 611: * Receipt continuation. ! 612: */ ! 613: void ! 614: ttycont(s) ! 615: { ! 616: ! 617: hadcont++; ! 618: sigrelse(SIGCONT); ! 619: longjmp(rewrite, 1); ! 620: } ! 621: #endif ! 622: ! 623: /* following two functions added for V9 by adb */ ! 624: getbaud() ! 625: { ! 626: struct ttydevb tbuf; ! 627: int baud; ! 628: ! 629: outtty = isatty(1); ! 630: if (ioctl(1, TIOCGDEV, &tbuf)==0) ! 631: baud = tbuf.ospeed; ! 632: else ! 633: baud = B9600; ! 634: if( baud < B1200 ) return(5); ! 635: else if( baud == B1200) return(10); ! 636: else return(20); ! 637: } ! 638: ! 639: #ifdef TIOCGETP ! 640: gtty(i,buf) ! 641: int i; ! 642: struct sgttyb *buf; ! 643: { ! 644: return(ioctl(i,TIOCGETP,buf)); ! 645: } ! 646: stty(i,buf) ! 647: int i; ! 648: struct sgttyb *buf; ! 649: { ! 650: return(ioctl(i,TIOCSETP,buf)); ! 651: } ! 652: #endif /* TIOCGETP */ ! 653: ! 654: ! 655: /* ! 656: * Null routine to allow us to hold SIGCONT ! 657: */ ! 658: void ! 659: signull(s) ! 660: {} ! 661: #endif /* USG_TTY */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.