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