xref: /original-bsd/usr.bin/tn3270/ctlr/outbound.c (revision c3e32dec)
1 /*-
2  * Copyright (c) 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)outbound.c	8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11 
12 #include <stdio.h>
13 
14 #include "../general/general.h"
15 
16 #include "hostctlr.h"
17 #include "oia.h"
18 #include "screen.h"
19 #include "../api/ebc_disp.h"
20 
21 #include "../general/globals.h"
22 #include "externs.h"
23 #include "declare.h"
24 
25 #define SetHighestLowest(position) { \
26 					if (position < Lowest) { \
27 					    Lowest = position; \
28 					} \
29 					if (position > Highest) { \
30 					    Highest = position; \
31 					} \
32 				    }
33 
34 
35 static int	LastWasTerminated = 1;	/* was "control" = 1 last time? */
36 
37 /* some globals */
38 
39 #if	!defined(PURE3274)
40 int	OutputClock;		/* what time it is */
41 int	TransparentClock;		/* time we were last in transparent */
42 #endif	/* !defined(PURE3274) */
43 
44 char CIABuffer[64] = {
45     0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
46     0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
47     0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
48     0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
49     0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
50     0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
51     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
52     0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
53 };
54 
55 static struct orders_def orders_def[] = ORDERS_DEF;
56 
57 /*
58  * init_ctlr()
59  *
60  *	Initialize all data from the 'data' portion to their startup values.
61  */
62 
63 void
64 init_ctlr()
65 {
66     LastWasTerminated = 1;
67     init_inbound();
68     init_oia();
69 }
70 
71 
72 FieldInc(position)
73 register int	position;		/* Position in previous field */
74 {
75     register ScreenImage *ptr;
76 
77     ptr = (ScreenImage *)memNSchr((char *)Host+position+1, ATTR_MASK,
78 			HighestScreen()-position, ATTR_MASK, sizeof Host[0]);
79     if (ptr == 0) {
80 	ptr = (ScreenImage *)memNSchr((char *)Host+LowestScreen(), ATTR_MASK,
81 			position-LowestScreen(), ATTR_MASK, sizeof Host[0]);
82 	if (ptr == 0) {
83 	    return LowestScreen();
84 	}
85     }
86     return ptr-Host;
87 }
88 
89 FieldDec(position)
90 int	position;
91 {
92     register ScreenImage *ptr;
93 
94     ptr = (ScreenImage *)memNSchr((char *)(Host+position)-1, ATTR_MASK,
95 			position-LowestScreen(), ATTR_MASK, -sizeof Host[0]);
96     if (ptr == 0) {
97 	ptr = (ScreenImage *)memNSchr((char *)Host+HighestScreen(), ATTR_MASK,
98 			HighestScreen()-position, ATTR_MASK, -sizeof Host[0]);
99 	if (ptr == 0) {
100 	    return LowestScreen();
101 	}
102     }
103     return ptr-Host;
104 }
105 
106 /* Clear3270 - called to clear the screen */
107 
108 void
109 Clear3270()
110 {
111     ClearArray(Host);
112     DeleteAllFields();		/* get rid of all fields */
113     BufferAddress = SetBufferAddress(0,0);
114     CursorAddress = SetBufferAddress(0,0);
115     Lowest = LowestScreen();
116     Highest = HighestScreen();
117 }
118 
119 /* AddHost - called to add a character to the buffer.
120  *	We use a macro in this module, since we call it so
121  *	often from loops.
122  *
123  *	NOTE: It is a macro, so don't go around using AddHost(p, *c++), or
124  *	anything similar.  (I don't define any temporary variables, again
125  *	just for the speed.)
126  */
127 void
128 AddHost(position, character)
129 int	position;
130 char	character;
131 {
132 #   define	AddHostA(p,c)					\
133     {								\
134 	if (IsStartField(p)) {					\
135 	    DeleteField(p);					\
136 	    Highest = HighestScreen();				\
137 	    Lowest = LowestScreen();				\
138 	    SetHighestLowest(p);				\
139 	}							\
140 	SetHost(p, c);						\
141     }
142 #   define	AddHost(p,c)					\
143     {								\
144 	if (c != GetHost(p)) {					\
145 	    SetHighestLowest(p);				\
146 	}							\
147 	AddHostA(p,c);						\
148     }	/* end of macro of AddHost */
149 
150     AddHost(position, character);
151 }
152 
153 /* returns the number of characters consumed */
154 int
155 DataFromNetwork(Buffer, count, control)
156 char	*Buffer;				/* what the data is */
157 register int	count;				/* and how much there is */
158 int	control;				/* this buffer ended block? */
159 {
160     int origCount;
161     register unsigned char *buffer = (unsigned char *)Buffer;
162     register int c;
163     register int i;
164     static int Command;
165     static int Wcc;
166 
167     origCount = count;
168 
169     /*
170      * If this is the start of a new data stream, then look
171      * for an op-code and (possibly) a WCC.
172      */
173     if (LastWasTerminated) {
174 
175 	if (count < 2) {
176 	    if (count == 0) {
177 		ExitString("Short count received from host!\n", 1);
178 		return(count);
179 	    }
180 	    Command = buffer[0];
181 	    switch (Command) {		/* This had better be a read command */
182 	    case CMD_READ_MODIFIED:
183 	    case CMD_SNA_READ_MODIFIED:
184 	    case CMD_SNA_READ_MODIFIED_ALL:
185 		SetOiaOnlineA(&OperatorInformationArea);
186 		SetOiaModified();
187 		DoReadModified(Command);
188 		break;
189 	    case CMD_READ_BUFFER:
190 	    case CMD_SNA_READ_BUFFER:
191 		SetOiaOnlineA(&OperatorInformationArea);
192 		SetOiaModified();
193 		DoReadBuffer();
194 		break;
195 	    default:
196 		{
197 		    char s_buffer[100];
198 
199 		    sprintf(s_buffer,
200 			"Unexpected read command code 0x%x received.\n",
201 								    Command);
202 		    ExitString(s_buffer, 1);
203 		    break;
204 		}
205 	    }
206 	    return(1);			/* We consumed everything */
207 	}
208 	Command = buffer[0];
209 	Wcc = buffer[1];
210 	if (Wcc & WCC_RESET_MDT) {
211 	    i = c = WhereAttrByte(LowestScreen());
212 	    do {
213 		if (HasMdt(i)) {
214 		    TurnOffMdt(i);
215 		}
216 		i = FieldInc(i);
217 	    } while (i != c);
218 	}
219 
220 	switch (Command) {
221 	case CMD_ERASE_WRITE:
222 	case CMD_ERASE_WRITE_ALTERNATE:
223 	case CMD_SNA_ERASE_WRITE:
224 	case CMD_SNA_ERASE_WRITE_ALTERNATE:
225 	    {
226 		int newlines, newcolumns;
227 
228 		SetOiaOnlineA(&OperatorInformationArea);
229 		ResetOiaTWait(&OperatorInformationArea);
230 		SetOiaModified();
231 		if ((Command == CMD_ERASE_WRITE)
232 				|| (Command == CMD_SNA_ERASE_WRITE)) {
233 		    newlines = 24;
234 		    newcolumns = 80;
235 		} else {
236 		    newlines = MaxNumberLines;
237 		    newcolumns = MaxNumberColumns;
238 		}
239 		if ((newlines != NumberLines)
240 				|| (newcolumns != NumberColumns)) {
241 			/*
242 			 * The LocalClearScreen() is really for when we
243 			 * are going from a larger screen to a smaller
244 			 * screen, and we need to clear off the stuff
245 			 * at the end of the lines, or the lines at
246 			 * the end of the screen.
247 			 */
248 		    LocalClearScreen();
249 		    NumberLines = newlines;
250 		    NumberColumns = newcolumns;
251 		    ScreenSize = NumberLines * NumberColumns;
252 		}
253 		Clear3270();
254 #if	!defined(PURE3274)
255 		if (TransparentClock == OutputClock) {
256 		    TransStop();
257 		}
258 #endif	/* !defined(PURE3274) */
259 		break;
260 	    }
261 
262 	case CMD_ERASE_ALL_UNPROTECTED:
263 	case CMD_SNA_ERASE_ALL_UNPROTECTED:
264 	    SetOiaOnlineA(&OperatorInformationArea);
265 	    ResetOiaTWait(&OperatorInformationArea);
266 	    SetOiaModified();
267 	    CursorAddress = HighestScreen()+1;
268 	    for (i = LowestScreen(); i <= HighestScreen(); i = ScreenInc(i)) {
269 		if (IsUnProtected(i)) {
270 		    if (CursorAddress > i) {
271 			CursorAddress = i;
272 		    }
273 		    AddHost(i, '\0');
274 		}
275 		if (HasMdt(i)) {
276 		    TurnOffMdt(i);
277 		}
278 	    }
279 	    if (CursorAddress == HighestScreen()+1) {
280 		CursorAddress = SetBufferAddress(0,0);
281 	    }
282 	    UnLocked = 1;
283 	    AidByte = 0;
284 	    ResetOiaSystemLocked(&OperatorInformationArea);
285 	    SetOiaModified();
286 	    TerminalIn();
287 	    break;
288 	case CMD_WRITE:
289 	case CMD_SNA_WRITE:
290 	    SetOiaOnlineA(&OperatorInformationArea);
291 	    ResetOiaTWait(&OperatorInformationArea);
292 	    SetOiaModified();
293 	    break;
294 	default:
295 	    {
296 		char s_buffer[100];
297 
298 		sprintf(s_buffer,
299 			"Unexpected write command code 0x%x received.\n",
300 								Command);
301 		ExitString(s_buffer, 1);
302 		break;
303 	    }
304 	}
305 
306 	count -= 2;			/* strip off command and wcc */
307 	buffer += 2;
308 
309     } else {
310 #if	!defined(PURE3274)
311 	if (TransparentClock == OutputClock) {
312 	    TransOut(buffer, count, -1, control);
313 	    count = 0;
314 	}
315 #endif	/* !defined(PURE3274) */
316     }
317     LastWasTerminated = 0;		/* then, reset at end... */
318 
319     while (count) {
320 	count--;
321 	c = *buffer++;
322 	if (IsOrder(c)) {
323 	    /* handle an order */
324 	    switch (c) {
325 #		define Ensure(x)	if (count < x) { \
326 					    if (!control) { \
327 						return(origCount-(count+1)); \
328 					    } else { \
329 						/* XXX - should not occur */ \
330 						count = 0; \
331 						break; \
332 					    } \
333 					}
334 	    case ORDER_SF:
335 		Ensure(1);
336 		c = *buffer++;
337 		count--;
338 		if ( ! (IsStartField(BufferAddress) &&
339 					FieldAttributes(BufferAddress) == c)) {
340 		    SetHighestLowest(BufferAddress);
341 		    NewField(BufferAddress,c);
342 		}
343 		BufferAddress = ScreenInc(BufferAddress);
344 		break;
345 	    case ORDER_SBA:
346 		Ensure(2);
347 		i = buffer[0];
348 		c = buffer[1];
349 #if	!defined(PURE3274)
350 		/* Check for transparent write */
351 		if ((i == 0) && ((c == 0) || (c == 1) || (c == 5))) {
352 		    TransparentClock = OutputClock+1;
353 		    TransOut(buffer+2, count-2, c, control);
354 		    buffer += count;
355 		    count -= count;
356 		    break;
357 		}
358 #endif	/* !defined(PURE3274) */
359 		BufferAddress = Addr3270(i, c);
360 		buffer += 2;
361 		count -= 2;
362 		break;
363 	    case ORDER_IC:
364 		CursorAddress = BufferAddress;
365 		break;
366 	    /*
367 	     * XXX - PT is supposed to null fill the screen buffer
368 	     * under certain draconian conditions.
369 	     */
370 	    case ORDER_PT:
371 		i = BufferAddress;
372 		do {
373 		    if (IsStartField(i)) {
374 			if (!IsProtected(ScreenInc(i))) {
375 			    break;
376 			}
377 		    }
378 		    i = ScreenInc(i);
379 		} while (i != HighestScreen());
380 		BufferAddress = ScreenInc(i);
381 		break;
382 	    case ORDER_RA:
383 		Ensure(3);
384 		i = Addr3270(buffer[0], buffer[1]);
385 		if ((i < 0) || (i > HighestScreen())) {
386 		    char s_buffer[200];
387 
388 		    sprintf(s_buffer, "tn3270:  %s%d.\n\t%s%d%s%d%s\n",
389 			"Invalid 3270 order 'Repeat to Address' to address ",
390 			i,
391 			"(Screen currently set to ",
392 			NumberLines,
393 			" by ",
394 			NumberColumns,
395 			".)");
396 		    ExitString(s_buffer, 1);
397 		    /*NOTREACHED*/
398 		}
399 		c = buffer[2];
400 		if (c == ORDER_GE) {
401 		    Ensure(4);
402 		    c = buffer[3];
403 		    buffer += 4;
404 		    count -= 4;
405 		} else {
406 		    buffer += 3;
407 		    count -= 3;
408 		}
409 		do {
410 		    AddHost(BufferAddress, ebc_disp[c]);
411 		    BufferAddress = ScreenInc(BufferAddress);
412 		} while (BufferAddress != i);
413 		break;
414 	    case ORDER_EUA:    /* (from [here,there), ie: half open interval] */
415 		Ensure(2);
416 		/*
417 		 * Compiler error - msc version 4.0:
418 		 *			"expression too complicated".
419 		 */
420 		i = WhereAttrByte(BufferAddress);
421 		c = FieldAttributes(i);
422 		i = Addr3270(buffer[0], buffer[1]);
423 		if ((i < 0) || (i > HighestScreen())) {
424 		    char s_buffer[200];
425 
426 		    sprintf(s_buffer, "tn3270:  %s%d.\n\t%s%d%s%d%s\n",
427 			"Invalid 3270 order 'Erase Unprotected to Address' to address ",
428 			i,
429 			"(Screen currently set to ",
430 			NumberLines,
431 			" by ",
432 			NumberColumns,
433 			".)");
434 		    ExitString(s_buffer, 1);
435 		    /*NOTREACHED*/
436 		}
437 		do {
438 		    if (IsStartField(BufferAddress)) {
439 			c = FieldAttributes(BufferAddress);
440 		    } else if (!IsProtectedAttr(BufferAddress, c)) {
441 			AddHost(BufferAddress, 0);
442 		    }
443 		    BufferAddress = ScreenInc(BufferAddress);
444 		} while (i != BufferAddress);
445 		buffer += 2;
446 		count -= 2;
447 		break;
448 	    case ORDER_GE:
449 		Ensure(2);
450 		/* XXX Should do SOMETHING! */
451 		/* XXX buffer += 0; */
452 		/* XXX count -= 0; *//* For now, just use this character */
453 		break;
454 	    case ORDER_YALE:		/* special YALE defined order */
455 		Ensure(2);	/* need at least two characters */
456 		if (*buffer == 0x5b) {
457 		    i = OptOrder(buffer+1, count-1, control);
458 		    if (i == 0) {
459 			return(origCount-(count+1));	/* come here again */
460 		    } else {
461 			buffer += 1 + i;
462 			count  -= (1 + i);
463 		    }
464 		}
465 		break;
466 	    default:
467 		{
468 		    char s_buffer[100];
469 		    static struct orders_def unk_order
470 						= { 0, "??", "(unknown)" };
471 		    struct orders_def *porder = &unk_order;
472 		    int s_i;
473 
474 		    for (s_i = 0; s_i <= highestof(orders_def); s_i++) {
475 			if (orders_def[s_i].code == c) {
476 			    porder = &orders_def[s_i];
477 			    break;
478 			}
479 		    }
480 		    sprintf(s_buffer,
481 			"Unsupported order '%s' (%s, 0x%x) received.\n",
482 			porder->long_name, porder->short_name, c);
483 		    ExitString(s_buffer, 1);
484 		    /*NOTREACHED*/
485 		}
486 	    }
487 	    if (count < 0) {
488 		count = 0;
489 	    }
490 	} else {
491 	    /* Data comes in large clumps - take it all */
492 	    i = BufferAddress;
493 	    AddHostA(i, ebc_disp[c]);
494 	    SetHighestLowest(i);
495 	    i = ScreenInc(i);
496 	    c = *buffer;
497 	    while (count && !IsOrder(c)) {
498 		AddHostA(i, ebc_disp[c]);
499 		i = ScreenInc(i);
500 		if (i == LowestScreen()) {
501 		    SetHighestLowest(HighestScreen());
502 		}
503 		count--;
504 		buffer++;
505 		c = *buffer;
506 	    }
507 	    SetHighestLowest(i);
508 	    BufferAddress = i;
509 	}
510     }
511     if (count == 0) {
512 	if (control) {
513 #if	!defined(PURE3274)
514 	    OutputClock++;		/* time rolls on */
515 #endif	/* !defined(PURE3274) */
516 	    if (Wcc & WCC_RESTORE) {
517 #if	!defined(PURE3274)
518 		if (TransparentClock != OutputClock) {
519 		    AidByte = 0;
520 		}
521 #else	/* !defined(PURE3274) */
522 		AidByte = 0;
523 #endif	/* !defined(PURE3274) */
524 		UnLocked = 1;
525 		ResetOiaSystemLocked(&OperatorInformationArea);
526 		SetOiaModified();
527 		SetPsModified();
528 		TerminalIn();
529 	    }
530 	    if (Wcc & WCC_ALARM) {
531 		RingBell((char *)0);
532 	    }
533 	}
534 	LastWasTerminated = control;	/* state for next time */
535 	return(origCount);
536     } else {
537 	return(origCount-count);
538     }
539 }
540 
541 /*
542  * Init3270()
543  *
544  * Initialize any 3270 (controller) variables to an initial state
545  * in preparation for accepting a connection.
546  */
547 
548 void
549 Init3270()
550 {
551     int i;
552 
553     OptInit();		/* initialize mappings */
554 
555     ClearArray(Host);
556 
557     ClearArray(Orders);
558     for (i = 0; i <= highestof(orders_def); i++) {
559 	Orders[orders_def[i].code] = 1;
560     }
561 
562     DeleteAllFields();		/* Clear screen */
563     Lowest = HighestScreen()+1;
564     Highest = LowestScreen()-1;
565     CursorAddress = BufferAddress = SetBufferAddress(0,0);
566     UnLocked = 1;
567 #if	!defined(PURE3274)
568     OutputClock = 1;
569     TransparentClock = -1;
570 #endif	/* !defined(PURE3274) */
571     SetOiaReady3274(&OperatorInformationArea);
572 }
573 
574 
575 void
576 Stop3270()
577 {
578     ResetOiaReady3274(&OperatorInformationArea);
579 }
580