xref: /minix/usr.bin/telnet/tn3270.c (revision d642636d)
1 /*	$NetBSD: tn3270.c,v 1.22 2006/10/07 17:27:57 elad Exp $	*/
2 
3 /*
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)tn3270.c	8.2 (Berkeley) 5/30/95";
36 #else
37 __RCSID("$NetBSD: tn3270.c,v 1.22 2006/10/07 17:27:57 elad Exp $");
38 #endif
39 #endif /* not lint */
40 
41 #include <sys/types.h>
42 #include <sys/time.h>
43 #include <arpa/telnet.h>
44 #include <unistd.h>
45 #include <poll.h>
46 
47 #include "general.h"
48 #include "defines.h"
49 #include "ring.h"
50 #include "externs.h"
51 
52 #ifdef TN3270
53 
54 #include "../ctlr/screen.h"
55 #include "../ctlr/declare.h"
56 
57 #include "../ascii/state.h"
58 
59 #include "../general/globals.h"
60 
61 #include "../sys_curses/telextrn.h"
62 
63 int
64 	HaveInput,		/* There is input available to scan */
65 	cursesdata,		/* Do we dump curses data? */
66 	sigiocount;		/* Number of times we got a SIGIO */
67 
68 char	tline[200];
69 char	*transcom = 0;	/* transparent mode command (default: none) */
70 
71 char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
72 
73 static char	sb_terminal[] = { IAC, SB,
74 			TELOPT_TTYPE, TELQUAL_IS,
75 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
76 			IAC, SE };
77 #define	SBTERMMODEL	13
78 
79 static int
80 	Sent3270TerminalType;	/* Have we said we are a 3270? */
81 
82 #endif	/* defined(TN3270) */
83 
84 
85 #ifdef TN3270
86 void
87 init_3270(void)
88 {
89     HaveInput = 0;
90     sigiocount = 0;
91     Sent3270TerminalType = 0;
92     Ifrontp = Ibackp = Ibuf;
93     init_ctlr();		/* Initialize some things */
94     init_keyboard();
95     init_screen();
96     init_system();
97 }
98 #endif	/* defined(TN3270) */
99 
100 
101 #ifdef TN3270
102 
103 /*
104  * DataToNetwork - queue up some data to go to network.  If "done" is set,
105  * then when last byte is queued, we add on an IAC EOR sequence (so,
106  * don't call us with "done" until you want that done...)
107  *
108  * We actually do send all the data to the network buffer, since our
109  * only client needs for us to do that.
110  */
111 
112 int
113 DataToNetwork(char *buffer,	/* where the data is */
114     int  count,	/* how much to send */
115     int		  done)		/* is this the last of a logical block */
116 {
117     int loop, c;
118     int origCount;
119 
120     origCount = count;
121 
122     while (count) {
123 	/* If not enough room for EORs, IACs, etc., wait */
124 	if (NETROOM() < 6) {
125 	    struct pollfd set[1];
126 
127 	    set[0].fd = net;
128 	    set[0].events = POLLOUT;
129 	    netflush();
130 	    while (NETROOM() < 6) {
131 		(void) poll(set, 1, INFTIM);
132 		netflush();
133 	    }
134 	}
135 	c = ring_empty_count(&netoring);
136 	if (c > count) {
137 	    c = count;
138 	}
139 	loop = c;
140 	while (loop) {
141 	    if (((unsigned char)*buffer) == IAC) {
142 		break;
143 	    }
144 	    buffer++;
145 	    loop--;
146 	}
147 	if ((c = c-loop)) {
148 	    ring_supply_data(&netoring, buffer-c, c);
149 	    count -= c;
150 	}
151 	if (loop) {
152 	    NET2ADD(IAC, IAC);
153 	    count--;
154 	    buffer++;
155 	}
156     }
157 
158     if (done) {
159 	NET2ADD(IAC, EOR);
160 	netflush();		/* try to move along as quickly as ... */
161     }
162     return(origCount - count);
163 }
164 
165 
166 void
167 inputAvailable(int signo)
168 {
169     HaveInput = 1;
170     sigiocount++;
171 }
172 
173 void
174 outputPurge(void)
175 {
176     (void) ttyflush(1);
177 }
178 
179 
180 /*
181  * The following routines are places where the various tn3270
182  * routines make calls into telnet.c.
183  */
184 
185 /*
186  * DataToTerminal - queue up some data to go to terminal.
187  *
188  * Note: there are people who call us and depend on our processing
189  * *all* the data at one time (thus the poll).
190  */
191 
192 int
193 DataToTerminal(
194     char	*buffer,		/* where the data is */
195     int	count)			/* how much to send */
196 {
197     int c;
198     int origCount;
199 
200     origCount = count;
201 
202     while (count) {
203 	if (TTYROOM() == 0) {
204 	    struct pollfd set[1];
205 
206 	    set[0].fd = tout;
207 	    set[0].events = POLLOUT;
208 	    (void) ttyflush(0);
209 	    while (TTYROOM() == 0) {
210 		(void) poll(set, 1, INFTIM);
211 		(void) ttyflush(0);
212 	    }
213 	}
214 	c = TTYROOM();
215 	if (c > count) {
216 	    c = count;
217 	}
218 	ring_supply_data(&ttyoring, buffer, c);
219 	count -= c;
220 	buffer += c;
221     }
222     return(origCount);
223 }
224 
225 
226 /*
227  * Push3270 - Try to send data along the 3270 output (to screen) direction.
228  */
229 
230 int
231 Push3270(void)
232 {
233     int save = ring_full_count(&netiring);
234 
235     if (save) {
236 	if (Ifrontp+save > Ibuf+sizeof Ibuf) {
237 	    if (Ibackp != Ibuf) {
238 		memmove(Ibuf, Ibackp, Ifrontp-Ibackp);
239 		Ifrontp -= (Ibackp-Ibuf);
240 		Ibackp = Ibuf;
241 	    }
242 	}
243 	if (Ifrontp+save < Ibuf+sizeof Ibuf) {
244 	    (void)telrcv();
245 	}
246     }
247     return save != ring_full_count(&netiring);
248 }
249 
250 
251 /*
252  * Finish3270 - get the last dregs of 3270 data out to the terminal
253  *		before quitting.
254  */
255 
256 void
257 Finish3270(void)
258 {
259     while (Push3270() || !DoTerminalOutput()) {
260 	HaveInput = 0;
261 	;
262     }
263 }
264 
265 
266 /* StringToTerminal - output a null terminated string to the terminal */
267 
268 void
269 StringToTerminal(char *s)
270 {
271     int count;
272 
273     count = strlen(s);
274     if (count) {
275 	(void) DataToTerminal(s, count);	/* we know it always goes... */
276     }
277 }
278 
279 
280 /* _putchar - output a single character to the terminal.  This name is so that
281  *	curses(3x) can call us to send out data.
282  */
283 
284 int
285 _putchar(int cc)
286 {
287     char c = (char)cc;
288     if (cursesdata) {
289 	Dump('>', &c, 1);
290     }
291     if (!TTYROOM()) {
292 	(void) DataToTerminal(&c, 1);
293     } else {
294 	TTYADD(c);
295     }
296 
297     return (0);
298 }
299 
300 void
301 SetIn3270(void)
302 {
303     if (Sent3270TerminalType && my_want_state_is_will(TELOPT_BINARY)
304 		&& my_want_state_is_do(TELOPT_BINARY) && !donebinarytoggle) {
305 	if (!In3270) {
306 	    In3270 = 1;
307 	    Init3270();		/* Initialize 3270 functions */
308 	    /* initialize terminal key mapping */
309 	    InitTerminal();	/* Start terminal going */
310 	    setconnmode(0);
311 	}
312     } else {
313 	if (In3270) {
314 	    StopScreen(1);
315 	    In3270 = 0;
316 	    Stop3270();		/* Tell 3270 we aren't here anymore */
317 	    setconnmode(0);
318 	}
319     }
320 }
321 
322 /*
323  * tn3270_ttype()
324  *
325  *	Send a response to a terminal type negotiation.
326  *
327  *	Return '0' if no more responses to send; '1' if a response sent.
328  */
329 
330 int
331 tn3270_ttype(void)
332 {
333     /*
334      * Try to send a 3270 type terminal name.  Decide which one based
335      * on the format of our screen, and (in the future) color
336      * capaiblities.
337      */
338     InitTerminal();		/* Sets MaxNumberColumns, MaxNumberLines */
339     if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
340 	Sent3270TerminalType = 1;
341 	if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
342 	    MaxNumberLines = 27;
343 	    MaxNumberColumns = 132;
344 	    sb_terminal[SBTERMMODEL] = '5';
345 	} else if (MaxNumberLines >= 43) {
346 	    MaxNumberLines = 43;
347 	    MaxNumberColumns = 80;
348 	    sb_terminal[SBTERMMODEL] = '4';
349 	} else if (MaxNumberLines >= 32) {
350 	    MaxNumberLines = 32;
351 	    MaxNumberColumns = 80;
352 	    sb_terminal[SBTERMMODEL] = '3';
353 	} else {
354 	    MaxNumberLines = 24;
355 	    MaxNumberColumns = 80;
356 	    sb_terminal[SBTERMMODEL] = '2';
357 	}
358 	NumberLines = 24;		/* before we start out... */
359 	NumberColumns = 80;
360 	ScreenSize = NumberLines*NumberColumns;
361 	if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
362 	    ExitString("Programming error:  MAXSCREENSIZE too small.\n",
363 								1);
364 	    /*NOTREACHED*/
365 	}
366 	printsub('>', sb_terminal+2, sizeof sb_terminal-2);
367 	ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
368 	return 1;
369     } else {
370 	return 0;
371     }
372 }
373 
374 int
375 settranscom(int argc, char *argv[])
376 {
377 	int i;
378 
379 	if (argc == 1 && transcom) {
380 	   transcom = 0;
381 	}
382 	if (argc == 1) {
383 	   return 1;
384 	}
385 	transcom = tline;
386 	(void) strlcpy(tline, argv[1], sizeof(tline));
387 	for (i = 2; i < argc; ++i) {
388 	    (void) strlcat(tline, " ", sizeof(tline));
389 	    (void) strlcat(tline, argv[i], sizeof(tline));
390 	}
391 	return 1;
392 }
393 
394 #endif	/* defined(TN3270) */
395