130043Sminshall /* 2*33810Sbostic * Copyright (c) 1988 Regents of the University of California. 3*33810Sbostic * All rights reserved. 430043Sminshall * 5*33810Sbostic * Redistribution and use in source and binary forms are permitted 6*33810Sbostic * provided that this notice is preserved and that due credit is given 7*33810Sbostic * to the University of California at Berkeley. The name of the University 8*33810Sbostic * may not be used to endorse or promote products derived from this 9*33810Sbostic * software without specific prior written permission. This software 10*33810Sbostic * is provided ``as is'' without express or implied warranty. 1130043Sminshall */ 1230043Sminshall 1330043Sminshall #ifndef lint 14*33810Sbostic static char sccsid[] = "@(#)termout.c 3.2 (Berkeley) 03/28/88"; 15*33810Sbostic #endif /* not lint */ 1630043Sminshall 1730043Sminshall #if defined(unix) 1830043Sminshall #include <signal.h> 1930043Sminshall #include <sgtty.h> 2030043Sminshall #endif 2130043Sminshall #include <stdio.h> 2230043Sminshall #include <curses.h> 2330043Sminshall 2431179Sminshall #include "../general/general.h" 2531071Sminshall 2630043Sminshall #include "terminal.h" 2730043Sminshall 2830043Sminshall #include "../telnet.ext" 2930043Sminshall 3031873Sminshall #include "../api/disp_asc.h" 3131224Sminshall 3230043Sminshall #include "../ctlr/hostctlr.h" 3330043Sminshall #include "../ctlr/inbound.ext" 3431127Sminshall #include "../ctlr/oia.h" 3530043Sminshall #include "../ctlr/options.ext" 3630043Sminshall #include "../ctlr/outbound.ext" 3730043Sminshall #include "../ctlr/screen.h" 3830043Sminshall 3931179Sminshall #include "../ascii/map3270.ext" 4030043Sminshall 4131179Sminshall #include "../general/globals.h" 4230043Sminshall 4330043Sminshall extern void EmptyTerminal(); 4430043Sminshall 4530043Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \ 4631839Sminshall CursorAddress:UnLocked? CursorAddress: HighestScreen()) 4730043Sminshall 4830043Sminshall 4930328Sminshall static int terminalCursorAddress; /* where the cursor is on term */ 5030328Sminshall static int screenInitd; /* the screen has been initialized */ 5130328Sminshall static int screenStopped; /* the screen has been stopped */ 5230043Sminshall static int max_changes_before_poll; /* how many characters before looking */ 5330043Sminshall /* at terminal and net again */ 5430043Sminshall 5530328Sminshall static int needToRing; /* need to ring terinal bell */ 5630043Sminshall static char *bellSequence = "\07"; /* bell sequence (may be replaced by 5730043Sminshall * VB during initialization) 5830043Sminshall */ 5930328Sminshall static WINDOW *bellwin = 0; /* The window the bell message is in */ 6030043Sminshall int bellwinup = 0; /* Are we up with it or not */ 6130043Sminshall 6230043Sminshall #if defined(unix) 6330043Sminshall static char *KS, *KE; 6430043Sminshall #endif /* defined(unix) */ 6530043Sminshall 6630074Sminshall 6730074Sminshall static int inHighlightMode = 0; 6831071Sminshall ScreenImage Terminal[MAXSCREENSIZE]; 6930074Sminshall 7030074Sminshall /* Variables for transparent mode */ 7130043Sminshall #if defined(unix) 7230043Sminshall static int tcflag = -1; /* transparent mode command flag */ 7330043Sminshall static int savefd[2]; /* for storing fds during transcom */ 7430074Sminshall extern int tin, tout; /* file descriptors */ 7530043Sminshall #endif /* defined(unix) */ 7630043Sminshall 7730730Sminshall 7830730Sminshall /* 7930730Sminshall * init_screen() 8030730Sminshall * 8130730Sminshall * Initialize variables used by screen. 8230730Sminshall */ 8330730Sminshall 8430730Sminshall void 8530730Sminshall init_screen() 8630730Sminshall { 8730730Sminshall bellwinup = 0; 8830730Sminshall inHighlightMode = 0; 8931071Sminshall ClearArray(Terminal); 9030730Sminshall } 9130730Sminshall 9230730Sminshall 9330043Sminshall /* OurExitString - designed to keep us from going through infinite recursion */ 9430043Sminshall 9530043Sminshall static void 9630043Sminshall OurExitString(file, string, value) 9730043Sminshall FILE *file; 9830043Sminshall char *string; 9930043Sminshall int value; 10030043Sminshall { 10130043Sminshall static int recursion = 0; 10230043Sminshall 10330043Sminshall if (!recursion) { 10430043Sminshall recursion = 1; 10530043Sminshall ExitString(file, string, value); 10630043Sminshall } 10730043Sminshall } 10830043Sminshall 10930043Sminshall 11030043Sminshall /* DoARefresh */ 11130043Sminshall 11230043Sminshall static void 11330043Sminshall DoARefresh() 11430043Sminshall { 11530043Sminshall if (ERR == refresh()) { 11630043Sminshall OurExitString(stderr, "ERR from refresh\n", 1); 11730043Sminshall } 11830043Sminshall } 11930043Sminshall 12030043Sminshall static void 12130043Sminshall GoAway(from, where) 12230043Sminshall char *from; /* routine that gave error */ 12330043Sminshall int where; /* cursor address */ 12430043Sminshall { 12530043Sminshall char foo[100]; 12630043Sminshall 12730043Sminshall sprintf(foo, "ERR from %s at %d (%d, %d)\n", 12830043Sminshall from, where, ScreenLine(where), ScreenLineOffset(where)); 12930043Sminshall OurExitString(stderr, foo, 1); 13030043Sminshall /* NOTREACHED */ 13130043Sminshall } 13230043Sminshall 13330043Sminshall /* What is the screen address of the attribute byte for the terminal */ 13430043Sminshall 13530043Sminshall static int 13630043Sminshall WhereTermAttrByte(p) 13730043Sminshall register int p; 13830043Sminshall { 13930043Sminshall register int i; 14030043Sminshall 14130043Sminshall i = p; 14230043Sminshall 14330043Sminshall do { 14430043Sminshall if (TermIsStartField(i)) { 14530043Sminshall return(i); 14630043Sminshall } 14730043Sminshall i = ScreenDec(i); 14830043Sminshall } while (i != p); 14930043Sminshall 15030043Sminshall return(LowestScreen()); /* unformatted screen... */ 15130043Sminshall } 15230043Sminshall 15330043Sminshall /* 15430043Sminshall * There are two algorithms for updating the screen. 15530043Sminshall * The first, SlowScreen() optimizes the line between the 15630043Sminshall * computer and the screen (say a 9600 baud line). To do 15730043Sminshall * this, we break out of the loop every so often to look 15830043Sminshall * at any pending input from the network (so that successive 15930043Sminshall * screens will only partially print until the final screen, 16030043Sminshall * the one the user possibly wants to see, is displayed 16130043Sminshall * in its entirety). 16230043Sminshall * 16330043Sminshall * The second algorithm tries to optimize CPU time (by 16430043Sminshall * being simpler) at the cost of the bandwidth to the 16530043Sminshall * screen. 16630043Sminshall * 16730043Sminshall * Of course, curses(3X) gets in here also. 16830043Sminshall */ 16930043Sminshall 17030043Sminshall 17130043Sminshall #if defined(NOT43) 17230043Sminshall static int 17330043Sminshall #else /* defined(NOT43) */ 17430043Sminshall static void 17530043Sminshall #endif /* defined(NOT43) */ 17630043Sminshall SlowScreen() 17730043Sminshall { 17830043Sminshall register int pointer; 17930043Sminshall register int c; 18030043Sminshall register int fieldattr; 18130043Sminshall register int columnsleft; 18230043Sminshall 18330043Sminshall # define SetHighlightMode(p) { \ 18430043Sminshall if (!IsStartField(p) && IsHighlightedAttr(fieldattr)) { \ 18530043Sminshall if (!inHighlightMode) { \ 18630043Sminshall inHighlightMode = 1; \ 18730043Sminshall standout(); \ 18830043Sminshall } \ 18930043Sminshall } else { \ 19030043Sminshall if (inHighlightMode) { \ 19130043Sminshall inHighlightMode = 0; \ 19230043Sminshall standend(); \ 19330043Sminshall } \ 19430043Sminshall } \ 19530043Sminshall } 19630043Sminshall 19730043Sminshall # define DoCharacterAt(c,p) { \ 19830043Sminshall SetTerminal(p, c); \ 19930043Sminshall if (p != HighestScreen()) { \ 20030043Sminshall c = TerminalCharacterAttr(disp_asc[c&0xff], p, \ 20130043Sminshall fieldattr); \ 20230043Sminshall if (terminalCursorAddress != p) { \ 20330043Sminshall if (ERR == mvaddch(ScreenLine(p), \ 20430043Sminshall ScreenLineOffset(p), c)) {\ 20530043Sminshall GoAway("mvaddch", p); \ 20630043Sminshall } \ 20730043Sminshall } else { \ 20830043Sminshall if (ERR == addch(c)) {\ 20930043Sminshall GoAway("addch", p); \ 21030043Sminshall } \ 21130043Sminshall } \ 21230043Sminshall terminalCursorAddress = ScreenInc(p); \ 21330043Sminshall } \ 21430043Sminshall } 21530043Sminshall 21630043Sminshall 21730043Sminshall /* run through screen, printing out non-null lines */ 21830043Sminshall 21930043Sminshall /* There are two separate reasons for wanting to terminate this 22030043Sminshall * loop early. One is to respond to new input (either from 22130043Sminshall * the terminal or from the network [host]). For this reason, 22230043Sminshall * we expect to see 'HaveInput' come true when new input comes in. 22330043Sminshall * 22430043Sminshall * The second reason is a bit more difficult (for me) to understand. 22530043Sminshall * Basically, we don't want to get too far ahead of the characters that 22630043Sminshall * appear on the screen. Ideally, we would type out a few characters, 22730043Sminshall * wait until they appeared on the screen, then type out a few more. 22830043Sminshall * The reason for this is that the user, on seeing some characters 22930043Sminshall * appear on the screen may then start to type something. We would 23030043Sminshall * like to look at what the user types at about the same 'time' 23130043Sminshall * (measured by characters being sent to the terminal) that the 23230043Sminshall * user types them. For this reason, what we would like to do 23330043Sminshall * is update a bit, then call curses to do a refresh, flush the 23430043Sminshall * output to the terminal, then wait until the terminal data 23530043Sminshall * has been sent. 23630043Sminshall * 23730043Sminshall * Note that curses is useful for, among other things, deciding whether 23830043Sminshall * or not to send :ce: (clear to end of line), so we should call curses 23930043Sminshall * at end of lines (beginning of next lines). 24030043Sminshall * 24130043Sminshall * The problems here are the following: If we do lots of write(2)s, 24230043Sminshall * we will be doing lots of context switches, thus lots of overhead 24330043Sminshall * (which we have already). Second, if we do a select to wait for 24430043Sminshall * the output to drain, we have to contend with the fact that NOW 24530043Sminshall * we are scheduled to run, but who knows what the scheduler will 24630043Sminshall * decide when the output has caught up. 24730043Sminshall */ 24830043Sminshall 24930043Sminshall if (Highest == HighestScreen()) { 25030043Sminshall Highest = ScreenDec(Highest); /* else, while loop will never end */ 25130043Sminshall } 25230043Sminshall if (Lowest < LowestScreen()) { 25330043Sminshall Lowest = LowestScreen(); /* could be -1 in some cases with 25430043Sminshall * unformatted screens. 25530043Sminshall */ 25630043Sminshall } 25730043Sminshall if (Highest >= (pointer = Lowest)) { 25830043Sminshall /* if there is anything to do, do it. We won't terminate 25930043Sminshall * the loop until we've gone at least to Highest. 26030043Sminshall */ 26130043Sminshall while ((pointer <= Highest) && !HaveInput) { 26230043Sminshall 26330043Sminshall /* point at the next place of disagreement */ 26430043Sminshall pointer += (bunequal(Host+pointer, Terminal+pointer, 26530043Sminshall (Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]); 26630043Sminshall 26730043Sminshall /* how many characters to change until the end of the 26830043Sminshall * current line 26930043Sminshall */ 27030043Sminshall columnsleft = NumberColumns - ScreenLineOffset(pointer); 27130043Sminshall /* 27230043Sminshall * Make sure we are where we think we are. 27330043Sminshall */ 27430043Sminshall move(ScreenLine(pointer), ScreenLineOffset(pointer)); 27530043Sminshall 27630043Sminshall /* what is the field attribute of the current position */ 27730043Sminshall fieldattr = FieldAttributes(WhereAttrByte(pointer)); 27830043Sminshall 27930043Sminshall if ((IsStartField(pointer) != TermIsStartField(pointer)) || 28030043Sminshall (IsStartField(pointer) && 28130043Sminshall fieldattr != TermAttributes(pointer))) { 28230043Sminshall 28330043Sminshall int oldterm; 28430043Sminshall 28530043Sminshall oldterm = TermAttributes(pointer); 28630043Sminshall if (IsStartField(pointer)) { 28730043Sminshall TermNewField(pointer, fieldattr); 28830043Sminshall SetTerminal(pointer, 0); 28930043Sminshall } else { 29030043Sminshall TermDeleteField(pointer); 29130043Sminshall } 29230043Sminshall /* We always do the first character in a divergent 29330043Sminshall * field, since otherwise the start of a field in 29430043Sminshall * the Host structure may leave a highlighted blank 29530043Sminshall * on the screen, and the start of a field in the 29630043Sminshall * Terminal structure may leave a non-highlighted 29730043Sminshall * something in the middle of a highlighted field 29830043Sminshall * on the screen. 29930043Sminshall */ 30030043Sminshall SetHighlightMode(pointer); 30130043Sminshall c = GetHost(pointer); 30230043Sminshall DoCharacterAt(c,pointer); /* MACRO */ 30330043Sminshall 30430043Sminshall if (NotVisuallyCompatibleAttributes 30530043Sminshall (pointer, fieldattr, oldterm)) { 30630043Sminshall int j; 30730043Sminshall 30830043Sminshall j = pointer; 30930043Sminshall 31030043Sminshall pointer = ScreenInc(pointer); 31130043Sminshall if (!(--columnsleft)) { 31230043Sminshall DoARefresh(); 31330043Sminshall EmptyTerminal(); 31430043Sminshall move(ScreenLine(pointer), 0); 31530043Sminshall columnsleft = NumberColumns; 31630043Sminshall } 31730043Sminshall SetHighlightMode(pointer); /* Turn on highlighting */ 31831452Sminshall while ((!IsStartField(pointer)) && 31931452Sminshall (!TermIsStartField(pointer))) { 32030043Sminshall c = GetHost(pointer); 32130043Sminshall DoCharacterAt(c,pointer); /* MACRO */ 32230043Sminshall pointer = ScreenInc(pointer); 32330043Sminshall if (!(--columnsleft)) { 32430043Sminshall DoARefresh(); 32530043Sminshall EmptyTerminal(); 32630043Sminshall move(ScreenLine(pointer), 0); 32730043Sminshall columnsleft = NumberColumns; 32830043Sminshall /* We don't look at HaveInput here, since 32930043Sminshall * if we leave this loop before the end of 33030043Sminshall * the 3270 field, we could have pointer 33130043Sminshall * higher than Highest. This would cause 33230043Sminshall * us to end the highest "while" loop, 33330043Sminshall * but we may, in fact, need to go around the 33430043Sminshall * screen once again. 33530043Sminshall */ 33630043Sminshall } 33730043Sminshall /* The loop needs to be protected 33830043Sminshall * from the situation where there had been only 33930043Sminshall * one field on the Terminal, and none on the Host. 34030043Sminshall * In this case, we have just deleted our last 34130043Sminshall * field. Hence, the break. 34230043Sminshall */ 34330043Sminshall if (j == pointer) { 34430043Sminshall break; 34530043Sminshall } 34630043Sminshall } 34730043Sminshall if (IsStartField(pointer) && !TermIsStartField(pointer)) { 34830043Sminshall /* Remember what the terminal looked like */ 34930043Sminshall TermNewField(pointer, oldterm); 35030043Sminshall /* 35130043Sminshall * The danger here is that the current position may 35230043Sminshall * be the start of a Host field. If so, and the 35330043Sminshall * field is highlighted, and our terminal was 35430043Sminshall * highlighted, then we will leave a highlighted 35530043Sminshall * blank at this position. 35630043Sminshall */ 35730043Sminshall SetHighlightMode(pointer); 35830043Sminshall c = GetHost(pointer); 35930043Sminshall DoCharacterAt(c,pointer); 36030043Sminshall } 36130043Sminshall /* We could be in the situation of needing to exit. 36230043Sminshall * This could happen if the current field wrapped around 36330043Sminshall * the end of the screen. 36430043Sminshall */ 36530043Sminshall if (j > pointer) { 36631452Sminshall /* 36731452Sminshall * pointer is guaranteed to be higher than Highest... 36831452Sminshall */ 36931452Sminshall pointer = Highest+1; /* We did the highest thing */ 37030043Sminshall break; 37130043Sminshall } 37230043Sminshall } else { 37330043Sminshall c = GetHost(pointer); 37430043Sminshall /* We always do the first character in a divergent 37530043Sminshall * field, since otherwise the start of a field in 37630043Sminshall * the Host structure may leave a highlighted blank 37730043Sminshall * on the screen, and the start of a field in the 37830043Sminshall * Terminal structure may leave a non-highlighted 37930043Sminshall * something in the middle of a highlighted field 38030043Sminshall * on the screen. 38130043Sminshall */ 38230043Sminshall SetHighlightMode(pointer); 38330043Sminshall DoCharacterAt(c,pointer); 38430043Sminshall } 38530043Sminshall } else { 38630043Sminshall SetHighlightMode(pointer); 38730054Sminshall /* 38830054Sminshall * The following will terminate at least when we get back 38930043Sminshall * to the original 'pointer' location (since we force 39030043Sminshall * things to be equal). 39130043Sminshall */ 39230043Sminshall while (((c = GetHost(pointer)) != GetTerminal(pointer)) && 39330043Sminshall !IsStartField(pointer) && !TermIsStartField(pointer)) { 39430043Sminshall DoCharacterAt(c, pointer); 39530043Sminshall pointer = ScreenInc(pointer); 39630043Sminshall if (!(--columnsleft)) { 39730043Sminshall DoARefresh(); 39830043Sminshall EmptyTerminal(); 39930043Sminshall if (HaveInput) { /* if input came in, take it */ 40030043Sminshall break; 40130043Sminshall } 40230043Sminshall move(ScreenLine(pointer), 0); 40330043Sminshall columnsleft = NumberColumns; 40430043Sminshall } 40530043Sminshall } 40630043Sminshall } 40730043Sminshall } 40830043Sminshall } 40930043Sminshall DoARefresh(); 41030043Sminshall Lowest = pointer; 41130043Sminshall if (Lowest > Highest) { /* if we finished input... */ 41230043Sminshall Lowest = HighestScreen()+1; 41330043Sminshall Highest = LowestScreen()-1; 41430043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 41530043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 41630043Sminshall ScreenLineOffset(terminalCursorAddress))) { 41730043Sminshall GoAway("move", terminalCursorAddress); 41830043Sminshall } 41930043Sminshall DoARefresh(); 42030043Sminshall if (needToRing) { 42130043Sminshall StringToTerminal(bellSequence); 42230043Sminshall needToRing = 0; 42330043Sminshall } 42430043Sminshall } 42530043Sminshall EmptyTerminal(); /* move data along */ 42630043Sminshall return; 42730043Sminshall } 42830043Sminshall 42930043Sminshall #if defined(NOT43) 43030043Sminshall static int 43130043Sminshall #else /* defined(NOT43) */ 43230043Sminshall static void 43330043Sminshall #endif /* defined(NOT43) */ 43430043Sminshall FastScreen() 43530043Sminshall { 43631101Sminshall #if defined(MSDOS) 43730043Sminshall #define SaveCorner 0 43831101Sminshall #else /* defined(MSDOS) */ 43930043Sminshall #define SaveCorner 1 44031101Sminshall #endif /* defined(MSDOS) */ 44130043Sminshall 44230043Sminshall #define DoAttribute(a) if (IsHighlightedAttr(a)) { \ 44330043Sminshall standout(); \ 44430043Sminshall } else { \ 44530043Sminshall standend(); \ 44630043Sminshall } \ 44730043Sminshall if (IsNonDisplayAttr(a)) { \ 44830043Sminshall a = 0; /* zero == don't display */ \ 44930043Sminshall } \ 45030043Sminshall if (!FormattedScreen()) { \ 45130043Sminshall a = 1; /* one ==> do display on unformatted */\ 45230043Sminshall } 45330043Sminshall ScreenImage *p, *upper; 45430043Sminshall int fieldattr; /* spends most of its time == 0 or 1 */ 45530043Sminshall 45630043Sminshall /* OK. We want to do this a quickly as possible. So, we assume we 45730043Sminshall * only need to go from Lowest to Highest. However, if we find a 45830043Sminshall * field in the middle, we do the whole screen. 45930043Sminshall * 46030043Sminshall * In particular, we separate out the two cases from the beginning. 46130043Sminshall */ 46230043Sminshall if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) { 46330043Sminshall register int columnsleft; 46430043Sminshall 46530043Sminshall move(ScreenLine(Lowest), ScreenLineOffset(Lowest)); 46630043Sminshall p = &Host[Lowest]; 46731101Sminshall #if !defined(MSDOS) 46830043Sminshall if (Highest == HighestScreen()) { 46930043Sminshall Highest = ScreenDec(Highest); 47030043Sminshall } 47131101Sminshall #endif /* !defined(MSDOS) */ 47230043Sminshall upper = &Host[Highest]; 47330043Sminshall fieldattr = FieldAttributes(Lowest); 47430043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 47530043Sminshall columnsleft = NumberColumns-ScreenLineOffset(p-Host); 47630043Sminshall 47730043Sminshall while (p <= upper) { 47830054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 47930043Sminshall Highest = HighestScreen(); 48030043Sminshall Lowest = LowestScreen(); 48130043Sminshall FastScreen(); /* Recurse */ 48230043Sminshall return; 48330043Sminshall } else if (fieldattr) { /* Should we display? */ 48431148Sminshall /* Display translated data */ 48531148Sminshall addch(disp_asc[GetTerminalPointer(p)]); 48630043Sminshall } else { 48730043Sminshall addch(' '); /* Display a blank */ 48830043Sminshall } 48930043Sminshall /* If the physical screen is larger than what we 49030043Sminshall * are using, we need to make sure that each line 49130043Sminshall * starts at the beginning of the line. Otherwise, 49230043Sminshall * we will just string all the lines together. 49330043Sminshall */ 49430043Sminshall p++; 49530043Sminshall if (--columnsleft == 0) { 49630043Sminshall int i = p-Host; 49730043Sminshall 49830043Sminshall move(ScreenLine(i), 0); 49930043Sminshall columnsleft = NumberColumns; 50030043Sminshall } 50130043Sminshall } 50230043Sminshall } else { /* Going from Lowest to Highest */ 50330043Sminshall unsigned char tmpbuf[MAXNUMBERCOLUMNS+1]; 50430043Sminshall ScreenImage *End = &Host[ScreenSize]-1-SaveCorner; 50530043Sminshall register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns; 50630043Sminshall 50730043Sminshall *tmpend = 0; /* terminate from the beginning */ 50830043Sminshall move(0,0); 50930043Sminshall p = Host; 51030043Sminshall fieldattr = FieldAttributes(LowestScreen()); 51130043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 51230043Sminshall 51330043Sminshall while (p <= End) { 51430054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 51530043Sminshall if (tmp != tmpbuf) { 51630043Sminshall *tmp++ = 0; /* close out */ 51730043Sminshall addstr(tmpbuf); 51830043Sminshall tmp = tmpbuf; 51930043Sminshall tmpend = tmpbuf + NumberColumns - ScreenLineOffset(p-Host); 52030043Sminshall } 52130054Sminshall fieldattr = FieldAttributesPointer(p); /* Get attributes */ 52230043Sminshall DoAttribute(fieldattr); /* Set standout, non-display */ 52330043Sminshall *tmp++ = ' '; 52430043Sminshall } else { 52530043Sminshall if (fieldattr) { /* Should we display? */ 52630043Sminshall /* Display translated data */ 52731148Sminshall *tmp++ = disp_asc[GetTerminalPointer(p)]; 52830043Sminshall } else { 52930043Sminshall *tmp++ = ' '; 53030043Sminshall } 53130043Sminshall } 53230043Sminshall /* If the physical screen is larger than what we 53330043Sminshall * are using, we need to make sure that each line 53430043Sminshall * starts at the beginning of the line. Otherwise, 53530043Sminshall * we will just string all the lines together. 53630043Sminshall */ 53730043Sminshall p++; 53830043Sminshall if (tmp == tmpend) { 53930043Sminshall int i = p-Host; /* Be sure the "p++" happened first! */ 54030043Sminshall 54130043Sminshall *tmp++ = 0; 54230043Sminshall addstr(tmpbuf); 54330043Sminshall tmp = tmpbuf; 54430043Sminshall move(ScreenLine(i), 0); 54530043Sminshall tmpend = tmpbuf + NumberColumns; 54630043Sminshall } 54730043Sminshall } 54830043Sminshall if (tmp != tmpbuf) { 54930043Sminshall *tmp++ = 0; 55030043Sminshall addstr(tmpbuf); 55130043Sminshall tmp = tmpbuf; 55230043Sminshall } 55330043Sminshall } 55430043Sminshall Lowest = HighestScreen()+1; 55530043Sminshall Highest = LowestScreen()-1; 55630043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 55730043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 55830043Sminshall ScreenLineOffset(terminalCursorAddress))) { 55930043Sminshall GoAway("move", terminalCursorAddress); 56030043Sminshall } 56130043Sminshall DoARefresh(); 56230043Sminshall if (needToRing) { 56330043Sminshall StringToTerminal(bellSequence); 56430043Sminshall needToRing = 0; 56530043Sminshall } 56630043Sminshall EmptyTerminal(); /* move data along */ 56730043Sminshall return; 56830043Sminshall } 56930043Sminshall 57030043Sminshall 57130043Sminshall /* TryToSend - send data out to user's terminal */ 57230043Sminshall 57330043Sminshall #if defined(NOT43) 57430043Sminshall int 57530043Sminshall #else /* defined(NOT43) */ 57630043Sminshall void 57730043Sminshall #endif /* defined(NOT43) */ 57830043Sminshall (*TryToSend)() = FastScreen; 57930043Sminshall 58031127Sminshall void 58131127Sminshall ScreenOIA(oia) 58231127Sminshall OIA *oia; 58331127Sminshall { 58431127Sminshall } 58531127Sminshall 58631127Sminshall 58730328Sminshall /* InitTerminal - called to initialize the screen, etc. */ 58830043Sminshall 58930043Sminshall void 59030328Sminshall InitTerminal() 59130043Sminshall { 59230043Sminshall #if defined(unix) 59330043Sminshall struct sgttyb ourttyb; 59430043Sminshall static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 59530043Sminshall 2400, 4800, 9600 }; 59630043Sminshall #endif 59730043Sminshall 59830328Sminshall InitMapping(); /* Go do mapping file (MAP3270) first */ 59930043Sminshall if (!screenInitd) { /* not initialized */ 60030043Sminshall #if defined(unix) 60130043Sminshall char KSEbuffer[2050]; 60230043Sminshall char *lotsofspace = KSEbuffer; 60330043Sminshall extern int abort(); 60430043Sminshall extern char *tgetstr(); 60530043Sminshall #endif /* defined(unix) */ 60630043Sminshall 60731101Sminshall ClearArray(Terminal); 60830328Sminshall terminalCursorAddress = SetBufferAddress(0,0); 60930043Sminshall #if defined(unix) 61030043Sminshall signal(SIGHUP, abort); 61130043Sminshall #endif 61230043Sminshall 61330043Sminshall TryToSend = FastScreen; 61431559Sminshall #if defined(unix) 61530043Sminshall ioctl(1, TIOCGETP, (char *) &ourttyb); 61630043Sminshall if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) { 61730043Sminshall max_changes_before_poll = 1920; 61830043Sminshall } else { 61930043Sminshall max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10; 62030043Sminshall if (max_changes_before_poll < 40) { 62130043Sminshall max_changes_before_poll = 40; 62230043Sminshall } 62330043Sminshall TryToSend = SlowScreen; 62430043Sminshall HaveInput = 1; /* get signals going */ 62530043Sminshall } 62631559Sminshall #endif /* defined(unix) */ 62730043Sminshall setcommandmode(); 62830043Sminshall /* 62930043Sminshall * By now, initscr() (in curses) has been called (from telnet.c), 63030043Sminshall * and the screen has been initialized. 63130043Sminshall */ 63230043Sminshall #if defined(unix) 63330043Sminshall nonl(); 63430043Sminshall /* the problem is that curses catches SIGTSTP to 63530043Sminshall * be nice, but it messes us up. 63630043Sminshall */ 63730043Sminshall signal(SIGTSTP, SIG_DFL); 63830043Sminshall if ((KS = tgetstr("ks", &lotsofspace)) != 0) { 63930043Sminshall KS = strsave(KS); 64030043Sminshall StringToTerminal(KS); 64130043Sminshall } 64230043Sminshall if ((KE = tgetstr("ke", &lotsofspace)) != 0) { 64330043Sminshall KE = strsave(KE); 64430043Sminshall } 64530043Sminshall if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) { 64630043Sminshall SO = strsave(tgetstr("md", &lotsofspace)); 64730043Sminshall SE = strsave(tgetstr("me", &lotsofspace)); 64830043Sminshall } 64930043Sminshall #endif 65030043Sminshall DoARefresh(); 65130043Sminshall setconnmode(); 65230043Sminshall if (VB && *VB) { 65330043Sminshall bellSequence = VB; /* use visual bell */ 65430043Sminshall } 65530043Sminshall screenInitd = 1; 65630043Sminshall screenStopped = 0; /* Not stopped */ 65730043Sminshall } 65830043Sminshall } 65930043Sminshall 66030043Sminshall 66130043Sminshall /* StopScreen - called when we are going away... */ 66230043Sminshall 66330043Sminshall void 66430043Sminshall StopScreen(doNewLine) 66530043Sminshall int doNewLine; 66630043Sminshall { 66730043Sminshall if (screenInitd && !screenStopped) { 66830043Sminshall move(NumberLines-1, 1); 66930043Sminshall standend(); 67030043Sminshall inHighlightMode = 0; 67130043Sminshall DoARefresh(); 67230043Sminshall setcommandmode(); 67330043Sminshall endwin(); 67430043Sminshall setconnmode(); 67530043Sminshall #if defined(unix) 67630043Sminshall if (KE) { 67730043Sminshall StringToTerminal(KE); 67830043Sminshall } 67930043Sminshall #endif /* defined(unix) */ 68030043Sminshall if (doNewLine) { 68130043Sminshall StringToTerminal("\r\n"); 68230043Sminshall } 68330043Sminshall EmptyTerminal(); 68430043Sminshall screenStopped = 1; /* This is stopped */ 68530043Sminshall } 68630043Sminshall } 68730043Sminshall 68830043Sminshall 68930043Sminshall /* RefreshScreen - called to cause the screen to be refreshed */ 69030043Sminshall 69130043Sminshall void 69230043Sminshall RefreshScreen() 69330043Sminshall { 69430043Sminshall clearok(curscr, TRUE); 69530043Sminshall (*TryToSend)(); 69630043Sminshall } 69730043Sminshall 69830043Sminshall 69930043Sminshall /* ConnectScreen - called to reconnect to the screen */ 70030043Sminshall 70130043Sminshall void 70230043Sminshall ConnectScreen() 70330043Sminshall { 70430043Sminshall if (screenInitd) { 70530043Sminshall #if defined(unix) 70630043Sminshall if (KS) { 70730043Sminshall StringToTerminal(KS); 70830043Sminshall } 70930043Sminshall #endif /* defined(unix) */ 71030043Sminshall RefreshScreen(); 71130043Sminshall (*TryToSend)(); 71230043Sminshall screenStopped = 0; 71330043Sminshall } 71430043Sminshall } 71530043Sminshall 71630043Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */ 71730043Sminshall 71830043Sminshall void 71930043Sminshall LocalClearScreen() 72030043Sminshall { 72130043Sminshall outputPurge(); /* flush all data to terminal */ 72230043Sminshall clear(); /* clear in curses */ 72331101Sminshall ClearArray(Terminal); 72430043Sminshall Clear3270(); 72530043Sminshall Lowest = HighestScreen()+1; /* everything in sync... */ 72630043Sminshall Highest = LowestScreen()+1; 72730043Sminshall } 72830043Sminshall 72930043Sminshall 73030043Sminshall void 73130043Sminshall BellOff() 73230043Sminshall { 73330043Sminshall if (bellwinup) { 73430043Sminshall delwin(bellwin); 73530043Sminshall bellwin = 0; 73630043Sminshall bellwinup = 0; 73730043Sminshall touchwin(stdscr); 73830043Sminshall DoARefresh(); 73930043Sminshall } 74030043Sminshall } 74130043Sminshall 74230043Sminshall 74330043Sminshall void 74430043Sminshall RingBell(s) 74530043Sminshall char *s; 74630043Sminshall { 74730043Sminshall needToRing = 1; 74830043Sminshall if (s) { 74930043Sminshall int len = strlen(s); 75030043Sminshall 75130043Sminshall if (len > COLS-2) { 75230043Sminshall len = COLS-2; 75330043Sminshall } 75430043Sminshall if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) { 75530043Sminshall OurExitString(stderr, "Error from newwin in RingBell", 1); 75630043Sminshall } 75730043Sminshall werase(bellwin); 75830043Sminshall wstandout(bellwin); 75930043Sminshall box(bellwin, '|', '-'); 76030043Sminshall if (wmove(bellwin, 1, 1) == ERR) { 76130043Sminshall OurExitString(stderr, "Error from wmove in RingBell", 1); 76230043Sminshall } 76330043Sminshall while (len--) { 76430043Sminshall if (waddch(bellwin, *s++) == ERR) { 76530043Sminshall OurExitString(stderr, "Error from waddch in RingBell", 1); 76630043Sminshall } 76730043Sminshall } 76830043Sminshall wstandend(bellwin); 76930043Sminshall if (wrefresh(bellwin) == ERR) { 77030043Sminshall OurExitString(stderr, "Error from wrefresh in RingBell", 1); 77130043Sminshall } 77230043Sminshall bellwinup = 1; 77330043Sminshall } 77430043Sminshall } 77530043Sminshall 77630043Sminshall 77730043Sminshall /* returns a 1 if no more output available (so, go ahead and block), 77830043Sminshall or a 0 if there is more output available (so, just poll the other 77930043Sminshall sources/destinations, don't block). 78030043Sminshall */ 78130043Sminshall 78230043Sminshall int 78330043Sminshall DoTerminalOutput() 78430043Sminshall { 78530043Sminshall /* called just before a select to conserve IO to terminal */ 78631462Sminshall if (!(screenInitd||screenStopped)) { 78730369Sminshall return 1; /* No output if not initialized */ 78830369Sminshall } 78930369Sminshall if ((Lowest <= Highest) || needToRing || 79030369Sminshall (terminalCursorAddress != CorrectTerminalCursor())) { 79130043Sminshall (*TryToSend)(); 79230043Sminshall } 79330043Sminshall if (Lowest > Highest) { 79430369Sminshall return 1; /* no more output now */ 79530043Sminshall } else { 79630369Sminshall return 0; /* more output for future */ 79730043Sminshall } 79830043Sminshall } 79930074Sminshall 80030074Sminshall /* 80130074Sminshall * The following are defined to handle transparent data. 80230074Sminshall */ 80330074Sminshall 80430074Sminshall void 80530074Sminshall TransStop() 80630074Sminshall { 80730074Sminshall #if defined(unix) 80830074Sminshall if (tcflag == 0) { 80930074Sminshall tcflag = -1; 81030074Sminshall (void) signal(SIGCHLD, SIG_DFL); 81130074Sminshall } else if (tcflag > 0) { 81230074Sminshall setcommandmode(); 81330074Sminshall (void) close(tin); 81430074Sminshall (void) close(tout); 81530074Sminshall tin = savefd[0]; 81630074Sminshall tout = savefd[1]; 81730074Sminshall setconnmode(); 81830074Sminshall tcflag = -1; 81930074Sminshall (void) signal(SIGCHLD, SIG_DFL); 82030074Sminshall } 82130074Sminshall #endif /* defined(unix) */ 82230074Sminshall RefreshScreen(); 82330074Sminshall } 82430074Sminshall 82530074Sminshall void 82631863Sminshall TransOut(buffer, count, kind, control) 82730074Sminshall unsigned char *buffer; 82830074Sminshall int count; 82931863Sminshall int kind; /* 0 or 5 */ 83031863Sminshall int control; /* To see if we are done */ 83130074Sminshall { 83230074Sminshall #if defined(unix) 83330074Sminshall extern char *transcom; 83430074Sminshall int inpipefd[2], outpipefd[2], savemode; 83530074Sminshall void aborttc(); 83630074Sminshall #endif /* defined(unix) */ 83730074Sminshall 83830074Sminshall while (DoTerminalOutput() == 0) { 83930074Sminshall #if defined(unix) 84030074Sminshall HaveInput = 0; 84130074Sminshall #endif /* defined(unix) */ 84230074Sminshall } 84330074Sminshall #if defined(unix) 84430074Sminshall if (transcom && tcflag == -1) { 84530074Sminshall while (1) { /* go thru once */ 84630074Sminshall if (pipe(outpipefd) < 0) { 84730074Sminshall break; 84830074Sminshall } 84930074Sminshall if (pipe(inpipefd) < 0) { 85030074Sminshall break; 85130074Sminshall } 85230074Sminshall if ((tcflag = fork()) == 0) { 85330074Sminshall (void) close(outpipefd[1]); 85430074Sminshall (void) close(0); 85530074Sminshall if (dup(outpipefd[0]) < 0) { 85630074Sminshall exit(1); 85730074Sminshall } 85830074Sminshall (void) close(outpipefd[0]); 85930074Sminshall (void) close(inpipefd[0]); 86030074Sminshall (void) close(1); 86130074Sminshall if (dup(inpipefd[1]) < 0) { 86230074Sminshall exit(1); 86330074Sminshall } 86430074Sminshall (void) close(inpipefd[1]); 86530074Sminshall if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) { 86630074Sminshall exit(1); 86730074Sminshall } 86830074Sminshall } 86930074Sminshall (void) close(inpipefd[1]); 87030074Sminshall (void) close(outpipefd[0]); 87130074Sminshall savefd[0] = tin; 87230074Sminshall savefd[1] = tout; 87330074Sminshall setcommandmode(); 87430074Sminshall tin = inpipefd[0]; 87530074Sminshall tout = outpipefd[1]; 87630074Sminshall (void) signal(SIGCHLD, aborttc); 87730074Sminshall setconnmode(); 87830074Sminshall tcflag = 1; 87930074Sminshall break; 88030074Sminshall } 88130074Sminshall if (tcflag < 1) { 88230074Sminshall tcflag = 0; 88330074Sminshall } 88430074Sminshall } 88530074Sminshall #endif /* defined(unix) */ 88630074Sminshall (void) DataToTerminal(buffer, count); 88731863Sminshall if (control && (kind == 0)) { /* Send in AID byte */ 88831863Sminshall SendToIBM(); 88931863Sminshall } else { 89031863Sminshall TransInput(1, kind); /* Go get some data */ 89131863Sminshall } 89230074Sminshall } 89330074Sminshall 89430074Sminshall 89530074Sminshall #if defined(unix) 89630074Sminshall static void 89730074Sminshall aborttc() 89830074Sminshall { 89930074Sminshall int savemode; 90030074Sminshall 90130074Sminshall setcommandmode(); 90230074Sminshall (void) close(tin); 90330074Sminshall (void) close(tout); 90430074Sminshall tin = savefd[0]; 90530074Sminshall tout = savefd[1]; 90630074Sminshall setconnmode(); 90730074Sminshall tcflag = 0; 90830074Sminshall } 90930074Sminshall #endif /* defined(unix) */ 910