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