]>
git.saurik.com Git - apple/network_cmds.git/blob - telnetd.tproj/slc.c
a7b280def0faea914f0d26da57e46c202ae8546c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1989, 1993
26 * The Regents of the University of California. All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 static char sccsid
[] = "@(#)slc.c 8.2 (Berkeley) 5/30/95";
67 static unsigned char *def_slcbuf
= (unsigned char *)0;
68 static int def_slclen
= 0;
69 static int slcchange
; /* change to slc is requested */
70 static unsigned char *slcptr
; /* pointer into slc buffer */
71 static unsigned char slcbuf
[NSLC
*6]; /* buffer for slc negotiation */
76 * Write out the current special characters to the client.
84 * Send out list of triplets of special characters
85 * to client. We only send info on the characters
86 * that are currently supported.
88 for (i
= 1; i
<= NSLC
; i
++) {
89 if ((slctab
[i
].defset
.flag
& SLC_LEVELBITS
) == SLC_NOSUPPORT
)
91 add_slc((unsigned char)i
, slctab
[i
].current
.flag
,
92 slctab
[i
].current
.val
);
95 } /* end of send_slc */
100 * Set pty special characters to all the defaults.
107 for (i
= 1; i
<= NSLC
; i
++) {
108 slctab
[i
].current
.val
= slctab
[i
].defset
.val
;
109 if (slctab
[i
].current
.val
== (cc_t
)(_POSIX_VDISABLE
))
110 slctab
[i
].current
.flag
= SLC_NOSUPPORT
;
112 slctab
[i
].current
.flag
= slctab
[i
].defset
.flag
;
113 if (slctab
[i
].sptr
) {
114 *(slctab
[i
].sptr
) = slctab
[i
].defset
.val
;
119 } /* end of default_slc */
120 #endif /* LINEMODE */
125 * Initialize the slc mapping table.
134 for (i
= 1; i
<= NSLC
; i
++) {
135 slctab
[i
].defset
.flag
=
136 spcset(i
, &slctab
[i
].defset
.val
, &slctab
[i
].sptr
);
137 slctab
[i
].current
.flag
= SLC_NOSUPPORT
;
138 slctab
[i
].current
.val
= 0;
141 } /* end of get_slc_defaults */
147 * Add an slc triplet to the slc buffer.
150 add_slc(func
, flag
, val
)
151 register char func
, flag
;
155 if ((*slcptr
++ = (unsigned char)func
) == 0xff)
158 if ((*slcptr
++ = (unsigned char)flag
) == 0xff)
161 if ((*slcptr
++ = (unsigned char)val
) == 0xff)
164 } /* end of add_slc */
169 * Get ready to process incoming slc's and respond to them.
171 * The parameter getit is non-zero if it is necessary to grab a copy
172 * of the terminal control structures.
182 (void) sprintf((char *)slcbuf
, "%c%c%c%c",
183 IAC
, SB
, TELOPT_LINEMODE
, LM_SLC
);
186 } /* end of start_slc */
191 * Finish up the slc negotiation. If something to send, then send it.
195 register unsigned char **bufp
;
201 * If a change has occured, store the new terminal control
202 * structures back to the terminal driver.
209 * If the pty state has not yet been fully processed and there is a
210 * deferred slc request from the client, then do not send any
211 * sort of slc negotiation now. We will respond to the client's
214 if (def_slcbuf
&& (terminit() == 0)) {
218 if (slcptr
> (slcbuf
+ 4)) {
221 return(slcptr
- slcbuf
- 4);
223 (void) sprintf((char *)slcptr
, "%c%c", IAC
, SE
);
225 len
= slcptr
- slcbuf
;
226 writenet(slcbuf
, len
);
227 netflush(); /* force it out immediately */
228 DIAG(TD_OPTIONS
, printsub('>', slcbuf
+2, len
-2););
233 } /* end of end_slc */
238 * Figure out what to do about the client's slc
241 process_slc(func
, flag
, val
)
242 register unsigned char func
, flag
;
245 register int hislevel
, mylevel
, ack
;
248 * Ensure that we know something about this function
251 add_slc(func
, SLC_NOSUPPORT
, 0);
256 * Process the special case requests of 0 SLC_DEFAULT 0
257 * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't
258 * worry about whether the value is actually 0 or not.
261 if ((flag
= flag
& SLC_LEVELBITS
) == SLC_DEFAULT
) {
264 } else if (flag
== SLC_VARIABLE
) {
271 * Appears to be a function that we know something about. So
272 * get on with it and see what we know.
275 hislevel
= flag
& SLC_LEVELBITS
;
276 mylevel
= slctab
[func
].current
.flag
& SLC_LEVELBITS
;
277 ack
= flag
& SLC_ACK
;
279 * ignore the command if:
280 * the function value and level are the same as what we already have;
281 * or the level is the same and the ack bit is set
283 if (hislevel
== mylevel
&& (val
== slctab
[func
].current
.val
|| ack
)) {
287 * If we get here, we got an ack, but the levels don't match.
288 * This shouldn't happen. If it does, it is probably because
289 * we have sent two requests to set a variable without getting
290 * a response between them, and this is the first response.
291 * So, ignore it, and wait for the next response.
295 change_slc(func
, flag
, val
);
298 } /* end of process_slc */
303 * Process a request to change one of our special characters.
304 * Compare client's request with what we are capable of supporting.
307 change_slc(func
, flag
, val
)
308 register char func
, flag
;
311 register int hislevel
, mylevel
;
313 hislevel
= flag
& SLC_LEVELBITS
;
314 mylevel
= slctab
[func
].defset
.flag
& SLC_LEVELBITS
;
316 * If client is setting a function to NOSUPPORT
317 * or DEFAULT, then we can easily and directly
318 * accomodate the request.
320 if (hislevel
== SLC_NOSUPPORT
) {
321 slctab
[func
].current
.flag
= flag
;
322 slctab
[func
].current
.val
= (cc_t
)_POSIX_VDISABLE
;
324 add_slc(func
, flag
, val
);
327 if (hislevel
== SLC_DEFAULT
) {
329 * Special case here. If client tells us to use
330 * the default on a function we don't support, then
331 * return NOSUPPORT instead of what we may have as a
332 * default level of DEFAULT.
334 if (mylevel
== SLC_DEFAULT
) {
335 slctab
[func
].current
.flag
= SLC_NOSUPPORT
;
337 slctab
[func
].current
.flag
= slctab
[func
].defset
.flag
;
339 slctab
[func
].current
.val
= slctab
[func
].defset
.val
;
340 add_slc(func
, slctab
[func
].current
.flag
,
341 slctab
[func
].current
.val
);
346 * Client wants us to change to a new value or he
347 * is telling us that he can't change to our value.
348 * Some of the slc's we support and can change,
349 * some we do support but can't change,
350 * and others we don't support at all.
351 * If we can change it then we have a pointer to
352 * the place to put the new value, so change it,
353 * otherwise, continue the negotiation.
355 if (slctab
[func
].sptr
) {
357 * We can change this one.
359 slctab
[func
].current
.val
= val
;
360 *(slctab
[func
].sptr
) = val
;
361 slctab
[func
].current
.flag
= flag
;
364 add_slc(func
, flag
, val
);
367 * It is not possible for us to support this
368 * request as he asks.
370 * If our level is DEFAULT, then just ack whatever was
373 * If he can't change and we can't change,
374 * then degenerate to NOSUPPORT.
376 * Otherwise we send our level back to him, (CANTCHANGE
377 * or NOSUPPORT) and if CANTCHANGE, send
380 if (mylevel
== SLC_DEFAULT
) {
381 slctab
[func
].current
.flag
= flag
;
382 slctab
[func
].current
.val
= val
;
384 } else if (hislevel
== SLC_CANTCHANGE
&&
385 mylevel
== SLC_CANTCHANGE
) {
386 flag
&= ~SLC_LEVELBITS
;
387 flag
|= SLC_NOSUPPORT
;
388 slctab
[func
].current
.flag
= flag
;
390 flag
&= ~SLC_LEVELBITS
;
392 slctab
[func
].current
.flag
= flag
;
393 if (mylevel
== SLC_CANTCHANGE
) {
394 slctab
[func
].current
.val
=
395 slctab
[func
].defset
.val
;
396 val
= slctab
[func
].current
.val
;
399 add_slc(func
, flag
, val
);
402 } /* end of change_slc */
404 #if defined(USE_TERMIO) && (VEOF == VMIN)
405 cc_t oldeofc
= '\004';
411 * Check the special characters in use and notify the client if any have
412 * changed. Only those characters that are capable of being changed are
413 * likely to have changed. If a local change occurs, kick the support level
414 * and flags up to the defaults.
421 for (i
= 1; i
<= NSLC
; i
++) {
422 #if defined(USE_TERMIO) && (VEOF == VMIN)
424 * In a perfect world this would be a neat little
425 * function. But in this world, we should not notify
426 * client of changes to the VEOF char when
427 * ICANON is off, because it is not representing
428 * a special character.
431 if (!tty_isediting())
433 else if (slctab
[i
].sptr
)
434 oldeofc
= *(slctab
[i
].sptr
);
436 #endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */
437 if (slctab
[i
].sptr
&&
438 (*(slctab
[i
].sptr
) != slctab
[i
].current
.val
)) {
439 slctab
[i
].current
.val
= *(slctab
[i
].sptr
);
440 if (*(slctab
[i
].sptr
) == (cc_t
)_POSIX_VDISABLE
)
441 slctab
[i
].current
.flag
= SLC_NOSUPPORT
;
443 slctab
[i
].current
.flag
= slctab
[i
].defset
.flag
;
444 add_slc((unsigned char)i
, slctab
[i
].current
.flag
,
445 slctab
[i
].current
.val
);
453 * Process an slc option buffer. Defer processing of incoming slc's
454 * until after the terminal state has been processed. Save the first slc
455 * request that comes along, but discard all others.
457 * ptr points to the beginning of the buffer, len is the length.
461 register unsigned char *ptr
;
464 register unsigned char func
, flag
;
466 register unsigned char *end
= ptr
+ len
;
468 if (terminit()) { /* go ahead */
471 if (ptr
>= end
) break;
473 if (ptr
>= end
) break;
476 process_slc(func
, flag
, val
);
481 * save this slc buffer if it is the first, otherwise dump
484 if (def_slcbuf
== (unsigned char *)0) {
486 def_slcbuf
= (unsigned char *)malloc((unsigned)len
);
487 if (def_slcbuf
== (unsigned char *)0)
488 return; /* too bad */
489 memmove(def_slcbuf
, ptr
, len
);
493 } /* end of do_opt_slc */
498 * Do slc stuff that was deferred.
505 do_opt_slc(def_slcbuf
, def_slclen
);
508 def_slcbuf
= (unsigned char *)0;
512 } /* end of deferslc */
514 #endif /* LINEMODE */