138905Sborman /* 238905Sborman * Copyright (c) 1989 Regents of the University of California. 338905Sborman * All rights reserved. 438905Sborman * 542673Sbostic * %sccs.include.redist.c% 638905Sborman */ 738905Sborman 838905Sborman #ifndef lint 9*45234Sborman static char sccsid[] = "@(#)slc.c 5.5 (Berkeley) 09/14/90"; 1038905Sborman #endif /* not lint */ 1138905Sborman 1238905Sborman #include "telnetd.h" 1338905Sborman 1438905Sborman #ifdef LINEMODE 1538905Sborman /* 1638905Sborman * local varibles 1738905Sborman */ 1844364Sborman static unsigned char *def_slcbuf = (unsigned char *)0; 1944364Sborman static int def_slclen = 0; 2044364Sborman static int slcchange; /* change to slc is requested */ 2144364Sborman static unsigned char *slcptr; /* pointer into slc buffer */ 2244364Sborman static unsigned char slcbuf[NSLC*6]; /* buffer for slc negotiation */ 2338905Sborman 2438905Sborman /* 2538905Sborman * send_slc 2638905Sborman * 2738905Sborman * Write out the current special characters to the client. 2838905Sborman */ 2938905Sborman send_slc() 3038905Sborman { 3138905Sborman register int i; 3238905Sborman 3338905Sborman /* 3438905Sborman * Send out list of triplets of special characters 3538905Sborman * to client. We only send info on the characters 3638905Sborman * that are currently supported. 3738905Sborman */ 3838905Sborman for (i = 1; i <= NSLC; i++) { 39*45234Sborman if ((slctab[i].defset.flag & SLC_LEVELBITS) == SLC_NOSUPPORT) 40*45234Sborman continue; 41*45234Sborman add_slc((unsigned char)i, slctab[i].current.flag, 4238905Sborman slctab[i].current.val); 4338905Sborman } 4438905Sborman 4538905Sborman } /* end of send_slc */ 4638905Sborman 4738905Sborman /* 4838905Sborman * default_slc 4938905Sborman * 5038905Sborman * Set pty special characters to all the defaults. 5138905Sborman */ 5238905Sborman default_slc() 5338905Sborman { 5438905Sborman register int i; 5538905Sborman 5638905Sborman for (i = 1; i <= NSLC; i++) { 5738905Sborman slctab[i].current.val = slctab[i].defset.val; 58*45234Sborman if (slctab[i].current.val == (cc_t)(_POSIX_VDISABLE)) 59*45234Sborman slctab[i].current.flag = SLC_NOSUPPORT; 60*45234Sborman else 61*45234Sborman slctab[i].current.flag = slctab[i].defset.flag; 6238905Sborman if (slctab[i].sptr) { 6338905Sborman *(slctab[i].sptr) = slctab[i].defset.val; 6438905Sborman } 6538905Sborman } 6638905Sborman slcchange = 1; 6738905Sborman 6838905Sborman } /* end of default_slc */ 6938905Sborman #endif LINEMODE 7038905Sborman 7138905Sborman /* 7238905Sborman * get_slc_defaults 7338905Sborman * 7438905Sborman * Initialize the slc mapping table. 7538905Sborman */ 7638905Sborman get_slc_defaults() 7738905Sborman { 7838905Sborman register int i; 7938905Sborman 8038905Sborman init_termbuf(); 8138905Sborman 8238905Sborman for (i = 1; i <= NSLC; i++) { 8338905Sborman slctab[i].defset.flag = 8438905Sborman spcset(i, &slctab[i].defset.val, &slctab[i].sptr); 8538905Sborman slctab[i].current.flag = SLC_NOSUPPORT; 8638905Sborman slctab[i].current.val = 0; 8738905Sborman } 8838905Sborman 8938905Sborman } /* end of get_slc_defaults */ 9038905Sborman 9138905Sborman #ifdef LINEMODE 9238905Sborman /* 9338905Sborman * add_slc 9438905Sborman * 9538905Sborman * Add an slc triplet to the slc buffer. 9638905Sborman */ 9738905Sborman add_slc(func, flag, val) 9840242Sborman register unsigned char func, flag; 9940242Sborman cc_t val; 10038905Sborman { 10138905Sborman 10240242Sborman if ((*slcptr++ = func) == 0xff) 10338905Sborman *slcptr++ = 0xff; 10438905Sborman 10540242Sborman if ((*slcptr++ = flag) == 0xff) 10638905Sborman *slcptr++ = 0xff; 10738905Sborman 10840242Sborman if ((*slcptr++ = (unsigned char)val) == 0xff) 10938905Sborman *slcptr++ = 0xff; 11038905Sborman 11138905Sborman } /* end of add_slc */ 11238905Sborman 11338905Sborman /* 11438905Sborman * start_slc 11538905Sborman * 11638905Sborman * Get ready to process incoming slc's and respond to them. 11738905Sborman * 11838905Sborman * The parameter getit is non-zero if it is necessary to grab a copy 11938905Sborman * of the terminal control structures. 12038905Sborman */ 12138905Sborman start_slc(getit) 12238905Sborman register int getit; 12338905Sborman { 12438905Sborman 12538905Sborman slcchange = 0; 12638905Sborman if (getit) 12738905Sborman init_termbuf(); 12838905Sborman (void) sprintf(slcbuf, "%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_SLC); 12938905Sborman slcptr = slcbuf + 4; 13038905Sborman 13138905Sborman } /* end of start_slc */ 13238905Sborman 13338905Sborman /* 13438905Sborman * end_slc 13538905Sborman * 13638905Sborman * Finish up the slc negotiation. If something to send, then send it. 13738905Sborman */ 13838905Sborman end_slc(bufp) 13944364Sborman register unsigned char **bufp; 14038905Sborman { 14138905Sborman register int len; 14238905Sborman void netflush(); 14338905Sborman 14438905Sborman /* 14538905Sborman * If a change has occured, store the new terminal control 14638905Sborman * structures back to the terminal driver. 14738905Sborman */ 14838905Sborman if (slcchange) { 14938905Sborman set_termbuf(); 15038905Sborman } 15138905Sborman 15238905Sborman /* 15338905Sborman * If the pty state has not yet been fully processed and there is a 15438905Sborman * deferred slc request from the client, then do not send any 15538905Sborman * sort of slc negotiation now. We will respond to the client's 15638905Sborman * request very soon. 15738905Sborman */ 15838905Sborman if (def_slcbuf && (terminit() == 0)) { 15938905Sborman return; 16038905Sborman } 16138905Sborman 16238905Sborman if (slcptr > (slcbuf + 4)) { 16338905Sborman if (bufp) { 16438905Sborman *bufp = &slcbuf[4]; 16538905Sborman return(slcptr - slcbuf - 4); 16638905Sborman } else { 16738905Sborman (void) sprintf(slcptr, "%c%c", IAC, SE); 16838905Sborman slcptr += 2; 16938905Sborman len = slcptr - slcbuf; 17038905Sborman writenet(slcbuf, len); 17138905Sborman netflush(); /* force it out immediately */ 17238905Sborman } 17338905Sborman } 17438905Sborman 17538905Sborman } /* end of end_slc */ 17638905Sborman 17738905Sborman /* 17838905Sborman * process_slc 17938905Sborman * 18038905Sborman * Figure out what to do about the client's slc 18138905Sborman */ 18238905Sborman process_slc(func, flag, val) 18340242Sborman register unsigned char func, flag; 18440242Sborman cc_t val; 18538905Sborman { 18638905Sborman register int hislevel, mylevel, ack; 18738905Sborman 18838905Sborman /* 18938905Sborman * Ensure that we know something about this function 19038905Sborman */ 19138905Sborman if (func > NSLC) { 19238905Sborman add_slc(func, SLC_NOSUPPORT, 0); 19338905Sborman return; 19438905Sborman } 19538905Sborman 19638905Sborman /* 19738905Sborman * Process the special case requests of 0 SLC_DEFAULT 0 19838905Sborman * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't 19938905Sborman * worry about whether the value is actually 0 or not. 20038905Sborman */ 20138905Sborman if (func == 0) { 20238905Sborman if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) { 20338905Sborman default_slc(); 204*45234Sborman send_slc(1); 205*45234Sborman } else if (flag == SLC_VARIABLE) { 206*45234Sborman send_slc(0); 20738905Sborman } 20838905Sborman return; 20938905Sborman } 21038905Sborman 21138905Sborman /* 21238905Sborman * Appears to be a function that we know something about. So 21338905Sborman * get on with it and see what we know. 21438905Sborman */ 21538905Sborman 21638905Sborman hislevel = flag & SLC_LEVELBITS; 21738905Sborman mylevel = slctab[func].current.flag & SLC_LEVELBITS; 21838905Sborman ack = flag & SLC_ACK; 21938905Sborman /* 22038905Sborman * ignore the command if: 22138905Sborman * the function value and level are the same as what we already have; 22238905Sborman * or the level is the same and the ack bit is set 22338905Sborman */ 22438905Sborman if (hislevel == mylevel && (val == slctab[func].current.val || ack)) { 22538905Sborman return; 226*45234Sborman } else if (ack) { 227*45234Sborman /* 228*45234Sborman * If we get here, we got an ack, but the levels don't match. 229*45234Sborman * This shouldn't happen. If it does, it is probably because 230*45234Sborman * we have sent two requests to set a variable without getting 231*45234Sborman * a response between them, and this is the first response. 232*45234Sborman * So, ignore it, and wait for the next response. 233*45234Sborman */ 234*45234Sborman return; 23538905Sborman } else { 23638905Sborman change_slc(func, flag, val); 23738905Sborman } 23838905Sborman 23938905Sborman } /* end of process_slc */ 24038905Sborman 24138905Sborman /* 24238905Sborman * change_slc 24338905Sborman * 24438905Sborman * Process a request to change one of our special characters. 24538905Sborman * Compare client's request with what we are capable of supporting. 24638905Sborman */ 24738905Sborman change_slc(func, flag, val) 24840242Sborman register unsigned char func, flag; 24940242Sborman cc_t val; 25038905Sborman { 25138905Sborman register int hislevel, mylevel; 25238905Sborman 25338905Sborman hislevel = flag & SLC_LEVELBITS; 25438905Sborman mylevel = slctab[func].defset.flag & SLC_LEVELBITS; 25538905Sborman /* 25638905Sborman * If client is setting a function to NOSUPPORT 25738905Sborman * or DEFAULT, then we can easily and directly 25838905Sborman * accomodate the request. 25938905Sborman */ 26038905Sborman if (hislevel == SLC_NOSUPPORT) { 26138905Sborman slctab[func].current.flag = flag; 262*45234Sborman slctab[func].current.val = (cc_t)_POSIX_VDISABLE; 26338905Sborman flag |= SLC_ACK; 26438905Sborman add_slc(func, flag, val); 26538905Sborman return; 26638905Sborman } 26738905Sborman if (hislevel == SLC_DEFAULT) { 26838905Sborman /* 26938905Sborman * Special case here. If client tells us to use 27038905Sborman * the default on a function we don't support, then 27138905Sborman * return NOSUPPORT instead of what we may have as a 27238905Sborman * default level of DEFAULT. 27338905Sborman */ 27438905Sborman if (mylevel == SLC_DEFAULT) { 27538905Sborman slctab[func].current.flag = SLC_NOSUPPORT; 27638905Sborman } else { 27738905Sborman slctab[func].current.flag = slctab[func].defset.flag; 27838905Sborman } 27938905Sborman slctab[func].current.val = slctab[func].defset.val; 28038905Sborman add_slc(func, slctab[func].current.flag, 28138905Sborman slctab[func].current.val); 28238905Sborman return; 28338905Sborman } 28438905Sborman 28538905Sborman /* 28638905Sborman * Client wants us to change to a new value or he 28738905Sborman * is telling us that he can't change to our value. 28838905Sborman * Some of the slc's we support and can change, 28938905Sborman * some we do support but can't change, 29038905Sborman * and others we don't support at all. 29138905Sborman * If we can change it then we have a pointer to 29238905Sborman * the place to put the new value, so change it, 29338905Sborman * otherwise, continue the negotiation. 29438905Sborman */ 29538905Sborman if (slctab[func].sptr) { 29638905Sborman /* 29738905Sborman * We can change this one. 29838905Sborman */ 29938905Sborman slctab[func].current.val = val; 30038905Sborman *(slctab[func].sptr) = val; 30138905Sborman slctab[func].current.flag = flag; 30238905Sborman flag |= SLC_ACK; 30338905Sborman slcchange = 1; 30438905Sborman add_slc(func, flag, val); 30538905Sborman } else { 30638905Sborman /* 30738905Sborman * It is not possible for us to support this 30838905Sborman * request as he asks. 30938905Sborman * 31038905Sborman * If our level is DEFAULT, then just ack whatever was 31138905Sborman * sent. 31238905Sborman * 31338905Sborman * If he can't change and we can't change, 31438905Sborman * then degenerate to NOSUPPORT. 31538905Sborman * 31638905Sborman * Otherwise we send our level back to him, (CANTCHANGE 31738905Sborman * or NOSUPPORT) and if CANTCHANGE, send 31838905Sborman * our value as well. 31938905Sborman */ 32038905Sborman if (mylevel == SLC_DEFAULT) { 32138905Sborman slctab[func].current.flag = flag; 32238905Sborman slctab[func].current.val = val; 32338905Sborman flag |= SLC_ACK; 32438905Sborman } else if (hislevel == SLC_CANTCHANGE && 32538905Sborman mylevel == SLC_CANTCHANGE) { 32638905Sborman flag &= ~SLC_LEVELBITS; 32738905Sborman flag |= SLC_NOSUPPORT; 32838905Sborman slctab[func].current.flag = flag; 32938905Sborman } else { 33038905Sborman flag &= ~SLC_LEVELBITS; 33138905Sborman flag |= mylevel; 33238905Sborman slctab[func].current.flag = flag; 33338905Sborman if (mylevel == SLC_CANTCHANGE) { 33438905Sborman slctab[func].current.val = 33538905Sborman slctab[func].defset.val; 33638905Sborman val = slctab[func].current.val; 33738905Sborman } 33838905Sborman 33938905Sborman } 34038905Sborman add_slc(func, flag, val); 34138905Sborman } 34238905Sborman 34338905Sborman } /* end of change_slc */ 34438905Sborman 345*45234Sborman #if defined(USE_TERMIO) && (VEOF == VMIN) 34640242Sborman cc_t oldeofc = '\004'; 34740242Sborman #endif 34840242Sborman 34938905Sborman /* 35038905Sborman * check_slc 35138905Sborman * 35238905Sborman * Check the special characters in use and notify the client if any have 35338905Sborman * changed. Only those characters that are capable of being changed are 35438905Sborman * likely to have changed. If a local change occurs, kick the support level 35538905Sborman * and flags up to the defaults. 35638905Sborman */ 35738905Sborman check_slc() 35838905Sborman { 35938905Sborman register int i; 36038905Sborman 36138905Sborman for (i = 1; i <= NSLC; i++) { 362*45234Sborman #if defined(USE_TERMIO) && (VEOF == VMIN) 36338905Sborman /* 36438905Sborman * In a perfect world this would be a neat little 36538905Sborman * function. But in this world, we should not notify 36638905Sborman * client of changes to the VEOF char when 36738905Sborman * ICANON is off, because it is not representing 36838905Sborman * a special character. 36938905Sborman */ 37040242Sborman if (i == SLC_EOF) { 37140242Sborman if (!tty_isediting()) 37240242Sborman continue; 37340242Sborman else if (slctab[i].sptr) 37440242Sborman oldeofc = *(slctab[i].sptr); 37540242Sborman } 37638905Sborman #endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */ 37738905Sborman if (slctab[i].sptr && 37838905Sborman (*(slctab[i].sptr) != slctab[i].current.val)) { 37938905Sborman slctab[i].current.val = *(slctab[i].sptr); 380*45234Sborman if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE) 381*45234Sborman slctab[i].current.flag = SLC_NOSUPPORT; 382*45234Sborman else 383*45234Sborman slctab[i].current.flag = slctab[i].defset.flag; 38438905Sborman add_slc((unsigned char)i, slctab[i].current.flag, 38538905Sborman slctab[i].current.val); 38638905Sborman } 38738905Sborman } 38838905Sborman 38938905Sborman } /* check_slc */ 39038905Sborman 39138905Sborman /* 39238905Sborman * do_opt_slc 39338905Sborman * 39438905Sborman * Process an slc option buffer. Defer processing of incoming slc's 39538905Sborman * until after the terminal state has been processed. Save the first slc 39638905Sborman * request that comes along, but discard all others. 39738905Sborman * 39838905Sborman * ptr points to the beginning of the buffer, len is the length. 39938905Sborman */ 40038905Sborman do_opt_slc(ptr, len) 40138905Sborman register char *ptr; 40238905Sborman register int len; 40338905Sborman { 40440242Sborman register unsigned char func, flag; 40540242Sborman cc_t val; 40638905Sborman register char *end = (char *)(ptr + len); 40738905Sborman char *malloc(); 40838905Sborman 40938905Sborman if (terminit()) { /* go ahead */ 41038905Sborman while (ptr < end) { 41138905Sborman func = *ptr++; 41238905Sborman if (ptr >= end) break; 41338905Sborman flag = *ptr++; 41438905Sborman if (ptr >= end) break; 41540242Sborman val = (cc_t)*ptr++; 41638905Sborman 41738905Sborman process_slc(func, flag, val); 41838905Sborman 41938905Sborman } 42038905Sborman } else { 42138905Sborman /* 42238905Sborman * save this slc buffer if it is the first, otherwise dump 42338905Sborman * it. 42438905Sborman */ 42544364Sborman if (def_slcbuf == (unsigned char *)0) { 42638905Sborman def_slclen = len; 42744364Sborman def_slcbuf = (unsigned char *)malloc((unsigned)len); 42844364Sborman if (def_slcbuf == (unsigned char *)0) 42938905Sborman return; /* too bad */ 43038905Sborman bcopy(ptr, def_slcbuf, len); 43138905Sborman } 43238905Sborman } 43338905Sborman 43438905Sborman } /* end of do_opt_slc */ 43538905Sborman 43638905Sborman /* 43738905Sborman * deferslc 43838905Sborman * 43938905Sborman * Do slc stuff that was deferred. 44038905Sborman */ 44138905Sborman deferslc() 44238905Sborman { 44338905Sborman if (def_slcbuf) { 44438905Sborman start_slc(1); 44538905Sborman do_opt_slc(def_slcbuf, def_slclen); 44638905Sborman end_slc(0); 44738905Sborman free(def_slcbuf); 44844364Sborman def_slcbuf = (unsigned char *)0; 44938905Sborman def_slclen = 0; 45038905Sborman } 45138905Sborman 45238905Sborman } /* end of deferslc */ 45338905Sborman 45438905Sborman #endif /* LINEMODE */ 455