130043Sminshall /* 230043Sminshall * Copyright (c) 1984, 1985, 1986 by the Regents of the 330043Sminshall * University of California and by Gregory Glenn Minshall. 430043Sminshall * 530043Sminshall * Permission to use, copy, modify, and distribute these 630043Sminshall * programs and their documentation for any purpose and 730043Sminshall * without fee is hereby granted, provided that this 830043Sminshall * copyright and permission appear on all copies and 930043Sminshall * supporting documentation, the name of the Regents of 1030043Sminshall * the University of California not be used in advertising 1130043Sminshall * or publicity pertaining to distribution of the programs 1230043Sminshall * without specific prior permission, and notice be given in 1330043Sminshall * supporting documentation that copying and distribution is 1430043Sminshall * by permission of the Regents of the University of California 1530043Sminshall * and by Gregory Glenn Minshall. Neither the Regents of the 1630043Sminshall * University of California nor Gregory Glenn Minshall make 1730043Sminshall * representations about the suitability of this software 1830043Sminshall * for any purpose. It is provided "as is" without 1930043Sminshall * express or implied warranty. 2030043Sminshall */ 2130043Sminshall 2230043Sminshall #ifndef lint 2330043Sminshall static char sccsid[] = "@(#)outbound.c 3.1 10/29/86"; 2430043Sminshall #endif /* lint */ 2530043Sminshall 2630043Sminshall 2730043Sminshall #if defined(unix) 2830043Sminshall #include <signal.h> 2930043Sminshall #include <sgtty.h> 3030043Sminshall #endif 3130043Sminshall #include <stdio.h> 3230043Sminshall #include <curses.h> 3330043Sminshall 3431071Sminshall #include "../general.h" 3531071Sminshall 3630043Sminshall #include "terminal.h" 3730043Sminshall 3830043Sminshall #include "../telnet.ext" 3930043Sminshall 4030043Sminshall #include "../ctlr/hostctlr.h" 4130043Sminshall #include "../ctlr/inbound.ext" 42*31127Sminshall #include "../ctlr/oia.h" 4330043Sminshall #include "../ctlr/options.ext" 4430043Sminshall #include "../ctlr/outbound.ext" 4530043Sminshall #include "../ctlr/screen.h" 4630043Sminshall 4730043Sminshall #include "../keyboard/map3270.ext" 4830043Sminshall 4930043Sminshall #include "../system/globals.h" 5030043Sminshall 5130043Sminshall extern void EmptyTerminal(); 5230043Sminshall 5330043Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \ 5430043Sminshall terminalCursorAddress:UnLocked? CursorAddress: HighestScreen()) 5530043Sminshall 5630043Sminshall 5730328Sminshall static int terminalCursorAddress; /* where the cursor is on term */ 5830328Sminshall static int screenInitd; /* the screen has been initialized */ 5930328Sminshall static int screenStopped; /* the screen has been stopped */ 6030043Sminshall #if defined(SLOWSCREEN) 6130043Sminshall static int max_changes_before_poll; /* how many characters before looking */ 6230043Sminshall /* at terminal and net again */ 6330043Sminshall #endif /* defined(SLOWSCREEN) */ 6430043Sminshall 6530328Sminshall static int needToRing; /* need to ring terinal bell */ 6630043Sminshall static char *bellSequence = "\07"; /* bell sequence (may be replaced by 6730043Sminshall * VB during initialization) 6830043Sminshall */ 6930328Sminshall static WINDOW *bellwin = 0; /* The window the bell message is in */ 7030043Sminshall int bellwinup = 0; /* Are we up with it or not */ 7130043Sminshall 7230043Sminshall #if defined(unix) 7330043Sminshall static char *KS, *KE; 7430043Sminshall #endif /* defined(unix) */ 7530043Sminshall 7630074Sminshall 7730074Sminshall #if defined(SLOWSCREEN) 7830074Sminshall static int inHighlightMode = 0; 7931071Sminshall ScreenImage Terminal[MAXSCREENSIZE]; 8030074Sminshall #endif /* defined(SLOWSCREEN) */ 8130074Sminshall 8230074Sminshall /* Variables for transparent mode */ 8330043Sminshall #if defined(unix) 8430043Sminshall static int tcflag = -1; /* transparent mode command flag */ 8530043Sminshall static int savefd[2]; /* for storing fds during transcom */ 8630074Sminshall extern int tin, tout; /* file descriptors */ 8730043Sminshall #endif /* defined(unix) */ 8830043Sminshall 8930043Sminshall 9030043Sminshall #include "disp_asc.out" 9130043Sminshall 9230043Sminshall 9330730Sminshall 9430730Sminshall /* 9530730Sminshall * init_screen() 9630730Sminshall * 9730730Sminshall * Initialize variables used by screen. 9830730Sminshall */ 9930730Sminshall 10030730Sminshall void 10130730Sminshall init_screen() 10230730Sminshall { 10330730Sminshall bellwinup = 0; 10430730Sminshall #if defined(SLOWSCREEN) 10530730Sminshall inHighlightMode = 0; 10631071Sminshall ClearArray(Terminal); 10730730Sminshall #endif /* defined(SLOWSCREEN) */ 10830730Sminshall } 10930730Sminshall 11030730Sminshall 11130043Sminshall /* OurExitString - designed to keep us from going through infinite recursion */ 11230043Sminshall 11330043Sminshall static void 11430043Sminshall OurExitString(file, string, value) 11530043Sminshall FILE *file; 11630043Sminshall char *string; 11730043Sminshall int value; 11830043Sminshall { 11930043Sminshall static int recursion = 0; 12030043Sminshall 12130043Sminshall if (!recursion) { 12230043Sminshall recursion = 1; 12330043Sminshall ExitString(file, string, value); 12430043Sminshall } 12530043Sminshall } 12630043Sminshall 12730043Sminshall 12830043Sminshall /* DoARefresh */ 12930043Sminshall 13030043Sminshall static void 13130043Sminshall DoARefresh() 13230043Sminshall { 13330043Sminshall if (ERR == refresh()) { 13430043Sminshall OurExitString(stderr, "ERR from refresh\n", 1); 13530043Sminshall } 13630043Sminshall } 13730043Sminshall 13830043Sminshall static void 13930043Sminshall GoAway(from, where) 14030043Sminshall char *from; /* routine that gave error */ 14130043Sminshall int where; /* cursor address */ 14230043Sminshall { 14330043Sminshall char foo[100]; 14430043Sminshall 14530043Sminshall sprintf(foo, "ERR from %s at %d (%d, %d)\n", 14630043Sminshall from, where, ScreenLine(where), ScreenLineOffset(where)); 14730043Sminshall OurExitString(stderr, foo, 1); 14830043Sminshall /* NOTREACHED */ 14930043Sminshall } 15030043Sminshall 15130043Sminshall #if defined(SLOWSCREEN) 15230043Sminshall /* What is the screen address of the attribute byte for the terminal */ 15330043Sminshall 15430043Sminshall static int 15530043Sminshall WhereTermAttrByte(p) 15630043Sminshall register int p; 15730043Sminshall { 15830043Sminshall register int i; 15930043Sminshall 16030043Sminshall i = p; 16130043Sminshall 16230043Sminshall do { 16330043Sminshall if (TermIsStartField(i)) { 16430043Sminshall return(i); 16530043Sminshall } 16630043Sminshall i = ScreenDec(i); 16730043Sminshall } while (i != p); 16830043Sminshall 16930043Sminshall return(LowestScreen()); /* unformatted screen... */ 17030043Sminshall } 17130043Sminshall #endif /* defined(SLOWSCREEN) */ 17230043Sminshall 17330043Sminshall /* 17430043Sminshall * There are two algorithms for updating the screen. 17530043Sminshall * The first, SlowScreen() optimizes the line between the 17630043Sminshall * computer and the screen (say a 9600 baud line). To do 17730043Sminshall * this, we break out of the loop every so often to look 17830043Sminshall * at any pending input from the network (so that successive 17930043Sminshall * screens will only partially print until the final screen, 18030043Sminshall * the one the user possibly wants to see, is displayed 18130043Sminshall * in its entirety). 18230043Sminshall * 18330043Sminshall * The second algorithm tries to optimize CPU time (by 18430043Sminshall * being simpler) at the cost of the bandwidth to the 18530043Sminshall * screen. 18630043Sminshall * 18730043Sminshall * Of course, curses(3X) gets in here also. 18830043Sminshall */ 18930043Sminshall 19030043Sminshall 19130043Sminshall #if defined(SLOWSCREEN) 19230043Sminshall #if defined(NOT43) 19330043Sminshall static int 19430043Sminshall #else /* defined(NOT43) */ 19530043Sminshall static void 19630043Sminshall #endif /* defined(NOT43) */ 19730043Sminshall SlowScreen() 19830043Sminshall { 19930043Sminshall register int pointer; 20030043Sminshall register int c; 20130043Sminshall register int fieldattr; 20230043Sminshall register int columnsleft; 20330043Sminshall 20430043Sminshall # define SetHighlightMode(p) { \ 20530043Sminshall if (!IsStartField(p) && IsHighlightedAttr(fieldattr)) { \ 20630043Sminshall if (!inHighlightMode) { \ 20730043Sminshall inHighlightMode = 1; \ 20830043Sminshall standout(); \ 20930043Sminshall } \ 21030043Sminshall } else { \ 21130043Sminshall if (inHighlightMode) { \ 21230043Sminshall inHighlightMode = 0; \ 21330043Sminshall standend(); \ 21430043Sminshall } \ 21530043Sminshall } \ 21630043Sminshall } 21730043Sminshall 21830043Sminshall # define DoCharacterAt(c,p) { \ 21930043Sminshall SetTerminal(p, c); \ 22030043Sminshall if (p != HighestScreen()) { \ 22130043Sminshall c = TerminalCharacterAttr(disp_asc[c&0xff], p, \ 22230043Sminshall fieldattr); \ 22330043Sminshall if (terminalCursorAddress != p) { \ 22430043Sminshall if (ERR == mvaddch(ScreenLine(p), \ 22530043Sminshall ScreenLineOffset(p), c)) {\ 22630043Sminshall GoAway("mvaddch", p); \ 22730043Sminshall } \ 22830043Sminshall } else { \ 22930043Sminshall if (ERR == addch(c)) {\ 23030043Sminshall GoAway("addch", p); \ 23130043Sminshall } \ 23230043Sminshall } \ 23330043Sminshall terminalCursorAddress = ScreenInc(p); \ 23430043Sminshall } \ 23530043Sminshall } 23630043Sminshall 23730043Sminshall 23830043Sminshall /* run through screen, printing out non-null lines */ 23930043Sminshall 24030043Sminshall /* There are two separate reasons for wanting to terminate this 24130043Sminshall * loop early. One is to respond to new input (either from 24230043Sminshall * the terminal or from the network [host]). For this reason, 24330043Sminshall * we expect to see 'HaveInput' come true when new input comes in. 24430043Sminshall * 24530043Sminshall * The second reason is a bit more difficult (for me) to understand. 24630043Sminshall * Basically, we don't want to get too far ahead of the characters that 24730043Sminshall * appear on the screen. Ideally, we would type out a few characters, 24830043Sminshall * wait until they appeared on the screen, then type out a few more. 24930043Sminshall * The reason for this is that the user, on seeing some characters 25030043Sminshall * appear on the screen may then start to type something. We would 25130043Sminshall * like to look at what the user types at about the same 'time' 25230043Sminshall * (measured by characters being sent to the terminal) that the 25330043Sminshall * user types them. For this reason, what we would like to do 25430043Sminshall * is update a bit, then call curses to do a refresh, flush the 25530043Sminshall * output to the terminal, then wait until the terminal data 25630043Sminshall * has been sent. 25730043Sminshall * 25830043Sminshall * Note that curses is useful for, among other things, deciding whether 25930043Sminshall * or not to send :ce: (clear to end of line), so we should call curses 26030043Sminshall * at end of lines (beginning of next lines). 26130043Sminshall * 26230043Sminshall * The problems here are the following: If we do lots of write(2)s, 26330043Sminshall * we will be doing lots of context switches, thus lots of overhead 26430043Sminshall * (which we have already). Second, if we do a select to wait for 26530043Sminshall * the output to drain, we have to contend with the fact that NOW 26630043Sminshall * we are scheduled to run, but who knows what the scheduler will 26730043Sminshall * decide when the output has caught up. 26830043Sminshall */ 26930043Sminshall 27030043Sminshall if (Highest == HighestScreen()) { 27130043Sminshall Highest = ScreenDec(Highest); /* else, while loop will never end */ 27230043Sminshall } 27330043Sminshall if (Lowest < LowestScreen()) { 27430043Sminshall Lowest = LowestScreen(); /* could be -1 in some cases with 27530043Sminshall * unformatted screens. 27630043Sminshall */ 27730043Sminshall } 27830043Sminshall if (Highest >= (pointer = Lowest)) { 27930043Sminshall /* if there is anything to do, do it. We won't terminate 28030043Sminshall * the loop until we've gone at least to Highest. 28130043Sminshall */ 28230043Sminshall while ((pointer <= Highest) && !HaveInput) { 28330043Sminshall 28430043Sminshall /* point at the next place of disagreement */ 28530043Sminshall pointer += (bunequal(Host+pointer, Terminal+pointer, 28630043Sminshall (Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]); 28730043Sminshall 28830043Sminshall /* how many characters to change until the end of the 28930043Sminshall * current line 29030043Sminshall */ 29130043Sminshall columnsleft = NumberColumns - ScreenLineOffset(pointer); 29230043Sminshall /* 29330043Sminshall * Make sure we are where we think we are. 29430043Sminshall */ 29530043Sminshall move(ScreenLine(pointer), ScreenLineOffset(pointer)); 29630043Sminshall 29730043Sminshall /* what is the field attribute of the current position */ 29830043Sminshall fieldattr = FieldAttributes(WhereAttrByte(pointer)); 29930043Sminshall 30030043Sminshall if ((IsStartField(pointer) != TermIsStartField(pointer)) || 30130043Sminshall (IsStartField(pointer) && 30230043Sminshall fieldattr != TermAttributes(pointer))) { 30330043Sminshall 30430043Sminshall int oldterm; 30530043Sminshall 30630043Sminshall oldterm = TermAttributes(pointer); 30730043Sminshall if (IsStartField(pointer)) { 30830043Sminshall TermNewField(pointer, fieldattr); 30930043Sminshall SetTerminal(pointer, 0); 31030043Sminshall } else { 31130043Sminshall TermDeleteField(pointer); 31230043Sminshall } 31330043Sminshall /* We always do the first character in a divergent 31430043Sminshall * field, since otherwise the start of a field in 31530043Sminshall * the Host structure may leave a highlighted blank 31630043Sminshall * on the screen, and the start of a field in the 31730043Sminshall * Terminal structure may leave a non-highlighted 31830043Sminshall * something in the middle of a highlighted field 31930043Sminshall * on the screen. 32030043Sminshall */ 32130043Sminshall SetHighlightMode(pointer); 32230043Sminshall c = GetHost(pointer); 32330043Sminshall DoCharacterAt(c,pointer); /* MACRO */ 32430043Sminshall 32530043Sminshall if (NotVisuallyCompatibleAttributes 32630043Sminshall (pointer, fieldattr, oldterm)) { 32730043Sminshall int j; 32830043Sminshall 32930043Sminshall j = pointer; 33030043Sminshall 33130043Sminshall pointer = ScreenInc(pointer); 33230043Sminshall if (!(--columnsleft)) { 33330043Sminshall DoARefresh(); 33430043Sminshall EmptyTerminal(); 33530043Sminshall move(ScreenLine(pointer), 0); 33630043Sminshall columnsleft = NumberColumns; 33730043Sminshall } 33830043Sminshall SetHighlightMode(pointer); /* Turn on highlighting */ 33930043Sminshall while (!IsStartField(pointer) && 34030043Sminshall !TermIsStartField(pointer)) { 34130043Sminshall c = GetHost(pointer); 34230043Sminshall DoCharacterAt(c,pointer); /* MACRO */ 34330043Sminshall pointer = ScreenInc(pointer); 34430043Sminshall if (!(--columnsleft)) { 34530043Sminshall DoARefresh(); 34630043Sminshall EmptyTerminal(); 34730043Sminshall move(ScreenLine(pointer), 0); 34830043Sminshall columnsleft = NumberColumns; 34930043Sminshall /* We don't look at HaveInput here, since 35030043Sminshall * if we leave this loop before the end of 35130043Sminshall * the 3270 field, we could have pointer 35230043Sminshall * higher than Highest. This would cause 35330043Sminshall * us to end the highest "while" loop, 35430043Sminshall * but we may, in fact, need to go around the 35530043Sminshall * screen once again. 35630043Sminshall */ 35730043Sminshall } 35830043Sminshall /* The loop needs to be protected 35930043Sminshall * from the situation where there had been only 36030043Sminshall * one field on the Terminal, and none on the Host. 36130043Sminshall * In this case, we have just deleted our last 36230043Sminshall * field. Hence, the break. 36330043Sminshall */ 36430043Sminshall if (j == pointer) { 36530043Sminshall break; 36630043Sminshall } 36730043Sminshall } 36830043Sminshall if (IsStartField(pointer) && !TermIsStartField(pointer)) { 36930043Sminshall /* Remember what the terminal looked like */ 37030043Sminshall TermNewField(pointer, oldterm); 37130043Sminshall /* 37230043Sminshall * The danger here is that the current position may 37330043Sminshall * be the start of a Host field. If so, and the 37430043Sminshall * field is highlighted, and our terminal was 37530043Sminshall * highlighted, then we will leave a highlighted 37630043Sminshall * blank at this position. 37730043Sminshall */ 37830043Sminshall SetHighlightMode(pointer); 37930043Sminshall c = GetHost(pointer); 38030043Sminshall DoCharacterAt(c,pointer); 38130043Sminshall } 38230043Sminshall /* We could be in the situation of needing to exit. 38330043Sminshall * This could happen if the current field wrapped around 38430043Sminshall * the end of the screen. 38530043Sminshall */ 38630043Sminshall if (j > pointer) { 38730043Sminshall break; 38830043Sminshall } 38930043Sminshall } else { 39030043Sminshall c = GetHost(pointer); 39130043Sminshall /* We always do the first character in a divergent 39230043Sminshall * field, since otherwise the start of a field in 39330043Sminshall * the Host structure may leave a highlighted blank 39430043Sminshall * on the screen, and the start of a field in the 39530043Sminshall * Terminal structure may leave a non-highlighted 39630043Sminshall * something in the middle of a highlighted field 39730043Sminshall * on the screen. 39830043Sminshall */ 39930043Sminshall SetHighlightMode(pointer); 40030043Sminshall DoCharacterAt(c,pointer); 40130043Sminshall } 40230043Sminshall } else { 40330043Sminshall SetHighlightMode(pointer); 40430054Sminshall /* 40530054Sminshall * The following will terminate at least when we get back 40630043Sminshall * to the original 'pointer' location (since we force 40730043Sminshall * things to be equal). 40830043Sminshall */ 40930043Sminshall while (((c = GetHost(pointer)) != GetTerminal(pointer)) && 41030043Sminshall !IsStartField(pointer) && !TermIsStartField(pointer)) { 41130043Sminshall DoCharacterAt(c, pointer); 41230043Sminshall pointer = ScreenInc(pointer); 41330043Sminshall if (!(--columnsleft)) { 41430043Sminshall DoARefresh(); 41530043Sminshall EmptyTerminal(); 41630043Sminshall if (HaveInput) { /* if input came in, take it */ 41730043Sminshall break; 41830043Sminshall } 41930043Sminshall move(ScreenLine(pointer), 0); 42030043Sminshall columnsleft = NumberColumns; 42130043Sminshall } 42230043Sminshall } 42330043Sminshall } 42430043Sminshall } 42530043Sminshall } 42630043Sminshall DoARefresh(); 42730043Sminshall Lowest = pointer; 42830043Sminshall if (Lowest > Highest) { /* if we finished input... */ 42930043Sminshall Lowest = HighestScreen()+1; 43030043Sminshall Highest = LowestScreen()-1; 43130043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 43230043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 43330043Sminshall ScreenLineOffset(terminalCursorAddress))) { 43430043Sminshall GoAway("move", terminalCursorAddress); 43530043Sminshall } 43630043Sminshall DoARefresh(); 43730043Sminshall if (needToRing) { 43830043Sminshall StringToTerminal(bellSequence); 43930043Sminshall needToRing = 0; 44030043Sminshall } 44130043Sminshall } 44230043Sminshall EmptyTerminal(); /* move data along */ 44330043Sminshall return; 44430043Sminshall } 44530043Sminshall #endif /* defined(SLOWSCREEN) */ 44630043Sminshall 44730043Sminshall #if defined(NOT43) 44830043Sminshall static int 44930043Sminshall #else /* defined(NOT43) */ 45030043Sminshall static void 45130043Sminshall #endif /* defined(NOT43) */ 45230043Sminshall FastScreen() 45330043Sminshall { 45431101Sminshall #if defined(MSDOS) 45530043Sminshall #define SaveCorner 0 45631101Sminshall #else /* defined(MSDOS) */ 45730043Sminshall #define SaveCorner 1 45831101Sminshall #endif /* defined(MSDOS) */ 45930043Sminshall 46030043Sminshall #define DoAttribute(a) if (IsHighlightedAttr(a)) { \ 46130043Sminshall standout(); \ 46230043Sminshall } else { \ 46330043Sminshall standend(); \ 46430043Sminshall } \ 46530043Sminshall if (IsNonDisplayAttr(a)) { \ 46630043Sminshall a = 0; /* zero == don't display */ \ 46730043Sminshall } \ 46830043Sminshall if (!FormattedScreen()) { \ 46930043Sminshall a = 1; /* one ==> do display on unformatted */\ 47030043Sminshall } 47130043Sminshall ScreenImage *p, *upper; 47230043Sminshall int fieldattr; /* spends most of its time == 0 or 1 */ 47330043Sminshall 47430043Sminshall /* OK. We want to do this a quickly as possible. So, we assume we 47530043Sminshall * only need to go from Lowest to Highest. However, if we find a 47630043Sminshall * field in the middle, we do the whole screen. 47730043Sminshall * 47830043Sminshall * In particular, we separate out the two cases from the beginning. 47930043Sminshall */ 48030043Sminshall if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) { 48130043Sminshall register int columnsleft; 48230043Sminshall 48330043Sminshall move(ScreenLine(Lowest), ScreenLineOffset(Lowest)); 48430043Sminshall p = &Host[Lowest]; 48531101Sminshall #if !defined(MSDOS) 48630043Sminshall if (Highest == HighestScreen()) { 48730043Sminshall Highest = ScreenDec(Highest); 48830043Sminshall } 48931101Sminshall #endif /* !defined(MSDOS) */ 49030043Sminshall upper = &Host[Highest]; 49130043Sminshall fieldattr = FieldAttributes(Lowest); 49230043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 49330043Sminshall columnsleft = NumberColumns-ScreenLineOffset(p-Host); 49430043Sminshall 49530043Sminshall while (p <= upper) { 49630054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 49730043Sminshall Highest = HighestScreen(); 49830043Sminshall Lowest = LowestScreen(); 49930043Sminshall FastScreen(); /* Recurse */ 50030043Sminshall return; 50130043Sminshall } else if (fieldattr) { /* Should we display? */ 50230043Sminshall addch(disp_asc[p->data]); /* Display translated data */ 50330043Sminshall } else { 50430043Sminshall addch(' '); /* Display a blank */ 50530043Sminshall } 50630043Sminshall /* If the physical screen is larger than what we 50730043Sminshall * are using, we need to make sure that each line 50830043Sminshall * starts at the beginning of the line. Otherwise, 50930043Sminshall * we will just string all the lines together. 51030043Sminshall */ 51130043Sminshall p++; 51230043Sminshall if (--columnsleft == 0) { 51330043Sminshall int i = p-Host; 51430043Sminshall 51530043Sminshall move(ScreenLine(i), 0); 51630043Sminshall columnsleft = NumberColumns; 51730043Sminshall } 51830043Sminshall } 51930043Sminshall } else { /* Going from Lowest to Highest */ 52030043Sminshall unsigned char tmpbuf[MAXNUMBERCOLUMNS+1]; 52130043Sminshall ScreenImage *End = &Host[ScreenSize]-1-SaveCorner; 52230043Sminshall register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns; 52330043Sminshall 52430043Sminshall *tmpend = 0; /* terminate from the beginning */ 52530043Sminshall move(0,0); 52630043Sminshall p = Host; 52730043Sminshall fieldattr = FieldAttributes(LowestScreen()); 52830043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 52930043Sminshall 53030043Sminshall while (p <= End) { 53130054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 53230043Sminshall if (tmp != tmpbuf) { 53330043Sminshall *tmp++ = 0; /* close out */ 53430043Sminshall addstr(tmpbuf); 53530043Sminshall tmp = tmpbuf; 53630043Sminshall tmpend = tmpbuf + NumberColumns - ScreenLineOffset(p-Host); 53730043Sminshall } 53830054Sminshall fieldattr = FieldAttributesPointer(p); /* Get attributes */ 53930043Sminshall DoAttribute(fieldattr); /* Set standout, non-display */ 54030043Sminshall *tmp++ = ' '; 54130043Sminshall } else { 54230043Sminshall if (fieldattr) { /* Should we display? */ 54330043Sminshall /* Display translated data */ 54430043Sminshall *tmp++ = disp_asc[p->data]; 54530043Sminshall } else { 54630043Sminshall *tmp++ = ' '; 54730043Sminshall } 54830043Sminshall } 54930043Sminshall /* If the physical screen is larger than what we 55030043Sminshall * are using, we need to make sure that each line 55130043Sminshall * starts at the beginning of the line. Otherwise, 55230043Sminshall * we will just string all the lines together. 55330043Sminshall */ 55430043Sminshall p++; 55530043Sminshall if (tmp == tmpend) { 55630043Sminshall int i = p-Host; /* Be sure the "p++" happened first! */ 55730043Sminshall 55830043Sminshall *tmp++ = 0; 55930043Sminshall addstr(tmpbuf); 56030043Sminshall tmp = tmpbuf; 56130043Sminshall move(ScreenLine(i), 0); 56230043Sminshall tmpend = tmpbuf + NumberColumns; 56330043Sminshall } 56430043Sminshall } 56530043Sminshall if (tmp != tmpbuf) { 56630043Sminshall *tmp++ = 0; 56730043Sminshall addstr(tmpbuf); 56830043Sminshall tmp = tmpbuf; 56930043Sminshall } 57030043Sminshall } 57130043Sminshall Lowest = HighestScreen()+1; 57230043Sminshall Highest = LowestScreen()-1; 57330043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 57430043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 57530043Sminshall ScreenLineOffset(terminalCursorAddress))) { 57630043Sminshall GoAway("move", terminalCursorAddress); 57730043Sminshall } 57830043Sminshall DoARefresh(); 57930043Sminshall if (needToRing) { 58030043Sminshall StringToTerminal(bellSequence); 58130043Sminshall needToRing = 0; 58230043Sminshall } 58330043Sminshall EmptyTerminal(); /* move data along */ 58430043Sminshall return; 58530043Sminshall } 58630043Sminshall 58730043Sminshall 58830043Sminshall /* TryToSend - send data out to user's terminal */ 58930043Sminshall 59030043Sminshall #if defined(NOT43) 59130043Sminshall int 59230043Sminshall #else /* defined(NOT43) */ 59330043Sminshall void 59430043Sminshall #endif /* defined(NOT43) */ 59530043Sminshall (*TryToSend)() = FastScreen; 59630043Sminshall 597*31127Sminshall void 598*31127Sminshall ScreenOIA(oia) 599*31127Sminshall OIA *oia; 600*31127Sminshall { 601*31127Sminshall } 602*31127Sminshall 603*31127Sminshall 60430328Sminshall /* InitTerminal - called to initialize the screen, etc. */ 60530043Sminshall 60630043Sminshall void 60730328Sminshall InitTerminal() 60830043Sminshall { 60930043Sminshall #if defined(unix) 61030043Sminshall struct sgttyb ourttyb; 61130043Sminshall static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 61230043Sminshall 2400, 4800, 9600 }; 61330043Sminshall #endif 61430043Sminshall 61530328Sminshall InitMapping(); /* Go do mapping file (MAP3270) first */ 61630043Sminshall if (!screenInitd) { /* not initialized */ 61730043Sminshall #if defined(unix) 61830043Sminshall char KSEbuffer[2050]; 61930043Sminshall char *lotsofspace = KSEbuffer; 62030043Sminshall extern int abort(); 62130043Sminshall extern char *tgetstr(); 62230043Sminshall #endif /* defined(unix) */ 62330043Sminshall 62430043Sminshall #if defined(SLOWSCREEN) 62531101Sminshall ClearArray(Terminal); 62630043Sminshall #endif /* defined(SLOWSCREEN) */ 62730328Sminshall terminalCursorAddress = SetBufferAddress(0,0); 62830043Sminshall #if defined(unix) 62930043Sminshall signal(SIGHUP, abort); 63030043Sminshall #endif 63130043Sminshall 63230043Sminshall TryToSend = FastScreen; 63330043Sminshall #if defined(unix) && defined(SLOWSCREEN) 63430043Sminshall ioctl(1, TIOCGETP, (char *) &ourttyb); 63530043Sminshall if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) { 63630043Sminshall max_changes_before_poll = 1920; 63730043Sminshall } else { 63830043Sminshall max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10; 63930043Sminshall if (max_changes_before_poll < 40) { 64030043Sminshall max_changes_before_poll = 40; 64130043Sminshall } 64230043Sminshall TryToSend = SlowScreen; 64330043Sminshall HaveInput = 1; /* get signals going */ 64430043Sminshall } 64530043Sminshall #endif /* defined(unix) && defined(SLOWSCREEN) */ 64630043Sminshall setcommandmode(); 64730043Sminshall /* 64830043Sminshall * By now, initscr() (in curses) has been called (from telnet.c), 64930043Sminshall * and the screen has been initialized. 65030043Sminshall */ 65130043Sminshall #if defined(unix) 65230043Sminshall nonl(); 65330043Sminshall /* the problem is that curses catches SIGTSTP to 65430043Sminshall * be nice, but it messes us up. 65530043Sminshall */ 65630043Sminshall signal(SIGTSTP, SIG_DFL); 65730043Sminshall if ((KS = tgetstr("ks", &lotsofspace)) != 0) { 65830043Sminshall KS = strsave(KS); 65930043Sminshall StringToTerminal(KS); 66030043Sminshall } 66130043Sminshall if ((KE = tgetstr("ke", &lotsofspace)) != 0) { 66230043Sminshall KE = strsave(KE); 66330043Sminshall } 66430043Sminshall if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) { 66530043Sminshall SO = strsave(tgetstr("md", &lotsofspace)); 66630043Sminshall SE = strsave(tgetstr("me", &lotsofspace)); 66730043Sminshall } 66830043Sminshall #endif 66930043Sminshall DoARefresh(); 67030043Sminshall setconnmode(); 67130043Sminshall if (VB && *VB) { 67230043Sminshall bellSequence = VB; /* use visual bell */ 67330043Sminshall } 67430043Sminshall screenInitd = 1; 67530043Sminshall screenStopped = 0; /* Not stopped */ 67630043Sminshall } 67730328Sminshall Initialized = 1; 67830043Sminshall } 67930043Sminshall 68030043Sminshall 68130043Sminshall /* StopScreen - called when we are going away... */ 68230043Sminshall 68330043Sminshall void 68430043Sminshall StopScreen(doNewLine) 68530043Sminshall int doNewLine; 68630043Sminshall { 68730043Sminshall if (screenInitd && !screenStopped) { 68830043Sminshall move(NumberLines-1, 1); 68930043Sminshall standend(); 69030043Sminshall #if defined(SLOWSCREEN) 69130043Sminshall inHighlightMode = 0; 69230043Sminshall #endif /* defined(SLOWSCREEN) */ 69330043Sminshall DoARefresh(); 69430043Sminshall setcommandmode(); 69530043Sminshall endwin(); 69630043Sminshall setconnmode(); 69730043Sminshall #if defined(unix) 69830043Sminshall if (KE) { 69930043Sminshall StringToTerminal(KE); 70030043Sminshall } 70130043Sminshall #endif /* defined(unix) */ 70230043Sminshall if (doNewLine) { 70330043Sminshall StringToTerminal("\r\n"); 70430043Sminshall } 70530043Sminshall EmptyTerminal(); 70630043Sminshall screenStopped = 1; /* This is stopped */ 70730043Sminshall } 70830043Sminshall } 70930043Sminshall 71030043Sminshall 71130043Sminshall /* RefreshScreen - called to cause the screen to be refreshed */ 71230043Sminshall 71330043Sminshall void 71430043Sminshall RefreshScreen() 71530043Sminshall { 71630043Sminshall clearok(curscr, TRUE); 71730043Sminshall (*TryToSend)(); 71830043Sminshall } 71930043Sminshall 72030043Sminshall 72130043Sminshall /* ConnectScreen - called to reconnect to the screen */ 72230043Sminshall 72330043Sminshall void 72430043Sminshall ConnectScreen() 72530043Sminshall { 72630043Sminshall if (screenInitd) { 72730043Sminshall #if defined(unix) 72830043Sminshall if (KS) { 72930043Sminshall StringToTerminal(KS); 73030043Sminshall } 73130043Sminshall #endif /* defined(unix) */ 73230043Sminshall RefreshScreen(); 73330043Sminshall (*TryToSend)(); 73430043Sminshall screenStopped = 0; 73530043Sminshall } 73630043Sminshall } 73730043Sminshall 73830043Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */ 73930043Sminshall 74030043Sminshall void 74130043Sminshall LocalClearScreen() 74230043Sminshall { 74330043Sminshall outputPurge(); /* flush all data to terminal */ 74430043Sminshall clear(); /* clear in curses */ 74530043Sminshall #if defined(SLOWSCREEN) 74631101Sminshall ClearArray(Terminal); 74730043Sminshall #endif /* defined(SLOWSCREEN) */ 74830043Sminshall Clear3270(); 74930043Sminshall Lowest = HighestScreen()+1; /* everything in sync... */ 75030043Sminshall Highest = LowestScreen()+1; 75130043Sminshall } 75230043Sminshall 75330043Sminshall 75430043Sminshall void 75530043Sminshall BellOff() 75630043Sminshall { 75730043Sminshall if (bellwinup) { 75830043Sminshall delwin(bellwin); 75930043Sminshall bellwin = 0; 76030043Sminshall bellwinup = 0; 76130043Sminshall Lowest = MIN(Lowest, LINES/2); 76230043Sminshall Highest = MAX(Highest, (LINES/2)+3); 76330043Sminshall #if defined(SLOWSCREEN) 76431101Sminshall memset(Terminal+LINES/2, 0, (sizeof Terminal[0])*(3*COLS)); 76530043Sminshall #endif /* defined(SLOWSCREEN) */ 76630043Sminshall touchwin(stdscr); 76730043Sminshall DoARefresh(); 76830043Sminshall } 76930043Sminshall } 77030043Sminshall 77130043Sminshall 77230043Sminshall void 77330043Sminshall RingBell(s) 77430043Sminshall char *s; 77530043Sminshall { 77630043Sminshall needToRing = 1; 77730043Sminshall if (s) { 77830043Sminshall int len = strlen(s); 77930043Sminshall 78030043Sminshall if (len > COLS-2) { 78130043Sminshall len = COLS-2; 78230043Sminshall } 78330043Sminshall if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) { 78430043Sminshall OurExitString(stderr, "Error from newwin in RingBell", 1); 78530043Sminshall } 78630043Sminshall werase(bellwin); 78730043Sminshall wstandout(bellwin); 78830043Sminshall box(bellwin, '|', '-'); 78930043Sminshall if (wmove(bellwin, 1, 1) == ERR) { 79030043Sminshall OurExitString(stderr, "Error from wmove in RingBell", 1); 79130043Sminshall } 79230043Sminshall while (len--) { 79330043Sminshall if (waddch(bellwin, *s++) == ERR) { 79430043Sminshall OurExitString(stderr, "Error from waddch in RingBell", 1); 79530043Sminshall } 79630043Sminshall } 79730043Sminshall wstandend(bellwin); 79830043Sminshall if (wrefresh(bellwin) == ERR) { 79930043Sminshall OurExitString(stderr, "Error from wrefresh in RingBell", 1); 80030043Sminshall } 80130043Sminshall bellwinup = 1; 80230043Sminshall } 80330043Sminshall } 80430043Sminshall 80530043Sminshall 80630043Sminshall /* returns a 1 if no more output available (so, go ahead and block), 80730043Sminshall or a 0 if there is more output available (so, just poll the other 80830043Sminshall sources/destinations, don't block). 80930043Sminshall */ 81030043Sminshall 81130043Sminshall int 81230043Sminshall DoTerminalOutput() 81330043Sminshall { 81430043Sminshall /* called just before a select to conserve IO to terminal */ 81530369Sminshall if (!Initialized) { 81630369Sminshall return 1; /* No output if not initialized */ 81730369Sminshall } 81830369Sminshall if ((Lowest <= Highest) || needToRing || 81930369Sminshall (terminalCursorAddress != CorrectTerminalCursor())) { 82030043Sminshall (*TryToSend)(); 82130043Sminshall } 82230043Sminshall if (Lowest > Highest) { 82330369Sminshall return 1; /* no more output now */ 82430043Sminshall } else { 82530369Sminshall return 0; /* more output for future */ 82630043Sminshall } 82730043Sminshall } 82830074Sminshall 82930074Sminshall /* 83030074Sminshall * The following are defined to handle transparent data. 83130074Sminshall */ 83230074Sminshall 83330074Sminshall void 83430074Sminshall TransStop() 83530074Sminshall { 83630074Sminshall #if defined(unix) 83730074Sminshall if (tcflag == 0) { 83830074Sminshall tcflag = -1; 83930074Sminshall (void) signal(SIGCHLD, SIG_DFL); 84030074Sminshall } else if (tcflag > 0) { 84130074Sminshall setcommandmode(); 84230074Sminshall (void) close(tin); 84330074Sminshall (void) close(tout); 84430074Sminshall tin = savefd[0]; 84530074Sminshall tout = savefd[1]; 84630074Sminshall setconnmode(); 84730074Sminshall tcflag = -1; 84830074Sminshall (void) signal(SIGCHLD, SIG_DFL); 84930074Sminshall } 85030074Sminshall #endif /* defined(unix) */ 85130074Sminshall RefreshScreen(); 85230074Sminshall } 85330074Sminshall 85430074Sminshall void 85530074Sminshall TransOut(buffer, count) 85630074Sminshall unsigned char *buffer; 85730074Sminshall int count; 85830074Sminshall { 85930074Sminshall #if defined(unix) 86030074Sminshall extern char *transcom; 86130074Sminshall int inpipefd[2], outpipefd[2], savemode; 86230074Sminshall void aborttc(); 86330074Sminshall #endif /* defined(unix) */ 86430074Sminshall 86530074Sminshall while (DoTerminalOutput() == 0) { 86630074Sminshall #if defined(unix) 86730074Sminshall HaveInput = 0; 86830074Sminshall #endif /* defined(unix) */ 86930074Sminshall } 87030074Sminshall #if defined(unix) 87130074Sminshall if (transcom && tcflag == -1) { 87230074Sminshall while (1) { /* go thru once */ 87330074Sminshall if (pipe(outpipefd) < 0) { 87430074Sminshall break; 87530074Sminshall } 87630074Sminshall if (pipe(inpipefd) < 0) { 87730074Sminshall break; 87830074Sminshall } 87930074Sminshall if ((tcflag = fork()) == 0) { 88030074Sminshall (void) close(outpipefd[1]); 88130074Sminshall (void) close(0); 88230074Sminshall if (dup(outpipefd[0]) < 0) { 88330074Sminshall exit(1); 88430074Sminshall } 88530074Sminshall (void) close(outpipefd[0]); 88630074Sminshall (void) close(inpipefd[0]); 88730074Sminshall (void) close(1); 88830074Sminshall if (dup(inpipefd[1]) < 0) { 88930074Sminshall exit(1); 89030074Sminshall } 89130074Sminshall (void) close(inpipefd[1]); 89230074Sminshall if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) { 89330074Sminshall exit(1); 89430074Sminshall } 89530074Sminshall } 89630074Sminshall (void) close(inpipefd[1]); 89730074Sminshall (void) close(outpipefd[0]); 89830074Sminshall savefd[0] = tin; 89930074Sminshall savefd[1] = tout; 90030074Sminshall setcommandmode(); 90130074Sminshall tin = inpipefd[0]; 90230074Sminshall tout = outpipefd[1]; 90330074Sminshall (void) signal(SIGCHLD, aborttc); 90430074Sminshall setconnmode(); 90530074Sminshall tcflag = 1; 90630074Sminshall break; 90730074Sminshall } 90830074Sminshall if (tcflag < 1) { 90930074Sminshall tcflag = 0; 91030074Sminshall } 91130074Sminshall } 91230074Sminshall #endif /* defined(unix) */ 91330074Sminshall (void) DataToTerminal(buffer, count); 91430074Sminshall } 91530074Sminshall 91630074Sminshall 91730074Sminshall #if defined(unix) 91830074Sminshall static void 91930074Sminshall aborttc() 92030074Sminshall { 92130074Sminshall int savemode; 92230074Sminshall 92330074Sminshall setcommandmode(); 92430074Sminshall (void) close(tin); 92530074Sminshall (void) close(tout); 92630074Sminshall tin = savefd[0]; 92730074Sminshall tout = savefd[1]; 92830074Sminshall setconnmode(); 92930074Sminshall tcflag = 0; 93030074Sminshall } 93130074Sminshall #endif /* defined(unix) */ 932