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