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