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