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