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*44364Sborman static char sccsid[] = "@(#)slc.c 5.4 (Berkeley) 06/28/90"; 1038905Sborman #endif /* not lint */ 1138905Sborman 1238905Sborman #include "telnetd.h" 1338905Sborman 1438905Sborman #ifdef LINEMODE 1538905Sborman /* 1638905Sborman * local varibles 1738905Sborman */ 18*44364Sborman static unsigned char *def_slcbuf = (unsigned char *)0; 19*44364Sborman static int def_slclen = 0; 20*44364Sborman static int slcchange; /* change to slc is requested */ 21*44364Sborman static unsigned char *slcptr; /* pointer into slc buffer */ 22*44364Sborman 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++) { 3938905Sborman if ((slctab[i].current.flag & SLC_LEVELBITS) != SLC_NOSUPPORT) { 4038905Sborman add_slc((unsigned char)i, slctab[i].current.flag, 4138905Sborman slctab[i].current.val); 4238905Sborman } 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.flag = slctab[i].defset.flag; 5838905Sborman slctab[i].current.val = slctab[i].defset.val; 5938905Sborman if (slctab[i].sptr) { 6038905Sborman *(slctab[i].sptr) = slctab[i].defset.val; 6138905Sborman } 6238905Sborman } 6338905Sborman slcchange = 1; 6438905Sborman 6538905Sborman } /* end of default_slc */ 6638905Sborman #endif LINEMODE 6738905Sborman 6838905Sborman /* 6938905Sborman * get_slc_defaults 7038905Sborman * 7138905Sborman * Initialize the slc mapping table. 7238905Sborman */ 7338905Sborman get_slc_defaults() 7438905Sborman { 7538905Sborman register int i; 7638905Sborman 7738905Sborman init_termbuf(); 7838905Sborman 7938905Sborman for (i = 1; i <= NSLC; i++) { 8038905Sborman slctab[i].defset.flag = 8138905Sborman spcset(i, &slctab[i].defset.val, &slctab[i].sptr); 8238905Sborman slctab[i].current.flag = SLC_NOSUPPORT; 8338905Sborman slctab[i].current.val = 0; 8438905Sborman } 8538905Sborman 8638905Sborman } /* end of get_slc_defaults */ 8738905Sborman 8838905Sborman #ifdef LINEMODE 8938905Sborman /* 9038905Sborman * add_slc 9138905Sborman * 9238905Sborman * Add an slc triplet to the slc buffer. 9338905Sborman */ 9438905Sborman add_slc(func, flag, val) 9540242Sborman register unsigned char func, flag; 9640242Sborman cc_t val; 9738905Sborman { 9838905Sborman 9940242Sborman if ((*slcptr++ = func) == 0xff) 10038905Sborman *slcptr++ = 0xff; 10138905Sborman 10240242Sborman if ((*slcptr++ = flag) == 0xff) 10338905Sborman *slcptr++ = 0xff; 10438905Sborman 10540242Sborman if ((*slcptr++ = (unsigned char)val) == 0xff) 10638905Sborman *slcptr++ = 0xff; 10738905Sborman 10838905Sborman } /* end of add_slc */ 10938905Sborman 11038905Sborman /* 11138905Sborman * start_slc 11238905Sborman * 11338905Sborman * Get ready to process incoming slc's and respond to them. 11438905Sborman * 11538905Sborman * The parameter getit is non-zero if it is necessary to grab a copy 11638905Sborman * of the terminal control structures. 11738905Sborman */ 11838905Sborman start_slc(getit) 11938905Sborman register int getit; 12038905Sborman { 12138905Sborman 12238905Sborman slcchange = 0; 12338905Sborman if (getit) 12438905Sborman init_termbuf(); 12538905Sborman (void) sprintf(slcbuf, "%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_SLC); 12638905Sborman slcptr = slcbuf + 4; 12738905Sborman 12838905Sborman } /* end of start_slc */ 12938905Sborman 13038905Sborman /* 13138905Sborman * end_slc 13238905Sborman * 13338905Sborman * Finish up the slc negotiation. If something to send, then send it. 13438905Sborman */ 13538905Sborman end_slc(bufp) 136*44364Sborman register unsigned char **bufp; 13738905Sborman { 13838905Sborman register int len; 13938905Sborman void netflush(); 14038905Sborman 14138905Sborman /* 14238905Sborman * If a change has occured, store the new terminal control 14338905Sborman * structures back to the terminal driver. 14438905Sborman */ 14538905Sborman if (slcchange) { 14638905Sborman set_termbuf(); 14738905Sborman } 14838905Sborman 14938905Sborman /* 15038905Sborman * If the pty state has not yet been fully processed and there is a 15138905Sborman * deferred slc request from the client, then do not send any 15238905Sborman * sort of slc negotiation now. We will respond to the client's 15338905Sborman * request very soon. 15438905Sborman */ 15538905Sborman if (def_slcbuf && (terminit() == 0)) { 15638905Sborman return; 15738905Sborman } 15838905Sborman 15938905Sborman if (slcptr > (slcbuf + 4)) { 16038905Sborman if (bufp) { 16138905Sborman *bufp = &slcbuf[4]; 16238905Sborman return(slcptr - slcbuf - 4); 16338905Sborman } else { 16438905Sborman (void) sprintf(slcptr, "%c%c", IAC, SE); 16538905Sborman slcptr += 2; 16638905Sborman len = slcptr - slcbuf; 16738905Sborman writenet(slcbuf, len); 16838905Sborman netflush(); /* force it out immediately */ 16938905Sborman } 17038905Sborman } 17138905Sborman 17238905Sborman } /* end of end_slc */ 17338905Sborman 17438905Sborman /* 17538905Sborman * process_slc 17638905Sborman * 17738905Sborman * Figure out what to do about the client's slc 17838905Sborman */ 17938905Sborman process_slc(func, flag, val) 18040242Sborman register unsigned char func, flag; 18140242Sborman cc_t val; 18238905Sborman { 18338905Sborman register int hislevel, mylevel, ack; 18438905Sborman 18538905Sborman /* 18638905Sborman * Ensure that we know something about this function 18738905Sborman */ 18838905Sborman if (func > NSLC) { 18938905Sborman add_slc(func, SLC_NOSUPPORT, 0); 19038905Sborman return; 19138905Sborman } 19238905Sborman 19338905Sborman /* 19438905Sborman * Process the special case requests of 0 SLC_DEFAULT 0 19538905Sborman * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't 19638905Sborman * worry about whether the value is actually 0 or not. 19738905Sborman */ 19838905Sborman if (func == 0) { 19938905Sborman if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) { 20038905Sborman default_slc(); 20138905Sborman } 20238905Sborman if (flag == SLC_DEFAULT || flag == SLC_VARIABLE) { 20338905Sborman send_slc(); 20438905Sborman } 20538905Sborman return; 20638905Sborman } 20738905Sborman 20838905Sborman /* 20938905Sborman * Appears to be a function that we know something about. So 21038905Sborman * get on with it and see what we know. 21138905Sborman */ 21238905Sborman 21338905Sborman hislevel = flag & SLC_LEVELBITS; 21438905Sborman mylevel = slctab[func].current.flag & SLC_LEVELBITS; 21538905Sborman ack = flag & SLC_ACK; 21638905Sborman /* 21738905Sborman * ignore the command if: 21838905Sborman * the function value and level are the same as what we already have; 21938905Sborman * or the level is the same and the ack bit is set 22038905Sborman */ 22138905Sborman if (hislevel == mylevel && (val == slctab[func].current.val || ack)) { 22238905Sborman return; 22338905Sborman } else { 22438905Sborman change_slc(func, flag, val); 22538905Sborman } 22638905Sborman 22738905Sborman } /* end of process_slc */ 22838905Sborman 22938905Sborman /* 23038905Sborman * change_slc 23138905Sborman * 23238905Sborman * Process a request to change one of our special characters. 23338905Sborman * Compare client's request with what we are capable of supporting. 23438905Sborman */ 23538905Sborman change_slc(func, flag, val) 23640242Sborman register unsigned char func, flag; 23740242Sborman cc_t val; 23838905Sborman { 23938905Sborman register int hislevel, mylevel; 24038905Sborman 24138905Sborman hislevel = flag & SLC_LEVELBITS; 24238905Sborman mylevel = slctab[func].defset.flag & SLC_LEVELBITS; 24338905Sborman /* 24438905Sborman * If client is setting a function to NOSUPPORT 24538905Sborman * or DEFAULT, then we can easily and directly 24638905Sborman * accomodate the request. 24738905Sborman */ 24838905Sborman if (hislevel == SLC_NOSUPPORT) { 24938905Sborman slctab[func].current.flag = flag; 25038905Sborman slctab[func].current.val = val; 25138905Sborman flag |= SLC_ACK; 25238905Sborman add_slc(func, flag, val); 25338905Sborman return; 25438905Sborman } 25538905Sborman if (hislevel == SLC_DEFAULT) { 25638905Sborman /* 25738905Sborman * Special case here. If client tells us to use 25838905Sborman * the default on a function we don't support, then 25938905Sborman * return NOSUPPORT instead of what we may have as a 26038905Sborman * default level of DEFAULT. 26138905Sborman */ 26238905Sborman if (mylevel == SLC_DEFAULT) { 26338905Sborman slctab[func].current.flag = SLC_NOSUPPORT; 26438905Sborman } else { 26538905Sborman slctab[func].current.flag = slctab[func].defset.flag; 26638905Sborman } 26738905Sborman slctab[func].current.val = slctab[func].defset.val; 26838905Sborman add_slc(func, slctab[func].current.flag, 26938905Sborman slctab[func].current.val); 27038905Sborman return; 27138905Sborman } 27238905Sborman 27338905Sborman /* 27438905Sborman * Client wants us to change to a new value or he 27538905Sborman * is telling us that he can't change to our value. 27638905Sborman * Some of the slc's we support and can change, 27738905Sborman * some we do support but can't change, 27838905Sborman * and others we don't support at all. 27938905Sborman * If we can change it then we have a pointer to 28038905Sborman * the place to put the new value, so change it, 28138905Sborman * otherwise, continue the negotiation. 28238905Sborman */ 28338905Sborman if (slctab[func].sptr) { 28438905Sborman /* 28538905Sborman * We can change this one. 28638905Sborman */ 28738905Sborman slctab[func].current.val = val; 28838905Sborman *(slctab[func].sptr) = val; 28938905Sborman slctab[func].current.flag = flag; 29038905Sborman flag |= SLC_ACK; 29138905Sborman slcchange = 1; 29238905Sborman add_slc(func, flag, val); 29338905Sborman } else { 29438905Sborman /* 29538905Sborman * It is not possible for us to support this 29638905Sborman * request as he asks. 29738905Sborman * 29838905Sborman * If our level is DEFAULT, then just ack whatever was 29938905Sborman * sent. 30038905Sborman * 30138905Sborman * If he can't change and we can't change, 30238905Sborman * then degenerate to NOSUPPORT. 30338905Sborman * 30438905Sborman * Otherwise we send our level back to him, (CANTCHANGE 30538905Sborman * or NOSUPPORT) and if CANTCHANGE, send 30638905Sborman * our value as well. 30738905Sborman */ 30838905Sborman if (mylevel == SLC_DEFAULT) { 30938905Sborman slctab[func].current.flag = flag; 31038905Sborman slctab[func].current.val = val; 31138905Sborman flag |= SLC_ACK; 31238905Sborman } else if (hislevel == SLC_CANTCHANGE && 31338905Sborman mylevel == SLC_CANTCHANGE) { 31438905Sborman flag &= ~SLC_LEVELBITS; 31538905Sborman flag |= SLC_NOSUPPORT; 31638905Sborman slctab[func].current.flag = flag; 31738905Sborman } else { 31838905Sborman flag &= ~SLC_LEVELBITS; 31938905Sborman flag |= mylevel; 32038905Sborman slctab[func].current.flag = flag; 32138905Sborman if (mylevel == SLC_CANTCHANGE) { 32238905Sborman slctab[func].current.val = 32338905Sborman slctab[func].defset.val; 32438905Sborman val = slctab[func].current.val; 32538905Sborman } 32638905Sborman 32738905Sborman } 32838905Sborman add_slc(func, flag, val); 32938905Sborman } 33038905Sborman 33138905Sborman } /* end of change_slc */ 33238905Sborman 33340242Sborman #if defined(USE_TERMIO) && defined(SYSV_TERMIO) 33440242Sborman cc_t oldeofc = '\004'; 33540242Sborman #endif 33640242Sborman 33738905Sborman /* 33838905Sborman * check_slc 33938905Sborman * 34038905Sborman * Check the special characters in use and notify the client if any have 34138905Sborman * changed. Only those characters that are capable of being changed are 34238905Sborman * likely to have changed. If a local change occurs, kick the support level 34338905Sborman * and flags up to the defaults. 34438905Sborman */ 34538905Sborman check_slc() 34638905Sborman { 34738905Sborman register int i; 34838905Sborman 34938905Sborman for (i = 1; i <= NSLC; i++) { 35038905Sborman #if defined(USE_TERMIO) && defined(SYSV_TERMIO) 35138905Sborman /* 35238905Sborman * In a perfect world this would be a neat little 35338905Sborman * function. But in this world, we should not notify 35438905Sborman * client of changes to the VEOF char when 35538905Sborman * ICANON is off, because it is not representing 35638905Sborman * a special character. 35738905Sborman */ 35840242Sborman if (i == SLC_EOF) { 35940242Sborman if (!tty_isediting()) 36040242Sborman continue; 36140242Sborman else if (slctab[i].sptr) 36240242Sborman oldeofc = *(slctab[i].sptr); 36340242Sborman } 36438905Sborman #endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */ 36538905Sborman if (slctab[i].sptr && 36638905Sborman (*(slctab[i].sptr) != slctab[i].current.val)) { 36738905Sborman slctab[i].current.val = *(slctab[i].sptr); 36838905Sborman slctab[i].current.flag = slctab[i].defset.flag; 36938905Sborman add_slc((unsigned char)i, slctab[i].current.flag, 37038905Sborman slctab[i].current.val); 37138905Sborman } 37238905Sborman } 37338905Sborman 37438905Sborman } /* check_slc */ 37538905Sborman 37638905Sborman /* 37738905Sborman * do_opt_slc 37838905Sborman * 37938905Sborman * Process an slc option buffer. Defer processing of incoming slc's 38038905Sborman * until after the terminal state has been processed. Save the first slc 38138905Sborman * request that comes along, but discard all others. 38238905Sborman * 38338905Sborman * ptr points to the beginning of the buffer, len is the length. 38438905Sborman */ 38538905Sborman do_opt_slc(ptr, len) 38638905Sborman register char *ptr; 38738905Sborman register int len; 38838905Sborman { 38940242Sborman register unsigned char func, flag; 39040242Sborman cc_t val; 39138905Sborman register char *end = (char *)(ptr + len); 39238905Sborman char *malloc(); 39338905Sborman 39438905Sborman if (terminit()) { /* go ahead */ 39538905Sborman while (ptr < end) { 39638905Sborman func = *ptr++; 39738905Sborman if (ptr >= end) break; 39838905Sborman flag = *ptr++; 39938905Sborman if (ptr >= end) break; 40040242Sborman val = (cc_t)*ptr++; 40138905Sborman 40238905Sborman process_slc(func, flag, val); 40338905Sborman 40438905Sborman } 40538905Sborman } else { 40638905Sborman /* 40738905Sborman * save this slc buffer if it is the first, otherwise dump 40838905Sborman * it. 40938905Sborman */ 410*44364Sborman if (def_slcbuf == (unsigned char *)0) { 41138905Sborman def_slclen = len; 412*44364Sborman def_slcbuf = (unsigned char *)malloc((unsigned)len); 413*44364Sborman if (def_slcbuf == (unsigned char *)0) 41438905Sborman return; /* too bad */ 41538905Sborman bcopy(ptr, def_slcbuf, len); 41638905Sborman } 41738905Sborman } 41838905Sborman 41938905Sborman } /* end of do_opt_slc */ 42038905Sborman 42138905Sborman /* 42238905Sborman * deferslc 42338905Sborman * 42438905Sborman * Do slc stuff that was deferred. 42538905Sborman */ 42638905Sborman deferslc() 42738905Sborman { 42838905Sborman if (def_slcbuf) { 42938905Sborman start_slc(1); 43038905Sborman do_opt_slc(def_slcbuf, def_slclen); 43138905Sborman end_slc(0); 43238905Sborman free(def_slcbuf); 433*44364Sborman def_slcbuf = (unsigned char *)0; 43438905Sborman def_slclen = 0; 43538905Sborman } 43638905Sborman 43738905Sborman } /* end of deferslc */ 43838905Sborman 43938905Sborman #endif /* LINEMODE */ 440