jcs's openbsd hax
openbsd
1/* $OpenBSD: input.c,v 1.251 2026/02/18 09:10:31 nicm Exp $ */
2
3/*
4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20
21#include <netinet/in.h>
22
23#include <ctype.h>
24#include <resolv.h>
25#include <stdlib.h>
26#include <string.h>
27#include <time.h>
28
29#include "tmux.h"
30
31/*
32 * Based on the description by Paul Williams at:
33 *
34 * https://vt100.net/emu/dec_ansi_parser
35 *
36 * With the following changes:
37 *
38 * - 7-bit only.
39 *
40 * - Support for UTF-8.
41 *
42 * - OSC (but not APC) may be terminated by \007 as well as ST.
43 *
44 * - A state for APC similar to OSC. Some terminals appear to use this to set
45 * the title.
46 *
47 * - A state for the screen \033k...\033\\ sequence to rename a window. This is
48 * pretty stupid but not supporting it is more trouble than it is worth.
49 *
50 * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
51 * be passed to the underlying terminals.
52 */
53
54/* Type of terminator. */
55enum input_end_type {
56 INPUT_END_ST,
57 INPUT_END_BEL
58};
59
60/* Request sent by a pane. */
61struct input_request {
62 struct client *c;
63 struct input_ctx *ictx;
64
65 enum input_request_type type;
66 uint64_t t;
67 enum input_end_type end;
68
69 int idx;
70 void *data;
71
72 TAILQ_ENTRY(input_request) entry;
73 TAILQ_ENTRY(input_request) centry;
74};
75#define INPUT_REQUEST_TIMEOUT 500
76
77/* Input parser cell. */
78struct input_cell {
79 struct grid_cell cell;
80 int set;
81 int g0set; /* 1 if ACS */
82 int g1set; /* 1 if ACS */
83};
84
85/* Input parser argument. */
86struct input_param {
87 enum {
88 INPUT_MISSING,
89 INPUT_NUMBER,
90 INPUT_STRING
91 } type;
92 union {
93 int num;
94 char *str;
95 };
96};
97
98/* Input parser context. */
99struct input_ctx {
100 struct window_pane *wp;
101 struct bufferevent *event;
102 struct screen_write_ctx ctx;
103 struct colour_palette *palette;
104 struct client *c;
105
106 struct input_cell cell;
107 struct input_cell old_cell;
108 u_int old_cx;
109 u_int old_cy;
110 int old_mode;
111
112 u_char interm_buf[4];
113 size_t interm_len;
114
115 u_char param_buf[64];
116 size_t param_len;
117
118#define INPUT_BUF_START 32
119 u_char *input_buf;
120 size_t input_len;
121 size_t input_space;
122 enum input_end_type input_end;
123
124 struct input_param param_list[24];
125 u_int param_list_len;
126
127 struct utf8_data utf8data;
128 int utf8started;
129
130 int ch;
131 struct utf8_data last;
132
133 const struct input_state *state;
134 int flags;
135#define INPUT_DISCARD 0x1
136#define INPUT_LAST 0x2
137
138 struct input_requests requests;
139 u_int request_count;
140 struct event request_timer;
141
142 /*
143 * All input received since we were last in the ground state. Sent to
144 * control clients on connection.
145 */
146 struct evbuffer *since_ground;
147 struct event ground_timer;
148};
149
150/* Helper functions. */
151struct input_transition;
152static void input_request_timer_callback(int, short, void *);
153static void input_start_request_timer(struct input_ctx *);
154static struct input_request *input_make_request(struct input_ctx *,
155 enum input_request_type);
156static void input_free_request(struct input_request *);
157static int input_add_request(struct input_ctx *, enum input_request_type,
158 int);
159static int input_split(struct input_ctx *);
160static int input_get(struct input_ctx *, u_int, int, int);
161static void input_set_state(struct input_ctx *,
162 const struct input_transition *);
163static void input_reset_cell(struct input_ctx *);
164static void input_report_current_theme(struct input_ctx *);
165static void input_osc_4(struct input_ctx *, const char *);
166static void input_osc_8(struct input_ctx *, const char *);
167static void input_osc_10(struct input_ctx *, const char *);
168static void input_osc_11(struct input_ctx *, const char *);
169static void input_osc_12(struct input_ctx *, const char *);
170static void input_osc_52(struct input_ctx *, const char *);
171static void input_osc_104(struct input_ctx *, const char *);
172static void input_osc_110(struct input_ctx *, const char *);
173static void input_osc_111(struct input_ctx *, const char *);
174static void input_osc_112(struct input_ctx *, const char *);
175static void input_osc_133(struct input_ctx *, const char *);
176
177/* Transition entry/exit handlers. */
178static void input_clear(struct input_ctx *);
179static void input_ground(struct input_ctx *);
180static void input_enter_dcs(struct input_ctx *);
181static void input_enter_osc(struct input_ctx *);
182static void input_exit_osc(struct input_ctx *);
183static void input_enter_apc(struct input_ctx *);
184static void input_exit_apc(struct input_ctx *);
185static void input_enter_rename(struct input_ctx *);
186static void input_exit_rename(struct input_ctx *);
187
188/* Input state handlers. */
189static int input_print(struct input_ctx *);
190static int input_intermediate(struct input_ctx *);
191static int input_parameter(struct input_ctx *);
192static int input_input(struct input_ctx *);
193static int input_c0_dispatch(struct input_ctx *);
194static int input_esc_dispatch(struct input_ctx *);
195static int input_csi_dispatch(struct input_ctx *);
196static void input_csi_dispatch_rm(struct input_ctx *);
197static void input_csi_dispatch_rm_private(struct input_ctx *);
198static void input_csi_dispatch_sm(struct input_ctx *);
199static void input_csi_dispatch_sm_private(struct input_ctx *);
200static void input_csi_dispatch_sm_graphics(struct input_ctx *);
201static void input_csi_dispatch_winops(struct input_ctx *);
202static void input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *);
203static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *);
204static void input_csi_dispatch_sgr(struct input_ctx *);
205static int input_dcs_dispatch(struct input_ctx *);
206static int input_top_bit_set(struct input_ctx *);
207static int input_end_bel(struct input_ctx *);
208
209/* Command table comparison function. */
210static int input_table_compare(const void *, const void *);
211
212/* Command table entry. */
213struct input_table_entry {
214 int ch;
215 const char *interm;
216 int type;
217};
218
219/* Escape commands. */
220enum input_esc_type {
221 INPUT_ESC_DECALN,
222 INPUT_ESC_DECKPAM,
223 INPUT_ESC_DECKPNM,
224 INPUT_ESC_DECRC,
225 INPUT_ESC_DECSC,
226 INPUT_ESC_HTS,
227 INPUT_ESC_IND,
228 INPUT_ESC_NEL,
229 INPUT_ESC_RI,
230 INPUT_ESC_RIS,
231 INPUT_ESC_SCSG0_OFF,
232 INPUT_ESC_SCSG0_ON,
233 INPUT_ESC_SCSG1_OFF,
234 INPUT_ESC_SCSG1_ON,
235 INPUT_ESC_ST
236};
237
238/* Escape command table. */
239static const struct input_table_entry input_esc_table[] = {
240 { '0', "(", INPUT_ESC_SCSG0_ON },
241 { '0', ")", INPUT_ESC_SCSG1_ON },
242 { '7', "", INPUT_ESC_DECSC },
243 { '8', "", INPUT_ESC_DECRC },
244 { '8', "#", INPUT_ESC_DECALN },
245 { '=', "", INPUT_ESC_DECKPAM },
246 { '>', "", INPUT_ESC_DECKPNM },
247 { 'B', "(", INPUT_ESC_SCSG0_OFF },
248 { 'B', ")", INPUT_ESC_SCSG1_OFF },
249 { 'D', "", INPUT_ESC_IND },
250 { 'E', "", INPUT_ESC_NEL },
251 { 'H', "", INPUT_ESC_HTS },
252 { 'M', "", INPUT_ESC_RI },
253 { '\\', "", INPUT_ESC_ST },
254 { 'c', "", INPUT_ESC_RIS },
255};
256
257/* Control (CSI) commands. */
258enum input_csi_type {
259 INPUT_CSI_CBT,
260 INPUT_CSI_CNL,
261 INPUT_CSI_CPL,
262 INPUT_CSI_CUB,
263 INPUT_CSI_CUD,
264 INPUT_CSI_CUF,
265 INPUT_CSI_CUP,
266 INPUT_CSI_CUU,
267 INPUT_CSI_DA,
268 INPUT_CSI_DA_TWO,
269 INPUT_CSI_DCH,
270 INPUT_CSI_DECSCUSR,
271 INPUT_CSI_DECSTBM,
272 INPUT_CSI_DL,
273 INPUT_CSI_DSR,
274 INPUT_CSI_DSR_PRIVATE,
275 INPUT_CSI_ECH,
276 INPUT_CSI_ED,
277 INPUT_CSI_EL,
278 INPUT_CSI_HPA,
279 INPUT_CSI_ICH,
280 INPUT_CSI_IL,
281 INPUT_CSI_MODOFF,
282 INPUT_CSI_MODSET,
283 INPUT_CSI_QUERY_PRIVATE,
284 INPUT_CSI_RCP,
285 INPUT_CSI_REP,
286 INPUT_CSI_RM,
287 INPUT_CSI_RM_PRIVATE,
288 INPUT_CSI_SCP,
289 INPUT_CSI_SD,
290 INPUT_CSI_SGR,
291 INPUT_CSI_SM,
292 INPUT_CSI_SM_GRAPHICS,
293 INPUT_CSI_SM_PRIVATE,
294 INPUT_CSI_SU,
295 INPUT_CSI_TBC,
296 INPUT_CSI_VPA,
297 INPUT_CSI_WINOPS,
298 INPUT_CSI_XDA
299};
300
301/* Control (CSI) command table. */
302static const struct input_table_entry input_csi_table[] = {
303 { '@', "", INPUT_CSI_ICH },
304 { 'A', "", INPUT_CSI_CUU },
305 { 'B', "", INPUT_CSI_CUD },
306 { 'C', "", INPUT_CSI_CUF },
307 { 'D', "", INPUT_CSI_CUB },
308 { 'E', "", INPUT_CSI_CNL },
309 { 'F', "", INPUT_CSI_CPL },
310 { 'G', "", INPUT_CSI_HPA },
311 { 'H', "", INPUT_CSI_CUP },
312 { 'J', "", INPUT_CSI_ED },
313 { 'K', "", INPUT_CSI_EL },
314 { 'L', "", INPUT_CSI_IL },
315 { 'M', "", INPUT_CSI_DL },
316 { 'P', "", INPUT_CSI_DCH },
317 { 'S', "", INPUT_CSI_SU },
318 { 'S', "?", INPUT_CSI_SM_GRAPHICS },
319 { 'T', "", INPUT_CSI_SD },
320 { 'X', "", INPUT_CSI_ECH },
321 { 'Z', "", INPUT_CSI_CBT },
322 { '`', "", INPUT_CSI_HPA },
323 { 'b', "", INPUT_CSI_REP },
324 { 'c', "", INPUT_CSI_DA },
325 { 'c', ">", INPUT_CSI_DA_TWO },
326 { 'd', "", INPUT_CSI_VPA },
327 { 'f', "", INPUT_CSI_CUP },
328 { 'g', "", INPUT_CSI_TBC },
329 { 'h', "", INPUT_CSI_SM },
330 { 'h', "?", INPUT_CSI_SM_PRIVATE },
331 { 'l', "", INPUT_CSI_RM },
332 { 'l', "?", INPUT_CSI_RM_PRIVATE },
333 { 'm', "", INPUT_CSI_SGR },
334 { 'm', ">", INPUT_CSI_MODSET },
335 { 'n', "", INPUT_CSI_DSR },
336 { 'n', ">", INPUT_CSI_MODOFF },
337 { 'n', "?", INPUT_CSI_DSR_PRIVATE },
338 { 'p', "?$", INPUT_CSI_QUERY_PRIVATE },
339 { 'q', " ", INPUT_CSI_DECSCUSR },
340 { 'q', ">", INPUT_CSI_XDA },
341 { 'r', "", INPUT_CSI_DECSTBM },
342 { 's', "", INPUT_CSI_SCP },
343 { 't', "", INPUT_CSI_WINOPS },
344 { 'u', "", INPUT_CSI_RCP }
345};
346
347/* Input transition. */
348struct input_transition {
349 int first;
350 int last;
351
352 int (*handler)(struct input_ctx *);
353 const struct input_state *state;
354};
355
356/* Input state. */
357struct input_state {
358 const char *name;
359 void (*enter)(struct input_ctx *);
360 void (*exit)(struct input_ctx *);
361 const struct input_transition *transitions;
362};
363
364/* State transitions available from all states. */
365#define INPUT_STATE_ANYWHERE \
366 { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
367 { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
368 { 0x1b, 0x1b, NULL, &input_state_esc_enter }
369
370/* Forward declarations of state tables. */
371static const struct input_transition input_state_ground_table[];
372static const struct input_transition input_state_esc_enter_table[];
373static const struct input_transition input_state_esc_intermediate_table[];
374static const struct input_transition input_state_csi_enter_table[];
375static const struct input_transition input_state_csi_parameter_table[];
376static const struct input_transition input_state_csi_intermediate_table[];
377static const struct input_transition input_state_csi_ignore_table[];
378static const struct input_transition input_state_dcs_enter_table[];
379static const struct input_transition input_state_dcs_parameter_table[];
380static const struct input_transition input_state_dcs_intermediate_table[];
381static const struct input_transition input_state_dcs_handler_table[];
382static const struct input_transition input_state_dcs_escape_table[];
383static const struct input_transition input_state_dcs_ignore_table[];
384static const struct input_transition input_state_osc_string_table[];
385static const struct input_transition input_state_apc_string_table[];
386static const struct input_transition input_state_rename_string_table[];
387static const struct input_transition input_state_consume_st_table[];
388
389/* ground state definition. */
390static const struct input_state input_state_ground = {
391 "ground",
392 input_ground, NULL,
393 input_state_ground_table
394};
395
396/* esc_enter state definition. */
397static const struct input_state input_state_esc_enter = {
398 "esc_enter",
399 input_clear, NULL,
400 input_state_esc_enter_table
401};
402
403/* esc_intermediate state definition. */
404static const struct input_state input_state_esc_intermediate = {
405 "esc_intermediate",
406 NULL, NULL,
407 input_state_esc_intermediate_table
408};
409
410/* csi_enter state definition. */
411static const struct input_state input_state_csi_enter = {
412 "csi_enter",
413 input_clear, NULL,
414 input_state_csi_enter_table
415};
416
417/* csi_parameter state definition. */
418static const struct input_state input_state_csi_parameter = {
419 "csi_parameter",
420 NULL, NULL,
421 input_state_csi_parameter_table
422};
423
424/* csi_intermediate state definition. */
425static const struct input_state input_state_csi_intermediate = {
426 "csi_intermediate",
427 NULL, NULL,
428 input_state_csi_intermediate_table
429};
430
431/* csi_ignore state definition. */
432static const struct input_state input_state_csi_ignore = {
433 "csi_ignore",
434 NULL, NULL,
435 input_state_csi_ignore_table
436};
437
438/* dcs_enter state definition. */
439static const struct input_state input_state_dcs_enter = {
440 "dcs_enter",
441 input_enter_dcs, NULL,
442 input_state_dcs_enter_table
443};
444
445/* dcs_parameter state definition. */
446static const struct input_state input_state_dcs_parameter = {
447 "dcs_parameter",
448 NULL, NULL,
449 input_state_dcs_parameter_table
450};
451
452/* dcs_intermediate state definition. */
453static const struct input_state input_state_dcs_intermediate = {
454 "dcs_intermediate",
455 NULL, NULL,
456 input_state_dcs_intermediate_table
457};
458
459/* dcs_handler state definition. */
460static const struct input_state input_state_dcs_handler = {
461 "dcs_handler",
462 NULL, NULL,
463 input_state_dcs_handler_table
464};
465
466/* dcs_escape state definition. */
467static const struct input_state input_state_dcs_escape = {
468 "dcs_escape",
469 NULL, NULL,
470 input_state_dcs_escape_table
471};
472
473/* dcs_ignore state definition. */
474static const struct input_state input_state_dcs_ignore = {
475 "dcs_ignore",
476 NULL, NULL,
477 input_state_dcs_ignore_table
478};
479
480/* osc_string state definition. */
481static const struct input_state input_state_osc_string = {
482 "osc_string",
483 input_enter_osc, input_exit_osc,
484 input_state_osc_string_table
485};
486
487/* apc_string state definition. */
488static const struct input_state input_state_apc_string = {
489 "apc_string",
490 input_enter_apc, input_exit_apc,
491 input_state_apc_string_table
492};
493
494/* rename_string state definition. */
495static const struct input_state input_state_rename_string = {
496 "rename_string",
497 input_enter_rename, input_exit_rename,
498 input_state_rename_string_table
499};
500
501/* consume_st state definition. */
502static const struct input_state input_state_consume_st = {
503 "consume_st",
504 input_enter_rename, NULL, /* rename also waits for ST */
505 input_state_consume_st_table
506};
507
508/* ground state table. */
509static const struct input_transition input_state_ground_table[] = {
510 INPUT_STATE_ANYWHERE,
511
512 { 0x00, 0x17, input_c0_dispatch, NULL },
513 { 0x19, 0x19, input_c0_dispatch, NULL },
514 { 0x1c, 0x1f, input_c0_dispatch, NULL },
515 { 0x20, 0x7e, input_print, NULL },
516 { 0x7f, 0x7f, NULL, NULL },
517 { 0x80, 0xff, input_top_bit_set, NULL },
518
519 { -1, -1, NULL, NULL }
520};
521
522/* esc_enter state table. */
523static const struct input_transition input_state_esc_enter_table[] = {
524 INPUT_STATE_ANYWHERE,
525
526 { 0x00, 0x17, input_c0_dispatch, NULL },
527 { 0x19, 0x19, input_c0_dispatch, NULL },
528 { 0x1c, 0x1f, input_c0_dispatch, NULL },
529 { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
530 { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
531 { 0x50, 0x50, NULL, &input_state_dcs_enter },
532 { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
533 { 0x58, 0x58, NULL, &input_state_consume_st },
534 { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
535 { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
536 { 0x5b, 0x5b, NULL, &input_state_csi_enter },
537 { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
538 { 0x5d, 0x5d, NULL, &input_state_osc_string },
539 { 0x5e, 0x5e, NULL, &input_state_consume_st },
540 { 0x5f, 0x5f, NULL, &input_state_apc_string },
541 { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
542 { 0x6b, 0x6b, NULL, &input_state_rename_string },
543 { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
544 { 0x7f, 0xff, NULL, NULL },
545
546 { -1, -1, NULL, NULL }
547};
548
549/* esc_intermediate state table. */
550static const struct input_transition input_state_esc_intermediate_table[] = {
551 INPUT_STATE_ANYWHERE,
552
553 { 0x00, 0x17, input_c0_dispatch, NULL },
554 { 0x19, 0x19, input_c0_dispatch, NULL },
555 { 0x1c, 0x1f, input_c0_dispatch, NULL },
556 { 0x20, 0x2f, input_intermediate, NULL },
557 { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
558 { 0x7f, 0xff, NULL, NULL },
559
560 { -1, -1, NULL, NULL }
561};
562
563/* csi_enter state table. */
564static const struct input_transition input_state_csi_enter_table[] = {
565 INPUT_STATE_ANYWHERE,
566
567 { 0x00, 0x17, input_c0_dispatch, NULL },
568 { 0x19, 0x19, input_c0_dispatch, NULL },
569 { 0x1c, 0x1f, input_c0_dispatch, NULL },
570 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
571 { 0x30, 0x39, input_parameter, &input_state_csi_parameter },
572 { 0x3a, 0x3a, input_parameter, &input_state_csi_parameter },
573 { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
574 { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
575 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
576 { 0x7f, 0xff, NULL, NULL },
577
578 { -1, -1, NULL, NULL }
579};
580
581/* csi_parameter state table. */
582static const struct input_transition input_state_csi_parameter_table[] = {
583 INPUT_STATE_ANYWHERE,
584
585 { 0x00, 0x17, input_c0_dispatch, NULL },
586 { 0x19, 0x19, input_c0_dispatch, NULL },
587 { 0x1c, 0x1f, input_c0_dispatch, NULL },
588 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
589 { 0x30, 0x39, input_parameter, NULL },
590 { 0x3a, 0x3a, input_parameter, NULL },
591 { 0x3b, 0x3b, input_parameter, NULL },
592 { 0x3c, 0x3f, NULL, &input_state_csi_ignore },
593 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
594 { 0x7f, 0xff, NULL, NULL },
595
596 { -1, -1, NULL, NULL }
597};
598
599/* csi_intermediate state table. */
600static const struct input_transition input_state_csi_intermediate_table[] = {
601 INPUT_STATE_ANYWHERE,
602
603 { 0x00, 0x17, input_c0_dispatch, NULL },
604 { 0x19, 0x19, input_c0_dispatch, NULL },
605 { 0x1c, 0x1f, input_c0_dispatch, NULL },
606 { 0x20, 0x2f, input_intermediate, NULL },
607 { 0x30, 0x3f, NULL, &input_state_csi_ignore },
608 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
609 { 0x7f, 0xff, NULL, NULL },
610
611 { -1, -1, NULL, NULL }
612};
613
614/* csi_ignore state table. */
615static const struct input_transition input_state_csi_ignore_table[] = {
616 INPUT_STATE_ANYWHERE,
617
618 { 0x00, 0x17, input_c0_dispatch, NULL },
619 { 0x19, 0x19, input_c0_dispatch, NULL },
620 { 0x1c, 0x1f, input_c0_dispatch, NULL },
621 { 0x20, 0x3f, NULL, NULL },
622 { 0x40, 0x7e, NULL, &input_state_ground },
623 { 0x7f, 0xff, NULL, NULL },
624
625 { -1, -1, NULL, NULL }
626};
627
628/* dcs_enter state table. */
629static const struct input_transition input_state_dcs_enter_table[] = {
630 INPUT_STATE_ANYWHERE,
631
632 { 0x00, 0x17, NULL, NULL },
633 { 0x19, 0x19, NULL, NULL },
634 { 0x1c, 0x1f, NULL, NULL },
635 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
636 { 0x30, 0x39, input_parameter, &input_state_dcs_parameter },
637 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
638 { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter },
639 { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
640 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
641 { 0x7f, 0xff, NULL, NULL },
642
643 { -1, -1, NULL, NULL }
644};
645
646/* dcs_parameter state table. */
647static const struct input_transition input_state_dcs_parameter_table[] = {
648 INPUT_STATE_ANYWHERE,
649
650 { 0x00, 0x17, NULL, NULL },
651 { 0x19, 0x19, NULL, NULL },
652 { 0x1c, 0x1f, NULL, NULL },
653 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
654 { 0x30, 0x39, input_parameter, NULL },
655 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
656 { 0x3b, 0x3b, input_parameter, NULL },
657 { 0x3c, 0x3f, NULL, &input_state_dcs_ignore },
658 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
659 { 0x7f, 0xff, NULL, NULL },
660
661 { -1, -1, NULL, NULL }
662};
663
664/* dcs_intermediate state table. */
665static const struct input_transition input_state_dcs_intermediate_table[] = {
666 INPUT_STATE_ANYWHERE,
667
668 { 0x00, 0x17, NULL, NULL },
669 { 0x19, 0x19, NULL, NULL },
670 { 0x1c, 0x1f, NULL, NULL },
671 { 0x20, 0x2f, input_intermediate, NULL },
672 { 0x30, 0x3f, NULL, &input_state_dcs_ignore },
673 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
674 { 0x7f, 0xff, NULL, NULL },
675
676 { -1, -1, NULL, NULL }
677};
678
679/* dcs_handler state table. */
680static const struct input_transition input_state_dcs_handler_table[] = {
681 /* No INPUT_STATE_ANYWHERE */
682
683 { 0x00, 0x1a, input_input, NULL },
684 { 0x1b, 0x1b, NULL, &input_state_dcs_escape },
685 { 0x1c, 0xff, input_input, NULL },
686
687 { -1, -1, NULL, NULL }
688};
689
690/* dcs_escape state table. */
691static const struct input_transition input_state_dcs_escape_table[] = {
692 /* No INPUT_STATE_ANYWHERE */
693
694 { 0x00, 0x5b, input_input, &input_state_dcs_handler },
695 { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
696 { 0x5d, 0xff, input_input, &input_state_dcs_handler },
697
698 { -1, -1, NULL, NULL }
699};
700
701/* dcs_ignore state table. */
702static const struct input_transition input_state_dcs_ignore_table[] = {
703 INPUT_STATE_ANYWHERE,
704
705 { 0x00, 0x17, NULL, NULL },
706 { 0x19, 0x19, NULL, NULL },
707 { 0x1c, 0x1f, NULL, NULL },
708 { 0x20, 0xff, NULL, NULL },
709
710 { -1, -1, NULL, NULL }
711};
712
713/* osc_string state table. */
714static const struct input_transition input_state_osc_string_table[] = {
715 INPUT_STATE_ANYWHERE,
716
717 { 0x00, 0x06, NULL, NULL },
718 { 0x07, 0x07, input_end_bel, &input_state_ground },
719 { 0x08, 0x17, NULL, NULL },
720 { 0x19, 0x19, NULL, NULL },
721 { 0x1c, 0x1f, NULL, NULL },
722 { 0x20, 0xff, input_input, NULL },
723
724 { -1, -1, NULL, NULL }
725};
726
727/* apc_string state table. */
728static const struct input_transition input_state_apc_string_table[] = {
729 INPUT_STATE_ANYWHERE,
730
731 { 0x00, 0x17, NULL, NULL },
732 { 0x19, 0x19, NULL, NULL },
733 { 0x1c, 0x1f, NULL, NULL },
734 { 0x20, 0xff, input_input, NULL },
735
736 { -1, -1, NULL, NULL }
737};
738
739/* rename_string state table. */
740static const struct input_transition input_state_rename_string_table[] = {
741 INPUT_STATE_ANYWHERE,
742
743 { 0x00, 0x17, NULL, NULL },
744 { 0x19, 0x19, NULL, NULL },
745 { 0x1c, 0x1f, NULL, NULL },
746 { 0x20, 0xff, input_input, NULL },
747
748 { -1, -1, NULL, NULL }
749};
750
751/* consume_st state table. */
752static const struct input_transition input_state_consume_st_table[] = {
753 INPUT_STATE_ANYWHERE,
754
755 { 0x00, 0x17, NULL, NULL },
756 { 0x19, 0x19, NULL, NULL },
757 { 0x1c, 0x1f, NULL, NULL },
758 { 0x20, 0xff, NULL, NULL },
759
760 { -1, -1, NULL, NULL }
761};
762
763/* Maximum of bytes allowed to read in a single input. */
764static size_t input_buffer_size = INPUT_BUF_DEFAULT_SIZE;
765
766/* Input table compare. */
767static int
768input_table_compare(const void *key, const void *value)
769{
770 const struct input_ctx *ictx = key;
771 const struct input_table_entry *entry = value;
772
773 if (ictx->ch != entry->ch)
774 return (ictx->ch - entry->ch);
775 return (strcmp(ictx->interm_buf, entry->interm));
776}
777
778/* Stop UTF-8 and enter an invalid character. */
779static void
780input_stop_utf8(struct input_ctx *ictx)
781{
782 struct screen_write_ctx *sctx = &ictx->ctx;
783 static struct utf8_data rc = { "\357\277\275", 3, 3, 1 };
784
785 if (ictx->utf8started) {
786 utf8_copy(&ictx->cell.cell.data, &rc);
787 screen_write_collect_add(sctx, &ictx->cell.cell);
788 }
789 ictx->utf8started = 0;
790}
791
792/*
793 * Timer - if this expires then have been waiting for a terminator for too
794 * long, so reset to ground.
795 */
796static void
797input_ground_timer_callback(__unused int fd, __unused short events, void *arg)
798{
799 struct input_ctx *ictx = arg;
800
801 log_debug("%s: %s expired" , __func__, ictx->state->name);
802 input_reset(ictx, 0);
803}
804
805/* Start the timer. */
806static void
807input_start_ground_timer(struct input_ctx *ictx)
808{
809 struct timeval tv = { .tv_sec = 5, .tv_usec = 0 };
810
811 event_del(&ictx->ground_timer);
812 event_add(&ictx->ground_timer, &tv);
813}
814
815/* Reset cell state to default. */
816static void
817input_reset_cell(struct input_ctx *ictx)
818{
819 memcpy(&ictx->cell.cell, &grid_default_cell, sizeof ictx->cell.cell);
820 ictx->cell.set = 0;
821 ictx->cell.g0set = ictx->cell.g1set = 0;
822
823 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
824 ictx->old_cx = 0;
825 ictx->old_cy = 0;
826}
827
828/* Save screen state. */
829static void
830input_save_state(struct input_ctx *ictx)
831{
832 struct screen_write_ctx *sctx = &ictx->ctx;
833 struct screen *s = sctx->s;
834
835 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
836 ictx->old_cx = s->cx;
837 ictx->old_cy = s->cy;
838 ictx->old_mode = s->mode;
839}
840
841/* Restore screen state. */
842static void
843input_restore_state(struct input_ctx *ictx)
844{
845 struct screen_write_ctx *sctx = &ictx->ctx;
846
847 memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
848 if (ictx->old_mode & MODE_ORIGIN)
849 screen_write_mode_set(sctx, MODE_ORIGIN);
850 else
851 screen_write_mode_clear(sctx, MODE_ORIGIN);
852 screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy, 0);
853}
854
855/* Initialise input parser. */
856struct input_ctx *
857input_init(struct window_pane *wp, struct bufferevent *bev,
858 struct colour_palette *palette, struct client *c)
859{
860 struct input_ctx *ictx;
861
862 ictx = xcalloc(1, sizeof *ictx);
863 ictx->wp = wp;
864 ictx->event = bev;
865 ictx->palette = palette;
866 ictx->c = c;
867
868 ictx->input_space = INPUT_BUF_START;
869 ictx->input_buf = xmalloc(INPUT_BUF_START);
870
871 ictx->since_ground = evbuffer_new();
872 if (ictx->since_ground == NULL)
873 fatalx("out of memory");
874 evtimer_set(&ictx->ground_timer, input_ground_timer_callback, ictx);
875
876 TAILQ_INIT(&ictx->requests);
877 evtimer_set(&ictx->request_timer, input_request_timer_callback, ictx);
878
879 input_reset(ictx, 0);
880 return (ictx);
881}
882
883/* Destroy input parser. */
884void
885input_free(struct input_ctx *ictx)
886{
887 struct input_request *ir, *ir1;
888 u_int i;
889
890 for (i = 0; i < ictx->param_list_len; i++) {
891 if (ictx->param_list[i].type == INPUT_STRING)
892 free(ictx->param_list[i].str);
893 }
894
895 TAILQ_FOREACH_SAFE(ir, &ictx->requests, entry, ir1)
896 input_free_request(ir);
897 event_del(&ictx->request_timer);
898
899 free(ictx->input_buf);
900 evbuffer_free(ictx->since_ground);
901 event_del(&ictx->ground_timer);
902
903 screen_write_stop_sync(ictx->wp);
904
905 free(ictx);
906}
907
908/* Reset input state and clear screen. */
909void
910input_reset(struct input_ctx *ictx, int clear)
911{
912 struct screen_write_ctx *sctx = &ictx->ctx;
913 struct window_pane *wp = ictx->wp;
914
915 input_reset_cell(ictx);
916
917 if (clear && wp != NULL) {
918 if (TAILQ_EMPTY(&wp->modes))
919 screen_write_start_pane(sctx, wp, &wp->base);
920 else
921 screen_write_start(sctx, &wp->base);
922 screen_write_reset(sctx);
923 screen_write_stop(sctx);
924 }
925
926 input_clear(ictx);
927
928 ictx->state = &input_state_ground;
929 ictx->flags = 0;
930}
931
932/* Return pending data. */
933struct evbuffer *
934input_pending(struct input_ctx *ictx)
935{
936 return (ictx->since_ground);
937}
938
939/* Change input state. */
940static void
941input_set_state(struct input_ctx *ictx, const struct input_transition *itr)
942{
943 if (ictx->state->exit != NULL)
944 ictx->state->exit(ictx);
945 ictx->state = itr->state;
946 if (ictx->state->enter != NULL)
947 ictx->state->enter(ictx);
948}
949
950/* Parse data. */
951static void
952input_parse(struct input_ctx *ictx, u_char *buf, size_t len)
953{
954 struct screen_write_ctx *sctx = &ictx->ctx;
955 const struct input_state *state = NULL;
956 const struct input_transition *itr = NULL;
957 size_t off = 0;
958
959 /* Parse the input. */
960 while (off < len) {
961 ictx->ch = buf[off++];
962
963 /* Find the transition. */
964 if (ictx->state != state ||
965 itr == NULL ||
966 ictx->ch < itr->first ||
967 ictx->ch > itr->last) {
968 itr = ictx->state->transitions;
969 while (itr->first != -1 && itr->last != -1) {
970 if (ictx->ch >= itr->first &&
971 ictx->ch <= itr->last)
972 break;
973 itr++;
974 }
975 if (itr->first == -1 || itr->last == -1) {
976 /* No transition? Eh? */
977 fatalx("no transition from state");
978 }
979 }
980 state = ictx->state;
981
982 /*
983 * Any state except print stops the current collection. This is
984 * an optimization to avoid checking if the attributes have
985 * changed for every character. It will stop unnecessarily for
986 * sequences that don't make a terminal change, but they should
987 * be the minority.
988 */
989 if (itr->handler != input_print)
990 screen_write_collect_end(sctx);
991
992 /*
993 * Execute the handler, if any. Don't switch state if it
994 * returns non-zero.
995 */
996 if (itr->handler != NULL && itr->handler(ictx) != 0)
997 continue;
998
999 /* And switch state, if necessary. */
1000 if (itr->state != NULL)
1001 input_set_state(ictx, itr);
1002
1003 /* If not in ground state, save input. */
1004 if (ictx->state != &input_state_ground)
1005 evbuffer_add(ictx->since_ground, &ictx->ch, 1);
1006 }
1007}
1008
1009/* Parse input from pane. */
1010void
1011input_parse_pane(struct window_pane *wp)
1012{
1013 void *new_data;
1014 size_t new_size;
1015
1016 new_data = window_pane_get_new_data(wp, &wp->offset, &new_size);
1017 input_parse_buffer(wp, new_data, new_size);
1018 window_pane_update_used_data(wp, &wp->offset, new_size);
1019}
1020
1021/* Parse given input. */
1022void
1023input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
1024{
1025 struct input_ctx *ictx = wp->ictx;
1026 struct screen_write_ctx *sctx = &ictx->ctx;
1027
1028 if (len == 0)
1029 return;
1030
1031 window_update_activity(wp->window);
1032 wp->flags |= PANE_CHANGED;
1033
1034 /* Flag new input while in a mode. */
1035 if (!TAILQ_EMPTY(&wp->modes))
1036 wp->flags |= PANE_UNSEENCHANGES;
1037
1038 /* NULL wp if there is a mode set as don't want to update the tty. */
1039 if (TAILQ_EMPTY(&wp->modes))
1040 screen_write_start_pane(sctx, wp, &wp->base);
1041 else
1042 screen_write_start(sctx, &wp->base);
1043
1044 log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
1045 ictx->state->name, len, (int)len, buf);
1046
1047 input_parse(ictx, buf, len);
1048 screen_write_stop(sctx);
1049}
1050
1051/* Parse given input for screen. */
1052void
1053input_parse_screen(struct input_ctx *ictx, struct screen *s,
1054 screen_write_init_ctx_cb cb, void *arg, u_char *buf, size_t len)
1055{
1056 struct screen_write_ctx *sctx = &ictx->ctx;
1057
1058 if (len == 0)
1059 return;
1060
1061 screen_write_start_callback(sctx, s, cb, arg);
1062 input_parse(ictx, buf, len);
1063 screen_write_stop(sctx);
1064}
1065
1066/* Split the parameter list (if any). */
1067static int
1068input_split(struct input_ctx *ictx)
1069{
1070 const char *errstr;
1071 char *ptr, *out;
1072 struct input_param *ip;
1073 u_int i;
1074
1075 for (i = 0; i < ictx->param_list_len; i++) {
1076 if (ictx->param_list[i].type == INPUT_STRING)
1077 free(ictx->param_list[i].str);
1078 }
1079 ictx->param_list_len = 0;
1080
1081 if (ictx->param_len == 0)
1082 return (0);
1083 ip = &ictx->param_list[0];
1084
1085 ptr = ictx->param_buf;
1086 while ((out = strsep(&ptr, ";")) != NULL) {
1087 if (*out == '\0')
1088 ip->type = INPUT_MISSING;
1089 else {
1090 if (strchr(out, ':') != NULL) {
1091 ip->type = INPUT_STRING;
1092 ip->str = xstrdup(out);
1093 } else {
1094 ip->type = INPUT_NUMBER;
1095 ip->num = strtonum(out, 0, INT_MAX, &errstr);
1096 if (errstr != NULL)
1097 return (-1);
1098 }
1099 }
1100 ip = &ictx->param_list[++ictx->param_list_len];
1101 if (ictx->param_list_len == nitems(ictx->param_list))
1102 return (-1);
1103 }
1104
1105 for (i = 0; i < ictx->param_list_len; i++) {
1106 ip = &ictx->param_list[i];
1107 if (ip->type == INPUT_MISSING)
1108 log_debug("parameter %u: missing", i);
1109 else if (ip->type == INPUT_STRING)
1110 log_debug("parameter %u: string %s", i, ip->str);
1111 else if (ip->type == INPUT_NUMBER)
1112 log_debug("parameter %u: number %d", i, ip->num);
1113 }
1114
1115 return (0);
1116}
1117
1118/* Get an argument or return default value. */
1119static int
1120input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1121{
1122 struct input_param *ip;
1123 int retval;
1124
1125 if (validx >= ictx->param_list_len)
1126 return (defval);
1127 ip = &ictx->param_list[validx];
1128 if (ip->type == INPUT_MISSING)
1129 return (defval);
1130 if (ip->type == INPUT_STRING)
1131 return (-1);
1132 retval = ip->num;
1133 if (retval < minval)
1134 return (minval);
1135 return (retval);
1136}
1137
1138/* Send reply. */
1139static void
1140input_send_reply(struct input_ctx *ictx, const char *reply)
1141{
1142 if (ictx->event != NULL) {
1143 log_debug("%s: %s", __func__, reply);
1144 bufferevent_write(ictx->event, reply, strlen(reply));
1145 }
1146}
1147
1148/* Reply to terminal query. */
1149static void printflike(3, 4)
1150input_reply(struct input_ctx *ictx, int add, const char *fmt, ...)
1151{
1152 struct input_request *ir;
1153 va_list ap;
1154 char *reply;
1155
1156 va_start(ap, fmt);
1157 xvasprintf(&reply, fmt, ap);
1158 va_end(ap);
1159
1160 if (add && !TAILQ_EMPTY(&ictx->requests)) {
1161 ir = input_make_request(ictx, INPUT_REQUEST_QUEUE);
1162 ir->data = reply;
1163 } else {
1164 input_send_reply(ictx, reply);
1165 free(reply);
1166 }
1167}
1168
1169/* Clear saved state. */
1170static void
1171input_clear(struct input_ctx *ictx)
1172{
1173 event_del(&ictx->ground_timer);
1174
1175 *ictx->interm_buf = '\0';
1176 ictx->interm_len = 0;
1177
1178 *ictx->param_buf = '\0';
1179 ictx->param_len = 0;
1180
1181 *ictx->input_buf = '\0';
1182 ictx->input_len = 0;
1183
1184 ictx->input_end = INPUT_END_ST;
1185
1186 ictx->flags &= ~INPUT_DISCARD;
1187}
1188
1189/* Reset for ground state. */
1190static void
1191input_ground(struct input_ctx *ictx)
1192{
1193 event_del(&ictx->ground_timer);
1194 evbuffer_drain(ictx->since_ground, EVBUFFER_LENGTH(ictx->since_ground));
1195
1196 if (ictx->input_space > INPUT_BUF_START) {
1197 ictx->input_space = INPUT_BUF_START;
1198 ictx->input_buf = xrealloc(ictx->input_buf, INPUT_BUF_START);
1199 }
1200}
1201
1202/* Output this character to the screen. */
1203static int
1204input_print(struct input_ctx *ictx)
1205{
1206 struct screen_write_ctx *sctx = &ictx->ctx;
1207 int set;
1208
1209 input_stop_utf8(ictx); /* can't be valid UTF-8 */
1210
1211 set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
1212 if (set == 1)
1213 ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
1214 else
1215 ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1216 utf8_set(&ictx->cell.cell.data, ictx->ch);
1217 screen_write_collect_add(sctx, &ictx->cell.cell);
1218
1219 utf8_copy(&ictx->last, &ictx->cell.cell.data);
1220 ictx->flags |= INPUT_LAST;
1221
1222 ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1223
1224 return (0);
1225}
1226
1227/* Collect intermediate string. */
1228static int
1229input_intermediate(struct input_ctx *ictx)
1230{
1231 if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
1232 ictx->flags |= INPUT_DISCARD;
1233 else {
1234 ictx->interm_buf[ictx->interm_len++] = ictx->ch;
1235 ictx->interm_buf[ictx->interm_len] = '\0';
1236 }
1237
1238 return (0);
1239}
1240
1241/* Collect parameter string. */
1242static int
1243input_parameter(struct input_ctx *ictx)
1244{
1245 if (ictx->param_len == (sizeof ictx->param_buf) - 1)
1246 ictx->flags |= INPUT_DISCARD;
1247 else {
1248 ictx->param_buf[ictx->param_len++] = ictx->ch;
1249 ictx->param_buf[ictx->param_len] = '\0';
1250 }
1251
1252 return (0);
1253}
1254
1255/* Collect input string. */
1256static int
1257input_input(struct input_ctx *ictx)
1258{
1259 size_t available;
1260
1261 available = ictx->input_space;
1262 while (ictx->input_len + 1 >= available) {
1263 available *= 2;
1264 if (available > input_buffer_size) {
1265 ictx->flags |= INPUT_DISCARD;
1266 return (0);
1267 }
1268 ictx->input_buf = xrealloc(ictx->input_buf, available);
1269 ictx->input_space = available;
1270 }
1271 ictx->input_buf[ictx->input_len++] = ictx->ch;
1272 ictx->input_buf[ictx->input_len] = '\0';
1273
1274 return (0);
1275}
1276
1277/* Execute C0 control sequence. */
1278static int
1279input_c0_dispatch(struct input_ctx *ictx)
1280{
1281 struct screen_write_ctx *sctx = &ictx->ctx;
1282 struct window_pane *wp = ictx->wp;
1283 struct screen *s = sctx->s;
1284 struct grid_cell gc, first_gc;
1285 u_int cx, line;
1286 u_int width;
1287 int has_content = 0;
1288
1289 input_stop_utf8(ictx); /* can't be valid UTF-8 */
1290
1291 log_debug("%s: '%c'", __func__, ictx->ch);
1292
1293 switch (ictx->ch) {
1294 case '\000': /* NUL */
1295 break;
1296 case '\007': /* BEL */
1297 if (wp != NULL)
1298 alerts_queue(wp->window, WINDOW_BELL);
1299 break;
1300 case '\010': /* BS */
1301 screen_write_backspace(sctx);
1302 break;
1303 case '\011': /* HT */
1304 /* Don't tab beyond the end of the line. */
1305 cx = s->cx;
1306 if (cx >= screen_size_x(s) - 1)
1307 break;
1308
1309 /* Find the next tab point, or use the last column if none. */
1310 line = s->cy + s->grid->hsize;
1311 grid_get_cell(s->grid, cx, line, &first_gc);
1312 do {
1313 if (!has_content) {
1314 grid_get_cell(s->grid, cx, line, &gc);
1315 if (gc.data.size != 1 ||
1316 *gc.data.data != ' ' ||
1317 !grid_cells_look_equal(&gc, &first_gc))
1318 has_content = 1;
1319 }
1320 cx++;
1321 if (bit_test(s->tabs, cx))
1322 break;
1323 } while (cx < screen_size_x(s) - 1);
1324
1325 width = cx - s->cx;
1326 if (has_content || width > sizeof gc.data.data)
1327 s->cx = cx;
1328 else {
1329 grid_get_cell(s->grid, s->cx, line, &gc);
1330 grid_set_tab(&gc, width);
1331 screen_write_collect_add(sctx, &gc);
1332 }
1333 break;
1334 case '\012': /* LF */
1335 case '\013': /* VT */
1336 case '\014': /* FF */
1337 screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1338 if (s->mode & MODE_CRLF)
1339 screen_write_carriagereturn(sctx);
1340 break;
1341 case '\015': /* CR */
1342 screen_write_carriagereturn(sctx);
1343 break;
1344 case '\016': /* SO */
1345 ictx->cell.set = 1;
1346 break;
1347 case '\017': /* SI */
1348 ictx->cell.set = 0;
1349 break;
1350 default:
1351 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1352 break;
1353 }
1354
1355 ictx->flags &= ~INPUT_LAST;
1356 return (0);
1357}
1358
1359/* Execute escape sequence. */
1360static int
1361input_esc_dispatch(struct input_ctx *ictx)
1362{
1363 struct screen_write_ctx *sctx = &ictx->ctx;
1364 struct screen *s = sctx->s;
1365 struct input_table_entry *entry;
1366
1367 if (ictx->flags & INPUT_DISCARD)
1368 return (0);
1369 log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1370
1371 entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1372 sizeof input_esc_table[0], input_table_compare);
1373 if (entry == NULL) {
1374 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1375 return (0);
1376 }
1377
1378 switch (entry->type) {
1379 case INPUT_ESC_RIS:
1380 colour_palette_clear(ictx->palette);
1381 input_reset_cell(ictx);
1382 screen_write_reset(sctx);
1383 screen_write_fullredraw(sctx);
1384 break;
1385 case INPUT_ESC_IND:
1386 screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1387 break;
1388 case INPUT_ESC_NEL:
1389 screen_write_carriagereturn(sctx);
1390 screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1391 break;
1392 case INPUT_ESC_HTS:
1393 if (s->cx < screen_size_x(s))
1394 bit_set(s->tabs, s->cx);
1395 break;
1396 case INPUT_ESC_RI:
1397 screen_write_reverseindex(sctx, ictx->cell.cell.bg);
1398 break;
1399 case INPUT_ESC_DECKPAM:
1400 screen_write_mode_set(sctx, MODE_KKEYPAD);
1401 break;
1402 case INPUT_ESC_DECKPNM:
1403 screen_write_mode_clear(sctx, MODE_KKEYPAD);
1404 break;
1405 case INPUT_ESC_DECSC:
1406 input_save_state(ictx);
1407 break;
1408 case INPUT_ESC_DECRC:
1409 input_restore_state(ictx);
1410 break;
1411 case INPUT_ESC_DECALN:
1412 screen_write_alignmenttest(sctx);
1413 break;
1414 case INPUT_ESC_SCSG0_ON:
1415 ictx->cell.g0set = 1;
1416 break;
1417 case INPUT_ESC_SCSG0_OFF:
1418 ictx->cell.g0set = 0;
1419 break;
1420 case INPUT_ESC_SCSG1_ON:
1421 ictx->cell.g1set = 1;
1422 break;
1423 case INPUT_ESC_SCSG1_OFF:
1424 ictx->cell.g1set = 0;
1425 break;
1426 case INPUT_ESC_ST:
1427 /* ST terminates OSC but the state transition already did it. */
1428 break;
1429 }
1430
1431 ictx->flags &= ~INPUT_LAST;
1432 return (0);
1433}
1434
1435/* Execute control sequence. */
1436static int
1437input_csi_dispatch(struct input_ctx *ictx)
1438{
1439 struct screen_write_ctx *sctx = &ictx->ctx;
1440 struct screen *s = sctx->s;
1441 struct input_table_entry *entry;
1442 struct options *oo;
1443 int i, n, m, ek, set, p;
1444 u_int cx, bg = ictx->cell.cell.bg;
1445
1446 if (ictx->flags & INPUT_DISCARD)
1447 return (0);
1448
1449 log_debug("%s: '%c' \"%s\" \"%s\"", __func__, ictx->ch,
1450 ictx->interm_buf, ictx->param_buf);
1451
1452 if (input_split(ictx) != 0)
1453 return (0);
1454
1455 entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1456 sizeof input_csi_table[0], input_table_compare);
1457 if (entry == NULL) {
1458 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1459 return (0);
1460 }
1461
1462 switch (entry->type) {
1463 case INPUT_CSI_CBT:
1464 /* Find the previous tab point, n times. */
1465 cx = s->cx;
1466 if (cx > screen_size_x(s) - 1)
1467 cx = screen_size_x(s) - 1;
1468 n = input_get(ictx, 0, 1, 1);
1469 if (n == -1)
1470 break;
1471 while (cx > 0 && n-- > 0) {
1472 do
1473 cx--;
1474 while (cx > 0 && !bit_test(s->tabs, cx));
1475 }
1476 s->cx = cx;
1477 break;
1478 case INPUT_CSI_CUB:
1479 n = input_get(ictx, 0, 1, 1);
1480 if (n != -1)
1481 screen_write_cursorleft(sctx, n);
1482 break;
1483 case INPUT_CSI_CUD:
1484 n = input_get(ictx, 0, 1, 1);
1485 if (n != -1)
1486 screen_write_cursordown(sctx, n);
1487 break;
1488 case INPUT_CSI_CUF:
1489 n = input_get(ictx, 0, 1, 1);
1490 if (n != -1)
1491 screen_write_cursorright(sctx, n);
1492 break;
1493 case INPUT_CSI_CUP:
1494 n = input_get(ictx, 0, 1, 1);
1495 m = input_get(ictx, 1, 1, 1);
1496 if (n != -1 && m != -1)
1497 screen_write_cursormove(sctx, m - 1, n - 1, 1);
1498 break;
1499 case INPUT_CSI_MODSET:
1500 n = input_get(ictx, 0, 0, 0);
1501 if (n != 4)
1502 break;
1503 m = input_get(ictx, 1, 0, 0);
1504
1505 /*
1506 * Set the extended key reporting mode as per the client
1507 * request, unless "extended-keys" is set to "off".
1508 */
1509 ek = options_get_number(global_options, "extended-keys");
1510 if (ek == 0)
1511 break;
1512 screen_write_mode_clear(sctx, EXTENDED_KEY_MODES);
1513 if (m == 2)
1514 screen_write_mode_set(sctx, MODE_KEYS_EXTENDED_2);
1515 else if (m == 1 || ek == 2)
1516 screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
1517 break;
1518 case INPUT_CSI_MODOFF:
1519 n = input_get(ictx, 0, 0, 0);
1520 if (n != 4)
1521 break;
1522
1523 /*
1524 * Clear the extended key reporting mode as per the client
1525 * request, unless "extended-keys always" forces into mode 1.
1526 */
1527 screen_write_mode_clear(sctx,
1528 MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2);
1529 if (options_get_number(global_options, "extended-keys") == 2)
1530 screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
1531 break;
1532 case INPUT_CSI_WINOPS:
1533 input_csi_dispatch_winops(ictx);
1534 break;
1535 case INPUT_CSI_CUU:
1536 n = input_get(ictx, 0, 1, 1);
1537 if (n != -1)
1538 screen_write_cursorup(sctx, n);
1539 break;
1540 case INPUT_CSI_CNL:
1541 n = input_get(ictx, 0, 1, 1);
1542 if (n != -1) {
1543 screen_write_carriagereturn(sctx);
1544 screen_write_cursordown(sctx, n);
1545 }
1546 break;
1547 case INPUT_CSI_CPL:
1548 n = input_get(ictx, 0, 1, 1);
1549 if (n != -1) {
1550 screen_write_carriagereturn(sctx);
1551 screen_write_cursorup(sctx, n);
1552 }
1553 break;
1554 case INPUT_CSI_DA:
1555 switch (input_get(ictx, 0, 0, 0)) {
1556 case -1:
1557 break;
1558 case 0:
1559 input_reply(ictx, 1, "\033[?1;2c");
1560 break;
1561 default:
1562 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1563 break;
1564 }
1565 break;
1566 case INPUT_CSI_DA_TWO:
1567 switch (input_get(ictx, 0, 0, 0)) {
1568 case -1:
1569 break;
1570 case 0:
1571 input_reply(ictx, 1, "\033[>84;0;0c");
1572 break;
1573 default:
1574 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1575 break;
1576 }
1577 break;
1578 case INPUT_CSI_ECH:
1579 n = input_get(ictx, 0, 1, 1);
1580 if (n != -1)
1581 screen_write_clearcharacter(sctx, n, bg);
1582 break;
1583 case INPUT_CSI_DCH:
1584 n = input_get(ictx, 0, 1, 1);
1585 if (n != -1)
1586 screen_write_deletecharacter(sctx, n, bg);
1587 break;
1588 case INPUT_CSI_DECSTBM:
1589 n = input_get(ictx, 0, 1, 1);
1590 m = input_get(ictx, 1, 1, screen_size_y(s));
1591 if (n != -1 && m != -1)
1592 screen_write_scrollregion(sctx, n - 1, m - 1);
1593 break;
1594 case INPUT_CSI_DL:
1595 n = input_get(ictx, 0, 1, 1);
1596 if (n != -1)
1597 screen_write_deleteline(sctx, n, bg);
1598 break;
1599 case INPUT_CSI_DSR_PRIVATE:
1600 switch (input_get(ictx, 0, 0, 0)) {
1601 case 996:
1602 input_report_current_theme(ictx);
1603 break;
1604 }
1605 break;
1606 case INPUT_CSI_QUERY_PRIVATE:
1607 switch (input_get(ictx, 0, 0, 0)) {
1608 case 12: /* cursor blink: 1 = blink, 2 = steady */
1609 if (s->cstyle != SCREEN_CURSOR_DEFAULT ||
1610 s->mode & MODE_CURSOR_BLINKING_SET)
1611 n = (s->mode & MODE_CURSOR_BLINKING) ? 1 : 2;
1612 else {
1613 if (ictx->wp != NULL)
1614 oo = ictx->wp->options;
1615 else
1616 oo = global_options;
1617 p = options_get_number(oo, "cursor-style");
1618
1619 /* blink for 1,3,5; steady for 0,2,4,6 */
1620 n = (p == 1 || p == 3 || p == 5) ? 1 : 2;
1621 }
1622 input_reply(ictx, 1, "\033[?12;%d$y", n);
1623 break;
1624 case 2004: /* bracketed paste */
1625 n = (s->mode & MODE_BRACKETPASTE) ? 1 : 2;
1626 input_reply(ictx, 1, "\033[?2004;%d$y", n);
1627 break;
1628 case 1004: /* focus reporting */
1629 n = (s->mode & MODE_FOCUSON) ? 1 : 2;
1630 input_reply(ictx, 1, "\033[?1004;%d$y", n);
1631 break;
1632 case 1006: /* SGR mouse */
1633 n = (s->mode & MODE_MOUSE_SGR) ? 1 : 2;
1634 input_reply(ictx, 1, "\033[?1006;%d$y", n);
1635 break;
1636 case 2031:
1637 input_reply(ictx, 1, "\033[?2031;2$y");
1638 break;
1639 }
1640 break;
1641 case INPUT_CSI_DSR:
1642 switch (input_get(ictx, 0, 0, 0)) {
1643 case -1:
1644 break;
1645 case 5:
1646 input_reply(ictx, 1, "\033[0n");
1647 break;
1648 case 6:
1649 input_reply(ictx, 1, "\033[%u;%uR", s->cy + 1,
1650 s->cx + 1);
1651 break;
1652 default:
1653 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1654 break;
1655 }
1656 break;
1657 case INPUT_CSI_ED:
1658 switch (input_get(ictx, 0, 0, 0)) {
1659 case -1:
1660 break;
1661 case 0:
1662 screen_write_clearendofscreen(sctx, bg);
1663 break;
1664 case 1:
1665 screen_write_clearstartofscreen(sctx, bg);
1666 break;
1667 case 2:
1668 screen_write_clearscreen(sctx, bg);
1669 break;
1670 case 3:
1671 if (input_get(ictx, 1, 0, 0) == 0) {
1672 /*
1673 * Linux console extension to clear history
1674 * (for example before locking the screen).
1675 */
1676 screen_write_clearhistory(sctx);
1677 }
1678 break;
1679 default:
1680 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1681 break;
1682 }
1683 break;
1684 case INPUT_CSI_EL:
1685 switch (input_get(ictx, 0, 0, 0)) {
1686 case -1:
1687 break;
1688 case 0:
1689 screen_write_clearendofline(sctx, bg);
1690 break;
1691 case 1:
1692 screen_write_clearstartofline(sctx, bg);
1693 break;
1694 case 2:
1695 screen_write_clearline(sctx, bg);
1696 break;
1697 default:
1698 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1699 break;
1700 }
1701 break;
1702 case INPUT_CSI_HPA:
1703 n = input_get(ictx, 0, 1, 1);
1704 if (n != -1)
1705 screen_write_cursormove(sctx, n - 1, -1, 1);
1706 break;
1707 case INPUT_CSI_ICH:
1708 n = input_get(ictx, 0, 1, 1);
1709 if (n != -1)
1710 screen_write_insertcharacter(sctx, n, bg);
1711 break;
1712 case INPUT_CSI_IL:
1713 n = input_get(ictx, 0, 1, 1);
1714 if (n != -1)
1715 screen_write_insertline(sctx, n, bg);
1716 break;
1717 case INPUT_CSI_REP:
1718 n = input_get(ictx, 0, 1, 1);
1719 if (n == -1)
1720 break;
1721
1722 m = screen_size_x(s) - s->cx;
1723 if (n > m)
1724 n = m;
1725
1726 if (~ictx->flags & INPUT_LAST)
1727 break;
1728
1729 set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
1730 if (set == 1)
1731 ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
1732 else
1733 ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1734 utf8_copy(&ictx->cell.cell.data, &ictx->last);
1735 for (i = 0; i < n; i++)
1736 screen_write_collect_add(sctx, &ictx->cell.cell);
1737 break;
1738 case INPUT_CSI_RCP:
1739 input_restore_state(ictx);
1740 break;
1741 case INPUT_CSI_RM:
1742 input_csi_dispatch_rm(ictx);
1743 break;
1744 case INPUT_CSI_RM_PRIVATE:
1745 input_csi_dispatch_rm_private(ictx);
1746 break;
1747 case INPUT_CSI_SCP:
1748 input_save_state(ictx);
1749 break;
1750 case INPUT_CSI_SGR:
1751 input_csi_dispatch_sgr(ictx);
1752 break;
1753 case INPUT_CSI_SM:
1754 input_csi_dispatch_sm(ictx);
1755 break;
1756 case INPUT_CSI_SM_PRIVATE:
1757 input_csi_dispatch_sm_private(ictx);
1758 break;
1759 case INPUT_CSI_SM_GRAPHICS:
1760 input_csi_dispatch_sm_graphics(ictx);
1761 break;
1762 case INPUT_CSI_SU:
1763 n = input_get(ictx, 0, 1, 1);
1764 if (n != -1)
1765 screen_write_scrollup(sctx, n, bg);
1766 break;
1767 case INPUT_CSI_SD:
1768 n = input_get(ictx, 0, 1, 1);
1769 if (n != -1)
1770 screen_write_scrolldown(sctx, n, bg);
1771 break;
1772 case INPUT_CSI_TBC:
1773 switch (input_get(ictx, 0, 0, 0)) {
1774 case -1:
1775 break;
1776 case 0:
1777 if (s->cx < screen_size_x(s))
1778 bit_clear(s->tabs, s->cx);
1779 break;
1780 case 3:
1781 bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1782 break;
1783 default:
1784 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1785 break;
1786 }
1787 break;
1788 case INPUT_CSI_VPA:
1789 n = input_get(ictx, 0, 1, 1);
1790 if (n != -1)
1791 screen_write_cursormove(sctx, -1, n - 1, 1);
1792 break;
1793 case INPUT_CSI_DECSCUSR:
1794 n = input_get(ictx, 0, 0, 0);
1795 if (n == -1)
1796 break;
1797 screen_set_cursor_style(n, &s->cstyle, &s->mode);
1798 if (n == 0) {
1799 /* Go back to default blinking state. */
1800 screen_write_mode_clear(sctx, MODE_CURSOR_BLINKING_SET);
1801 }
1802 break;
1803 case INPUT_CSI_XDA:
1804 n = input_get(ictx, 0, 0, 0);
1805 if (n == 0) {
1806 input_reply(ictx, 1, "\033P>|tmux %s\033\\",
1807 getversion());
1808 }
1809 break;
1810
1811 }
1812
1813 ictx->flags &= ~INPUT_LAST;
1814 return (0);
1815}
1816
1817/* Handle CSI RM. */
1818static void
1819input_csi_dispatch_rm(struct input_ctx *ictx)
1820{
1821 struct screen_write_ctx *sctx = &ictx->ctx;
1822 u_int i;
1823
1824 for (i = 0; i < ictx->param_list_len; i++) {
1825 switch (input_get(ictx, i, 0, -1)) {
1826 case -1:
1827 break;
1828 case 4: /* IRM */
1829 screen_write_mode_clear(sctx, MODE_INSERT);
1830 break;
1831 case 34:
1832 screen_write_mode_set(sctx, MODE_CURSOR_VERY_VISIBLE);
1833 break;
1834 default:
1835 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1836 break;
1837 }
1838 }
1839}
1840
1841/* Handle CSI private RM. */
1842static void
1843input_csi_dispatch_rm_private(struct input_ctx *ictx)
1844{
1845 struct screen_write_ctx *sctx = &ictx->ctx;
1846 struct grid_cell *gc = &ictx->cell.cell;
1847 u_int i;
1848
1849 for (i = 0; i < ictx->param_list_len; i++) {
1850 switch (input_get(ictx, i, 0, -1)) {
1851 case -1:
1852 break;
1853 case 1: /* DECCKM */
1854 screen_write_mode_clear(sctx, MODE_KCURSOR);
1855 break;
1856 case 3: /* DECCOLM */
1857 screen_write_cursormove(sctx, 0, 0, 1);
1858 screen_write_clearscreen(sctx, gc->bg);
1859 break;
1860 case 6: /* DECOM */
1861 screen_write_mode_clear(sctx, MODE_ORIGIN);
1862 screen_write_cursormove(sctx, 0, 0, 1);
1863 break;
1864 case 7: /* DECAWM */
1865 screen_write_mode_clear(sctx, MODE_WRAP);
1866 break;
1867 case 12:
1868 screen_write_mode_clear(sctx, MODE_CURSOR_BLINKING);
1869 screen_write_mode_set(sctx, MODE_CURSOR_BLINKING_SET);
1870 break;
1871 case 25: /* TCEM */
1872 screen_write_mode_clear(sctx, MODE_CURSOR);
1873 break;
1874 case 1000:
1875 case 1001:
1876 case 1002:
1877 case 1003:
1878 screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1879 break;
1880 case 1004:
1881 screen_write_mode_clear(sctx, MODE_FOCUSON);
1882 break;
1883 case 1005:
1884 screen_write_mode_clear(sctx, MODE_MOUSE_UTF8);
1885 break;
1886 case 1006:
1887 screen_write_mode_clear(sctx, MODE_MOUSE_SGR);
1888 break;
1889 case 47:
1890 case 1047:
1891 screen_write_alternateoff(sctx, gc, 0);
1892 break;
1893 case 1049:
1894 screen_write_alternateoff(sctx, gc, 1);
1895 break;
1896 case 2004:
1897 screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
1898 break;
1899 case 2031:
1900 screen_write_mode_clear(sctx, MODE_THEME_UPDATES);
1901 if (ictx->wp != NULL)
1902 ictx->wp->flags &= ~PANE_THEMECHANGED;
1903 break;
1904 case 2026: /* synchronized output */
1905 screen_write_stop_sync(ictx->wp);
1906 if (ictx->wp != NULL)
1907 ictx->wp->flags |= PANE_REDRAW;
1908 break;
1909 default:
1910 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1911 break;
1912 }
1913 }
1914}
1915
1916/* Handle CSI SM. */
1917static void
1918input_csi_dispatch_sm(struct input_ctx *ictx)
1919{
1920 struct screen_write_ctx *sctx = &ictx->ctx;
1921 u_int i;
1922
1923 for (i = 0; i < ictx->param_list_len; i++) {
1924 switch (input_get(ictx, i, 0, -1)) {
1925 case -1:
1926 break;
1927 case 4: /* IRM */
1928 screen_write_mode_set(sctx, MODE_INSERT);
1929 break;
1930 case 34:
1931 screen_write_mode_clear(sctx, MODE_CURSOR_VERY_VISIBLE);
1932 break;
1933 default:
1934 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1935 break;
1936 }
1937 }
1938}
1939
1940/* Handle CSI private SM. */
1941static void
1942input_csi_dispatch_sm_private(struct input_ctx *ictx)
1943{
1944 struct screen_write_ctx *sctx = &ictx->ctx;
1945 struct grid_cell *gc = &ictx->cell.cell;
1946 u_int i;
1947
1948 for (i = 0; i < ictx->param_list_len; i++) {
1949 switch (input_get(ictx, i, 0, -1)) {
1950 case -1:
1951 break;
1952 case 1: /* DECCKM */
1953 screen_write_mode_set(sctx, MODE_KCURSOR);
1954 break;
1955 case 3: /* DECCOLM */
1956 screen_write_cursormove(sctx, 0, 0, 1);
1957 screen_write_clearscreen(sctx, ictx->cell.cell.bg);
1958 break;
1959 case 6: /* DECOM */
1960 screen_write_mode_set(sctx, MODE_ORIGIN);
1961 screen_write_cursormove(sctx, 0, 0, 1);
1962 break;
1963 case 7: /* DECAWM */
1964 screen_write_mode_set(sctx, MODE_WRAP);
1965 break;
1966 case 12:
1967 screen_write_mode_set(sctx, MODE_CURSOR_BLINKING);
1968 screen_write_mode_set(sctx, MODE_CURSOR_BLINKING_SET);
1969 break;
1970 case 25: /* TCEM */
1971 screen_write_mode_set(sctx, MODE_CURSOR);
1972 break;
1973 case 1000:
1974 screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1975 screen_write_mode_set(sctx, MODE_MOUSE_STANDARD);
1976 break;
1977 case 1002:
1978 screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1979 screen_write_mode_set(sctx, MODE_MOUSE_BUTTON);
1980 break;
1981 case 1003:
1982 screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1983 screen_write_mode_set(sctx, MODE_MOUSE_ALL);
1984 break;
1985 case 1004:
1986 screen_write_mode_set(sctx, MODE_FOCUSON);
1987 break;
1988 case 1005:
1989 screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
1990 break;
1991 case 1006:
1992 screen_write_mode_set(sctx, MODE_MOUSE_SGR);
1993 break;
1994 case 47:
1995 case 1047:
1996 screen_write_alternateon(sctx, gc, 0);
1997 break;
1998 case 1049:
1999 screen_write_alternateon(sctx, gc, 1);
2000 break;
2001 case 2004:
2002 screen_write_mode_set(sctx, MODE_BRACKETPASTE);
2003 break;
2004 case 2031:
2005 screen_write_mode_set(sctx, MODE_THEME_UPDATES);
2006 if (ictx->wp != NULL) {
2007 ictx->wp->last_theme = window_pane_get_theme(ictx->wp);
2008 ictx->wp->flags &= ~PANE_THEMECHANGED;
2009 }
2010 break;
2011 case 2026: /* synchronized output */
2012 screen_write_start_sync(ictx->wp);
2013 break;
2014 default:
2015 log_debug("%s: unknown '%c'", __func__, ictx->ch);
2016 break;
2017 }
2018 }
2019}
2020
2021/* Handle CSI graphics SM. */
2022static void
2023input_csi_dispatch_sm_graphics(__unused struct input_ctx *ictx)
2024{
2025}
2026
2027/* Handle CSI window operations. */
2028static void
2029input_csi_dispatch_winops(struct input_ctx *ictx)
2030{
2031 struct screen_write_ctx *sctx = &ictx->ctx;
2032 struct screen *s = sctx->s;
2033 struct window_pane *wp = ictx->wp;
2034 struct window *w = NULL;
2035 u_int x = screen_size_x(s), y = screen_size_y(s);
2036 int n, m;
2037
2038 if (wp != NULL)
2039 w = wp->window;
2040
2041 m = 0;
2042 while ((n = input_get(ictx, m, 0, -1)) != -1) {
2043 switch (n) {
2044 case 1:
2045 case 2:
2046 case 5:
2047 case 6:
2048 case 7:
2049 case 11:
2050 case 13:
2051 case 20:
2052 case 21:
2053 case 24:
2054 break;
2055 case 3:
2056 case 4:
2057 case 8:
2058 m++;
2059 if (input_get(ictx, m, 0, -1) == -1)
2060 return;
2061 /* FALLTHROUGH */
2062 case 9:
2063 case 10:
2064 m++;
2065 if (input_get(ictx, m, 0, -1) == -1)
2066 return;
2067 break;
2068 case 14:
2069 if (w == NULL)
2070 break;
2071 input_reply(ictx, 1, "\033[4;%u;%ut", y * w->ypixel,
2072 x * w->xpixel);
2073 break;
2074 case 15:
2075 if (w == NULL)
2076 break;
2077 input_reply(ictx, 1, "\033[5;%u;%ut", y * w->ypixel,
2078 x * w->xpixel);
2079 break;
2080 case 16:
2081 if (w == NULL)
2082 break;
2083 input_reply(ictx, 1, "\033[6;%u;%ut", w->ypixel,
2084 w->xpixel);
2085 break;
2086 case 18:
2087 input_reply(ictx, 1, "\033[8;%u;%ut", y, x);
2088 break;
2089 case 19:
2090 input_reply(ictx, 1, "\033[9;%u;%ut", y, x);
2091 break;
2092 case 22:
2093 m++;
2094 switch (input_get(ictx, m, 0, -1)) {
2095 case -1:
2096 return;
2097 case 0:
2098 case 2:
2099 screen_push_title(sctx->s);
2100 break;
2101 }
2102 break;
2103 case 23:
2104 m++;
2105 switch (input_get(ictx, m, 0, -1)) {
2106 case -1:
2107 return;
2108 case 0:
2109 case 2:
2110 screen_pop_title(sctx->s);
2111 if (wp == NULL)
2112 break;
2113 notify_pane("pane-title-changed", wp);
2114 server_redraw_window_borders(w);
2115 server_status_window(w);
2116 break;
2117 }
2118 break;
2119 default:
2120 log_debug("%s: unknown '%c'", __func__, ictx->ch);
2121 break;
2122 }
2123 m++;
2124 }
2125}
2126
2127/* Helper for 256 colour SGR. */
2128static int
2129input_csi_dispatch_sgr_256_do(struct input_ctx *ictx, int fgbg, int c)
2130{
2131 struct grid_cell *gc = &ictx->cell.cell;
2132
2133 if (c == -1 || c > 255) {
2134 if (fgbg == 38)
2135 gc->fg = 8;
2136 else if (fgbg == 48)
2137 gc->bg = 8;
2138 } else {
2139 if (fgbg == 38)
2140 gc->fg = c | COLOUR_FLAG_256;
2141 else if (fgbg == 48)
2142 gc->bg = c | COLOUR_FLAG_256;
2143 else if (fgbg == 58)
2144 gc->us = c | COLOUR_FLAG_256;
2145 }
2146 return (1);
2147}
2148
2149/* Handle CSI SGR for 256 colours. */
2150static void
2151input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
2152{
2153 int c;
2154
2155 c = input_get(ictx, (*i) + 1, 0, -1);
2156 if (input_csi_dispatch_sgr_256_do(ictx, fgbg, c))
2157 (*i)++;
2158}
2159
2160/* Helper for RGB colour SGR. */
2161static int
2162input_csi_dispatch_sgr_rgb_do(struct input_ctx *ictx, int fgbg, int r, int g,
2163 int b)
2164{
2165 struct grid_cell *gc = &ictx->cell.cell;
2166
2167 if (r == -1 || r > 255)
2168 return (0);
2169 if (g == -1 || g > 255)
2170 return (0);
2171 if (b == -1 || b > 255)
2172 return (0);
2173
2174 if (fgbg == 38)
2175 gc->fg = colour_join_rgb(r, g, b);
2176 else if (fgbg == 48)
2177 gc->bg = colour_join_rgb(r, g, b);
2178 else if (fgbg == 58)
2179 gc->us = colour_join_rgb(r, g, b);
2180 return (1);
2181}
2182
2183/* Handle CSI SGR for RGB colours. */
2184static void
2185input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
2186{
2187 int r, g, b;
2188
2189 r = input_get(ictx, (*i) + 1, 0, -1);
2190 g = input_get(ictx, (*i) + 2, 0, -1);
2191 b = input_get(ictx, (*i) + 3, 0, -1);
2192 if (input_csi_dispatch_sgr_rgb_do(ictx, fgbg, r, g, b))
2193 (*i) += 3;
2194}
2195
2196/* Handle CSI SGR with a ISO parameter. */
2197static void
2198input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
2199{
2200 struct grid_cell *gc = &ictx->cell.cell;
2201 char *s = ictx->param_list[i].str, *copy, *ptr, *out;
2202 int p[8];
2203 u_int n;
2204 const char *errstr;
2205
2206 for (n = 0; n < nitems(p); n++)
2207 p[n] = -1;
2208 n = 0;
2209
2210 ptr = copy = xstrdup(s);
2211 while ((out = strsep(&ptr, ":")) != NULL) {
2212 if (*out != '\0') {
2213 p[n++] = strtonum(out, 0, INT_MAX, &errstr);
2214 if (errstr != NULL || n == nitems(p)) {
2215 free(copy);
2216 return;
2217 }
2218 } else {
2219 n++;
2220 if (n == nitems(p)) {
2221 free(copy);
2222 return;
2223 }
2224 }
2225 log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]);
2226 }
2227 free(copy);
2228
2229 if (n == 0)
2230 return;
2231 if (p[0] == 4) {
2232 if (n != 2)
2233 return;
2234 switch (p[1]) {
2235 case 0:
2236 gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2237 break;
2238 case 1:
2239 gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2240 gc->attr |= GRID_ATTR_UNDERSCORE;
2241 break;
2242 case 2:
2243 gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2244 gc->attr |= GRID_ATTR_UNDERSCORE_2;
2245 break;
2246 case 3:
2247 gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2248 gc->attr |= GRID_ATTR_UNDERSCORE_3;
2249 break;
2250 case 4:
2251 gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2252 gc->attr |= GRID_ATTR_UNDERSCORE_4;
2253 break;
2254 case 5:
2255 gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2256 gc->attr |= GRID_ATTR_UNDERSCORE_5;
2257 break;
2258 }
2259 return;
2260 }
2261 if (n < 2 || (p[0] != 38 && p[0] != 48 && p[0] != 58))
2262 return;
2263 switch (p[1]) {
2264 case 2:
2265 if (n < 3)
2266 break;
2267 if (n == 5)
2268 i = 2;
2269 else
2270 i = 3;
2271 if (n < i + 3)
2272 break;
2273 input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i], p[i + 1],
2274 p[i + 2]);
2275 break;
2276 case 5:
2277 if (n < 3)
2278 break;
2279 input_csi_dispatch_sgr_256_do(ictx, p[0], p[2]);
2280 break;
2281 }
2282}
2283
2284/* Handle CSI SGR. */
2285static void
2286input_csi_dispatch_sgr(struct input_ctx *ictx)
2287{
2288 struct grid_cell *gc = &ictx->cell.cell;
2289 u_int i, link;
2290 int n;
2291
2292 if (ictx->param_list_len == 0) {
2293 memcpy(gc, &grid_default_cell, sizeof *gc);
2294 return;
2295 }
2296
2297 for (i = 0; i < ictx->param_list_len; i++) {
2298 if (ictx->param_list[i].type == INPUT_STRING) {
2299 input_csi_dispatch_sgr_colon(ictx, i);
2300 continue;
2301 }
2302 n = input_get(ictx, i, 0, 0);
2303 if (n == -1)
2304 continue;
2305
2306 if (n == 38 || n == 48 || n == 58) {
2307 i++;
2308 switch (input_get(ictx, i, 0, -1)) {
2309 case 2:
2310 input_csi_dispatch_sgr_rgb(ictx, n, &i);
2311 break;
2312 case 5:
2313 input_csi_dispatch_sgr_256(ictx, n, &i);
2314 break;
2315 }
2316 continue;
2317 }
2318
2319 switch (n) {
2320 case 0:
2321 link = gc->link;
2322 memcpy(gc, &grid_default_cell, sizeof *gc);
2323 gc->link = link;
2324 break;
2325 case 1:
2326 gc->attr |= GRID_ATTR_BRIGHT;
2327 break;
2328 case 2:
2329 gc->attr |= GRID_ATTR_DIM;
2330 break;
2331 case 3:
2332 gc->attr |= GRID_ATTR_ITALICS;
2333 break;
2334 case 4:
2335 gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2336 gc->attr |= GRID_ATTR_UNDERSCORE;
2337 break;
2338 case 5:
2339 case 6:
2340 gc->attr |= GRID_ATTR_BLINK;
2341 break;
2342 case 7:
2343 gc->attr |= GRID_ATTR_REVERSE;
2344 break;
2345 case 8:
2346 gc->attr |= GRID_ATTR_HIDDEN;
2347 break;
2348 case 9:
2349 gc->attr |= GRID_ATTR_STRIKETHROUGH;
2350 break;
2351 case 21:
2352 gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2353 gc->attr |= GRID_ATTR_UNDERSCORE_2;
2354 break;
2355 case 22:
2356 gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
2357 break;
2358 case 23:
2359 gc->attr &= ~GRID_ATTR_ITALICS;
2360 break;
2361 case 24:
2362 gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2363 break;
2364 case 25:
2365 gc->attr &= ~GRID_ATTR_BLINK;
2366 break;
2367 case 27:
2368 gc->attr &= ~GRID_ATTR_REVERSE;
2369 break;
2370 case 28:
2371 gc->attr &= ~GRID_ATTR_HIDDEN;
2372 break;
2373 case 29:
2374 gc->attr &= ~GRID_ATTR_STRIKETHROUGH;
2375 break;
2376 case 30:
2377 case 31:
2378 case 32:
2379 case 33:
2380 case 34:
2381 case 35:
2382 case 36:
2383 case 37:
2384 gc->fg = n - 30;
2385 break;
2386 case 39:
2387 gc->fg = 8;
2388 break;
2389 case 40:
2390 case 41:
2391 case 42:
2392 case 43:
2393 case 44:
2394 case 45:
2395 case 46:
2396 case 47:
2397 gc->bg = n - 40;
2398 break;
2399 case 49:
2400 gc->bg = 8;
2401 break;
2402 case 53:
2403 gc->attr |= GRID_ATTR_OVERLINE;
2404 break;
2405 case 55:
2406 gc->attr &= ~GRID_ATTR_OVERLINE;
2407 break;
2408 case 59:
2409 gc->us = 8;
2410 break;
2411 case 90:
2412 case 91:
2413 case 92:
2414 case 93:
2415 case 94:
2416 case 95:
2417 case 96:
2418 case 97:
2419 gc->fg = n;
2420 break;
2421 case 100:
2422 case 101:
2423 case 102:
2424 case 103:
2425 case 104:
2426 case 105:
2427 case 106:
2428 case 107:
2429 gc->bg = n - 10;
2430 break;
2431 }
2432 }
2433}
2434
2435/* End of input with BEL. */
2436static int
2437input_end_bel(struct input_ctx *ictx)
2438{
2439 log_debug("%s", __func__);
2440
2441 ictx->input_end = INPUT_END_BEL;
2442
2443 return (0);
2444}
2445
2446/* DCS string started. */
2447static void
2448input_enter_dcs(struct input_ctx *ictx)
2449{
2450 log_debug("%s", __func__);
2451
2452 input_clear(ictx);
2453 input_start_ground_timer(ictx);
2454 ictx->flags &= ~INPUT_LAST;
2455}
2456
2457/* Handle DECRQSS query. */
2458static int
2459input_handle_decrqss(struct input_ctx *ictx)
2460{
2461 struct window_pane *wp = ictx->wp;
2462 struct options *oo;
2463 struct screen_write_ctx *sctx = &ictx->ctx;
2464 u_char *buf = ictx->input_buf;
2465 size_t len = ictx->input_len;
2466 struct screen *s = sctx->s;
2467 int ps, opt_ps, blinking;
2468
2469 if (len < 3 || buf[1] != ' ' || buf[2] != 'q')
2470 goto not_recognized;
2471
2472 /*
2473 * Cursor style query: DCS $ q SP q
2474 * Reply: DCS 1 $ r SP q <Ps> SP q ST
2475 */
2476 if (s->cstyle == SCREEN_CURSOR_BLOCK ||
2477 s->cstyle == SCREEN_CURSOR_UNDERLINE ||
2478 s->cstyle == SCREEN_CURSOR_BAR) {
2479 blinking = (s->mode & MODE_CURSOR_BLINKING) != 0;
2480 switch (s->cstyle) {
2481 case SCREEN_CURSOR_BLOCK:
2482 ps = blinking ? 1 : 2;
2483 break;
2484 case SCREEN_CURSOR_UNDERLINE:
2485 ps = blinking ? 3 : 4;
2486 break;
2487 case SCREEN_CURSOR_BAR:
2488 ps = blinking ? 5 : 6;
2489 break;
2490 default:
2491 ps = 0;
2492 break;
2493 }
2494 } else {
2495 /*
2496 * No explicit runtime style: fall back to the configured
2497 * cursor-style option (integer Ps 0..6). Pane options inherit.
2498 */
2499 if (wp != NULL)
2500 oo = wp->options;
2501 else
2502 oo = global_options;
2503 opt_ps = options_get_number(oo, "cursor-style");
2504
2505 /* Sanity clamp: valid Ps are 0..6 per DECSCUSR. */
2506 if (opt_ps < 0 || opt_ps > 6)
2507 opt_ps = 0;
2508 ps = opt_ps;
2509 }
2510
2511 log_debug("%s: DECRQSS cursor -> Ps=%d (cstyle=%d mode=%#x)", __func__,
2512 ps, s->cstyle, s->mode);
2513
2514 input_reply(ictx, 1, "\033P1$r q%d q\033\\", ps);
2515 return (0);
2516
2517not_recognized:
2518 /* Unrecognized DECRQSS: send DCS 0 $ r Pt ST. */
2519 input_reply(ictx, 1, "\033P0$r\033\\");
2520 return (0);
2521}
2522
2523/* DCS terminator (ST) received. */
2524static int
2525input_dcs_dispatch(struct input_ctx *ictx)
2526{
2527 struct window_pane *wp = ictx->wp;
2528 struct options *oo;
2529 struct screen_write_ctx *sctx = &ictx->ctx;
2530 u_char *buf = ictx->input_buf;
2531 size_t len = ictx->input_len;
2532 const char prefix[] = "tmux;";
2533 const u_int prefixlen = (sizeof prefix) - 1;
2534 long long allow_passthrough = 0;
2535
2536 if (wp == NULL)
2537 return (0);
2538 oo = wp->options;
2539
2540 if (ictx->flags & INPUT_DISCARD) {
2541 log_debug("%s: %zu bytes (discard)", __func__, len);
2542 return (0);
2543 }
2544 log_debug("%s: %zu bytes", __func__, len);
2545
2546 /* DCS sequences with intermediate byte '$' (includes DECRQSS). */
2547 if (ictx->interm_len == 1 && ictx->interm_buf[0] == '$') {
2548 /* DECRQSS is DCS $ q Pt ST. */
2549 if (len >= 1 && buf[0] == 'q')
2550 return (input_handle_decrqss(ictx));
2551
2552 /*
2553 * Not DECRQSS. DCS '$' is currently only used by DECRQSS, but
2554 * leave other '$' DCS (if any appear in future) to existing
2555 * handlers.
2556 */
2557 }
2558
2559 allow_passthrough = options_get_number(oo, "allow-passthrough");
2560 if (!allow_passthrough)
2561 return (0);
2562 log_debug("%s: \"%s\"", __func__, buf);
2563
2564 if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0) {
2565 screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen,
2566 allow_passthrough == 2);
2567 }
2568
2569 return (0);
2570}
2571
2572/* OSC string started. */
2573static void
2574input_enter_osc(struct input_ctx *ictx)
2575{
2576 log_debug("%s", __func__);
2577
2578 input_clear(ictx);
2579 input_start_ground_timer(ictx);
2580 ictx->flags &= ~INPUT_LAST;
2581}
2582
2583/* OSC terminator (ST) received. */
2584static void
2585input_exit_osc(struct input_ctx *ictx)
2586{
2587 struct screen_write_ctx *sctx = &ictx->ctx;
2588 struct window_pane *wp = ictx->wp;
2589 u_char *p = ictx->input_buf;
2590 u_int option;
2591
2592 if (ictx->flags & INPUT_DISCARD)
2593 return;
2594 if (ictx->input_len < 1 || *p < '0' || *p > '9')
2595 return;
2596
2597 log_debug("%s: \"%s\" (end %s)", __func__, p,
2598 ictx->input_end == INPUT_END_ST ? "ST" : "BEL");
2599
2600 option = 0;
2601 while (*p >= '0' && *p <= '9')
2602 option = option * 10 + *p++ - '0';
2603 if (*p != ';' && *p != '\0')
2604 return;
2605 if (*p == ';')
2606 p++;
2607
2608 switch (option) {
2609 case 0:
2610 case 2:
2611 if (wp != NULL &&
2612 options_get_number(wp->options, "allow-set-title") &&
2613 screen_set_title(sctx->s, p)) {
2614 notify_pane("pane-title-changed", wp);
2615 server_redraw_window_borders(wp->window);
2616 server_status_window(wp->window);
2617 }
2618 break;
2619 case 4:
2620 input_osc_4(ictx, p);
2621 break;
2622 case 7:
2623 if (utf8_isvalid(p)) {
2624 screen_set_path(sctx->s, p);
2625 if (wp != NULL) {
2626 server_redraw_window_borders(wp->window);
2627 server_status_window(wp->window);
2628 }
2629 }
2630 break;
2631 case 8:
2632 input_osc_8(ictx, p);
2633 break;
2634 case 10:
2635 input_osc_10(ictx, p);
2636 break;
2637 case 11:
2638 input_osc_11(ictx, p);
2639 break;
2640 case 12:
2641 input_osc_12(ictx, p);
2642 break;
2643 case 52:
2644 input_osc_52(ictx, p);
2645 break;
2646 case 104:
2647 input_osc_104(ictx, p);
2648 break;
2649 case 110:
2650 input_osc_110(ictx, p);
2651 break;
2652 case 111:
2653 input_osc_111(ictx, p);
2654 break;
2655 case 112:
2656 input_osc_112(ictx, p);
2657 break;
2658 case 133:
2659 input_osc_133(ictx, p);
2660 break;
2661 default:
2662 log_debug("%s: unknown '%u'", __func__, option);
2663 break;
2664 }
2665}
2666
2667/* APC string started. */
2668static void
2669input_enter_apc(struct input_ctx *ictx)
2670{
2671 log_debug("%s", __func__);
2672
2673 input_clear(ictx);
2674 input_start_ground_timer(ictx);
2675 ictx->flags &= ~INPUT_LAST;
2676}
2677
2678/* APC terminator (ST) received. */
2679static void
2680input_exit_apc(struct input_ctx *ictx)
2681{
2682 struct screen_write_ctx *sctx = &ictx->ctx;
2683 struct window_pane *wp = ictx->wp;
2684
2685 if (ictx->flags & INPUT_DISCARD)
2686 return;
2687 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2688
2689 if (wp != NULL &&
2690 options_get_number(wp->options, "allow-set-title") &&
2691 screen_set_title(sctx->s, ictx->input_buf)) {
2692 notify_pane("pane-title-changed", wp);
2693 server_redraw_window_borders(wp->window);
2694 server_status_window(wp->window);
2695 }
2696}
2697
2698/* Rename string started. */
2699static void
2700input_enter_rename(struct input_ctx *ictx)
2701{
2702 log_debug("%s", __func__);
2703
2704 input_clear(ictx);
2705 input_start_ground_timer(ictx);
2706 ictx->flags &= ~INPUT_LAST;
2707}
2708
2709/* Rename terminator (ST) received. */
2710static void
2711input_exit_rename(struct input_ctx *ictx)
2712{
2713 struct window_pane *wp = ictx->wp;
2714 struct window *w;
2715 struct options_entry *o;
2716
2717 if (wp == NULL)
2718 return;
2719 if (ictx->flags & INPUT_DISCARD)
2720 return;
2721 if (!options_get_number(ictx->wp->options, "allow-rename"))
2722 return;
2723 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2724
2725 if (!utf8_isvalid(ictx->input_buf))
2726 return;
2727 w = wp->window;
2728
2729 if (ictx->input_len == 0) {
2730 o = options_get_only(w->options, "automatic-rename");
2731 if (o != NULL)
2732 options_remove_or_default(o, -1, NULL);
2733 if (!options_get_number(w->options, "automatic-rename"))
2734 window_set_name(w, "");
2735 } else {
2736 options_set_number(w->options, "automatic-rename", 0);
2737 window_set_name(w, ictx->input_buf);
2738 }
2739 server_redraw_window_borders(w);
2740 server_status_window(w);
2741}
2742
2743/* Open UTF-8 character. */
2744static int
2745input_top_bit_set(struct input_ctx *ictx)
2746{
2747 struct screen_write_ctx *sctx = &ictx->ctx;
2748 struct utf8_data *ud = &ictx->utf8data;
2749
2750 ictx->flags &= ~INPUT_LAST;
2751
2752 if (!ictx->utf8started) {
2753 ictx->utf8started = 1;
2754 if (utf8_open(ud, ictx->ch) != UTF8_MORE)
2755 input_stop_utf8(ictx);
2756 return (0);
2757 }
2758
2759 switch (utf8_append(ud, ictx->ch)) {
2760 case UTF8_MORE:
2761 return (0);
2762 case UTF8_ERROR:
2763 input_stop_utf8(ictx);
2764 return (0);
2765 case UTF8_DONE:
2766 break;
2767 }
2768 ictx->utf8started = 0;
2769
2770 log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size,
2771 (int)ud->size, ud->data, ud->width);
2772
2773 utf8_copy(&ictx->cell.cell.data, ud);
2774 screen_write_collect_add(sctx, &ictx->cell.cell);
2775
2776 utf8_copy(&ictx->last, &ictx->cell.cell.data);
2777 ictx->flags |= INPUT_LAST;
2778
2779 return (0);
2780}
2781
2782/* Reply to a colour request. */
2783static void
2784input_osc_colour_reply(struct input_ctx *ictx, int add, u_int n, int idx, int c,
2785 enum input_end_type end_type)
2786{
2787 u_char r, g, b;
2788 const char *end;
2789
2790 if (c != -1)
2791 c = colour_force_rgb(c);
2792 if (c == -1)
2793 return;
2794 colour_split_rgb(c, &r, &g, &b);
2795
2796 if (end_type == INPUT_END_BEL)
2797 end = "\007";
2798 else
2799 end = "\033\\";
2800
2801 if (n == 4) {
2802 input_reply(ictx, add,
2803 "\033]%u;%d;rgb:%02hhx%02hhx/%02hhx%02hhx/%02hhx%02hhx%s",
2804 n, idx, r, r, g, g, b, b, end);
2805 } else {
2806 input_reply(ictx, add,
2807 "\033]%u;rgb:%02hhx%02hhx/%02hhx%02hhx/%02hhx%02hhx%s",
2808 n, r, r, g, g, b, b, end);
2809 }
2810}
2811
2812/* Handle the OSC 4 sequence for setting (multiple) palette entries. */
2813static void
2814input_osc_4(struct input_ctx *ictx, const char *p)
2815{
2816 char *copy, *s, *next = NULL;
2817 long idx;
2818 int c, bad = 0, redraw = 0;
2819 struct colour_palette *palette = ictx->palette;
2820
2821 copy = s = xstrdup(p);
2822 while (s != NULL && *s != '\0') {
2823 idx = strtol(s, &next, 10);
2824 if (*next++ != ';') {
2825 bad = 1;
2826 break;
2827 }
2828 if (idx < 0 || idx >= 256) {
2829 bad = 1;
2830 break;
2831 }
2832
2833 s = strsep(&next, ";");
2834 if (strcmp(s, "?") == 0) {
2835 c = colour_palette_get(palette, idx|COLOUR_FLAG_256);
2836 if (c != -1) {
2837 input_osc_colour_reply(ictx, 1, 4, idx, c,
2838 ictx->input_end);
2839 s = next;
2840 continue;
2841 }
2842 input_add_request(ictx, INPUT_REQUEST_PALETTE, idx);
2843 s = next;
2844 continue;
2845 }
2846 if ((c = colour_parseX11(s)) == -1) {
2847 s = next;
2848 continue;
2849 }
2850 if (colour_palette_set(palette, idx, c))
2851 redraw = 1;
2852 s = next;
2853 }
2854 if (bad)
2855 log_debug("bad OSC 4: %s", p);
2856 if (redraw)
2857 screen_write_fullredraw(&ictx->ctx);
2858 free(copy);
2859}
2860
2861/* Handle the OSC 8 sequence for embedding hyperlinks. */
2862static void
2863input_osc_8(struct input_ctx *ictx, const char *p)
2864{
2865 struct hyperlinks *hl = ictx->ctx.s->hyperlinks;
2866 struct grid_cell *gc = &ictx->cell.cell;
2867 const char *start, *end, *uri;
2868 char *id = NULL;
2869
2870 for (start = p; (end = strpbrk(start, ":;")) != NULL; start = end + 1) {
2871 if (end - start >= 4 && strncmp(start, "id=", 3) == 0) {
2872 if (id != NULL)
2873 goto bad;
2874 id = xstrndup(start + 3, end - start - 3);
2875 }
2876
2877 /* The first ; is the end of parameters and start of the URI. */
2878 if (*end == ';')
2879 break;
2880 }
2881 if (end == NULL || *end != ';')
2882 goto bad;
2883 uri = end + 1;
2884 if (*uri == '\0') {
2885 gc->link = 0;
2886 free(id);
2887 return;
2888 }
2889 gc->link = hyperlinks_put(hl, uri, id);
2890 if (id == NULL)
2891 log_debug("hyperlink (anonymous) %s = %u", uri, gc->link);
2892 else
2893 log_debug("hyperlink (id=%s) %s = %u", id, uri, gc->link);
2894 free(id);
2895 return;
2896
2897bad:
2898 log_debug("bad OSC 8 %s", p);
2899 free(id);
2900}
2901
2902
2903/* Handle the OSC 10 sequence for setting and querying foreground colour. */
2904static void
2905input_osc_10(struct input_ctx *ictx, const char *p)
2906{
2907 struct window_pane *wp = ictx->wp;
2908 struct grid_cell defaults;
2909 int c;
2910
2911 if (strcmp(p, "?") == 0) {
2912 if (wp == NULL)
2913 return;
2914 c = window_pane_get_fg_control_client(wp);
2915 if (c == -1) {
2916 tty_default_colours(&defaults, wp);
2917 if (COLOUR_DEFAULT(defaults.fg))
2918 c = window_pane_get_fg(wp);
2919 else
2920 c = defaults.fg;
2921 }
2922 input_osc_colour_reply(ictx, 1, 10, 0, c, ictx->input_end);
2923 return;
2924 }
2925
2926 if ((c = colour_parseX11(p)) == -1) {
2927 log_debug("bad OSC 10: %s", p);
2928 return;
2929 }
2930 if (ictx->palette != NULL) {
2931 ictx->palette->fg = c;
2932 if (wp != NULL)
2933 wp->flags |= PANE_STYLECHANGED;
2934 screen_write_fullredraw(&ictx->ctx);
2935 }
2936}
2937
2938/* Handle the OSC 110 sequence for resetting foreground colour. */
2939static void
2940input_osc_110(struct input_ctx *ictx, const char *p)
2941{
2942 struct window_pane *wp = ictx->wp;
2943
2944 if (*p != '\0')
2945 return;
2946 if (ictx->palette != NULL) {
2947 ictx->palette->fg = 8;
2948 if (wp != NULL)
2949 wp->flags |= PANE_STYLECHANGED;
2950 screen_write_fullredraw(&ictx->ctx);
2951 }
2952}
2953
2954/* Handle the OSC 11 sequence for setting and querying background colour. */
2955static void
2956input_osc_11(struct input_ctx *ictx, const char *p)
2957{
2958 struct window_pane *wp = ictx->wp;
2959 int c;
2960
2961 if (strcmp(p, "?") == 0) {
2962 if (wp == NULL)
2963 return;
2964 c = window_pane_get_bg(wp);
2965 input_osc_colour_reply(ictx, 1, 11, 0, c, ictx->input_end);
2966 return;
2967 }
2968
2969 if ((c = colour_parseX11(p)) == -1) {
2970 log_debug("bad OSC 11: %s", p);
2971 return;
2972 }
2973 if (ictx->palette != NULL) {
2974 ictx->palette->bg = c;
2975 if (wp != NULL)
2976 wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
2977 screen_write_fullredraw(&ictx->ctx);
2978 }
2979}
2980
2981/* Handle the OSC 111 sequence for resetting background colour. */
2982static void
2983input_osc_111(struct input_ctx *ictx, const char *p)
2984{
2985 struct window_pane *wp = ictx->wp;
2986
2987 if (*p != '\0')
2988 return;
2989 if (ictx->palette != NULL) {
2990 ictx->palette->bg = 8;
2991 if (wp != NULL)
2992 wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
2993 screen_write_fullredraw(&ictx->ctx);
2994 }
2995}
2996
2997/* Handle the OSC 12 sequence for setting and querying cursor colour. */
2998static void
2999input_osc_12(struct input_ctx *ictx, const char *p)
3000{
3001 struct window_pane *wp = ictx->wp;
3002 int c;
3003
3004 if (strcmp(p, "?") == 0) {
3005 if (wp != NULL) {
3006 c = ictx->ctx.s->ccolour;
3007 if (c == -1)
3008 c = ictx->ctx.s->default_ccolour;
3009 input_osc_colour_reply(ictx, 1, 12, 0, c, ictx->input_end);
3010 }
3011 return;
3012 }
3013
3014 if ((c = colour_parseX11(p)) == -1) {
3015 log_debug("bad OSC 12: %s", p);
3016 return;
3017 }
3018 screen_set_cursor_colour(ictx->ctx.s, c);
3019}
3020
3021/* Handle the OSC 112 sequence for resetting cursor colour. */
3022static void
3023input_osc_112(struct input_ctx *ictx, const char *p)
3024{
3025 if (*p == '\0') /* no arguments allowed */
3026 screen_set_cursor_colour(ictx->ctx.s, -1);
3027}
3028
3029/* Handle the OSC 133 sequence. */
3030static void
3031input_osc_133(struct input_ctx *ictx, const char *p)
3032{
3033 struct grid *gd = ictx->ctx.s->grid;
3034 u_int line = ictx->ctx.s->cy + gd->hsize;
3035 struct grid_line *gl;
3036
3037 if (line > gd->hsize + gd->sy - 1)
3038 return;
3039 gl = grid_get_line(gd, line);
3040
3041 switch (*p) {
3042 case 'A':
3043 gl->flags |= GRID_LINE_START_PROMPT;
3044 break;
3045 case 'C':
3046 gl->flags |= GRID_LINE_START_OUTPUT;
3047 break;
3048 }
3049}
3050
3051/* Handle OSC 52 reply. */
3052static void
3053input_osc_52_reply(struct input_ctx *ictx, char clip)
3054{
3055 struct bufferevent *ev = ictx->event;
3056 struct paste_buffer *pb;
3057 int state;
3058 const char *buf;
3059 size_t len;
3060
3061 state = options_get_number(global_options, "get-clipboard");
3062 if (state == 0)
3063 return;
3064 if (state == 1) {
3065 if ((pb = paste_get_top(NULL)) == NULL)
3066 return;
3067 buf = paste_buffer_data(pb, &len);
3068 if (ictx->input_end == INPUT_END_BEL)
3069 input_reply_clipboard(ev, buf, len, "\007", clip);
3070 else
3071 input_reply_clipboard(ev, buf, len, "\033\\", clip);
3072 return;
3073 }
3074 input_add_request(ictx, INPUT_REQUEST_CLIPBOARD, ictx->input_end);
3075}
3076
3077/*
3078 * Parse and decode OSC 52 clipboard data. Returns 0 on failure or if handled
3079 * as a query. On success, returns 1 and sets *out, *outlen, and *flags (caller
3080 * must free *out).
3081 */
3082static int
3083input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out,
3084 int *outlen, char *clip)
3085{
3086 char *end;
3087 size_t len;
3088 const char *allow = "cpqs01234567";
3089 u_int i, j = 0;
3090
3091 if (options_get_number(global_options, "set-clipboard") != 2)
3092 return (0);
3093
3094 if ((end = strchr(p, ';')) == NULL)
3095 return (0);
3096 end++;
3097 if (*end == '\0')
3098 return (0);
3099 log_debug("%s: %s", __func__, end);
3100
3101 for (i = 0; p + i != end; i++) {
3102 if (strchr(allow, p[i]) != NULL && strchr(clip, p[i]) == NULL)
3103 clip[j++] = p[i];
3104 }
3105 log_debug("%s: %.*s %s", __func__, (int)(end - p - 1), p, clip);
3106
3107 if (strcmp(end, "?") == 0) {
3108 input_osc_52_reply(ictx, *clip);
3109 return (0);
3110 }
3111
3112 len = (strlen(end) / 4) * 3;
3113 if (len == 0)
3114 return (0);
3115
3116 *out = xmalloc(len);
3117 if ((*outlen = b64_pton(end, *out, len)) == -1) {
3118 free(*out);
3119 *out = NULL;
3120 return (0);
3121 }
3122
3123 return (1);
3124}
3125
3126/* Handle the OSC 52 sequence for setting the clipboard. */
3127static void
3128input_osc_52(struct input_ctx *ictx, const char *p)
3129{
3130 struct window_pane *wp = ictx->wp;
3131 struct screen_write_ctx ctx;
3132 u_char *out;
3133 int outlen;
3134 char clip[sizeof "cpqs01234567"] = "";
3135
3136 if (!input_osc_52_parse(ictx, p, &out, &outlen, clip))
3137 return;
3138
3139 if (wp == NULL) {
3140 /* Popup window. */
3141 if (ictx->c == NULL) {
3142 free(out);
3143 return;
3144 }
3145 tty_set_selection(&ictx->c->tty, clip, out, outlen);
3146 paste_add(NULL, out, outlen);
3147 } else {
3148 /* Normal window. */
3149 screen_write_start_pane(&ctx, wp, NULL);
3150 screen_write_setselection(&ctx, clip, out, outlen);
3151 screen_write_stop(&ctx);
3152 notify_pane("pane-set-clipboard", wp);
3153 paste_add(NULL, out, outlen);
3154 }
3155 free(out);
3156}
3157
3158/* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
3159static void
3160input_osc_104(struct input_ctx *ictx, const char *p)
3161{
3162 char *copy, *s;
3163 long idx;
3164 int bad = 0, redraw = 0;
3165
3166 if (*p == '\0') {
3167 colour_palette_clear(ictx->palette);
3168 screen_write_fullredraw(&ictx->ctx);
3169 return;
3170 }
3171
3172 copy = s = xstrdup(p);
3173 while (*s != '\0') {
3174 idx = strtol(s, &s, 10);
3175 if (*s != '\0' && *s != ';') {
3176 bad = 1;
3177 break;
3178 }
3179 if (idx < 0 || idx >= 256) {
3180 bad = 1;
3181 break;
3182 }
3183 if (colour_palette_set(ictx->palette, idx, -1))
3184 redraw = 1;
3185 if (*s == ';')
3186 s++;
3187 }
3188 if (bad)
3189 log_debug("bad OSC 104: %s", p);
3190 if (redraw)
3191 screen_write_fullredraw(&ictx->ctx);
3192 free(copy);
3193}
3194
3195/* Send a clipboard reply. */
3196void
3197input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len,
3198 const char *end, char clip)
3199{
3200 char *out = NULL;
3201 int outlen = 0;
3202
3203 if (buf != NULL && len != 0) {
3204 if (len >= ((size_t)INT_MAX * 3 / 4) - 1)
3205 return;
3206 outlen = 4 * ((len + 2) / 3) + 1;
3207 out = xmalloc(outlen);
3208 if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) {
3209 free(out);
3210 return;
3211 }
3212 }
3213
3214 bufferevent_write(bev, "\033]52;", 5);
3215 if (clip != 0)
3216 bufferevent_write(bev, &clip, 1);
3217 bufferevent_write(bev, ";", 1);
3218 if (outlen != 0)
3219 bufferevent_write(bev, out, outlen);
3220 bufferevent_write(bev, end, strlen(end));
3221 free(out);
3222}
3223
3224/* Set input buffer size. */
3225void
3226input_set_buffer_size(size_t buffer_size)
3227{
3228 log_debug("%s: %lu -> %lu", __func__, input_buffer_size, buffer_size);
3229 input_buffer_size = buffer_size;
3230}
3231
3232/* Request timer. Remove any requests that are too old. */
3233static void
3234input_request_timer_callback(__unused int fd, __unused short events, void *arg)
3235{
3236 struct input_ctx *ictx = arg;
3237 struct input_request *ir, *ir1;
3238 uint64_t t = get_timer();
3239
3240 TAILQ_FOREACH_SAFE(ir, &ictx->requests, entry, ir1) {
3241 if (ir->t >= t - INPUT_REQUEST_TIMEOUT)
3242 continue;
3243 if (ir->type == INPUT_REQUEST_QUEUE)
3244 input_send_reply(ir->ictx, ir->data);
3245 input_free_request(ir);
3246 }
3247 if (ictx->request_count != 0)
3248 input_start_request_timer(ictx);
3249}
3250
3251/* Start the request timer. */
3252static void
3253input_start_request_timer(struct input_ctx *ictx)
3254{
3255 struct timeval tv = { .tv_sec = 0, .tv_usec = 100000 };
3256
3257 event_del(&ictx->request_timer);
3258 event_add(&ictx->request_timer, &tv);
3259}
3260
3261/* Create a request. */
3262static struct input_request *
3263input_make_request(struct input_ctx *ictx, enum input_request_type type)
3264{
3265 struct input_request *ir;
3266
3267 ir = xcalloc (1, sizeof *ir);
3268 ir->type = type;
3269 ir->ictx = ictx;
3270 ir->t = get_timer();
3271
3272 if (++ictx->request_count == 1)
3273 input_start_request_timer(ictx);
3274 TAILQ_INSERT_TAIL(&ictx->requests, ir, entry);
3275
3276 return (ir);
3277}
3278
3279/* Free a request. */
3280static void
3281input_free_request(struct input_request *ir)
3282{
3283 struct input_ctx *ictx = ir->ictx;
3284
3285 if (ir->c != NULL)
3286 TAILQ_REMOVE(&ir->c->input_requests, ir, centry);
3287
3288 ictx->request_count--;
3289 TAILQ_REMOVE(&ictx->requests, ir, entry);
3290
3291 free(ir->data);
3292 free(ir);
3293}
3294
3295/* Add a request. */
3296static int
3297input_add_request(struct input_ctx *ictx, enum input_request_type type, int idx)
3298{
3299 struct window_pane *wp = ictx->wp;
3300 struct window *w;
3301 struct client *c = NULL, *loop;
3302 struct input_request *ir;
3303 char s[64];
3304
3305 if (wp == NULL)
3306 return (-1);
3307 w = wp->window;
3308
3309 TAILQ_FOREACH(loop, &clients, entry) {
3310 if (loop->flags & CLIENT_UNATTACHEDFLAGS)
3311 continue;
3312 if (loop->session == NULL || !session_has(loop->session, w))
3313 continue;
3314 if (~loop->tty.flags & TTY_STARTED)
3315 continue;
3316 if (c == NULL)
3317 c = loop;
3318 else if (timercmp(&loop->activity_time, &c->activity_time, >))
3319 c = loop;
3320 }
3321 if (c == NULL)
3322 return (-1);
3323
3324 ir = input_make_request(ictx, type);
3325 ir->c = c;
3326 ir->idx = idx;
3327 ir->end = ictx->input_end;
3328 TAILQ_INSERT_TAIL(&c->input_requests, ir, centry);
3329
3330 switch (type) {
3331 case INPUT_REQUEST_PALETTE:
3332 xsnprintf(s, sizeof s, "\033]4;%d;?\033\\", idx);
3333 tty_puts(&c->tty, s);
3334 break;
3335 case INPUT_REQUEST_CLIPBOARD:
3336 tty_putcode_ss(&c->tty, TTYC_MS, "", "?");
3337 break;
3338 case INPUT_REQUEST_QUEUE:
3339 break;
3340 }
3341
3342 return (0);
3343}
3344
3345/* Handle a palette reply. */
3346static void
3347input_request_palette_reply(struct input_request *ir, void *data)
3348{
3349 struct input_request_palette_data *pd = data;
3350
3351 input_osc_colour_reply(ir->ictx, 0, 4, pd->idx, pd->c, ir->end);
3352}
3353
3354/* Handle a clipboard reply. */
3355static void
3356input_request_clipboard_reply(struct input_request *ir, void *data)
3357{
3358 struct input_ctx *ictx = ir->ictx;
3359 struct bufferevent *ev = ictx->event;
3360 struct input_request_clipboard_data *cd = data;
3361 int state;
3362 char *copy;
3363
3364 state = options_get_number(global_options, "get-clipboard");
3365 if (state == 0 || state == 1)
3366 return;
3367 if (state == 3) {
3368 copy = xmalloc(cd->len);
3369 memcpy(copy, cd->buf, cd->len);
3370 paste_add(NULL, copy, cd->len);
3371 }
3372
3373 if (ir->idx == INPUT_END_BEL)
3374 input_reply_clipboard(ev, cd->buf, cd->len, "\007", cd->clip);
3375 else
3376 input_reply_clipboard(ev, cd->buf, cd->len, "\033\\", cd->clip);
3377}
3378
3379/* Handle a reply to a request. */
3380void
3381input_request_reply(struct client *c, enum input_request_type type, void *data)
3382{
3383 struct input_request *ir, *ir1, *found = NULL;
3384 struct input_request_palette_data *pd = data;
3385 int complete = 0;
3386
3387 TAILQ_FOREACH_SAFE(ir, &c->input_requests, centry, ir1) {
3388 if (ir->type != type) {
3389 input_free_request(ir);
3390 continue;
3391 }
3392 if (type == INPUT_REQUEST_PALETTE) {
3393 if (pd->idx != ir->idx) {
3394 input_free_request(ir);
3395 continue;
3396 }
3397 found = ir;
3398 break;
3399 }
3400 if (type == INPUT_REQUEST_CLIPBOARD) {
3401 found = ir;
3402 break;
3403 }
3404 }
3405 if (found == NULL)
3406 return;
3407
3408 TAILQ_FOREACH_SAFE(ir, &found->ictx->requests, entry, ir1) {
3409 if (complete && ir->type != INPUT_REQUEST_QUEUE)
3410 break;
3411 if (ir->type == INPUT_REQUEST_QUEUE)
3412 input_send_reply(ir->ictx, ir->data);
3413 else if (ir == found) {
3414 if (ir->type == INPUT_REQUEST_PALETTE)
3415 input_request_palette_reply(ir, data);
3416 else if (ir->type == INPUT_REQUEST_CLIPBOARD)
3417 input_request_clipboard_reply(ir, data);
3418 complete = 1;
3419 }
3420 input_free_request(ir);
3421 }
3422}
3423
3424/* Cancel pending requests for client. */
3425void
3426input_cancel_requests(struct client *c)
3427{
3428 struct input_request *ir, *ir1;
3429
3430 TAILQ_FOREACH_SAFE(ir, &c->input_requests, centry, ir1)
3431 input_free_request(ir);
3432}
3433
3434/* Report current theme. */
3435static void
3436input_report_current_theme(struct input_ctx *ictx)
3437{
3438 struct window_pane *wp = ictx->wp;
3439
3440 if (wp != NULL) {
3441 wp->last_theme = window_pane_get_theme(wp);
3442 wp->flags &= ~PANE_THEMECHANGED;
3443
3444 switch (wp->last_theme) {
3445 case THEME_DARK:
3446 log_debug("%s: %%%u dark theme", __func__, wp->id);
3447 input_reply(ictx, 0, "\033[?997;1n");
3448 break;
3449 case THEME_LIGHT:
3450 log_debug("%s: %%%u light theme", __func__, wp->id);
3451 input_reply(ictx, 0, "\033[?997;2n");
3452 break;
3453 case THEME_UNKNOWN:
3454 log_debug("%s: %%%u unknown theme", __func__, wp->id);
3455 break;
3456 }
3457 }
3458}