Seems to work with 'close' then 'open'
[unix-history] / usr / src / usr.bin / tn3270 / ctlr / outbound.c
CommitLineData
3d8b96ab
GM
1/*
2 * Copyright (c) 1984, 1985, 1986 by the Regents of the
3 * University of California and by Gregory Glenn Minshall.
4 *
5 * Permission to use, copy, modify, and distribute these
6 * programs and their documentation for any purpose and
7 * without fee is hereby granted, provided that this
8 * copyright and permission appear on all copies and
9 * supporting documentation, the name of the Regents of
10 * the University of California not be used in advertising
11 * or publicity pertaining to distribution of the programs
12 * without specific prior permission, and notice be given in
13 * supporting documentation that copying and distribution is
14 * by permission of the Regents of the University of California
15 * and by Gregory Glenn Minshall. Neither the Regents of the
16 * University of California nor Gregory Glenn Minshall make
17 * representations about the suitability of this software
18 * for any purpose. It is provided "as is" without
19 * express or implied warranty.
20 */
21
22#ifndef lint
23static char sccsid[] = "@(#)outbound.c 3.1 10/29/86";
24#endif /* lint */
25
26
3d8b96ab
GM
27#include "hostctlr.h"
28#include "screen.h"
29#include "ebc_disp.h"
30
31#include "../system/globals.h"
32#include "options.ext"
33#include "../telnet.ext"
34#include "inbound.ext"
35#include "outbound.ext"
564518ce 36#include "../system/bsubs.ext"
3d8b96ab
GM
37
38#define SetHighestLowest(position) { \
39 if (position < Lowest) { \
40 Lowest = position; \
41 } \
42 if (position > Highest) { \
43 Highest = position; \
44 } \
45 }
46
3d8b96ab 47
25dbbecd
GM
48static int LastWasTerminated = 1; /* was "control" = 1 last time? */
49
3d8b96ab
GM
50/* some globals */
51
44d721ab 52#if !defined(PURE3274)
25dbbecd
GM
53int OutputClock; /* what time it is */
54int TransparentClock; /* time we were last in transparent */
44d721ab 55#endif /* !defined(PURE3274) */
3d8b96ab
GM
56\f
57
58char CIABuffer[64] = {
59 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
60 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
61 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
62 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
63 0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
64 0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
65 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
66 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
67};
68\f
25dbbecd
GM
69/*
70 * ctlrinit()
71 *
72 * Initialize all data from the 'data' portion to their startup values.
73 */
74
75void
76ctlrinit()
77{
78 LastWasTerminated = 1;
79}
80
3d8b96ab
GM
81/* What we know is that table is of size ScreenSize */
82
83FieldFind(table, position, failure)
84register char *table; /* which table of bytes to use */
85register int position; /* what position to start from */
86int failure; /* if unformatted, what value to return */
87{
88 register int ourp;
89
90 ourp = position + 1 + bskip(table+position+1, ScreenSize-position-1, 0);
91 if (ourp < ScreenSize) {
92 return(ourp);
93 }
94 /* No fields in table after position. Look for fields from beginning
95 * of table.
96 */
97 ourp = bskip(table, position+1, 0);
98 if (ourp <= position) {
99 return(ourp);
100 }
101 return(failure);
102}
103
104/* Clear3270 - called to clear the screen */
105
106void
107Clear3270()
108{
109 bzero((char *)Host, sizeof(Host));
110 DeleteAllFields(); /* get rid of all fields */
111 BufferAddress = SetBufferAddress(0,0);
112 CursorAddress = SetBufferAddress(0,0);
113 Lowest = LowestScreen();
114 Highest = HighestScreen();
115}
116\f
117/* AddHost - called to add a character to the buffer.
118 * We use a macro in this module, since we call it so
119 * often from loops.
120 *
121 * NOTE: It is a macro, so don't go around using AddHost(p, *c++), or
122 * anything similar. (I don't define any temporary variables, again
123 * just for the speed.)
124 */
125void
126AddHost(position, character)
127int position;
128char character;
129{
130#if defined(SLOWSCREEN)
131# define AddHostA(p,c) \
132 { \
133 if (IsStartField(p)) { \
134 DeleteField(p); \
135 Highest = HighestScreen(); \
136 Lowest = LowestScreen(); \
137 SetHighestLowest(p); \
138 } \
139 SetHost(p, c); \
140 }
141# define AddHost(p,c) \
142 { \
143 if (c != GetHost(p)) { \
144 SetHighestLowest(p); \
145 } \
146 AddHostA(p,c); \
147 } /* end of macro of AddHost */
148#else /* defined(SLOWSCREEN) */
149# define AddHost(p,c) \
150 { \
151 if (IsStartField(p)) { \
152 DeleteField(p); \
153 Highest = HighestScreen(); \
154 Lowest = LowestScreen(); \
155 SetHost(p, c); \
156 } else { \
157 SetHost(p, c); \
158 SetHighestLowest(p); \
159 } \
160 } /* end of macro of AddHost */
161#endif /* defined(SLOWSCREEN) */
162
163 AddHost(position, character);
164}
165\f
166/* returns the number of characters consumed */
167int
168DataFromNetwork(buffer, count, control)
169register unsigned char *buffer; /* what the data is */
170register int count; /* and how much there is */
171int control; /* this buffer ended block? */
172{
173 int origCount;
174 register int c;
175 register int i;
176 static int Command;
177 static int Wcc;
3d8b96ab
GM
178
179 origCount = count;
180
181 if (LastWasTerminated) {
182
183 if (count < 2) {
184 if (count == 0) {
15fd51e0 185 ExitString("Short count received from host!\n", 1);
3d8b96ab
GM
186 return(count);
187 }
188 Command = buffer[0];
189 switch (Command) { /* This had better be a read command */
190 case CMD_READ_MODIFIED:
191 case CMD_SNA_READ_MODIFIED:
192 case CMD_SNA_READ_MODIFIED_ALL:
193 DoReadModified(Command);
194 break;
195 case CMD_READ_BUFFER:
196 case CMD_SNA_READ_BUFFER:
197 DoReadBuffer();
198 break;
199 default:
200 break;
201 }
202 return(1); /* We consumed everything */
203 }
204 Command = buffer[0];
205 Wcc = buffer[1];
206 if (Wcc & WCC_RESET_MDT) {
207 i = c = WhereAttrByte(LowestScreen());
208 do {
209 if (HasMdt(i)) {
210 TurnOffMdt(i);
211 }
212 i = FieldInc(i);
213 } while (i != c);
214 }
215
216 switch (Command) {
217 case CMD_ERASE_WRITE:
218 case CMD_ERASE_WRITE_ALTERNATE:
219 case CMD_SNA_ERASE_WRITE:
220 case CMD_SNA_ERASE_WRITE_ALTERNATE:
221 {
222 int newlines, newcolumns;
223
3d8b96ab
GM
224 if ((Command == CMD_ERASE_WRITE)
225 || (Command == CMD_SNA_ERASE_WRITE)) {
226 newlines = 24;
227 newcolumns = 80;
228 } else {
229 newlines = MaxNumberLines;
230 newcolumns = MaxNumberColumns;
231 }
232 if ((newlines != NumberLines)
233 || (newcolumns != NumberColumns)) {
234 /*
235 * The LocalClearScreen() is really for when we
236 * are going from a larger screen to a smaller
237 * screen, and we need to clear off the stuff
238 * at the end of the lines, or the lines at
239 * the end of the screen.
240 */
241 LocalClearScreen();
242 NumberLines = newlines;
243 NumberColumns = newcolumns;
244 ScreenSize = NumberLines * NumberColumns;
245 }
246 Clear3270();
44d721ab 247#if !defined(PURE3274)
3d8b96ab 248 if (TransparentClock == OutputClock) {
15fd51e0 249 TransStop();
3d8b96ab 250 }
44d721ab 251#endif /* !defined(PURE3274) */
3d8b96ab
GM
252 break;
253 }
254
255 case CMD_ERASE_ALL_UNPROTECTED:
256 case CMD_SNA_ERASE_ALL_UNPROTECTED:
257 CursorAddress = HighestScreen()+1;
258 for (i = LowestScreen(); i <= HighestScreen(); i = ScreenInc(i)) {
259 if (IsUnProtected(i)) {
260 if (CursorAddress > i) {
261 CursorAddress = i;
262 }
263 AddHost(i, '\0');
264 }
265 if (HasMdt(i)) {
266 TurnOffMdt(i);
267 }
268 }
269 if (CursorAddress == HighestScreen()+1) {
270 CursorAddress = SetBufferAddress(0,0);
271 }
272 UnLocked = 1;
273 AidByte = 0;
274 break;
275 case CMD_WRITE:
276 case CMD_SNA_WRITE:
277 break;
278 default:
279 {
280 char buffer[100];
281
282 sprintf(buffer, "Unexpected command code 0x%x received.\n",
283 Command);
15fd51e0 284 ExitString(buffer, 1);
3d8b96ab
GM
285 break;
286 }
287 }
288
289 count -= 2; /* strip off command and wcc */
290 buffer += 2;
291
292 }
293 LastWasTerminated = 0; /* then, reset at end... */
294
295 while (count) {
296 count--;
297 c = *buffer++;
298 if (IsOrder(c)) {
299 /* handle an order */
300 switch (c) {
301# define Ensure(x) if (count < x) { \
302 if (!control) { \
303 return(origCount-(count+1)); \
304 } else { \
305 /* XXX - should not occur */ \
306 count = 0; \
307 break; \
308 } \
309 }
310 case ORDER_SF:
311 Ensure(1);
312 c = *buffer++;
313 count--;
314 if ( ! (IsStartField(BufferAddress) &&
315 FieldAttributes(BufferAddress) == c)) {
316 SetHighestLowest(BufferAddress);
317 NewField(BufferAddress,c);
318 }
3d8b96ab
GM
319 BufferAddress = ScreenInc(BufferAddress);
320 break;
321 case ORDER_SBA:
322 Ensure(2);
323 i = buffer[0];
324 c = buffer[1];
44d721ab 325#if !defined(PURE3274)
3d8b96ab
GM
326 if (!i && !c) { /* transparent write */
327 if (!control) {
328 return(origCount-(count+1));
329 } else {
15fd51e0
GM
330 TransparentClock = OutputClock; /* clock next */
331 TransOut(buffer+2, count-2); /* output */
332 SendToIBM(); /* ack block */
3d8b96ab
GM
333 TransparentClock = OutputClock+1; /* clock next */
334 buffer += count;
335 count -= count;
336 }
44d721ab 337 break;
3d8b96ab 338 }
44d721ab
GM
339#endif /* !defined(PURE3274) */
340 BufferAddress = Addr3270(i, c);
341 buffer += 2;
342 count -= 2;
3d8b96ab
GM
343 break;
344 case ORDER_IC:
345 CursorAddress = BufferAddress;
346 break;
347 case ORDER_PT:
348 for (i = ScreenInc(BufferAddress); (i != HighestScreen());
349 i = ScreenInc(i)) {
350 if (IsStartField(i)) {
351 i = ScreenInc(i);
352 if (!IsProtected(ScreenInc(i))) {
353 break;
354 }
355 if (i == HighestScreen()) {
356 break;
357 }
358 }
359 }
360 CursorAddress = i;
361 break;
362 case ORDER_RA:
363 Ensure(3);
364 i = Addr3270(buffer[0], buffer[1]);
365 c = buffer[2];
366 do {
367 AddHost(BufferAddress, ebc_disp[c]);
368 BufferAddress = ScreenInc(BufferAddress);
369 } while (BufferAddress != i);
370 buffer += 3;
371 count -= 3;
372 break;
373 case ORDER_EUA: /* (from [here,there), ie: half open interval] */
374 Ensure(2);
564518ce
GM
375 /*
376 * Compiler error - msc version 4.0:
377 * "expression too complicated".
378 */
379 i = WhereAttrByte(BufferAddress);
380 c = FieldAttributes(i);
3d8b96ab
GM
381 for (i = Addr3270(buffer[0], buffer[1]); i != BufferAddress;
382 BufferAddress = ScreenInc(BufferAddress)) {
383 if (!IsProtectedAttr(BufferAddress, c)) {
384 AddHost(BufferAddress, 0);
385 }
386 }
387 buffer += 2;
388 count -= 2;
389 break;
390 case ORDER_YALE: /* special YALE defined order */
391 Ensure(2); /* need at least two characters */
392 if (*buffer == 0x5b) {
393 i = OptOrder(buffer+1, count-1, control);
394 if (i == 0) {
395 return(origCount-(count+1)); /* come here again */
396 } else {
397 buffer += 1 + i;
398 count -= (1 + i);
399 }
400 }
401 break;
402 default:
403 break; /* XXX ? */
404 }
405 if (count < 0) {
406 count = 0;
407 }
408 } else {
409 /* Data comes in large clumps - take it all */
410 i = BufferAddress;
411#if !defined(SLOWSCREEN)
412 AddHost(i, ebc_disp[c]);
413#else /* !defined(SLOWSCREEN) */
414 AddHostA(i, ebc_disp[c]);
415 SetHighestLowest(i);
416#endif /* !defined(SLOWSCREEN) */
417 i = ScreenInc(i);
418 c = *buffer;
419 while (count && !IsOrder(c)) {
420#if !defined(SLOWSCREEN)
421 AddHost(i, ebc_disp[c]);
422#else /* !defined(SLOWSCREEN) */
423 AddHostA(i, ebc_disp[c]);
424#endif /* !defined(SLOWSCREEN) */
425 i = ScreenInc(i);
426#if defined(SLOWSCREEN)
427 if (i == LowestScreen()) {
428 SetHighestLowest(HighestScreen());
429 }
430#endif /* defined(SLOWSCREEN) */
431 count--;
432 buffer++;
433 c = *buffer;
434 }
435#if defined(SLOWSCREEN)
436 SetHighestLowest(i);
437#endif /* defined(SLOWSCREEN) */
438 BufferAddress = i;
439 }
440 }
441 if (count == 0) {
44d721ab 442#if !defined(PURE3274)
3d8b96ab 443 OutputClock++; /* time rolls on */
44d721ab 444#endif /* !defined(PURE3274) */
3d8b96ab
GM
445 if (control) {
446 if (Wcc & WCC_RESTORE) {
44d721ab 447#if !defined(PURE3274)
3d8b96ab
GM
448 if (TransparentClock != OutputClock) {
449 AidByte = 0;
450 }
44d721ab
GM
451#else /* !defined(PURE3274) */
452 AidByte = 0;
453#endif /* !defined(PURE3274) */
3d8b96ab
GM
454 UnLocked = 1;
455 }
456 if (Wcc & WCC_ALARM) {
457 RingBell(0);
458 }
459 }
460 LastWasTerminated = control; /* state for next time */
461 return(origCount);
462 } else {
463 return(origCount-count);
464 }
465}
25dbbecd
GM
466
467/*
468 * Init3270()
469 *
470 * Initialize any 3270 (controller) variables to an initial state
471 * in preparation for accepting a connection.
472 */
473
474void
475Init3270()
476{
477 OptInit(); /* initialize mappings */
478
479 bzero((char *)Host, sizeof Host); /* Clear host */
480
481 bzero(Orders, sizeof Orders);
482 Orders[ORDER_SF] = Orders[ORDER_SBA] = Orders[ORDER_IC]
483 = Orders[ORDER_PT] = Orders[ORDER_RA] = Orders[ORDER_EUA]
484 = Orders[ORDER_YALE] = 1; /* What is an order */
485
486 DeleteAllFields(); /* Clear screen */
487 Lowest = HighestScreen()+1;
488 Highest = LowestScreen()-1;
489 CursorAddress = BufferAddress = SetBufferAddress(0,0);
490 UnLocked = 1;
491 OutputClock = 1;
492 TransparentClock = -1;
493}