Commit | Line | Data |
---|---|---|
897ce52e KB |
1 | /* |
2 | * Copyright (c) 1988 Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
cb956e54 | 5 | * %sccs.include.redist.c% |
897ce52e KB |
6 | */ |
7 | ||
8 | #ifndef lint | |
18773698 | 9 | static char sccsid[] = "@(#)tn3270.c 5.1 (Berkeley) %G%"; |
897ce52e KB |
10 | #endif /* not lint */ |
11 | ||
476b1e3a GM |
12 | #include <sys/types.h> |
13 | #include <arpa/telnet.h> | |
14 | ||
2dde2af0 GM |
15 | #include "general.h" |
16 | ||
476b1e3a GM |
17 | #include "defines.h" |
18 | #include "ring.h" | |
19 | #include "externs.h" | |
807a3a7d GM |
20 | #include "fdset.h" |
21 | ||
b6a8714b | 22 | #if defined(TN3270) |
b6a8714b | 23 | |
476b1e3a GM |
24 | #include "../ctlr/screen.h" |
25 | #include "../general/globals.h" | |
b6a8714b | 26 | |
0ea35455 GM |
27 | #include "../telextrn.h" |
28 | #include "../ctlr/externs.h" | |
29 | ||
476b1e3a | 30 | #if defined(unix) |
4127eb64 GM |
31 | int |
32 | HaveInput, /* There is input available to scan */ | |
40cc3fc2 | 33 | cursesdata, /* Do we dump curses data? */ |
4127eb64 GM |
34 | sigiocount; /* Number of times we got a SIGIO */ |
35 | ||
476b1e3a GM |
36 | char tline[200]; |
37 | char *transcom = 0; /* transparent mode command (default: none) */ | |
38 | #endif /* defined(unix) */ | |
b307f09e | 39 | |
476b1e3a | 40 | char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; |
b307f09e GM |
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 | ||
476b1e3a | 51 | #endif /* defined(TN3270) */ |
b307f09e | 52 | |
e571aa72 | 53 | |
476b1e3a | 54 | void |
66c4b72a | 55 | init_3270() |
476b1e3a GM |
56 | { |
57 | #if defined(TN3270) | |
4127eb64 GM |
58 | #if defined(unix) |
59 | HaveInput = 0; | |
60 | sigiocount = 0; | |
61 | #endif /* defined(unix) */ | |
476b1e3a GM |
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) */ | |
e571aa72 | 69 | } |
476b1e3a GM |
70 | |
71 | \f | |
72 | #if defined(TN3270) | |
e571aa72 | 73 | |
b6a8714b GM |
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 | { | |
476b1e3a | 89 | register int loop, c; |
b6a8714b | 90 | int origCount; |
b6a8714b GM |
91 | |
92 | origCount = count; | |
b6a8714b GM |
93 | |
94 | while (count) { | |
66c4b72a | 95 | /* If not enough room for EORs, IACs, etc., wait */ |
476b1e3a GM |
96 | if (NETROOM() < 6) { |
97 | fd_set o; | |
98 | ||
99 | FD_ZERO(&o); | |
b6a8714b | 100 | netflush(); |
476b1e3a | 101 | while (NETROOM() < 6) { |
b6a8714b GM |
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 | } | |
66c4b72a GM |
108 | c = ring_empty_count(&netoring); |
109 | if (c > count) { | |
110 | c = count; | |
111 | } | |
112 | loop = c; | |
476b1e3a | 113 | while (loop) { |
5dc973da | 114 | if (((unsigned char)*buffer) == IAC) { |
476b1e3a GM |
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--; | |
66c4b72a | 127 | buffer++; |
b6a8714b GM |
128 | } |
129 | } | |
130 | ||
476b1e3a | 131 | if (done) { |
66c4b72a | 132 | NET2ADD(IAC, EOR); |
b6a8714b GM |
133 | netflush(); /* try to move along as quickly as ... */ |
134 | } | |
135 | return(origCount - count); | |
136 | } | |
137 | ||
138 | ||
139 | #if defined(unix) | |
476b1e3a | 140 | void |
b6a8714b GM |
141 | inputAvailable() |
142 | { | |
143 | HaveInput = 1; | |
4127eb64 | 144 | sigiocount++; |
b6a8714b GM |
145 | } |
146 | #endif /* defined(unix) */ | |
147 | ||
148 | void | |
149 | outputPurge() | |
150 | { | |
4a8a7128 | 151 | (void) ttyflush(1); |
b6a8714b GM |
152 | } |
153 | ||
154 | ||
155 | /* | |
156 | * The following routines are places where the various tn3270 | |
157 | * routines make calls into telnet.c. | |
158 | */ | |
159 | ||
66c4b72a GM |
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 | */ | |
b6a8714b GM |
166 | |
167 | int | |
168 | DataToTerminal(buffer, count) | |
169 | register char *buffer; /* where the data is */ | |
170 | register int count; /* how much to send */ | |
171 | { | |
0ea35455 | 172 | register int c; |
b6a8714b | 173 | int origCount; |
b6a8714b | 174 | |
b6a8714b GM |
175 | origCount = count; |
176 | ||
177 | while (count) { | |
476b1e3a GM |
178 | if (TTYROOM() == 0) { |
179 | #if defined(unix) | |
180 | fd_set o; | |
181 | ||
182 | FD_ZERO(&o); | |
183 | #endif /* defined(unix) */ | |
4a8a7128 | 184 | (void) ttyflush(0); |
476b1e3a | 185 | while (TTYROOM() == 0) { |
b6a8714b GM |
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) */ | |
4a8a7128 | 191 | (void) ttyflush(0); |
b6a8714b GM |
192 | } |
193 | } | |
66c4b72a GM |
194 | c = TTYROOM(); |
195 | if (c > count) { | |
196 | c = count; | |
476b1e3a | 197 | } |
66c4b72a GM |
198 | ring_supply_data(&ttyoring, buffer, c); |
199 | count -= c; | |
200 | buffer += c; | |
b6a8714b | 201 | } |
66c4b72a | 202 | return(origCount); |
b6a8714b | 203 | } |
b6a8714b GM |
204 | \f |
205 | ||
206 | /* | |
207 | * Push3270 - Try to send data along the 3270 output (to screen) direction. | |
208 | */ | |
209 | ||
476b1e3a | 210 | int |
b6a8714b GM |
211 | Push3270() |
212 | { | |
476b1e3a | 213 | int save = ring_full_count(&netiring); |
b6a8714b | 214 | |
476b1e3a GM |
215 | if (save) { |
216 | if (Ifrontp+save > Ibuf+sizeof Ibuf) { | |
b6a8714b GM |
217 | if (Ibackp != Ibuf) { |
218 | memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); | |
219 | Ifrontp -= (Ibackp-Ibuf); | |
220 | Ibackp = Ibuf; | |
221 | } | |
222 | } | |
476b1e3a | 223 | if (Ifrontp+save < Ibuf+sizeof Ibuf) { |
4a8a7128 | 224 | (void)telrcv(); |
b6a8714b GM |
225 | } |
226 | } | |
476b1e3a | 227 | return save != ring_full_count(&netiring); |
b6a8714b GM |
228 | } |
229 | ||
230 | ||
231 | /* | |
232 | * Finish3270 - get the last dregs of 3270 data out to the terminal | |
233 | * before quitting. | |
234 | */ | |
235 | ||
476b1e3a | 236 | void |
b6a8714b GM |
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 | { | |
b5e56c6f GM |
272 | #if defined(sun) /* SunOS 4.0 bug */ |
273 | c &= 0x7f; | |
274 | #endif /* defined(sun) */ | |
40cc3fc2 GM |
275 | if (cursesdata) { |
276 | Dump('>', &c, 1); | |
277 | } | |
4127eb64 | 278 | if (!TTYROOM()) { |
b6a8714b GM |
279 | (void) DataToTerminal(&c, 1); |
280 | } else { | |
476b1e3a | 281 | TTYADD(c); |
b6a8714b GM |
282 | } |
283 | } | |
284 | #endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */ | |
285 | ||
b307f09e GM |
286 | void |
287 | SetIn3270() | |
288 | { | |
6055a9f6 PB |
289 | if (Sent3270TerminalType && my_want_state_is_will(TELOPT_BINARY) |
290 | && my_want_state_is_do(TELOPT_BINARY) && !donebinarytoggle) { | |
b307f09e GM |
291 | if (!In3270) { |
292 | In3270 = 1; | |
293 | Init3270(); /* Initialize 3270 functions */ | |
294 | /* initialize terminal key mapping */ | |
295 | InitTerminal(); /* Start terminal going */ | |
6055a9f6 | 296 | setconnmode(0); |
b307f09e GM |
297 | } |
298 | } else { | |
299 | if (In3270) { | |
300 | StopScreen(1); | |
301 | In3270 = 0; | |
302 | Stop3270(); /* Tell 3270 we aren't here anymore */ | |
6055a9f6 | 303 | setconnmode(0); |
b307f09e GM |
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 | } | |
6055a9f6 | 352 | printsub('>', sb_terminal+2, sizeof sb_terminal-2); |
b307f09e GM |
353 | ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal); |
354 | return 1; | |
355 | } else { | |
356 | return 0; | |
357 | } | |
358 | } | |
476b1e3a GM |
359 | |
360 | #if defined(unix) | |
361 | settranscom(argc, argv) | |
362 | int argc; | |
363 | char *argv[]; | |
364 | { | |
0ea35455 | 365 | int i; |
476b1e3a GM |
366 | |
367 | if (argc == 1 && transcom) { | |
368 | transcom = 0; | |
369 | } | |
370 | if (argc == 1) { | |
371 | return; | |
372 | } | |
476b1e3a GM |
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 | ||
b6a8714b | 382 | #endif /* defined(TN3270) */ |