xref: /original-bsd/usr.bin/telnet/tn3270.c (revision c7ce21e7)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)tn3270.c	1.12 (Berkeley) 06/29/88";
20 #endif /* not lint */
21 
22 #include <sys/types.h>
23 #include <arpa/telnet.h>
24 
25 #include "general.h"
26 
27 #include "defines.h"
28 #include "ring.h"
29 #include "externs.h"
30 #include "fdset.h"
31 
32 #if	defined(TN3270)
33 
34 #include "../ctlr/screen.h"
35 #include "../general/globals.h"
36 
37 #if	defined(unix)
38 char	tline[200];
39 char	*transcom = 0;	/* transparent mode command (default: none) */
40 #endif	/* defined(unix) */
41 
42 char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
43 
44 static char	sb_terminal[] = { IAC, SB,
45 			TELOPT_TTYPE, TELQUAL_IS,
46 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
47 			IAC, SE };
48 #define	SBTERMMODEL	13
49 
50 static int
51 	Sent3270TerminalType;	/* Have we said we are a 3270? */
52 
53 #endif	/* defined(TN3270) */
54 
55 
56 void
57 init_3270()
58 {
59 #if	defined(TN3270)
60     Sent3270TerminalType = 0;
61     Ifrontp = Ibackp = Ibuf;
62     init_ctlr();		/* Initialize some things */
63     init_keyboard();
64     init_screen();
65     init_system();
66 #endif	/* defined(TN3270) */
67 }
68 
69 
70 #if	defined(TN3270)
71 
72 /*
73  * DataToNetwork - queue up some data to go to network.  If "done" is set,
74  * then when last byte is queued, we add on an IAC EOR sequence (so,
75  * don't call us with "done" until you want that done...)
76  *
77  * We actually do send all the data to the network buffer, since our
78  * only client needs for us to do that.
79  */
80 
81 int
82 DataToNetwork(buffer, count, done)
83 register char	*buffer;	/* where the data is */
84 register int	count;		/* how much to send */
85 int		done;		/* is this the last of a logical block */
86 {
87     register int loop, c;
88     int origCount;
89 
90     origCount = count;
91 
92     while (count) {
93 	/* If not enough room for EORs, IACs, etc., wait */
94 	if (NETROOM() < 6) {
95 	    fd_set o;
96 
97 	    FD_ZERO(&o);
98 	    netflush();
99 	    while (NETROOM() < 6) {
100 		FD_SET(net, &o);
101 		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
102 						(struct timeval *) 0);
103 		netflush();
104 	    }
105 	}
106 	c = ring_empty_count(&netoring);
107 	if (c > count) {
108 	    c = count;
109 	}
110 	loop = c;
111 	while (loop) {
112 	    if (((unsigned char)*buffer) == IAC) {
113 		break;
114 	    }
115 	    buffer++;
116 	    loop--;
117 	}
118 	if ((c = c-loop)) {
119 	    ring_supply_data(&netoring, buffer-c, c);
120 	    count -= c;
121 	}
122 	if (loop) {
123 	    NET2ADD(IAC, IAC);
124 	    count--;
125 	    buffer++;
126 	}
127     }
128 
129     if (done) {
130 	NET2ADD(IAC, EOR);
131 	netflush();		/* try to move along as quickly as ... */
132     }
133     return(origCount - count);
134 }
135 
136 
137 #if	defined(unix)
138 void
139 inputAvailable()
140 {
141     HaveInput = 1;
142 }
143 #endif	/* defined(unix) */
144 
145 void
146 outputPurge()
147 {
148     ttyflush(1);
149 }
150 
151 
152 /*
153  * The following routines are places where the various tn3270
154  * routines make calls into telnet.c.
155  */
156 
157 /*
158  * DataToTerminal - queue up some data to go to terminal.
159  *
160  * Note: there are people who call us and depend on our processing
161  * *all* the data at one time (thus the select).
162  */
163 
164 int
165 DataToTerminal(buffer, count)
166 register char	*buffer;		/* where the data is */
167 register int	count;			/* how much to send */
168 {
169     register int loop, c;
170     int origCount;
171 
172     origCount = count;
173 
174     while (count) {
175 	if (TTYROOM() == 0) {
176 #if	defined(unix)
177 	    fd_set o;
178 
179 	    FD_ZERO(&o);
180 #endif	/* defined(unix) */
181 	    ttyflush();
182 	    while (TTYROOM() == 0) {
183 #if	defined(unix)
184 		FD_SET(tout, &o);
185 		(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
186 						(struct timeval *) 0);
187 #endif	/* defined(unix) */
188 		ttyflush();
189 	    }
190 	}
191 	c = TTYROOM();
192 	if (c > count) {
193 	    c = count;
194 	}
195 	ring_supply_data(&ttyoring, buffer, c);
196 	count -= c;
197 	buffer += c;
198     }
199     return(origCount);
200 }
201 
202 /* EmptyTerminal - called to make sure that the terminal buffer is empty.
203  *			Note that we consider the buffer to run all the
204  *			way to the kernel (thus the select).
205  */
206 
207 void
208 EmptyTerminal()
209 {
210 #if	defined(unix)
211     fd_set	o;
212 
213     FD_ZERO(&o);
214 #endif	/* defined(unix) */
215 
216     if (TTYBYTES() == 0) {
217 #if	defined(unix)
218 	FD_SET(tout, &o);
219 	(void) select(tout+1, (int *) 0, &o, (int *) 0,
220 			(struct timeval *) 0);	/* wait for TTLOWAT */
221 #endif	/* defined(unix) */
222     } else {
223 	while (TTYBYTES()) {
224 	    ttyflush(0);
225 #if	defined(unix)
226 	    FD_SET(tout, &o);
227 	    (void) select(tout+1, (int *) 0, &o, (int *) 0,
228 				(struct timeval *) 0);	/* wait for TTLOWAT */
229 #endif	/* defined(unix) */
230 	}
231     }
232 }
233 
234 
235 /*
236  * Push3270 - Try to send data along the 3270 output (to screen) direction.
237  */
238 
239 int
240 Push3270()
241 {
242     int save = ring_full_count(&netiring);
243 
244     if (save) {
245 	if (Ifrontp+save > Ibuf+sizeof Ibuf) {
246 	    if (Ibackp != Ibuf) {
247 		memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
248 		Ifrontp -= (Ibackp-Ibuf);
249 		Ibackp = Ibuf;
250 	    }
251 	}
252 	if (Ifrontp+save < Ibuf+sizeof Ibuf) {
253 	    telrcv();
254 	}
255     }
256     return save != ring_full_count(&netiring);
257 }
258 
259 
260 /*
261  * Finish3270 - get the last dregs of 3270 data out to the terminal
262  *		before quitting.
263  */
264 
265 void
266 Finish3270()
267 {
268     while (Push3270() || !DoTerminalOutput()) {
269 #if	defined(unix)
270 	HaveInput = 0;
271 #endif	/* defined(unix) */
272 	;
273     }
274 }
275 
276 
277 /* StringToTerminal - output a null terminated string to the terminal */
278 
279 void
280 StringToTerminal(s)
281 char *s;
282 {
283     int count;
284 
285     count = strlen(s);
286     if (count) {
287 	(void) DataToTerminal(s, count);	/* we know it always goes... */
288     }
289 }
290 
291 
292 #if	((!defined(NOT43)) || defined(PUTCHAR))
293 /* _putchar - output a single character to the terminal.  This name is so that
294  *	curses(3x) can call us to send out data.
295  */
296 
297 void
298 _putchar(c)
299 char c;
300 {
301     if (TTYBYTES()) {
302 	(void) DataToTerminal(&c, 1);
303     } else {
304 	TTYADD(c);
305     }
306 }
307 #endif	/* ((!defined(NOT43)) || defined(PUTCHAR)) */
308 
309 void
310 SetForExit()
311 {
312     setconnmode();
313     if (In3270) {
314 	Finish3270();
315     }
316     setcommandmode();
317     fflush(stdout);
318     fflush(stderr);
319     if (In3270) {
320 	StopScreen(1);
321     }
322     setconnmode();
323     setcommandmode();
324 }
325 
326 void
327 Exit(returnCode)
328 int returnCode;
329 {
330     SetForExit();
331     exit(returnCode);
332 }
333 
334 void
335 ExitString(string, returnCode)
336 char *string;
337 int returnCode;
338 {
339     SetForExit();
340     fwrite(string, 1, strlen(string), stderr);
341     exit(returnCode);
342 }
343 
344 void
345 ExitPerror(string, returnCode)
346 char *string;
347 int returnCode;
348 {
349     SetForExit();
350     perror(string);
351     exit(returnCode);
352 }
353 
354 void
355 SetIn3270()
356 {
357     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
358 			    && hisopts[TELOPT_BINARY] && !donebinarytoggle) {
359 	if (!In3270) {
360 	    In3270 = 1;
361 	    Init3270();		/* Initialize 3270 functions */
362 	    /* initialize terminal key mapping */
363 	    InitTerminal();	/* Start terminal going */
364 	    setconnmode();
365 	}
366     } else {
367 	if (In3270) {
368 	    StopScreen(1);
369 	    In3270 = 0;
370 	    Stop3270();		/* Tell 3270 we aren't here anymore */
371 	    setconnmode();
372 	}
373     }
374 }
375 
376 /*
377  * tn3270_ttype()
378  *
379  *	Send a response to a terminal type negotiation.
380  *
381  *	Return '0' if no more responses to send; '1' if a response sent.
382  */
383 
384 int
385 tn3270_ttype()
386 {
387     /*
388      * Try to send a 3270 type terminal name.  Decide which one based
389      * on the format of our screen, and (in the future) color
390      * capaiblities.
391      */
392     InitTerminal();		/* Sets MaxNumberColumns, MaxNumberLines */
393     if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
394 	Sent3270TerminalType = 1;
395 	if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
396 	    MaxNumberLines = 27;
397 	    MaxNumberColumns = 132;
398 	    sb_terminal[SBTERMMODEL] = '5';
399 	} else if (MaxNumberLines >= 43) {
400 	    MaxNumberLines = 43;
401 	    MaxNumberColumns = 80;
402 	    sb_terminal[SBTERMMODEL] = '4';
403 	} else if (MaxNumberLines >= 32) {
404 	    MaxNumberLines = 32;
405 	    MaxNumberColumns = 80;
406 	    sb_terminal[SBTERMMODEL] = '3';
407 	} else {
408 	    MaxNumberLines = 24;
409 	    MaxNumberColumns = 80;
410 	    sb_terminal[SBTERMMODEL] = '2';
411 	}
412 	NumberLines = 24;		/* before we start out... */
413 	NumberColumns = 80;
414 	ScreenSize = NumberLines*NumberColumns;
415 	if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
416 	    ExitString("Programming error:  MAXSCREENSIZE too small.\n",
417 								1);
418 	    /*NOTREACHED*/
419 	}
420 	printsub(">", sb_terminal+2, sizeof sb_terminal-2);
421 	ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
422 	return 1;
423     } else {
424 	return 0;
425     }
426 }
427 
428 #if	defined(unix)
429 settranscom(argc, argv)
430 	int argc;
431 	char *argv[];
432 {
433 	int i, len = 0;
434 
435 	if (argc == 1 && transcom) {
436 	   transcom = 0;
437 	}
438 	if (argc == 1) {
439 	   return;
440 	}
441 	for (i = 1; i < argc; ++i) {
442 	    len += 1 + strlen(argv[1]);
443 	}
444 	transcom = tline;
445 	(void) strcpy(transcom, argv[1]);
446 	for (i = 2; i < argc; ++i) {
447 	    (void) strcat(transcom, " ");
448 	    (void) strcat(transcom, argv[i]);
449 	}
450 }
451 #endif	/* defined(unix) */
452 
453 #endif	/* defined(TN3270) */
454