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
init_3270(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
DataToNetwork(char * buffer,int count,int done)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
inputAvailable(int signo)167 inputAvailable(int signo)
168 {
169 HaveInput = 1;
170 sigiocount++;
171 }
172
173 void
outputPurge(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
DataToTerminal(char * buffer,int count)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
Push3270(void)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
Finish3270(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
StringToTerminal(char * s)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
_putchar(int cc)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
SetIn3270(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
tn3270_ttype(void)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
settranscom(int argc,char * argv[])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