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