Commit | Line | Data |
---|---|---|
897ce52e KB |
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 | |
b36fc510 KB |
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. | |
897ce52e KB |
16 | */ |
17 | ||
18 | #ifndef lint | |
b36fc510 | 19 | static char sccsid[] = "@(#)tn3270.c 1.12 (Berkeley) %G%"; |
897ce52e KB |
20 | #endif /* not lint */ |
21 | ||
476b1e3a GM |
22 | #include <sys/types.h> |
23 | #include <arpa/telnet.h> | |
24 | ||
2dde2af0 GM |
25 | #include "general.h" |
26 | ||
476b1e3a GM |
27 | #include "defines.h" |
28 | #include "ring.h" | |
29 | #include "externs.h" | |
807a3a7d GM |
30 | #include "fdset.h" |
31 | ||
b6a8714b | 32 | #if defined(TN3270) |
b6a8714b | 33 | |
476b1e3a GM |
34 | #include "../ctlr/screen.h" |
35 | #include "../general/globals.h" | |
b6a8714b | 36 | |
476b1e3a GM |
37 | #if defined(unix) |
38 | char tline[200]; | |
39 | char *transcom = 0; /* transparent mode command (default: none) */ | |
40 | #endif /* defined(unix) */ | |
b307f09e | 41 | |
476b1e3a | 42 | char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; |
b307f09e GM |
43 | |
44 | static char sb_terminal[] = { IAC, SB, | |
45 | TELOPT_TTYPE, TELQUAL_IS, | |
46 | 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', | |
47 | IAC, SE }; | |
48 | #define SBTERMMODEL 13 | |
49 | ||
50 | static int | |
51 | Sent3270TerminalType; /* Have we said we are a 3270? */ | |
52 | ||
476b1e3a | 53 | #endif /* defined(TN3270) */ |
b307f09e | 54 | |
e571aa72 | 55 | |
476b1e3a | 56 | void |
66c4b72a | 57 | init_3270() |
476b1e3a GM |
58 | { |
59 | #if defined(TN3270) | |
60 | Sent3270TerminalType = 0; | |
61 | Ifrontp = Ibackp = Ibuf; | |
62 | init_ctlr(); /* Initialize some things */ | |
63 | init_keyboard(); | |
64 | init_screen(); | |
65 | init_system(); | |
66 | #endif /* defined(TN3270) */ | |
e571aa72 | 67 | } |
476b1e3a GM |
68 | |
69 | \f | |
70 | #if defined(TN3270) | |
e571aa72 | 71 | |
b6a8714b GM |
72 | /* |
73 | * DataToNetwork - queue up some data to go to network. If "done" is set, | |
74 | * then when last byte is queued, we add on an IAC EOR sequence (so, | |
75 | * don't call us with "done" until you want that done...) | |
76 | * | |
77 | * We actually do send all the data to the network buffer, since our | |
78 | * only client needs for us to do that. | |
79 | */ | |
80 | ||
81 | int | |
82 | DataToNetwork(buffer, count, done) | |
83 | register char *buffer; /* where the data is */ | |
84 | register int count; /* how much to send */ | |
85 | int done; /* is this the last of a logical block */ | |
86 | { | |
476b1e3a | 87 | register int loop, c; |
b6a8714b | 88 | int origCount; |
b6a8714b GM |
89 | |
90 | origCount = count; | |
b6a8714b GM |
91 | |
92 | while (count) { | |
66c4b72a | 93 | /* If not enough room for EORs, IACs, etc., wait */ |
476b1e3a GM |
94 | if (NETROOM() < 6) { |
95 | fd_set o; | |
96 | ||
97 | FD_ZERO(&o); | |
b6a8714b | 98 | netflush(); |
476b1e3a | 99 | while (NETROOM() < 6) { |
b6a8714b GM |
100 | FD_SET(net, &o); |
101 | (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, | |
102 | (struct timeval *) 0); | |
103 | netflush(); | |
104 | } | |
105 | } | |
66c4b72a GM |
106 | c = ring_empty_count(&netoring); |
107 | if (c > count) { | |
108 | c = count; | |
109 | } | |
110 | loop = c; | |
476b1e3a | 111 | while (loop) { |
5dc973da | 112 | if (((unsigned char)*buffer) == IAC) { |
476b1e3a GM |
113 | break; |
114 | } | |
115 | buffer++; | |
116 | loop--; | |
117 | } | |
118 | if ((c = c-loop)) { | |
119 | ring_supply_data(&netoring, buffer-c, c); | |
120 | count -= c; | |
121 | } | |
122 | if (loop) { | |
123 | NET2ADD(IAC, IAC); | |
124 | count--; | |
66c4b72a | 125 | buffer++; |
b6a8714b GM |
126 | } |
127 | } | |
128 | ||
476b1e3a | 129 | if (done) { |
66c4b72a | 130 | NET2ADD(IAC, EOR); |
b6a8714b GM |
131 | netflush(); /* try to move along as quickly as ... */ |
132 | } | |
133 | return(origCount - count); | |
134 | } | |
135 | ||
136 | ||
137 | #if defined(unix) | |
476b1e3a | 138 | void |
b6a8714b GM |
139 | inputAvailable() |
140 | { | |
141 | HaveInput = 1; | |
142 | } | |
143 | #endif /* defined(unix) */ | |
144 | ||
145 | void | |
146 | outputPurge() | |
147 | { | |
d732be39 | 148 | ttyflush(1); |
b6a8714b GM |
149 | } |
150 | ||
151 | ||
152 | /* | |
153 | * The following routines are places where the various tn3270 | |
154 | * routines make calls into telnet.c. | |
155 | */ | |
156 | ||
66c4b72a GM |
157 | /* |
158 | * DataToTerminal - queue up some data to go to terminal. | |
159 | * | |
160 | * Note: there are people who call us and depend on our processing | |
161 | * *all* the data at one time (thus the select). | |
162 | */ | |
b6a8714b GM |
163 | |
164 | int | |
165 | DataToTerminal(buffer, count) | |
166 | register char *buffer; /* where the data is */ | |
167 | register int count; /* how much to send */ | |
168 | { | |
476b1e3a | 169 | register int loop, c; |
b6a8714b | 170 | int origCount; |
b6a8714b | 171 | |
b6a8714b GM |
172 | origCount = count; |
173 | ||
174 | while (count) { | |
476b1e3a GM |
175 | if (TTYROOM() == 0) { |
176 | #if defined(unix) | |
177 | fd_set o; | |
178 | ||
179 | FD_ZERO(&o); | |
180 | #endif /* defined(unix) */ | |
181 | ttyflush(); | |
182 | while (TTYROOM() == 0) { | |
b6a8714b GM |
183 | #if defined(unix) |
184 | FD_SET(tout, &o); | |
185 | (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, | |
186 | (struct timeval *) 0); | |
187 | #endif /* defined(unix) */ | |
476b1e3a | 188 | ttyflush(); |
b6a8714b GM |
189 | } |
190 | } | |
66c4b72a GM |
191 | c = TTYROOM(); |
192 | if (c > count) { | |
193 | c = count; | |
476b1e3a | 194 | } |
66c4b72a GM |
195 | ring_supply_data(&ttyoring, buffer, c); |
196 | count -= c; | |
197 | buffer += c; | |
b6a8714b | 198 | } |
66c4b72a | 199 | return(origCount); |
b6a8714b GM |
200 | } |
201 | ||
202 | /* EmptyTerminal - called to make sure that the terminal buffer is empty. | |
203 | * Note that we consider the buffer to run all the | |
204 | * way to the kernel (thus the select). | |
205 | */ | |
206 | ||
207 | void | |
208 | EmptyTerminal() | |
209 | { | |
210 | #if defined(unix) | |
211 | fd_set o; | |
212 | ||
213 | FD_ZERO(&o); | |
214 | #endif /* defined(unix) */ | |
215 | ||
66c4b72a | 216 | if (TTYBYTES() == 0) { |
b6a8714b GM |
217 | #if defined(unix) |
218 | FD_SET(tout, &o); | |
219 | (void) select(tout+1, (int *) 0, &o, (int *) 0, | |
220 | (struct timeval *) 0); /* wait for TTLOWAT */ | |
221 | #endif /* defined(unix) */ | |
222 | } else { | |
476b1e3a | 223 | while (TTYBYTES()) { |
d732be39 | 224 | ttyflush(0); |
b6a8714b GM |
225 | #if defined(unix) |
226 | FD_SET(tout, &o); | |
227 | (void) select(tout+1, (int *) 0, &o, (int *) 0, | |
228 | (struct timeval *) 0); /* wait for TTLOWAT */ | |
229 | #endif /* defined(unix) */ | |
230 | } | |
231 | } | |
232 | } | |
233 | \f | |
234 | ||
235 | /* | |
236 | * Push3270 - Try to send data along the 3270 output (to screen) direction. | |
237 | */ | |
238 | ||
476b1e3a | 239 | int |
b6a8714b GM |
240 | Push3270() |
241 | { | |
476b1e3a | 242 | int save = ring_full_count(&netiring); |
b6a8714b | 243 | |
476b1e3a GM |
244 | if (save) { |
245 | if (Ifrontp+save > Ibuf+sizeof Ibuf) { | |
b6a8714b GM |
246 | if (Ibackp != Ibuf) { |
247 | memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); | |
248 | Ifrontp -= (Ibackp-Ibuf); | |
249 | Ibackp = Ibuf; | |
250 | } | |
251 | } | |
476b1e3a | 252 | if (Ifrontp+save < Ibuf+sizeof Ibuf) { |
b6a8714b GM |
253 | telrcv(); |
254 | } | |
255 | } | |
476b1e3a | 256 | return save != ring_full_count(&netiring); |
b6a8714b GM |
257 | } |
258 | ||
259 | ||
260 | /* | |
261 | * Finish3270 - get the last dregs of 3270 data out to the terminal | |
262 | * before quitting. | |
263 | */ | |
264 | ||
476b1e3a | 265 | void |
b6a8714b GM |
266 | Finish3270() |
267 | { | |
268 | while (Push3270() || !DoTerminalOutput()) { | |
269 | #if defined(unix) | |
270 | HaveInput = 0; | |
271 | #endif /* defined(unix) */ | |
272 | ; | |
273 | } | |
274 | } | |
275 | ||
276 | ||
277 | /* StringToTerminal - output a null terminated string to the terminal */ | |
278 | ||
279 | void | |
280 | StringToTerminal(s) | |
281 | char *s; | |
282 | { | |
283 | int count; | |
284 | ||
285 | count = strlen(s); | |
286 | if (count) { | |
287 | (void) DataToTerminal(s, count); /* we know it always goes... */ | |
288 | } | |
289 | } | |
290 | ||
291 | ||
292 | #if ((!defined(NOT43)) || defined(PUTCHAR)) | |
293 | /* _putchar - output a single character to the terminal. This name is so that | |
294 | * curses(3x) can call us to send out data. | |
295 | */ | |
296 | ||
297 | void | |
298 | _putchar(c) | |
299 | char c; | |
300 | { | |
476b1e3a | 301 | if (TTYBYTES()) { |
b6a8714b GM |
302 | (void) DataToTerminal(&c, 1); |
303 | } else { | |
476b1e3a | 304 | TTYADD(c); |
b6a8714b GM |
305 | } |
306 | } | |
307 | #endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */ | |
308 | ||
b307f09e GM |
309 | void |
310 | SetForExit() | |
311 | { | |
312 | setconnmode(); | |
313 | if (In3270) { | |
314 | Finish3270(); | |
315 | } | |
316 | setcommandmode(); | |
317 | fflush(stdout); | |
318 | fflush(stderr); | |
319 | if (In3270) { | |
320 | StopScreen(1); | |
321 | } | |
322 | setconnmode(); | |
323 | setcommandmode(); | |
324 | } | |
325 | ||
326 | void | |
327 | Exit(returnCode) | |
328 | int returnCode; | |
329 | { | |
330 | SetForExit(); | |
331 | exit(returnCode); | |
332 | } | |
333 | ||
334 | void | |
335 | ExitString(string, returnCode) | |
336 | char *string; | |
337 | int returnCode; | |
338 | { | |
339 | SetForExit(); | |
340 | fwrite(string, 1, strlen(string), stderr); | |
341 | exit(returnCode); | |
342 | } | |
343 | ||
344 | void | |
345 | ExitPerror(string, returnCode) | |
346 | char *string; | |
347 | int returnCode; | |
348 | { | |
349 | SetForExit(); | |
350 | perror(string); | |
351 | exit(returnCode); | |
352 | } | |
353 | ||
354 | void | |
355 | SetIn3270() | |
356 | { | |
357 | if (Sent3270TerminalType && myopts[TELOPT_BINARY] | |
358 | && hisopts[TELOPT_BINARY] && !donebinarytoggle) { | |
359 | if (!In3270) { | |
360 | In3270 = 1; | |
361 | Init3270(); /* Initialize 3270 functions */ | |
362 | /* initialize terminal key mapping */ | |
363 | InitTerminal(); /* Start terminal going */ | |
364 | setconnmode(); | |
365 | } | |
366 | } else { | |
367 | if (In3270) { | |
368 | StopScreen(1); | |
369 | In3270 = 0; | |
370 | Stop3270(); /* Tell 3270 we aren't here anymore */ | |
371 | setconnmode(); | |
372 | } | |
373 | } | |
374 | } | |
375 | ||
376 | /* | |
377 | * tn3270_ttype() | |
378 | * | |
379 | * Send a response to a terminal type negotiation. | |
380 | * | |
381 | * Return '0' if no more responses to send; '1' if a response sent. | |
382 | */ | |
383 | ||
384 | int | |
385 | tn3270_ttype() | |
386 | { | |
387 | /* | |
388 | * Try to send a 3270 type terminal name. Decide which one based | |
389 | * on the format of our screen, and (in the future) color | |
390 | * capaiblities. | |
391 | */ | |
392 | InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */ | |
393 | if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { | |
394 | Sent3270TerminalType = 1; | |
395 | if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { | |
396 | MaxNumberLines = 27; | |
397 | MaxNumberColumns = 132; | |
398 | sb_terminal[SBTERMMODEL] = '5'; | |
399 | } else if (MaxNumberLines >= 43) { | |
400 | MaxNumberLines = 43; | |
401 | MaxNumberColumns = 80; | |
402 | sb_terminal[SBTERMMODEL] = '4'; | |
403 | } else if (MaxNumberLines >= 32) { | |
404 | MaxNumberLines = 32; | |
405 | MaxNumberColumns = 80; | |
406 | sb_terminal[SBTERMMODEL] = '3'; | |
407 | } else { | |
408 | MaxNumberLines = 24; | |
409 | MaxNumberColumns = 80; | |
410 | sb_terminal[SBTERMMODEL] = '2'; | |
411 | } | |
412 | NumberLines = 24; /* before we start out... */ | |
413 | NumberColumns = 80; | |
414 | ScreenSize = NumberLines*NumberColumns; | |
415 | if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { | |
416 | ExitString("Programming error: MAXSCREENSIZE too small.\n", | |
417 | 1); | |
418 | /*NOTREACHED*/ | |
419 | } | |
420 | printsub(">", sb_terminal+2, sizeof sb_terminal-2); | |
421 | ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal); | |
422 | return 1; | |
423 | } else { | |
424 | return 0; | |
425 | } | |
426 | } | |
476b1e3a GM |
427 | |
428 | #if defined(unix) | |
429 | settranscom(argc, argv) | |
430 | int argc; | |
431 | char *argv[]; | |
432 | { | |
433 | int i, len = 0; | |
434 | ||
435 | if (argc == 1 && transcom) { | |
436 | transcom = 0; | |
437 | } | |
438 | if (argc == 1) { | |
439 | return; | |
440 | } | |
441 | for (i = 1; i < argc; ++i) { | |
442 | len += 1 + strlen(argv[1]); | |
443 | } | |
444 | transcom = tline; | |
445 | (void) strcpy(transcom, argv[1]); | |
446 | for (i = 2; i < argc; ++i) { | |
447 | (void) strcat(transcom, " "); | |
448 | (void) strcat(transcom, argv[i]); | |
449 | } | |
450 | } | |
451 | #endif /* defined(unix) */ | |
452 | ||
b6a8714b | 453 | #endif /* defined(TN3270) */ |