Coverage Report

Created: 2026-10-28 06:08

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