1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2009 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 #include <sys/ioctl.h>
21 #include <sys/uio.h>
22 
23 #include <errno.h>
24 #include <event.h>
25 #include <fcntl.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 #include <unistd.h>
30 
31 #include "tmux.h"
32 #include "tmate.h"
33 
34 void		server_client_free(int, short, void *);
35 void		server_client_check_focus(struct window_pane *);
36 void		server_client_check_resize(struct window_pane *);
37 key_code	server_client_check_mouse(struct client *);
38 void		server_client_repeat_timer(int, short, void *);
39 void		server_client_check_exit(struct client *);
40 void		server_client_check_redraw(struct client *);
41 void		server_client_set_title(struct client *);
42 void		server_client_reset_state(struct client *);
43 int		server_client_assume_paste(struct session *);
44 
45 void		server_client_dispatch(struct imsg *, void *);
46 void		server_client_dispatch_command(struct client *, struct imsg *);
47 void		server_client_dispatch_identify(struct client *, struct imsg *);
48 void		server_client_dispatch_shell(struct client *);
49 
50 /* Check if this client is inside this server. */
51 int
server_client_check_nested(struct client * c)52 server_client_check_nested(struct client *c)
53 {
54 	struct environ_entry	*envent;
55 	struct window_pane	*wp;
56 
57 	if (c->tty.path == NULL)
58 		return (0);
59 
60 	envent = environ_find(c->environ, "TMUX");
61 	if (envent == NULL || *envent->value == '\0')
62 		return (0);
63 
64 	RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
65 		if (strcmp(wp->tty, c->tty.path) == 0)
66 			return (1);
67 	}
68 	return (0);
69 }
70 
71 /* Set client key table. */
72 void
server_client_set_key_table(struct client * c,const char * name)73 server_client_set_key_table(struct client *c, const char *name)
74 {
75 	if (name == NULL)
76 		name = server_client_get_key_table(c);
77 
78 	key_bindings_unref_table(c->keytable);
79 	c->keytable = key_bindings_get_table(name, 1);
80 	c->keytable->references++;
81 }
82 
83 /* Get default key table. */
84 const char *
server_client_get_key_table(struct client * c)85 server_client_get_key_table(struct client *c)
86 {
87 	struct session	*s = c->session;
88 	const char	*name;
89 
90 	if (s == NULL)
91 		return ("root");
92 
93 	name = options_get_string(s->options, "key-table");
94 	if (*name == '\0')
95 		return ("root");
96 	return (name);
97 }
98 
99 #ifdef TMATE
100 u_int	next_client_id;
101 #endif
102 
103 /* Create a new client. */
104 void
server_client_create(int fd)105 server_client_create(int fd)
106 {
107 	struct client	*c;
108 
109 	setblocking(fd, 0);
110 
111 	c = xcalloc(1, sizeof *c);
112 
113 #ifdef TMATE
114 	c->id = next_client_id++;
115 	c->ip_address = NULL;
116 	c->pubkey = NULL;
117 	c->readonly = true;
118 #endif
119 
120 	c->references = 1;
121 	c->peer = proc_add_peer(server_proc, fd, server_client_dispatch, c);
122 
123 	if (gettimeofday(&c->creation_time, NULL) != 0)
124 		fatal("gettimeofday failed");
125 	memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
126 
127 	c->environ = environ_create();
128 
129 	c->fd = -1;
130 	c->cwd = NULL;
131 
132 	c->cmdq = cmdq_new(c);
133 	c->cmdq->client_exit = 1;
134 
135 	c->stdin_data = evbuffer_new();
136 	c->stdout_data = evbuffer_new();
137 	c->stderr_data = evbuffer_new();
138 
139 	c->tty.fd = -1;
140 	c->title = NULL;
141 
142 	c->session = NULL;
143 	c->last_session = NULL;
144 	c->tty.sx = 80;
145 	c->tty.sy = 24;
146 
147 	screen_init(&c->status, c->tty.sx, 1, 0);
148 
149 	c->message_string = NULL;
150 	TAILQ_INIT(&c->message_log);
151 
152 	c->prompt_string = NULL;
153 	c->prompt_buffer = NULL;
154 	c->prompt_index = 0;
155 
156 	c->flags |= CLIENT_FOCUSED;
157 
158 	c->keytable = key_bindings_get_table("root", 1);
159 	c->keytable->references++;
160 
161 	evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
162 
163 	TAILQ_INSERT_TAIL(&clients, c, entry);
164 	log_debug("new client %p", c);
165 }
166 
167 /* Open client terminal if needed. */
168 int
server_client_open(struct client * c,char ** cause)169 server_client_open(struct client *c, char **cause)
170 {
171 	if (c->flags & CLIENT_CONTROL)
172 		return (0);
173 
174 	if (strcmp(c->ttyname, "/dev/tty") == 0) {
175 		*cause = xstrdup("can't use /dev/tty");
176 		return (-1);
177 	}
178 
179 	if (!(c->flags & CLIENT_TERMINAL)) {
180 		*cause = xstrdup("not a terminal");
181 		return (-1);
182 	}
183 
184 	if (tty_open(&c->tty, cause) != 0)
185 		return (-1);
186 
187 	return (0);
188 }
189 
190 /* Lost a client. */
191 void
server_client_lost(struct client * c)192 server_client_lost(struct client *c)
193 {
194 	struct message_entry	*msg, *msg1;
195 
196 	c->flags |= CLIENT_DEAD;
197 
198 	status_prompt_clear(c);
199 	status_message_clear(c);
200 
201 	if (c->stdin_callback != NULL)
202 		c->stdin_callback(c, 1, c->stdin_callback_data);
203 
204 	TAILQ_REMOVE(&clients, c, entry);
205 	log_debug("lost client %p", c);
206 
207 #ifdef TMATE
208 	tmate_notify_client_left(tmate_session, c);
209 #endif
210 
211 	/*
212 	 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
213 	 * and tty_free might close an unrelated fd.
214 	 */
215 	if (c->flags & CLIENT_TERMINAL)
216 		tty_free(&c->tty);
217 	free(c->ttyname);
218 	free(c->term);
219 
220 	evbuffer_free(c->stdin_data);
221 	evbuffer_free(c->stdout_data);
222 	if (c->stderr_data != c->stdout_data)
223 		evbuffer_free(c->stderr_data);
224 
225 	if (event_initialized(&c->status_timer))
226 		evtimer_del(&c->status_timer);
227 	screen_free(&c->status);
228 
229 	free(c->title);
230 	free((void *)c->cwd);
231 
232 	evtimer_del(&c->repeat_timer);
233 
234 	key_bindings_unref_table(c->keytable);
235 
236 	if (event_initialized(&c->identify_timer))
237 		evtimer_del(&c->identify_timer);
238 
239 	free(c->message_string);
240 	if (event_initialized(&c->message_timer))
241 		evtimer_del(&c->message_timer);
242 	TAILQ_FOREACH_SAFE(msg, &c->message_log, entry, msg1) {
243 		free(msg->msg);
244 		TAILQ_REMOVE(&c->message_log, msg, entry);
245 		free(msg);
246 	}
247 
248 	free(c->prompt_string);
249 	free(c->prompt_buffer);
250 
251 	c->cmdq->flags |= CMD_Q_DEAD;
252 	cmdq_free(c->cmdq);
253 	c->cmdq = NULL;
254 
255 #ifdef TMATE
256 	free(c->ip_address);
257 	c->ip_address = NULL;
258 	free(c->pubkey);
259 	c->pubkey = NULL;
260 #endif
261 
262 	environ_free(c->environ);
263 
264 	proc_remove_peer(c->peer);
265 	c->peer = NULL;
266 
267 	server_client_unref(c);
268 
269 #ifndef TMATE
270 	server_add_accept(0); /* may be more file descriptors now */
271 #endif
272 
273 	recalculate_sizes();
274 	server_check_unattached();
275 	server_update_socket();
276 }
277 
278 /* Remove reference from a client. */
279 void
server_client_unref(struct client * c)280 server_client_unref(struct client *c)
281 {
282 	log_debug("unref client %p (%d references)", c, c->references);
283 
284 	c->references--;
285 	if (c->references == 0)
286 		event_once(-1, EV_TIMEOUT, server_client_free, c, NULL);
287 }
288 
289 /* Free dead client. */
290 void
server_client_free(__unused int fd,__unused short events,void * arg)291 server_client_free(__unused int fd, __unused short events, void *arg)
292 {
293 	struct client	*c = arg;
294 
295 	log_debug("free client %p (%d references)", c, c->references);
296 
297 	if (c->references == 0)
298 		free(c);
299 }
300 
301 /* Detach a client. */
302 void
server_client_detach(struct client * c,enum msgtype msgtype)303 server_client_detach(struct client *c, enum msgtype msgtype)
304 {
305 	struct session	*s = c->session;
306 
307 	if (s == NULL)
308 		return;
309 
310 	hooks_run(c->session->hooks, c, NULL, "client-detached");
311 	proc_send_s(c->peer, msgtype, s->name);
312 }
313 
314 /* Check for mouse keys. */
315 key_code
server_client_check_mouse(struct client * c)316 server_client_check_mouse(struct client *c)
317 {
318 	struct session				*s = c->session;
319 	struct mouse_event			*m = &c->tty.mouse;
320 	struct window				*w;
321 	struct window_pane			*wp;
322 	enum { NOTYPE, DOWN, UP, DRAG, WHEEL }	 type = NOTYPE;
323 	enum { NOWHERE, PANE, STATUS, BORDER }	 where = NOWHERE;
324 	u_int					 x, y, b;
325 	key_code				 key;
326 
327 	log_debug("mouse %02x at %u,%u (last %u,%u) (%d)", m->b, m->x, m->y,
328 	    m->lx, m->ly, c->tty.mouse_drag_flag);
329 
330 	/* What type of event is this? */
331 	if (MOUSE_DRAG(m->b)) {
332 		type = DRAG;
333 		if (c->tty.mouse_drag_flag) {
334 			x = m->x, y = m->y, b = m->b;
335 			log_debug("drag update at %u,%u", x, y);
336 		} else {
337 			x = m->lx, y = m->ly, b = m->lb;
338 			log_debug("drag start at %u,%u", x, y);
339 		}
340 	} else if (MOUSE_WHEEL(m->b)) {
341 		type = WHEEL;
342 		x = m->x, y = m->y, b = m->b;
343 		log_debug("wheel at %u,%u", x, y);
344 	} else if (MOUSE_BUTTONS(m->b) == 3) {
345 		type = UP;
346 		x = m->x, y = m->y, b = m->lb;
347 		log_debug("up at %u,%u", x, y);
348 	} else {
349 		type = DOWN;
350 		x = m->x, y = m->y, b = m->b;
351 		log_debug("down at %u,%u", x, y);
352 	}
353 	if (type == NOTYPE)
354 		return (KEYC_UNKNOWN);
355 
356 	/* Always save the session. */
357 	m->s = s->id;
358 
359 	/* Is this on the status line? */
360 	m->statusat = status_at_line(c);
361 	if (m->statusat != -1 && y == (u_int)m->statusat) {
362 		w = status_get_window_at(c, x);
363 		if (w == NULL)
364 			return (KEYC_UNKNOWN);
365 		m->w = w->id;
366 		where = STATUS;
367 	} else
368 		m->w = -1;
369 
370 	/* Not on status line. Adjust position and check for border or pane. */
371 	if (where == NOWHERE) {
372 		if (m->statusat == 0 && y > 0)
373 			y--;
374 		else if (m->statusat > 0 && y >= (u_int)m->statusat)
375 			y = m->statusat - 1;
376 
377 		TAILQ_FOREACH(wp, &s->curw->window->panes, entry) {
378 			if ((wp->xoff + wp->sx == x &&
379 			    wp->yoff <= 1 + y &&
380 			    wp->yoff + wp->sy >= y) ||
381 			    (wp->yoff + wp->sy == y &&
382 			    wp->xoff <= 1 + x &&
383 			    wp->xoff + wp->sx >= x))
384 				break;
385 		}
386 		if (wp != NULL)
387 			where = BORDER;
388 		else {
389 			wp = window_get_active_at(s->curw->window, x, y);
390 			if (wp != NULL) {
391 				where = PANE;
392 				log_debug("mouse at %u,%u is on pane %%%u",
393 				    x, y, wp->id);
394 			}
395 		}
396 		if (where == NOWHERE)
397 			return (KEYC_UNKNOWN);
398 		m->wp = wp->id;
399 		m->w = wp->window->id;
400 	} else
401 		m->wp = -1;
402 
403 	/* Stop dragging if needed. */
404 	if (type != DRAG && c->tty.mouse_drag_flag) {
405 		if (c->tty.mouse_drag_release != NULL)
406 			c->tty.mouse_drag_release(c, m);
407 
408 		c->tty.mouse_drag_update = NULL;
409 		c->tty.mouse_drag_release = NULL;
410 
411 		/*
412 		 * End a mouse drag by passing a MouseDragEnd key corresponding
413 		 * to the button that started the drag.
414 		 */
415 		switch (c->tty.mouse_drag_flag) {
416 		case 1:
417 			if (where == PANE)
418 				key = KEYC_MOUSEDRAGEND1_PANE;
419 			if (where == STATUS)
420 				key = KEYC_MOUSEDRAGEND1_STATUS;
421 			if (where == BORDER)
422 				key = KEYC_MOUSEDRAGEND1_BORDER;
423 			break;
424 		case 2:
425 			if (where == PANE)
426 				key = KEYC_MOUSEDRAGEND2_PANE;
427 			if (where == STATUS)
428 				key = KEYC_MOUSEDRAGEND2_STATUS;
429 			if (where == BORDER)
430 				key = KEYC_MOUSEDRAGEND2_BORDER;
431 			break;
432 		case 3:
433 			if (where == PANE)
434 				key = KEYC_MOUSEDRAGEND3_PANE;
435 			if (where == STATUS)
436 				key = KEYC_MOUSEDRAGEND3_STATUS;
437 			if (where == BORDER)
438 				key = KEYC_MOUSEDRAGEND3_BORDER;
439 			break;
440 		default:
441 			key = KEYC_MOUSE;
442 			break;
443 		}
444 		c->tty.mouse_drag_flag = 0;
445 
446 		return (key);
447 	}
448 
449 	/* Convert to a key binding. */
450 	key = KEYC_UNKNOWN;
451 	switch (type) {
452 	case NOTYPE:
453 		break;
454 	case DRAG:
455 		if (c->tty.mouse_drag_update != NULL)
456 			c->tty.mouse_drag_update(c, m);
457 		else {
458 			switch (MOUSE_BUTTONS(b)) {
459 			case 0:
460 				if (where == PANE)
461 					key = KEYC_MOUSEDRAG1_PANE;
462 				if (where == STATUS)
463 					key = KEYC_MOUSEDRAG1_STATUS;
464 				if (where == BORDER)
465 					key = KEYC_MOUSEDRAG1_BORDER;
466 				break;
467 			case 1:
468 				if (where == PANE)
469 					key = KEYC_MOUSEDRAG2_PANE;
470 				if (where == STATUS)
471 					key = KEYC_MOUSEDRAG2_STATUS;
472 				if (where == BORDER)
473 					key = KEYC_MOUSEDRAG2_BORDER;
474 				break;
475 			case 2:
476 				if (where == PANE)
477 					key = KEYC_MOUSEDRAG3_PANE;
478 				if (where == STATUS)
479 					key = KEYC_MOUSEDRAG3_STATUS;
480 				if (where == BORDER)
481 					key = KEYC_MOUSEDRAG3_BORDER;
482 				break;
483 			}
484 		}
485 
486 		/*
487 		 * Begin a drag by setting the flag to a non-zero value that
488 		 * corresponds to the mouse button in use.
489 		 */
490 		c->tty.mouse_drag_flag = MOUSE_BUTTONS(b) + 1;
491 		break;
492 	case WHEEL:
493 		if (MOUSE_BUTTONS(b) == MOUSE_WHEEL_UP) {
494 			if (where == PANE)
495 				key = KEYC_WHEELUP_PANE;
496 			if (where == STATUS)
497 				key = KEYC_WHEELUP_STATUS;
498 			if (where == BORDER)
499 				key = KEYC_WHEELUP_BORDER;
500 		} else {
501 			if (where == PANE)
502 				key = KEYC_WHEELDOWN_PANE;
503 			if (where == STATUS)
504 				key = KEYC_WHEELDOWN_STATUS;
505 			if (where == BORDER)
506 				key = KEYC_WHEELDOWN_BORDER;
507 		}
508 		break;
509 	case UP:
510 		switch (MOUSE_BUTTONS(b)) {
511 		case 0:
512 			if (where == PANE)
513 				key = KEYC_MOUSEUP1_PANE;
514 			if (where == STATUS)
515 				key = KEYC_MOUSEUP1_STATUS;
516 			if (where == BORDER)
517 				key = KEYC_MOUSEUP1_BORDER;
518 			break;
519 		case 1:
520 			if (where == PANE)
521 				key = KEYC_MOUSEUP2_PANE;
522 			if (where == STATUS)
523 				key = KEYC_MOUSEUP2_STATUS;
524 			if (where == BORDER)
525 				key = KEYC_MOUSEUP2_BORDER;
526 			break;
527 		case 2:
528 			if (where == PANE)
529 				key = KEYC_MOUSEUP3_PANE;
530 			if (where == STATUS)
531 				key = KEYC_MOUSEUP3_STATUS;
532 			if (where == BORDER)
533 				key = KEYC_MOUSEUP3_BORDER;
534 			break;
535 		}
536 		break;
537 	case DOWN:
538 		switch (MOUSE_BUTTONS(b)) {
539 		case 0:
540 			if (where == PANE)
541 				key = KEYC_MOUSEDOWN1_PANE;
542 			if (where == STATUS)
543 				key = KEYC_MOUSEDOWN1_STATUS;
544 			if (where == BORDER)
545 				key = KEYC_MOUSEDOWN1_BORDER;
546 			break;
547 		case 1:
548 			if (where == PANE)
549 				key = KEYC_MOUSEDOWN2_PANE;
550 			if (where == STATUS)
551 				key = KEYC_MOUSEDOWN2_STATUS;
552 			if (where == BORDER)
553 				key = KEYC_MOUSEDOWN2_BORDER;
554 			break;
555 		case 2:
556 			if (where == PANE)
557 				key = KEYC_MOUSEDOWN3_PANE;
558 			if (where == STATUS)
559 				key = KEYC_MOUSEDOWN3_STATUS;
560 			if (where == BORDER)
561 				key = KEYC_MOUSEDOWN3_BORDER;
562 			break;
563 		}
564 		break;
565 	}
566 	if (key == KEYC_UNKNOWN)
567 		return (KEYC_UNKNOWN);
568 
569 	/* Apply modifiers if any. */
570 	if (b & MOUSE_MASK_META)
571 		key |= KEYC_ESCAPE;
572 	if (b & MOUSE_MASK_CTRL)
573 		key |= KEYC_CTRL;
574 	if (b & MOUSE_MASK_SHIFT)
575 		key |= KEYC_SHIFT;
576 
577 	return (key);
578 }
579 
580 /* Is this fast enough to probably be a paste? */
581 int
server_client_assume_paste(struct session * s)582 server_client_assume_paste(struct session *s)
583 {
584 	struct timeval	tv;
585 	int		t;
586 
587 	if ((t = options_get_number(s->options, "assume-paste-time")) == 0)
588 		return (0);
589 
590 	timersub(&s->activity_time, &s->last_activity_time, &tv);
591 	if (tv.tv_sec == 0 && tv.tv_usec < t * 1000) {
592 		log_debug("session %s pasting (flag %d)", s->name,
593 		    !!(s->flags & SESSION_PASTING));
594 		if (s->flags & SESSION_PASTING)
595 			return (1);
596 		s->flags |= SESSION_PASTING;
597 		return (0);
598 	}
599 	log_debug("session %s not pasting", s->name);
600 	s->flags &= ~SESSION_PASTING;
601 	return (0);
602 }
603 
604 /* Handle data key input from client. */
605 void
server_client_handle_key(struct client * c,key_code key)606 server_client_handle_key(struct client *c, key_code key)
607 {
608 	struct mouse_event	*m = &c->tty.mouse;
609 	struct session		*s = c->session;
610 	struct window		*w;
611 	struct window_pane	*wp;
612 	struct timeval		 tv;
613 	struct key_table	*table;
614 	struct key_binding	 bd_find, *bd;
615 	int			 xtimeout;
616 
617 	/* Check the client is good to accept input. */
618 	if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
619 		return;
620 	w = s->curw->window;
621 
622 	/* Update the activity timer. */
623 	if (gettimeofday(&c->activity_time, NULL) != 0)
624 		fatal("gettimeofday failed");
625 	session_update_activity(s, &c->activity_time);
626 
627 	/* Number keys jump to pane in identify mode. */
628 	if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
629 		if (c->flags & CLIENT_READONLY)
630 			return;
631 
632 		window_unzoom(w);
633 		wp = window_pane_at_index(w, key - '0');
634 		if (wp != NULL && window_pane_visible(wp))
635 #ifdef TMATE
636 			tmate_client_set_active_pane(c->id, key - '0', wp->id);
637 #else
638 			window_set_active_pane(w, wp);
639 #endif
640 		server_clear_identify(c);
641 		return;
642 	}
643 
644 	/* Handle status line. */
645 	if (!(c->flags & CLIENT_READONLY)) {
646 		status_message_clear(c);
647 		server_clear_identify(c);
648 	}
649 	if (c->prompt_string != NULL) {
650 		if (!(c->flags & CLIENT_READONLY))
651 			status_prompt_key(c, key);
652 		return;
653 	}
654 
655 	/* Check for mouse keys. */
656 	if (key == KEYC_MOUSE) {
657 		if (c->flags & CLIENT_READONLY)
658 			return;
659 		key = server_client_check_mouse(c);
660 		if (key == KEYC_UNKNOWN)
661 			return;
662 
663 		m->valid = 1;
664 		m->key = key;
665 
666 		if (!options_get_number(s->options, "mouse"))
667 			goto forward;
668 	} else
669 		m->valid = 0;
670 
671 	/* Treat everything as a regular key when pasting is detected. */
672 	if (!KEYC_IS_MOUSE(key) && server_client_assume_paste(s))
673 		goto forward;
674 
675 retry:
676 	/* Try to see if there is a key binding in the current table. */
677 	bd_find.key = key;
678 	bd = RB_FIND(key_bindings, &c->keytable->key_bindings, &bd_find);
679 	if (bd != NULL) {
680 		/*
681 		 * Key was matched in this table. If currently repeating but a
682 		 * non-repeating binding was found, stop repeating and try
683 		 * again in the root table.
684 		 */
685 		if ((c->flags & CLIENT_REPEAT) && !bd->can_repeat) {
686 			server_client_set_key_table(c, NULL);
687 			c->flags &= ~CLIENT_REPEAT;
688 			server_status_client(c);
689 			goto retry;
690 		}
691 
692 		/*
693 		 * Take a reference to this table to make sure the key binding
694 		 * doesn't disappear.
695 		 */
696 		table = c->keytable;
697 		table->references++;
698 
699 		/*
700 		 * If this is a repeating key, start the timer. Otherwise reset
701 		 * the client back to the root table.
702 		 */
703 		xtimeout = options_get_number(s->options, "repeat-time");
704 		if (xtimeout != 0 && bd->can_repeat) {
705 			c->flags |= CLIENT_REPEAT;
706 
707 			tv.tv_sec = xtimeout / 1000;
708 			tv.tv_usec = (xtimeout % 1000) * 1000L;
709 			evtimer_del(&c->repeat_timer);
710 			evtimer_add(&c->repeat_timer, &tv);
711 		} else {
712 			c->flags &= ~CLIENT_REPEAT;
713 			server_client_set_key_table(c, NULL);
714 		}
715 		server_status_client(c);
716 
717 		/* Dispatch the key binding. */
718 		key_bindings_dispatch(bd, c, m);
719 		key_bindings_unref_table(table);
720 		return;
721 	}
722 
723 	/*
724 	 * No match in this table. If repeating, switch the client back to the
725 	 * root table and try again.
726 	 */
727 	if (c->flags & CLIENT_REPEAT) {
728 		server_client_set_key_table(c, NULL);
729 		c->flags &= ~CLIENT_REPEAT;
730 		server_status_client(c);
731 		goto retry;
732 	}
733 
734 	/* If no match and we're not in the root table, that's it. */
735 	if (strcmp(c->keytable->name, server_client_get_key_table(c)) != 0) {
736 		server_client_set_key_table(c, NULL);
737 		server_status_client(c);
738 		return;
739 	}
740 
741 	/*
742 	 * No match, but in the root table. Prefix switches to the prefix table
743 	 * and everything else is passed through.
744 	 */
745 	if (key == (key_code)options_get_number(s->options, "prefix") ||
746 	    key == (key_code)options_get_number(s->options, "prefix2")) {
747 		server_client_set_key_table(c, "prefix");
748 		server_status_client(c);
749 		return;
750 	}
751 
752 forward:
753 	if (c->flags & CLIENT_READONLY)
754 		return;
755 	if (KEYC_IS_MOUSE(key))
756 		wp = cmd_mouse_pane(m, NULL, NULL);
757 	else
758 		wp = w->active;
759 	if (wp != NULL)
760 		window_pane_key(wp, c, s, key, m);
761 }
762 
763 /* Client functions that need to happen every loop. */
764 void
server_client_loop(void)765 server_client_loop(void)
766 {
767 	struct client		*c;
768 	struct window		*w;
769 	struct window_pane	*wp;
770 
771 	TAILQ_FOREACH(c, &clients, entry) {
772 		server_client_check_exit(c);
773 		if (c->session != NULL) {
774 			server_client_check_redraw(c);
775 			server_client_reset_state(c);
776 		}
777 	}
778 
779 	/*
780 	 * Any windows will have been redrawn as part of clients, so clear
781 	 * their flags now. Also check pane focus and resize.
782 	 */
783 	RB_FOREACH(w, windows, &windows) {
784 		w->flags &= ~WINDOW_REDRAW;
785 		TAILQ_FOREACH(wp, &w->panes, entry) {
786 #ifndef TMATE
787 			if (wp->fd != -1) {
788 				server_client_check_focus(wp);
789 				server_client_check_resize(wp);
790 			}
791 #endif
792 			wp->flags &= ~PANE_REDRAW;
793 		}
794 		check_window_name(w);
795 	}
796 }
797 
798 #ifndef TMATE
799 /* Check if pane should be resized. */
800 void
server_client_check_resize(struct window_pane * wp)801 server_client_check_resize(struct window_pane *wp)
802 {
803 	struct winsize	ws;
804 
805 	if (!(wp->flags & PANE_RESIZE))
806 		return;
807 
808 	memset(&ws, 0, sizeof ws);
809 	ws.ws_col = wp->sx;
810 	ws.ws_row = wp->sy;
811 
812 	if (ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) {
813 #ifdef __sun
814 		/*
815 		 * Some versions of Solaris apparently can return an error when
816 		 * resizing; don't know why this happens, can't reproduce on
817 		 * other platforms and ignoring it doesn't seem to cause any
818 		 * issues.
819 		 */
820 		if (errno != EINVAL && errno != ENXIO)
821 #endif
822 		fatal("ioctl failed");
823 	}
824 
825 	wp->flags &= ~PANE_RESIZE;
826 }
827 
828 /* Check whether pane should be focused. */
829 void
server_client_check_focus(struct window_pane * wp)830 server_client_check_focus(struct window_pane *wp)
831 {
832 	struct client	*c;
833 	int		 push;
834 
835 	/* Are focus events off? */
836 	if (!options_get_number(global_options, "focus-events"))
837 		return;
838 
839 	/* Do we need to push the focus state? */
840 	push = wp->flags & PANE_FOCUSPUSH;
841 	wp->flags &= ~PANE_FOCUSPUSH;
842 
843 	/* If we don't care about focus, forget it. */
844 	if (!(wp->base.mode & MODE_FOCUSON))
845 		return;
846 
847 	/* If we're not the active pane in our window, we're not focused. */
848 	if (wp->window->active != wp)
849 		goto not_focused;
850 
851 	/* If we're in a mode, we're not focused. */
852 	if (wp->screen != &wp->base)
853 		goto not_focused;
854 
855 	/*
856 	 * If our window is the current window in any focused clients with an
857 	 * attached session, we're focused.
858 	 */
859 	TAILQ_FOREACH(c, &clients, entry) {
860 		if (c->session == NULL || !(c->flags & CLIENT_FOCUSED))
861 			continue;
862 		if (c->session->flags & SESSION_UNATTACHED)
863 			continue;
864 
865 		if (c->session->curw->window == wp->window)
866 			goto focused;
867 	}
868 
869 not_focused:
870 	if (push || (wp->flags & PANE_FOCUSED))
871 		bufferevent_write(wp->event, "\033[O", 3);
872 	wp->flags &= ~PANE_FOCUSED;
873 	return;
874 
875 focused:
876 	if (push || !(wp->flags & PANE_FOCUSED))
877 		bufferevent_write(wp->event, "\033[I", 3);
878 	wp->flags |= PANE_FOCUSED;
879 }
880 #endif
881 
882 /*
883  * Update cursor position and mode settings. The scroll region and attributes
884  * are cleared when idle (waiting for an event) as this is the most likely time
885  * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
886  * compromise between excessive resets and likelihood of an interrupt.
887  *
888  * tty_region/tty_reset/tty_update_mode already take care of not resetting
889  * things that are already in their default state.
890  */
891 void
server_client_reset_state(struct client * c)892 server_client_reset_state(struct client *c)
893 {
894 	struct window		*w = c->session->curw->window;
895 	struct window_pane	*wp = w->active;
896 	struct screen		*s = wp->screen;
897 	struct options		*oo = c->session->options;
898 	int			 status, mode, o;
899 
900 	if (c->flags & CLIENT_SUSPENDED)
901 		return;
902 
903 	if (c->flags & CLIENT_CONTROL)
904 		return;
905 
906 	tty_region(&c->tty, 0, c->tty.sy - 1);
907 
908 	status = options_get_number(oo, "status");
909 	if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)
910 		tty_cursor(&c->tty, 0, 0);
911 	else {
912 		o = status && options_get_number(oo, "status-position") == 0;
913 		tty_cursor(&c->tty, wp->xoff + s->cx, o + wp->yoff + s->cy);
914 	}
915 
916 	/*
917 	 * Set mouse mode if requested. To support dragging, always use button
918 	 * mode.
919 	 */
920 	mode = s->mode;
921 	if (options_get_number(oo, "mouse"))
922 		mode = (mode & ~ALL_MOUSE_MODES) | MODE_MOUSE_BUTTON;
923 
924 	/* Set the terminal mode and reset attributes. */
925 	tty_update_mode(&c->tty, mode, s);
926 	tty_reset(&c->tty);
927 }
928 
929 /* Repeat time callback. */
930 void
server_client_repeat_timer(__unused int fd,__unused short events,void * data)931 server_client_repeat_timer(__unused int fd, __unused short events, void *data)
932 {
933 	struct client	*c = data;
934 
935 	if (c->flags & CLIENT_REPEAT) {
936 		server_client_set_key_table(c, NULL);
937 		c->flags &= ~CLIENT_REPEAT;
938 		server_status_client(c);
939 	}
940 }
941 
942 /* Check if client should be exited. */
943 void
server_client_check_exit(struct client * c)944 server_client_check_exit(struct client *c)
945 {
946 	if (!(c->flags & CLIENT_EXIT))
947 		return;
948 
949 	if (EVBUFFER_LENGTH(c->stdin_data) != 0)
950 		return;
951 	if (EVBUFFER_LENGTH(c->stdout_data) != 0)
952 		return;
953 	if (EVBUFFER_LENGTH(c->stderr_data) != 0)
954 		return;
955 
956 	proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval);
957 	c->flags &= ~CLIENT_EXIT;
958 }
959 
960 /* Check for client redraws. */
961 void
server_client_check_redraw(struct client * c)962 server_client_check_redraw(struct client *c)
963 {
964 	struct session		*s = c->session;
965 	struct tty		*tty = &c->tty;
966 	struct window_pane	*wp;
967 	int		 	 flags, redraw;
968 
969 	if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
970 		return;
971 
972 	if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
973 		if (options_get_number(s->options, "set-titles"))
974 			server_client_set_title(c);
975 
976 		if (c->message_string != NULL)
977 			redraw = status_message_redraw(c);
978 		else if (c->prompt_string != NULL)
979 			redraw = status_prompt_redraw(c);
980 		else
981 			redraw = status_redraw(c);
982 		if (!redraw)
983 			c->flags &= ~CLIENT_STATUS;
984 	}
985 
986 	flags = tty->flags & (TTY_FREEZE|TTY_NOCURSOR);
987 	tty->flags = (tty->flags & ~TTY_FREEZE) | TTY_NOCURSOR;
988 
989 	if (c->flags & CLIENT_REDRAW) {
990 		tty_update_mode(tty, tty->mode, NULL);
991 		screen_redraw_screen(c, 1, 1, 1);
992 		c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS);
993 	} else if (c->flags & CLIENT_REDRAWWINDOW) {
994 		tty_update_mode(tty, tty->mode, NULL);
995 		TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry)
996 			screen_redraw_pane(c, wp);
997 		c->flags &= ~CLIENT_REDRAWWINDOW;
998 	} else {
999 		TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
1000 			if (wp->flags & PANE_REDRAW) {
1001 				tty_update_mode(tty, tty->mode, NULL);
1002 				screen_redraw_pane(c, wp);
1003 			}
1004 		}
1005 	}
1006 
1007 	if (c->flags & CLIENT_BORDERS) {
1008 		tty_update_mode(tty, tty->mode, NULL);
1009 		screen_redraw_screen(c, 0, 0, 1);
1010 	}
1011 
1012 	if (c->flags & CLIENT_STATUS) {
1013 		tty_update_mode(tty, tty->mode, NULL);
1014 		screen_redraw_screen(c, 0, 1, 0);
1015 	}
1016 
1017 	tty->flags = (tty->flags & ~(TTY_FREEZE|TTY_NOCURSOR)) | flags;
1018 	tty_update_mode(tty, tty->mode, NULL);
1019 
1020 	c->flags &= ~(CLIENT_REDRAW|CLIENT_BORDERS|CLIENT_STATUS|
1021 	    CLIENT_STATUSFORCE);
1022 }
1023 
1024 /* Set client title. */
1025 void
server_client_set_title(struct client * c)1026 server_client_set_title(struct client *c)
1027 {
1028 	struct session		*s = c->session;
1029 	const char		*template;
1030 	char			*title;
1031 	struct format_tree	*ft;
1032 
1033 	template = options_get_string(s->options, "set-titles-string");
1034 
1035 	ft = format_create(NULL, 0);
1036 	format_defaults(ft, c, NULL, NULL, NULL);
1037 
1038 	title = format_expand_time(ft, template, time(NULL));
1039 	if (c->title == NULL || strcmp(title, c->title) != 0) {
1040 		free(c->title);
1041 		c->title = xstrdup(title);
1042 		tty_set_title(&c->tty, c->title);
1043 	}
1044 	free(title);
1045 
1046 	format_free(ft);
1047 }
1048 
1049 /* Dispatch message from client. */
1050 void
server_client_dispatch(struct imsg * imsg,void * arg)1051 server_client_dispatch(struct imsg *imsg, void *arg)
1052 {
1053 	struct client		*c = arg;
1054 	struct msg_stdin_data	 stdindata;
1055 	const char		*data;
1056 	ssize_t			 datalen;
1057 	struct session		*s;
1058 
1059 	if (c->flags & CLIENT_DEAD)
1060 		return;
1061 
1062 #ifdef TMATE
1063 	if (c->flags & CLIENT_EXIT)
1064 		return;
1065 #endif
1066 
1067 	if (imsg == NULL) {
1068 		server_client_lost(c);
1069 		return;
1070 	}
1071 
1072 	data = imsg->data;
1073 	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1074 
1075 #ifdef TMATE
1076 	switch (imsg->hdr.type) {
1077 	case MSG_IDENTIFY_TMATE_IP_ADDRESS:
1078 	case MSG_IDENTIFY_TMATE_AUTH_NONE:
1079 	case MSG_IDENTIFY_TMATE_AUTH_PUBKEY:
1080 	case MSG_IDENTIFY_TMATE_READONLY:
1081 		server_client_dispatch_identify(c, imsg);
1082 		return;
1083 	}
1084 
1085 	if (!(c->flags & CLIENT_TMATE_AUTHENTICATED)) {
1086 		control_write(c, "Authentication needed");
1087 		tmate_info("Dropping unauthenticated client");
1088 		c->flags |= CLIENT_EXIT;
1089 		return;
1090 	}
1091 #endif
1092 
1093 	switch (imsg->hdr.type) {
1094 	case MSG_IDENTIFY_FLAGS:
1095 	case MSG_IDENTIFY_TERM:
1096 	case MSG_IDENTIFY_TTYNAME:
1097 	case MSG_IDENTIFY_CWD:
1098 	case MSG_IDENTIFY_STDIN:
1099 	case MSG_IDENTIFY_ENVIRON:
1100 	case MSG_IDENTIFY_CLIENTPID:
1101 	case MSG_IDENTIFY_DONE:
1102 		server_client_dispatch_identify(c, imsg);
1103 		return;
1104 	}
1105 
1106 #ifdef TMATE
1107 	if (!(c->flags & CLIENT_IDENTIFIED)) {
1108 		tmate_info("dropping unidentified client message: %d", imsg->hdr.type);
1109 		return;
1110 	}
1111 #endif
1112 
1113 	switch (imsg->hdr.type) {
1114 	case MSG_COMMAND:
1115 		server_client_dispatch_command(c, imsg);
1116 		break;
1117 	case MSG_STDIN:
1118 		if (datalen != sizeof stdindata)
1119 			fatalx("bad MSG_STDIN size");
1120 		memcpy(&stdindata, data, sizeof stdindata);
1121 
1122 		if (c->stdin_callback == NULL)
1123 			break;
1124 		if (stdindata.size <= 0)
1125 			c->stdin_closed = 1;
1126 		else {
1127 			evbuffer_add(c->stdin_data, stdindata.data,
1128 			    stdindata.size);
1129 		}
1130 		c->stdin_callback(c, c->stdin_closed,
1131 		    c->stdin_callback_data);
1132 		break;
1133 	case MSG_RESIZE:
1134 		if (datalen != 0)
1135 			fatalx("bad MSG_RESIZE size");
1136 
1137 		if (c->flags & CLIENT_CONTROL)
1138 			break;
1139 		if (tty_resize(&c->tty)) {
1140 			recalculate_sizes();
1141 			server_redraw_client(c);
1142 		}
1143 		if (c->session != NULL)
1144 			hooks_run(c->session->hooks, c, NULL, "client-resized");
1145 		break;
1146 	case MSG_EXITING:
1147 		if (datalen != 0)
1148 			fatalx("bad MSG_EXITING size");
1149 
1150 		c->session = NULL;
1151 		tty_close(&c->tty);
1152 		proc_send(c->peer, MSG_EXITED, -1, NULL, 0);
1153 		break;
1154 	case MSG_WAKEUP:
1155 	case MSG_UNLOCK:
1156 		if (datalen != 0)
1157 			fatalx("bad MSG_WAKEUP size");
1158 
1159 		if (!(c->flags & CLIENT_SUSPENDED))
1160 			break;
1161 		c->flags &= ~CLIENT_SUSPENDED;
1162 
1163 		if (c->tty.fd == -1) /* exited in the meantime */
1164 			break;
1165 		s = c->session;
1166 
1167 		if (gettimeofday(&c->activity_time, NULL) != 0)
1168 			fatal("gettimeofday failed");
1169 		if (s != NULL)
1170 			session_update_activity(s, &c->activity_time);
1171 
1172 		tty_start_tty(&c->tty);
1173 		server_redraw_client(c);
1174 		recalculate_sizes();
1175 		break;
1176 	case MSG_SHELL:
1177 		if (datalen != 0)
1178 			fatalx("bad MSG_SHELL size");
1179 
1180 		server_client_dispatch_shell(c);
1181 		break;
1182 	}
1183 }
1184 
1185 /* Handle command message. */
1186 void
server_client_dispatch_command(struct client * c,struct imsg * imsg)1187 server_client_dispatch_command(struct client *c, struct imsg *imsg)
1188 {
1189 	struct msg_command_data	  data;
1190 	char			 *buf;
1191 	size_t			  len;
1192 	struct cmd_list		 *cmdlist = NULL;
1193 	int			  argc;
1194 	char			**argv, *cause;
1195 
1196 	if (imsg->hdr.len - IMSG_HEADER_SIZE < sizeof data)
1197 		fatalx("bad MSG_COMMAND size");
1198 	memcpy(&data, imsg->data, sizeof data);
1199 
1200 	buf = (char *)imsg->data + sizeof data;
1201 	len = imsg->hdr.len  - IMSG_HEADER_SIZE - sizeof data;
1202 	if (len > 0 && buf[len - 1] != '\0')
1203 		fatalx("bad MSG_COMMAND string");
1204 
1205 	argc = data.argc;
1206 	if (cmd_unpack_argv(buf, len, argc, &argv) != 0) {
1207 		cmdq_error(c->cmdq, "command too long");
1208 		goto error;
1209 	}
1210 
1211 	if (argc == 0) {
1212 		argc = 1;
1213 		argv = xcalloc(1, sizeof *argv);
1214 		*argv = xstrdup("new-session");
1215 	}
1216 
1217 	if ((cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause)) == NULL) {
1218 		cmdq_error(c->cmdq, "%s", cause);
1219 		cmd_free_argv(argc, argv);
1220 		goto error;
1221 	}
1222 	cmd_free_argv(argc, argv);
1223 
1224 	if (c != cfg_client || cfg_finished)
1225 		cmdq_run(c->cmdq, cmdlist, NULL);
1226 	else
1227 		cmdq_append(c->cmdq, cmdlist, NULL);
1228 	cmd_list_free(cmdlist);
1229 	return;
1230 
1231 error:
1232 	if (cmdlist != NULL)
1233 		cmd_list_free(cmdlist);
1234 
1235 	c->flags |= CLIENT_EXIT;
1236 }
1237 
handle_tmate_auth(struct client * c)1238 static void handle_tmate_auth(struct client *c)
1239 {
1240 	bool allow = tmate_allow_auth(c->pubkey);
1241 	if (allow)
1242 		c->flags |= CLIENT_TMATE_AUTHENTICATED;
1243 
1244 	proc_send(c->peer, MSG_TMATE_AUTH_STATUS, -1, &allow, sizeof(allow));
1245 }
1246 
1247 /* Handle identify message. */
1248 void
server_client_dispatch_identify(struct client * c,struct imsg * imsg)1249 server_client_dispatch_identify(struct client *c, struct imsg *imsg)
1250 {
1251 	const char	*data, *home;
1252 	size_t	 	 datalen;
1253 	int		 flags;
1254 
1255 	if (c->flags & CLIENT_IDENTIFIED)
1256 		fatalx("out-of-order identify message");
1257 
1258 	data = imsg->data;
1259 	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1260 
1261 	switch (imsg->hdr.type)	{
1262 	case MSG_IDENTIFY_FLAGS:
1263 		if (datalen != sizeof flags)
1264 			fatalx("bad MSG_IDENTIFY_FLAGS size");
1265 		memcpy(&flags, data, sizeof flags);
1266 		c->flags |= flags;
1267 		log_debug("client %p IDENTIFY_FLAGS %#x", c, flags);
1268 		break;
1269 	case MSG_IDENTIFY_TERM:
1270 		if (datalen == 0 || data[datalen - 1] != '\0')
1271 			fatalx("bad MSG_IDENTIFY_TERM string");
1272 		c->term = xstrdup(data);
1273 		log_debug("client %p IDENTIFY_TERM %s", c, data);
1274 		break;
1275 	case MSG_IDENTIFY_TTYNAME:
1276 		if (datalen == 0 || data[datalen - 1] != '\0')
1277 			fatalx("bad MSG_IDENTIFY_TTYNAME string");
1278 		c->ttyname = xstrdup(data);
1279 		log_debug("client %p IDENTIFY_TTYNAME %s", c, data);
1280 		break;
1281 	case MSG_IDENTIFY_CWD:
1282 		if (datalen == 0 || data[datalen - 1] != '\0')
1283 			fatalx("bad MSG_IDENTIFY_CWD string");
1284 		if (access(data, X_OK) == 0)
1285 			c->cwd = xstrdup(data);
1286 		else if ((home = find_home()) != NULL)
1287 			c->cwd = xstrdup(home);
1288 		else
1289 			c->cwd = xstrdup("/");
1290 		log_debug("client %p IDENTIFY_CWD %s", c, data);
1291 		break;
1292 	case MSG_IDENTIFY_STDIN:
1293 		if (datalen != 0)
1294 			fatalx("bad MSG_IDENTIFY_STDIN size");
1295 		c->fd = imsg->fd;
1296 		log_debug("client %p IDENTIFY_STDIN %d", c, imsg->fd);
1297 		break;
1298 	case MSG_IDENTIFY_ENVIRON:
1299 		if (datalen == 0 || data[datalen - 1] != '\0')
1300 			fatalx("bad MSG_IDENTIFY_ENVIRON string");
1301 		if (strchr(data, '=') != NULL)
1302 			environ_put(c->environ, data);
1303 		log_debug("client %p IDENTIFY_ENVIRON %s", c, data);
1304 		break;
1305 	case MSG_IDENTIFY_CLIENTPID:
1306 		if (datalen != sizeof c->pid)
1307 			fatalx("bad MSG_IDENTIFY_CLIENTPID size");
1308 		memcpy(&c->pid, data, sizeof c->pid);
1309 		log_debug("client %p IDENTIFY_CLIENTPID %ld", c, (long)c->pid);
1310 		break;
1311 #ifdef TMATE
1312 	case MSG_IDENTIFY_TMATE_IP_ADDRESS:
1313 		if (datalen == 0 || data[datalen - 1] != '\0')
1314 			fatalx("bad MSG_IDENTIFY_TMATE_IP_ADDRESS string");
1315 		c->ip_address = xstrdup(data);
1316 		break;
1317 
1318 	case MSG_IDENTIFY_TMATE_AUTH_NONE:
1319 		assert(!c->pubkey);
1320 		handle_tmate_auth(c);
1321 		break;
1322 
1323 	case MSG_IDENTIFY_TMATE_AUTH_PUBKEY:
1324 		if (datalen == 0 || data[datalen - 1] != '\0')
1325 			fatalx("bad MSG_IDENTIFY_TMATE_PUBKEY string");
1326 		c->pubkey = xstrdup(data);
1327 		handle_tmate_auth(c);
1328 		break;
1329 
1330 	case MSG_IDENTIFY_TMATE_READONLY:
1331 		if (datalen != 1)
1332 			fatalx("bad MSG_IDENTIFY_TMATE_READONLY size");
1333 		c->readonly = *(bool*)data;
1334 		break;
1335 #endif
1336 	default:
1337 		break;
1338 	}
1339 
1340 	if (imsg->hdr.type != MSG_IDENTIFY_DONE)
1341 		return;
1342 	c->flags |= CLIENT_IDENTIFIED;
1343 
1344 #ifdef __CYGWIN__
1345 	c->fd = open(c->ttyname, O_RDWR|O_NOCTTY);
1346 #endif
1347 
1348 	if (c->flags & CLIENT_CONTROL) {
1349 		c->stdin_callback = control_callback;
1350 
1351 		evbuffer_free(c->stderr_data);
1352 		c->stderr_data = c->stdout_data;
1353 
1354 		if (c->flags & CLIENT_CONTROLCONTROL)
1355 			evbuffer_add_printf(c->stdout_data, "\033P1000p");
1356 		proc_send(c->peer, MSG_STDIN, -1, NULL, 0);
1357 
1358 		c->tty.fd = -1;
1359 
1360 		close(c->fd);
1361 		c->fd = -1;
1362 
1363 		return;
1364 	}
1365 
1366 	if (c->fd == -1)
1367 		return;
1368 	if (tty_init(&c->tty, c, c->fd, c->term) != 0) {
1369 		close(c->fd);
1370 		c->fd = -1;
1371 		return;
1372 	}
1373 	if (c->flags & CLIENT_UTF8)
1374 		c->tty.flags |= TTY_UTF8;
1375 	if (c->flags & CLIENT_256COLOURS)
1376 		c->tty.term_flags |= TERM_256COLOURS;
1377 
1378 	tty_resize(&c->tty);
1379 
1380 	if (!(c->flags & CLIENT_CONTROL))
1381 		c->flags |= CLIENT_TERMINAL;
1382 
1383 #ifdef TMATE
1384 	tmate_notify_client_join(tmate_session, c);
1385 #endif
1386 }
1387 
1388 /* Handle shell message. */
1389 void
server_client_dispatch_shell(struct client * c)1390 server_client_dispatch_shell(struct client *c)
1391 {
1392 	const char	*shell;
1393 
1394 	shell = options_get_string(global_s_options, "default-shell");
1395 	if (*shell == '\0' || areshell(shell))
1396 		shell = _PATH_BSHELL;
1397 	proc_send_s(c->peer, MSG_SHELL, shell);
1398 
1399 	proc_kill_peer(c->peer);
1400 }
1401 
1402 /* Event callback to push more stdout data if any left. */
1403 static void
server_client_stdout_cb(__unused int fd,__unused short events,void * arg)1404 server_client_stdout_cb(__unused int fd, __unused short events, void *arg)
1405 {
1406 	struct client	*c = arg;
1407 
1408 	if (~c->flags & CLIENT_DEAD)
1409 		server_client_push_stdout(c);
1410 	server_client_unref(c);
1411 }
1412 
1413 /* Push stdout to client if possible. */
1414 void
server_client_push_stdout(struct client * c)1415 server_client_push_stdout(struct client *c)
1416 {
1417 	struct msg_stdout_data data;
1418 	size_t                 sent, left;
1419 
1420 	if (!(c->flags & CLIENT_TMATE_AUTHENTICATED))
1421 		return;
1422 
1423 	left = EVBUFFER_LENGTH(c->stdout_data);
1424 	while (left != 0) {
1425 		sent = left;
1426 		if (sent > sizeof data.data)
1427 			sent = sizeof data.data;
1428 		memcpy(data.data, EVBUFFER_DATA(c->stdout_data), sent);
1429 		data.size = sent;
1430 
1431 		if (proc_send(c->peer, MSG_STDOUT, -1, &data, sizeof data) != 0)
1432 			break;
1433 		evbuffer_drain(c->stdout_data, sent);
1434 
1435 		left = EVBUFFER_LENGTH(c->stdout_data);
1436 		log_debug("%s: client %p, sent %zu, left %zu", __func__, c,
1437 		    sent, left);
1438 	}
1439 	if (left != 0) {
1440 		c->references++;
1441 		event_once(-1, EV_TIMEOUT, server_client_stdout_cb, c, NULL);
1442 		log_debug("%s: client %p, queued", __func__, c);
1443 	}
1444 }
1445 
1446 /* Event callback to push more stderr data if any left. */
1447 static void
server_client_stderr_cb(__unused int fd,__unused short events,void * arg)1448 server_client_stderr_cb(__unused int fd, __unused short events, void *arg)
1449 {
1450 	struct client	*c = arg;
1451 
1452 	if (~c->flags & CLIENT_DEAD)
1453 		server_client_push_stderr(c);
1454 	server_client_unref(c);
1455 }
1456 
1457 /* Push stderr to client if possible. */
1458 void
server_client_push_stderr(struct client * c)1459 server_client_push_stderr(struct client *c)
1460 {
1461 	struct msg_stderr_data data;
1462 	size_t                 sent, left;
1463 
1464 	if (!(c->flags & CLIENT_TMATE_AUTHENTICATED))
1465 		return;
1466 
1467 	if (c->stderr_data == c->stdout_data) {
1468 		server_client_push_stdout(c);
1469 		return;
1470 	}
1471 
1472 	left = EVBUFFER_LENGTH(c->stderr_data);
1473 	while (left != 0) {
1474 		sent = left;
1475 		if (sent > sizeof data.data)
1476 			sent = sizeof data.data;
1477 		memcpy(data.data, EVBUFFER_DATA(c->stderr_data), sent);
1478 		data.size = sent;
1479 
1480 		if (proc_send(c->peer, MSG_STDERR, -1, &data, sizeof data) != 0)
1481 			break;
1482 		evbuffer_drain(c->stderr_data, sent);
1483 
1484 		left = EVBUFFER_LENGTH(c->stderr_data);
1485 		log_debug("%s: client %p, sent %zu, left %zu", __func__, c,
1486 		    sent, left);
1487 	}
1488 	if (left != 0) {
1489 		c->references++;
1490 		event_once(-1, EV_TIMEOUT, server_client_stderr_cb, c, NULL);
1491 		log_debug("%s: client %p, queued", __func__, c);
1492 	}
1493 }
1494