2 * ldisc.c: PuTTY line discipline. Sits between the input coming
\r
3 * from keypresses in the window, and the output channel leading to
\r
4 * the back end. Implements echo and/or local line editing,
\r
5 * depending on what's currently configured.
\r
13 #include "terminal.h"
\r
21 * When the backend is not reporting true from sendok(), terminal
\r
22 * input that comes here is stored in this bufchain instead. When
\r
23 * the backend later decides it wants session input, we empty the
\r
24 * queue in ldisc_check_sendok_callback(), passing its contents on
\r
25 * to the backend. Before then, we also provide data from this
\r
26 * queue to term_get_userpass_input() via ldisc_get_input_token(),
\r
27 * to be interpreted as user responses to username and password
\r
28 * prompts during authentication.
\r
30 * Unfortunately, the data stored in this queue is not all of the
\r
31 * same type: our output to the backend consists of both raw bytes
\r
32 * sent to backend_send(), and also session specials such as
\r
33 * SS_EOL and SS_EC. So we have to encode our queued data in a way
\r
34 * that can represent both.
\r
36 * The encoding is private to this source file, so we can change
\r
37 * it if necessary and only have to worry about the encode and
\r
38 * decode functions here. Currently, it is:
\r
40 * - Bytes other than 0xFF are stored literally.
\r
41 * - The byte 0xFF itself is stored as 0xFF 0xFF.
\r
42 * - A session special (code, arg) is stored as 0xFF, followed by
\r
43 * a big-endian 4-byte integer containing code, followed by
\r
44 * another big-endian 4-byte integer containing arg.
\r
46 * (This representation relies on session special codes being at
\r
47 * most 0xFEFFFFFF when represented in 32 bits, so that the first
\r
48 * byte of the 'code' integer can't be confused with the 0xFF
\r
49 * followup byte indicating a literal 0xFF, But since session
\r
50 * special codes are defined by an enum counting up from zero, and
\r
51 * there are only a couple of dozen of them, that shouldn't be a
\r
52 * problem! Even so, just in case, an assertion checks that at
\r
55 bufchain input_queue;
\r
57 IdempotentCallback input_queue_callback;
\r
61 * Values cached out of conf.
\r
63 bool telnet_keyboard, telnet_newline;
\r
64 int protocol, localecho, localedit;
\r
67 size_t buflen, bufsiz;
\r
71 #define ECHOING (ldisc->localecho == FORCE_ON || \
\r
72 (ldisc->localecho == AUTO && \
\r
73 (backend_ldisc_option_state(ldisc->backend, LD_ECHO))))
\r
74 #define EDITING (ldisc->localedit == FORCE_ON || \
\r
75 (ldisc->localedit == AUTO && \
\r
76 (backend_ldisc_option_state(ldisc->backend, LD_EDIT))))
\r
78 static void c_write(Ldisc *ldisc, const void *buf, int len)
\r
80 seat_stdout(ldisc->seat, buf, len);
\r
83 static int plen(Ldisc *ldisc, unsigned char c)
\r
85 if ((c >= 32 && c <= 126) || (c >= 160 && !in_utf(ldisc->term)))
\r
88 return 2; /* ^x for some x */
\r
89 else if (in_utf(ldisc->term) && c >= 0xC0)
\r
90 return 1; /* UTF-8 introducer character
\r
91 * (FIXME: combining / wide chars) */
\r
92 else if (in_utf(ldisc->term) && c >= 0x80 && c < 0xC0)
\r
93 return 0; /* UTF-8 followup character */
\r
95 return 4; /* <XY> hex representation */
\r
98 static void pwrite(Ldisc *ldisc, unsigned char c)
\r
100 if ((c >= 32 && c <= 126) ||
\r
101 (!in_utf(ldisc->term) && c >= 0xA0) ||
\r
102 (in_utf(ldisc->term) && c >= 0x80)) {
\r
103 c_write(ldisc, &c, 1);
\r
104 } else if (c < 128) {
\r
106 cc[1] = (c == 127 ? '?' : c + 0x40);
\r
108 c_write(ldisc, cc, 2);
\r
111 sprintf(cc, "<%02X>", c);
\r
112 c_write(ldisc, cc, 4);
\r
116 static bool char_start(Ldisc *ldisc, unsigned char c)
\r
118 if (in_utf(ldisc->term))
\r
119 return (c < 0x80 || c >= 0xC0);
\r
124 static void bsb(Ldisc *ldisc, int n)
\r
127 c_write(ldisc, "\010 \010", 3);
\r
130 static void ldisc_input_queue_callback(void *ctx);
\r
132 #define CTRL(x) (x^'@')
\r
133 #define KCTRL(x) ((x^'@') | 0x100)
\r
135 Ldisc *ldisc_create(Conf *conf, Terminal *term, Backend *backend, Seat *seat)
\r
137 Ldisc *ldisc = snew(Ldisc);
\r
142 ldisc->quotenext = false;
\r
144 ldisc->backend = backend;
\r
145 ldisc->term = term;
\r
146 ldisc->seat = seat;
\r
148 bufchain_init(&ldisc->input_queue);
\r
150 ldisc->prompts = NULL;
\r
151 ldisc->input_queue_callback.fn = ldisc_input_queue_callback;
\r
152 ldisc->input_queue_callback.ctx = ldisc;
\r
153 ldisc->input_queue_callback.queued = false;
\r
154 bufchain_set_callback(&ldisc->input_queue, &ldisc->input_queue_callback);
\r
156 ldisc_configure(ldisc, conf);
\r
158 /* Link ourselves into the backend and the terminal */
\r
160 term->ldisc = ldisc;
\r
162 backend_provide_ldisc(backend, ldisc);
\r
167 void ldisc_configure(Ldisc *ldisc, Conf *conf)
\r
169 ldisc->telnet_keyboard = conf_get_bool(conf, CONF_telnet_keyboard);
\r
170 ldisc->telnet_newline = conf_get_bool(conf, CONF_telnet_newline);
\r
171 ldisc->protocol = conf_get_int(conf, CONF_protocol);
\r
172 ldisc->localecho = conf_get_int(conf, CONF_localecho);
\r
173 ldisc->localedit = conf_get_int(conf, CONF_localedit);
\r
176 void ldisc_free(Ldisc *ldisc)
\r
178 bufchain_clear(&ldisc->input_queue);
\r
180 ldisc->term->ldisc = NULL;
\r
181 if (ldisc->backend)
\r
182 backend_provide_ldisc(ldisc->backend, NULL);
\r
185 if (ldisc->prompts && ldisc->prompts->ldisc_ptr_to_us == &ldisc->prompts)
\r
186 ldisc->prompts->ldisc_ptr_to_us = NULL;
\r
187 delete_callbacks_for_context(ldisc);
\r
191 void ldisc_echoedit_update(Ldisc *ldisc)
\r
193 seat_echoedit_update(ldisc->seat, ECHOING, EDITING);
\r
196 void ldisc_enable_prompt_callback(Ldisc *ldisc, prompts_t *prompts)
\r
199 * Called by the terminal to indicate that there's a prompts_t
\r
200 * currently in flight, or to indicate that one has just finished
\r
201 * (by passing NULL). When ldisc->prompts is not null, we notify
\r
202 * the terminal whenever new data arrives in our input queue, so
\r
203 * that it can continue the interactive prompting process.
\r
205 ldisc->prompts = prompts;
\r
207 ldisc->prompts->ldisc_ptr_to_us = &ldisc->prompts;
\r
210 static void ldisc_input_queue_callback(void *ctx)
\r
213 * Toplevel callback that is triggered whenever the input queue
\r
214 * lengthens. If we're currently processing an interactive prompt,
\r
215 * we call back the Terminal to tell it to do some more stuff with
\r
216 * that prompt based on the new input.
\r
218 Ldisc *ldisc = (Ldisc *)ctx;
\r
219 if (ldisc->term && ldisc->prompts) {
\r
221 * The integer return value from this call is discarded,
\r
222 * because we have no channel to pass it on to the backend
\r
223 * that originally wanted it. But that's OK, because if the
\r
224 * return value is >= 0 (that is, the prompts are either
\r
225 * completely filled in, or aborted by the user), then the
\r
226 * terminal will notify the callback in the prompts_t, and
\r
227 * when that calls term_get_userpass_input again, it will
\r
228 * return the same answer again.
\r
230 term_get_userpass_input(ldisc->term, ldisc->prompts);
\r
234 static void ldisc_to_backend_raw(
\r
235 Ldisc *ldisc, const void *vbuf, size_t len)
\r
237 if (backend_sendok(ldisc->backend)) {
\r
238 backend_send(ldisc->backend, vbuf, len);
\r
240 const char *buf = (const char *)vbuf;
\r
243 * Encode raw data in input_queue, by storing large chunks
\r
244 * as long as they don't include 0xFF, and pausing every
\r
245 * time they do to escape it.
\r
247 const char *ff = memchr(buf, '\xFF', len);
\r
248 size_t this_len = ff ? ff - buf : len;
\r
249 if (this_len > 0) {
\r
250 bufchain_add(&ldisc->input_queue, buf, len);
\r
252 bufchain_add(&ldisc->input_queue, "\xFF\xFF", 2);
\r
261 static void ldisc_to_backend_special(
\r
262 Ldisc *ldisc, SessionSpecialCode code, int arg)
\r
264 if (backend_sendok(ldisc->backend)) {
\r
265 backend_special(ldisc->backend, code, arg);
\r
268 * Encode a session special in input_queue.
\r
270 unsigned char data[9];
\r
272 PUT_32BIT_MSB_FIRST(data+1, code);
\r
273 PUT_32BIT_MSB_FIRST(data+5, arg);
\r
274 assert(data[1] != 0xFF &&
\r
275 "SessionSpecialCode encoding collides with FF FF escape");
\r
276 bufchain_add(&ldisc->input_queue, data, 9);
\r
280 bool ldisc_has_input_buffered(Ldisc *ldisc)
\r
282 return bufchain_size(&ldisc->input_queue) > 0;
\r
285 LdiscInputToken ldisc_get_input_token(Ldisc *ldisc)
\r
287 assert(bufchain_size(&ldisc->input_queue) > 0 &&
\r
288 "You're not supposed to call this unless there is buffered input!");
\r
290 LdiscInputToken tok;
\r
293 bufchain_fetch_consume(&ldisc->input_queue, &c, 1);
\r
295 /* A literal non-FF byte */
\r
296 tok.is_special = false;
\r
302 /* See if the byte after the FF is also FF, indicating a literal FF */
\r
303 bufchain_fetch_consume(&ldisc->input_queue, data, 1);
\r
304 if (data[0] == '\xFF') {
\r
305 tok.is_special = false;
\r
310 /* If not, get the rest of an 8-byte chunk and decode a special */
\r
311 bufchain_fetch_consume(&ldisc->input_queue, data+1, 7);
\r
312 tok.is_special = true;
\r
313 tok.code = GET_32BIT_MSB_FIRST(data);
\r
314 tok.arg = toint(GET_32BIT_MSB_FIRST(data+4));
\r
319 static void ldisc_check_sendok_callback(void *ctx)
\r
321 Ldisc *ldisc = (Ldisc *)ctx;
\r
323 if (!(ldisc->backend && backend_sendok(ldisc->backend)))
\r
327 * Flush the ldisc input queue into the backend, which is now
\r
328 * willing to receive the data.
\r
330 while (bufchain_size(&ldisc->input_queue) > 0) {
\r
332 * Process either a chunk of non-special data, or an FF
\r
333 * escape, depending on whether the first thing we see is an
\r
336 ptrlen data = bufchain_prefix(&ldisc->input_queue);
\r
337 const char *ff = memchr(data.ptr, '\xFF', data.len);
\r
338 if (ff != data.ptr) {
\r
339 /* Send a maximal block of data not containing any
\r
340 * difficult bytes. */
\r
342 data.len = ff - (const char *)data.ptr;
\r
343 backend_send(ldisc->backend, data.ptr, data.len);
\r
344 bufchain_consume(&ldisc->input_queue, data.len);
\r
346 /* Decode either a special or an escaped FF byte. The
\r
347 * easiest way to do this is to reuse the decoding code
\r
348 * already in ldisc_get_input_token. */
\r
349 LdiscInputToken tok = ldisc_get_input_token(ldisc);
\r
350 if (tok.is_special)
\r
351 backend_special(ldisc->backend, tok.code, tok.arg);
\r
353 backend_send(ldisc->backend, &tok.chr, 1);
\r
358 void ldisc_check_sendok(Ldisc *ldisc)
\r
360 queue_toplevel_callback(ldisc_check_sendok_callback, ldisc);
\r
363 void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, bool interactive)
\r
365 const char *buf = (const char *)vbuf;
\r
368 assert(ldisc->term);
\r
372 * Interrupt a paste from the clipboard, if one was in
\r
373 * progress when the user pressed a key. This is easier than
\r
374 * buffering the current piece of data and saving it until the
\r
375 * terminal has finished pasting, and has the potential side
\r
376 * benefit of permitting a user to cancel an accidental huge
\r
379 term_nopaste(ldisc->term);
\r
383 * Less than zero means null terminated special string.
\r
387 keyflag = KCTRL('@');
\r
390 * Either perform local editing, or just send characters.
\r
395 c = (unsigned char)(*buf++) + keyflag;
\r
396 if (!interactive && c == '\r')
\r
398 switch (ldisc->quotenext ? ' ' : c) {
\r
400 * ^h/^?: delete, and output BSBs, to return to
\r
401 * last character boundary (in UTF-8 mode this may
\r
402 * be more than one byte)
\r
403 * ^w: delete, and output BSBs, to return to last
\r
404 * space/nonspace boundary
\r
405 * ^u: delete, and output BSBs, to return to BOL
\r
406 * ^c: Do a ^u then send a telnet IP
\r
407 * ^z: Do a ^u then send a telnet SUSP
\r
408 * ^\: Do a ^u then send a telnet ABORT
\r
409 * ^r: echo "^R\n" and redraw line
\r
410 * ^v: quote next char
\r
411 * ^d: if at BOL, end of file and close connection,
\r
412 * else send line and reset to BOL
\r
413 * ^m: send line-plus-\r\n and reset to BOL
\r
416 case KCTRL('?'): /* backspace/delete */
\r
417 if (ldisc->buflen > 0) {
\r
420 bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
\r
422 } while (!char_start(ldisc, ldisc->buf[ldisc->buflen]));
\r
425 case CTRL('W'): /* delete word */
\r
426 while (ldisc->buflen > 0) {
\r
428 bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
\r
430 if (ldisc->buflen > 0 &&
\r
431 isspace((unsigned char)ldisc->buf[ldisc->buflen-1]) &&
\r
432 !isspace((unsigned char)ldisc->buf[ldisc->buflen]))
\r
436 case CTRL('U'): /* delete line */
\r
437 case CTRL('C'): /* Send IP */
\r
438 case CTRL('\\'): /* Quit */
\r
439 case CTRL('Z'): /* Suspend */
\r
440 while (ldisc->buflen > 0) {
\r
442 bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
\r
445 if (c == CTRL('U'))
\r
446 break; /* ^U *just* erases a line */
\r
447 ldisc_to_backend_special(ldisc, SS_EL, 0);
\r
449 * We don't send IP, SUSP or ABORT if the user has
\r
450 * configured telnet specials off! This breaks
\r
451 * talkers otherwise.
\r
453 if (!ldisc->telnet_keyboard)
\r
455 if (c == CTRL('C'))
\r
456 ldisc_to_backend_special(ldisc, SS_IP, 0);
\r
457 if (c == CTRL('Z'))
\r
458 ldisc_to_backend_special(ldisc, SS_SUSP, 0);
\r
459 if (c == CTRL('\\'))
\r
460 ldisc_to_backend_special(ldisc, SS_ABORT, 0);
\r
462 case CTRL('R'): /* redraw line */
\r
465 c_write(ldisc, "^R\r\n", 4);
\r
466 for (i = 0; i < ldisc->buflen; i++)
\r
467 pwrite(ldisc, ldisc->buf[i]);
\r
470 case CTRL('V'): /* quote next char */
\r
471 ldisc->quotenext = true;
\r
473 case CTRL('D'): /* logout or send */
\r
474 if (ldisc->buflen == 0) {
\r
475 ldisc_to_backend_special(ldisc, SS_EOF, 0);
\r
477 ldisc_to_backend_raw(ldisc, ldisc->buf, ldisc->buflen);
\r
482 * This particularly hideous bit of code from RDB
\r
483 * allows ordinary ^M^J to do the same thing as
\r
484 * magic-^M when in Raw protocol. The line `case
\r
485 * KCTRL('M'):' is _inside_ the if block. Thus:
\r
487 * - receiving regular ^M goes straight to the
\r
488 * default clause and inserts as a literal ^M.
\r
489 * - receiving regular ^J _not_ directly after a
\r
490 * literal ^M (or not in Raw protocol) fails the
\r
491 * if condition, leaps to the bottom of the if,
\r
492 * and falls through into the default clause
\r
494 * - receiving regular ^J just after a literal ^M
\r
495 * in Raw protocol passes the if condition,
\r
496 * deletes the literal ^M, and falls through
\r
497 * into the magic-^M code
\r
498 * - receiving a magic-^M empties the line buffer,
\r
499 * signals end-of-line in one of the various
\r
500 * entertaining ways, and _doesn't_ fall out of
\r
501 * the bottom of the if and through to the
\r
502 * default clause because of the break.
\r
505 if (ldisc->protocol == PROT_RAW &&
\r
506 ldisc->buflen > 0 && ldisc->buf[ldisc->buflen - 1] == '\r') {
\r
508 bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
\r
511 case KCTRL('M'): /* send with newline */
\r
512 if (ldisc->buflen > 0)
\r
513 ldisc_to_backend_raw(ldisc, ldisc->buf, ldisc->buflen);
\r
514 if (ldisc->protocol == PROT_RAW)
\r
515 ldisc_to_backend_raw(ldisc, "\r\n", 2);
\r
516 else if (ldisc->protocol == PROT_TELNET && ldisc->telnet_newline)
\r
517 ldisc_to_backend_special(ldisc, SS_EOL, 0);
\r
519 ldisc_to_backend_raw(ldisc, "\r", 1);
\r
521 c_write(ldisc, "\r\n", 2);
\r
526 default: /* get to this label from ^V handler */
\r
528 sgrowarray(ldisc->buf, ldisc->bufsiz, ldisc->buflen);
\r
529 ldisc->buf[ldisc->buflen++] = c;
\r
531 pwrite(ldisc, (unsigned char) c);
\r
532 ldisc->quotenext = false;
\r
537 if (ldisc->buflen != 0) {
\r
538 ldisc_to_backend_raw(ldisc, ldisc->buf, ldisc->buflen);
\r
539 while (ldisc->buflen > 0) {
\r
540 bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
\r
546 c_write(ldisc, buf, len);
\r
547 if (keyflag && ldisc->protocol == PROT_TELNET && len == 1) {
\r
550 if (ldisc->protocol == PROT_TELNET && ldisc->telnet_newline)
\r
551 ldisc_to_backend_special(ldisc, SS_EOL, 0);
\r
553 ldisc_to_backend_raw(ldisc, "\r", 1);
\r
557 if (ldisc->telnet_keyboard) {
\r
558 ldisc_to_backend_special(ldisc, SS_EC, 0);
\r
562 if (ldisc->telnet_keyboard) {
\r
563 ldisc_to_backend_special(ldisc, SS_IP, 0);
\r
567 if (ldisc->telnet_keyboard) {
\r
568 ldisc_to_backend_special(ldisc, SS_SUSP, 0);
\r
573 ldisc_to_backend_raw(ldisc, buf, len);
\r
577 ldisc_to_backend_raw(ldisc, buf, len);
\r