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