xref: /original-bsd/usr.bin/telnet/tn3270.c (revision e9b82df0)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)tn3270.c	1.20 (Berkeley) 06/01/90";
10 #endif /* not lint */
11 
12 #include <sys/types.h>
13 #include <arpa/telnet.h>
14 
15 #include "general.h"
16 
17 #include "defines.h"
18 #include "ring.h"
19 #include "externs.h"
20 #include "fdset.h"
21 
22 #if	defined(TN3270)
23 
24 #include "../ctlr/screen.h"
25 #include "../general/globals.h"
26 
27 #include "../telextrn.h"
28 #include "../ctlr/externs.h"
29 
30 #if	defined(unix)
31 int
32 	HaveInput,		/* There is input available to scan */
33 	cursesdata,		/* Do we dump curses data? */
34 	sigiocount;		/* Number of times we got a SIGIO */
35 
36 char	tline[200];
37 char	*transcom = 0;	/* transparent mode command (default: none) */
38 #endif	/* defined(unix) */
39 
40 char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
41 
42 static char	sb_terminal[] = { IAC, SB,
43 			TELOPT_TTYPE, TELQUAL_IS,
44 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
45 			IAC, SE };
46 #define	SBTERMMODEL	13
47 
48 static int
49 	Sent3270TerminalType;	/* Have we said we are a 3270? */
50 
51 #endif	/* defined(TN3270) */
52 
53 
54 void
55 init_3270()
56 {
57 #if	defined(TN3270)
58 #if	defined(unix)
59     HaveInput = 0;
60     sigiocount = 0;
61 #endif	/* defined(unix) */
62     Sent3270TerminalType = 0;
63     Ifrontp = Ibackp = Ibuf;
64     init_ctlr();		/* Initialize some things */
65     init_keyboard();
66     init_screen();
67     init_system();
68 #endif	/* defined(TN3270) */
69 }
70 
71 
72 #if	defined(TN3270)
73 
74 /*
75  * DataToNetwork - queue up some data to go to network.  If "done" is set,
76  * then when last byte is queued, we add on an IAC EOR sequence (so,
77  * don't call us with "done" until you want that done...)
78  *
79  * We actually do send all the data to the network buffer, since our
80  * only client needs for us to do that.
81  */
82 
83 int
84 DataToNetwork(buffer, count, done)
85 register char	*buffer;	/* where the data is */
86 register int	count;		/* how much to send */
87 int		done;		/* is this the last of a logical block */
88 {
89     register int loop, c;
90     int origCount;
91 
92     origCount = count;
93 
94     while (count) {
95 	/* If not enough room for EORs, IACs, etc., wait */
96 	if (NETROOM() < 6) {
97 	    fd_set o;
98 
99 	    FD_ZERO(&o);
100 	    netflush();
101 	    while (NETROOM() < 6) {
102 		FD_SET(net, &o);
103 		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
104 						(struct timeval *) 0);
105 		netflush();
106 	    }
107 	}
108 	c = ring_empty_count(&netoring);
109 	if (c > count) {
110 	    c = count;
111 	}
112 	loop = c;
113 	while (loop) {
114 	    if (((unsigned char)*buffer) == IAC) {
115 		break;
116 	    }
117 	    buffer++;
118 	    loop--;
119 	}
120 	if ((c = c-loop)) {
121 	    ring_supply_data(&netoring, buffer-c, c);
122 	    count -= c;
123 	}
124 	if (loop) {
125 	    NET2ADD(IAC, IAC);
126 	    count--;
127 	    buffer++;
128 	}
129     }
130 
131     if (done) {
132 	NET2ADD(IAC, EOR);
133 	netflush();		/* try to move along as quickly as ... */
134     }
135     return(origCount - count);
136 }
137 
138 
139 #if	defined(unix)
140 void
141 inputAvailable()
142 {
143     HaveInput = 1;
144     sigiocount++;
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 
206 /*
207  * Push3270 - Try to send data along the 3270 output (to screen) direction.
208  */
209 
210 int
211 Push3270()
212 {
213     int save = ring_full_count(&netiring);
214 
215     if (save) {
216 	if (Ifrontp+save > Ibuf+sizeof Ibuf) {
217 	    if (Ibackp != Ibuf) {
218 		memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
219 		Ifrontp -= (Ibackp-Ibuf);
220 		Ibackp = Ibuf;
221 	    }
222 	}
223 	if (Ifrontp+save < Ibuf+sizeof Ibuf) {
224 	    telrcv();
225 	}
226     }
227     return save != ring_full_count(&netiring);
228 }
229 
230 
231 /*
232  * Finish3270 - get the last dregs of 3270 data out to the terminal
233  *		before quitting.
234  */
235 
236 void
237 Finish3270()
238 {
239     while (Push3270() || !DoTerminalOutput()) {
240 #if	defined(unix)
241 	HaveInput = 0;
242 #endif	/* defined(unix) */
243 	;
244     }
245 }
246 
247 
248 /* StringToTerminal - output a null terminated string to the terminal */
249 
250 void
251 StringToTerminal(s)
252 char *s;
253 {
254     int count;
255 
256     count = strlen(s);
257     if (count) {
258 	(void) DataToTerminal(s, count);	/* we know it always goes... */
259     }
260 }
261 
262 
263 #if	((!defined(NOT43)) || defined(PUTCHAR))
264 /* _putchar - output a single character to the terminal.  This name is so that
265  *	curses(3x) can call us to send out data.
266  */
267 
268 void
269 _putchar(c)
270 char c;
271 {
272 #if	defined(sun)		/* SunOS 4.0 bug */
273     c &= 0x7f;
274 #endif	/* defined(sun) */
275     if (cursesdata) {
276 	Dump('>', &c, 1);
277     }
278     if (!TTYROOM()) {
279 	(void) DataToTerminal(&c, 1);
280     } else {
281 	TTYADD(c);
282     }
283 }
284 #endif	/* ((!defined(NOT43)) || defined(PUTCHAR)) */
285 
286 void
287 SetIn3270()
288 {
289     if (Sent3270TerminalType && my_want_state_is_will(TELOPT_BINARY)
290 		&& my_want_state_is_do(TELOPT_BINARY) && !donebinarytoggle) {
291 	if (!In3270) {
292 	    In3270 = 1;
293 	    Init3270();		/* Initialize 3270 functions */
294 	    /* initialize terminal key mapping */
295 	    InitTerminal();	/* Start terminal going */
296 	    setconnmode(0);
297 	}
298     } else {
299 	if (In3270) {
300 	    StopScreen(1);
301 	    In3270 = 0;
302 	    Stop3270();		/* Tell 3270 we aren't here anymore */
303 	    setconnmode(0);
304 	}
305     }
306 }
307 
308 /*
309  * tn3270_ttype()
310  *
311  *	Send a response to a terminal type negotiation.
312  *
313  *	Return '0' if no more responses to send; '1' if a response sent.
314  */
315 
316 int
317 tn3270_ttype()
318 {
319     /*
320      * Try to send a 3270 type terminal name.  Decide which one based
321      * on the format of our screen, and (in the future) color
322      * capaiblities.
323      */
324     InitTerminal();		/* Sets MaxNumberColumns, MaxNumberLines */
325     if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
326 	Sent3270TerminalType = 1;
327 	if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
328 	    MaxNumberLines = 27;
329 	    MaxNumberColumns = 132;
330 	    sb_terminal[SBTERMMODEL] = '5';
331 	} else if (MaxNumberLines >= 43) {
332 	    MaxNumberLines = 43;
333 	    MaxNumberColumns = 80;
334 	    sb_terminal[SBTERMMODEL] = '4';
335 	} else if (MaxNumberLines >= 32) {
336 	    MaxNumberLines = 32;
337 	    MaxNumberColumns = 80;
338 	    sb_terminal[SBTERMMODEL] = '3';
339 	} else {
340 	    MaxNumberLines = 24;
341 	    MaxNumberColumns = 80;
342 	    sb_terminal[SBTERMMODEL] = '2';
343 	}
344 	NumberLines = 24;		/* before we start out... */
345 	NumberColumns = 80;
346 	ScreenSize = NumberLines*NumberColumns;
347 	if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
348 	    ExitString("Programming error:  MAXSCREENSIZE too small.\n",
349 								1);
350 	    /*NOTREACHED*/
351 	}
352 	printsub('>', sb_terminal+2, sizeof sb_terminal-2);
353 	ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
354 	return 1;
355     } else {
356 	return 0;
357     }
358 }
359 
360 #if	defined(unix)
361 settranscom(argc, argv)
362 	int argc;
363 	char *argv[];
364 {
365 	int i;
366 
367 	if (argc == 1 && transcom) {
368 	   transcom = 0;
369 	}
370 	if (argc == 1) {
371 	   return;
372 	}
373 	transcom = tline;
374 	(void) strcpy(transcom, argv[1]);
375 	for (i = 2; i < argc; ++i) {
376 	    (void) strcat(transcom, " ");
377 	    (void) strcat(transcom, argv[i]);
378 	}
379 }
380 #endif	/* defined(unix) */
381 
382 #endif	/* defined(TN3270) */
383