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