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