xref: /csrg-svn/usr.bin/tn3270/ctlr/outbound.c (revision 31892)
1 /*
2  *	Copyright (c) 1984-1987 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	1.22 (Berkeley) 07/17/87";
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 "../api/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     init_inbound();
86     init_oia();
87 }
88 
89 
90 FieldInc(position)
91 register int	position;		/* Position in previous field */
92 {
93     register ScreenImage *ptr;
94 
95     ptr = (ScreenImage *)memNSchr((char *)Host+position+1, ATTR_MASK,
96 			HighestScreen()-position, ATTR_MASK, sizeof Host[0]);
97     if (ptr == 0) {
98 	ptr = (ScreenImage *)memNSchr((char *)Host+LowestScreen(), ATTR_MASK,
99 			position-LowestScreen(), ATTR_MASK, sizeof Host[0]);
100 	if (ptr == 0) {
101 	    return LowestScreen();
102 	}
103     }
104     return ptr-Host;
105 }
106 
107 FieldDec(position)
108 int	position;
109 {
110     register ScreenImage *ptr;
111 
112     ptr = (ScreenImage *)memNSchr((char *)(Host+position)-1, ATTR_MASK,
113 			position-LowestScreen(), ATTR_MASK, -sizeof Host[0]);
114     if (ptr == 0) {
115 	ptr = (ScreenImage *)memNSchr((char *)Host+HighestScreen(), ATTR_MASK,
116 			HighestScreen()-position, ATTR_MASK, -sizeof Host[0]);
117 	if (ptr == 0) {
118 	    return LowestScreen();
119 	}
120     }
121     return ptr-Host;
122 }
123 
124 /* Clear3270 - called to clear the screen */
125 
126 void
127 Clear3270()
128 {
129     ClearArray(Host);
130     DeleteAllFields();		/* get rid of all fields */
131     BufferAddress = SetBufferAddress(0,0);
132     CursorAddress = SetBufferAddress(0,0);
133     Lowest = LowestScreen();
134     Highest = HighestScreen();
135 }
136 
137 /* AddHost - called to add a character to the buffer.
138  *	We use a macro in this module, since we call it so
139  *	often from loops.
140  *
141  *	NOTE: It is a macro, so don't go around using AddHost(p, *c++), or
142  *	anything similar.  (I don't define any temporary variables, again
143  *	just for the speed.)
144  */
145 void
146 AddHost(position, character)
147 int	position;
148 char	character;
149 {
150 #   define	AddHostA(p,c)					\
151     {								\
152 	if (IsStartField(p)) {					\
153 	    DeleteField(p);					\
154 	    Highest = HighestScreen();				\
155 	    Lowest = LowestScreen();				\
156 	    SetHighestLowest(p);				\
157 	}							\
158 	SetHost(p, c);						\
159     }
160 #   define	AddHost(p,c)					\
161     {								\
162 	if (c != GetHost(p)) {					\
163 	    SetHighestLowest(p);				\
164 	}							\
165 	AddHostA(p,c);						\
166     }	/* end of macro of AddHost */
167 
168     AddHost(position, character);
169 }
170 
171 /* returns the number of characters consumed */
172 int
173 DataFromNetwork(buffer, count, control)
174 register unsigned char	*buffer;		/* what the data is */
175 register int	count;				/* and how much there is */
176 int	control;				/* this buffer ended block? */
177 {
178     int origCount;
179     register int c;
180     register int i;
181     static int Command;
182     static int Wcc;
183 
184     origCount = count;
185 
186     /*
187      * If this is the start of a new data stream, then look
188      * for an op-code and (possibly) a WCC.
189      */
190     if (LastWasTerminated) {
191 
192 	if (count < 2) {
193 	    if (count == 0) {
194 		ExitString(stderr, "Short count received from host!\n", 1);
195 		return(count);
196 	    }
197 	    Command = buffer[0];
198 	    switch (Command) {		/* This had better be a read command */
199 	    case CMD_READ_MODIFIED:
200 	    case CMD_SNA_READ_MODIFIED:
201 	    case CMD_SNA_READ_MODIFIED_ALL:
202 		SetOiaOnlineA(&OperatorInformationArea);
203 		SetOiaModified();
204 		DoReadModified(Command);
205 		break;
206 	    case CMD_READ_BUFFER:
207 	    case CMD_SNA_READ_BUFFER:
208 		SetOiaOnlineA(&OperatorInformationArea);
209 		SetOiaModified();
210 		DoReadBuffer();
211 		break;
212 	    default:
213 		{
214 		    char buffer[100];
215 
216 		    sprintf(buffer,
217 			"Unexpected read command code 0x%x received.\n",
218 								    Command);
219 		    ExitString(stderr, buffer, 1);
220 		    break;
221 		}
222 	    }
223 	    return(1);			/* We consumed everything */
224 	}
225 	Command = buffer[0];
226 	Wcc = buffer[1];
227 	if (Wcc & WCC_RESET_MDT) {
228 	    i = c = WhereAttrByte(LowestScreen());
229 	    do {
230 		if (HasMdt(i)) {
231 		    TurnOffMdt(i);
232 		}
233 		i = FieldInc(i);
234 	    } while (i != c);
235 	}
236 
237 	switch (Command) {
238 	case CMD_ERASE_WRITE:
239 	case CMD_ERASE_WRITE_ALTERNATE:
240 	case CMD_SNA_ERASE_WRITE:
241 	case CMD_SNA_ERASE_WRITE_ALTERNATE:
242 	    {
243 		int newlines, newcolumns;
244 
245 		SetOiaOnlineA(&OperatorInformationArea);
246 		ResetOiaTWait(&OperatorInformationArea);
247 		SetOiaModified();
248 		if ((Command == CMD_ERASE_WRITE)
249 				|| (Command == CMD_SNA_ERASE_WRITE)) {
250 		    newlines = 24;
251 		    newcolumns = 80;
252 		} else {
253 		    newlines = MaxNumberLines;
254 		    newcolumns = MaxNumberColumns;
255 		}
256 		if ((newlines != NumberLines)
257 				|| (newcolumns != NumberColumns)) {
258 			/*
259 			 * The LocalClearScreen() is really for when we
260 			 * are going from a larger screen to a smaller
261 			 * screen, and we need to clear off the stuff
262 			 * at the end of the lines, or the lines at
263 			 * the end of the screen.
264 			 */
265 		    LocalClearScreen();
266 		    NumberLines = newlines;
267 		    NumberColumns = newcolumns;
268 		    ScreenSize = NumberLines * NumberColumns;
269 		}
270 		Clear3270();
271 #if	!defined(PURE3274)
272 		if (TransparentClock == OutputClock) {
273 		    TransStop();
274 		}
275 #endif	/* !defined(PURE3274) */
276 		break;
277 	    }
278 
279 	case CMD_ERASE_ALL_UNPROTECTED:
280 	case CMD_SNA_ERASE_ALL_UNPROTECTED:
281 	    SetOiaOnlineA(&OperatorInformationArea);
282 	    ResetOiaTWait(&OperatorInformationArea);
283 	    SetOiaModified();
284 	    CursorAddress = HighestScreen()+1;
285 	    for (i = LowestScreen(); i <= HighestScreen(); i = ScreenInc(i)) {
286 		if (IsUnProtected(i)) {
287 		    if (CursorAddress > i) {
288 			CursorAddress = i;
289 		    }
290 		    AddHost(i, '\0');
291 		}
292 		if (HasMdt(i)) {
293 		    TurnOffMdt(i);
294 		}
295 	    }
296 	    if (CursorAddress == HighestScreen()+1) {
297 		CursorAddress = SetBufferAddress(0,0);
298 	    }
299 	    UnLocked = 1;
300 	    AidByte = 0;
301 	    ResetOiaSystemLocked(&OperatorInformationArea);
302 	    SetOiaModified();
303 	    TerminalIn();
304 	    break;
305 	case CMD_WRITE:
306 	case CMD_SNA_WRITE:
307 	    SetOiaOnlineA(&OperatorInformationArea);
308 	    ResetOiaTWait(&OperatorInformationArea);
309 	    SetOiaModified();
310 	    break;
311 	default:
312 	    {
313 		char buffer[100];
314 
315 		sprintf(buffer,
316 			"Unexpected write command code 0x%x received.\n",
317 								Command);
318 		ExitString(stderr, buffer, 1);
319 		break;
320 	    }
321 	}
322 
323 	count -= 2;			/* strip off command and wcc */
324 	buffer += 2;
325 
326     } else {
327 #if	!defined(PURE3274)
328 	if (TransparentClock == OutputClock) {
329 	    TransOut(buffer, count, -1, control);
330 	    count = 0;
331 	}
332 #endif	/* !defined(PURE3274) */
333     }
334     LastWasTerminated = 0;		/* then, reset at end... */
335 
336     while (count) {
337 	count--;
338 	c = *buffer++;
339 	if (IsOrder(c)) {
340 	    /* handle an order */
341 	    switch (c) {
342 #		define Ensure(x)	if (count < x) { \
343 					    if (!control) { \
344 						return(origCount-(count+1)); \
345 					    } else { \
346 						/* XXX - should not occur */ \
347 						count = 0; \
348 						break; \
349 					    } \
350 					}
351 	    case ORDER_SF:
352 		Ensure(1);
353 		c = *buffer++;
354 		count--;
355 		if ( ! (IsStartField(BufferAddress) &&
356 					FieldAttributes(BufferAddress) == c)) {
357 		    SetHighestLowest(BufferAddress);
358 		    NewField(BufferAddress,c);
359 		}
360 		BufferAddress = ScreenInc(BufferAddress);
361 		break;
362 	    case ORDER_SBA:
363 		Ensure(2);
364 		i = buffer[0];
365 		c = buffer[1];
366 #if	!defined(PURE3274)
367 		/* Check for transparent write */
368 		if ((i == 0) && ((c == 0) || (c == 1) || (c == 5))) {
369 		    TransparentClock = OutputClock+1;
370 		    TransOut(buffer+2, count-2, c, control);
371 		    buffer += count;
372 		    count -= count;
373 		    break;
374 		}
375 #endif	/* !defined(PURE3274) */
376 		BufferAddress = Addr3270(i, c);
377 		buffer += 2;
378 		count -= 2;
379 		break;
380 	    case ORDER_IC:
381 		CursorAddress = BufferAddress;
382 		break;
383 	    /*
384 	     * XXX - PT is supposed to null fill the screen buffer
385 	     * under certain draconian conditions.
386 	     */
387 	    case ORDER_PT:
388 		i = BufferAddress;
389 		do {
390 		    if (IsStartField(i)) {
391 			if (!IsProtected(ScreenInc(i))) {
392 			    break;
393 			}
394 		    }
395 		    i = ScreenInc(i);
396 		} while (i != HighestScreen());
397 		BufferAddress = ScreenInc(i);
398 		break;
399 	    case ORDER_RA:
400 		Ensure(3);
401 		i = Addr3270(buffer[0], buffer[1]);
402 		c = buffer[2];
403 		if (c == ORDER_GE) {
404 		    Ensure(4);
405 		    c = buffer[3];
406 		    buffer += 4;
407 		    count -= 4;
408 		} else {
409 		    buffer += 3;
410 		    count -= 3;
411 		}
412 		do {
413 		    AddHost(BufferAddress, ebc_disp[c]);
414 		    BufferAddress = ScreenInc(BufferAddress);
415 		} while (BufferAddress != i);
416 		break;
417 	    case ORDER_EUA:    /* (from [here,there), ie: half open interval] */
418 		Ensure(2);
419 		/*
420 		 * Compiler error - msc version 4.0:
421 		 *			"expression too complicated".
422 		 */
423 		i = WhereAttrByte(BufferAddress);
424 		c = FieldAttributes(i);
425 		for (i = Addr3270(buffer[0], buffer[1]); i != BufferAddress;
426 				BufferAddress = ScreenInc(BufferAddress)) {
427 		    if (IsStartField(BufferAddress)) {
428 			c = FieldAttributes(BufferAddress);
429 		    } else if (!IsProtectedAttr(BufferAddress, c)) {
430 			AddHost(BufferAddress, 0);
431 		    }
432 		}
433 		buffer += 2;
434 		count -= 2;
435 		break;
436 	    case ORDER_GE:
437 		Ensure(2);
438 		/* XXX Should do SOMETHING! */
439 		buffer += 0;
440 		count -= 0;		/* For now, just use this character */
441 		break;
442 	    case ORDER_YALE:		/* special YALE defined order */
443 		Ensure(2);	/* need at least two characters */
444 		if (*buffer == 0x5b) {
445 		    i = OptOrder(buffer+1, count-1, control);
446 		    if (i == 0) {
447 			return(origCount-(count+1));	/* come here again */
448 		    } else {
449 			buffer += 1 + i;
450 			count  -= (1 + i);
451 		    }
452 		}
453 		break;
454 	    default:
455 		{
456 		    char buffer[100];
457 		    static struct orders_def unk_order
458 						= { 0, "??", "(unknown)" };
459 		    struct orders_def *porder = &unk_order;
460 		    int i;
461 
462 		    for (i = 0; i <= highestof(orders_def); i++) {
463 			if (orders_def[i].code == c) {
464 			    porder = &orders_def[i];
465 			    break;
466 			}
467 		    }
468 		    sprintf(buffer,
469 			"Unsupported order '%s' (%s, 0x%x) received.\n",
470 			porder->long_name, porder->short_name, c);
471 		    ExitString(stderr, buffer, 1);
472 		    /*NOTREACHED*/
473 		}
474 	    }
475 	    if (count < 0) {
476 		count = 0;
477 	    }
478 	} else {
479 	    /* Data comes in large clumps - take it all */
480 	    i = BufferAddress;
481 	    AddHostA(i, ebc_disp[c]);
482 	    SetHighestLowest(i);
483 	    i = ScreenInc(i);
484 	    c = *buffer;
485 	    while (count && !IsOrder(c)) {
486 		AddHostA(i, ebc_disp[c]);
487 		i = ScreenInc(i);
488 		if (i == LowestScreen()) {
489 		    SetHighestLowest(HighestScreen());
490 		}
491 		count--;
492 		buffer++;
493 		c = *buffer;
494 	    }
495 	    SetHighestLowest(i);
496 	    BufferAddress = i;
497 	}
498     }
499     if (count == 0) {
500 	if (control) {
501 #if	!defined(PURE3274)
502 	    OutputClock++;		/* time rolls on */
503 #endif	/* !defined(PURE3274) */
504 	    if (Wcc & WCC_RESTORE) {
505 #if	!defined(PURE3274)
506 		if (TransparentClock != OutputClock) {
507 		    AidByte = 0;
508 		}
509 #else	/* !defined(PURE3274) */
510 		AidByte = 0;
511 #endif	/* !defined(PURE3274) */
512 		UnLocked = 1;
513 		ResetOiaSystemLocked(&OperatorInformationArea);
514 		SetOiaModified();
515 		SetPsModified();
516 		TerminalIn();
517 	    }
518 	    if (Wcc & WCC_ALARM) {
519 		RingBell(0);
520 	    }
521 	}
522 	LastWasTerminated = control;	/* state for next time */
523 	return(origCount);
524     } else {
525 	return(origCount-count);
526     }
527 }
528 
529 /*
530  * Init3270()
531  *
532  * Initialize any 3270 (controller) variables to an initial state
533  * in preparation for accepting a connection.
534  */
535 
536 void
537 Init3270()
538 {
539     int i;
540 
541     OptInit();		/* initialize mappings */
542 
543     ClearArray(Host);
544 
545     ClearArray(Orders);
546     for (i = 0; i <= highestof(orders_def); i++) {
547 	Orders[orders_def[i].code] = 1;
548     }
549 
550     DeleteAllFields();		/* Clear screen */
551     Lowest = HighestScreen()+1;
552     Highest = LowestScreen()-1;
553     CursorAddress = BufferAddress = SetBufferAddress(0,0);
554     UnLocked = 1;
555 #if	!defined(PURE3274)
556     OutputClock = 1;
557     TransparentClock = -1;
558 #endif	/* !defined(PURE3274) */
559     SetOiaReady3274(&OperatorInformationArea);
560 }
561 
562 
563 void
564 Stop3270()
565 {
566     ResetOiaReady3274(&OperatorInformationArea);
567 }
568