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