* Copyright (c) 1989 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)slc.c 5.7 (Berkeley) 3/1/91";
static unsigned char *def_slcbuf
= (unsigned char *)0;
static int def_slclen
= 0;
static int slcchange
; /* change to slc is requested */
static unsigned char *slcptr
; /* pointer into slc buffer */
static unsigned char slcbuf
[NSLC
*6]; /* buffer for slc negotiation */
* Write out the current special characters to the client.
* Send out list of triplets of special characters
* to client. We only send info on the characters
* that are currently supported.
for (i
= 1; i
<= NSLC
; i
++) {
if ((slctab
[i
].defset
.flag
& SLC_LEVELBITS
) == SLC_NOSUPPORT
)
add_slc((unsigned char)i
, slctab
[i
].current
.flag
,
* Set pty special characters to all the defaults.
for (i
= 1; i
<= NSLC
; i
++) {
slctab
[i
].current
.val
= slctab
[i
].defset
.val
;
if (slctab
[i
].current
.val
== (cc_t
)(_POSIX_VDISABLE
))
slctab
[i
].current
.flag
= SLC_NOSUPPORT
;
slctab
[i
].current
.flag
= slctab
[i
].defset
.flag
;
*(slctab
[i
].sptr
) = slctab
[i
].defset
.val
;
} /* end of default_slc */
* Initialize the slc mapping table.
for (i
= 1; i
<= NSLC
; i
++) {
spcset(i
, &slctab
[i
].defset
.val
, &slctab
[i
].sptr
);
slctab
[i
].current
.flag
= SLC_NOSUPPORT
;
slctab
[i
].current
.val
= 0;
} /* end of get_slc_defaults */
* Add an slc triplet to the slc buffer.
register char func
, flag
;
if ((*slcptr
++ = (unsigned char)func
) == 0xff)
if ((*slcptr
++ = (unsigned char)flag
) == 0xff)
if ((*slcptr
++ = (unsigned char)val
) == 0xff)
* Get ready to process incoming slc's and respond to them.
* The parameter getit is non-zero if it is necessary to grab a copy
* of the terminal control structures.
(void) sprintf((char *)slcbuf
, "%c%c%c%c",
IAC
, SB
, TELOPT_LINEMODE
, LM_SLC
);
* Finish up the slc negotiation. If something to send, then send it.
register unsigned char **bufp
;
* If a change has occured, store the new terminal control
* structures back to the terminal driver.
* If the pty state has not yet been fully processed and there is a
* deferred slc request from the client, then do not send any
* sort of slc negotiation now. We will respond to the client's
if (def_slcbuf
&& (terminit() == 0)) {
if (slcptr
> (slcbuf
+ 4)) {
return(slcptr
- slcbuf
- 4);
(void) sprintf((char *)slcptr
, "%c%c", IAC
, SE
);
netflush(); /* force it out immediately */
* Figure out what to do about the client's slc
process_slc(func
, flag
, val
)
register unsigned char func
, flag
;
register int hislevel
, mylevel
, ack
;
* Ensure that we know something about this function
add_slc(func
, SLC_NOSUPPORT
, 0);
* Process the special case requests of 0 SLC_DEFAULT 0
* and 0 SLC_VARIABLE 0. Be a little forgiving here, don't
* worry about whether the value is actually 0 or not.
if ((flag
= flag
& SLC_LEVELBITS
) == SLC_DEFAULT
) {
} else if (flag
== SLC_VARIABLE
) {
* Appears to be a function that we know something about. So
* get on with it and see what we know.
hislevel
= flag
& SLC_LEVELBITS
;
mylevel
= slctab
[func
].current
.flag
& SLC_LEVELBITS
;
* the function value and level are the same as what we already have;
* or the level is the same and the ack bit is set
if (hislevel
== mylevel
&& (val
== slctab
[func
].current
.val
|| ack
)) {
* If we get here, we got an ack, but the levels don't match.
* This shouldn't happen. If it does, it is probably because
* we have sent two requests to set a variable without getting
* a response between them, and this is the first response.
* So, ignore it, and wait for the next response.
change_slc(func
, flag
, val
);
} /* end of process_slc */
* Process a request to change one of our special characters.
* Compare client's request with what we are capable of supporting.
change_slc(func
, flag
, val
)
register char func
, flag
;
register int hislevel
, mylevel
;
hislevel
= flag
& SLC_LEVELBITS
;
mylevel
= slctab
[func
].defset
.flag
& SLC_LEVELBITS
;
* If client is setting a function to NOSUPPORT
* or DEFAULT, then we can easily and directly
* accomodate the request.
if (hislevel
== SLC_NOSUPPORT
) {
slctab
[func
].current
.flag
= flag
;
slctab
[func
].current
.val
= (cc_t
)_POSIX_VDISABLE
;
add_slc(func
, flag
, val
);
if (hislevel
== SLC_DEFAULT
) {
* Special case here. If client tells us to use
* the default on a function we don't support, then
* return NOSUPPORT instead of what we may have as a
* default level of DEFAULT.
if (mylevel
== SLC_DEFAULT
) {
slctab
[func
].current
.flag
= SLC_NOSUPPORT
;
slctab
[func
].current
.flag
= slctab
[func
].defset
.flag
;
slctab
[func
].current
.val
= slctab
[func
].defset
.val
;
add_slc(func
, slctab
[func
].current
.flag
,
slctab
[func
].current
.val
);
* Client wants us to change to a new value or he
* is telling us that he can't change to our value.
* Some of the slc's we support and can change,
* some we do support but can't change,
* and others we don't support at all.
* If we can change it then we have a pointer to
* the place to put the new value, so change it,
* otherwise, continue the negotiation.
* We can change this one.
slctab
[func
].current
.val
= val
;
*(slctab
[func
].sptr
) = val
;
slctab
[func
].current
.flag
= flag
;
add_slc(func
, flag
, val
);
* It is not possible for us to support this
* If our level is DEFAULT, then just ack whatever was
* If he can't change and we can't change,
* then degenerate to NOSUPPORT.
* Otherwise we send our level back to him, (CANTCHANGE
* or NOSUPPORT) and if CANTCHANGE, send
if (mylevel
== SLC_DEFAULT
) {
slctab
[func
].current
.flag
= flag
;
slctab
[func
].current
.val
= val
;
} else if (hislevel
== SLC_CANTCHANGE
&&
mylevel
== SLC_CANTCHANGE
) {
slctab
[func
].current
.flag
= flag
;
slctab
[func
].current
.flag
= flag
;
if (mylevel
== SLC_CANTCHANGE
) {
slctab
[func
].current
.val
=
val
= slctab
[func
].current
.val
;
add_slc(func
, flag
, val
);
} /* end of change_slc */
#if defined(USE_TERMIO) && (VEOF == VMIN)
* Check the special characters in use and notify the client if any have
* changed. Only those characters that are capable of being changed are
* likely to have changed. If a local change occurs, kick the support level
* and flags up to the defaults.
for (i
= 1; i
<= NSLC
; i
++) {
#if defined(USE_TERMIO) && (VEOF == VMIN)
* In a perfect world this would be a neat little
* function. But in this world, we should not notify
* client of changes to the VEOF char when
* ICANON is off, because it is not representing
oldeofc
= *(slctab
[i
].sptr
);
#endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */
(*(slctab
[i
].sptr
) != slctab
[i
].current
.val
)) {
slctab
[i
].current
.val
= *(slctab
[i
].sptr
);
if (*(slctab
[i
].sptr
) == (cc_t
)_POSIX_VDISABLE
)
slctab
[i
].current
.flag
= SLC_NOSUPPORT
;
slctab
[i
].current
.flag
= slctab
[i
].defset
.flag
;
add_slc((unsigned char)i
, slctab
[i
].current
.flag
,
* Process an slc option buffer. Defer processing of incoming slc's
* until after the terminal state has been processed. Save the first slc
* request that comes along, but discard all others.
* ptr points to the beginning of the buffer, len is the length.
register unsigned char *ptr
;
register unsigned char func
, flag
;
register unsigned char *end
= ptr
+ len
;
if (terminit()) { /* go ahead */
process_slc(func
, flag
, val
);
* save this slc buffer if it is the first, otherwise dump
if (def_slcbuf
== (unsigned char *)0) {
def_slcbuf
= (unsigned char *)malloc((unsigned)len
);
if (def_slcbuf
== (unsigned char *)0)
bcopy(ptr
, def_slcbuf
, len
);
} /* end of do_opt_slc */
* Do slc stuff that was deferred.
do_opt_slc(def_slcbuf
, def_slclen
);
def_slcbuf
= (unsigned char *)0;