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