xref: /minix3/external/bsd/tmux/dist/server-client.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /* Id */
2eda6f593SDavid van Moolenbroek 
3eda6f593SDavid van Moolenbroek /*
4eda6f593SDavid van Moolenbroek  * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
5eda6f593SDavid van Moolenbroek  *
6eda6f593SDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
7eda6f593SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
8eda6f593SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
9eda6f593SDavid van Moolenbroek  *
10eda6f593SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11eda6f593SDavid van Moolenbroek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12eda6f593SDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13eda6f593SDavid van Moolenbroek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14eda6f593SDavid van Moolenbroek  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15eda6f593SDavid van Moolenbroek  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16eda6f593SDavid van Moolenbroek  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17eda6f593SDavid van Moolenbroek  */
18eda6f593SDavid van Moolenbroek 
19eda6f593SDavid van Moolenbroek #include <sys/types.h>
20*0a6a1f1dSLionel Sambuc #include <sys/ioctl.h>
21eda6f593SDavid van Moolenbroek 
22*0a6a1f1dSLionel Sambuc #include <errno.h>
23eda6f593SDavid van Moolenbroek #include <event.h>
24eda6f593SDavid van Moolenbroek #include <fcntl.h>
25*0a6a1f1dSLionel Sambuc #include <stdlib.h>
26eda6f593SDavid van Moolenbroek #include <string.h>
27eda6f593SDavid van Moolenbroek #include <time.h>
28eda6f593SDavid van Moolenbroek #include <unistd.h>
29eda6f593SDavid van Moolenbroek 
30eda6f593SDavid van Moolenbroek #include "tmux.h"
31eda6f593SDavid van Moolenbroek 
32*0a6a1f1dSLionel Sambuc void	server_client_check_focus(struct window_pane *);
33*0a6a1f1dSLionel Sambuc void	server_client_check_resize(struct window_pane *);
34*0a6a1f1dSLionel Sambuc void	server_client_check_mouse(struct client *, struct window_pane *);
35eda6f593SDavid van Moolenbroek void	server_client_repeat_timer(int, short, void *);
36eda6f593SDavid van Moolenbroek void	server_client_check_exit(struct client *);
37eda6f593SDavid van Moolenbroek void	server_client_check_redraw(struct client *);
38eda6f593SDavid van Moolenbroek void	server_client_set_title(struct client *);
39eda6f593SDavid van Moolenbroek void	server_client_reset_state(struct client *);
40*0a6a1f1dSLionel Sambuc int	server_client_assume_paste(struct session *);
41eda6f593SDavid van Moolenbroek 
42eda6f593SDavid van Moolenbroek int	server_client_msg_dispatch(struct client *);
43*0a6a1f1dSLionel Sambuc void	server_client_msg_command(struct client *, struct imsg *);
44*0a6a1f1dSLionel Sambuc void	server_client_msg_identify(struct client *, struct imsg *);
45eda6f593SDavid van Moolenbroek void	server_client_msg_shell(struct client *);
46eda6f593SDavid van Moolenbroek 
47eda6f593SDavid van Moolenbroek /* Create a new client. */
48eda6f593SDavid van Moolenbroek void
server_client_create(int fd)49eda6f593SDavid van Moolenbroek server_client_create(int fd)
50eda6f593SDavid van Moolenbroek {
51eda6f593SDavid van Moolenbroek 	struct client	*c;
52eda6f593SDavid van Moolenbroek 	u_int		 i;
53eda6f593SDavid van Moolenbroek 
54eda6f593SDavid van Moolenbroek 	setblocking(fd, 0);
55eda6f593SDavid van Moolenbroek 
56eda6f593SDavid van Moolenbroek 	c = xcalloc(1, sizeof *c);
57eda6f593SDavid van Moolenbroek 	c->references = 0;
58eda6f593SDavid van Moolenbroek 	imsg_init(&c->ibuf, fd);
59eda6f593SDavid van Moolenbroek 	server_update_event(c);
60eda6f593SDavid van Moolenbroek 
61eda6f593SDavid van Moolenbroek 	if (gettimeofday(&c->creation_time, NULL) != 0)
62eda6f593SDavid van Moolenbroek 		fatal("gettimeofday failed");
63eda6f593SDavid van Moolenbroek 	memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
64eda6f593SDavid van Moolenbroek 
65*0a6a1f1dSLionel Sambuc 	environ_init(&c->environ);
66*0a6a1f1dSLionel Sambuc 
67*0a6a1f1dSLionel Sambuc 	c->cmdq = cmdq_new(c);
68*0a6a1f1dSLionel Sambuc 	c->cmdq->client_exit = 1;
69*0a6a1f1dSLionel Sambuc 
70*0a6a1f1dSLionel Sambuc 	c->stdin_data = evbuffer_new();
71*0a6a1f1dSLionel Sambuc 	c->stdout_data = evbuffer_new();
72*0a6a1f1dSLionel Sambuc 	c->stderr_data = evbuffer_new();
73eda6f593SDavid van Moolenbroek 
74eda6f593SDavid van Moolenbroek 	c->tty.fd = -1;
75eda6f593SDavid van Moolenbroek 	c->title = NULL;
76eda6f593SDavid van Moolenbroek 
77eda6f593SDavid van Moolenbroek 	c->session = NULL;
78eda6f593SDavid van Moolenbroek 	c->last_session = NULL;
79eda6f593SDavid van Moolenbroek 	c->tty.sx = 80;
80eda6f593SDavid van Moolenbroek 	c->tty.sy = 24;
81eda6f593SDavid van Moolenbroek 
82eda6f593SDavid van Moolenbroek 	screen_init(&c->status, c->tty.sx, 1, 0);
83eda6f593SDavid van Moolenbroek 	RB_INIT(&c->status_new);
84eda6f593SDavid van Moolenbroek 	RB_INIT(&c->status_old);
85eda6f593SDavid van Moolenbroek 
86eda6f593SDavid van Moolenbroek 	c->message_string = NULL;
87eda6f593SDavid van Moolenbroek 	ARRAY_INIT(&c->message_log);
88eda6f593SDavid van Moolenbroek 
89eda6f593SDavid van Moolenbroek 	c->prompt_string = NULL;
90eda6f593SDavid van Moolenbroek 	c->prompt_buffer = NULL;
91eda6f593SDavid van Moolenbroek 	c->prompt_index = 0;
92eda6f593SDavid van Moolenbroek 
93*0a6a1f1dSLionel Sambuc 	c->tty.mouse.xb = c->tty.mouse.button = 3;
94*0a6a1f1dSLionel Sambuc 	c->tty.mouse.x = c->tty.mouse.y = -1;
95*0a6a1f1dSLionel Sambuc 	c->tty.mouse.lx = c->tty.mouse.ly = -1;
96*0a6a1f1dSLionel Sambuc 	c->tty.mouse.sx = c->tty.mouse.sy = -1;
97*0a6a1f1dSLionel Sambuc 	c->tty.mouse.event = MOUSE_EVENT_UP;
98*0a6a1f1dSLionel Sambuc 	c->tty.mouse.flags = 0;
99*0a6a1f1dSLionel Sambuc 
100*0a6a1f1dSLionel Sambuc 	c->flags |= CLIENT_FOCUSED;
101eda6f593SDavid van Moolenbroek 
102eda6f593SDavid van Moolenbroek 	evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
103eda6f593SDavid van Moolenbroek 
104eda6f593SDavid van Moolenbroek 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
105eda6f593SDavid van Moolenbroek 		if (ARRAY_ITEM(&clients, i) == NULL) {
106eda6f593SDavid van Moolenbroek 			ARRAY_SET(&clients, i, c);
107eda6f593SDavid van Moolenbroek 			return;
108eda6f593SDavid van Moolenbroek 		}
109eda6f593SDavid van Moolenbroek 	}
110eda6f593SDavid van Moolenbroek 	ARRAY_ADD(&clients, c);
111eda6f593SDavid van Moolenbroek 	log_debug("new client %d", fd);
112eda6f593SDavid van Moolenbroek }
113eda6f593SDavid van Moolenbroek 
114*0a6a1f1dSLionel Sambuc /* Open client terminal if needed. */
115*0a6a1f1dSLionel Sambuc int
server_client_open(struct client * c,struct session * s,char ** cause)116*0a6a1f1dSLionel Sambuc server_client_open(struct client *c, struct session *s, char **cause)
117*0a6a1f1dSLionel Sambuc {
118*0a6a1f1dSLionel Sambuc 	struct options	*oo = s != NULL ? &s->options : &global_s_options;
119*0a6a1f1dSLionel Sambuc 	char		*overrides;
120*0a6a1f1dSLionel Sambuc 
121*0a6a1f1dSLionel Sambuc 	if (c->flags & CLIENT_CONTROL)
122*0a6a1f1dSLionel Sambuc 		return (0);
123*0a6a1f1dSLionel Sambuc 
124*0a6a1f1dSLionel Sambuc 	if (!(c->flags & CLIENT_TERMINAL)) {
125*0a6a1f1dSLionel Sambuc 		*cause = xstrdup("not a terminal");
126*0a6a1f1dSLionel Sambuc 		return (-1);
127*0a6a1f1dSLionel Sambuc 	}
128*0a6a1f1dSLionel Sambuc 
129*0a6a1f1dSLionel Sambuc 	overrides = options_get_string(oo, "terminal-overrides");
130*0a6a1f1dSLionel Sambuc 	if (tty_open(&c->tty, overrides, cause) != 0)
131*0a6a1f1dSLionel Sambuc 		return (-1);
132*0a6a1f1dSLionel Sambuc 
133*0a6a1f1dSLionel Sambuc 	return (0);
134*0a6a1f1dSLionel Sambuc }
135*0a6a1f1dSLionel Sambuc 
136eda6f593SDavid van Moolenbroek /* Lost a client. */
137eda6f593SDavid van Moolenbroek void
server_client_lost(struct client * c)138eda6f593SDavid van Moolenbroek server_client_lost(struct client *c)
139eda6f593SDavid van Moolenbroek {
140eda6f593SDavid van Moolenbroek 	struct message_entry	*msg;
141eda6f593SDavid van Moolenbroek 	u_int			 i;
142eda6f593SDavid van Moolenbroek 
143eda6f593SDavid van Moolenbroek 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
144eda6f593SDavid van Moolenbroek 		if (ARRAY_ITEM(&clients, i) == c)
145eda6f593SDavid van Moolenbroek 			ARRAY_SET(&clients, i, NULL);
146eda6f593SDavid van Moolenbroek 	}
147eda6f593SDavid van Moolenbroek 	log_debug("lost client %d", c->ibuf.fd);
148eda6f593SDavid van Moolenbroek 
149eda6f593SDavid van Moolenbroek 	/*
150eda6f593SDavid van Moolenbroek 	 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
151eda6f593SDavid van Moolenbroek 	 * and tty_free might close an unrelated fd.
152eda6f593SDavid van Moolenbroek 	 */
153eda6f593SDavid van Moolenbroek 	if (c->flags & CLIENT_TERMINAL)
154eda6f593SDavid van Moolenbroek 		tty_free(&c->tty);
155*0a6a1f1dSLionel Sambuc 	free(c->ttyname);
156*0a6a1f1dSLionel Sambuc 	free(c->term);
157eda6f593SDavid van Moolenbroek 
158*0a6a1f1dSLionel Sambuc 	evbuffer_free(c->stdin_data);
159*0a6a1f1dSLionel Sambuc 	evbuffer_free(c->stdout_data);
160*0a6a1f1dSLionel Sambuc 	if (c->stderr_data != c->stdout_data)
161*0a6a1f1dSLionel Sambuc 		evbuffer_free (c->stderr_data);
162eda6f593SDavid van Moolenbroek 
163eda6f593SDavid van Moolenbroek 	status_free_jobs(&c->status_new);
164eda6f593SDavid van Moolenbroek 	status_free_jobs(&c->status_old);
165eda6f593SDavid van Moolenbroek 	screen_free(&c->status);
166eda6f593SDavid van Moolenbroek 
167*0a6a1f1dSLionel Sambuc 	free(c->title);
168*0a6a1f1dSLionel Sambuc 	close(c->cwd);
169eda6f593SDavid van Moolenbroek 
170eda6f593SDavid van Moolenbroek 	evtimer_del(&c->repeat_timer);
171eda6f593SDavid van Moolenbroek 
172*0a6a1f1dSLionel Sambuc 	if (event_initialized(&c->identify_timer))
173eda6f593SDavid van Moolenbroek 		evtimer_del(&c->identify_timer);
174eda6f593SDavid van Moolenbroek 
175*0a6a1f1dSLionel Sambuc 	free(c->message_string);
176*0a6a1f1dSLionel Sambuc 	if (event_initialized(&c->message_timer))
177eda6f593SDavid van Moolenbroek 		evtimer_del(&c->message_timer);
178eda6f593SDavid van Moolenbroek 	for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) {
179eda6f593SDavid van Moolenbroek 		msg = &ARRAY_ITEM(&c->message_log, i);
180*0a6a1f1dSLionel Sambuc 		free(msg->msg);
181eda6f593SDavid van Moolenbroek 	}
182eda6f593SDavid van Moolenbroek 	ARRAY_FREE(&c->message_log);
183eda6f593SDavid van Moolenbroek 
184*0a6a1f1dSLionel Sambuc 	free(c->prompt_string);
185*0a6a1f1dSLionel Sambuc 	free(c->prompt_buffer);
186eda6f593SDavid van Moolenbroek 
187*0a6a1f1dSLionel Sambuc 	c->cmdq->dead = 1;
188*0a6a1f1dSLionel Sambuc 	cmdq_free(c->cmdq);
189*0a6a1f1dSLionel Sambuc 	c->cmdq = NULL;
190*0a6a1f1dSLionel Sambuc 
191*0a6a1f1dSLionel Sambuc 	environ_free(&c->environ);
192eda6f593SDavid van Moolenbroek 
193eda6f593SDavid van Moolenbroek 	close(c->ibuf.fd);
194eda6f593SDavid van Moolenbroek 	imsg_clear(&c->ibuf);
195*0a6a1f1dSLionel Sambuc 	if (event_initialized(&c->event))
196eda6f593SDavid van Moolenbroek 		event_del(&c->event);
197eda6f593SDavid van Moolenbroek 
198eda6f593SDavid van Moolenbroek 	for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
199eda6f593SDavid van Moolenbroek 		if (ARRAY_ITEM(&dead_clients, i) == NULL) {
200eda6f593SDavid van Moolenbroek 			ARRAY_SET(&dead_clients, i, c);
201eda6f593SDavid van Moolenbroek 			break;
202eda6f593SDavid van Moolenbroek 		}
203eda6f593SDavid van Moolenbroek 	}
204eda6f593SDavid van Moolenbroek 	if (i == ARRAY_LENGTH(&dead_clients))
205eda6f593SDavid van Moolenbroek 		ARRAY_ADD(&dead_clients, c);
206eda6f593SDavid van Moolenbroek 	c->flags |= CLIENT_DEAD;
207eda6f593SDavid van Moolenbroek 
208*0a6a1f1dSLionel Sambuc 	server_add_accept(0); /* may be more file descriptors now */
209*0a6a1f1dSLionel Sambuc 
210eda6f593SDavid van Moolenbroek 	recalculate_sizes();
211eda6f593SDavid van Moolenbroek 	server_check_unattached();
212eda6f593SDavid van Moolenbroek 	server_update_socket();
213eda6f593SDavid van Moolenbroek }
214eda6f593SDavid van Moolenbroek 
215eda6f593SDavid van Moolenbroek /* Process a single client event. */
216eda6f593SDavid van Moolenbroek void
server_client_callback(int fd,short events,void * data)217eda6f593SDavid van Moolenbroek server_client_callback(int fd, short events, void *data)
218eda6f593SDavid van Moolenbroek {
219eda6f593SDavid van Moolenbroek 	struct client	*c = data;
220eda6f593SDavid van Moolenbroek 
221eda6f593SDavid van Moolenbroek 	if (c->flags & CLIENT_DEAD)
222eda6f593SDavid van Moolenbroek 		return;
223eda6f593SDavid van Moolenbroek 
224eda6f593SDavid van Moolenbroek 	if (fd == c->ibuf.fd) {
225*0a6a1f1dSLionel Sambuc 		if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) < 0 &&
226*0a6a1f1dSLionel Sambuc 		    errno != EAGAIN)
227eda6f593SDavid van Moolenbroek 			goto client_lost;
228eda6f593SDavid van Moolenbroek 
229eda6f593SDavid van Moolenbroek 		if (c->flags & CLIENT_BAD) {
230eda6f593SDavid van Moolenbroek 			if (c->ibuf.w.queued == 0)
231eda6f593SDavid van Moolenbroek 				goto client_lost;
232eda6f593SDavid van Moolenbroek 			return;
233eda6f593SDavid van Moolenbroek 		}
234eda6f593SDavid van Moolenbroek 
235eda6f593SDavid van Moolenbroek 		if (events & EV_READ && server_client_msg_dispatch(c) != 0)
236eda6f593SDavid van Moolenbroek 			goto client_lost;
237eda6f593SDavid van Moolenbroek 	}
238eda6f593SDavid van Moolenbroek 
239*0a6a1f1dSLionel Sambuc 	server_push_stdout(c);
240*0a6a1f1dSLionel Sambuc 	server_push_stderr(c);
241*0a6a1f1dSLionel Sambuc 
242eda6f593SDavid van Moolenbroek 	server_update_event(c);
243eda6f593SDavid van Moolenbroek 	return;
244eda6f593SDavid van Moolenbroek 
245eda6f593SDavid van Moolenbroek client_lost:
246eda6f593SDavid van Moolenbroek 	server_client_lost(c);
247eda6f593SDavid van Moolenbroek }
248eda6f593SDavid van Moolenbroek 
249eda6f593SDavid van Moolenbroek /* Handle client status timer. */
250eda6f593SDavid van Moolenbroek void
server_client_status_timer(void)251eda6f593SDavid van Moolenbroek server_client_status_timer(void)
252eda6f593SDavid van Moolenbroek {
253eda6f593SDavid van Moolenbroek 	struct client	*c;
254eda6f593SDavid van Moolenbroek 	struct session	*s;
255eda6f593SDavid van Moolenbroek 	struct timeval	 tv;
256eda6f593SDavid van Moolenbroek 	u_int		 i;
257eda6f593SDavid van Moolenbroek 	int		 interval;
258eda6f593SDavid van Moolenbroek 	time_t		 difference;
259eda6f593SDavid van Moolenbroek 
260eda6f593SDavid van Moolenbroek 	if (gettimeofday(&tv, NULL) != 0)
261eda6f593SDavid van Moolenbroek 		fatal("gettimeofday failed");
262eda6f593SDavid van Moolenbroek 
263eda6f593SDavid van Moolenbroek 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
264eda6f593SDavid van Moolenbroek 		c = ARRAY_ITEM(&clients, i);
265eda6f593SDavid van Moolenbroek 		if (c == NULL || c->session == NULL)
266eda6f593SDavid van Moolenbroek 			continue;
267eda6f593SDavid van Moolenbroek 		if (c->message_string != NULL || c->prompt_string != NULL) {
268eda6f593SDavid van Moolenbroek 			/*
269eda6f593SDavid van Moolenbroek 			 * Don't need timed redraw for messages/prompts so bail
270eda6f593SDavid van Moolenbroek 			 * now. The status timer isn't reset when they are
271eda6f593SDavid van Moolenbroek 			 * redrawn anyway.
272eda6f593SDavid van Moolenbroek 			 */
273eda6f593SDavid van Moolenbroek 			continue;
274eda6f593SDavid van Moolenbroek 		}
275eda6f593SDavid van Moolenbroek 		s = c->session;
276eda6f593SDavid van Moolenbroek 
277eda6f593SDavid van Moolenbroek 		if (!options_get_number(&s->options, "status"))
278eda6f593SDavid van Moolenbroek 			continue;
279eda6f593SDavid van Moolenbroek 		interval = options_get_number(&s->options, "status-interval");
280eda6f593SDavid van Moolenbroek 
281eda6f593SDavid van Moolenbroek 		difference = tv.tv_sec - c->status_timer.tv_sec;
282*0a6a1f1dSLionel Sambuc 		if (interval != 0 && difference >= interval) {
283eda6f593SDavid van Moolenbroek 			status_update_jobs(c);
284eda6f593SDavid van Moolenbroek 			c->flags |= CLIENT_STATUS;
285eda6f593SDavid van Moolenbroek 		}
286eda6f593SDavid van Moolenbroek 	}
287eda6f593SDavid van Moolenbroek }
288eda6f593SDavid van Moolenbroek 
289*0a6a1f1dSLionel Sambuc /* Check for mouse keys. */
290*0a6a1f1dSLionel Sambuc void
server_client_check_mouse(struct client * c,struct window_pane * wp)291*0a6a1f1dSLionel Sambuc server_client_check_mouse(struct client *c, struct window_pane *wp)
292*0a6a1f1dSLionel Sambuc {
293*0a6a1f1dSLionel Sambuc 	struct session		*s = c->session;
294*0a6a1f1dSLionel Sambuc 	struct options		*oo = &s->options;
295*0a6a1f1dSLionel Sambuc 	struct mouse_event	*m = &c->tty.mouse;
296*0a6a1f1dSLionel Sambuc 	int			 statusat;
297*0a6a1f1dSLionel Sambuc 
298*0a6a1f1dSLionel Sambuc 	statusat = status_at_line(c);
299*0a6a1f1dSLionel Sambuc 
300*0a6a1f1dSLionel Sambuc 	/* Is this a window selection click on the status line? */
301*0a6a1f1dSLionel Sambuc 	if (statusat != -1 && m->y == (u_int)statusat &&
302*0a6a1f1dSLionel Sambuc 	    options_get_number(oo, "mouse-select-window")) {
303*0a6a1f1dSLionel Sambuc 		if (m->event & MOUSE_EVENT_CLICK) {
304*0a6a1f1dSLionel Sambuc 			status_set_window_at(c, m->x);
305*0a6a1f1dSLionel Sambuc 		} else if (m->event == MOUSE_EVENT_WHEEL) {
306*0a6a1f1dSLionel Sambuc 			if (m->wheel == MOUSE_WHEEL_UP)
307*0a6a1f1dSLionel Sambuc 				session_previous(c->session, 0);
308*0a6a1f1dSLionel Sambuc 			else if (m->wheel == MOUSE_WHEEL_DOWN)
309*0a6a1f1dSLionel Sambuc 				session_next(c->session, 0);
310*0a6a1f1dSLionel Sambuc 			server_redraw_session(s);
311*0a6a1f1dSLionel Sambuc 		}
312*0a6a1f1dSLionel Sambuc 		recalculate_sizes();
313*0a6a1f1dSLionel Sambuc 		return;
314*0a6a1f1dSLionel Sambuc 	}
315*0a6a1f1dSLionel Sambuc 
316*0a6a1f1dSLionel Sambuc 	/*
317*0a6a1f1dSLionel Sambuc 	 * Not on status line - adjust mouse position if status line is at the
318*0a6a1f1dSLionel Sambuc 	 * top and limit if at the bottom. From here on a struct mouse
319*0a6a1f1dSLionel Sambuc 	 * represents the offset onto the window itself.
320*0a6a1f1dSLionel Sambuc 	 */
321*0a6a1f1dSLionel Sambuc 	if (statusat == 0 && m->y > 0)
322*0a6a1f1dSLionel Sambuc 		m->y--;
323*0a6a1f1dSLionel Sambuc 	else if (statusat > 0 && m->y >= (u_int)statusat)
324*0a6a1f1dSLionel Sambuc 		m->y = statusat - 1;
325*0a6a1f1dSLionel Sambuc 
326*0a6a1f1dSLionel Sambuc 	/* Is this a pane selection? */
327*0a6a1f1dSLionel Sambuc 	if (options_get_number(oo, "mouse-select-pane") &&
328*0a6a1f1dSLionel Sambuc 	    (m->event == MOUSE_EVENT_DOWN || m->event == MOUSE_EVENT_WHEEL)) {
329*0a6a1f1dSLionel Sambuc 		window_set_active_at(wp->window, m->x, m->y);
330*0a6a1f1dSLionel Sambuc 		server_redraw_window_borders(wp->window);
331*0a6a1f1dSLionel Sambuc 		wp = wp->window->active; /* may have changed */
332*0a6a1f1dSLionel Sambuc 	}
333*0a6a1f1dSLionel Sambuc 
334*0a6a1f1dSLionel Sambuc 	/* Check if trying to resize pane. */
335*0a6a1f1dSLionel Sambuc 	if (options_get_number(oo, "mouse-resize-pane"))
336*0a6a1f1dSLionel Sambuc 		layout_resize_pane_mouse(c);
337*0a6a1f1dSLionel Sambuc 
338*0a6a1f1dSLionel Sambuc 	/* Update last and pass through to client. */
339*0a6a1f1dSLionel Sambuc 	window_pane_mouse(wp, c->session, m);
340*0a6a1f1dSLionel Sambuc }
341*0a6a1f1dSLionel Sambuc 
342*0a6a1f1dSLionel Sambuc /* Is this fast enough to probably be a paste? */
343*0a6a1f1dSLionel Sambuc int
server_client_assume_paste(struct session * s)344*0a6a1f1dSLionel Sambuc server_client_assume_paste(struct session *s)
345*0a6a1f1dSLionel Sambuc {
346*0a6a1f1dSLionel Sambuc 	struct timeval	tv;
347*0a6a1f1dSLionel Sambuc 	int		t;
348*0a6a1f1dSLionel Sambuc 
349*0a6a1f1dSLionel Sambuc 	if ((t = options_get_number(&s->options, "assume-paste-time")) == 0)
350*0a6a1f1dSLionel Sambuc 		return (0);
351*0a6a1f1dSLionel Sambuc 
352*0a6a1f1dSLionel Sambuc 	timersub(&s->activity_time, &s->last_activity_time, &tv);
353*0a6a1f1dSLionel Sambuc 	if (tv.tv_sec == 0 && tv.tv_usec < t * 1000)
354*0a6a1f1dSLionel Sambuc 		return (1);
355*0a6a1f1dSLionel Sambuc 	return (0);
356*0a6a1f1dSLionel Sambuc }
357*0a6a1f1dSLionel Sambuc 
358eda6f593SDavid van Moolenbroek /* Handle data key input from client. */
359eda6f593SDavid van Moolenbroek void
server_client_handle_key(struct client * c,int key)360*0a6a1f1dSLionel Sambuc server_client_handle_key(struct client *c, int key)
361eda6f593SDavid van Moolenbroek {
362eda6f593SDavid van Moolenbroek 	struct session		*s;
363eda6f593SDavid van Moolenbroek 	struct window		*w;
364eda6f593SDavid van Moolenbroek 	struct window_pane	*wp;
365eda6f593SDavid van Moolenbroek 	struct timeval		 tv;
366eda6f593SDavid van Moolenbroek 	struct key_binding	*bd;
367*0a6a1f1dSLionel Sambuc 	int		      	 xtimeout, isprefix, ispaste;
368eda6f593SDavid van Moolenbroek 
369eda6f593SDavid van Moolenbroek 	/* Check the client is good to accept input. */
370eda6f593SDavid van Moolenbroek 	if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
371eda6f593SDavid van Moolenbroek 		return;
372*0a6a1f1dSLionel Sambuc 
373eda6f593SDavid van Moolenbroek 	if (c->session == NULL)
374eda6f593SDavid van Moolenbroek 		return;
375eda6f593SDavid van Moolenbroek 	s = c->session;
376eda6f593SDavid van Moolenbroek 
377eda6f593SDavid van Moolenbroek 	/* Update the activity timer. */
378eda6f593SDavid van Moolenbroek 	if (gettimeofday(&c->activity_time, NULL) != 0)
379eda6f593SDavid van Moolenbroek 		fatal("gettimeofday failed");
380*0a6a1f1dSLionel Sambuc 
381*0a6a1f1dSLionel Sambuc 	memcpy(&s->last_activity_time, &s->activity_time,
382*0a6a1f1dSLionel Sambuc 	    sizeof s->last_activity_time);
383eda6f593SDavid van Moolenbroek 	memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time);
384eda6f593SDavid van Moolenbroek 
385eda6f593SDavid van Moolenbroek 	w = c->session->curw->window;
386eda6f593SDavid van Moolenbroek 	wp = w->active;
387eda6f593SDavid van Moolenbroek 
388eda6f593SDavid van Moolenbroek 	/* Special case: number keys jump to pane in identify mode. */
389eda6f593SDavid van Moolenbroek 	if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
390eda6f593SDavid van Moolenbroek 		if (c->flags & CLIENT_READONLY)
391eda6f593SDavid van Moolenbroek 			return;
392*0a6a1f1dSLionel Sambuc 		window_unzoom(w);
393eda6f593SDavid van Moolenbroek 		wp = window_pane_at_index(w, key - '0');
394eda6f593SDavid van Moolenbroek 		if (wp != NULL && window_pane_visible(wp))
395eda6f593SDavid van Moolenbroek 			window_set_active_pane(w, wp);
396eda6f593SDavid van Moolenbroek 		server_clear_identify(c);
397eda6f593SDavid van Moolenbroek 		return;
398eda6f593SDavid van Moolenbroek 	}
399eda6f593SDavid van Moolenbroek 
400eda6f593SDavid van Moolenbroek 	/* Handle status line. */
401eda6f593SDavid van Moolenbroek 	if (!(c->flags & CLIENT_READONLY)) {
402eda6f593SDavid van Moolenbroek 		status_message_clear(c);
403eda6f593SDavid van Moolenbroek 		server_clear_identify(c);
404eda6f593SDavid van Moolenbroek 	}
405eda6f593SDavid van Moolenbroek 	if (c->prompt_string != NULL) {
406eda6f593SDavid van Moolenbroek 		if (!(c->flags & CLIENT_READONLY))
407eda6f593SDavid van Moolenbroek 			status_prompt_key(c, key);
408eda6f593SDavid van Moolenbroek 		return;
409eda6f593SDavid van Moolenbroek 	}
410eda6f593SDavid van Moolenbroek 
411eda6f593SDavid van Moolenbroek 	/* Check for mouse keys. */
412eda6f593SDavid van Moolenbroek 	if (key == KEYC_MOUSE) {
413eda6f593SDavid van Moolenbroek 		if (c->flags & CLIENT_READONLY)
414eda6f593SDavid van Moolenbroek 			return;
415*0a6a1f1dSLionel Sambuc 		server_client_check_mouse(c, wp);
416eda6f593SDavid van Moolenbroek 		return;
417eda6f593SDavid van Moolenbroek 	}
418eda6f593SDavid van Moolenbroek 
419eda6f593SDavid van Moolenbroek 	/* Is this a prefix key? */
420*0a6a1f1dSLionel Sambuc 	if (key == options_get_number(&s->options, "prefix"))
421eda6f593SDavid van Moolenbroek 		isprefix = 1;
422*0a6a1f1dSLionel Sambuc 	else if (key == options_get_number(&s->options, "prefix2"))
423*0a6a1f1dSLionel Sambuc 		isprefix = 1;
424*0a6a1f1dSLionel Sambuc 	else
425*0a6a1f1dSLionel Sambuc 		isprefix = 0;
426*0a6a1f1dSLionel Sambuc 
427*0a6a1f1dSLionel Sambuc 	/* Treat prefix as a regular key when pasting is detected. */
428*0a6a1f1dSLionel Sambuc 	ispaste = server_client_assume_paste(s);
429*0a6a1f1dSLionel Sambuc 	if (ispaste)
430*0a6a1f1dSLionel Sambuc 		isprefix = 0;
431eda6f593SDavid van Moolenbroek 
432eda6f593SDavid van Moolenbroek 	/* No previous prefix key. */
433eda6f593SDavid van Moolenbroek 	if (!(c->flags & CLIENT_PREFIX)) {
434*0a6a1f1dSLionel Sambuc 		if (isprefix) {
435eda6f593SDavid van Moolenbroek 			c->flags |= CLIENT_PREFIX;
436*0a6a1f1dSLionel Sambuc 			server_status_client(c);
437*0a6a1f1dSLionel Sambuc 			return;
438*0a6a1f1dSLionel Sambuc 		}
439*0a6a1f1dSLionel Sambuc 
440eda6f593SDavid van Moolenbroek 		/* Try as a non-prefix key binding. */
441*0a6a1f1dSLionel Sambuc 		if (ispaste || (bd = key_bindings_lookup(key)) == NULL) {
442eda6f593SDavid van Moolenbroek 			if (!(c->flags & CLIENT_READONLY))
443*0a6a1f1dSLionel Sambuc 				window_pane_key(wp, s, key);
444eda6f593SDavid van Moolenbroek 		} else
445eda6f593SDavid van Moolenbroek 			key_bindings_dispatch(bd, c);
446eda6f593SDavid van Moolenbroek 		return;
447eda6f593SDavid van Moolenbroek 	}
448eda6f593SDavid van Moolenbroek 
449eda6f593SDavid van Moolenbroek 	/* Prefix key already pressed. Reset prefix and lookup key. */
450eda6f593SDavid van Moolenbroek 	c->flags &= ~CLIENT_PREFIX;
451*0a6a1f1dSLionel Sambuc 	server_status_client(c);
452eda6f593SDavid van Moolenbroek 	if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) {
453eda6f593SDavid van Moolenbroek 		/* If repeating, treat this as a key, else ignore. */
454eda6f593SDavid van Moolenbroek 		if (c->flags & CLIENT_REPEAT) {
455eda6f593SDavid van Moolenbroek 			c->flags &= ~CLIENT_REPEAT;
456eda6f593SDavid van Moolenbroek 			if (isprefix)
457eda6f593SDavid van Moolenbroek 				c->flags |= CLIENT_PREFIX;
458eda6f593SDavid van Moolenbroek 			else if (!(c->flags & CLIENT_READONLY))
459*0a6a1f1dSLionel Sambuc 				window_pane_key(wp, s, key);
460eda6f593SDavid van Moolenbroek 		}
461eda6f593SDavid van Moolenbroek 		return;
462eda6f593SDavid van Moolenbroek 	}
463eda6f593SDavid van Moolenbroek 
464eda6f593SDavid van Moolenbroek 	/* If already repeating, but this key can't repeat, skip it. */
465eda6f593SDavid van Moolenbroek 	if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
466eda6f593SDavid van Moolenbroek 		c->flags &= ~CLIENT_REPEAT;
467eda6f593SDavid van Moolenbroek 		if (isprefix)
468eda6f593SDavid van Moolenbroek 			c->flags |= CLIENT_PREFIX;
469eda6f593SDavid van Moolenbroek 		else if (!(c->flags & CLIENT_READONLY))
470*0a6a1f1dSLionel Sambuc 			window_pane_key(wp, s, key);
471eda6f593SDavid van Moolenbroek 		return;
472eda6f593SDavid van Moolenbroek 	}
473eda6f593SDavid van Moolenbroek 
474eda6f593SDavid van Moolenbroek 	/* If this key can repeat, reset the repeat flags and timer. */
475*0a6a1f1dSLionel Sambuc 	xtimeout = options_get_number(&s->options, "repeat-time");
476eda6f593SDavid van Moolenbroek 	if (xtimeout != 0 && bd->can_repeat) {
477eda6f593SDavid van Moolenbroek 		c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
478eda6f593SDavid van Moolenbroek 
479eda6f593SDavid van Moolenbroek 		tv.tv_sec = xtimeout / 1000;
480eda6f593SDavid van Moolenbroek 		tv.tv_usec = (xtimeout % 1000) * 1000L;
481eda6f593SDavid van Moolenbroek 		evtimer_del(&c->repeat_timer);
482eda6f593SDavid van Moolenbroek 		evtimer_add(&c->repeat_timer, &tv);
483eda6f593SDavid van Moolenbroek 	}
484eda6f593SDavid van Moolenbroek 
485eda6f593SDavid van Moolenbroek 	/* Dispatch the command. */
486eda6f593SDavid van Moolenbroek 	key_bindings_dispatch(bd, c);
487eda6f593SDavid van Moolenbroek }
488eda6f593SDavid van Moolenbroek 
489eda6f593SDavid van Moolenbroek /* Client functions that need to happen every loop. */
490eda6f593SDavid van Moolenbroek void
server_client_loop(void)491eda6f593SDavid van Moolenbroek server_client_loop(void)
492eda6f593SDavid van Moolenbroek {
493eda6f593SDavid van Moolenbroek 	struct client		*c;
494eda6f593SDavid van Moolenbroek 	struct window		*w;
495eda6f593SDavid van Moolenbroek 	struct window_pane	*wp;
496eda6f593SDavid van Moolenbroek 	u_int		 	 i;
497eda6f593SDavid van Moolenbroek 
498eda6f593SDavid van Moolenbroek 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
499eda6f593SDavid van Moolenbroek 		c = ARRAY_ITEM(&clients, i);
500eda6f593SDavid van Moolenbroek 		if (c == NULL)
501eda6f593SDavid van Moolenbroek 			continue;
502eda6f593SDavid van Moolenbroek 
503eda6f593SDavid van Moolenbroek 		server_client_check_exit(c);
504eda6f593SDavid van Moolenbroek 		if (c->session != NULL) {
505eda6f593SDavid van Moolenbroek 			server_client_check_redraw(c);
506eda6f593SDavid van Moolenbroek 			server_client_reset_state(c);
507eda6f593SDavid van Moolenbroek 		}
508eda6f593SDavid van Moolenbroek 	}
509eda6f593SDavid van Moolenbroek 
510eda6f593SDavid van Moolenbroek 	/*
511eda6f593SDavid van Moolenbroek 	 * Any windows will have been redrawn as part of clients, so clear
512*0a6a1f1dSLionel Sambuc 	 * their flags now. Also check pane focus and resize.
513eda6f593SDavid van Moolenbroek 	 */
514eda6f593SDavid van Moolenbroek 	for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
515eda6f593SDavid van Moolenbroek 		w = ARRAY_ITEM(&windows, i);
516eda6f593SDavid van Moolenbroek 		if (w == NULL)
517eda6f593SDavid van Moolenbroek 			continue;
518eda6f593SDavid van Moolenbroek 
519eda6f593SDavid van Moolenbroek 		w->flags &= ~WINDOW_REDRAW;
520*0a6a1f1dSLionel Sambuc 		TAILQ_FOREACH(wp, &w->panes, entry) {
521*0a6a1f1dSLionel Sambuc 			if (wp->fd != -1) {
522*0a6a1f1dSLionel Sambuc 				server_client_check_focus(wp);
523*0a6a1f1dSLionel Sambuc 				server_client_check_resize(wp);
524*0a6a1f1dSLionel Sambuc 			}
525eda6f593SDavid van Moolenbroek 			wp->flags &= ~PANE_REDRAW;
526eda6f593SDavid van Moolenbroek 		}
527eda6f593SDavid van Moolenbroek 	}
528*0a6a1f1dSLionel Sambuc }
529*0a6a1f1dSLionel Sambuc 
530*0a6a1f1dSLionel Sambuc /* Check if pane should be resized. */
531*0a6a1f1dSLionel Sambuc void
server_client_check_resize(struct window_pane * wp)532*0a6a1f1dSLionel Sambuc server_client_check_resize(struct window_pane *wp)
533*0a6a1f1dSLionel Sambuc {
534*0a6a1f1dSLionel Sambuc 	struct winsize	ws;
535*0a6a1f1dSLionel Sambuc 
536*0a6a1f1dSLionel Sambuc 	if (!(wp->flags & PANE_RESIZE))
537*0a6a1f1dSLionel Sambuc 		return;
538*0a6a1f1dSLionel Sambuc 
539*0a6a1f1dSLionel Sambuc 	memset(&ws, 0, sizeof ws);
540*0a6a1f1dSLionel Sambuc 	ws.ws_col = wp->sx;
541*0a6a1f1dSLionel Sambuc 	ws.ws_row = wp->sy;
542*0a6a1f1dSLionel Sambuc 
543*0a6a1f1dSLionel Sambuc 	if (ioctl(wp->fd, TIOCSWINSZ, &ws) == -1)
544*0a6a1f1dSLionel Sambuc 		fatal("ioctl failed");
545*0a6a1f1dSLionel Sambuc 
546*0a6a1f1dSLionel Sambuc 	wp->flags &= ~PANE_RESIZE;
547*0a6a1f1dSLionel Sambuc }
548*0a6a1f1dSLionel Sambuc 
549*0a6a1f1dSLionel Sambuc /* Check whether pane should be focused. */
550*0a6a1f1dSLionel Sambuc void
server_client_check_focus(struct window_pane * wp)551*0a6a1f1dSLionel Sambuc server_client_check_focus(struct window_pane *wp)
552*0a6a1f1dSLionel Sambuc {
553*0a6a1f1dSLionel Sambuc 	u_int		 i;
554*0a6a1f1dSLionel Sambuc 	struct client	*c;
555*0a6a1f1dSLionel Sambuc 	int		 push;
556*0a6a1f1dSLionel Sambuc 
557*0a6a1f1dSLionel Sambuc 	/* Are focus events off? */
558*0a6a1f1dSLionel Sambuc 	if (!options_get_number(&global_options, "focus-events"))
559*0a6a1f1dSLionel Sambuc 		return;
560*0a6a1f1dSLionel Sambuc 
561*0a6a1f1dSLionel Sambuc 	/* Do we need to push the focus state? */
562*0a6a1f1dSLionel Sambuc 	push = wp->flags & PANE_FOCUSPUSH;
563*0a6a1f1dSLionel Sambuc 	wp->flags &= ~PANE_FOCUSPUSH;
564*0a6a1f1dSLionel Sambuc 
565*0a6a1f1dSLionel Sambuc 	/* If we don't care about focus, forget it. */
566*0a6a1f1dSLionel Sambuc 	if (!(wp->base.mode & MODE_FOCUSON))
567*0a6a1f1dSLionel Sambuc 		return;
568*0a6a1f1dSLionel Sambuc 
569*0a6a1f1dSLionel Sambuc 	/* If we're not the active pane in our window, we're not focused. */
570*0a6a1f1dSLionel Sambuc 	if (wp->window->active != wp)
571*0a6a1f1dSLionel Sambuc 		goto not_focused;
572*0a6a1f1dSLionel Sambuc 
573*0a6a1f1dSLionel Sambuc 	/* If we're in a mode, we're not focused. */
574*0a6a1f1dSLionel Sambuc 	if (wp->screen != &wp->base)
575*0a6a1f1dSLionel Sambuc 		goto not_focused;
576*0a6a1f1dSLionel Sambuc 
577*0a6a1f1dSLionel Sambuc 	/*
578*0a6a1f1dSLionel Sambuc 	 * If our window is the current window in any focused clients with an
579*0a6a1f1dSLionel Sambuc 	 * attached session, we're focused.
580*0a6a1f1dSLionel Sambuc 	 */
581*0a6a1f1dSLionel Sambuc 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
582*0a6a1f1dSLionel Sambuc 		c = ARRAY_ITEM(&clients, i);
583*0a6a1f1dSLionel Sambuc 		if (c == NULL || c->session == NULL)
584*0a6a1f1dSLionel Sambuc 			continue;
585*0a6a1f1dSLionel Sambuc 
586*0a6a1f1dSLionel Sambuc 		if (!(c->flags & CLIENT_FOCUSED))
587*0a6a1f1dSLionel Sambuc 			continue;
588*0a6a1f1dSLionel Sambuc 		if (c->session->flags & SESSION_UNATTACHED)
589*0a6a1f1dSLionel Sambuc 			continue;
590*0a6a1f1dSLionel Sambuc 
591*0a6a1f1dSLionel Sambuc 		if (c->session->curw->window == wp->window)
592*0a6a1f1dSLionel Sambuc 			goto focused;
593*0a6a1f1dSLionel Sambuc 	}
594*0a6a1f1dSLionel Sambuc 
595*0a6a1f1dSLionel Sambuc not_focused:
596*0a6a1f1dSLionel Sambuc 	if (push || (wp->flags & PANE_FOCUSED))
597*0a6a1f1dSLionel Sambuc 		bufferevent_write(wp->event, "\033[O", 3);
598*0a6a1f1dSLionel Sambuc 	wp->flags &= ~PANE_FOCUSED;
599*0a6a1f1dSLionel Sambuc 	return;
600*0a6a1f1dSLionel Sambuc 
601*0a6a1f1dSLionel Sambuc focused:
602*0a6a1f1dSLionel Sambuc 	if (push || !(wp->flags & PANE_FOCUSED))
603*0a6a1f1dSLionel Sambuc 		bufferevent_write(wp->event, "\033[I", 3);
604*0a6a1f1dSLionel Sambuc 	wp->flags |= PANE_FOCUSED;
605*0a6a1f1dSLionel Sambuc }
606eda6f593SDavid van Moolenbroek 
607eda6f593SDavid van Moolenbroek /*
608eda6f593SDavid van Moolenbroek  * Update cursor position and mode settings. The scroll region and attributes
609eda6f593SDavid van Moolenbroek  * are cleared when idle (waiting for an event) as this is the most likely time
610eda6f593SDavid van Moolenbroek  * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
611eda6f593SDavid van Moolenbroek  * compromise between excessive resets and likelihood of an interrupt.
612eda6f593SDavid van Moolenbroek  *
613eda6f593SDavid van Moolenbroek  * tty_region/tty_reset/tty_update_mode already take care of not resetting
614eda6f593SDavid van Moolenbroek  * things that are already in their default state.
615eda6f593SDavid van Moolenbroek  */
616eda6f593SDavid van Moolenbroek void
server_client_reset_state(struct client * c)617eda6f593SDavid van Moolenbroek server_client_reset_state(struct client *c)
618eda6f593SDavid van Moolenbroek {
619eda6f593SDavid van Moolenbroek 	struct window		*w = c->session->curw->window;
620eda6f593SDavid van Moolenbroek 	struct window_pane	*wp = w->active;
621eda6f593SDavid van Moolenbroek 	struct screen		*s = wp->screen;
622eda6f593SDavid van Moolenbroek 	struct options		*oo = &c->session->options;
623eda6f593SDavid van Moolenbroek 	struct options		*wo = &w->options;
624*0a6a1f1dSLionel Sambuc 	int			 status, mode, o;
625eda6f593SDavid van Moolenbroek 
626eda6f593SDavid van Moolenbroek 	if (c->flags & CLIENT_SUSPENDED)
627eda6f593SDavid van Moolenbroek 		return;
628eda6f593SDavid van Moolenbroek 
629*0a6a1f1dSLionel Sambuc 	if (c->flags & CLIENT_CONTROL)
630*0a6a1f1dSLionel Sambuc 		return;
631*0a6a1f1dSLionel Sambuc 
632eda6f593SDavid van Moolenbroek 	tty_region(&c->tty, 0, c->tty.sy - 1);
633eda6f593SDavid van Moolenbroek 
634eda6f593SDavid van Moolenbroek 	status = options_get_number(oo, "status");
635eda6f593SDavid van Moolenbroek 	if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)
636eda6f593SDavid van Moolenbroek 		tty_cursor(&c->tty, 0, 0);
637*0a6a1f1dSLionel Sambuc 	else {
638*0a6a1f1dSLionel Sambuc 		o = status && options_get_number (oo, "status-position") == 0;
639*0a6a1f1dSLionel Sambuc 		tty_cursor(&c->tty, wp->xoff + s->cx, o + wp->yoff + s->cy);
640*0a6a1f1dSLionel Sambuc 	}
641eda6f593SDavid van Moolenbroek 
642eda6f593SDavid van Moolenbroek 	/*
643eda6f593SDavid van Moolenbroek 	 * Resizing panes with the mouse requires at least button mode to give
644eda6f593SDavid van Moolenbroek 	 * a smooth appearance.
645eda6f593SDavid van Moolenbroek 	 */
646eda6f593SDavid van Moolenbroek 	mode = s->mode;
647*0a6a1f1dSLionel Sambuc 	if ((c->tty.mouse.flags & MOUSE_RESIZE_PANE) &&
648eda6f593SDavid van Moolenbroek 	    !(mode & (MODE_MOUSE_BUTTON|MODE_MOUSE_ANY)))
649eda6f593SDavid van Moolenbroek 		mode |= MODE_MOUSE_BUTTON;
650eda6f593SDavid van Moolenbroek 
651eda6f593SDavid van Moolenbroek 	/*
652eda6f593SDavid van Moolenbroek 	 * Any mode will do for mouse-select-pane, but set standard mode if
653eda6f593SDavid van Moolenbroek 	 * none.
654eda6f593SDavid van Moolenbroek 	 */
655eda6f593SDavid van Moolenbroek 	if ((mode & ALL_MOUSE_MODES) == 0) {
656eda6f593SDavid van Moolenbroek 		if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL &&
657eda6f593SDavid van Moolenbroek 		    options_get_number(oo, "mouse-select-pane"))
658eda6f593SDavid van Moolenbroek 			mode |= MODE_MOUSE_STANDARD;
659eda6f593SDavid van Moolenbroek 		else if (options_get_number(oo, "mouse-resize-pane"))
660eda6f593SDavid van Moolenbroek 			mode |= MODE_MOUSE_STANDARD;
661eda6f593SDavid van Moolenbroek 		else if (options_get_number(oo, "mouse-select-window"))
662eda6f593SDavid van Moolenbroek 			mode |= MODE_MOUSE_STANDARD;
663eda6f593SDavid van Moolenbroek 		else if (options_get_number(wo, "mode-mouse"))
664eda6f593SDavid van Moolenbroek 			mode |= MODE_MOUSE_STANDARD;
665eda6f593SDavid van Moolenbroek 	}
666eda6f593SDavid van Moolenbroek 
667eda6f593SDavid van Moolenbroek 	/*
668eda6f593SDavid van Moolenbroek 	 * Set UTF-8 mouse input if required. If the terminal is UTF-8, the
669eda6f593SDavid van Moolenbroek 	 * user has set mouse-utf8 and any mouse mode is in effect, turn on
670eda6f593SDavid van Moolenbroek 	 * UTF-8 mouse input. If the receiving terminal hasn't requested it
671eda6f593SDavid van Moolenbroek 	 * (that is, it isn't in s->mode), then it'll be converted in
672eda6f593SDavid van Moolenbroek 	 * input_mouse.
673eda6f593SDavid van Moolenbroek 	 */
674eda6f593SDavid van Moolenbroek 	if ((c->tty.flags & TTY_UTF8) &&
675eda6f593SDavid van Moolenbroek 	    (mode & ALL_MOUSE_MODES) && options_get_number(oo, "mouse-utf8"))
676eda6f593SDavid van Moolenbroek 		mode |= MODE_MOUSE_UTF8;
677eda6f593SDavid van Moolenbroek 	else
678eda6f593SDavid van Moolenbroek 		mode &= ~MODE_MOUSE_UTF8;
679eda6f593SDavid van Moolenbroek 
680eda6f593SDavid van Moolenbroek 	/* Set the terminal mode and reset attributes. */
681eda6f593SDavid van Moolenbroek 	tty_update_mode(&c->tty, mode, s);
682eda6f593SDavid van Moolenbroek 	tty_reset(&c->tty);
683eda6f593SDavid van Moolenbroek }
684eda6f593SDavid van Moolenbroek 
685eda6f593SDavid van Moolenbroek /* Repeat time callback. */
686eda6f593SDavid van Moolenbroek void
server_client_repeat_timer(unused int fd,unused short events,void * data)687eda6f593SDavid van Moolenbroek server_client_repeat_timer(unused int fd, unused short events, void *data)
688eda6f593SDavid van Moolenbroek {
689eda6f593SDavid van Moolenbroek 	struct client	*c = data;
690eda6f593SDavid van Moolenbroek 
691*0a6a1f1dSLionel Sambuc 	if (c->flags & CLIENT_REPEAT) {
692*0a6a1f1dSLionel Sambuc 		if (c->flags & CLIENT_PREFIX)
693*0a6a1f1dSLionel Sambuc 			server_status_client(c);
694eda6f593SDavid van Moolenbroek 		c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
695eda6f593SDavid van Moolenbroek 	}
696*0a6a1f1dSLionel Sambuc }
697eda6f593SDavid van Moolenbroek 
698eda6f593SDavid van Moolenbroek /* Check if client should be exited. */
699eda6f593SDavid van Moolenbroek void
server_client_check_exit(struct client * c)700eda6f593SDavid van Moolenbroek server_client_check_exit(struct client *c)
701eda6f593SDavid van Moolenbroek {
702eda6f593SDavid van Moolenbroek 	if (!(c->flags & CLIENT_EXIT))
703eda6f593SDavid van Moolenbroek 		return;
704eda6f593SDavid van Moolenbroek 
705*0a6a1f1dSLionel Sambuc 	if (EVBUFFER_LENGTH(c->stdin_data) != 0)
706eda6f593SDavid van Moolenbroek 		return;
707*0a6a1f1dSLionel Sambuc 	if (EVBUFFER_LENGTH(c->stdout_data) != 0)
708*0a6a1f1dSLionel Sambuc 		return;
709*0a6a1f1dSLionel Sambuc 	if (EVBUFFER_LENGTH(c->stderr_data) != 0)
710eda6f593SDavid van Moolenbroek 		return;
711eda6f593SDavid van Moolenbroek 
712*0a6a1f1dSLionel Sambuc 	server_write_client(c, MSG_EXIT, &c->retval, sizeof c->retval);
713eda6f593SDavid van Moolenbroek 	c->flags &= ~CLIENT_EXIT;
714eda6f593SDavid van Moolenbroek }
715eda6f593SDavid van Moolenbroek 
716eda6f593SDavid van Moolenbroek /* Check for client redraws. */
717eda6f593SDavid van Moolenbroek void
server_client_check_redraw(struct client * c)718eda6f593SDavid van Moolenbroek server_client_check_redraw(struct client *c)
719eda6f593SDavid van Moolenbroek {
720eda6f593SDavid van Moolenbroek 	struct session		*s = c->session;
721eda6f593SDavid van Moolenbroek 	struct window_pane	*wp;
722eda6f593SDavid van Moolenbroek 	int		 	 flags, redraw;
723eda6f593SDavid van Moolenbroek 
724*0a6a1f1dSLionel Sambuc 	if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
725*0a6a1f1dSLionel Sambuc 		return;
726*0a6a1f1dSLionel Sambuc 
727eda6f593SDavid van Moolenbroek 	flags = c->tty.flags & TTY_FREEZE;
728eda6f593SDavid van Moolenbroek 	c->tty.flags &= ~TTY_FREEZE;
729eda6f593SDavid van Moolenbroek 
730eda6f593SDavid van Moolenbroek 	if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
731eda6f593SDavid van Moolenbroek 		if (options_get_number(&s->options, "set-titles"))
732eda6f593SDavid van Moolenbroek 			server_client_set_title(c);
733eda6f593SDavid van Moolenbroek 
734eda6f593SDavid van Moolenbroek 		if (c->message_string != NULL)
735eda6f593SDavid van Moolenbroek 			redraw = status_message_redraw(c);
736eda6f593SDavid van Moolenbroek 		else if (c->prompt_string != NULL)
737eda6f593SDavid van Moolenbroek 			redraw = status_prompt_redraw(c);
738eda6f593SDavid van Moolenbroek 		else
739eda6f593SDavid van Moolenbroek 			redraw = status_redraw(c);
740eda6f593SDavid van Moolenbroek 		if (!redraw)
741eda6f593SDavid van Moolenbroek 			c->flags &= ~CLIENT_STATUS;
742eda6f593SDavid van Moolenbroek 	}
743eda6f593SDavid van Moolenbroek 
744eda6f593SDavid van Moolenbroek 	if (c->flags & CLIENT_REDRAW) {
745*0a6a1f1dSLionel Sambuc 		screen_redraw_screen(c, 1, 1, 1);
746eda6f593SDavid van Moolenbroek 		c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS);
747eda6f593SDavid van Moolenbroek 	} else if (c->flags & CLIENT_REDRAWWINDOW) {
748eda6f593SDavid van Moolenbroek 		TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry)
749eda6f593SDavid van Moolenbroek 			screen_redraw_pane(c, wp);
750eda6f593SDavid van Moolenbroek 		c->flags &= ~CLIENT_REDRAWWINDOW;
751eda6f593SDavid van Moolenbroek 	} else {
752eda6f593SDavid van Moolenbroek 		TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
753eda6f593SDavid van Moolenbroek 			if (wp->flags & PANE_REDRAW)
754eda6f593SDavid van Moolenbroek 				screen_redraw_pane(c, wp);
755eda6f593SDavid van Moolenbroek 		}
756eda6f593SDavid van Moolenbroek 	}
757eda6f593SDavid van Moolenbroek 
758eda6f593SDavid van Moolenbroek 	if (c->flags & CLIENT_BORDERS)
759*0a6a1f1dSLionel Sambuc 		screen_redraw_screen(c, 0, 0, 1);
760eda6f593SDavid van Moolenbroek 
761eda6f593SDavid van Moolenbroek 	if (c->flags & CLIENT_STATUS)
762*0a6a1f1dSLionel Sambuc 		screen_redraw_screen(c, 0, 1, 0);
763eda6f593SDavid van Moolenbroek 
764eda6f593SDavid van Moolenbroek 	c->tty.flags |= flags;
765eda6f593SDavid van Moolenbroek 
766eda6f593SDavid van Moolenbroek 	c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS|CLIENT_BORDERS);
767eda6f593SDavid van Moolenbroek }
768eda6f593SDavid van Moolenbroek 
769eda6f593SDavid van Moolenbroek /* Set client title. */
770eda6f593SDavid van Moolenbroek void
server_client_set_title(struct client * c)771eda6f593SDavid van Moolenbroek server_client_set_title(struct client *c)
772eda6f593SDavid van Moolenbroek {
773eda6f593SDavid van Moolenbroek 	struct session	*s = c->session;
774eda6f593SDavid van Moolenbroek 	const char	*template;
775eda6f593SDavid van Moolenbroek 	char		*title;
776eda6f593SDavid van Moolenbroek 
777eda6f593SDavid van Moolenbroek 	template = options_get_string(&s->options, "set-titles-string");
778eda6f593SDavid van Moolenbroek 
779eda6f593SDavid van Moolenbroek 	title = status_replace(c, NULL, NULL, NULL, template, time(NULL), 1);
780eda6f593SDavid van Moolenbroek 	if (c->title == NULL || strcmp(title, c->title) != 0) {
781*0a6a1f1dSLionel Sambuc 		free(c->title);
782eda6f593SDavid van Moolenbroek 		c->title = xstrdup(title);
783eda6f593SDavid van Moolenbroek 		tty_set_title(&c->tty, c->title);
784eda6f593SDavid van Moolenbroek 	}
785*0a6a1f1dSLionel Sambuc 	free(title);
786eda6f593SDavid van Moolenbroek }
787eda6f593SDavid van Moolenbroek 
788eda6f593SDavid van Moolenbroek /* Dispatch message from client. */
789eda6f593SDavid van Moolenbroek int
server_client_msg_dispatch(struct client * c)790eda6f593SDavid van Moolenbroek server_client_msg_dispatch(struct client *c)
791eda6f593SDavid van Moolenbroek {
792eda6f593SDavid van Moolenbroek 	struct imsg		 imsg;
793*0a6a1f1dSLionel Sambuc 	struct msg_stdin_data	 stdindata;
794*0a6a1f1dSLionel Sambuc 	const char		*data;
795eda6f593SDavid van Moolenbroek 	ssize_t			 n, datalen;
796eda6f593SDavid van Moolenbroek 
797eda6f593SDavid van Moolenbroek 	if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
798eda6f593SDavid van Moolenbroek 		return (-1);
799eda6f593SDavid van Moolenbroek 
800eda6f593SDavid van Moolenbroek 	for (;;) {
801eda6f593SDavid van Moolenbroek 		if ((n = imsg_get(&c->ibuf, &imsg)) == -1)
802eda6f593SDavid van Moolenbroek 			return (-1);
803eda6f593SDavid van Moolenbroek 		if (n == 0)
804eda6f593SDavid van Moolenbroek 			return (0);
805*0a6a1f1dSLionel Sambuc 
806*0a6a1f1dSLionel Sambuc 		data = imsg.data;
807eda6f593SDavid van Moolenbroek 		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
808eda6f593SDavid van Moolenbroek 
809eda6f593SDavid van Moolenbroek 		if (imsg.hdr.peerid != PROTOCOL_VERSION) {
810eda6f593SDavid van Moolenbroek 			server_write_client(c, MSG_VERSION, NULL, 0);
811eda6f593SDavid van Moolenbroek 			c->flags |= CLIENT_BAD;
812*0a6a1f1dSLionel Sambuc 			if (imsg.fd != -1)
813*0a6a1f1dSLionel Sambuc 				close(imsg.fd);
814eda6f593SDavid van Moolenbroek 			imsg_free(&imsg);
815eda6f593SDavid van Moolenbroek 			continue;
816eda6f593SDavid van Moolenbroek 		}
817eda6f593SDavid van Moolenbroek 
818eda6f593SDavid van Moolenbroek 		log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd);
819eda6f593SDavid van Moolenbroek 		switch (imsg.hdr.type) {
820*0a6a1f1dSLionel Sambuc 		case MSG_IDENTIFY_FLAGS:
821*0a6a1f1dSLionel Sambuc 		case MSG_IDENTIFY_TERM:
822*0a6a1f1dSLionel Sambuc 		case MSG_IDENTIFY_TTYNAME:
823*0a6a1f1dSLionel Sambuc 		case MSG_IDENTIFY_CWD:
824*0a6a1f1dSLionel Sambuc 		case MSG_IDENTIFY_STDIN:
825*0a6a1f1dSLionel Sambuc 		case MSG_IDENTIFY_ENVIRON:
826*0a6a1f1dSLionel Sambuc 		case MSG_IDENTIFY_DONE:
827*0a6a1f1dSLionel Sambuc 			server_client_msg_identify(c, &imsg);
828*0a6a1f1dSLionel Sambuc 			break;
829eda6f593SDavid van Moolenbroek 		case MSG_COMMAND:
830*0a6a1f1dSLionel Sambuc 			server_client_msg_command(c, &imsg);
831eda6f593SDavid van Moolenbroek 			break;
832*0a6a1f1dSLionel Sambuc 		case MSG_STDIN:
833*0a6a1f1dSLionel Sambuc 			if (datalen != sizeof stdindata)
834*0a6a1f1dSLionel Sambuc 				fatalx("bad MSG_STDIN size");
835*0a6a1f1dSLionel Sambuc 			memcpy(&stdindata, data, sizeof stdindata);
836eda6f593SDavid van Moolenbroek 
837*0a6a1f1dSLionel Sambuc 			if (c->stdin_callback == NULL)
838eda6f593SDavid van Moolenbroek 				break;
839*0a6a1f1dSLionel Sambuc 			if (stdindata.size <= 0)
840*0a6a1f1dSLionel Sambuc 				c->stdin_closed = 1;
841*0a6a1f1dSLionel Sambuc 			else {
842*0a6a1f1dSLionel Sambuc 				evbuffer_add(c->stdin_data, stdindata.data,
843*0a6a1f1dSLionel Sambuc 				    stdindata.size);
844*0a6a1f1dSLionel Sambuc 			}
845*0a6a1f1dSLionel Sambuc 			c->stdin_callback(c, c->stdin_closed,
846*0a6a1f1dSLionel Sambuc 			    c->stdin_callback_data);
847eda6f593SDavid van Moolenbroek 			break;
848eda6f593SDavid van Moolenbroek 		case MSG_RESIZE:
849eda6f593SDavid van Moolenbroek 			if (datalen != 0)
850eda6f593SDavid van Moolenbroek 				fatalx("bad MSG_RESIZE size");
851eda6f593SDavid van Moolenbroek 
852*0a6a1f1dSLionel Sambuc 			if (c->flags & CLIENT_CONTROL)
853*0a6a1f1dSLionel Sambuc 				break;
854eda6f593SDavid van Moolenbroek 			if (tty_resize(&c->tty)) {
855eda6f593SDavid van Moolenbroek 				recalculate_sizes();
856eda6f593SDavid van Moolenbroek 				server_redraw_client(c);
857eda6f593SDavid van Moolenbroek 			}
858eda6f593SDavid van Moolenbroek 			break;
859eda6f593SDavid van Moolenbroek 		case MSG_EXITING:
860eda6f593SDavid van Moolenbroek 			if (datalen != 0)
861eda6f593SDavid van Moolenbroek 				fatalx("bad MSG_EXITING size");
862eda6f593SDavid van Moolenbroek 
863eda6f593SDavid van Moolenbroek 			c->session = NULL;
864eda6f593SDavid van Moolenbroek 			tty_close(&c->tty);
865eda6f593SDavid van Moolenbroek 			server_write_client(c, MSG_EXITED, NULL, 0);
866eda6f593SDavid van Moolenbroek 			break;
867eda6f593SDavid van Moolenbroek 		case MSG_WAKEUP:
868eda6f593SDavid van Moolenbroek 		case MSG_UNLOCK:
869eda6f593SDavid van Moolenbroek 			if (datalen != 0)
870eda6f593SDavid van Moolenbroek 				fatalx("bad MSG_WAKEUP size");
871eda6f593SDavid van Moolenbroek 
872eda6f593SDavid van Moolenbroek 			if (!(c->flags & CLIENT_SUSPENDED))
873eda6f593SDavid van Moolenbroek 				break;
874eda6f593SDavid van Moolenbroek 			c->flags &= ~CLIENT_SUSPENDED;
875eda6f593SDavid van Moolenbroek 
876eda6f593SDavid van Moolenbroek 			if (gettimeofday(&c->activity_time, NULL) != 0)
877eda6f593SDavid van Moolenbroek 				fatal("gettimeofday");
878eda6f593SDavid van Moolenbroek 			if (c->session != NULL)
879eda6f593SDavid van Moolenbroek 				session_update_activity(c->session);
880eda6f593SDavid van Moolenbroek 
881eda6f593SDavid van Moolenbroek 			tty_start_tty(&c->tty);
882eda6f593SDavid van Moolenbroek 			server_redraw_client(c);
883eda6f593SDavid van Moolenbroek 			recalculate_sizes();
884eda6f593SDavid van Moolenbroek 			break;
885eda6f593SDavid van Moolenbroek 		case MSG_SHELL:
886eda6f593SDavid van Moolenbroek 			if (datalen != 0)
887eda6f593SDavid van Moolenbroek 				fatalx("bad MSG_SHELL size");
888eda6f593SDavid van Moolenbroek 
889eda6f593SDavid van Moolenbroek 			server_client_msg_shell(c);
890eda6f593SDavid van Moolenbroek 			break;
891eda6f593SDavid van Moolenbroek 		}
892eda6f593SDavid van Moolenbroek 
893eda6f593SDavid van Moolenbroek 		imsg_free(&imsg);
894eda6f593SDavid van Moolenbroek 	}
895eda6f593SDavid van Moolenbroek }
896eda6f593SDavid van Moolenbroek 
897eda6f593SDavid van Moolenbroek /* Handle command message. */
898eda6f593SDavid van Moolenbroek void
server_client_msg_command(struct client * c,struct imsg * imsg)899*0a6a1f1dSLionel Sambuc server_client_msg_command(struct client *c, struct imsg *imsg)
900eda6f593SDavid van Moolenbroek {
901*0a6a1f1dSLionel Sambuc 	struct msg_command_data	  data;
902*0a6a1f1dSLionel Sambuc 	char			 *buf;
903*0a6a1f1dSLionel Sambuc 	size_t			  len;
904eda6f593SDavid van Moolenbroek 	struct cmd_list		 *cmdlist = NULL;
905eda6f593SDavid van Moolenbroek 	int			  argc;
906eda6f593SDavid van Moolenbroek 	char			**argv, *cause;
907eda6f593SDavid van Moolenbroek 
908*0a6a1f1dSLionel Sambuc 	if (imsg->hdr.len - IMSG_HEADER_SIZE < sizeof data)
909*0a6a1f1dSLionel Sambuc 		fatalx("bad MSG_COMMAND size");
910*0a6a1f1dSLionel Sambuc 	memcpy(&data, imsg->data, sizeof data);
911eda6f593SDavid van Moolenbroek 
912*0a6a1f1dSLionel Sambuc 	buf = (char*)imsg->data + sizeof data;
913*0a6a1f1dSLionel Sambuc 	len = imsg->hdr.len  - IMSG_HEADER_SIZE - sizeof data;
914*0a6a1f1dSLionel Sambuc 	if (len > 0 && buf[len - 1] != '\0')
915*0a6a1f1dSLionel Sambuc 		fatalx("bad MSG_COMMAND string");
916eda6f593SDavid van Moolenbroek 
917*0a6a1f1dSLionel Sambuc 	argc = data.argc;
918*0a6a1f1dSLionel Sambuc 	if (cmd_unpack_argv(buf, len, argc, &argv) != 0) {
919*0a6a1f1dSLionel Sambuc 		cmdq_error(c->cmdq, "command too long");
920eda6f593SDavid van Moolenbroek 		goto error;
921eda6f593SDavid van Moolenbroek 	}
922eda6f593SDavid van Moolenbroek 
923eda6f593SDavid van Moolenbroek 	if (argc == 0) {
924eda6f593SDavid van Moolenbroek 		argc = 1;
925eda6f593SDavid van Moolenbroek 		argv = xcalloc(1, sizeof *argv);
926eda6f593SDavid van Moolenbroek 		*argv = xstrdup("new-session");
927eda6f593SDavid van Moolenbroek 	}
928eda6f593SDavid van Moolenbroek 
929*0a6a1f1dSLionel Sambuc 	if ((cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause)) == NULL) {
930*0a6a1f1dSLionel Sambuc 		cmdq_error(c->cmdq, "%s", cause);
931eda6f593SDavid van Moolenbroek 		cmd_free_argv(argc, argv);
932eda6f593SDavid van Moolenbroek 		goto error;
933eda6f593SDavid van Moolenbroek 	}
934eda6f593SDavid van Moolenbroek 	cmd_free_argv(argc, argv);
935eda6f593SDavid van Moolenbroek 
936*0a6a1f1dSLionel Sambuc 	if (c != cfg_client || cfg_finished)
937*0a6a1f1dSLionel Sambuc 		cmdq_run(c->cmdq, cmdlist);
938*0a6a1f1dSLionel Sambuc 	else
939*0a6a1f1dSLionel Sambuc 		cmdq_append(c->cmdq, cmdlist);
940eda6f593SDavid van Moolenbroek 	cmd_list_free(cmdlist);
941eda6f593SDavid van Moolenbroek 	return;
942eda6f593SDavid van Moolenbroek 
943eda6f593SDavid van Moolenbroek error:
944eda6f593SDavid van Moolenbroek 	if (cmdlist != NULL)
945eda6f593SDavid van Moolenbroek 		cmd_list_free(cmdlist);
946*0a6a1f1dSLionel Sambuc 
947eda6f593SDavid van Moolenbroek 	c->flags |= CLIENT_EXIT;
948eda6f593SDavid van Moolenbroek }
949eda6f593SDavid van Moolenbroek 
950eda6f593SDavid van Moolenbroek /* Handle identify message. */
951eda6f593SDavid van Moolenbroek void
server_client_msg_identify(struct client * c,struct imsg * imsg)952*0a6a1f1dSLionel Sambuc server_client_msg_identify(struct client *c, struct imsg *imsg)
953eda6f593SDavid van Moolenbroek {
954*0a6a1f1dSLionel Sambuc 	const char	*data;
955*0a6a1f1dSLionel Sambuc 	size_t	 	 datalen;
956*0a6a1f1dSLionel Sambuc 	int		 flags;
957eda6f593SDavid van Moolenbroek 
958*0a6a1f1dSLionel Sambuc 	if (c->flags & CLIENT_IDENTIFIED)
959*0a6a1f1dSLionel Sambuc 		fatalx("out-of-order identify message");
960eda6f593SDavid van Moolenbroek 
961*0a6a1f1dSLionel Sambuc 	data = imsg->data;
962*0a6a1f1dSLionel Sambuc 	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
963*0a6a1f1dSLionel Sambuc 
964*0a6a1f1dSLionel Sambuc 	switch (imsg->hdr.type)	{
965*0a6a1f1dSLionel Sambuc 	case MSG_IDENTIFY_FLAGS:
966*0a6a1f1dSLionel Sambuc 		if (datalen != sizeof flags)
967*0a6a1f1dSLionel Sambuc 			fatalx("bad MSG_IDENTIFY_FLAGS size");
968*0a6a1f1dSLionel Sambuc 		memcpy(&flags, data, sizeof flags);
969*0a6a1f1dSLionel Sambuc 		c->flags |= flags;
970*0a6a1f1dSLionel Sambuc 		break;
971*0a6a1f1dSLionel Sambuc 	case MSG_IDENTIFY_TERM:
972*0a6a1f1dSLionel Sambuc 		if (datalen == 0 || data[datalen - 1] != '\0')
973*0a6a1f1dSLionel Sambuc 			fatalx("bad MSG_IDENTIFY_TERM string");
974*0a6a1f1dSLionel Sambuc 		c->term = xstrdup(data);
975*0a6a1f1dSLionel Sambuc 		break;
976*0a6a1f1dSLionel Sambuc 	case MSG_IDENTIFY_TTYNAME:
977*0a6a1f1dSLionel Sambuc 		if (datalen == 0 || data[datalen - 1] != '\0')
978*0a6a1f1dSLionel Sambuc 			fatalx("bad MSG_IDENTIFY_TTYNAME string");
979*0a6a1f1dSLionel Sambuc 		c->ttyname = xstrdup(data);
980*0a6a1f1dSLionel Sambuc 		break;
981*0a6a1f1dSLionel Sambuc 	case MSG_IDENTIFY_CWD:
982*0a6a1f1dSLionel Sambuc 		if (datalen != 0)
983*0a6a1f1dSLionel Sambuc 			fatalx("bad MSG_IDENTIFY_CWD size");
984*0a6a1f1dSLionel Sambuc 		c->cwd = imsg->fd;
985*0a6a1f1dSLionel Sambuc 		break;
986*0a6a1f1dSLionel Sambuc 	case MSG_IDENTIFY_STDIN:
987*0a6a1f1dSLionel Sambuc 		if (datalen != 0)
988*0a6a1f1dSLionel Sambuc 			fatalx("bad MSG_IDENTIFY_STDIN size");
989*0a6a1f1dSLionel Sambuc 		c->fd = imsg->fd;
990*0a6a1f1dSLionel Sambuc 		break;
991*0a6a1f1dSLionel Sambuc 	case MSG_IDENTIFY_ENVIRON:
992*0a6a1f1dSLionel Sambuc 		if (datalen == 0 || data[datalen - 1] != '\0')
993*0a6a1f1dSLionel Sambuc 			fatalx("bad MSG_IDENTIFY_ENVIRON string");
994*0a6a1f1dSLionel Sambuc 		if (strchr(data, '=') != NULL)
995*0a6a1f1dSLionel Sambuc 			environ_put(&c->environ, data);
996*0a6a1f1dSLionel Sambuc 		break;
997*0a6a1f1dSLionel Sambuc 	default:
998*0a6a1f1dSLionel Sambuc 		break;
999*0a6a1f1dSLionel Sambuc 	}
1000*0a6a1f1dSLionel Sambuc 
1001*0a6a1f1dSLionel Sambuc 	if (imsg->hdr.type != MSG_IDENTIFY_DONE)
1002eda6f593SDavid van Moolenbroek 		return;
1003*0a6a1f1dSLionel Sambuc 	c->flags |= CLIENT_IDENTIFIED;
1004*0a6a1f1dSLionel Sambuc 
1005*0a6a1f1dSLionel Sambuc #ifdef __CYGWIN__
1006*0a6a1f1dSLionel Sambuc 	c->fd = open(c->ttyname, O_RDWR|O_NOCTTY);
1007*0a6a1f1dSLionel Sambuc 	c->cwd = open(".", O_RDONLY);
1008*0a6a1f1dSLionel Sambuc #endif
1009*0a6a1f1dSLionel Sambuc 
1010*0a6a1f1dSLionel Sambuc 	if (c->flags & CLIENT_CONTROL) {
1011*0a6a1f1dSLionel Sambuc 		c->stdin_callback = control_callback;
1012*0a6a1f1dSLionel Sambuc 
1013*0a6a1f1dSLionel Sambuc 		evbuffer_free(c->stderr_data);
1014*0a6a1f1dSLionel Sambuc 		c->stderr_data = c->stdout_data;
1015*0a6a1f1dSLionel Sambuc 
1016*0a6a1f1dSLionel Sambuc 		if (c->flags & CLIENT_CONTROLCONTROL)
1017*0a6a1f1dSLionel Sambuc 			evbuffer_add_printf(c->stdout_data, "\033P1000p");
1018*0a6a1f1dSLionel Sambuc 		server_write_client(c, MSG_STDIN, NULL, 0);
1019*0a6a1f1dSLionel Sambuc 
1020*0a6a1f1dSLionel Sambuc 		c->tty.fd = -1;
1021*0a6a1f1dSLionel Sambuc 		c->tty.log_fd = -1;
1022*0a6a1f1dSLionel Sambuc 
1023*0a6a1f1dSLionel Sambuc 		close(c->fd);
1024*0a6a1f1dSLionel Sambuc 		c->fd = -1;
1025*0a6a1f1dSLionel Sambuc 
1026*0a6a1f1dSLionel Sambuc 		return;
1027*0a6a1f1dSLionel Sambuc 	}
1028*0a6a1f1dSLionel Sambuc 
1029*0a6a1f1dSLionel Sambuc 	if (c->fd == -1)
1030*0a6a1f1dSLionel Sambuc 		return;
1031*0a6a1f1dSLionel Sambuc 	if (!isatty(c->fd)) {
1032*0a6a1f1dSLionel Sambuc 		close(c->fd);
1033*0a6a1f1dSLionel Sambuc 		c->fd = -1;
1034*0a6a1f1dSLionel Sambuc 		return;
1035*0a6a1f1dSLionel Sambuc 	}
1036*0a6a1f1dSLionel Sambuc 	tty_init(&c->tty, c, c->fd, c->term);
1037*0a6a1f1dSLionel Sambuc 	if (c->flags & CLIENT_UTF8)
1038eda6f593SDavid van Moolenbroek 		c->tty.flags |= TTY_UTF8;
1039*0a6a1f1dSLionel Sambuc 	if (c->flags & CLIENT_256COLOURS)
1040eda6f593SDavid van Moolenbroek 		c->tty.term_flags |= TERM_256COLOURS;
1041eda6f593SDavid van Moolenbroek 
1042eda6f593SDavid van Moolenbroek 	tty_resize(&c->tty);
1043eda6f593SDavid van Moolenbroek 
1044*0a6a1f1dSLionel Sambuc 	if (!(c->flags & CLIENT_CONTROL))
1045eda6f593SDavid van Moolenbroek 		c->flags |= CLIENT_TERMINAL;
1046eda6f593SDavid van Moolenbroek }
1047eda6f593SDavid van Moolenbroek 
1048eda6f593SDavid van Moolenbroek /* Handle shell message. */
1049eda6f593SDavid van Moolenbroek void
server_client_msg_shell(struct client * c)1050eda6f593SDavid van Moolenbroek server_client_msg_shell(struct client *c)
1051eda6f593SDavid van Moolenbroek {
1052eda6f593SDavid van Moolenbroek 	const char	*shell;
1053eda6f593SDavid van Moolenbroek 
1054eda6f593SDavid van Moolenbroek 	shell = options_get_string(&global_s_options, "default-shell");
1055eda6f593SDavid van Moolenbroek 	if (*shell == '\0' || areshell(shell))
1056eda6f593SDavid van Moolenbroek 		shell = _PATH_BSHELL;
1057*0a6a1f1dSLionel Sambuc 	server_write_client(c, MSG_SHELL, shell, strlen(shell) + 1);
1058eda6f593SDavid van Moolenbroek 
1059eda6f593SDavid van Moolenbroek 	c->flags |= CLIENT_BAD;	/* it will die after exec */
1060eda6f593SDavid van Moolenbroek }
1061