Coverage Report

Created: 2026-08-31 06:23

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