Coverage Report

Created: 2026-04-12 06:58

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