1 /* $NetBSD: outbound.c,v 1.5 2003/08/07 11:16:32 agc Exp $ */
4 * Copyright (c) 1988 The Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)outbound.c 4.3 (Berkeley) 4/26/91";
37 __RCSID("$NetBSD: outbound.c,v 1.5 2003/08/07 11:16:32 agc Exp $");
43 #include "../general/general.h"
49 #include "../api/ebc_disp.h"
50 #include "../ascii/state.h"
51 #include "../sys_curses/telextrn.h"
53 #include "../general/globals.h"
57 #define SetHighestLowest(position) { \
58 if (position < Lowest) { \
61 if (position > Highest) { \
67 static int LastWasTerminated
= 1; /* was "control" = 1 last time? */
71 #if !defined(PURE3274)
72 int OutputClock
; /* what time it is */
73 int TransparentClock
; /* time we were last in transparent */
74 #endif /* !defined(PURE3274) */
76 char CIABuffer
[64] = {
77 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
78 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
79 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
80 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
81 0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
82 0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
83 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
84 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
87 static struct orders_def orders_def
[] = ORDERS_DEF
;
92 * Initialize all data from the 'data' portion to their startup values.
98 LastWasTerminated
= 1;
106 int position
; /* Position in previous field */
110 ptr
= (ScreenImage
*)memNSchr((char *)Host
+position
+1, ATTR_MASK
,
111 HighestScreen()-position
, ATTR_MASK
, sizeof Host
[0]);
113 ptr
= (ScreenImage
*)memNSchr((char *)Host
+LowestScreen(), ATTR_MASK
,
114 position
-LowestScreen(), ATTR_MASK
, sizeof Host
[0]);
116 return LowestScreen();
128 ptr
= (ScreenImage
*)memNSchr((char *)(Host
+position
)-1, ATTR_MASK
,
129 position
-LowestScreen(), ATTR_MASK
, -sizeof Host
[0]);
131 ptr
= (ScreenImage
*)memNSchr((char *)Host
+HighestScreen(), ATTR_MASK
,
132 HighestScreen()-position
, ATTR_MASK
, -sizeof Host
[0]);
134 return LowestScreen();
140 /* Clear3270 - called to clear the screen */
146 DeleteAllFields(); /* get rid of all fields */
147 BufferAddress
= SetBufferAddress(0,0);
148 CursorAddress
= SetBufferAddress(0,0);
149 Lowest
= LowestScreen();
150 Highest
= HighestScreen();
153 /* AddHost - called to add a character to the buffer.
154 * We use a macro in this module, since we call it so
157 * NOTE: It is a macro, so don't go around using AddHost(p, *c++), or
158 * anything similar. (I don't define any temporary variables, again
159 * just for the speed.)
162 AddHost(position
, character
)
166 # define AddHostA(p,c) \
168 if (IsStartField(p)) { \
170 Highest = HighestScreen(); \
171 Lowest = LowestScreen(); \
172 SetHighestLowest(p); \
176 # define AddHost(p,c) \
178 if (c != GetHost(p)) { \
179 SetHighestLowest(p); \
182 } /* end of macro of AddHost */
184 AddHost(position
, character
);
187 /* returns the number of characters consumed */
189 DataFromNetwork(Buffer
, count
, control
)
190 char *Buffer
; /* what the data is */
191 int count
; /* and how much there is */
192 int control
; /* this buffer ended block? */
195 unsigned char *buffer
= (unsigned char *)Buffer
;
204 * If this is the start of a new data stream, then look
205 * for an op-code and (possibly) a WCC.
207 if (LastWasTerminated
) {
211 ExitString("Short count received from host!\n", 1);
215 switch (Command
) { /* This had better be a read command */
216 case CMD_READ_MODIFIED
:
217 case CMD_SNA_READ_MODIFIED
:
218 case CMD_SNA_READ_MODIFIED_ALL
:
219 SetOiaOnlineA(&OperatorInformationArea
);
221 DoReadModified(Command
);
223 case CMD_READ_BUFFER
:
224 case CMD_SNA_READ_BUFFER
:
225 SetOiaOnlineA(&OperatorInformationArea
);
234 "Unexpected read command code 0x%x received.\n",
236 ExitString(s_buffer
, 1);
240 return(1); /* We consumed everything */
244 if (Wcc
& WCC_RESET_MDT
) {
245 i
= c
= WhereAttrByte(LowestScreen());
255 case CMD_ERASE_WRITE
:
256 case CMD_ERASE_WRITE_ALTERNATE
:
257 case CMD_SNA_ERASE_WRITE
:
258 case CMD_SNA_ERASE_WRITE_ALTERNATE
:
260 int newlines
, newcolumns
;
262 SetOiaOnlineA(&OperatorInformationArea
);
263 ResetOiaTWait(&OperatorInformationArea
);
265 if ((Command
== CMD_ERASE_WRITE
)
266 || (Command
== CMD_SNA_ERASE_WRITE
)) {
270 newlines
= MaxNumberLines
;
271 newcolumns
= MaxNumberColumns
;
273 if ((newlines
!= NumberLines
)
274 || (newcolumns
!= NumberColumns
)) {
276 * The LocalClearScreen() is really for when we
277 * are going from a larger screen to a smaller
278 * screen, and we need to clear off the stuff
279 * at the end of the lines, or the lines at
280 * the end of the screen.
283 NumberLines
= newlines
;
284 NumberColumns
= newcolumns
;
285 ScreenSize
= NumberLines
* NumberColumns
;
288 #if !defined(PURE3274)
289 if (TransparentClock
== OutputClock
) {
292 #endif /* !defined(PURE3274) */
296 case CMD_ERASE_ALL_UNPROTECTED
:
297 case CMD_SNA_ERASE_ALL_UNPROTECTED
:
298 SetOiaOnlineA(&OperatorInformationArea
);
299 ResetOiaTWait(&OperatorInformationArea
);
301 CursorAddress
= HighestScreen()+1;
302 for (i
= LowestScreen(); i
<= HighestScreen(); i
= ScreenInc(i
)) {
303 if (IsUnProtected(i
)) {
304 if (CursorAddress
> i
) {
313 if (CursorAddress
== HighestScreen()+1) {
314 CursorAddress
= SetBufferAddress(0,0);
318 ResetOiaSystemLocked(&OperatorInformationArea
);
324 SetOiaOnlineA(&OperatorInformationArea
);
325 ResetOiaTWait(&OperatorInformationArea
);
333 "Unexpected write command code 0x%x received.\n",
335 ExitString(s_buffer
, 1);
340 count
-= 2; /* strip off command and wcc */
344 #if !defined(PURE3274)
345 if (TransparentClock
== OutputClock
) {
346 TransOut(buffer
, count
, -1, control
);
349 #endif /* !defined(PURE3274) */
351 LastWasTerminated
= 0; /* then, reset at end... */
357 /* handle an order */
359 # define Ensure(x) if (count < x) { \
361 return(origCount-(count+1)); \
363 /* XXX - should not occur */ \
372 if ( ! (IsStartField(BufferAddress
) &&
373 FieldAttributes(BufferAddress
) == c
)) {
374 SetHighestLowest(BufferAddress
);
375 NewField(BufferAddress
,c
);
377 BufferAddress
= ScreenInc(BufferAddress
);
383 #if !defined(PURE3274)
384 /* Check for transparent write */
385 if ((i
== 0) && ((c
== 0) || (c
== 1) || (c
== 5))) {
386 TransparentClock
= OutputClock
+1;
387 TransOut(buffer
+2, count
-2, c
, control
);
392 #endif /* !defined(PURE3274) */
393 BufferAddress
= Addr3270(i
, c
);
398 CursorAddress
= BufferAddress
;
401 * XXX - PT is supposed to null fill the screen buffer
402 * under certain draconian conditions.
407 if (IsStartField(i
)) {
408 if (!IsProtected(ScreenInc(i
))) {
413 } while (i
!= HighestScreen());
414 BufferAddress
= ScreenInc(i
);
418 i
= Addr3270(buffer
[0], buffer
[1]);
419 if ((i
< 0) || (i
> HighestScreen())) {
422 sprintf(s_buffer
, "tn3270: %s%d.\n\t%s%d%s%d%s\n",
423 "Invalid 3270 order 'Repeat to Address' to address ",
425 "(Screen currently set to ",
430 ExitString(s_buffer
, 1);
444 AddHost(BufferAddress
, ebc_disp
[c
]);
445 BufferAddress
= ScreenInc(BufferAddress
);
446 } while (BufferAddress
!= i
);
448 case ORDER_EUA
: /* (from [here,there), ie: half open interval] */
451 * Compiler error - msc version 4.0:
452 * "expression too complicated".
454 i
= WhereAttrByte(BufferAddress
);
455 c
= FieldAttributes(i
);
456 i
= Addr3270(buffer
[0], buffer
[1]);
457 if ((i
< 0) || (i
> HighestScreen())) {
460 sprintf(s_buffer
, "tn3270: %s%d.\n\t%s%d%s%d%s\n",
461 "Invalid 3270 order 'Erase Unprotected to Address' to address ",
463 "(Screen currently set to ",
468 ExitString(s_buffer
, 1);
472 if (IsStartField(BufferAddress
)) {
473 c
= FieldAttributes(BufferAddress
);
474 } else if (!IsProtectedAttr(BufferAddress
, c
)) {
475 AddHost(BufferAddress
, 0);
477 BufferAddress
= ScreenInc(BufferAddress
);
478 } while (i
!= BufferAddress
);
484 /* XXX Should do SOMETHING! */
485 /* XXX buffer += 0; */
486 /* XXX count -= 0; *//* For now, just use this character */
488 case ORDER_YALE
: /* special YALE defined order */
489 Ensure(2); /* need at least two characters */
490 if (*buffer
== 0x5b) {
491 i
= OptOrder(buffer
+1, count
-1, control
);
493 return(origCount
-(count
+1)); /* come here again */
503 static struct orders_def unk_order
504 = { 0, "??", "(unknown)" };
505 struct orders_def
*porder
= &unk_order
;
508 for (s_i
= 0; s_i
<= highestof(orders_def
); s_i
++) {
509 if (orders_def
[s_i
].code
== c
) {
510 porder
= &orders_def
[s_i
];
515 "Unsupported order '%s' (%s, 0x%x) received.\n",
516 porder
->long_name
, porder
->short_name
, c
);
517 ExitString(s_buffer
, 1);
525 /* Data comes in large clumps - take it all */
527 AddHostA(i
, ebc_disp
[c
]);
531 while (count
&& !IsOrder(c
)) {
532 AddHostA(i
, ebc_disp
[c
]);
534 if (i
== LowestScreen()) {
535 SetHighestLowest(HighestScreen());
549 #if !defined(PURE3274)
550 OutputClock
++; /* time rolls on */
551 #endif /* !defined(PURE3274) */
552 if (Wcc
& WCC_RESTORE
) {
553 #if !defined(PURE3274)
554 if (TransparentClock
!= OutputClock
) {
557 #else /* !defined(PURE3274) */
559 #endif /* !defined(PURE3274) */
561 ResetOiaSystemLocked(&OperatorInformationArea
);
566 if (Wcc
& WCC_ALARM
) {
570 LastWasTerminated
= control
; /* state for next time */
574 return(origCount
-count
);
582 * Initialize any 3270 (controller) variables to an initial state
583 * in preparation for accepting a connection.
591 OptInit(); /* initialize mappings */
596 for (i
= 0; i
<= highestof(orders_def
); i
++) {
597 Orders
[orders_def
[i
].code
] = 1;
600 DeleteAllFields(); /* Clear screen */
601 Lowest
= HighestScreen()+1;
602 Highest
= LowestScreen()-1;
603 CursorAddress
= BufferAddress
= SetBufferAddress(0,0);
605 #if !defined(PURE3274)
607 TransparentClock
= -1;
608 #endif /* !defined(PURE3274) */
609 SetOiaReady3274(&OperatorInformationArea
);
616 ResetOiaReady3274(&OperatorInformationArea
);