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 3430043Sminshall #include "terminal.h" 3530043Sminshall 3630043Sminshall #include "../telnet.ext" 3730043Sminshall 3830043Sminshall #include "../ctlr/hostctlr.h" 3930043Sminshall #include "../ctlr/inbound.ext" 4030043Sminshall #include "../ctlr/options.ext" 4130043Sminshall #include "../ctlr/outbound.ext" 4230043Sminshall #include "../ctlr/screen.h" 4330043Sminshall 4430043Sminshall #include "../keyboard/map3270.ext" 4530043Sminshall 4630043Sminshall #include "../system/globals.h" 4730043Sminshall 4830043Sminshall extern void EmptyTerminal(); 4930043Sminshall 5030043Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \ 5130043Sminshall terminalCursorAddress:UnLocked? CursorAddress: HighestScreen()) 5230043Sminshall 5330043Sminshall 5430043Sminshall static int terminalCursorAddress = 0; /* where the cursor is on term */ 5530043Sminshall static int screenInitd = 0; /* the screen has been initialized */ 5630043Sminshall static int screenStopped = 1; /* the screen has been stopped */ 5730043Sminshall #if defined(SLOWSCREEN) 5830043Sminshall static int max_changes_before_poll; /* how many characters before looking */ 5930043Sminshall /* at terminal and net again */ 6030043Sminshall #endif /* defined(SLOWSCREEN) */ 6130043Sminshall 6230043Sminshall static int needToRing = 0; /* need to ring terinal bell */ 6330043Sminshall static char *bellSequence = "\07"; /* bell sequence (may be replaced by 6430043Sminshall * VB during initialization) 6530043Sminshall */ 6630043Sminshall static WINDOW *bellwin; /* The window the bell message is in */ 6730043Sminshall int bellwinup = 0; /* Are we up with it or not */ 6830043Sminshall 6930043Sminshall #if defined(unix) 7030043Sminshall static char *KS, *KE; 7130043Sminshall #endif /* defined(unix) */ 7230043Sminshall 73*30074Sminshall 74*30074Sminshall #if defined(SLOWSCREEN) 75*30074Sminshall static int inHighlightMode = 0; 76*30074Sminshall #endif /* defined(SLOWSCREEN) */ 77*30074Sminshall 78*30074Sminshall /* Variables for transparent mode */ 7930043Sminshall #if defined(unix) 8030043Sminshall static int tcflag = -1; /* transparent mode command flag */ 8130043Sminshall static int savefd[2]; /* for storing fds during transcom */ 82*30074Sminshall extern int tin, tout; /* file descriptors */ 8330043Sminshall #endif /* defined(unix) */ 8430043Sminshall 8530043Sminshall 8630043Sminshall #include "disp_asc.out" 8730043Sminshall 8830043Sminshall 8930043Sminshall /* OurExitString - designed to keep us from going through infinite recursion */ 9030043Sminshall 9130043Sminshall static void 9230043Sminshall OurExitString(file, string, value) 9330043Sminshall FILE *file; 9430043Sminshall char *string; 9530043Sminshall int value; 9630043Sminshall { 9730043Sminshall static int recursion = 0; 9830043Sminshall 9930043Sminshall if (!recursion) { 10030043Sminshall recursion = 1; 10130043Sminshall ExitString(file, string, value); 10230043Sminshall } 10330043Sminshall } 10430043Sminshall 10530043Sminshall 10630043Sminshall /* DoARefresh */ 10730043Sminshall 10830043Sminshall static void 10930043Sminshall DoARefresh() 11030043Sminshall { 11130043Sminshall if (ERR == refresh()) { 11230043Sminshall OurExitString(stderr, "ERR from refresh\n", 1); 11330043Sminshall } 11430043Sminshall } 11530043Sminshall 11630043Sminshall static void 11730043Sminshall GoAway(from, where) 11830043Sminshall char *from; /* routine that gave error */ 11930043Sminshall int where; /* cursor address */ 12030043Sminshall { 12130043Sminshall char foo[100]; 12230043Sminshall 12330043Sminshall sprintf(foo, "ERR from %s at %d (%d, %d)\n", 12430043Sminshall from, where, ScreenLine(where), ScreenLineOffset(where)); 12530043Sminshall OurExitString(stderr, foo, 1); 12630043Sminshall /* NOTREACHED */ 12730043Sminshall } 12830043Sminshall 12930043Sminshall #if defined(SLOWSCREEN) 13030043Sminshall /* What is the screen address of the attribute byte for the terminal */ 13130043Sminshall 13230043Sminshall static int 13330043Sminshall WhereTermAttrByte(p) 13430043Sminshall register int p; 13530043Sminshall { 13630043Sminshall register int i; 13730043Sminshall 13830043Sminshall i = p; 13930043Sminshall 14030043Sminshall do { 14130043Sminshall if (TermIsStartField(i)) { 14230043Sminshall return(i); 14330043Sminshall } 14430043Sminshall i = ScreenDec(i); 14530043Sminshall } while (i != p); 14630043Sminshall 14730043Sminshall return(LowestScreen()); /* unformatted screen... */ 14830043Sminshall } 14930043Sminshall #endif /* defined(SLOWSCREEN) */ 15030043Sminshall 15130043Sminshall /* 15230043Sminshall * There are two algorithms for updating the screen. 15330043Sminshall * The first, SlowScreen() optimizes the line between the 15430043Sminshall * computer and the screen (say a 9600 baud line). To do 15530043Sminshall * this, we break out of the loop every so often to look 15630043Sminshall * at any pending input from the network (so that successive 15730043Sminshall * screens will only partially print until the final screen, 15830043Sminshall * the one the user possibly wants to see, is displayed 15930043Sminshall * in its entirety). 16030043Sminshall * 16130043Sminshall * The second algorithm tries to optimize CPU time (by 16230043Sminshall * being simpler) at the cost of the bandwidth to the 16330043Sminshall * screen. 16430043Sminshall * 16530043Sminshall * Of course, curses(3X) gets in here also. 16630043Sminshall */ 16730043Sminshall 16830043Sminshall 16930043Sminshall #if defined(SLOWSCREEN) 17030043Sminshall #if defined(NOT43) 17130043Sminshall static int 17230043Sminshall #else /* defined(NOT43) */ 17330043Sminshall static void 17430043Sminshall #endif /* defined(NOT43) */ 17530043Sminshall SlowScreen() 17630043Sminshall { 17730043Sminshall register int pointer; 17830043Sminshall register int c; 17930043Sminshall register int fieldattr; 18030043Sminshall register int columnsleft; 18130043Sminshall 18230043Sminshall # define SetHighlightMode(p) { \ 18330043Sminshall if (!IsStartField(p) && IsHighlightedAttr(fieldattr)) { \ 18430043Sminshall if (!inHighlightMode) { \ 18530043Sminshall inHighlightMode = 1; \ 18630043Sminshall standout(); \ 18730043Sminshall } \ 18830043Sminshall } else { \ 18930043Sminshall if (inHighlightMode) { \ 19030043Sminshall inHighlightMode = 0; \ 19130043Sminshall standend(); \ 19230043Sminshall } \ 19330043Sminshall } \ 19430043Sminshall } 19530043Sminshall 19630043Sminshall # define DoCharacterAt(c,p) { \ 19730043Sminshall SetTerminal(p, c); \ 19830043Sminshall if (p != HighestScreen()) { \ 19930043Sminshall c = TerminalCharacterAttr(disp_asc[c&0xff], p, \ 20030043Sminshall fieldattr); \ 20130043Sminshall if (terminalCursorAddress != p) { \ 20230043Sminshall if (ERR == mvaddch(ScreenLine(p), \ 20330043Sminshall ScreenLineOffset(p), c)) {\ 20430043Sminshall GoAway("mvaddch", p); \ 20530043Sminshall } \ 20630043Sminshall } else { \ 20730043Sminshall if (ERR == addch(c)) {\ 20830043Sminshall GoAway("addch", p); \ 20930043Sminshall } \ 21030043Sminshall } \ 21130043Sminshall terminalCursorAddress = ScreenInc(p); \ 21230043Sminshall } \ 21330043Sminshall } 21430043Sminshall 21530043Sminshall 21630043Sminshall /* run through screen, printing out non-null lines */ 21730043Sminshall 21830043Sminshall /* There are two separate reasons for wanting to terminate this 21930043Sminshall * loop early. One is to respond to new input (either from 22030043Sminshall * the terminal or from the network [host]). For this reason, 22130043Sminshall * we expect to see 'HaveInput' come true when new input comes in. 22230043Sminshall * 22330043Sminshall * The second reason is a bit more difficult (for me) to understand. 22430043Sminshall * Basically, we don't want to get too far ahead of the characters that 22530043Sminshall * appear on the screen. Ideally, we would type out a few characters, 22630043Sminshall * wait until they appeared on the screen, then type out a few more. 22730043Sminshall * The reason for this is that the user, on seeing some characters 22830043Sminshall * appear on the screen may then start to type something. We would 22930043Sminshall * like to look at what the user types at about the same 'time' 23030043Sminshall * (measured by characters being sent to the terminal) that the 23130043Sminshall * user types them. For this reason, what we would like to do 23230043Sminshall * is update a bit, then call curses to do a refresh, flush the 23330043Sminshall * output to the terminal, then wait until the terminal data 23430043Sminshall * has been sent. 23530043Sminshall * 23630043Sminshall * Note that curses is useful for, among other things, deciding whether 23730043Sminshall * or not to send :ce: (clear to end of line), so we should call curses 23830043Sminshall * at end of lines (beginning of next lines). 23930043Sminshall * 24030043Sminshall * The problems here are the following: If we do lots of write(2)s, 24130043Sminshall * we will be doing lots of context switches, thus lots of overhead 24230043Sminshall * (which we have already). Second, if we do a select to wait for 24330043Sminshall * the output to drain, we have to contend with the fact that NOW 24430043Sminshall * we are scheduled to run, but who knows what the scheduler will 24530043Sminshall * decide when the output has caught up. 24630043Sminshall */ 24730043Sminshall 24830043Sminshall if (Highest == HighestScreen()) { 24930043Sminshall Highest = ScreenDec(Highest); /* else, while loop will never end */ 25030043Sminshall } 25130043Sminshall if (Lowest < LowestScreen()) { 25230043Sminshall Lowest = LowestScreen(); /* could be -1 in some cases with 25330043Sminshall * unformatted screens. 25430043Sminshall */ 25530043Sminshall } 25630043Sminshall if (Highest >= (pointer = Lowest)) { 25730043Sminshall /* if there is anything to do, do it. We won't terminate 25830043Sminshall * the loop until we've gone at least to Highest. 25930043Sminshall */ 26030043Sminshall while ((pointer <= Highest) && !HaveInput) { 26130043Sminshall 26230043Sminshall /* point at the next place of disagreement */ 26330043Sminshall pointer += (bunequal(Host+pointer, Terminal+pointer, 26430043Sminshall (Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]); 26530043Sminshall 26630043Sminshall /* how many characters to change until the end of the 26730043Sminshall * current line 26830043Sminshall */ 26930043Sminshall columnsleft = NumberColumns - ScreenLineOffset(pointer); 27030043Sminshall /* 27130043Sminshall * Make sure we are where we think we are. 27230043Sminshall */ 27330043Sminshall move(ScreenLine(pointer), ScreenLineOffset(pointer)); 27430043Sminshall 27530043Sminshall /* what is the field attribute of the current position */ 27630043Sminshall fieldattr = FieldAttributes(WhereAttrByte(pointer)); 27730043Sminshall 27830043Sminshall if ((IsStartField(pointer) != TermIsStartField(pointer)) || 27930043Sminshall (IsStartField(pointer) && 28030043Sminshall fieldattr != TermAttributes(pointer))) { 28130043Sminshall 28230043Sminshall int oldterm; 28330043Sminshall 28430043Sminshall oldterm = TermAttributes(pointer); 28530043Sminshall if (IsStartField(pointer)) { 28630043Sminshall TermNewField(pointer, fieldattr); 28730043Sminshall SetTerminal(pointer, 0); 28830043Sminshall } else { 28930043Sminshall TermDeleteField(pointer); 29030043Sminshall } 29130043Sminshall /* We always do the first character in a divergent 29230043Sminshall * field, since otherwise the start of a field in 29330043Sminshall * the Host structure may leave a highlighted blank 29430043Sminshall * on the screen, and the start of a field in the 29530043Sminshall * Terminal structure may leave a non-highlighted 29630043Sminshall * something in the middle of a highlighted field 29730043Sminshall * on the screen. 29830043Sminshall */ 29930043Sminshall SetHighlightMode(pointer); 30030043Sminshall c = GetHost(pointer); 30130043Sminshall DoCharacterAt(c,pointer); /* MACRO */ 30230043Sminshall 30330043Sminshall if (NotVisuallyCompatibleAttributes 30430043Sminshall (pointer, fieldattr, oldterm)) { 30530043Sminshall int j; 30630043Sminshall 30730043Sminshall j = pointer; 30830043Sminshall 30930043Sminshall pointer = ScreenInc(pointer); 31030043Sminshall if (!(--columnsleft)) { 31130043Sminshall DoARefresh(); 31230043Sminshall EmptyTerminal(); 31330043Sminshall move(ScreenLine(pointer), 0); 31430043Sminshall columnsleft = NumberColumns; 31530043Sminshall } 31630043Sminshall SetHighlightMode(pointer); /* Turn on highlighting */ 31730043Sminshall while (!IsStartField(pointer) && 31830043Sminshall !TermIsStartField(pointer)) { 31930043Sminshall c = GetHost(pointer); 32030043Sminshall DoCharacterAt(c,pointer); /* MACRO */ 32130043Sminshall pointer = ScreenInc(pointer); 32230043Sminshall if (!(--columnsleft)) { 32330043Sminshall DoARefresh(); 32430043Sminshall EmptyTerminal(); 32530043Sminshall move(ScreenLine(pointer), 0); 32630043Sminshall columnsleft = NumberColumns; 32730043Sminshall /* We don't look at HaveInput here, since 32830043Sminshall * if we leave this loop before the end of 32930043Sminshall * the 3270 field, we could have pointer 33030043Sminshall * higher than Highest. This would cause 33130043Sminshall * us to end the highest "while" loop, 33230043Sminshall * but we may, in fact, need to go around the 33330043Sminshall * screen once again. 33430043Sminshall */ 33530043Sminshall } 33630043Sminshall /* The loop needs to be protected 33730043Sminshall * from the situation where there had been only 33830043Sminshall * one field on the Terminal, and none on the Host. 33930043Sminshall * In this case, we have just deleted our last 34030043Sminshall * field. Hence, the break. 34130043Sminshall */ 34230043Sminshall if (j == pointer) { 34330043Sminshall break; 34430043Sminshall } 34530043Sminshall } 34630043Sminshall if (IsStartField(pointer) && !TermIsStartField(pointer)) { 34730043Sminshall /* Remember what the terminal looked like */ 34830043Sminshall TermNewField(pointer, oldterm); 34930043Sminshall /* 35030043Sminshall * The danger here is that the current position may 35130043Sminshall * be the start of a Host field. If so, and the 35230043Sminshall * field is highlighted, and our terminal was 35330043Sminshall * highlighted, then we will leave a highlighted 35430043Sminshall * blank at this position. 35530043Sminshall */ 35630043Sminshall SetHighlightMode(pointer); 35730043Sminshall c = GetHost(pointer); 35830043Sminshall DoCharacterAt(c,pointer); 35930043Sminshall } 36030043Sminshall /* We could be in the situation of needing to exit. 36130043Sminshall * This could happen if the current field wrapped around 36230043Sminshall * the end of the screen. 36330043Sminshall */ 36430043Sminshall if (j > pointer) { 36530043Sminshall break; 36630043Sminshall } 36730043Sminshall } else { 36830043Sminshall c = GetHost(pointer); 36930043Sminshall /* We always do the first character in a divergent 37030043Sminshall * field, since otherwise the start of a field in 37130043Sminshall * the Host structure may leave a highlighted blank 37230043Sminshall * on the screen, and the start of a field in the 37330043Sminshall * Terminal structure may leave a non-highlighted 37430043Sminshall * something in the middle of a highlighted field 37530043Sminshall * on the screen. 37630043Sminshall */ 37730043Sminshall SetHighlightMode(pointer); 37830043Sminshall DoCharacterAt(c,pointer); 37930043Sminshall } 38030043Sminshall } else { 38130043Sminshall SetHighlightMode(pointer); 38230054Sminshall /* 38330054Sminshall * The following will terminate at least when we get back 38430043Sminshall * to the original 'pointer' location (since we force 38530043Sminshall * things to be equal). 38630043Sminshall */ 38730043Sminshall while (((c = GetHost(pointer)) != GetTerminal(pointer)) && 38830043Sminshall !IsStartField(pointer) && !TermIsStartField(pointer)) { 38930043Sminshall DoCharacterAt(c, pointer); 39030043Sminshall pointer = ScreenInc(pointer); 39130043Sminshall if (!(--columnsleft)) { 39230043Sminshall DoARefresh(); 39330043Sminshall EmptyTerminal(); 39430043Sminshall if (HaveInput) { /* if input came in, take it */ 39530043Sminshall break; 39630043Sminshall } 39730043Sminshall move(ScreenLine(pointer), 0); 39830043Sminshall columnsleft = NumberColumns; 39930043Sminshall } 40030043Sminshall } 40130043Sminshall } 40230043Sminshall } 40330043Sminshall } 40430043Sminshall DoARefresh(); 40530043Sminshall Lowest = pointer; 40630043Sminshall if (Lowest > Highest) { /* if we finished input... */ 40730043Sminshall Lowest = HighestScreen()+1; 40830043Sminshall Highest = LowestScreen()-1; 40930043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 41030043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 41130043Sminshall ScreenLineOffset(terminalCursorAddress))) { 41230043Sminshall GoAway("move", terminalCursorAddress); 41330043Sminshall } 41430043Sminshall DoARefresh(); 41530043Sminshall if (needToRing) { 41630043Sminshall StringToTerminal(bellSequence); 41730043Sminshall needToRing = 0; 41830043Sminshall } 41930043Sminshall } 42030043Sminshall EmptyTerminal(); /* move data along */ 42130043Sminshall return; 42230043Sminshall } 42330043Sminshall #endif /* defined(SLOWSCREEN) */ 42430043Sminshall 42530043Sminshall #if defined(NOT43) 42630043Sminshall static int 42730043Sminshall #else /* defined(NOT43) */ 42830043Sminshall static void 42930043Sminshall #endif /* defined(NOT43) */ 43030043Sminshall FastScreen() 43130043Sminshall { 43230043Sminshall #if defined(msdos) 43330043Sminshall #define SaveCorner 0 43430043Sminshall #else /* defined(msdos) */ 43530043Sminshall #define SaveCorner 1 43630043Sminshall #endif /* defined(msdos) */ 43730043Sminshall 43830043Sminshall #define DoAttribute(a) if (IsHighlightedAttr(a)) { \ 43930043Sminshall standout(); \ 44030043Sminshall } else { \ 44130043Sminshall standend(); \ 44230043Sminshall } \ 44330043Sminshall if (IsNonDisplayAttr(a)) { \ 44430043Sminshall a = 0; /* zero == don't display */ \ 44530043Sminshall } \ 44630043Sminshall if (!FormattedScreen()) { \ 44730043Sminshall a = 1; /* one ==> do display on unformatted */\ 44830043Sminshall } 44930043Sminshall ScreenImage *p, *upper; 45030043Sminshall int fieldattr; /* spends most of its time == 0 or 1 */ 45130043Sminshall 45230043Sminshall /* OK. We want to do this a quickly as possible. So, we assume we 45330043Sminshall * only need to go from Lowest to Highest. However, if we find a 45430043Sminshall * field in the middle, we do the whole screen. 45530043Sminshall * 45630043Sminshall * In particular, we separate out the two cases from the beginning. 45730043Sminshall */ 45830043Sminshall if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) { 45930043Sminshall register int columnsleft; 46030043Sminshall 46130043Sminshall move(ScreenLine(Lowest), ScreenLineOffset(Lowest)); 46230043Sminshall p = &Host[Lowest]; 46330043Sminshall #if !defined(msdos) 46430043Sminshall if (Highest == HighestScreen()) { 46530043Sminshall Highest = ScreenDec(Highest); 46630043Sminshall } 46730043Sminshall #endif /* !defined(msdos) */ 46830043Sminshall upper = &Host[Highest]; 46930043Sminshall fieldattr = FieldAttributes(Lowest); 47030043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 47130043Sminshall columnsleft = NumberColumns-ScreenLineOffset(p-Host); 47230043Sminshall 47330043Sminshall while (p <= upper) { 47430054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 47530043Sminshall Highest = HighestScreen(); 47630043Sminshall Lowest = LowestScreen(); 47730043Sminshall FastScreen(); /* Recurse */ 47830043Sminshall return; 47930043Sminshall } else if (fieldattr) { /* Should we display? */ 48030043Sminshall addch(disp_asc[p->data]); /* Display translated data */ 48130043Sminshall } else { 48230043Sminshall addch(' '); /* Display a blank */ 48330043Sminshall } 48430043Sminshall /* If the physical screen is larger than what we 48530043Sminshall * are using, we need to make sure that each line 48630043Sminshall * starts at the beginning of the line. Otherwise, 48730043Sminshall * we will just string all the lines together. 48830043Sminshall */ 48930043Sminshall p++; 49030043Sminshall if (--columnsleft == 0) { 49130043Sminshall int i = p-Host; 49230043Sminshall 49330043Sminshall move(ScreenLine(i), 0); 49430043Sminshall columnsleft = NumberColumns; 49530043Sminshall } 49630043Sminshall } 49730043Sminshall } else { /* Going from Lowest to Highest */ 49830043Sminshall unsigned char tmpbuf[MAXNUMBERCOLUMNS+1]; 49930043Sminshall ScreenImage *End = &Host[ScreenSize]-1-SaveCorner; 50030043Sminshall register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns; 50130043Sminshall 50230043Sminshall *tmpend = 0; /* terminate from the beginning */ 50330043Sminshall move(0,0); 50430043Sminshall p = Host; 50530043Sminshall fieldattr = FieldAttributes(LowestScreen()); 50630043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 50730043Sminshall 50830043Sminshall while (p <= End) { 50930054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 51030043Sminshall if (tmp != tmpbuf) { 51130043Sminshall *tmp++ = 0; /* close out */ 51230043Sminshall addstr(tmpbuf); 51330043Sminshall tmp = tmpbuf; 51430043Sminshall tmpend = tmpbuf + NumberColumns - ScreenLineOffset(p-Host); 51530043Sminshall } 51630054Sminshall fieldattr = FieldAttributesPointer(p); /* Get attributes */ 51730043Sminshall DoAttribute(fieldattr); /* Set standout, non-display */ 51830043Sminshall *tmp++ = ' '; 51930043Sminshall } else { 52030043Sminshall if (fieldattr) { /* Should we display? */ 52130043Sminshall /* Display translated data */ 52230043Sminshall *tmp++ = disp_asc[p->data]; 52330043Sminshall } else { 52430043Sminshall *tmp++ = ' '; 52530043Sminshall } 52630043Sminshall } 52730043Sminshall /* If the physical screen is larger than what we 52830043Sminshall * are using, we need to make sure that each line 52930043Sminshall * starts at the beginning of the line. Otherwise, 53030043Sminshall * we will just string all the lines together. 53130043Sminshall */ 53230043Sminshall p++; 53330043Sminshall if (tmp == tmpend) { 53430043Sminshall int i = p-Host; /* Be sure the "p++" happened first! */ 53530043Sminshall 53630043Sminshall *tmp++ = 0; 53730043Sminshall addstr(tmpbuf); 53830043Sminshall tmp = tmpbuf; 53930043Sminshall move(ScreenLine(i), 0); 54030043Sminshall tmpend = tmpbuf + NumberColumns; 54130043Sminshall } 54230043Sminshall } 54330043Sminshall if (tmp != tmpbuf) { 54430043Sminshall *tmp++ = 0; 54530043Sminshall addstr(tmpbuf); 54630043Sminshall tmp = tmpbuf; 54730043Sminshall } 54830043Sminshall } 54930043Sminshall Lowest = HighestScreen()+1; 55030043Sminshall Highest = LowestScreen()-1; 55130043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 55230043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 55330043Sminshall ScreenLineOffset(terminalCursorAddress))) { 55430043Sminshall GoAway("move", terminalCursorAddress); 55530043Sminshall } 55630043Sminshall DoARefresh(); 55730043Sminshall if (needToRing) { 55830043Sminshall StringToTerminal(bellSequence); 55930043Sminshall needToRing = 0; 56030043Sminshall } 56130043Sminshall EmptyTerminal(); /* move data along */ 56230043Sminshall return; 56330043Sminshall } 56430043Sminshall 56530043Sminshall 56630043Sminshall /* TryToSend - send data out to user's terminal */ 56730043Sminshall 56830043Sminshall #if defined(NOT43) 56930043Sminshall int 57030043Sminshall #else /* defined(NOT43) */ 57130043Sminshall void 57230043Sminshall #endif /* defined(NOT43) */ 57330043Sminshall (*TryToSend)() = FastScreen; 57430043Sminshall 57530043Sminshall /* StartScreen - called to initialize the screen, etc. */ 57630043Sminshall 57730043Sminshall void 57830043Sminshall StartScreen() 57930043Sminshall { 58030043Sminshall #if defined(unix) 58130043Sminshall struct sgttyb ourttyb; 58230043Sminshall static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 58330043Sminshall 2400, 4800, 9600 }; 58430043Sminshall #endif 58530043Sminshall 58630043Sminshall if (!screenInitd) { /* not initialized */ 58730043Sminshall #if defined(unix) 58830043Sminshall char KSEbuffer[2050]; 58930043Sminshall char *lotsofspace = KSEbuffer; 59030043Sminshall extern int abort(); 59130043Sminshall extern char *tgetstr(); 59230043Sminshall #endif /* defined(unix) */ 59330043Sminshall 59430043Sminshall bzero((char *)Host, sizeof Host); 59530043Sminshall 59630043Sminshall bzero(Orders, sizeof Orders); 59730043Sminshall Orders[ORDER_SF] = Orders[ORDER_SBA] = Orders[ORDER_IC] 59830043Sminshall = Orders[ORDER_PT] = Orders[ORDER_RA] = Orders[ORDER_EUA] 59930043Sminshall = Orders[ORDER_YALE] = 1; 60030043Sminshall 60130043Sminshall DeleteAllFields(); 60230043Sminshall #if defined(SLOWSCREEN) 60330043Sminshall bzero((char *)Terminal, sizeof Terminal); 60430043Sminshall #endif /* defined(SLOWSCREEN) */ 60530043Sminshall Lowest = HighestScreen()+1; 60630043Sminshall Highest = LowestScreen()-1; 60730043Sminshall terminalCursorAddress = 60830043Sminshall CursorAddress = 60930043Sminshall BufferAddress = SetBufferAddress(0,0); 61030043Sminshall UnLocked = 1; 61130043Sminshall Initialized = 1; 61230043Sminshall OutputClock = 1; 61330043Sminshall TransparentClock = -1; 61430043Sminshall #if defined(unix) 61530043Sminshall signal(SIGHUP, abort); 61630043Sminshall #endif 61730043Sminshall 61830043Sminshall TryToSend = FastScreen; 61930043Sminshall #if defined(unix) && defined(SLOWSCREEN) 62030043Sminshall ioctl(1, TIOCGETP, (char *) &ourttyb); 62130043Sminshall if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) { 62230043Sminshall max_changes_before_poll = 1920; 62330043Sminshall } else { 62430043Sminshall max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10; 62530043Sminshall if (max_changes_before_poll < 40) { 62630043Sminshall max_changes_before_poll = 40; 62730043Sminshall } 62830043Sminshall TryToSend = SlowScreen; 62930043Sminshall HaveInput = 1; /* get signals going */ 63030043Sminshall } 63130043Sminshall #endif /* defined(unix) && defined(SLOWSCREEN) */ 63230043Sminshall setcommandmode(); 63330043Sminshall /* 63430043Sminshall * By now, initscr() (in curses) has been called (from telnet.c), 63530043Sminshall * and the screen has been initialized. 63630043Sminshall */ 63730043Sminshall #if defined(unix) 63830043Sminshall nonl(); 63930043Sminshall /* the problem is that curses catches SIGTSTP to 64030043Sminshall * be nice, but it messes us up. 64130043Sminshall */ 64230043Sminshall signal(SIGTSTP, SIG_DFL); 64330043Sminshall if ((KS = tgetstr("ks", &lotsofspace)) != 0) { 64430043Sminshall KS = strsave(KS); 64530043Sminshall StringToTerminal(KS); 64630043Sminshall } 64730043Sminshall if ((KE = tgetstr("ke", &lotsofspace)) != 0) { 64830043Sminshall KE = strsave(KE); 64930043Sminshall } 65030043Sminshall if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) { 65130043Sminshall SO = strsave(tgetstr("md", &lotsofspace)); 65230043Sminshall SE = strsave(tgetstr("me", &lotsofspace)); 65330043Sminshall } 65430043Sminshall #endif 65530043Sminshall DoARefresh(); 65630043Sminshall setconnmode(); 65730043Sminshall if (VB && *VB) { 65830043Sminshall bellSequence = VB; /* use visual bell */ 65930043Sminshall } 66030043Sminshall screenInitd = 1; 66130043Sminshall screenStopped = 0; /* Not stopped */ 66230043Sminshall } 66330043Sminshall } 66430043Sminshall 66530043Sminshall 66630043Sminshall /* StopScreen - called when we are going away... */ 66730043Sminshall 66830043Sminshall void 66930043Sminshall StopScreen(doNewLine) 67030043Sminshall int doNewLine; 67130043Sminshall { 67230043Sminshall if (screenInitd && !screenStopped) { 67330043Sminshall move(NumberLines-1, 1); 67430043Sminshall standend(); 67530043Sminshall #if defined(SLOWSCREEN) 67630043Sminshall inHighlightMode = 0; 67730043Sminshall #endif /* defined(SLOWSCREEN) */ 67830043Sminshall DoARefresh(); 67930043Sminshall setcommandmode(); 68030043Sminshall endwin(); 68130043Sminshall setconnmode(); 68230043Sminshall #if defined(unix) 68330043Sminshall if (KE) { 68430043Sminshall StringToTerminal(KE); 68530043Sminshall } 68630043Sminshall #endif /* defined(unix) */ 68730043Sminshall if (doNewLine) { 68830043Sminshall StringToTerminal("\r\n"); 68930043Sminshall } 69030043Sminshall EmptyTerminal(); 69130043Sminshall screenStopped = 1; /* This is stopped */ 69230043Sminshall } 69330043Sminshall } 69430043Sminshall 69530043Sminshall 69630043Sminshall /* RefreshScreen - called to cause the screen to be refreshed */ 69730043Sminshall 69830043Sminshall void 69930043Sminshall RefreshScreen() 70030043Sminshall { 70130043Sminshall clearok(curscr, TRUE); 70230043Sminshall (*TryToSend)(); 70330043Sminshall } 70430043Sminshall 70530043Sminshall 70630043Sminshall /* ConnectScreen - called to reconnect to the screen */ 70730043Sminshall 70830043Sminshall void 70930043Sminshall ConnectScreen() 71030043Sminshall { 71130043Sminshall if (screenInitd) { 71230043Sminshall #if defined(unix) 71330043Sminshall if (KS) { 71430043Sminshall StringToTerminal(KS); 71530043Sminshall } 71630043Sminshall #endif /* defined(unix) */ 71730043Sminshall RefreshScreen(); 71830043Sminshall (*TryToSend)(); 71930043Sminshall screenStopped = 0; 72030043Sminshall } 72130043Sminshall } 72230043Sminshall 72330043Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */ 72430043Sminshall 72530043Sminshall void 72630043Sminshall LocalClearScreen() 72730043Sminshall { 72830043Sminshall outputPurge(); /* flush all data to terminal */ 72930043Sminshall clear(); /* clear in curses */ 73030043Sminshall #if defined(SLOWSCREEN) 73130043Sminshall bzero((char *)Terminal, sizeof Terminal); 73230043Sminshall #endif /* defined(SLOWSCREEN) */ 73330043Sminshall Clear3270(); 73430043Sminshall Lowest = HighestScreen()+1; /* everything in sync... */ 73530043Sminshall Highest = LowestScreen()+1; 73630043Sminshall } 73730043Sminshall 73830043Sminshall 73930043Sminshall void 74030043Sminshall BellOff() 74130043Sminshall { 74230043Sminshall if (bellwinup) { 74330043Sminshall delwin(bellwin); 74430043Sminshall bellwin = 0; 74530043Sminshall bellwinup = 0; 74630043Sminshall Lowest = MIN(Lowest, LINES/2); 74730043Sminshall Highest = MAX(Highest, (LINES/2)+3); 74830043Sminshall #if defined(SLOWSCREEN) 74930043Sminshall bzero(Terminal+LINES/2, (sizeof Terminal[0])*(3*COLS)); 75030043Sminshall #endif /* defined(SLOWSCREEN) */ 75130043Sminshall touchwin(stdscr); 75230043Sminshall DoARefresh(); 75330043Sminshall } 75430043Sminshall } 75530043Sminshall 75630043Sminshall 75730043Sminshall void 75830043Sminshall RingBell(s) 75930043Sminshall char *s; 76030043Sminshall { 76130043Sminshall needToRing = 1; 76230043Sminshall if (s) { 76330043Sminshall int len = strlen(s); 76430043Sminshall 76530043Sminshall if (len > COLS-2) { 76630043Sminshall len = COLS-2; 76730043Sminshall } 76830043Sminshall if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) { 76930043Sminshall OurExitString(stderr, "Error from newwin in RingBell", 1); 77030043Sminshall } 77130043Sminshall werase(bellwin); 77230043Sminshall wstandout(bellwin); 77330043Sminshall box(bellwin, '|', '-'); 77430043Sminshall if (wmove(bellwin, 1, 1) == ERR) { 77530043Sminshall OurExitString(stderr, "Error from wmove in RingBell", 1); 77630043Sminshall } 77730043Sminshall while (len--) { 77830043Sminshall if (waddch(bellwin, *s++) == ERR) { 77930043Sminshall OurExitString(stderr, "Error from waddch in RingBell", 1); 78030043Sminshall } 78130043Sminshall } 78230043Sminshall wstandend(bellwin); 78330043Sminshall if (wrefresh(bellwin) == ERR) { 78430043Sminshall OurExitString(stderr, "Error from wrefresh in RingBell", 1); 78530043Sminshall } 78630043Sminshall bellwinup = 1; 78730043Sminshall } 78830043Sminshall } 78930043Sminshall 79030043Sminshall 79130043Sminshall /* returns a 1 if no more output available (so, go ahead and block), 79230043Sminshall or a 0 if there is more output available (so, just poll the other 79330043Sminshall sources/destinations, don't block). 79430043Sminshall */ 79530043Sminshall 79630043Sminshall int 79730043Sminshall DoTerminalOutput() 79830043Sminshall { 79930043Sminshall /* called just before a select to conserve IO to terminal */ 80030043Sminshall if (Initialized && 80130043Sminshall ((Lowest <= Highest) || needToRing || 80230043Sminshall (terminalCursorAddress != CorrectTerminalCursor()))) { 80330043Sminshall (*TryToSend)(); 80430043Sminshall } 80530043Sminshall if (Lowest > Highest) { 80630043Sminshall return(1); /* no more output now */ 80730043Sminshall } else { 80830043Sminshall return(0); /* more output for future */ 80930043Sminshall } 81030043Sminshall } 811*30074Sminshall 812*30074Sminshall /* 813*30074Sminshall * The following are defined to handle transparent data. 814*30074Sminshall */ 815*30074Sminshall 816*30074Sminshall void 817*30074Sminshall TransStop() 818*30074Sminshall { 819*30074Sminshall #if defined(unix) 820*30074Sminshall if (tcflag == 0) { 821*30074Sminshall tcflag = -1; 822*30074Sminshall (void) signal(SIGCHLD, SIG_DFL); 823*30074Sminshall } else if (tcflag > 0) { 824*30074Sminshall setcommandmode(); 825*30074Sminshall (void) close(tin); 826*30074Sminshall (void) close(tout); 827*30074Sminshall tin = savefd[0]; 828*30074Sminshall tout = savefd[1]; 829*30074Sminshall setconnmode(); 830*30074Sminshall tcflag = -1; 831*30074Sminshall (void) signal(SIGCHLD, SIG_DFL); 832*30074Sminshall } 833*30074Sminshall #endif /* defined(unix) */ 834*30074Sminshall RefreshScreen(); 835*30074Sminshall } 836*30074Sminshall 837*30074Sminshall void 838*30074Sminshall TransOut(buffer, count) 839*30074Sminshall unsigned char *buffer; 840*30074Sminshall int count; 841*30074Sminshall { 842*30074Sminshall #if defined(unix) 843*30074Sminshall extern char *transcom; 844*30074Sminshall int inpipefd[2], outpipefd[2], savemode; 845*30074Sminshall void aborttc(); 846*30074Sminshall #endif /* defined(unix) */ 847*30074Sminshall 848*30074Sminshall while (DoTerminalOutput() == 0) { 849*30074Sminshall #if defined(unix) 850*30074Sminshall HaveInput = 0; 851*30074Sminshall #endif /* defined(unix) */ 852*30074Sminshall } 853*30074Sminshall #if defined(unix) 854*30074Sminshall if (transcom && tcflag == -1) { 855*30074Sminshall while (1) { /* go thru once */ 856*30074Sminshall if (pipe(outpipefd) < 0) { 857*30074Sminshall break; 858*30074Sminshall } 859*30074Sminshall if (pipe(inpipefd) < 0) { 860*30074Sminshall break; 861*30074Sminshall } 862*30074Sminshall if ((tcflag = fork()) == 0) { 863*30074Sminshall (void) close(outpipefd[1]); 864*30074Sminshall (void) close(0); 865*30074Sminshall if (dup(outpipefd[0]) < 0) { 866*30074Sminshall exit(1); 867*30074Sminshall } 868*30074Sminshall (void) close(outpipefd[0]); 869*30074Sminshall (void) close(inpipefd[0]); 870*30074Sminshall (void) close(1); 871*30074Sminshall if (dup(inpipefd[1]) < 0) { 872*30074Sminshall exit(1); 873*30074Sminshall } 874*30074Sminshall (void) close(inpipefd[1]); 875*30074Sminshall if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) { 876*30074Sminshall exit(1); 877*30074Sminshall } 878*30074Sminshall } 879*30074Sminshall (void) close(inpipefd[1]); 880*30074Sminshall (void) close(outpipefd[0]); 881*30074Sminshall savefd[0] = tin; 882*30074Sminshall savefd[1] = tout; 883*30074Sminshall setcommandmode(); 884*30074Sminshall tin = inpipefd[0]; 885*30074Sminshall tout = outpipefd[1]; 886*30074Sminshall (void) signal(SIGCHLD, aborttc); 887*30074Sminshall setconnmode(); 888*30074Sminshall tcflag = 1; 889*30074Sminshall break; 890*30074Sminshall } 891*30074Sminshall if (tcflag < 1) { 892*30074Sminshall tcflag = 0; 893*30074Sminshall } 894*30074Sminshall } 895*30074Sminshall #endif /* defined(unix) */ 896*30074Sminshall (void) DataToTerminal(buffer, count); 897*30074Sminshall } 898*30074Sminshall 899*30074Sminshall 900*30074Sminshall #if defined(unix) 901*30074Sminshall static void 902*30074Sminshall aborttc() 903*30074Sminshall { 904*30074Sminshall int savemode; 905*30074Sminshall 906*30074Sminshall setcommandmode(); 907*30074Sminshall (void) close(tin); 908*30074Sminshall (void) close(tout); 909*30074Sminshall tin = savefd[0]; 910*30074Sminshall tout = savefd[1]; 911*30074Sminshall setconnmode(); 912*30074Sminshall tcflag = 0; 913*30074Sminshall } 914*30074Sminshall #endif /* defined(unix) */ 915