Oops, remove comma.
[dragonfly.git] / libexec / telnetd / slc.c
1 /*
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)slc.c    8.2 (Berkeley) 5/30/95
34  * $FreeBSD: src/libexec/telnetd/slc.c,v 1.8.2.4 2002/04/13 11:07:12 markm Exp $
35  * $DragonFly: src/libexec/telnetd/slc.c,v 1.2 2003/06/17 04:27:08 dillon Exp $
36  */
37
38 #include "telnetd.h"
39
40 #ifdef  LINEMODE
41 /*
42  * local variables
43  */
44 static unsigned char    *def_slcbuf = (unsigned char *)0;
45 static int              def_slclen = 0;
46 static int              slcchange;      /* change to slc is requested */
47 static unsigned char    *slcptr;        /* pointer into slc buffer */
48 static unsigned char    slcbuf[NSLC*6]; /* buffer for slc negotiation */
49
50 /*
51  * send_slc
52  *
53  * Write out the current special characters to the client.
54  */
55 void
56 send_slc(void)
57 {
58         int i;
59
60         /*
61          * Send out list of triplets of special characters
62          * to client.  We only send info on the characters
63          * that are currently supported.
64          */
65         for (i = 1; i <= NSLC; i++) {
66                 if ((slctab[i].defset.flag & SLC_LEVELBITS) == SLC_NOSUPPORT)
67                         continue;
68                 add_slc((unsigned char)i, slctab[i].current.flag,
69                                                         slctab[i].current.val);
70         }
71
72 }  /* end of send_slc */
73
74 /*
75  * default_slc
76  *
77  * Set pty special characters to all the defaults.
78  */
79 static void
80 default_slc(void)
81 {
82         int i;
83
84         for (i = 1; i <= NSLC; i++) {
85                 slctab[i].current.val = slctab[i].defset.val;
86                 if (slctab[i].current.val == (cc_t)(_POSIX_VDISABLE))
87                         slctab[i].current.flag = SLC_NOSUPPORT;
88                 else
89                         slctab[i].current.flag = slctab[i].defset.flag;
90                 if (slctab[i].sptr) {
91                         *(slctab[i].sptr) = slctab[i].defset.val;
92                 }
93         }
94         slcchange = 1;
95
96 }  /* end of default_slc */
97 #endif  /* LINEMODE */
98
99 /*
100  * get_slc_defaults
101  *
102  * Initialize the slc mapping table.
103  */
104 void
105 get_slc_defaults(void)
106 {
107         int i;
108
109         init_termbuf();
110
111         for (i = 1; i <= NSLC; i++) {
112                 slctab[i].defset.flag =
113                         spcset(i, &slctab[i].defset.val, &slctab[i].sptr);
114                 slctab[i].current.flag = SLC_NOSUPPORT;
115                 slctab[i].current.val = 0;
116         }
117
118 }  /* end of get_slc_defaults */
119
120 #ifdef  LINEMODE
121 /*
122  * add_slc
123  *
124  * Add an slc triplet to the slc buffer.
125  */
126 void
127 add_slc(char func, char flag, cc_t val)
128 {
129
130         if ((*slcptr++ = (unsigned char)func) == 0xff)
131                 *slcptr++ = 0xff;
132
133         if ((*slcptr++ = (unsigned char)flag) == 0xff)
134                 *slcptr++ = 0xff;
135
136         if ((*slcptr++ = (unsigned char)val) == 0xff)
137                 *slcptr++ = 0xff;
138
139 }  /* end of add_slc */
140
141 /*
142  * start_slc
143  *
144  * Get ready to process incoming slc's and respond to them.
145  *
146  * The parameter getit is non-zero if it is necessary to grab a copy
147  * of the terminal control structures.
148  */
149 void
150 start_slc(int getit)
151 {
152
153         slcchange = 0;
154         if (getit)
155                 init_termbuf();
156         (void) sprintf((char *)slcbuf, "%c%c%c%c",
157                                         IAC, SB, TELOPT_LINEMODE, LM_SLC);
158         slcptr = slcbuf + 4;
159
160 }  /* end of start_slc */
161
162 /*
163  * end_slc
164  *
165  * Finish up the slc negotiation.  If something to send, then send it.
166  */
167 int
168 end_slc(unsigned char **bufp)
169 {
170         int len;
171
172         /*
173          * If a change has occured, store the new terminal control
174          * structures back to the terminal driver.
175          */
176         if (slcchange) {
177                 set_termbuf();
178         }
179
180         /*
181          * If the pty state has not yet been fully processed and there is a
182          * deferred slc request from the client, then do not send any
183          * sort of slc negotiation now.  We will respond to the client's
184          * request very soon.
185          */
186         if (def_slcbuf && (terminit() == 0)) {
187                 return(0);
188         }
189
190         if (slcptr > (slcbuf + 4)) {
191                 if (bufp) {
192                         *bufp = &slcbuf[4];
193                         return(slcptr - slcbuf - 4);
194                 } else {
195                         (void) sprintf((char *)slcptr, "%c%c", IAC, SE);
196                         slcptr += 2;
197                         len = slcptr - slcbuf;
198                         output_datalen(slcbuf, len);
199                         netflush();  /* force it out immediately */
200                         DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2););
201                 }
202         }
203         return (0);
204
205 }  /* end of end_slc */
206
207 /*
208  * process_slc
209  *
210  * Figure out what to do about the client's slc
211  */
212 void
213 process_slc(unsigned char func, unsigned char flag, cc_t val)
214 {
215         int hislevel, mylevel, ack;
216
217         /*
218          * Ensure that we know something about this function
219          */
220         if (func > NSLC) {
221                 add_slc(func, SLC_NOSUPPORT, 0);
222                 return;
223         }
224
225         /*
226          * Process the special case requests of 0 SLC_DEFAULT 0
227          * and 0 SLC_VARIABLE 0.  Be a little forgiving here, don't
228          * worry about whether the value is actually 0 or not.
229          */
230         if (func == 0) {
231                 if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) {
232                         default_slc();
233                         send_slc();
234                 } else if (flag == SLC_VARIABLE) {
235                         send_slc();
236                 }
237                 return;
238         }
239
240         /*
241          * Appears to be a function that we know something about.  So
242          * get on with it and see what we know.
243          */
244
245         hislevel = flag & SLC_LEVELBITS;
246         mylevel = slctab[func].current.flag & SLC_LEVELBITS;
247         ack = flag & SLC_ACK;
248         /*
249          * ignore the command if:
250          * the function value and level are the same as what we already have;
251          * or the level is the same and the ack bit is set
252          */
253         if (hislevel == mylevel && (val == slctab[func].current.val || ack)) {
254                 return;
255         } else if (ack) {
256                 /*
257                  * If we get here, we got an ack, but the levels don't match.
258                  * This shouldn't happen.  If it does, it is probably because
259                  * we have sent two requests to set a variable without getting
260                  * a response between them, and this is the first response.
261                  * So, ignore it, and wait for the next response.
262                  */
263                 return;
264         } else {
265                 change_slc(func, flag, val);
266         }
267
268 }  /* end of process_slc */
269
270 /*
271  * change_slc
272  *
273  * Process a request to change one of our special characters.
274  * Compare client's request with what we are capable of supporting.
275  */
276 void
277 change_slc(char func, char flag, cc_t val)
278 {
279         int hislevel, mylevel;
280
281         hislevel = flag & SLC_LEVELBITS;
282         mylevel = slctab[(int)func].defset.flag & SLC_LEVELBITS;
283         /*
284          * If client is setting a function to NOSUPPORT
285          * or DEFAULT, then we can easily and directly
286          * accomodate the request.
287          */
288         if (hislevel == SLC_NOSUPPORT) {
289                 slctab[(int)func].current.flag = flag;
290                 slctab[(int)func].current.val = (cc_t)_POSIX_VDISABLE;
291                 flag |= SLC_ACK;
292                 add_slc(func, flag, val);
293                 return;
294         }
295         if (hislevel == SLC_DEFAULT) {
296                 /*
297                  * Special case here.  If client tells us to use
298                  * the default on a function we don't support, then
299                  * return NOSUPPORT instead of what we may have as a
300                  * default level of DEFAULT.
301                  */
302                 if (mylevel == SLC_DEFAULT) {
303                         slctab[(int)func].current.flag = SLC_NOSUPPORT;
304                 } else {
305                         slctab[(int)func].current.flag = slctab[(int)func].defset.flag;
306                 }
307                 slctab[(int)func].current.val = slctab[(int)func].defset.val;
308                 add_slc(func, slctab[(int)func].current.flag,
309                                                 slctab[(int)func].current.val);
310                 return;
311         }
312
313         /*
314          * Client wants us to change to a new value or he
315          * is telling us that he can't change to our value.
316          * Some of the slc's we support and can change,
317          * some we do support but can't change,
318          * and others we don't support at all.
319          * If we can change it then we have a pointer to
320          * the place to put the new value, so change it,
321          * otherwise, continue the negotiation.
322          */
323         if (slctab[(int)func].sptr) {
324                 /*
325                  * We can change this one.
326                  */
327                 slctab[(int)func].current.val = val;
328                 *(slctab[(int)func].sptr) = val;
329                 slctab[(int)func].current.flag = flag;
330                 flag |= SLC_ACK;
331                 slcchange = 1;
332                 add_slc(func, flag, val);
333         } else {
334                 /*
335                 * It is not possible for us to support this
336                 * request as he asks.
337                 *
338                 * If our level is DEFAULT, then just ack whatever was
339                 * sent.
340                 *
341                 * If he can't change and we can't change,
342                 * then degenerate to NOSUPPORT.
343                 *
344                 * Otherwise we send our level back to him, (CANTCHANGE
345                 * or NOSUPPORT) and if CANTCHANGE, send
346                 * our value as well.
347                 */
348                 if (mylevel == SLC_DEFAULT) {
349                         slctab[(int)func].current.flag = flag;
350                         slctab[(int)func].current.val = val;
351                         flag |= SLC_ACK;
352                 } else if (hislevel == SLC_CANTCHANGE &&
353                                     mylevel == SLC_CANTCHANGE) {
354                         flag &= ~SLC_LEVELBITS;
355                         flag |= SLC_NOSUPPORT;
356                         slctab[(int)func].current.flag = flag;
357                 } else {
358                         flag &= ~SLC_LEVELBITS;
359                         flag |= mylevel;
360                         slctab[(int)func].current.flag = flag;
361                         if (mylevel == SLC_CANTCHANGE) {
362                                 slctab[(int)func].current.val =
363                                         slctab[(int)func].defset.val;
364                                 val = slctab[(int)func].current.val;
365                         }
366                 }
367                 add_slc(func, flag, val);
368         }
369
370 }  /* end of change_slc */
371
372 #if     defined(USE_TERMIO) && (VEOF == VMIN)
373 cc_t oldeofc = '\004';
374 #endif
375
376 /*
377  * check_slc
378  *
379  * Check the special characters in use and notify the client if any have
380  * changed.  Only those characters that are capable of being changed are
381  * likely to have changed.  If a local change occurs, kick the support level
382  * and flags up to the defaults.
383  */
384 void
385 check_slc(void)
386 {
387         int i;
388
389         for (i = 1; i <= NSLC; i++) {
390 #if     defined(USE_TERMIO) && (VEOF == VMIN)
391                 /*
392                  * In a perfect world this would be a neat little
393                  * function.  But in this world, we should not notify
394                  * client of changes to the VEOF char when
395                  * ICANON is off, because it is not representing
396                  * a special character.
397                  */
398                 if (i == SLC_EOF) {
399                         if (!tty_isediting())
400                                 continue;
401                         else if (slctab[i].sptr)
402                                 oldeofc = *(slctab[i].sptr);
403                 }
404 #endif  /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */
405                 if (slctab[i].sptr &&
406                                 (*(slctab[i].sptr) != slctab[i].current.val)) {
407                         slctab[i].current.val = *(slctab[i].sptr);
408                         if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE)
409                                 slctab[i].current.flag = SLC_NOSUPPORT;
410                         else
411                                 slctab[i].current.flag = slctab[i].defset.flag;
412                         add_slc((unsigned char)i, slctab[i].current.flag,
413                                                 slctab[i].current.val);
414                 }
415         }
416 }  /* check_slc */
417
418 /*
419  * do_opt_slc
420  *
421  * Process an slc option buffer.  Defer processing of incoming slc's
422  * until after the terminal state has been processed.  Save the first slc
423  * request that comes along, but discard all others.
424  *
425  * ptr points to the beginning of the buffer, len is the length.
426  */
427 void
428 do_opt_slc(unsigned char *ptr, int len)
429 {
430         unsigned char func, flag;
431         cc_t val;
432         unsigned char *end = ptr + len;
433
434         if (terminit()) {  /* go ahead */
435                 while (ptr < end) {
436                         func = *ptr++;
437                         if (ptr >= end) break;
438                         flag = *ptr++;
439                         if (ptr >= end) break;
440                         val = (cc_t)*ptr++;
441
442                         process_slc(func, flag, val);
443
444                 }
445         } else {
446                 /*
447                  * save this slc buffer if it is the first, otherwise dump
448                  * it.
449                  */
450                 if (def_slcbuf == (unsigned char *)0) {
451                         def_slclen = len;
452                         def_slcbuf = (unsigned char *)malloc((unsigned)len);
453                         if (def_slcbuf == (unsigned char *)0)
454                                 return;  /* too bad */
455                         memmove(def_slcbuf, ptr, len);
456                 }
457         }
458
459 }  /* end of do_opt_slc */
460
461 /*
462  * deferslc
463  *
464  * Do slc stuff that was deferred.
465  */
466 void
467 deferslc(void)
468 {
469         if (def_slcbuf) {
470                 start_slc(1);
471                 do_opt_slc(def_slcbuf, def_slclen);
472                 (void) end_slc(0);
473                 free(def_slcbuf);
474                 def_slcbuf = (unsigned char *)0;
475                 def_slclen = 0;
476         }
477
478 }  /* end of deferslc */
479
480 #endif  /* LINEMODE */