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