1 /* 2 * Copyright (c) 1984, 1985, 1986 by the Regents of the 3 * University of California and by Gregory Glenn Minshall. 4 * 5 * Permission to use, copy, modify, and distribute these 6 * programs and their documentation for any purpose and 7 * without fee is hereby granted, provided that this 8 * copyright and permission appear on all copies and 9 * supporting documentation, the name of the Regents of 10 * the University of California not be used in advertising 11 * or publicity pertaining to distribution of the programs 12 * without specific prior permission, and notice be given in 13 * supporting documentation that copying and distribution is 14 * by permission of the Regents of the University of California 15 * and by Gregory Glenn Minshall. Neither the Regents of the 16 * University of California nor Gregory Glenn Minshall make 17 * representations about the suitability of this software 18 * for any purpose. It is provided "as is" without 19 * express or implied warranty. 20 */ 21 22 #ifndef lint 23 static char sccsid[] = "@(#)outbound.c 3.1 10/29/86"; 24 #endif /* lint */ 25 26 27 #if defined(unix) 28 #include <signal.h> 29 #include <sgtty.h> 30 #endif 31 #include <stdio.h> 32 #include <curses.h> 33 34 #include "../general/general.h" 35 36 #include "terminal.h" 37 38 #include "../telnet.ext" 39 40 #include "../ascii/disp_asc.h" 41 42 #include "../ctlr/hostctlr.h" 43 #include "../ctlr/inbound.ext" 44 #include "../ctlr/oia.h" 45 #include "../ctlr/options.ext" 46 #include "../ctlr/outbound.ext" 47 #include "../ctlr/screen.h" 48 49 #include "../ascii/map3270.ext" 50 51 #include "../general/globals.h" 52 53 extern void EmptyTerminal(); 54 55 #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \ 56 terminalCursorAddress:UnLocked? CursorAddress: HighestScreen()) 57 58 59 static int terminalCursorAddress; /* where the cursor is on term */ 60 static int screenInitd; /* the screen has been initialized */ 61 static int screenStopped; /* the screen has been stopped */ 62 #if defined(SLOWSCREEN) 63 static int max_changes_before_poll; /* how many characters before looking */ 64 /* at terminal and net again */ 65 #endif /* defined(SLOWSCREEN) */ 66 67 static int needToRing; /* need to ring terinal bell */ 68 static char *bellSequence = "\07"; /* bell sequence (may be replaced by 69 * VB during initialization) 70 */ 71 static WINDOW *bellwin = 0; /* The window the bell message is in */ 72 int bellwinup = 0; /* Are we up with it or not */ 73 74 #if defined(unix) 75 static char *KS, *KE; 76 #endif /* defined(unix) */ 77 78 79 #if defined(SLOWSCREEN) 80 static int inHighlightMode = 0; 81 ScreenImage Terminal[MAXSCREENSIZE]; 82 #endif /* defined(SLOWSCREEN) */ 83 84 /* Variables for transparent mode */ 85 #if defined(unix) 86 static int tcflag = -1; /* transparent mode command flag */ 87 static int savefd[2]; /* for storing fds during transcom */ 88 extern int tin, tout; /* file descriptors */ 89 #endif /* defined(unix) */ 90 91 92 /* 93 * init_screen() 94 * 95 * Initialize variables used by screen. 96 */ 97 98 void 99 init_screen() 100 { 101 bellwinup = 0; 102 #if defined(SLOWSCREEN) 103 inHighlightMode = 0; 104 ClearArray(Terminal); 105 #endif /* defined(SLOWSCREEN) */ 106 } 107 108 109 /* OurExitString - designed to keep us from going through infinite recursion */ 110 111 static void 112 OurExitString(file, string, value) 113 FILE *file; 114 char *string; 115 int value; 116 { 117 static int recursion = 0; 118 119 if (!recursion) { 120 recursion = 1; 121 ExitString(file, string, value); 122 } 123 } 124 125 126 /* DoARefresh */ 127 128 static void 129 DoARefresh() 130 { 131 if (ERR == refresh()) { 132 OurExitString(stderr, "ERR from refresh\n", 1); 133 } 134 } 135 136 static void 137 GoAway(from, where) 138 char *from; /* routine that gave error */ 139 int where; /* cursor address */ 140 { 141 char foo[100]; 142 143 sprintf(foo, "ERR from %s at %d (%d, %d)\n", 144 from, where, ScreenLine(where), ScreenLineOffset(where)); 145 OurExitString(stderr, foo, 1); 146 /* NOTREACHED */ 147 } 148 149 #if defined(SLOWSCREEN) 150 /* What is the screen address of the attribute byte for the terminal */ 151 152 static int 153 WhereTermAttrByte(p) 154 register int p; 155 { 156 register int i; 157 158 i = p; 159 160 do { 161 if (TermIsStartField(i)) { 162 return(i); 163 } 164 i = ScreenDec(i); 165 } while (i != p); 166 167 return(LowestScreen()); /* unformatted screen... */ 168 } 169 #endif /* defined(SLOWSCREEN) */ 170 171 /* 172 * There are two algorithms for updating the screen. 173 * The first, SlowScreen() optimizes the line between the 174 * computer and the screen (say a 9600 baud line). To do 175 * this, we break out of the loop every so often to look 176 * at any pending input from the network (so that successive 177 * screens will only partially print until the final screen, 178 * the one the user possibly wants to see, is displayed 179 * in its entirety). 180 * 181 * The second algorithm tries to optimize CPU time (by 182 * being simpler) at the cost of the bandwidth to the 183 * screen. 184 * 185 * Of course, curses(3X) gets in here also. 186 */ 187 188 189 #if defined(SLOWSCREEN) 190 #if defined(NOT43) 191 static int 192 #else /* defined(NOT43) */ 193 static void 194 #endif /* defined(NOT43) */ 195 SlowScreen() 196 { 197 register int pointer; 198 register int c; 199 register int fieldattr; 200 register int columnsleft; 201 202 # define SetHighlightMode(p) { \ 203 if (!IsStartField(p) && IsHighlightedAttr(fieldattr)) { \ 204 if (!inHighlightMode) { \ 205 inHighlightMode = 1; \ 206 standout(); \ 207 } \ 208 } else { \ 209 if (inHighlightMode) { \ 210 inHighlightMode = 0; \ 211 standend(); \ 212 } \ 213 } \ 214 } 215 216 # define DoCharacterAt(c,p) { \ 217 SetTerminal(p, c); \ 218 if (p != HighestScreen()) { \ 219 c = TerminalCharacterAttr(disp_asc[c&0xff], p, \ 220 fieldattr); \ 221 if (terminalCursorAddress != p) { \ 222 if (ERR == mvaddch(ScreenLine(p), \ 223 ScreenLineOffset(p), c)) {\ 224 GoAway("mvaddch", p); \ 225 } \ 226 } else { \ 227 if (ERR == addch(c)) {\ 228 GoAway("addch", p); \ 229 } \ 230 } \ 231 terminalCursorAddress = ScreenInc(p); \ 232 } \ 233 } 234 235 236 /* run through screen, printing out non-null lines */ 237 238 /* There are two separate reasons for wanting to terminate this 239 * loop early. One is to respond to new input (either from 240 * the terminal or from the network [host]). For this reason, 241 * we expect to see 'HaveInput' come true when new input comes in. 242 * 243 * The second reason is a bit more difficult (for me) to understand. 244 * Basically, we don't want to get too far ahead of the characters that 245 * appear on the screen. Ideally, we would type out a few characters, 246 * wait until they appeared on the screen, then type out a few more. 247 * The reason for this is that the user, on seeing some characters 248 * appear on the screen may then start to type something. We would 249 * like to look at what the user types at about the same 'time' 250 * (measured by characters being sent to the terminal) that the 251 * user types them. For this reason, what we would like to do 252 * is update a bit, then call curses to do a refresh, flush the 253 * output to the terminal, then wait until the terminal data 254 * has been sent. 255 * 256 * Note that curses is useful for, among other things, deciding whether 257 * or not to send :ce: (clear to end of line), so we should call curses 258 * at end of lines (beginning of next lines). 259 * 260 * The problems here are the following: If we do lots of write(2)s, 261 * we will be doing lots of context switches, thus lots of overhead 262 * (which we have already). Second, if we do a select to wait for 263 * the output to drain, we have to contend with the fact that NOW 264 * we are scheduled to run, but who knows what the scheduler will 265 * decide when the output has caught up. 266 */ 267 268 if (Highest == HighestScreen()) { 269 Highest = ScreenDec(Highest); /* else, while loop will never end */ 270 } 271 if (Lowest < LowestScreen()) { 272 Lowest = LowestScreen(); /* could be -1 in some cases with 273 * unformatted screens. 274 */ 275 } 276 if (Highest >= (pointer = Lowest)) { 277 /* if there is anything to do, do it. We won't terminate 278 * the loop until we've gone at least to Highest. 279 */ 280 while ((pointer <= Highest) && !HaveInput) { 281 282 /* point at the next place of disagreement */ 283 pointer += (bunequal(Host+pointer, Terminal+pointer, 284 (Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]); 285 286 /* how many characters to change until the end of the 287 * current line 288 */ 289 columnsleft = NumberColumns - ScreenLineOffset(pointer); 290 /* 291 * Make sure we are where we think we are. 292 */ 293 move(ScreenLine(pointer), ScreenLineOffset(pointer)); 294 295 /* what is the field attribute of the current position */ 296 fieldattr = FieldAttributes(WhereAttrByte(pointer)); 297 298 if ((IsStartField(pointer) != TermIsStartField(pointer)) || 299 (IsStartField(pointer) && 300 fieldattr != TermAttributes(pointer))) { 301 302 int oldterm; 303 304 oldterm = TermAttributes(pointer); 305 if (IsStartField(pointer)) { 306 TermNewField(pointer, fieldattr); 307 SetTerminal(pointer, 0); 308 } else { 309 TermDeleteField(pointer); 310 } 311 /* We always do the first character in a divergent 312 * field, since otherwise the start of a field in 313 * the Host structure may leave a highlighted blank 314 * on the screen, and the start of a field in the 315 * Terminal structure may leave a non-highlighted 316 * something in the middle of a highlighted field 317 * on the screen. 318 */ 319 SetHighlightMode(pointer); 320 c = GetHost(pointer); 321 DoCharacterAt(c,pointer); /* MACRO */ 322 323 if (NotVisuallyCompatibleAttributes 324 (pointer, fieldattr, oldterm)) { 325 int j; 326 327 j = pointer; 328 329 pointer = ScreenInc(pointer); 330 if (!(--columnsleft)) { 331 DoARefresh(); 332 EmptyTerminal(); 333 move(ScreenLine(pointer), 0); 334 columnsleft = NumberColumns; 335 } 336 SetHighlightMode(pointer); /* Turn on highlighting */ 337 while (!IsStartField(pointer) && 338 !TermIsStartField(pointer)) { 339 c = GetHost(pointer); 340 DoCharacterAt(c,pointer); /* MACRO */ 341 pointer = ScreenInc(pointer); 342 if (!(--columnsleft)) { 343 DoARefresh(); 344 EmptyTerminal(); 345 move(ScreenLine(pointer), 0); 346 columnsleft = NumberColumns; 347 /* We don't look at HaveInput here, since 348 * if we leave this loop before the end of 349 * the 3270 field, we could have pointer 350 * higher than Highest. This would cause 351 * us to end the highest "while" loop, 352 * but we may, in fact, need to go around the 353 * screen once again. 354 */ 355 } 356 /* The loop needs to be protected 357 * from the situation where there had been only 358 * one field on the Terminal, and none on the Host. 359 * In this case, we have just deleted our last 360 * field. Hence, the break. 361 */ 362 if (j == pointer) { 363 break; 364 } 365 } 366 if (IsStartField(pointer) && !TermIsStartField(pointer)) { 367 /* Remember what the terminal looked like */ 368 TermNewField(pointer, oldterm); 369 /* 370 * The danger here is that the current position may 371 * be the start of a Host field. If so, and the 372 * field is highlighted, and our terminal was 373 * highlighted, then we will leave a highlighted 374 * blank at this position. 375 */ 376 SetHighlightMode(pointer); 377 c = GetHost(pointer); 378 DoCharacterAt(c,pointer); 379 } 380 /* We could be in the situation of needing to exit. 381 * This could happen if the current field wrapped around 382 * the end of the screen. 383 */ 384 if (j > pointer) { 385 break; 386 } 387 } else { 388 c = GetHost(pointer); 389 /* We always do the first character in a divergent 390 * field, since otherwise the start of a field in 391 * the Host structure may leave a highlighted blank 392 * on the screen, and the start of a field in the 393 * Terminal structure may leave a non-highlighted 394 * something in the middle of a highlighted field 395 * on the screen. 396 */ 397 SetHighlightMode(pointer); 398 DoCharacterAt(c,pointer); 399 } 400 } else { 401 SetHighlightMode(pointer); 402 /* 403 * The following will terminate at least when we get back 404 * to the original 'pointer' location (since we force 405 * things to be equal). 406 */ 407 while (((c = GetHost(pointer)) != GetTerminal(pointer)) && 408 !IsStartField(pointer) && !TermIsStartField(pointer)) { 409 DoCharacterAt(c, pointer); 410 pointer = ScreenInc(pointer); 411 if (!(--columnsleft)) { 412 DoARefresh(); 413 EmptyTerminal(); 414 if (HaveInput) { /* if input came in, take it */ 415 break; 416 } 417 move(ScreenLine(pointer), 0); 418 columnsleft = NumberColumns; 419 } 420 } 421 } 422 } 423 } 424 DoARefresh(); 425 Lowest = pointer; 426 if (Lowest > Highest) { /* if we finished input... */ 427 Lowest = HighestScreen()+1; 428 Highest = LowestScreen()-1; 429 terminalCursorAddress = CorrectTerminalCursor(); 430 if (ERR == move(ScreenLine(terminalCursorAddress), 431 ScreenLineOffset(terminalCursorAddress))) { 432 GoAway("move", terminalCursorAddress); 433 } 434 DoARefresh(); 435 if (needToRing) { 436 StringToTerminal(bellSequence); 437 needToRing = 0; 438 } 439 } 440 EmptyTerminal(); /* move data along */ 441 return; 442 } 443 #endif /* defined(SLOWSCREEN) */ 444 445 #if defined(NOT43) 446 static int 447 #else /* defined(NOT43) */ 448 static void 449 #endif /* defined(NOT43) */ 450 FastScreen() 451 { 452 #if defined(MSDOS) 453 #define SaveCorner 0 454 #else /* defined(MSDOS) */ 455 #define SaveCorner 1 456 #endif /* defined(MSDOS) */ 457 458 #define DoAttribute(a) if (IsHighlightedAttr(a)) { \ 459 standout(); \ 460 } else { \ 461 standend(); \ 462 } \ 463 if (IsNonDisplayAttr(a)) { \ 464 a = 0; /* zero == don't display */ \ 465 } \ 466 if (!FormattedScreen()) { \ 467 a = 1; /* one ==> do display on unformatted */\ 468 } 469 ScreenImage *p, *upper; 470 int fieldattr; /* spends most of its time == 0 or 1 */ 471 472 /* OK. We want to do this a quickly as possible. So, we assume we 473 * only need to go from Lowest to Highest. However, if we find a 474 * field in the middle, we do the whole screen. 475 * 476 * In particular, we separate out the two cases from the beginning. 477 */ 478 if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) { 479 register int columnsleft; 480 481 move(ScreenLine(Lowest), ScreenLineOffset(Lowest)); 482 p = &Host[Lowest]; 483 #if !defined(MSDOS) 484 if (Highest == HighestScreen()) { 485 Highest = ScreenDec(Highest); 486 } 487 #endif /* !defined(MSDOS) */ 488 upper = &Host[Highest]; 489 fieldattr = FieldAttributes(Lowest); 490 DoAttribute(fieldattr); /* Set standout, non-display status */ 491 columnsleft = NumberColumns-ScreenLineOffset(p-Host); 492 493 while (p <= upper) { 494 if (IsStartFieldPointer(p)) { /* New field? */ 495 Highest = HighestScreen(); 496 Lowest = LowestScreen(); 497 FastScreen(); /* Recurse */ 498 return; 499 } else if (fieldattr) { /* Should we display? */ 500 /* Display translated data */ 501 addch(disp_asc[GetTerminalPointer(p)]); 502 } else { 503 addch(' '); /* Display a blank */ 504 } 505 /* If the physical screen is larger than what we 506 * are using, we need to make sure that each line 507 * starts at the beginning of the line. Otherwise, 508 * we will just string all the lines together. 509 */ 510 p++; 511 if (--columnsleft == 0) { 512 int i = p-Host; 513 514 move(ScreenLine(i), 0); 515 columnsleft = NumberColumns; 516 } 517 } 518 } else { /* Going from Lowest to Highest */ 519 unsigned char tmpbuf[MAXNUMBERCOLUMNS+1]; 520 ScreenImage *End = &Host[ScreenSize]-1-SaveCorner; 521 register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns; 522 523 *tmpend = 0; /* terminate from the beginning */ 524 move(0,0); 525 p = Host; 526 fieldattr = FieldAttributes(LowestScreen()); 527 DoAttribute(fieldattr); /* Set standout, non-display status */ 528 529 while (p <= End) { 530 if (IsStartFieldPointer(p)) { /* New field? */ 531 if (tmp != tmpbuf) { 532 *tmp++ = 0; /* close out */ 533 addstr(tmpbuf); 534 tmp = tmpbuf; 535 tmpend = tmpbuf + NumberColumns - ScreenLineOffset(p-Host); 536 } 537 fieldattr = FieldAttributesPointer(p); /* Get attributes */ 538 DoAttribute(fieldattr); /* Set standout, non-display */ 539 *tmp++ = ' '; 540 } else { 541 if (fieldattr) { /* Should we display? */ 542 /* Display translated data */ 543 *tmp++ = disp_asc[GetTerminalPointer(p)]; 544 } else { 545 *tmp++ = ' '; 546 } 547 } 548 /* If the physical screen is larger than what we 549 * are using, we need to make sure that each line 550 * starts at the beginning of the line. Otherwise, 551 * we will just string all the lines together. 552 */ 553 p++; 554 if (tmp == tmpend) { 555 int i = p-Host; /* Be sure the "p++" happened first! */ 556 557 *tmp++ = 0; 558 addstr(tmpbuf); 559 tmp = tmpbuf; 560 move(ScreenLine(i), 0); 561 tmpend = tmpbuf + NumberColumns; 562 } 563 } 564 if (tmp != tmpbuf) { 565 *tmp++ = 0; 566 addstr(tmpbuf); 567 tmp = tmpbuf; 568 } 569 } 570 Lowest = HighestScreen()+1; 571 Highest = LowestScreen()-1; 572 terminalCursorAddress = CorrectTerminalCursor(); 573 if (ERR == move(ScreenLine(terminalCursorAddress), 574 ScreenLineOffset(terminalCursorAddress))) { 575 GoAway("move", terminalCursorAddress); 576 } 577 DoARefresh(); 578 if (needToRing) { 579 StringToTerminal(bellSequence); 580 needToRing = 0; 581 } 582 EmptyTerminal(); /* move data along */ 583 return; 584 } 585 586 587 /* TryToSend - send data out to user's terminal */ 588 589 #if defined(NOT43) 590 int 591 #else /* defined(NOT43) */ 592 void 593 #endif /* defined(NOT43) */ 594 (*TryToSend)() = FastScreen; 595 596 void 597 ScreenOIA(oia) 598 OIA *oia; 599 { 600 } 601 602 603 /* InitTerminal - called to initialize the screen, etc. */ 604 605 void 606 InitTerminal() 607 { 608 #if defined(unix) 609 struct sgttyb ourttyb; 610 static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 611 2400, 4800, 9600 }; 612 #endif 613 614 InitMapping(); /* Go do mapping file (MAP3270) first */ 615 if (!screenInitd) { /* not initialized */ 616 #if defined(unix) 617 char KSEbuffer[2050]; 618 char *lotsofspace = KSEbuffer; 619 extern int abort(); 620 extern char *tgetstr(); 621 #endif /* defined(unix) */ 622 623 #if defined(SLOWSCREEN) 624 ClearArray(Terminal); 625 #endif /* defined(SLOWSCREEN) */ 626 terminalCursorAddress = SetBufferAddress(0,0); 627 #if defined(unix) 628 signal(SIGHUP, abort); 629 #endif 630 631 TryToSend = FastScreen; 632 #if defined(unix) && defined(SLOWSCREEN) 633 ioctl(1, TIOCGETP, (char *) &ourttyb); 634 if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) { 635 max_changes_before_poll = 1920; 636 } else { 637 max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10; 638 if (max_changes_before_poll < 40) { 639 max_changes_before_poll = 40; 640 } 641 TryToSend = SlowScreen; 642 HaveInput = 1; /* get signals going */ 643 } 644 #endif /* defined(unix) && defined(SLOWSCREEN) */ 645 setcommandmode(); 646 /* 647 * By now, initscr() (in curses) has been called (from telnet.c), 648 * and the screen has been initialized. 649 */ 650 #if defined(unix) 651 nonl(); 652 /* the problem is that curses catches SIGTSTP to 653 * be nice, but it messes us up. 654 */ 655 signal(SIGTSTP, SIG_DFL); 656 if ((KS = tgetstr("ks", &lotsofspace)) != 0) { 657 KS = strsave(KS); 658 StringToTerminal(KS); 659 } 660 if ((KE = tgetstr("ke", &lotsofspace)) != 0) { 661 KE = strsave(KE); 662 } 663 if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) { 664 SO = strsave(tgetstr("md", &lotsofspace)); 665 SE = strsave(tgetstr("me", &lotsofspace)); 666 } 667 #endif 668 DoARefresh(); 669 setconnmode(); 670 if (VB && *VB) { 671 bellSequence = VB; /* use visual bell */ 672 } 673 screenInitd = 1; 674 screenStopped = 0; /* Not stopped */ 675 } 676 Initialized = 1; 677 } 678 679 680 /* StopScreen - called when we are going away... */ 681 682 void 683 StopScreen(doNewLine) 684 int doNewLine; 685 { 686 if (screenInitd && !screenStopped) { 687 move(NumberLines-1, 1); 688 standend(); 689 #if defined(SLOWSCREEN) 690 inHighlightMode = 0; 691 #endif /* defined(SLOWSCREEN) */ 692 DoARefresh(); 693 setcommandmode(); 694 endwin(); 695 setconnmode(); 696 #if defined(unix) 697 if (KE) { 698 StringToTerminal(KE); 699 } 700 #endif /* defined(unix) */ 701 if (doNewLine) { 702 StringToTerminal("\r\n"); 703 } 704 EmptyTerminal(); 705 screenStopped = 1; /* This is stopped */ 706 } 707 } 708 709 710 /* RefreshScreen - called to cause the screen to be refreshed */ 711 712 void 713 RefreshScreen() 714 { 715 clearok(curscr, TRUE); 716 (*TryToSend)(); 717 } 718 719 720 /* ConnectScreen - called to reconnect to the screen */ 721 722 void 723 ConnectScreen() 724 { 725 if (screenInitd) { 726 #if defined(unix) 727 if (KS) { 728 StringToTerminal(KS); 729 } 730 #endif /* defined(unix) */ 731 RefreshScreen(); 732 (*TryToSend)(); 733 screenStopped = 0; 734 } 735 } 736 737 /* LocalClearScreen() - clear the whole ball of wax, cheaply */ 738 739 void 740 LocalClearScreen() 741 { 742 outputPurge(); /* flush all data to terminal */ 743 clear(); /* clear in curses */ 744 #if defined(SLOWSCREEN) 745 ClearArray(Terminal); 746 #endif /* defined(SLOWSCREEN) */ 747 Clear3270(); 748 Lowest = HighestScreen()+1; /* everything in sync... */ 749 Highest = LowestScreen()+1; 750 } 751 752 753 void 754 BellOff() 755 { 756 if (bellwinup) { 757 delwin(bellwin); 758 bellwin = 0; 759 bellwinup = 0; 760 Lowest = MIN(Lowest, LINES/2); 761 Highest = MAX(Highest, (LINES/2)+3); 762 #if defined(SLOWSCREEN) 763 memset((char *)(Terminal+LINES/2), 0, (sizeof Terminal[0])*(3*COLS)); 764 #endif /* defined(SLOWSCREEN) */ 765 touchwin(stdscr); 766 DoARefresh(); 767 } 768 } 769 770 771 void 772 RingBell(s) 773 char *s; 774 { 775 needToRing = 1; 776 if (s) { 777 int len = strlen(s); 778 779 if (len > COLS-2) { 780 len = COLS-2; 781 } 782 if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) { 783 OurExitString(stderr, "Error from newwin in RingBell", 1); 784 } 785 werase(bellwin); 786 wstandout(bellwin); 787 box(bellwin, '|', '-'); 788 if (wmove(bellwin, 1, 1) == ERR) { 789 OurExitString(stderr, "Error from wmove in RingBell", 1); 790 } 791 while (len--) { 792 if (waddch(bellwin, *s++) == ERR) { 793 OurExitString(stderr, "Error from waddch in RingBell", 1); 794 } 795 } 796 wstandend(bellwin); 797 if (wrefresh(bellwin) == ERR) { 798 OurExitString(stderr, "Error from wrefresh in RingBell", 1); 799 } 800 bellwinup = 1; 801 } 802 } 803 804 805 /* returns a 1 if no more output available (so, go ahead and block), 806 or a 0 if there is more output available (so, just poll the other 807 sources/destinations, don't block). 808 */ 809 810 int 811 DoTerminalOutput() 812 { 813 /* called just before a select to conserve IO to terminal */ 814 if (!Initialized) { 815 return 1; /* No output if not initialized */ 816 } 817 if ((Lowest <= Highest) || needToRing || 818 (terminalCursorAddress != CorrectTerminalCursor())) { 819 (*TryToSend)(); 820 } 821 if (Lowest > Highest) { 822 return 1; /* no more output now */ 823 } else { 824 return 0; /* more output for future */ 825 } 826 } 827 828 /* 829 * The following are defined to handle transparent data. 830 */ 831 832 void 833 TransStop() 834 { 835 #if defined(unix) 836 if (tcflag == 0) { 837 tcflag = -1; 838 (void) signal(SIGCHLD, SIG_DFL); 839 } else if (tcflag > 0) { 840 setcommandmode(); 841 (void) close(tin); 842 (void) close(tout); 843 tin = savefd[0]; 844 tout = savefd[1]; 845 setconnmode(); 846 tcflag = -1; 847 (void) signal(SIGCHLD, SIG_DFL); 848 } 849 #endif /* defined(unix) */ 850 RefreshScreen(); 851 } 852 853 void 854 TransOut(buffer, count) 855 unsigned char *buffer; 856 int count; 857 { 858 #if defined(unix) 859 extern char *transcom; 860 int inpipefd[2], outpipefd[2], savemode; 861 void aborttc(); 862 #endif /* defined(unix) */ 863 864 while (DoTerminalOutput() == 0) { 865 #if defined(unix) 866 HaveInput = 0; 867 #endif /* defined(unix) */ 868 } 869 #if defined(unix) 870 if (transcom && tcflag == -1) { 871 while (1) { /* go thru once */ 872 if (pipe(outpipefd) < 0) { 873 break; 874 } 875 if (pipe(inpipefd) < 0) { 876 break; 877 } 878 if ((tcflag = fork()) == 0) { 879 (void) close(outpipefd[1]); 880 (void) close(0); 881 if (dup(outpipefd[0]) < 0) { 882 exit(1); 883 } 884 (void) close(outpipefd[0]); 885 (void) close(inpipefd[0]); 886 (void) close(1); 887 if (dup(inpipefd[1]) < 0) { 888 exit(1); 889 } 890 (void) close(inpipefd[1]); 891 if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) { 892 exit(1); 893 } 894 } 895 (void) close(inpipefd[1]); 896 (void) close(outpipefd[0]); 897 savefd[0] = tin; 898 savefd[1] = tout; 899 setcommandmode(); 900 tin = inpipefd[0]; 901 tout = outpipefd[1]; 902 (void) signal(SIGCHLD, aborttc); 903 setconnmode(); 904 tcflag = 1; 905 break; 906 } 907 if (tcflag < 1) { 908 tcflag = 0; 909 } 910 } 911 #endif /* defined(unix) */ 912 (void) DataToTerminal(buffer, count); 913 } 914 915 916 #if defined(unix) 917 static void 918 aborttc() 919 { 920 int savemode; 921 922 setcommandmode(); 923 (void) close(tin); 924 (void) close(tout); 925 tin = savefd[0]; 926 tout = savefd[1]; 927 setconnmode(); 928 tcflag = 0; 929 } 930 #endif /* defined(unix) */ 931