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