Make disp_asc 256 characters, so we can have the last 64 point
[unix-history] / usr / src / usr.bin / tn3270 / ctlr / outbound.c
CommitLineData
3d8b96ab
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
23static char sccsid[] = "@(#)outbound.c 3.1 10/29/86";
24#endif /* lint */
25
26
27#if defined(unix)
28#include <signal.h>
29#endif /* defined(unix) */
30#include <stdio.h>
31
32#include "hostctlr.h"
33#include "screen.h"
34#include "ebc_disp.h"
35
36#include "../system/globals.h"
37#include "options.ext"
38#include "../telnet.ext"
39#include "inbound.ext"
40#include "outbound.ext"
41#include "bsubs.ext"
42
43#define SetHighestLowest(position) { \
44 if (position < Lowest) { \
45 Lowest = position; \
46 } \
47 if (position > Highest) { \
48 Highest = position; \
49 } \
50 }
51
52#if defined(unix)
53extern int tin, tout; /* file descriptors */
54#endif /* defined(unix) */
55
56
57#if defined(unix)
58static int tcflag = -1; /* transparent mode command flag */
59static int savefd[2]; /* for storing fds during transcom */
60#endif /* defined(unix) */
61
62/* some globals */
63
64int OutputClock = 0; /* what time it is */
65int TransparentClock = 0; /* time we were last in transparent */
66\f
67
68char CIABuffer[64] = {
69 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
70 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
71 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
72 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
73 0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
74 0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
75 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
76 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
77};
78\f
79/* What we know is that table is of size ScreenSize */
80
81FieldFind(table, position, failure)
82register char *table; /* which table of bytes to use */
83register int position; /* what position to start from */
84int failure; /* if unformatted, what value to return */
85{
86 register int ourp;
87
88 ourp = position + 1 + bskip(table+position+1, ScreenSize-position-1, 0);
89 if (ourp < ScreenSize) {
90 return(ourp);
91 }
92 /* No fields in table after position. Look for fields from beginning
93 * of table.
94 */
95 ourp = bskip(table, position+1, 0);
96 if (ourp <= position) {
97 return(ourp);
98 }
99 return(failure);
100}
101
102/* Clear3270 - called to clear the screen */
103
104void
105Clear3270()
106{
107 bzero((char *)Host, sizeof(Host));
108 DeleteAllFields(); /* get rid of all fields */
109 BufferAddress = SetBufferAddress(0,0);
110 CursorAddress = SetBufferAddress(0,0);
111 Lowest = LowestScreen();
112 Highest = HighestScreen();
113}
114\f
115/* AddHost - called to add a character to the buffer.
116 * We use a macro in this module, since we call it so
117 * often from loops.
118 *
119 * NOTE: It is a macro, so don't go around using AddHost(p, *c++), or
120 * anything similar. (I don't define any temporary variables, again
121 * just for the speed.)
122 */
123void
124AddHost(position, character)
125int position;
126char character;
127{
128#if defined(SLOWSCREEN)
129# define AddHostA(p,c) \
130 { \
131 if (IsStartField(p)) { \
132 DeleteField(p); \
133 Highest = HighestScreen(); \
134 Lowest = LowestScreen(); \
135 SetHighestLowest(p); \
136 } \
137 SetHost(p, c); \
138 }
139# define AddHost(p,c) \
140 { \
141 if (c != GetHost(p)) { \
142 SetHighestLowest(p); \
143 } \
144 AddHostA(p,c); \
145 } /* end of macro of AddHost */
146#else /* defined(SLOWSCREEN) */
147# define AddHost(p,c) \
148 { \
149 if (IsStartField(p)) { \
150 DeleteField(p); \
151 Highest = HighestScreen(); \
152 Lowest = LowestScreen(); \
153 SetHost(p, c); \
154 } else { \
155 SetHost(p, c); \
156 SetHighestLowest(p); \
157 } \
158 } /* end of macro of AddHost */
159#endif /* defined(SLOWSCREEN) */
160
161 AddHost(position, character);
162}
163\f
164/* returns the number of characters consumed */
165int
166DataFromNetwork(buffer, count, control)
167register unsigned char *buffer; /* what the data is */
168register int count; /* and how much there is */
169int control; /* this buffer ended block? */
170{
171 int origCount;
172 register int c;
173 register int i;
174 static int Command;
175 static int Wcc;
176 static int LastWasTerminated = 1; /* was "control" = 1 last time? */
177#if defined(unix)
178 extern char *transcom;
179 int inpipefd[2], outpipefd[2], savemode, aborttc();
180#endif /* defined(unix) */
181
182 origCount = count;
183
184 if (LastWasTerminated) {
185
186 if (count < 2) {
187 if (count == 0) {
188 StringToTerminal("Short count received from host!\n");
189 return(count);
190 }
191 Command = buffer[0];
192 switch (Command) { /* This had better be a read command */
193 case CMD_READ_MODIFIED:
194 case CMD_SNA_READ_MODIFIED:
195 case CMD_SNA_READ_MODIFIED_ALL:
196 DoReadModified(Command);
197 break;
198 case CMD_READ_BUFFER:
199 case CMD_SNA_READ_BUFFER:
200 DoReadBuffer();
201 break;
202 default:
203 break;
204 }
205 return(1); /* We consumed everything */
206 }
207 Command = buffer[0];
208 Wcc = buffer[1];
209 if (Wcc & WCC_RESET_MDT) {
210 i = c = WhereAttrByte(LowestScreen());
211 do {
212 if (HasMdt(i)) {
213 TurnOffMdt(i);
214 }
215 i = FieldInc(i);
216 } while (i != c);
217 }
218
219 switch (Command) {
220 case CMD_ERASE_WRITE:
221 case CMD_ERASE_WRITE_ALTERNATE:
222 case CMD_SNA_ERASE_WRITE:
223 case CMD_SNA_ERASE_WRITE_ALTERNATE:
224 {
225 int newlines, newcolumns;
226
227#if defined(unix)
228 if (tcflag == 0) {
229 tcflag = -1;
230 (void) signal(SIGCHLD, SIG_DFL);
231 } else if (tcflag > 0) {
232 setcommandmode();
233 (void) close(tin);
234 (void) close(tout);
235 tin = savefd[0];
236 tout = savefd[1];
237 setconnmode();
238 tcflag = -1;
239 (void) signal(SIGCHLD, SIG_DFL);
240 }
241#endif /* defined(unix) */
242 if ((Command == CMD_ERASE_WRITE)
243 || (Command == CMD_SNA_ERASE_WRITE)) {
244 newlines = 24;
245 newcolumns = 80;
246 } else {
247 newlines = MaxNumberLines;
248 newcolumns = MaxNumberColumns;
249 }
250 if ((newlines != NumberLines)
251 || (newcolumns != NumberColumns)) {
252 /*
253 * The LocalClearScreen() is really for when we
254 * are going from a larger screen to a smaller
255 * screen, and we need to clear off the stuff
256 * at the end of the lines, or the lines at
257 * the end of the screen.
258 */
259 LocalClearScreen();
260 NumberLines = newlines;
261 NumberColumns = newcolumns;
262 ScreenSize = NumberLines * NumberColumns;
263 }
264 Clear3270();
265 if (TransparentClock == OutputClock) {
266 RefreshScreen();
267 }
268 break;
269 }
270
271 case CMD_ERASE_ALL_UNPROTECTED:
272 case CMD_SNA_ERASE_ALL_UNPROTECTED:
273 CursorAddress = HighestScreen()+1;
274 for (i = LowestScreen(); i <= HighestScreen(); i = ScreenInc(i)) {
275 if (IsUnProtected(i)) {
276 if (CursorAddress > i) {
277 CursorAddress = i;
278 }
279 AddHost(i, '\0');
280 }
281 if (HasMdt(i)) {
282 TurnOffMdt(i);
283 }
284 }
285 if (CursorAddress == HighestScreen()+1) {
286 CursorAddress = SetBufferAddress(0,0);
287 }
288 UnLocked = 1;
289 AidByte = 0;
290 break;
291 case CMD_WRITE:
292 case CMD_SNA_WRITE:
293 break;
294 default:
295 {
296 char buffer[100];
297
298 sprintf(buffer, "Unexpected command code 0x%x received.\n",
299 Command);
300 ExitString(stderr, buffer, 1);
301 break;
302 }
303 }
304
305 count -= 2; /* strip off command and wcc */
306 buffer += 2;
307
308 }
309 LastWasTerminated = 0; /* then, reset at end... */
310
311 while (count) {
312 count--;
313 c = *buffer++;
314 if (IsOrder(c)) {
315 /* handle an order */
316 switch (c) {
317# define Ensure(x) if (count < x) { \
318 if (!control) { \
319 return(origCount-(count+1)); \
320 } else { \
321 /* XXX - should not occur */ \
322 count = 0; \
323 break; \
324 } \
325 }
326 case ORDER_SF:
327 Ensure(1);
328 c = *buffer++;
329 count--;
330 if ( ! (IsStartField(BufferAddress) &&
331 FieldAttributes(BufferAddress) == c)) {
332 SetHighestLowest(BufferAddress);
333 NewField(BufferAddress,c);
334 }
3d8b96ab
GM
335 BufferAddress = ScreenInc(BufferAddress);
336 break;
337 case ORDER_SBA:
338 Ensure(2);
339 i = buffer[0];
340 c = buffer[1];
341 if (!i && !c) { /* transparent write */
342 if (!control) {
343 return(origCount-(count+1));
344 } else {
345 while (DoTerminalOutput() == 0) {
346#if defined(unix)
347 HaveInput = 0;
348#endif /* defined(unix) */
349 }
350 TransparentClock = OutputClock; /* this clock */
351#if defined(unix)
352 if (transcom && tcflag == -1) {
353 while (1) { /* go thru once */
354 if (pipe(outpipefd) < 0) {
355 break;
356 }
357 if (pipe(inpipefd) < 0) {
358 break;
359 }
360 if ((tcflag = fork()) == 0) {
361 (void) close(outpipefd[1]);
362 (void) close(0);
363 if (dup(outpipefd[0]) < 0) {
364 exit(1);
365 }
366 (void) close(outpipefd[0]);
367 (void) close(inpipefd[0]);
368 (void) close(1);
369 if (dup(inpipefd[1]) < 0) {
370 exit(1);
371 }
372 (void) close(inpipefd[1]);
373 if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) {
374 exit(1);
375 }
376 }
377 (void) close(inpipefd[1]);
378 (void) close(outpipefd[0]);
379 savefd[0] = tin;
380 savefd[1] = tout;
381 setcommandmode();
382 tin = inpipefd[0];
383 tout = outpipefd[1];
384 (void) signal(SIGCHLD, aborttc);
385 setconnmode();
386 tcflag = 1;
387 break;
388 }
389 if (tcflag < 1) {
390 tcflag = 0;
391 }
392 }
393#endif /* defined(unix) */
394 (void) DataToTerminal(buffer+2, count-2);
395 SendToIBM();
396 TransparentClock = OutputClock+1; /* clock next */
397 buffer += count;
398 count -= count;
399 }
400 } else {
401 BufferAddress = Addr3270(i, c);
402 buffer += 2;
403 count -= 2;
404 }
405 break;
406 case ORDER_IC:
407 CursorAddress = BufferAddress;
408 break;
409 case ORDER_PT:
410 for (i = ScreenInc(BufferAddress); (i != HighestScreen());
411 i = ScreenInc(i)) {
412 if (IsStartField(i)) {
413 i = ScreenInc(i);
414 if (!IsProtected(ScreenInc(i))) {
415 break;
416 }
417 if (i == HighestScreen()) {
418 break;
419 }
420 }
421 }
422 CursorAddress = i;
423 break;
424 case ORDER_RA:
425 Ensure(3);
426 i = Addr3270(buffer[0], buffer[1]);
427 c = buffer[2];
428 do {
429 AddHost(BufferAddress, ebc_disp[c]);
430 BufferAddress = ScreenInc(BufferAddress);
431 } while (BufferAddress != i);
432 buffer += 3;
433 count -= 3;
434 break;
435 case ORDER_EUA: /* (from [here,there), ie: half open interval] */
436 Ensure(2);
437 c = FieldAttributes(WhereAttrByte(BufferAddress));
438 for (i = Addr3270(buffer[0], buffer[1]); i != BufferAddress;
439 BufferAddress = ScreenInc(BufferAddress)) {
440 if (!IsProtectedAttr(BufferAddress, c)) {
441 AddHost(BufferAddress, 0);
442 }
443 }
444 buffer += 2;
445 count -= 2;
446 break;
447 case ORDER_YALE: /* special YALE defined order */
448 Ensure(2); /* need at least two characters */
449 if (*buffer == 0x5b) {
450 i = OptOrder(buffer+1, count-1, control);
451 if (i == 0) {
452 return(origCount-(count+1)); /* come here again */
453 } else {
454 buffer += 1 + i;
455 count -= (1 + i);
456 }
457 }
458 break;
459 default:
460 break; /* XXX ? */
461 }
462 if (count < 0) {
463 count = 0;
464 }
465 } else {
466 /* Data comes in large clumps - take it all */
467 i = BufferAddress;
468#if !defined(SLOWSCREEN)
469 AddHost(i, ebc_disp[c]);
470#else /* !defined(SLOWSCREEN) */
471 AddHostA(i, ebc_disp[c]);
472 SetHighestLowest(i);
473#endif /* !defined(SLOWSCREEN) */
474 i = ScreenInc(i);
475 c = *buffer;
476 while (count && !IsOrder(c)) {
477#if !defined(SLOWSCREEN)
478 AddHost(i, ebc_disp[c]);
479#else /* !defined(SLOWSCREEN) */
480 AddHostA(i, ebc_disp[c]);
481#endif /* !defined(SLOWSCREEN) */
482 i = ScreenInc(i);
483#if defined(SLOWSCREEN)
484 if (i == LowestScreen()) {
485 SetHighestLowest(HighestScreen());
486 }
487#endif /* defined(SLOWSCREEN) */
488 count--;
489 buffer++;
490 c = *buffer;
491 }
492#if defined(SLOWSCREEN)
493 SetHighestLowest(i);
494#endif /* defined(SLOWSCREEN) */
495 BufferAddress = i;
496 }
497 }
498 if (count == 0) {
499 OutputClock++; /* time rolls on */
500 if (control) {
501 if (Wcc & WCC_RESTORE) {
502 if (TransparentClock != OutputClock) {
503 AidByte = 0;
504 }
505 UnLocked = 1;
506 }
507 if (Wcc & WCC_ALARM) {
508 RingBell(0);
509 }
510 }
511 LastWasTerminated = control; /* state for next time */
512 return(origCount);
513 } else {
514 return(origCount-count);
515 }
516}
517
518
519#if defined(unix)
520aborttc()
521{
522 int savemode;
523
524 setcommandmode();
525 (void) close(tin);
526 (void) close(tout);
527 tin = savefd[0];
528 tout = savefd[1];
529 setconnmode();
530 tcflag = 0;
531}
532#endif /* defined(unix) */