jcs's openbsd hax
openbsd
at jcs 3458 lines 83 kB view raw
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}