1 | /* $OpenBSD$ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2007 Nicholas Marriott <[email protected]> |
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 | #include <sys/time.h> |
21 | |
22 | #include <netinet/in.h> |
23 | |
24 | #include <limits.h> |
25 | #include <resolv.h> |
26 | #include <stdlib.h> |
27 | #include <string.h> |
28 | #include <termios.h> |
29 | #include <unistd.h> |
30 | |
31 | #include "tmux.h" |
32 | |
33 | /* |
34 | * Handle keys input from the outside terminal. tty_default_*_keys[] are a base |
35 | * table of supported keys which are looked up in terminfo(5) and translated |
36 | * into a ternary tree. |
37 | */ |
38 | |
39 | static void tty_keys_add1(struct tty_key **, const char *, key_code); |
40 | static void tty_keys_add(struct tty *, const char *, key_code); |
41 | static void tty_keys_free1(struct tty_key *); |
42 | static struct tty_key *tty_keys_find1(struct tty_key *, const char *, size_t, |
43 | size_t *); |
44 | static struct tty_key *tty_keys_find(struct tty *, const char *, size_t, |
45 | size_t *); |
46 | static int tty_keys_next1(struct tty *, const char *, size_t, key_code *, |
47 | size_t *, int); |
48 | static void tty_keys_callback(int, short, void *); |
49 | static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *, |
50 | struct mouse_event *); |
51 | static int tty_keys_clipboard(struct tty *, const char *, size_t, |
52 | size_t *); |
53 | static int tty_keys_device_attributes(struct tty *, const char *, size_t, |
54 | size_t *); |
55 | static int tty_keys_device_status_report(struct tty *, const char *, |
56 | size_t, size_t *); |
57 | |
58 | /* Default raw keys. */ |
59 | struct tty_default_key_raw { |
60 | const char *string; |
61 | key_code key; |
62 | }; |
63 | static const struct tty_default_key_raw tty_default_raw_keys[] = { |
64 | /* |
65 | * Numeric keypad. Just use the vt100 escape sequences here and always |
66 | * put the terminal into keypad_xmit mode. Translation of numbers |
67 | * mode/applications mode is done in input-keys.c. |
68 | */ |
69 | { "\033Oo" , KEYC_KP_SLASH }, |
70 | { "\033Oj" , KEYC_KP_STAR }, |
71 | { "\033Om" , KEYC_KP_MINUS }, |
72 | { "\033Ow" , KEYC_KP_SEVEN }, |
73 | { "\033Ox" , KEYC_KP_EIGHT }, |
74 | { "\033Oy" , KEYC_KP_NINE }, |
75 | { "\033Ok" , KEYC_KP_PLUS }, |
76 | { "\033Ot" , KEYC_KP_FOUR }, |
77 | { "\033Ou" , KEYC_KP_FIVE }, |
78 | { "\033Ov" , KEYC_KP_SIX }, |
79 | { "\033Oq" , KEYC_KP_ONE }, |
80 | { "\033Or" , KEYC_KP_TWO }, |
81 | { "\033Os" , KEYC_KP_THREE }, |
82 | { "\033OM" , KEYC_KP_ENTER }, |
83 | { "\033Op" , KEYC_KP_ZERO }, |
84 | { "\033On" , KEYC_KP_PERIOD }, |
85 | |
86 | /* Arrow keys. */ |
87 | { "\033OA" , KEYC_UP }, |
88 | { "\033OB" , KEYC_DOWN }, |
89 | { "\033OC" , KEYC_RIGHT }, |
90 | { "\033OD" , KEYC_LEFT }, |
91 | |
92 | { "\033[A" , KEYC_UP }, |
93 | { "\033[B" , KEYC_DOWN }, |
94 | { "\033[C" , KEYC_RIGHT }, |
95 | { "\033[D" , KEYC_LEFT }, |
96 | |
97 | /* Other (xterm) "cursor" keys. */ |
98 | { "\033OH" , KEYC_HOME }, |
99 | { "\033OF" , KEYC_END }, |
100 | |
101 | { "\033[H" , KEYC_HOME }, |
102 | { "\033[F" , KEYC_END }, |
103 | |
104 | /* rxvt-style arrow + modifier keys. */ |
105 | { "\033Oa" , KEYC_UP|KEYC_CTRL }, |
106 | { "\033Ob" , KEYC_DOWN|KEYC_CTRL }, |
107 | { "\033Oc" , KEYC_RIGHT|KEYC_CTRL }, |
108 | { "\033Od" , KEYC_LEFT|KEYC_CTRL }, |
109 | |
110 | { "\033[a" , KEYC_UP|KEYC_SHIFT }, |
111 | { "\033[b" , KEYC_DOWN|KEYC_SHIFT }, |
112 | { "\033[c" , KEYC_RIGHT|KEYC_SHIFT }, |
113 | { "\033[d" , KEYC_LEFT|KEYC_SHIFT }, |
114 | |
115 | /* rxvt-style function + modifier keys (C = ^, S = $, C-S = @). */ |
116 | { "\033[11^" , KEYC_F1|KEYC_CTRL }, |
117 | { "\033[12^" , KEYC_F2|KEYC_CTRL }, |
118 | { "\033[13^" , KEYC_F3|KEYC_CTRL }, |
119 | { "\033[14^" , KEYC_F4|KEYC_CTRL }, |
120 | { "\033[15^" , KEYC_F5|KEYC_CTRL }, |
121 | { "\033[17^" , KEYC_F6|KEYC_CTRL }, |
122 | { "\033[18^" , KEYC_F7|KEYC_CTRL }, |
123 | { "\033[19^" , KEYC_F8|KEYC_CTRL }, |
124 | { "\033[20^" , KEYC_F9|KEYC_CTRL }, |
125 | { "\033[21^" , KEYC_F10|KEYC_CTRL }, |
126 | { "\033[23^" , KEYC_F11|KEYC_CTRL }, |
127 | { "\033[24^" , KEYC_F12|KEYC_CTRL }, |
128 | { "\033[2^" , KEYC_IC|KEYC_CTRL }, |
129 | { "\033[3^" , KEYC_DC|KEYC_CTRL }, |
130 | { "\033[7^" , KEYC_HOME|KEYC_CTRL }, |
131 | { "\033[8^" , KEYC_END|KEYC_CTRL }, |
132 | { "\033[6^" , KEYC_NPAGE|KEYC_CTRL }, |
133 | { "\033[5^" , KEYC_PPAGE|KEYC_CTRL }, |
134 | |
135 | { "\033[11$" , KEYC_F1|KEYC_SHIFT }, |
136 | { "\033[12$" , KEYC_F2|KEYC_SHIFT }, |
137 | { "\033[13$" , KEYC_F3|KEYC_SHIFT }, |
138 | { "\033[14$" , KEYC_F4|KEYC_SHIFT }, |
139 | { "\033[15$" , KEYC_F5|KEYC_SHIFT }, |
140 | { "\033[17$" , KEYC_F6|KEYC_SHIFT }, |
141 | { "\033[18$" , KEYC_F7|KEYC_SHIFT }, |
142 | { "\033[19$" , KEYC_F8|KEYC_SHIFT }, |
143 | { "\033[20$" , KEYC_F9|KEYC_SHIFT }, |
144 | { "\033[21$" , KEYC_F10|KEYC_SHIFT }, |
145 | { "\033[23$" , KEYC_F11|KEYC_SHIFT }, |
146 | { "\033[24$" , KEYC_F12|KEYC_SHIFT }, |
147 | { "\033[2$" , KEYC_IC|KEYC_SHIFT }, |
148 | { "\033[3$" , KEYC_DC|KEYC_SHIFT }, |
149 | { "\033[7$" , KEYC_HOME|KEYC_SHIFT }, |
150 | { "\033[8$" , KEYC_END|KEYC_SHIFT }, |
151 | { "\033[6$" , KEYC_NPAGE|KEYC_SHIFT }, |
152 | { "\033[5$" , KEYC_PPAGE|KEYC_SHIFT }, |
153 | |
154 | { "\033[11@" , KEYC_F1|KEYC_CTRL|KEYC_SHIFT }, |
155 | { "\033[12@" , KEYC_F2|KEYC_CTRL|KEYC_SHIFT }, |
156 | { "\033[13@" , KEYC_F3|KEYC_CTRL|KEYC_SHIFT }, |
157 | { "\033[14@" , KEYC_F4|KEYC_CTRL|KEYC_SHIFT }, |
158 | { "\033[15@" , KEYC_F5|KEYC_CTRL|KEYC_SHIFT }, |
159 | { "\033[17@" , KEYC_F6|KEYC_CTRL|KEYC_SHIFT }, |
160 | { "\033[18@" , KEYC_F7|KEYC_CTRL|KEYC_SHIFT }, |
161 | { "\033[19@" , KEYC_F8|KEYC_CTRL|KEYC_SHIFT }, |
162 | { "\033[20@" , KEYC_F9|KEYC_CTRL|KEYC_SHIFT }, |
163 | { "\033[21@" , KEYC_F10|KEYC_CTRL|KEYC_SHIFT }, |
164 | { "\033[23@" , KEYC_F11|KEYC_CTRL|KEYC_SHIFT }, |
165 | { "\033[24@" , KEYC_F12|KEYC_CTRL|KEYC_SHIFT }, |
166 | { "\033[2@" , KEYC_IC|KEYC_CTRL|KEYC_SHIFT }, |
167 | { "\033[3@" , KEYC_DC|KEYC_CTRL|KEYC_SHIFT }, |
168 | { "\033[7@" , KEYC_HOME|KEYC_CTRL|KEYC_SHIFT }, |
169 | { "\033[8@" , KEYC_END|KEYC_CTRL|KEYC_SHIFT }, |
170 | { "\033[6@" , KEYC_NPAGE|KEYC_CTRL|KEYC_SHIFT }, |
171 | { "\033[5@" , KEYC_PPAGE|KEYC_CTRL|KEYC_SHIFT }, |
172 | |
173 | /* Focus tracking. */ |
174 | { "\033[I" , KEYC_FOCUS_IN }, |
175 | { "\033[O" , KEYC_FOCUS_OUT }, |
176 | |
177 | /* Paste keys. */ |
178 | { "\033[200~" , KEYC_PASTE_START }, |
179 | { "\033[201~" , KEYC_PASTE_END }, |
180 | }; |
181 | |
182 | /* |
183 | * Default terminfo(5) keys. Any keys that have builtin modifiers |
184 | * (that is, where the key itself contains the modifiers) has the |
185 | * KEYC_XTERM flag set so a leading escape is not treated as meta (and |
186 | * probably removed). |
187 | */ |
188 | struct tty_default_key_code { |
189 | enum tty_code_code code; |
190 | key_code key; |
191 | }; |
192 | static const struct tty_default_key_code tty_default_code_keys[] = { |
193 | /* Function keys. */ |
194 | { TTYC_KF1, KEYC_F1 }, |
195 | { TTYC_KF2, KEYC_F2 }, |
196 | { TTYC_KF3, KEYC_F3 }, |
197 | { TTYC_KF4, KEYC_F4 }, |
198 | { TTYC_KF5, KEYC_F5 }, |
199 | { TTYC_KF6, KEYC_F6 }, |
200 | { TTYC_KF7, KEYC_F7 }, |
201 | { TTYC_KF8, KEYC_F8 }, |
202 | { TTYC_KF9, KEYC_F9 }, |
203 | { TTYC_KF10, KEYC_F10 }, |
204 | { TTYC_KF11, KEYC_F11 }, |
205 | { TTYC_KF12, KEYC_F12 }, |
206 | |
207 | { TTYC_KF13, KEYC_F1|KEYC_SHIFT|KEYC_XTERM }, |
208 | { TTYC_KF14, KEYC_F2|KEYC_SHIFT|KEYC_XTERM }, |
209 | { TTYC_KF15, KEYC_F3|KEYC_SHIFT|KEYC_XTERM }, |
210 | { TTYC_KF16, KEYC_F4|KEYC_SHIFT|KEYC_XTERM }, |
211 | { TTYC_KF17, KEYC_F5|KEYC_SHIFT|KEYC_XTERM }, |
212 | { TTYC_KF18, KEYC_F6|KEYC_SHIFT|KEYC_XTERM }, |
213 | { TTYC_KF19, KEYC_F7|KEYC_SHIFT|KEYC_XTERM }, |
214 | { TTYC_KF20, KEYC_F8|KEYC_SHIFT|KEYC_XTERM }, |
215 | { TTYC_KF21, KEYC_F9|KEYC_SHIFT|KEYC_XTERM }, |
216 | { TTYC_KF22, KEYC_F10|KEYC_SHIFT|KEYC_XTERM }, |
217 | { TTYC_KF23, KEYC_F11|KEYC_SHIFT|KEYC_XTERM }, |
218 | { TTYC_KF24, KEYC_F12|KEYC_SHIFT|KEYC_XTERM }, |
219 | |
220 | { TTYC_KF25, KEYC_F1|KEYC_CTRL|KEYC_XTERM }, |
221 | { TTYC_KF26, KEYC_F2|KEYC_CTRL|KEYC_XTERM }, |
222 | { TTYC_KF27, KEYC_F3|KEYC_CTRL|KEYC_XTERM }, |
223 | { TTYC_KF28, KEYC_F4|KEYC_CTRL|KEYC_XTERM }, |
224 | { TTYC_KF29, KEYC_F5|KEYC_CTRL|KEYC_XTERM }, |
225 | { TTYC_KF30, KEYC_F6|KEYC_CTRL|KEYC_XTERM }, |
226 | { TTYC_KF31, KEYC_F7|KEYC_CTRL|KEYC_XTERM }, |
227 | { TTYC_KF32, KEYC_F8|KEYC_CTRL|KEYC_XTERM }, |
228 | { TTYC_KF33, KEYC_F9|KEYC_CTRL|KEYC_XTERM }, |
229 | { TTYC_KF34, KEYC_F10|KEYC_CTRL|KEYC_XTERM }, |
230 | { TTYC_KF35, KEYC_F11|KEYC_CTRL|KEYC_XTERM }, |
231 | { TTYC_KF36, KEYC_F12|KEYC_CTRL|KEYC_XTERM }, |
232 | |
233 | { TTYC_KF37, KEYC_F1|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
234 | { TTYC_KF38, KEYC_F2|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
235 | { TTYC_KF39, KEYC_F3|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
236 | { TTYC_KF40, KEYC_F4|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
237 | { TTYC_KF41, KEYC_F5|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
238 | { TTYC_KF42, KEYC_F6|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
239 | { TTYC_KF43, KEYC_F7|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
240 | { TTYC_KF44, KEYC_F8|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
241 | { TTYC_KF45, KEYC_F9|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
242 | { TTYC_KF46, KEYC_F10|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
243 | { TTYC_KF47, KEYC_F11|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
244 | { TTYC_KF48, KEYC_F12|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
245 | |
246 | { TTYC_KF49, KEYC_F1|KEYC_ESCAPE|KEYC_XTERM }, |
247 | { TTYC_KF50, KEYC_F2|KEYC_ESCAPE|KEYC_XTERM }, |
248 | { TTYC_KF51, KEYC_F3|KEYC_ESCAPE|KEYC_XTERM }, |
249 | { TTYC_KF52, KEYC_F4|KEYC_ESCAPE|KEYC_XTERM }, |
250 | { TTYC_KF53, KEYC_F5|KEYC_ESCAPE|KEYC_XTERM }, |
251 | { TTYC_KF54, KEYC_F6|KEYC_ESCAPE|KEYC_XTERM }, |
252 | { TTYC_KF55, KEYC_F7|KEYC_ESCAPE|KEYC_XTERM }, |
253 | { TTYC_KF56, KEYC_F8|KEYC_ESCAPE|KEYC_XTERM }, |
254 | { TTYC_KF57, KEYC_F9|KEYC_ESCAPE|KEYC_XTERM }, |
255 | { TTYC_KF58, KEYC_F10|KEYC_ESCAPE|KEYC_XTERM }, |
256 | { TTYC_KF59, KEYC_F11|KEYC_ESCAPE|KEYC_XTERM }, |
257 | { TTYC_KF60, KEYC_F12|KEYC_ESCAPE|KEYC_XTERM }, |
258 | |
259 | { TTYC_KF61, KEYC_F1|KEYC_ESCAPE|KEYC_SHIFT|KEYC_XTERM }, |
260 | { TTYC_KF62, KEYC_F2|KEYC_ESCAPE|KEYC_SHIFT|KEYC_XTERM }, |
261 | { TTYC_KF63, KEYC_F3|KEYC_ESCAPE|KEYC_SHIFT|KEYC_XTERM }, |
262 | |
263 | { TTYC_KICH1, KEYC_IC }, |
264 | { TTYC_KDCH1, KEYC_DC }, |
265 | { TTYC_KHOME, KEYC_HOME }, |
266 | { TTYC_KEND, KEYC_END }, |
267 | { TTYC_KNP, KEYC_NPAGE }, |
268 | { TTYC_KPP, KEYC_PPAGE }, |
269 | { TTYC_KCBT, KEYC_BTAB }, |
270 | |
271 | /* Arrow keys from terminfo. */ |
272 | { TTYC_KCUU1, KEYC_UP }, |
273 | { TTYC_KCUD1, KEYC_DOWN }, |
274 | { TTYC_KCUB1, KEYC_LEFT }, |
275 | { TTYC_KCUF1, KEYC_RIGHT }, |
276 | |
277 | /* Key and modifier capabilities. */ |
278 | { TTYC_KDC2, KEYC_DC|KEYC_SHIFT|KEYC_XTERM }, |
279 | { TTYC_KDC3, KEYC_DC|KEYC_ESCAPE|KEYC_XTERM }, |
280 | { TTYC_KDC4, KEYC_DC|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM }, |
281 | { TTYC_KDC5, KEYC_DC|KEYC_CTRL|KEYC_XTERM }, |
282 | { TTYC_KDC6, KEYC_DC|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
283 | { TTYC_KDC7, KEYC_DC|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM }, |
284 | { TTYC_KIND, KEYC_DOWN|KEYC_SHIFT|KEYC_XTERM }, |
285 | { TTYC_KDN2, KEYC_DOWN|KEYC_SHIFT|KEYC_XTERM }, |
286 | { TTYC_KDN3, KEYC_DOWN|KEYC_ESCAPE|KEYC_XTERM }, |
287 | { TTYC_KDN4, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM }, |
288 | { TTYC_KDN5, KEYC_DOWN|KEYC_CTRL|KEYC_XTERM }, |
289 | { TTYC_KDN6, KEYC_DOWN|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
290 | { TTYC_KDN7, KEYC_DOWN|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM }, |
291 | { TTYC_KEND2, KEYC_END|KEYC_SHIFT|KEYC_XTERM }, |
292 | { TTYC_KEND3, KEYC_END|KEYC_ESCAPE|KEYC_XTERM }, |
293 | { TTYC_KEND4, KEYC_END|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM }, |
294 | { TTYC_KEND5, KEYC_END|KEYC_CTRL|KEYC_XTERM }, |
295 | { TTYC_KEND6, KEYC_END|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
296 | { TTYC_KEND7, KEYC_END|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM }, |
297 | { TTYC_KHOM2, KEYC_HOME|KEYC_SHIFT|KEYC_XTERM }, |
298 | { TTYC_KHOM3, KEYC_HOME|KEYC_ESCAPE|KEYC_XTERM }, |
299 | { TTYC_KHOM4, KEYC_HOME|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM }, |
300 | { TTYC_KHOM5, KEYC_HOME|KEYC_CTRL|KEYC_XTERM }, |
301 | { TTYC_KHOM6, KEYC_HOME|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
302 | { TTYC_KHOM7, KEYC_HOME|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM }, |
303 | { TTYC_KIC2, KEYC_IC|KEYC_SHIFT|KEYC_XTERM }, |
304 | { TTYC_KIC3, KEYC_IC|KEYC_ESCAPE|KEYC_XTERM }, |
305 | { TTYC_KIC4, KEYC_IC|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM }, |
306 | { TTYC_KIC5, KEYC_IC|KEYC_CTRL|KEYC_XTERM }, |
307 | { TTYC_KIC6, KEYC_IC|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
308 | { TTYC_KIC7, KEYC_IC|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM }, |
309 | { TTYC_KLFT2, KEYC_LEFT|KEYC_SHIFT|KEYC_XTERM }, |
310 | { TTYC_KLFT3, KEYC_LEFT|KEYC_ESCAPE|KEYC_XTERM }, |
311 | { TTYC_KLFT4, KEYC_LEFT|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM }, |
312 | { TTYC_KLFT5, KEYC_LEFT|KEYC_CTRL|KEYC_XTERM }, |
313 | { TTYC_KLFT6, KEYC_LEFT|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
314 | { TTYC_KLFT7, KEYC_LEFT|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM }, |
315 | { TTYC_KNXT2, KEYC_NPAGE|KEYC_SHIFT|KEYC_XTERM }, |
316 | { TTYC_KNXT3, KEYC_NPAGE|KEYC_ESCAPE|KEYC_XTERM }, |
317 | { TTYC_KNXT4, KEYC_NPAGE|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM }, |
318 | { TTYC_KNXT5, KEYC_NPAGE|KEYC_CTRL|KEYC_XTERM }, |
319 | { TTYC_KNXT6, KEYC_NPAGE|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
320 | { TTYC_KNXT7, KEYC_NPAGE|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM }, |
321 | { TTYC_KPRV2, KEYC_PPAGE|KEYC_SHIFT|KEYC_XTERM }, |
322 | { TTYC_KPRV3, KEYC_PPAGE|KEYC_ESCAPE|KEYC_XTERM }, |
323 | { TTYC_KPRV4, KEYC_PPAGE|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM }, |
324 | { TTYC_KPRV5, KEYC_PPAGE|KEYC_CTRL|KEYC_XTERM }, |
325 | { TTYC_KPRV6, KEYC_PPAGE|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
326 | { TTYC_KPRV7, KEYC_PPAGE|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM }, |
327 | { TTYC_KRIT2, KEYC_RIGHT|KEYC_SHIFT|KEYC_XTERM }, |
328 | { TTYC_KRIT3, KEYC_RIGHT|KEYC_ESCAPE|KEYC_XTERM }, |
329 | { TTYC_KRIT4, KEYC_RIGHT|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM }, |
330 | { TTYC_KRIT5, KEYC_RIGHT|KEYC_CTRL|KEYC_XTERM }, |
331 | { TTYC_KRIT6, KEYC_RIGHT|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
332 | { TTYC_KRIT7, KEYC_RIGHT|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM }, |
333 | { TTYC_KRI, KEYC_UP|KEYC_SHIFT|KEYC_XTERM }, |
334 | { TTYC_KUP2, KEYC_UP|KEYC_SHIFT|KEYC_XTERM }, |
335 | { TTYC_KUP3, KEYC_UP|KEYC_ESCAPE|KEYC_XTERM }, |
336 | { TTYC_KUP4, KEYC_UP|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM }, |
337 | { TTYC_KUP5, KEYC_UP|KEYC_CTRL|KEYC_XTERM }, |
338 | { TTYC_KUP6, KEYC_UP|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, |
339 | { TTYC_KUP7, KEYC_UP|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM }, |
340 | }; |
341 | |
342 | /* Add key to tree. */ |
343 | static void |
344 | tty_keys_add(struct tty *tty, const char *s, key_code key) |
345 | { |
346 | struct tty_key *tk; |
347 | size_t size; |
348 | const char *keystr; |
349 | |
350 | keystr = key_string_lookup_key(key); |
351 | if ((tk = tty_keys_find(tty, s, strlen(s), &size)) == NULL) { |
352 | log_debug("new key %s: 0x%llx (%s)" , s, key, keystr); |
353 | tty_keys_add1(&tty->key_tree, s, key); |
354 | } else { |
355 | log_debug("replacing key %s: 0x%llx (%s)" , s, key, keystr); |
356 | tk->key = key; |
357 | } |
358 | } |
359 | |
360 | /* Add next node to the tree. */ |
361 | static void |
362 | tty_keys_add1(struct tty_key **tkp, const char *s, key_code key) |
363 | { |
364 | struct tty_key *tk; |
365 | |
366 | /* Allocate a tree entry if there isn't one already. */ |
367 | tk = *tkp; |
368 | if (tk == NULL) { |
369 | tk = *tkp = xcalloc(1, sizeof *tk); |
370 | tk->ch = *s; |
371 | tk->key = KEYC_UNKNOWN; |
372 | } |
373 | |
374 | /* Find the next entry. */ |
375 | if (*s == tk->ch) { |
376 | /* Move forward in string. */ |
377 | s++; |
378 | |
379 | /* If this is the end of the string, no more is necessary. */ |
380 | if (*s == '\0') { |
381 | tk->key = key; |
382 | return; |
383 | } |
384 | |
385 | /* Use the child tree for the next character. */ |
386 | tkp = &tk->next; |
387 | } else { |
388 | if (*s < tk->ch) |
389 | tkp = &tk->left; |
390 | else if (*s > tk->ch) |
391 | tkp = &tk->right; |
392 | } |
393 | |
394 | /* And recurse to add it. */ |
395 | tty_keys_add1(tkp, s, key); |
396 | } |
397 | |
398 | /* Initialise a key tree from the table. */ |
399 | void |
400 | tty_keys_build(struct tty *tty) |
401 | { |
402 | const struct tty_default_key_raw *tdkr; |
403 | const struct tty_default_key_code *tdkc; |
404 | u_int i; |
405 | const char *s; |
406 | struct options_entry *o; |
407 | struct options_array_item *a; |
408 | union options_value *ov; |
409 | |
410 | if (tty->key_tree != NULL) |
411 | tty_keys_free(tty); |
412 | tty->key_tree = NULL; |
413 | |
414 | for (i = 0; i < nitems(tty_default_raw_keys); i++) { |
415 | tdkr = &tty_default_raw_keys[i]; |
416 | |
417 | s = tdkr->string; |
418 | if (*s != '\0') |
419 | tty_keys_add(tty, s, tdkr->key); |
420 | } |
421 | for (i = 0; i < nitems(tty_default_code_keys); i++) { |
422 | tdkc = &tty_default_code_keys[i]; |
423 | |
424 | s = tty_term_string(tty->term, tdkc->code); |
425 | if (*s != '\0') |
426 | tty_keys_add(tty, s, tdkc->key); |
427 | |
428 | } |
429 | |
430 | o = options_get(global_options, "user-keys" ); |
431 | if (o != NULL) { |
432 | a = options_array_first(o); |
433 | while (a != NULL) { |
434 | i = options_array_item_index(a); |
435 | ov = options_array_item_value(a); |
436 | tty_keys_add(tty, ov->string, KEYC_USER + i); |
437 | a = options_array_next(a); |
438 | } |
439 | } |
440 | } |
441 | |
442 | /* Free the entire key tree. */ |
443 | void |
444 | tty_keys_free(struct tty *tty) |
445 | { |
446 | tty_keys_free1(tty->key_tree); |
447 | } |
448 | |
449 | /* Free a single key. */ |
450 | static void |
451 | tty_keys_free1(struct tty_key *tk) |
452 | { |
453 | if (tk->next != NULL) |
454 | tty_keys_free1(tk->next); |
455 | if (tk->left != NULL) |
456 | tty_keys_free1(tk->left); |
457 | if (tk->right != NULL) |
458 | tty_keys_free1(tk->right); |
459 | free(tk); |
460 | } |
461 | |
462 | /* Lookup a key in the tree. */ |
463 | static struct tty_key * |
464 | tty_keys_find(struct tty *tty, const char *buf, size_t len, size_t *size) |
465 | { |
466 | *size = 0; |
467 | return (tty_keys_find1(tty->key_tree, buf, len, size)); |
468 | } |
469 | |
470 | /* Find the next node. */ |
471 | static struct tty_key * |
472 | tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size) |
473 | { |
474 | /* If no data, no match. */ |
475 | if (len == 0) |
476 | return (NULL); |
477 | |
478 | /* If the node is NULL, this is the end of the tree. No match. */ |
479 | if (tk == NULL) |
480 | return (NULL); |
481 | |
482 | /* Pick the next in the sequence. */ |
483 | if (tk->ch == *buf) { |
484 | /* Move forward in the string. */ |
485 | buf++; len--; |
486 | (*size)++; |
487 | |
488 | /* At the end of the string, return the current node. */ |
489 | if (len == 0 || (tk->next == NULL && tk->key != KEYC_UNKNOWN)) |
490 | return (tk); |
491 | |
492 | /* Move into the next tree for the following character. */ |
493 | tk = tk->next; |
494 | } else { |
495 | if (*buf < tk->ch) |
496 | tk = tk->left; |
497 | else if (*buf > tk->ch) |
498 | tk = tk->right; |
499 | } |
500 | |
501 | /* Move to the next in the tree. */ |
502 | return (tty_keys_find1(tk, buf, len, size)); |
503 | } |
504 | |
505 | /* Look up part of the next key. */ |
506 | static int |
507 | tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key, |
508 | size_t *size, int expired) |
509 | { |
510 | struct client *c = tty->client; |
511 | struct tty_key *tk, *tk1; |
512 | struct utf8_data ud; |
513 | enum utf8_state more; |
514 | u_int i; |
515 | wchar_t wc; |
516 | int n; |
517 | |
518 | log_debug("%s: next key is %zu (%.*s) (expired=%d)" , c->name, len, |
519 | (int)len, buf, expired); |
520 | |
521 | /* Is this a known key? */ |
522 | tk = tty_keys_find(tty, buf, len, size); |
523 | if (tk != NULL && tk->key != KEYC_UNKNOWN) { |
524 | tk1 = tk; |
525 | do |
526 | log_debug("%s: keys in list: %#llx" , c->name, tk1->key); |
527 | while ((tk1 = tk1->next) != NULL); |
528 | if (tk->next != NULL && !expired) |
529 | return (1); |
530 | *key = tk->key; |
531 | return (0); |
532 | } |
533 | |
534 | /* Is this an an xterm(1) key? */ |
535 | n = xterm_keys_find(buf, len, size, key); |
536 | if (n == 0) |
537 | return (0); |
538 | if (n == 1 && !expired) |
539 | return (1); |
540 | |
541 | /* Is this valid UTF-8? */ |
542 | more = utf8_open(&ud, (u_char)*buf); |
543 | if (more == UTF8_MORE) { |
544 | *size = ud.size; |
545 | if (len < ud.size) { |
546 | if (!expired) |
547 | return (1); |
548 | return (-1); |
549 | } |
550 | for (i = 1; i < ud.size; i++) |
551 | more = utf8_append(&ud, (u_char)buf[i]); |
552 | if (more != UTF8_DONE) |
553 | return (-1); |
554 | |
555 | if (utf8_combine(&ud, &wc) != UTF8_DONE) |
556 | return (-1); |
557 | *key = wc; |
558 | |
559 | log_debug("%s: UTF-8 key %.*s %#llx" , c->name, (int)ud.size, |
560 | buf, *key); |
561 | return (0); |
562 | } |
563 | |
564 | return (-1); |
565 | } |
566 | |
567 | /* Process at least one key in the buffer. Return 0 if no keys present. */ |
568 | int |
569 | tty_keys_next(struct tty *tty) |
570 | { |
571 | struct client *c = tty->client; |
572 | struct timeval tv; |
573 | const char *buf; |
574 | size_t len, size; |
575 | cc_t bspace; |
576 | int delay, expired = 0, n; |
577 | key_code key; |
578 | struct mouse_event m = { 0 }; |
579 | struct key_event *event; |
580 | |
581 | gettimeofday(&tv, NULL); |
582 | |
583 | /* Get key buffer. */ |
584 | buf = EVBUFFER_DATA(tty->in); |
585 | len = EVBUFFER_LENGTH(tty->in); |
586 | if (len == 0) |
587 | return (0); |
588 | log_debug("%s: keys are %zu (%.*s)" , c->name, len, (int)len, buf); |
589 | |
590 | /* Is this a clipboard response? */ |
591 | switch (tty_keys_clipboard(tty, buf, len, &size)) { |
592 | case 0: /* yes */ |
593 | key = KEYC_UNKNOWN; |
594 | goto complete_key; |
595 | case -1: /* no, or not valid */ |
596 | break; |
597 | case 1: /* partial */ |
598 | goto partial_key; |
599 | } |
600 | |
601 | /* Is this a device attributes response? */ |
602 | switch (tty_keys_device_attributes(tty, buf, len, &size)) { |
603 | case 0: /* yes */ |
604 | key = KEYC_UNKNOWN; |
605 | goto complete_key; |
606 | case -1: /* no, or not valid */ |
607 | break; |
608 | case 1: /* partial */ |
609 | goto partial_key; |
610 | } |
611 | |
612 | /* Is this a device status report response? */ |
613 | switch (tty_keys_device_status_report(tty, buf, len, &size)) { |
614 | case 0: /* yes */ |
615 | key = KEYC_UNKNOWN; |
616 | goto complete_key; |
617 | case -1: /* no, or not valid */ |
618 | break; |
619 | case 1: /* partial */ |
620 | goto partial_key; |
621 | } |
622 | |
623 | /* Is this a mouse key press? */ |
624 | switch (tty_keys_mouse(tty, buf, len, &size, &m)) { |
625 | case 0: /* yes */ |
626 | key = KEYC_MOUSE; |
627 | goto complete_key; |
628 | case -1: /* no, or not valid */ |
629 | break; |
630 | case -2: /* yes, but we don't care. */ |
631 | key = KEYC_MOUSE; |
632 | goto discard_key; |
633 | case 1: /* partial */ |
634 | goto partial_key; |
635 | } |
636 | |
637 | first_key: |
638 | /* Try to lookup complete key. */ |
639 | n = tty_keys_next1(tty, buf, len, &key, &size, expired); |
640 | if (n == 0) /* found */ |
641 | goto complete_key; |
642 | if (n == 1) |
643 | goto partial_key; |
644 | |
645 | /* |
646 | * If not a complete key, look for key with an escape prefix (meta |
647 | * modifier). |
648 | */ |
649 | if (*buf == '\033' && len > 1) { |
650 | /* Look for a key without the escape. */ |
651 | n = tty_keys_next1(tty, buf + 1, len - 1, &key, &size, expired); |
652 | if (n == 0) { /* found */ |
653 | if (key & KEYC_XTERM) { |
654 | /* |
655 | * We want the escape key as well as the xterm |
656 | * key, because the xterm sequence implicitly |
657 | * includes the escape (so if we see |
658 | * \033\033[1;3D we know it is an Escape |
659 | * followed by M-Left, not just M-Left). |
660 | */ |
661 | key = '\033'; |
662 | size = 1; |
663 | goto complete_key; |
664 | } |
665 | key |= KEYC_ESCAPE; |
666 | size++; |
667 | goto complete_key; |
668 | } |
669 | if (n == 1) /* partial */ |
670 | goto partial_key; |
671 | } |
672 | |
673 | /* |
674 | * At this point, we know the key is not partial (with or without |
675 | * escape). So pass it through even if the timer has not expired. |
676 | */ |
677 | if (*buf == '\033' && len >= 2) { |
678 | key = (u_char)buf[1] | KEYC_ESCAPE; |
679 | size = 2; |
680 | } else { |
681 | key = (u_char)buf[0]; |
682 | size = 1; |
683 | } |
684 | goto complete_key; |
685 | |
686 | partial_key: |
687 | log_debug("%s: partial key %.*s" , c->name, (int)len, buf); |
688 | |
689 | /* If timer is going, check for expiration. */ |
690 | if (tty->flags & TTY_TIMER) { |
691 | if (evtimer_initialized(&tty->key_timer) && |
692 | !evtimer_pending(&tty->key_timer, NULL)) { |
693 | expired = 1; |
694 | goto first_key; |
695 | } |
696 | return (0); |
697 | } |
698 | |
699 | /* Get the time period. */ |
700 | delay = options_get_number(global_options, "escape-time" ); |
701 | tv.tv_sec = delay / 1000; |
702 | tv.tv_usec = (delay % 1000) * 1000L; |
703 | |
704 | /* Start the timer. */ |
705 | if (event_initialized(&tty->key_timer)) |
706 | evtimer_del(&tty->key_timer); |
707 | evtimer_set(&tty->key_timer, tty_keys_callback, tty); |
708 | evtimer_add(&tty->key_timer, &tv); |
709 | |
710 | tty->flags |= TTY_TIMER; |
711 | return (0); |
712 | |
713 | complete_key: |
714 | log_debug("%s: complete key %.*s %#llx" , c->name, (int)size, buf, key); |
715 | |
716 | /* |
717 | * Check for backspace key using termios VERASE - the terminfo |
718 | * kbs entry is extremely unreliable, so cannot be safely |
719 | * used. termios should have a better idea. |
720 | */ |
721 | bspace = tty->tio.c_cc[VERASE]; |
722 | if (bspace != _POSIX_VDISABLE && (key & KEYC_MASK_KEY) == bspace) |
723 | key = (key & KEYC_MASK_MOD) | KEYC_BSPACE; |
724 | |
725 | /* Remove data from buffer. */ |
726 | evbuffer_drain(tty->in, size); |
727 | |
728 | /* Remove key timer. */ |
729 | if (event_initialized(&tty->key_timer)) |
730 | evtimer_del(&tty->key_timer); |
731 | tty->flags &= ~TTY_TIMER; |
732 | |
733 | /* Check for focus events. */ |
734 | if (key == KEYC_FOCUS_OUT) { |
735 | tty->client->flags &= ~CLIENT_FOCUSED; |
736 | return (1); |
737 | } else if (key == KEYC_FOCUS_IN) { |
738 | tty->client->flags |= CLIENT_FOCUSED; |
739 | return (1); |
740 | } |
741 | |
742 | /* Fire the key. */ |
743 | if (key != KEYC_UNKNOWN) { |
744 | event = xmalloc(sizeof *event); |
745 | event->key = key; |
746 | memcpy(&event->m, &m, sizeof event->m); |
747 | if (!server_client_handle_key(c, event)) |
748 | free(event); |
749 | } |
750 | |
751 | return (1); |
752 | |
753 | discard_key: |
754 | log_debug("%s: discard key %.*s %#llx" , c->name, (int)size, buf, key); |
755 | |
756 | /* Remove data from buffer. */ |
757 | evbuffer_drain(tty->in, size); |
758 | |
759 | return (1); |
760 | } |
761 | |
762 | /* Key timer callback. */ |
763 | static void |
764 | tty_keys_callback(__unused int fd, __unused short events, void *data) |
765 | { |
766 | struct tty *tty = data; |
767 | |
768 | if (tty->flags & TTY_TIMER) { |
769 | while (tty_keys_next(tty)) |
770 | ; |
771 | } |
772 | } |
773 | |
774 | /* |
775 | * Handle mouse key input. Returns 0 for success, -1 for failure, 1 for partial |
776 | * (probably a mouse sequence but need more data). |
777 | */ |
778 | static int |
779 | tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, |
780 | struct mouse_event *m) |
781 | { |
782 | struct client *c = tty->client; |
783 | u_int i, x, y, b, sgr_b; |
784 | u_char sgr_type, ch; |
785 | |
786 | /* |
787 | * Standard mouse sequences are \033[M followed by three characters |
788 | * indicating button, X and Y, all based at 32 with 1,1 top-left. |
789 | * |
790 | * UTF-8 mouse sequences are similar but the three are expressed as |
791 | * UTF-8 characters. |
792 | * |
793 | * SGR extended mouse sequences are \033[< followed by three numbers in |
794 | * decimal and separated by semicolons indicating button, X and Y. A |
795 | * trailing 'M' is click or scroll and trailing 'm' release. All are |
796 | * based at 0 with 1,1 top-left. |
797 | */ |
798 | |
799 | *size = 0; |
800 | x = y = b = sgr_b = 0; |
801 | sgr_type = ' '; |
802 | |
803 | /* First two bytes are always \033[. */ |
804 | if (buf[0] != '\033') |
805 | return (-1); |
806 | if (len == 1) |
807 | return (1); |
808 | if (buf[1] != '[') |
809 | return (-1); |
810 | if (len == 2) |
811 | return (1); |
812 | |
813 | /* |
814 | * Third byte is M in old standard (and UTF-8 extension which we do not |
815 | * support), < in SGR extension. |
816 | */ |
817 | if (buf[2] == 'M') { |
818 | /* Read the three inputs. */ |
819 | *size = 3; |
820 | for (i = 0; i < 3; i++) { |
821 | if (len <= *size) |
822 | return (1); |
823 | ch = (u_char)buf[(*size)++]; |
824 | if (i == 0) |
825 | b = ch; |
826 | else if (i == 1) |
827 | x = ch; |
828 | else |
829 | y = ch; |
830 | } |
831 | log_debug("%s: mouse input: %.*s" , c->name, (int)*size, buf); |
832 | |
833 | /* Check and return the mouse input. */ |
834 | if (b < 32) |
835 | return (-1); |
836 | b -= 32; |
837 | if (x >= 33) |
838 | x -= 33; |
839 | else |
840 | x = 256 - x; |
841 | if (y >= 33) |
842 | y -= 33; |
843 | else |
844 | y = 256 - y; |
845 | } else if (buf[2] == '<') { |
846 | /* Read the three inputs. */ |
847 | *size = 3; |
848 | while (1) { |
849 | if (len <= *size) |
850 | return (1); |
851 | ch = (u_char)buf[(*size)++]; |
852 | if (ch == ';') |
853 | break; |
854 | if (ch < '0' || ch > '9') |
855 | return (-1); |
856 | sgr_b = 10 * sgr_b + (ch - '0'); |
857 | } |
858 | while (1) { |
859 | if (len <= *size) |
860 | return (1); |
861 | ch = (u_char)buf[(*size)++]; |
862 | if (ch == ';') |
863 | break; |
864 | if (ch < '0' || ch > '9') |
865 | return (-1); |
866 | x = 10 * x + (ch - '0'); |
867 | } |
868 | while (1) { |
869 | if (len <= *size) |
870 | return (1); |
871 | ch = (u_char)buf[(*size)++]; |
872 | if (ch == 'M' || ch == 'm') |
873 | break; |
874 | if (ch < '0' || ch > '9') |
875 | return (-1); |
876 | y = 10 * y + (ch - '0'); |
877 | } |
878 | log_debug("%s: mouse input (SGR): %.*s" , c->name, (int)*size, |
879 | buf); |
880 | |
881 | /* Check and return the mouse input. */ |
882 | if (x < 1 || y < 1) |
883 | return (-1); |
884 | x--; |
885 | y--; |
886 | b = sgr_b; |
887 | |
888 | /* Type is M for press, m for release. */ |
889 | sgr_type = ch; |
890 | if (sgr_type == 'm') |
891 | b |= 3; |
892 | |
893 | /* |
894 | * Some terminals (like PuTTY 0.63) mistakenly send |
895 | * button-release events for scroll-wheel button-press event. |
896 | * Discard it before it reaches any program running inside |
897 | * tmux. |
898 | */ |
899 | if (sgr_type == 'm' && (sgr_b & 64)) |
900 | return (-2); |
901 | } else |
902 | return (-1); |
903 | |
904 | /* Fill mouse event. */ |
905 | m->lx = tty->mouse_last_x; |
906 | m->x = x; |
907 | m->ly = tty->mouse_last_y; |
908 | m->y = y; |
909 | m->lb = tty->mouse_last_b; |
910 | m->b = b; |
911 | m->sgr_type = sgr_type; |
912 | m->sgr_b = sgr_b; |
913 | |
914 | /* Update last mouse state. */ |
915 | tty->mouse_last_x = x; |
916 | tty->mouse_last_y = y; |
917 | tty->mouse_last_b = b; |
918 | |
919 | return (0); |
920 | } |
921 | |
922 | /* |
923 | * Handle OSC 52 clipboard input. Returns 0 for success, -1 for failure, 1 for |
924 | * partial. |
925 | */ |
926 | static int |
927 | tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len, |
928 | size_t *size) |
929 | { |
930 | size_t end, terminator, needed; |
931 | char *copy, *out; |
932 | int outlen; |
933 | |
934 | *size = 0; |
935 | |
936 | /* First three bytes are always \033]52;. */ |
937 | if (buf[0] != '\033') |
938 | return (-1); |
939 | if (len == 1) |
940 | return (1); |
941 | if (buf[1] != ']') |
942 | return (-1); |
943 | if (len == 2) |
944 | return (1); |
945 | if (buf[2] != '5') |
946 | return (-1); |
947 | if (len == 3) |
948 | return (1); |
949 | if (buf[3] != '2') |
950 | return (-1); |
951 | if (len == 4) |
952 | return (1); |
953 | if (buf[4] != ';') |
954 | return (-1); |
955 | if (len == 5) |
956 | return (1); |
957 | |
958 | /* Find the terminator if any. */ |
959 | for (end = 5; end < len; end++) { |
960 | if (buf[end] == '\007') { |
961 | terminator = 1; |
962 | break; |
963 | } |
964 | if (end > 5 && buf[end - 1] == '\033' && buf[end] == '\\') { |
965 | terminator = 2; |
966 | break; |
967 | } |
968 | } |
969 | if (end == len) |
970 | return (1); |
971 | *size = end + terminator; |
972 | |
973 | /* Skip the initial part. */ |
974 | buf += 5; |
975 | end -= 5; |
976 | |
977 | /* Get the second argument. */ |
978 | while (end != 0 && *buf != ';') { |
979 | buf++; |
980 | end--; |
981 | } |
982 | if (end == 0 || end == 1) |
983 | return (0); |
984 | buf++; |
985 | end--; |
986 | |
987 | /* It has to be a string so copy it. */ |
988 | copy = xmalloc(end + 1); |
989 | memcpy(copy, buf, end); |
990 | copy[end] = '\0'; |
991 | |
992 | /* Convert from base64. */ |
993 | needed = (end / 4) * 3; |
994 | out = xmalloc(needed); |
995 | if ((outlen = b64_pton(copy, out, len)) == -1) { |
996 | free(out); |
997 | free(copy); |
998 | return (0); |
999 | } |
1000 | free(copy); |
1001 | |
1002 | /* Create a new paste buffer. */ |
1003 | log_debug("%s: %.*s" , __func__, outlen, out); |
1004 | paste_add(NULL, out, outlen); |
1005 | |
1006 | return (0); |
1007 | } |
1008 | |
1009 | /* |
1010 | * Handle device attributes input. Returns 0 for success, -1 for failure, 1 for |
1011 | * partial. |
1012 | */ |
1013 | static int |
1014 | tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len, |
1015 | size_t *size) |
1016 | { |
1017 | struct client *c = tty->client; |
1018 | u_int i, n = 0; |
1019 | char tmp[64], *endptr, p[32] = { 0 }, *cp, *next; |
1020 | int flags = 0; |
1021 | |
1022 | *size = 0; |
1023 | if (tty->flags & TTY_HAVEDA) |
1024 | return (-1); |
1025 | |
1026 | /* First three bytes are always \033[?. */ |
1027 | if (buf[0] != '\033') |
1028 | return (-1); |
1029 | if (len == 1) |
1030 | return (1); |
1031 | if (buf[1] != '[') |
1032 | return (-1); |
1033 | if (len == 2) |
1034 | return (1); |
1035 | if (buf[2] != '?') |
1036 | return (-1); |
1037 | if (len == 3) |
1038 | return (1); |
1039 | |
1040 | /* Copy the rest up to a 'c'. */ |
1041 | for (i = 0; i < (sizeof tmp) - 1 && buf[3 + i] != 'c'; i++) { |
1042 | if (3 + i == len) |
1043 | return (1); |
1044 | tmp[i] = buf[3 + i]; |
1045 | } |
1046 | if (i == (sizeof tmp) - 1) |
1047 | return (-1); |
1048 | tmp[i] = '\0'; |
1049 | *size = 4 + i; |
1050 | |
1051 | /* Convert version numbers. */ |
1052 | cp = tmp; |
1053 | while ((next = strsep(&cp, ";" )) != NULL) { |
1054 | p[n] = strtoul(next, &endptr, 10); |
1055 | if (*endptr != '\0') |
1056 | p[n] = 0; |
1057 | n++; |
1058 | } |
1059 | |
1060 | /* Set terminal flags. */ |
1061 | switch (p[0]) { |
1062 | case 64: /* VT420 */ |
1063 | flags |= (TERM_DECFRA|TERM_DECSLRM); |
1064 | break; |
1065 | } |
1066 | for (i = 1; i < n; i++) |
1067 | log_debug("%s: DA feature: %d" , c->name, p[i]); |
1068 | log_debug("%s: received DA %.*s" , c->name, (int)*size, buf); |
1069 | |
1070 | tty_set_flags(tty, flags); |
1071 | tty->flags |= TTY_HAVEDA; |
1072 | |
1073 | return (0); |
1074 | } |
1075 | |
1076 | /* |
1077 | * Handle device status report input. Returns 0 for success, -1 for failure, 1 |
1078 | * for partial. |
1079 | */ |
1080 | static int |
1081 | tty_keys_device_status_report(struct tty *tty, const char *buf, size_t len, |
1082 | size_t *size) |
1083 | { |
1084 | struct client *c = tty->client; |
1085 | u_int i; |
1086 | char tmp[64]; |
1087 | int flags = 0; |
1088 | |
1089 | *size = 0; |
1090 | if (tty->flags & TTY_HAVEDSR) |
1091 | return (-1); |
1092 | |
1093 | /* First three bytes are always \033[. */ |
1094 | if (buf[0] != '\033') |
1095 | return (-1); |
1096 | if (len == 1) |
1097 | return (1); |
1098 | if (buf[1] != '[') |
1099 | return (-1); |
1100 | if (len == 2) |
1101 | return (1); |
1102 | if (buf[2] != 'I' && buf[2] != 'T') |
1103 | return (-1); |
1104 | if (len == 3) |
1105 | return (1); |
1106 | |
1107 | /* Copy the rest up to a 'n'. */ |
1108 | for (i = 0; i < (sizeof tmp) - 1 && buf[2 + i] != 'n'; i++) { |
1109 | if (2 + i == len) |
1110 | return (1); |
1111 | tmp[i] = buf[2 + i]; |
1112 | } |
1113 | if (i == (sizeof tmp) - 1) |
1114 | return (-1); |
1115 | tmp[i] = '\0'; |
1116 | *size = 3 + i; |
1117 | |
1118 | /* Set terminal flags. */ |
1119 | if (strncmp(tmp, "ITERM2 " , 7) == 0) |
1120 | flags |= (TERM_DECSLRM|TERM_256COLOURS|TERM_RGBCOLOURS); |
1121 | if (strncmp(tmp, "TMUX " , 5) == 0) |
1122 | flags |= (TERM_256COLOURS|TERM_RGBCOLOURS); |
1123 | log_debug("%s: received DSR %.*s" , c->name, (int)*size, buf); |
1124 | |
1125 | tty_set_flags(tty, flags); |
1126 | tty->flags |= TTY_HAVEDSR; |
1127 | |
1128 | return (0); |
1129 | } |
1130 | |