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