]> git.saurik.com Git - apple/network_cmds.git/blob - telnetd.tproj/slc.c
a7b280def0faea914f0d26da57e46c202ae8546c
[apple/network_cmds.git] / telnetd.tproj / slc.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
12 * this file.
13 *
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
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * Copyright (c) 1989, 1993
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
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.
43 *
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
54 * SUCH DAMAGE.
55 */
56
57 #ifndef lint
58 static char sccsid[] = "@(#)slc.c 8.2 (Berkeley) 5/30/95";
59 #endif /* not lint */
60
61 #include "telnetd.h"
62
63 #ifdef LINEMODE
64 /*
65 * local varibles
66 */
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 */
72
73 /*
74 * send_slc
75 *
76 * Write out the current special characters to the client.
77 */
78 void
79 send_slc()
80 {
81 register int i;
82
83 /*
84 * Send out list of triplets of special characters
85 * to client. We only send info on the characters
86 * that are currently supported.
87 */
88 for (i = 1; i <= NSLC; i++) {
89 if ((slctab[i].defset.flag & SLC_LEVELBITS) == SLC_NOSUPPORT)
90 continue;
91 add_slc((unsigned char)i, slctab[i].current.flag,
92 slctab[i].current.val);
93 }
94
95 } /* end of send_slc */
96
97 /*
98 * default_slc
99 *
100 * Set pty special characters to all the defaults.
101 */
102 void
103 default_slc()
104 {
105 register int i;
106
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;
111 else
112 slctab[i].current.flag = slctab[i].defset.flag;
113 if (slctab[i].sptr) {
114 *(slctab[i].sptr) = slctab[i].defset.val;
115 }
116 }
117 slcchange = 1;
118
119 } /* end of default_slc */
120 #endif /* LINEMODE */
121
122 /*
123 * get_slc_defaults
124 *
125 * Initialize the slc mapping table.
126 */
127 void
128 get_slc_defaults()
129 {
130 register int i;
131
132 init_termbuf();
133
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;
139 }
140
141 } /* end of get_slc_defaults */
142
143 #ifdef LINEMODE
144 /*
145 * add_slc
146 *
147 * Add an slc triplet to the slc buffer.
148 */
149 void
150 add_slc(func, flag, val)
151 register char func, flag;
152 register cc_t val;
153 {
154
155 if ((*slcptr++ = (unsigned char)func) == 0xff)
156 *slcptr++ = 0xff;
157
158 if ((*slcptr++ = (unsigned char)flag) == 0xff)
159 *slcptr++ = 0xff;
160
161 if ((*slcptr++ = (unsigned char)val) == 0xff)
162 *slcptr++ = 0xff;
163
164 } /* end of add_slc */
165
166 /*
167 * start_slc
168 *
169 * Get ready to process incoming slc's and respond to them.
170 *
171 * The parameter getit is non-zero if it is necessary to grab a copy
172 * of the terminal control structures.
173 */
174 void
175 start_slc(getit)
176 register int getit;
177 {
178
179 slcchange = 0;
180 if (getit)
181 init_termbuf();
182 (void) sprintf((char *)slcbuf, "%c%c%c%c",
183 IAC, SB, TELOPT_LINEMODE, LM_SLC);
184 slcptr = slcbuf + 4;
185
186 } /* end of start_slc */
187
188 /*
189 * end_slc
190 *
191 * Finish up the slc negotiation. If something to send, then send it.
192 */
193 int
194 end_slc(bufp)
195 register unsigned char **bufp;
196 {
197 register int len;
198 void netflush();
199
200 /*
201 * If a change has occured, store the new terminal control
202 * structures back to the terminal driver.
203 */
204 if (slcchange) {
205 set_termbuf();
206 }
207
208 /*
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
212 * request very soon.
213 */
214 if (def_slcbuf && (terminit() == 0)) {
215 return(0);
216 }
217
218 if (slcptr > (slcbuf + 4)) {
219 if (bufp) {
220 *bufp = &slcbuf[4];
221 return(slcptr - slcbuf - 4);
222 } else {
223 (void) sprintf((char *)slcptr, "%c%c", IAC, SE);
224 slcptr += 2;
225 len = slcptr - slcbuf;
226 writenet(slcbuf, len);
227 netflush(); /* force it out immediately */
228 DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2););
229 }
230 }
231 return (0);
232
233 } /* end of end_slc */
234
235 /*
236 * process_slc
237 *
238 * Figure out what to do about the client's slc
239 */
240 void
241 process_slc(func, flag, val)
242 register unsigned char func, flag;
243 register cc_t val;
244 {
245 register int hislevel, mylevel, ack;
246
247 /*
248 * Ensure that we know something about this function
249 */
250 if (func > NSLC) {
251 add_slc(func, SLC_NOSUPPORT, 0);
252 return;
253 }
254
255 /*
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.
259 */
260 if (func == 0) {
261 if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) {
262 default_slc();
263 send_slc();
264 } else if (flag == SLC_VARIABLE) {
265 send_slc();
266 }
267 return;
268 }
269
270 /*
271 * Appears to be a function that we know something about. So
272 * get on with it and see what we know.
273 */
274
275 hislevel = flag & SLC_LEVELBITS;
276 mylevel = slctab[func].current.flag & SLC_LEVELBITS;
277 ack = flag & SLC_ACK;
278 /*
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
282 */
283 if (hislevel == mylevel && (val == slctab[func].current.val || ack)) {
284 return;
285 } else if (ack) {
286 /*
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.
292 */
293 return;
294 } else {
295 change_slc(func, flag, val);
296 }
297
298 } /* end of process_slc */
299
300 /*
301 * change_slc
302 *
303 * Process a request to change one of our special characters.
304 * Compare client's request with what we are capable of supporting.
305 */
306 void
307 change_slc(func, flag, val)
308 register char func, flag;
309 register cc_t val;
310 {
311 register int hislevel, mylevel;
312
313 hislevel = flag & SLC_LEVELBITS;
314 mylevel = slctab[func].defset.flag & SLC_LEVELBITS;
315 /*
316 * If client is setting a function to NOSUPPORT
317 * or DEFAULT, then we can easily and directly
318 * accomodate the request.
319 */
320 if (hislevel == SLC_NOSUPPORT) {
321 slctab[func].current.flag = flag;
322 slctab[func].current.val = (cc_t)_POSIX_VDISABLE;
323 flag |= SLC_ACK;
324 add_slc(func, flag, val);
325 return;
326 }
327 if (hislevel == SLC_DEFAULT) {
328 /*
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.
333 */
334 if (mylevel == SLC_DEFAULT) {
335 slctab[func].current.flag = SLC_NOSUPPORT;
336 } else {
337 slctab[func].current.flag = slctab[func].defset.flag;
338 }
339 slctab[func].current.val = slctab[func].defset.val;
340 add_slc(func, slctab[func].current.flag,
341 slctab[func].current.val);
342 return;
343 }
344
345 /*
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.
354 */
355 if (slctab[func].sptr) {
356 /*
357 * We can change this one.
358 */
359 slctab[func].current.val = val;
360 *(slctab[func].sptr) = val;
361 slctab[func].current.flag = flag;
362 flag |= SLC_ACK;
363 slcchange = 1;
364 add_slc(func, flag, val);
365 } else {
366 /*
367 * It is not possible for us to support this
368 * request as he asks.
369 *
370 * If our level is DEFAULT, then just ack whatever was
371 * sent.
372 *
373 * If he can't change and we can't change,
374 * then degenerate to NOSUPPORT.
375 *
376 * Otherwise we send our level back to him, (CANTCHANGE
377 * or NOSUPPORT) and if CANTCHANGE, send
378 * our value as well.
379 */
380 if (mylevel == SLC_DEFAULT) {
381 slctab[func].current.flag = flag;
382 slctab[func].current.val = val;
383 flag |= SLC_ACK;
384 } else if (hislevel == SLC_CANTCHANGE &&
385 mylevel == SLC_CANTCHANGE) {
386 flag &= ~SLC_LEVELBITS;
387 flag |= SLC_NOSUPPORT;
388 slctab[func].current.flag = flag;
389 } else {
390 flag &= ~SLC_LEVELBITS;
391 flag |= mylevel;
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;
397 }
398 }
399 add_slc(func, flag, val);
400 }
401
402 } /* end of change_slc */
403
404 #if defined(USE_TERMIO) && (VEOF == VMIN)
405 cc_t oldeofc = '\004';
406 #endif
407
408 /*
409 * check_slc
410 *
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.
415 */
416 void
417 check_slc()
418 {
419 register int i;
420
421 for (i = 1; i <= NSLC; i++) {
422 #if defined(USE_TERMIO) && (VEOF == VMIN)
423 /*
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.
429 */
430 if (i == SLC_EOF) {
431 if (!tty_isediting())
432 continue;
433 else if (slctab[i].sptr)
434 oldeofc = *(slctab[i].sptr);
435 }
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;
442 else
443 slctab[i].current.flag = slctab[i].defset.flag;
444 add_slc((unsigned char)i, slctab[i].current.flag,
445 slctab[i].current.val);
446 }
447 }
448 } /* check_slc */
449
450 /*
451 * do_opt_slc
452 *
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.
456 *
457 * ptr points to the beginning of the buffer, len is the length.
458 */
459 void
460 do_opt_slc(ptr, len)
461 register unsigned char *ptr;
462 register int len;
463 {
464 register unsigned char func, flag;
465 cc_t val;
466 register unsigned char *end = ptr + len;
467
468 if (terminit()) { /* go ahead */
469 while (ptr < end) {
470 func = *ptr++;
471 if (ptr >= end) break;
472 flag = *ptr++;
473 if (ptr >= end) break;
474 val = (cc_t)*ptr++;
475
476 process_slc(func, flag, val);
477
478 }
479 } else {
480 /*
481 * save this slc buffer if it is the first, otherwise dump
482 * it.
483 */
484 if (def_slcbuf == (unsigned char *)0) {
485 def_slclen = len;
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);
490 }
491 }
492
493 } /* end of do_opt_slc */
494
495 /*
496 * deferslc
497 *
498 * Do slc stuff that was deferred.
499 */
500 void
501 deferslc()
502 {
503 if (def_slcbuf) {
504 start_slc(1);
505 do_opt_slc(def_slcbuf, def_slclen);
506 (void) end_slc(0);
507 free(def_slcbuf);
508 def_slcbuf = (unsigned char *)0;
509 def_slclen = 0;
510 }
511
512 } /* end of deferslc */
513
514 #endif /* LINEMODE */