Sync usage with man page.
[netbsd-mini2440.git] / usr.bin / tn3270 / ctlr / outbound.c
blob82a20fa7d678d45c4400a394f3c60249edf001e0
1 /* $NetBSD: outbound.c,v 1.5 2003/08/07 11:16:32 agc Exp $ */
3 /*-
4 * Copyright (c) 1988 The Regents of the University of California.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)outbound.c 4.3 (Berkeley) 4/26/91";
36 #else
37 __RCSID("$NetBSD: outbound.c,v 1.5 2003/08/07 11:16:32 agc Exp $");
38 #endif
39 #endif /* not lint */
41 #include <stdio.h>
43 #include "../general/general.h"
45 #include "hostctlr.h"
46 #include "oia.h"
47 #include "screen.h"
48 #include "options.h"
49 #include "../api/ebc_disp.h"
50 #include "../ascii/state.h"
51 #include "../sys_curses/telextrn.h"
53 #include "../general/globals.h"
54 #include "externs.h"
55 #include "declare.h"
57 #define SetHighestLowest(position) { \
58 if (position < Lowest) { \
59 Lowest = position; \
60 } \
61 if (position > Highest) { \
62 Highest = position; \
63 } \
67 static int LastWasTerminated = 1; /* was "control" = 1 last time? */
69 /* some globals */
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;
90 * init_ctlr()
92 * Initialize all data from the 'data' portion to their startup values.
95 void
96 init_ctlr()
98 LastWasTerminated = 1;
99 init_inbound();
100 init_oia();
105 FieldInc(position)
106 int position; /* Position in previous field */
108 ScreenImage *ptr;
110 ptr = (ScreenImage *)memNSchr((char *)Host+position+1, ATTR_MASK,
111 HighestScreen()-position, ATTR_MASK, sizeof Host[0]);
112 if (ptr == 0) {
113 ptr = (ScreenImage *)memNSchr((char *)Host+LowestScreen(), ATTR_MASK,
114 position-LowestScreen(), ATTR_MASK, sizeof Host[0]);
115 if (ptr == 0) {
116 return LowestScreen();
119 return ptr-Host;
123 FieldDec(position)
124 int position;
126 ScreenImage *ptr;
128 ptr = (ScreenImage *)memNSchr((char *)(Host+position)-1, ATTR_MASK,
129 position-LowestScreen(), ATTR_MASK, -sizeof Host[0]);
130 if (ptr == 0) {
131 ptr = (ScreenImage *)memNSchr((char *)Host+HighestScreen(), ATTR_MASK,
132 HighestScreen()-position, ATTR_MASK, -sizeof Host[0]);
133 if (ptr == 0) {
134 return LowestScreen();
137 return ptr-Host;
140 /* Clear3270 - called to clear the screen */
142 void
143 Clear3270()
145 ClearArray(Host);
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
155 * often from loops.
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.)
161 void
162 AddHost(position, character)
163 int position;
164 char character;
166 # define AddHostA(p,c) \
168 if (IsStartField(p)) { \
169 DeleteField(p); \
170 Highest = HighestScreen(); \
171 Lowest = LowestScreen(); \
172 SetHighestLowest(p); \
174 SetHost(p, c); \
176 # define AddHost(p,c) \
178 if (c != GetHost(p)) { \
179 SetHighestLowest(p); \
181 AddHostA(p,c); \
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? */
194 int origCount;
195 unsigned char *buffer = (unsigned char *)Buffer;
196 int c;
197 int i;
198 static int Command;
199 static int Wcc;
201 origCount = count;
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) {
209 if (count < 2) {
210 if (count == 0) {
211 ExitString("Short count received from host!\n", 1);
212 return(count);
214 Command = buffer[0];
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);
220 SetOiaModified();
221 DoReadModified(Command);
222 break;
223 case CMD_READ_BUFFER:
224 case CMD_SNA_READ_BUFFER:
225 SetOiaOnlineA(&OperatorInformationArea);
226 SetOiaModified();
227 DoReadBuffer();
228 break;
229 default:
231 char s_buffer[100];
233 sprintf(s_buffer,
234 "Unexpected read command code 0x%x received.\n",
235 Command);
236 ExitString(s_buffer, 1);
237 break;
240 return(1); /* We consumed everything */
242 Command = buffer[0];
243 Wcc = buffer[1];
244 if (Wcc & WCC_RESET_MDT) {
245 i = c = WhereAttrByte(LowestScreen());
246 do {
247 if (HasMdt(i)) {
248 TurnOffMdt(i);
250 i = FieldInc(i);
251 } while (i != c);
254 switch (Command) {
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);
264 SetOiaModified();
265 if ((Command == CMD_ERASE_WRITE)
266 || (Command == CMD_SNA_ERASE_WRITE)) {
267 newlines = 24;
268 newcolumns = 80;
269 } else {
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.
282 LocalClearScreen();
283 NumberLines = newlines;
284 NumberColumns = newcolumns;
285 ScreenSize = NumberLines * NumberColumns;
287 Clear3270();
288 #if !defined(PURE3274)
289 if (TransparentClock == OutputClock) {
290 TransStop();
292 #endif /* !defined(PURE3274) */
293 break;
296 case CMD_ERASE_ALL_UNPROTECTED:
297 case CMD_SNA_ERASE_ALL_UNPROTECTED:
298 SetOiaOnlineA(&OperatorInformationArea);
299 ResetOiaTWait(&OperatorInformationArea);
300 SetOiaModified();
301 CursorAddress = HighestScreen()+1;
302 for (i = LowestScreen(); i <= HighestScreen(); i = ScreenInc(i)) {
303 if (IsUnProtected(i)) {
304 if (CursorAddress > i) {
305 CursorAddress = i;
307 AddHost(i, '\0');
309 if (HasMdt(i)) {
310 TurnOffMdt(i);
313 if (CursorAddress == HighestScreen()+1) {
314 CursorAddress = SetBufferAddress(0,0);
316 UnLocked = 1;
317 AidByte = 0;
318 ResetOiaSystemLocked(&OperatorInformationArea);
319 SetOiaModified();
320 TerminalIn();
321 break;
322 case CMD_WRITE:
323 case CMD_SNA_WRITE:
324 SetOiaOnlineA(&OperatorInformationArea);
325 ResetOiaTWait(&OperatorInformationArea);
326 SetOiaModified();
327 break;
328 default:
330 char s_buffer[100];
332 sprintf(s_buffer,
333 "Unexpected write command code 0x%x received.\n",
334 Command);
335 ExitString(s_buffer, 1);
336 break;
340 count -= 2; /* strip off command and wcc */
341 buffer += 2;
343 } else {
344 #if !defined(PURE3274)
345 if (TransparentClock == OutputClock) {
346 TransOut(buffer, count, -1, control);
347 count = 0;
349 #endif /* !defined(PURE3274) */
351 LastWasTerminated = 0; /* then, reset at end... */
353 while (count) {
354 count--;
355 c = *buffer++;
356 if (IsOrder(c)) {
357 /* handle an order */
358 switch (c) {
359 # define Ensure(x) if (count < x) { \
360 if (!control) { \
361 return(origCount-(count+1)); \
362 } else { \
363 /* XXX - should not occur */ \
364 count = 0; \
365 break; \
368 case ORDER_SF:
369 Ensure(1);
370 c = *buffer++;
371 count--;
372 if ( ! (IsStartField(BufferAddress) &&
373 FieldAttributes(BufferAddress) == c)) {
374 SetHighestLowest(BufferAddress);
375 NewField(BufferAddress,c);
377 BufferAddress = ScreenInc(BufferAddress);
378 break;
379 case ORDER_SBA:
380 Ensure(2);
381 i = buffer[0];
382 c = buffer[1];
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);
388 buffer += count;
389 count -= count;
390 break;
392 #endif /* !defined(PURE3274) */
393 BufferAddress = Addr3270(i, c);
394 buffer += 2;
395 count -= 2;
396 break;
397 case ORDER_IC:
398 CursorAddress = BufferAddress;
399 break;
401 * XXX - PT is supposed to null fill the screen buffer
402 * under certain draconian conditions.
404 case ORDER_PT:
405 i = BufferAddress;
406 do {
407 if (IsStartField(i)) {
408 if (!IsProtected(ScreenInc(i))) {
409 break;
412 i = ScreenInc(i);
413 } while (i != HighestScreen());
414 BufferAddress = ScreenInc(i);
415 break;
416 case ORDER_RA:
417 Ensure(3);
418 i = Addr3270(buffer[0], buffer[1]);
419 if ((i < 0) || (i > HighestScreen())) {
420 char s_buffer[200];
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 ",
426 NumberLines,
427 " by ",
428 NumberColumns,
429 ".)");
430 ExitString(s_buffer, 1);
431 /*NOTREACHED*/
433 c = buffer[2];
434 if (c == ORDER_GE) {
435 Ensure(4);
436 c = buffer[3];
437 buffer += 4;
438 count -= 4;
439 } else {
440 buffer += 3;
441 count -= 3;
443 do {
444 AddHost(BufferAddress, ebc_disp[c]);
445 BufferAddress = ScreenInc(BufferAddress);
446 } while (BufferAddress != i);
447 break;
448 case ORDER_EUA: /* (from [here,there), ie: half open interval] */
449 Ensure(2);
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())) {
458 char s_buffer[200];
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 ",
464 NumberLines,
465 " by ",
466 NumberColumns,
467 ".)");
468 ExitString(s_buffer, 1);
469 /*NOTREACHED*/
471 do {
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);
479 buffer += 2;
480 count -= 2;
481 break;
482 case ORDER_GE:
483 Ensure(2);
484 /* XXX Should do SOMETHING! */
485 /* XXX buffer += 0; */
486 /* XXX count -= 0; *//* For now, just use this character */
487 break;
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);
492 if (i == 0) {
493 return(origCount-(count+1)); /* come here again */
494 } else {
495 buffer += 1 + i;
496 count -= (1 + i);
499 break;
500 default:
502 char s_buffer[100];
503 static struct orders_def unk_order
504 = { 0, "??", "(unknown)" };
505 struct orders_def *porder = &unk_order;
506 int s_i;
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];
511 break;
514 sprintf(s_buffer,
515 "Unsupported order '%s' (%s, 0x%x) received.\n",
516 porder->long_name, porder->short_name, c);
517 ExitString(s_buffer, 1);
518 /*NOTREACHED*/
521 if (count < 0) {
522 count = 0;
524 } else {
525 /* Data comes in large clumps - take it all */
526 i = BufferAddress;
527 AddHostA(i, ebc_disp[c]);
528 SetHighestLowest(i);
529 i = ScreenInc(i);
530 c = *buffer;
531 while (count && !IsOrder(c)) {
532 AddHostA(i, ebc_disp[c]);
533 i = ScreenInc(i);
534 if (i == LowestScreen()) {
535 SetHighestLowest(HighestScreen());
537 count--;
538 buffer++;
539 c = *buffer;
541 SetHighestLowest(i);
542 BufferAddress = i;
545 #if 0
546 if (count == 0) {
547 #endif
548 if (control) {
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) {
555 AidByte = 0;
557 #else /* !defined(PURE3274) */
558 AidByte = 0;
559 #endif /* !defined(PURE3274) */
560 UnLocked = 1;
561 ResetOiaSystemLocked(&OperatorInformationArea);
562 SetOiaModified();
563 SetPsModified();
564 TerminalIn();
566 if (Wcc & WCC_ALARM) {
567 RingBell((char *)0);
570 LastWasTerminated = control; /* state for next time */
571 return(origCount);
572 #if 0
573 } else {
574 return(origCount-count);
576 #endif
580 * Init3270()
582 * Initialize any 3270 (controller) variables to an initial state
583 * in preparation for accepting a connection.
586 void
587 Init3270()
589 int i;
591 OptInit(); /* initialize mappings */
593 ClearArray(Host);
595 ClearArray(Orders);
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);
604 UnLocked = 1;
605 #if !defined(PURE3274)
606 OutputClock = 1;
607 TransparentClock = -1;
608 #endif /* !defined(PURE3274) */
609 SetOiaReady3274(&OperatorInformationArea);
613 void
614 Stop3270()
616 ResetOiaReady3274(&OperatorInformationArea);