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