1 /* 2 * Copyright (c) 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)slc.c 5.3 (Berkeley) 06/01/90"; 10 #endif /* not lint */ 11 12 #include "telnetd.h" 13 14 #ifdef LINEMODE 15 /* 16 * local varibles 17 */ 18 static char *def_slcbuf = (char *)0; 19 static int def_slclen = 0; 20 static int slcchange; /* change to slc is requested */ 21 static char *slcptr; /* pointer into slc buffer */ 22 static char slcbuf[NSLC*6]; /* buffer for slc negotiation */ 23 24 /* 25 * send_slc 26 * 27 * Write out the current special characters to the client. 28 */ 29 send_slc() 30 { 31 register int i; 32 33 /* 34 * Send out list of triplets of special characters 35 * to client. We only send info on the characters 36 * that are currently supported. 37 */ 38 for (i = 1; i <= NSLC; i++) { 39 if ((slctab[i].current.flag & SLC_LEVELBITS) != SLC_NOSUPPORT) { 40 add_slc((unsigned char)i, slctab[i].current.flag, 41 slctab[i].current.val); 42 } 43 } 44 45 } /* end of send_slc */ 46 47 /* 48 * default_slc 49 * 50 * Set pty special characters to all the defaults. 51 */ 52 default_slc() 53 { 54 register int i; 55 56 for (i = 1; i <= NSLC; i++) { 57 slctab[i].current.flag = slctab[i].defset.flag; 58 slctab[i].current.val = slctab[i].defset.val; 59 if (slctab[i].sptr) { 60 *(slctab[i].sptr) = slctab[i].defset.val; 61 } 62 } 63 slcchange = 1; 64 65 } /* end of default_slc */ 66 #endif LINEMODE 67 68 /* 69 * get_slc_defaults 70 * 71 * Initialize the slc mapping table. 72 */ 73 get_slc_defaults() 74 { 75 register int i; 76 77 init_termbuf(); 78 79 for (i = 1; i <= NSLC; i++) { 80 slctab[i].defset.flag = 81 spcset(i, &slctab[i].defset.val, &slctab[i].sptr); 82 slctab[i].current.flag = SLC_NOSUPPORT; 83 slctab[i].current.val = 0; 84 } 85 86 } /* end of get_slc_defaults */ 87 88 #ifdef LINEMODE 89 /* 90 * add_slc 91 * 92 * Add an slc triplet to the slc buffer. 93 */ 94 add_slc(func, flag, val) 95 register unsigned char func, flag; 96 cc_t val; 97 { 98 99 if ((*slcptr++ = func) == 0xff) 100 *slcptr++ = 0xff; 101 102 if ((*slcptr++ = flag) == 0xff) 103 *slcptr++ = 0xff; 104 105 if ((*slcptr++ = (unsigned char)val) == 0xff) 106 *slcptr++ = 0xff; 107 108 } /* end of add_slc */ 109 110 /* 111 * start_slc 112 * 113 * Get ready to process incoming slc's and respond to them. 114 * 115 * The parameter getit is non-zero if it is necessary to grab a copy 116 * of the terminal control structures. 117 */ 118 start_slc(getit) 119 register int getit; 120 { 121 122 slcchange = 0; 123 if (getit) 124 init_termbuf(); 125 (void) sprintf(slcbuf, "%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_SLC); 126 slcptr = slcbuf + 4; 127 128 } /* end of start_slc */ 129 130 /* 131 * end_slc 132 * 133 * Finish up the slc negotiation. If something to send, then send it. 134 */ 135 end_slc(bufp) 136 register char **bufp; 137 { 138 register int len; 139 void netflush(); 140 141 /* 142 * If a change has occured, store the new terminal control 143 * structures back to the terminal driver. 144 */ 145 if (slcchange) { 146 set_termbuf(); 147 } 148 149 /* 150 * If the pty state has not yet been fully processed and there is a 151 * deferred slc request from the client, then do not send any 152 * sort of slc negotiation now. We will respond to the client's 153 * request very soon. 154 */ 155 if (def_slcbuf && (terminit() == 0)) { 156 return; 157 } 158 159 if (slcptr > (slcbuf + 4)) { 160 if (bufp) { 161 *bufp = &slcbuf[4]; 162 return(slcptr - slcbuf - 4); 163 } else { 164 (void) sprintf(slcptr, "%c%c", IAC, SE); 165 slcptr += 2; 166 len = slcptr - slcbuf; 167 writenet(slcbuf, len); 168 netflush(); /* force it out immediately */ 169 } 170 } 171 172 } /* end of end_slc */ 173 174 /* 175 * process_slc 176 * 177 * Figure out what to do about the client's slc 178 */ 179 process_slc(func, flag, val) 180 register unsigned char func, flag; 181 cc_t val; 182 { 183 register int hislevel, mylevel, ack; 184 185 /* 186 * Ensure that we know something about this function 187 */ 188 if (func > NSLC) { 189 add_slc(func, SLC_NOSUPPORT, 0); 190 return; 191 } 192 193 /* 194 * Process the special case requests of 0 SLC_DEFAULT 0 195 * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't 196 * worry about whether the value is actually 0 or not. 197 */ 198 if (func == 0) { 199 if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) { 200 default_slc(); 201 } 202 if (flag == SLC_DEFAULT || flag == SLC_VARIABLE) { 203 send_slc(); 204 } 205 return; 206 } 207 208 /* 209 * Appears to be a function that we know something about. So 210 * get on with it and see what we know. 211 */ 212 213 hislevel = flag & SLC_LEVELBITS; 214 mylevel = slctab[func].current.flag & SLC_LEVELBITS; 215 ack = flag & SLC_ACK; 216 /* 217 * ignore the command if: 218 * the function value and level are the same as what we already have; 219 * or the level is the same and the ack bit is set 220 */ 221 if (hislevel == mylevel && (val == slctab[func].current.val || ack)) { 222 return; 223 } else { 224 change_slc(func, flag, val); 225 } 226 227 } /* end of process_slc */ 228 229 /* 230 * change_slc 231 * 232 * Process a request to change one of our special characters. 233 * Compare client's request with what we are capable of supporting. 234 */ 235 change_slc(func, flag, val) 236 register unsigned char func, flag; 237 cc_t val; 238 { 239 register int hislevel, mylevel; 240 241 hislevel = flag & SLC_LEVELBITS; 242 mylevel = slctab[func].defset.flag & SLC_LEVELBITS; 243 /* 244 * If client is setting a function to NOSUPPORT 245 * or DEFAULT, then we can easily and directly 246 * accomodate the request. 247 */ 248 if (hislevel == SLC_NOSUPPORT) { 249 slctab[func].current.flag = flag; 250 slctab[func].current.val = val; 251 flag |= SLC_ACK; 252 add_slc(func, flag, val); 253 return; 254 } 255 if (hislevel == SLC_DEFAULT) { 256 /* 257 * Special case here. If client tells us to use 258 * the default on a function we don't support, then 259 * return NOSUPPORT instead of what we may have as a 260 * default level of DEFAULT. 261 */ 262 if (mylevel == SLC_DEFAULT) { 263 slctab[func].current.flag = SLC_NOSUPPORT; 264 } else { 265 slctab[func].current.flag = slctab[func].defset.flag; 266 } 267 slctab[func].current.val = slctab[func].defset.val; 268 add_slc(func, slctab[func].current.flag, 269 slctab[func].current.val); 270 return; 271 } 272 273 /* 274 * Client wants us to change to a new value or he 275 * is telling us that he can't change to our value. 276 * Some of the slc's we support and can change, 277 * some we do support but can't change, 278 * and others we don't support at all. 279 * If we can change it then we have a pointer to 280 * the place to put the new value, so change it, 281 * otherwise, continue the negotiation. 282 */ 283 if (slctab[func].sptr) { 284 /* 285 * We can change this one. 286 */ 287 slctab[func].current.val = val; 288 *(slctab[func].sptr) = val; 289 slctab[func].current.flag = flag; 290 flag |= SLC_ACK; 291 slcchange = 1; 292 add_slc(func, flag, val); 293 } else { 294 /* 295 * It is not possible for us to support this 296 * request as he asks. 297 * 298 * If our level is DEFAULT, then just ack whatever was 299 * sent. 300 * 301 * If he can't change and we can't change, 302 * then degenerate to NOSUPPORT. 303 * 304 * Otherwise we send our level back to him, (CANTCHANGE 305 * or NOSUPPORT) and if CANTCHANGE, send 306 * our value as well. 307 */ 308 if (mylevel == SLC_DEFAULT) { 309 slctab[func].current.flag = flag; 310 slctab[func].current.val = val; 311 flag |= SLC_ACK; 312 } else if (hislevel == SLC_CANTCHANGE && 313 mylevel == SLC_CANTCHANGE) { 314 flag &= ~SLC_LEVELBITS; 315 flag |= SLC_NOSUPPORT; 316 slctab[func].current.flag = flag; 317 } else { 318 flag &= ~SLC_LEVELBITS; 319 flag |= mylevel; 320 slctab[func].current.flag = flag; 321 if (mylevel == SLC_CANTCHANGE) { 322 slctab[func].current.val = 323 slctab[func].defset.val; 324 val = slctab[func].current.val; 325 } 326 327 } 328 add_slc(func, flag, val); 329 } 330 331 } /* end of change_slc */ 332 333 #if defined(USE_TERMIO) && defined(SYSV_TERMIO) 334 cc_t oldeofc = '\004'; 335 #endif 336 337 /* 338 * check_slc 339 * 340 * Check the special characters in use and notify the client if any have 341 * changed. Only those characters that are capable of being changed are 342 * likely to have changed. If a local change occurs, kick the support level 343 * and flags up to the defaults. 344 */ 345 check_slc() 346 { 347 register int i; 348 349 for (i = 1; i <= NSLC; i++) { 350 #if defined(USE_TERMIO) && defined(SYSV_TERMIO) 351 /* 352 * In a perfect world this would be a neat little 353 * function. But in this world, we should not notify 354 * client of changes to the VEOF char when 355 * ICANON is off, because it is not representing 356 * a special character. 357 */ 358 if (i == SLC_EOF) { 359 if (!tty_isediting()) 360 continue; 361 else if (slctab[i].sptr) 362 oldeofc = *(slctab[i].sptr); 363 } 364 #endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */ 365 if (slctab[i].sptr && 366 (*(slctab[i].sptr) != slctab[i].current.val)) { 367 slctab[i].current.val = *(slctab[i].sptr); 368 slctab[i].current.flag = slctab[i].defset.flag; 369 add_slc((unsigned char)i, slctab[i].current.flag, 370 slctab[i].current.val); 371 } 372 } 373 374 } /* check_slc */ 375 376 /* 377 * do_opt_slc 378 * 379 * Process an slc option buffer. Defer processing of incoming slc's 380 * until after the terminal state has been processed. Save the first slc 381 * request that comes along, but discard all others. 382 * 383 * ptr points to the beginning of the buffer, len is the length. 384 */ 385 do_opt_slc(ptr, len) 386 register char *ptr; 387 register int len; 388 { 389 register unsigned char func, flag; 390 cc_t val; 391 register char *end = (char *)(ptr + len); 392 char *malloc(); 393 394 if (terminit()) { /* go ahead */ 395 while (ptr < end) { 396 func = *ptr++; 397 if (ptr >= end) break; 398 flag = *ptr++; 399 if (ptr >= end) break; 400 val = (cc_t)*ptr++; 401 402 process_slc(func, flag, val); 403 404 } 405 } else { 406 /* 407 * save this slc buffer if it is the first, otherwise dump 408 * it. 409 */ 410 if (def_slcbuf == (char *)0) { 411 def_slclen = len; 412 def_slcbuf = malloc((unsigned)len); 413 if (def_slcbuf == (char *)0) 414 return; /* too bad */ 415 bcopy(ptr, def_slcbuf, len); 416 } 417 } 418 419 } /* end of do_opt_slc */ 420 421 /* 422 * deferslc 423 * 424 * Do slc stuff that was deferred. 425 */ 426 deferslc() 427 { 428 if (def_slcbuf) { 429 start_slc(1); 430 do_opt_slc(def_slcbuf, def_slclen); 431 end_slc(0); 432 free(def_slcbuf); 433 def_slcbuf = (char *)0; 434 def_slclen = 0; 435 } 436 437 } /* end of deferslc */ 438 439 #endif /* LINEMODE */ 440