|
|
1.1 root 1: /*
2: * Copyright (c) 1988 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
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.
16: */
17:
18: #ifndef lint
19: static char sccsid[] = "@(#)outbound.c 4.2 (Berkeley) 2/6/89";
20: #endif /* not lint */
21:
22: #include <stdio.h>
23:
24: #include "../general/general.h"
25:
26: #include "hostctlr.h"
27: #include "oia.h"
28: #include "screen.h"
29: #include "../api/ebc_disp.h"
30:
31: #include "../general/globals.h"
32: #include "externs.h"
33: #include "declare.h"
34:
35: #define SetHighestLowest(position) { \
36: if (position < Lowest) { \
37: Lowest = position; \
38: } \
39: if (position > Highest) { \
40: Highest = position; \
41: } \
42: }
43:
44:
45: static int LastWasTerminated = 1; /* was "control" = 1 last time? */
46:
47: /* some globals */
48:
49: #if !defined(PURE3274)
50: int OutputClock; /* what time it is */
51: int TransparentClock; /* time we were last in transparent */
52: #endif /* !defined(PURE3274) */
53:
54: char 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: };
64:
65: static struct orders_def orders_def[] = ORDERS_DEF;
66:
67: /*
68: * init_ctlr()
69: *
70: * Initialize all data from the 'data' portion to their startup values.
71: */
72:
73: void
74: init_ctlr()
75: {
76: LastWasTerminated = 1;
77: init_inbound();
78: init_oia();
79: }
80:
81:
82: FieldInc(position)
83: register int position; /* Position in previous field */
84: {
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: }
95: }
96: return ptr-Host;
97: }
98:
99: FieldDec(position)
100: int 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) {
110: return LowestScreen();
111: }
112: }
113: return ptr-Host;
114: }
115:
116: /* Clear3270 - called to clear the screen */
117:
118: void
119: Clear3270()
120: {
121: ClearArray(Host);
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:
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: */
137: void
138: AddHost(position, character)
139: int position;
140: char character;
141: {
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 */
159:
160: AddHost(position, character);
161: }
162:
163: /* returns the number of characters consumed */
164: int
165: DataFromNetwork(Buffer, count, control)
166: char *Buffer; /* what the data is */
167: register int count; /* and how much there is */
168: int control; /* this buffer ended block? */
169: {
170: int origCount;
171: register unsigned char *buffer = (unsigned char *)Buffer;
172: register int c;
173: register int i;
174: static int Command;
175: static int Wcc;
176:
177: origCount = count;
178:
179: /*
180: * If this is the start of a new data stream, then look
181: * for an op-code and (possibly) a WCC.
182: */
183: if (LastWasTerminated) {
184:
185: if (count < 2) {
186: if (count == 0) {
187: ExitString("Short count received from host!\n", 1);
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:
195: SetOiaOnlineA(&OperatorInformationArea);
196: SetOiaModified();
197: DoReadModified(Command);
198: break;
199: case CMD_READ_BUFFER:
200: case CMD_SNA_READ_BUFFER:
201: SetOiaOnlineA(&OperatorInformationArea);
202: SetOiaModified();
203: DoReadBuffer();
204: break;
205: default:
206: {
207: char s_buffer[100];
208:
209: sprintf(s_buffer,
210: "Unexpected read command code 0x%x received.\n",
211: Command);
212: ExitString(s_buffer, 1);
213: break;
214: }
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:
238: SetOiaOnlineA(&OperatorInformationArea);
239: ResetOiaTWait(&OperatorInformationArea);
240: SetOiaModified();
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();
264: #if !defined(PURE3274)
265: if (TransparentClock == OutputClock) {
266: TransStop();
267: }
268: #endif /* !defined(PURE3274) */
269: break;
270: }
271:
272: case CMD_ERASE_ALL_UNPROTECTED:
273: case CMD_SNA_ERASE_ALL_UNPROTECTED:
274: SetOiaOnlineA(&OperatorInformationArea);
275: ResetOiaTWait(&OperatorInformationArea);
276: SetOiaModified();
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;
294: ResetOiaSystemLocked(&OperatorInformationArea);
295: SetOiaModified();
296: TerminalIn();
297: break;
298: case CMD_WRITE:
299: case CMD_SNA_WRITE:
300: SetOiaOnlineA(&OperatorInformationArea);
301: ResetOiaTWait(&OperatorInformationArea);
302: SetOiaModified();
303: break;
304: default:
305: {
306: char s_buffer[100];
307:
308: sprintf(s_buffer,
309: "Unexpected write command code 0x%x received.\n",
310: Command);
311: ExitString(s_buffer, 1);
312: break;
313: }
314: }
315:
316: count -= 2; /* strip off command and wcc */
317: buffer += 2;
318:
319: } else {
320: #if !defined(PURE3274)
321: if (TransparentClock == OutputClock) {
322: TransOut(buffer, count, -1, control);
323: count = 0;
324: }
325: #endif /* !defined(PURE3274) */
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: }
353: BufferAddress = ScreenInc(BufferAddress);
354: break;
355: case ORDER_SBA:
356: Ensure(2);
357: i = buffer[0];
358: c = buffer[1];
359: #if !defined(PURE3274)
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;
366: break;
367: }
368: #endif /* !defined(PURE3274) */
369: BufferAddress = Addr3270(i, c);
370: buffer += 2;
371: count -= 2;
372: break;
373: case ORDER_IC:
374: CursorAddress = BufferAddress;
375: break;
376: /*
377: * XXX - PT is supposed to null fill the screen buffer
378: * under certain draconian conditions.
379: */
380: case ORDER_PT:
381: i = BufferAddress;
382: do {
383: if (IsStartField(i)) {
384: if (!IsProtected(ScreenInc(i))) {
385: break;
386: }
387: }
388: i = ScreenInc(i);
389: } while (i != HighestScreen());
390: BufferAddress = ScreenInc(i);
391: break;
392: case ORDER_RA:
393: Ensure(3);
394: i = Addr3270(buffer[0], buffer[1]);
395: if ((i < 0) || (i > HighestScreen())) {
396: char s_buffer[200];
397:
398: sprintf(s_buffer, "tn3270: %s%d.\n\t%s%d%s%d%s\n",
399: "Invalid 3270 order 'Repeat to Address' to address ",
400: i,
401: "(Screen currently set to ",
402: NumberLines,
403: " by ",
404: NumberColumns,
405: ".)");
406: ExitString(s_buffer, 1);
407: /*NOTREACHED*/
408: }
409: c = buffer[2];
410: if (c == ORDER_GE) {
411: Ensure(4);
412: c = buffer[3];
413: buffer += 4;
414: count -= 4;
415: } else {
416: buffer += 3;
417: count -= 3;
418: }
419: do {
420: AddHost(BufferAddress, ebc_disp[c]);
421: BufferAddress = ScreenInc(BufferAddress);
422: } while (BufferAddress != i);
423: break;
424: case ORDER_EUA: /* (from [here,there), ie: half open interval] */
425: Ensure(2);
426: /*
427: * Compiler error - msc version 4.0:
428: * "expression too complicated".
429: */
430: i = WhereAttrByte(BufferAddress);
431: c = FieldAttributes(i);
432: i = Addr3270(buffer[0], buffer[1]);
433: if ((i < 0) || (i > HighestScreen())) {
434: char s_buffer[200];
435:
436: sprintf(s_buffer, "tn3270: %s%d.\n\t%s%d%s%d%s\n",
437: "Invalid 3270 order 'Erase Unprotected to Address' to address ",
438: i,
439: "(Screen currently set to ",
440: NumberLines,
441: " by ",
442: NumberColumns,
443: ".)");
444: ExitString(s_buffer, 1);
445: /*NOTREACHED*/
446: }
447: do {
448: if (IsStartField(BufferAddress)) {
449: c = FieldAttributes(BufferAddress);
450: } else if (!IsProtectedAttr(BufferAddress, c)) {
451: AddHost(BufferAddress, 0);
452: }
453: BufferAddress = ScreenInc(BufferAddress);
454: } while (i != BufferAddress);
455: buffer += 2;
456: count -= 2;
457: break;
458: case ORDER_GE:
459: Ensure(2);
460: /* XXX Should do SOMETHING! */
461: /* XXX buffer += 0; */
462: /* XXX count -= 0; *//* For now, just use this character */
463: break;
464: case ORDER_YALE: /* special YALE defined order */
465: Ensure(2); /* need at least two characters */
466: if (*buffer == 0x5b) {
467: i = OptOrder(buffer+1, count-1, control);
468: if (i == 0) {
469: return(origCount-(count+1)); /* come here again */
470: } else {
471: buffer += 1 + i;
472: count -= (1 + i);
473: }
474: }
475: break;
476: default:
477: {
478: char s_buffer[100];
479: static struct orders_def unk_order
480: = { 0, "??", "(unknown)" };
481: struct orders_def *porder = &unk_order;
482: int s_i;
483:
484: for (s_i = 0; s_i <= highestof(orders_def); s_i++) {
485: if (orders_def[s_i].code == c) {
486: porder = &orders_def[s_i];
487: break;
488: }
489: }
490: sprintf(s_buffer,
491: "Unsupported order '%s' (%s, 0x%x) received.\n",
492: porder->long_name, porder->short_name, c);
493: ExitString(s_buffer, 1);
494: /*NOTREACHED*/
495: }
496: }
497: if (count < 0) {
498: count = 0;
499: }
500: } else {
501: /* Data comes in large clumps - take it all */
502: i = BufferAddress;
503: AddHostA(i, ebc_disp[c]);
504: SetHighestLowest(i);
505: i = ScreenInc(i);
506: c = *buffer;
507: while (count && !IsOrder(c)) {
508: AddHostA(i, ebc_disp[c]);
509: i = ScreenInc(i);
510: if (i == LowestScreen()) {
511: SetHighestLowest(HighestScreen());
512: }
513: count--;
514: buffer++;
515: c = *buffer;
516: }
517: SetHighestLowest(i);
518: BufferAddress = i;
519: }
520: }
521: if (count == 0) {
522: if (control) {
523: #if !defined(PURE3274)
524: OutputClock++; /* time rolls on */
525: #endif /* !defined(PURE3274) */
526: if (Wcc & WCC_RESTORE) {
527: #if !defined(PURE3274)
528: if (TransparentClock != OutputClock) {
529: AidByte = 0;
530: }
531: #else /* !defined(PURE3274) */
532: AidByte = 0;
533: #endif /* !defined(PURE3274) */
534: UnLocked = 1;
535: ResetOiaSystemLocked(&OperatorInformationArea);
536: SetOiaModified();
537: SetPsModified();
538: TerminalIn();
539: }
540: if (Wcc & WCC_ALARM) {
541: RingBell((char *)0);
542: }
543: }
544: LastWasTerminated = control; /* state for next time */
545: return(origCount);
546: } else {
547: return(origCount-count);
548: }
549: }
550:
551: /*
552: * Init3270()
553: *
554: * Initialize any 3270 (controller) variables to an initial state
555: * in preparation for accepting a connection.
556: */
557:
558: void
559: Init3270()
560: {
561: int i;
562:
563: OptInit(); /* initialize mappings */
564:
565: ClearArray(Host);
566:
567: ClearArray(Orders);
568: for (i = 0; i <= highestof(orders_def); i++) {
569: Orders[orders_def[i].code] = 1;
570: }
571:
572: DeleteAllFields(); /* Clear screen */
573: Lowest = HighestScreen()+1;
574: Highest = LowestScreen()-1;
575: CursorAddress = BufferAddress = SetBufferAddress(0,0);
576: UnLocked = 1;
577: #if !defined(PURE3274)
578: OutputClock = 1;
579: TransparentClock = -1;
580: #endif /* !defined(PURE3274) */
581: SetOiaReady3274(&OperatorInformationArea);
582: }
583:
584:
585: void
586: Stop3270()
587: {
588: ResetOiaReady3274(&OperatorInformationArea);
589: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.