xref: /openbsd/usr.bin/tmux/server.c (revision 311827fb)
1*311827fbSnicm /* $OpenBSD: server.c,v 1.1 2009/06/01 22:58:49 nicm Exp $ */
2*311827fbSnicm 
3*311827fbSnicm /*
4*311827fbSnicm  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
5*311827fbSnicm  *
6*311827fbSnicm  * Permission to use, copy, modify, and distribute this software for any
7*311827fbSnicm  * purpose with or without fee is hereby granted, provided that the above
8*311827fbSnicm  * copyright notice and this permission notice appear in all copies.
9*311827fbSnicm  *
10*311827fbSnicm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*311827fbSnicm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*311827fbSnicm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*311827fbSnicm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*311827fbSnicm  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15*311827fbSnicm  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16*311827fbSnicm  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*311827fbSnicm  */
18*311827fbSnicm 
19*311827fbSnicm #include <sys/types.h>
20*311827fbSnicm #include <sys/ioctl.h>
21*311827fbSnicm #include <sys/socket.h>
22*311827fbSnicm #include <sys/stat.h>
23*311827fbSnicm #include <sys/un.h>
24*311827fbSnicm #include <sys/wait.h>
25*311827fbSnicm 
26*311827fbSnicm #include <errno.h>
27*311827fbSnicm #include <fcntl.h>
28*311827fbSnicm #include <signal.h>
29*311827fbSnicm #include <stdio.h>
30*311827fbSnicm #include <stdlib.h>
31*311827fbSnicm #include <string.h>
32*311827fbSnicm #include <syslog.h>
33*311827fbSnicm #include <termios.h>
34*311827fbSnicm #include <time.h>
35*311827fbSnicm #include <unistd.h>
36*311827fbSnicm 
37*311827fbSnicm #include "tmux.h"
38*311827fbSnicm 
39*311827fbSnicm /*
40*311827fbSnicm  * Main server functions.
41*311827fbSnicm  */
42*311827fbSnicm 
43*311827fbSnicm /* Client list. */
44*311827fbSnicm struct clients	 clients;
45*311827fbSnicm 
46*311827fbSnicm int		 server_create_socket(void);
47*311827fbSnicm int		 server_main(int);
48*311827fbSnicm void		 server_shutdown(void);
49*311827fbSnicm void		 server_child_signal(void);
50*311827fbSnicm void		 server_fill_windows(struct pollfd **);
51*311827fbSnicm void		 server_handle_windows(struct pollfd **);
52*311827fbSnicm void		 server_fill_clients(struct pollfd **);
53*311827fbSnicm void		 server_handle_clients(struct pollfd **);
54*311827fbSnicm struct client	*server_accept_client(int);
55*311827fbSnicm void		 server_handle_client(struct client *);
56*311827fbSnicm void		 server_handle_window(struct window *, struct window_pane *);
57*311827fbSnicm int		 server_check_window_bell(struct session *, struct window *,
58*311827fbSnicm 		      struct window_pane *);
59*311827fbSnicm int		 server_check_window_activity(struct session *,
60*311827fbSnicm 		      struct window *);
61*311827fbSnicm int		 server_check_window_content(struct session *, struct window *,
62*311827fbSnicm 		      struct window_pane *);
63*311827fbSnicm void		 server_lost_client(struct client *);
64*311827fbSnicm void	 	 server_check_window(struct window *);
65*311827fbSnicm void		 server_check_redraw(struct client *);
66*311827fbSnicm void		 server_redraw_locked(struct client *);
67*311827fbSnicm void		 server_check_timers(struct client *);
68*311827fbSnicm void		 server_second_timers(void);
69*311827fbSnicm int		 server_update_socket(void);
70*311827fbSnicm 
71*311827fbSnicm /* Create a new client. */
72*311827fbSnicm struct client *
73*311827fbSnicm server_create_client(int fd)
74*311827fbSnicm {
75*311827fbSnicm 	struct client	*c;
76*311827fbSnicm 	int		 mode;
77*311827fbSnicm 	u_int		 i;
78*311827fbSnicm 
79*311827fbSnicm 	if ((mode = fcntl(fd, F_GETFL)) == -1)
80*311827fbSnicm 		fatal("fcntl failed");
81*311827fbSnicm 	if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
82*311827fbSnicm 		fatal("fcntl failed");
83*311827fbSnicm 	if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
84*311827fbSnicm 		fatal("fcntl failed");
85*311827fbSnicm 
86*311827fbSnicm 	c = xcalloc(1, sizeof *c);
87*311827fbSnicm 	c->fd = fd;
88*311827fbSnicm 	c->in = buffer_create(BUFSIZ);
89*311827fbSnicm 	c->out = buffer_create(BUFSIZ);
90*311827fbSnicm 
91*311827fbSnicm 	ARRAY_INIT(&c->prompt_hdata);
92*311827fbSnicm 
93*311827fbSnicm 	c->tty.fd = -1;
94*311827fbSnicm 	c->title = NULL;
95*311827fbSnicm 
96*311827fbSnicm 	c->session = NULL;
97*311827fbSnicm 	c->tty.sx = 80;
98*311827fbSnicm 	c->tty.sy = 25;
99*311827fbSnicm 	screen_init(&c->status, c->tty.sx, 1, 0);
100*311827fbSnicm 
101*311827fbSnicm 	c->message_string = NULL;
102*311827fbSnicm 
103*311827fbSnicm 	c->prompt_string = NULL;
104*311827fbSnicm 	c->prompt_buffer = NULL;
105*311827fbSnicm 	c->prompt_index = 0;
106*311827fbSnicm 
107*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
108*311827fbSnicm 		if (ARRAY_ITEM(&clients, i) == NULL) {
109*311827fbSnicm 			ARRAY_SET(&clients, i, c);
110*311827fbSnicm 			return (c);
111*311827fbSnicm 		}
112*311827fbSnicm 	}
113*311827fbSnicm 	ARRAY_ADD(&clients, c);
114*311827fbSnicm 	return (c);
115*311827fbSnicm }
116*311827fbSnicm 
117*311827fbSnicm /* Find client index. */
118*311827fbSnicm int
119*311827fbSnicm server_client_index(struct client *c)
120*311827fbSnicm {
121*311827fbSnicm 	u_int	i;
122*311827fbSnicm 
123*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
124*311827fbSnicm 		if (c == ARRAY_ITEM(&clients, i))
125*311827fbSnicm 			return (i);
126*311827fbSnicm 	}
127*311827fbSnicm 	return (-1);
128*311827fbSnicm }
129*311827fbSnicm 
130*311827fbSnicm /* Fork new server. */
131*311827fbSnicm int
132*311827fbSnicm server_start(char *path)
133*311827fbSnicm {
134*311827fbSnicm 	int	pair[2], srv_fd;
135*311827fbSnicm 	char   *cause;
136*311827fbSnicm 	char	rpathbuf[MAXPATHLEN];
137*311827fbSnicm 
138*311827fbSnicm 	/* The first client is special and gets a socketpair; create it. */
139*311827fbSnicm 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
140*311827fbSnicm 		fatal("socketpair failed");
141*311827fbSnicm 
142*311827fbSnicm 	switch (fork()) {
143*311827fbSnicm 	case -1:
144*311827fbSnicm 		fatal("fork failed");
145*311827fbSnicm 	case 0:
146*311827fbSnicm 		break;
147*311827fbSnicm 	default:
148*311827fbSnicm 		close(pair[1]);
149*311827fbSnicm 		return (pair[0]);
150*311827fbSnicm 	}
151*311827fbSnicm 	close(pair[0]);
152*311827fbSnicm 
153*311827fbSnicm 	/*
154*311827fbSnicm 	 * Must daemonise before loading configuration as the PID changes so
155*311827fbSnicm 	 * $TMUX would be wrong for sessions created in the config file.
156*311827fbSnicm 	 */
157*311827fbSnicm 	if (daemon(1, 1) != 0)
158*311827fbSnicm 		fatal("daemon failed");
159*311827fbSnicm 
160*311827fbSnicm 	ARRAY_INIT(&windows);
161*311827fbSnicm 	ARRAY_INIT(&clients);
162*311827fbSnicm 	ARRAY_INIT(&sessions);
163*311827fbSnicm 	key_bindings_init();
164*311827fbSnicm 	utf8_build();
165*311827fbSnicm 
166*311827fbSnicm 	server_locked = 0;
167*311827fbSnicm 	server_password = NULL;
168*311827fbSnicm 	server_activity = time(NULL);
169*311827fbSnicm 
170*311827fbSnicm 	start_time = time(NULL);
171*311827fbSnicm 	socket_path = path;
172*311827fbSnicm 
173*311827fbSnicm 	if (cfg_file != NULL && load_cfg(cfg_file, &cause) != 0) {
174*311827fbSnicm 		log_warnx("%s", cause);
175*311827fbSnicm 		exit(1);
176*311827fbSnicm 	}
177*311827fbSnicm 	logfile("server");
178*311827fbSnicm 
179*311827fbSnicm 	log_debug("server started, pid %ld", (long) getpid());
180*311827fbSnicm 	log_debug("socket path %s", socket_path);
181*311827fbSnicm 
182*311827fbSnicm 	if (realpath(socket_path, rpathbuf) == NULL)
183*311827fbSnicm 		strlcpy(rpathbuf, socket_path, sizeof rpathbuf);
184*311827fbSnicm 	setproctitle("server (%s)", rpathbuf);
185*311827fbSnicm 
186*311827fbSnicm 	srv_fd = server_create_socket();
187*311827fbSnicm 	server_create_client(pair[1]);
188*311827fbSnicm 
189*311827fbSnicm 	exit(server_main(srv_fd));
190*311827fbSnicm }
191*311827fbSnicm 
192*311827fbSnicm /* Create server socket. */
193*311827fbSnicm int
194*311827fbSnicm server_create_socket(void)
195*311827fbSnicm {
196*311827fbSnicm 	struct sockaddr_un	sa;
197*311827fbSnicm 	size_t			size;
198*311827fbSnicm 	mode_t			mask;
199*311827fbSnicm 	int			fd, mode;
200*311827fbSnicm 
201*311827fbSnicm 	memset(&sa, 0, sizeof sa);
202*311827fbSnicm 	sa.sun_family = AF_UNIX;
203*311827fbSnicm 	size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
204*311827fbSnicm 	if (size >= sizeof sa.sun_path) {
205*311827fbSnicm 		errno = ENAMETOOLONG;
206*311827fbSnicm 		fatal("socket failed");
207*311827fbSnicm 	}
208*311827fbSnicm 	unlink(sa.sun_path);
209*311827fbSnicm 
210*311827fbSnicm 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
211*311827fbSnicm 		fatal("socket failed");
212*311827fbSnicm 
213*311827fbSnicm 	mask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
214*311827fbSnicm 	if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
215*311827fbSnicm 		fatal("bind failed");
216*311827fbSnicm 	umask(mask);
217*311827fbSnicm 
218*311827fbSnicm 	if (listen(fd, 16) == -1)
219*311827fbSnicm 		fatal("listen failed");
220*311827fbSnicm 
221*311827fbSnicm 	if ((mode = fcntl(fd, F_GETFL)) == -1)
222*311827fbSnicm 		fatal("fcntl failed");
223*311827fbSnicm 	if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
224*311827fbSnicm 		fatal("fcntl failed");
225*311827fbSnicm 	if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
226*311827fbSnicm 		fatal("fcntl failed");
227*311827fbSnicm 
228*311827fbSnicm 	return (fd);
229*311827fbSnicm }
230*311827fbSnicm 
231*311827fbSnicm /* Main server loop. */
232*311827fbSnicm int
233*311827fbSnicm server_main(int srv_fd)
234*311827fbSnicm {
235*311827fbSnicm 	struct window	*w;
236*311827fbSnicm 	struct pollfd	*pfds, *pfd;
237*311827fbSnicm 	int		 nfds, xtimeout;
238*311827fbSnicm 	u_int		 i, n;
239*311827fbSnicm 	time_t		 now, last;
240*311827fbSnicm 
241*311827fbSnicm 	siginit();
242*311827fbSnicm 
243*311827fbSnicm 	last = time(NULL);
244*311827fbSnicm 
245*311827fbSnicm 	pfds = NULL;
246*311827fbSnicm 	for (;;) {
247*311827fbSnicm 		/* If sigterm, kill all windows and clients. */
248*311827fbSnicm 		if (sigterm)
249*311827fbSnicm 			server_shutdown();
250*311827fbSnicm 
251*311827fbSnicm 		/* Handle child exit. */
252*311827fbSnicm 		if (sigchld) {
253*311827fbSnicm 			server_child_signal();
254*311827fbSnicm 			sigchld = 0;
255*311827fbSnicm 		}
256*311827fbSnicm 
257*311827fbSnicm 		/* Recreate socket on SIGUSR1. */
258*311827fbSnicm 		if (sigusr1) {
259*311827fbSnicm 			close(srv_fd);
260*311827fbSnicm 			srv_fd = server_create_socket();
261*311827fbSnicm 			sigusr1 = 0;
262*311827fbSnicm 		}
263*311827fbSnicm 
264*311827fbSnicm 		/* Initialise pollfd array. */
265*311827fbSnicm 		nfds = 1;
266*311827fbSnicm 		for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
267*311827fbSnicm 			w = ARRAY_ITEM(&windows, i);
268*311827fbSnicm 			if (w != NULL)
269*311827fbSnicm 				nfds += window_count_panes(w);
270*311827fbSnicm 		}
271*311827fbSnicm 		nfds += ARRAY_LENGTH(&clients) * 2;
272*311827fbSnicm 		pfds = xrealloc(pfds, nfds, sizeof *pfds);
273*311827fbSnicm 		memset(pfds, 0, nfds * sizeof *pfds);
274*311827fbSnicm 		pfd = pfds;
275*311827fbSnicm 
276*311827fbSnicm 		/* Fill server socket. */
277*311827fbSnicm 		pfd->fd = srv_fd;
278*311827fbSnicm 		pfd->events = POLLIN;
279*311827fbSnicm 		pfd++;
280*311827fbSnicm 
281*311827fbSnicm 		/* Fill window and client sockets. */
282*311827fbSnicm 		server_fill_windows(&pfd);
283*311827fbSnicm 		server_fill_clients(&pfd);
284*311827fbSnicm 
285*311827fbSnicm 		/* Update socket permissions. */
286*311827fbSnicm 		xtimeout = INFTIM;
287*311827fbSnicm 		if (sigterm || server_update_socket() != 0)
288*311827fbSnicm 			xtimeout = POLL_TIMEOUT;
289*311827fbSnicm 
290*311827fbSnicm 		/* Do the poll. */
291*311827fbSnicm 		if ((nfds = poll(pfds, nfds, xtimeout)) == -1) {
292*311827fbSnicm 			if (errno == EAGAIN || errno == EINTR)
293*311827fbSnicm 				continue;
294*311827fbSnicm 			fatal("poll failed");
295*311827fbSnicm 		}
296*311827fbSnicm 		pfd = pfds;
297*311827fbSnicm 
298*311827fbSnicm 		/* Handle server socket. */
299*311827fbSnicm 		if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP))
300*311827fbSnicm 			fatalx("lost server socket");
301*311827fbSnicm 		if (pfd->revents & POLLIN) {
302*311827fbSnicm 			server_accept_client(srv_fd);
303*311827fbSnicm 			continue;
304*311827fbSnicm 		}
305*311827fbSnicm 		pfd++;
306*311827fbSnicm 
307*311827fbSnicm 		/* Call second-based timers. */
308*311827fbSnicm 		now = time(NULL);
309*311827fbSnicm 		if (now != last) {
310*311827fbSnicm 			last = now;
311*311827fbSnicm 			server_second_timers();
312*311827fbSnicm 		}
313*311827fbSnicm 
314*311827fbSnicm 		/* Set window names. */
315*311827fbSnicm 		set_window_names();
316*311827fbSnicm 
317*311827fbSnicm 		/*
318*311827fbSnicm 		 * Handle window and client sockets. Clients can create
319*311827fbSnicm 		 * windows, so windows must come first to avoid messing up by
320*311827fbSnicm 		 * increasing the array size.
321*311827fbSnicm 		 */
322*311827fbSnicm 		server_handle_windows(&pfd);
323*311827fbSnicm 		server_handle_clients(&pfd);
324*311827fbSnicm 
325*311827fbSnicm 		/*
326*311827fbSnicm 		 * If we have no sessions and clients left, let's get out
327*311827fbSnicm 		 * of here...
328*311827fbSnicm 		 */
329*311827fbSnicm 		n = 0;
330*311827fbSnicm 		for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
331*311827fbSnicm 			if (ARRAY_ITEM(&sessions, i) != NULL)
332*311827fbSnicm 				n++;
333*311827fbSnicm 		}
334*311827fbSnicm 		for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
335*311827fbSnicm 			if (ARRAY_ITEM(&clients, i) != NULL)
336*311827fbSnicm 				n++;
337*311827fbSnicm 		}
338*311827fbSnicm 		if (n == 0)
339*311827fbSnicm 			break;
340*311827fbSnicm 	}
341*311827fbSnicm 	if (pfds != NULL)
342*311827fbSnicm 		xfree(pfds);
343*311827fbSnicm 
344*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
345*311827fbSnicm 		if (ARRAY_ITEM(&sessions, i) != NULL)
346*311827fbSnicm 			session_destroy(ARRAY_ITEM(&sessions, i));
347*311827fbSnicm 	}
348*311827fbSnicm 	ARRAY_FREE(&sessions);
349*311827fbSnicm 
350*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
351*311827fbSnicm 		if (ARRAY_ITEM(&clients, i) != NULL)
352*311827fbSnicm 			server_lost_client(ARRAY_ITEM(&clients, i));
353*311827fbSnicm 	}
354*311827fbSnicm 	ARRAY_FREE(&clients);
355*311827fbSnicm 
356*311827fbSnicm 	key_bindings_free();
357*311827fbSnicm 
358*311827fbSnicm 	close(srv_fd);
359*311827fbSnicm 
360*311827fbSnicm 	unlink(socket_path);
361*311827fbSnicm 	xfree(socket_path);
362*311827fbSnicm 
363*311827fbSnicm 	options_free(&global_options);
364*311827fbSnicm 	options_free(&global_window_options);
365*311827fbSnicm 	if (server_password != NULL)
366*311827fbSnicm 		xfree(server_password);
367*311827fbSnicm 
368*311827fbSnicm 	return (0);
369*311827fbSnicm }
370*311827fbSnicm 
371*311827fbSnicm /* Kill all clients. */
372*311827fbSnicm void
373*311827fbSnicm server_shutdown(void)
374*311827fbSnicm {
375*311827fbSnicm 	struct session	*s;
376*311827fbSnicm 	struct client	*c;
377*311827fbSnicm 	u_int		 i, j;
378*311827fbSnicm 
379*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
380*311827fbSnicm 		s = ARRAY_ITEM(&sessions, i);
381*311827fbSnicm 		for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
382*311827fbSnicm 			c = ARRAY_ITEM(&clients, j);
383*311827fbSnicm 			if (c != NULL && c->session == s) {
384*311827fbSnicm 				s = NULL;
385*311827fbSnicm 				break;
386*311827fbSnicm 			}
387*311827fbSnicm 		}
388*311827fbSnicm 		if (s != NULL)
389*311827fbSnicm 			session_destroy(s);
390*311827fbSnicm 	}
391*311827fbSnicm 
392*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
393*311827fbSnicm 		c = ARRAY_ITEM(&clients, i);
394*311827fbSnicm 		if (c != NULL)
395*311827fbSnicm 			server_write_client(c, MSG_SHUTDOWN, NULL, 0);
396*311827fbSnicm 	}
397*311827fbSnicm }
398*311827fbSnicm 
399*311827fbSnicm /* Handle SIGCHLD. */
400*311827fbSnicm void
401*311827fbSnicm server_child_signal(void)
402*311827fbSnicm {
403*311827fbSnicm 	struct window		*w;
404*311827fbSnicm 	struct window_pane	*wp;
405*311827fbSnicm 	int		 	 status;
406*311827fbSnicm 	pid_t		 	 pid;
407*311827fbSnicm 	u_int		 	 i;
408*311827fbSnicm 
409*311827fbSnicm 	for (;;) {
410*311827fbSnicm 		switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) {
411*311827fbSnicm 		case -1:
412*311827fbSnicm 			if (errno == ECHILD)
413*311827fbSnicm 				return;
414*311827fbSnicm 			fatal("waitpid");
415*311827fbSnicm 		case 0:
416*311827fbSnicm 			return;
417*311827fbSnicm 		}
418*311827fbSnicm 		if (!WIFSTOPPED(status))
419*311827fbSnicm 			continue;
420*311827fbSnicm 		if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
421*311827fbSnicm 			continue;
422*311827fbSnicm 
423*311827fbSnicm 		for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
424*311827fbSnicm 			w = ARRAY_ITEM(&windows, i);
425*311827fbSnicm 			if (w == NULL)
426*311827fbSnicm 				continue;
427*311827fbSnicm 			TAILQ_FOREACH(wp, &w->panes, entry) {
428*311827fbSnicm 				if (wp->pid == pid) {
429*311827fbSnicm 					if (killpg(pid, SIGCONT) != 0)
430*311827fbSnicm 						kill(pid, SIGCONT);
431*311827fbSnicm 				}
432*311827fbSnicm 			}
433*311827fbSnicm 		}
434*311827fbSnicm 	}
435*311827fbSnicm }
436*311827fbSnicm 
437*311827fbSnicm /* Fill window pollfds. */
438*311827fbSnicm void
439*311827fbSnicm server_fill_windows(struct pollfd **pfd)
440*311827fbSnicm {
441*311827fbSnicm 	struct window		*w;
442*311827fbSnicm 	struct window_pane	*wp;
443*311827fbSnicm 	u_int		 	 i;
444*311827fbSnicm 
445*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
446*311827fbSnicm 		w = ARRAY_ITEM(&windows, i);
447*311827fbSnicm 		if (w == NULL)
448*311827fbSnicm 			continue;
449*311827fbSnicm 
450*311827fbSnicm 		TAILQ_FOREACH(wp, &w->panes, entry) {
451*311827fbSnicm 			(*pfd)->fd = wp->fd;
452*311827fbSnicm 			if (wp->fd != -1) {
453*311827fbSnicm 				(*pfd)->events = POLLIN;
454*311827fbSnicm 				if (BUFFER_USED(wp->out) > 0)
455*311827fbSnicm 					(*pfd)->events |= POLLOUT;
456*311827fbSnicm 			}
457*311827fbSnicm 			(*pfd)++;
458*311827fbSnicm 		}
459*311827fbSnicm 	}
460*311827fbSnicm }
461*311827fbSnicm 
462*311827fbSnicm /* Handle window pollfds. */
463*311827fbSnicm void
464*311827fbSnicm server_handle_windows(struct pollfd **pfd)
465*311827fbSnicm {
466*311827fbSnicm 	struct window		*w;
467*311827fbSnicm 	struct window_pane	*wp;
468*311827fbSnicm 	u_int		 	 i;
469*311827fbSnicm 
470*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
471*311827fbSnicm 		w = ARRAY_ITEM(&windows, i);
472*311827fbSnicm 		if (w == NULL)
473*311827fbSnicm 			continue;
474*311827fbSnicm 
475*311827fbSnicm 		TAILQ_FOREACH(wp, &w->panes, entry) {
476*311827fbSnicm 			if (wp->fd != -1) {
477*311827fbSnicm 				if (buffer_poll(*pfd, wp->in, wp->out) != 0) {
478*311827fbSnicm 					close(wp->fd);
479*311827fbSnicm 					wp->fd = -1;
480*311827fbSnicm 				} else
481*311827fbSnicm 					server_handle_window(w, wp);
482*311827fbSnicm 			}
483*311827fbSnicm 			(*pfd)++;
484*311827fbSnicm 		}
485*311827fbSnicm 
486*311827fbSnicm 		server_check_window(w);
487*311827fbSnicm 	}
488*311827fbSnicm }
489*311827fbSnicm 
490*311827fbSnicm /* Check for general redraw on client. */
491*311827fbSnicm void
492*311827fbSnicm server_check_redraw(struct client *c)
493*311827fbSnicm {
494*311827fbSnicm 	struct session		*s;
495*311827fbSnicm 	struct window_pane	*wp;
496*311827fbSnicm 	char		 	 title[512];
497*311827fbSnicm 	int		 	 flags, redraw;
498*311827fbSnicm 
499*311827fbSnicm 	if (c == NULL || c->session == NULL)
500*311827fbSnicm 		return;
501*311827fbSnicm 	s = c->session;
502*311827fbSnicm 
503*311827fbSnicm 	flags = c->tty.flags & TTY_FREEZE;
504*311827fbSnicm 	c->tty.flags &= ~TTY_FREEZE;
505*311827fbSnicm 
506*311827fbSnicm 	if (options_get_number(&s->options, "set-titles")) {
507*311827fbSnicm 		xsnprintf(title, sizeof title, "%s:%u:%s - \"%s\"",
508*311827fbSnicm 		    s->name, s->curw->idx, s->curw->window->name,
509*311827fbSnicm 		    s->curw->window->active->screen->title);
510*311827fbSnicm 		if (c->title == NULL || strcmp(title, c->title) != 0) {
511*311827fbSnicm 			if (c->title != NULL)
512*311827fbSnicm 				xfree(c->title);
513*311827fbSnicm 			c->title = xstrdup(title);
514*311827fbSnicm 			tty_set_title(&c->tty, c->title);
515*311827fbSnicm 		}
516*311827fbSnicm 	}
517*311827fbSnicm 
518*311827fbSnicm 	if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
519*311827fbSnicm 		if (c->message_string != NULL)
520*311827fbSnicm 			redraw = status_message_redraw(c);
521*311827fbSnicm 		else if (c->prompt_string != NULL)
522*311827fbSnicm 			redraw = status_prompt_redraw(c);
523*311827fbSnicm 		else
524*311827fbSnicm 			redraw = status_redraw(c);
525*311827fbSnicm 		if (!redraw)
526*311827fbSnicm 			c->flags &= ~CLIENT_STATUS;
527*311827fbSnicm 	}
528*311827fbSnicm 
529*311827fbSnicm 	if (c->flags & CLIENT_REDRAW) {
530*311827fbSnicm 		if (server_locked)
531*311827fbSnicm 			server_redraw_locked(c);
532*311827fbSnicm 		else
533*311827fbSnicm  			screen_redraw_screen(c);
534*311827fbSnicm 		c->flags &= ~CLIENT_STATUS;
535*311827fbSnicm 	} else {
536*311827fbSnicm 		TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
537*311827fbSnicm 			if (wp->flags & PANE_REDRAW)
538*311827fbSnicm 				screen_redraw_pane(c, wp);
539*311827fbSnicm 		}
540*311827fbSnicm 	}
541*311827fbSnicm 
542*311827fbSnicm 	if (c->flags & CLIENT_STATUS)
543*311827fbSnicm 		screen_redraw_status(c);
544*311827fbSnicm 
545*311827fbSnicm 	c->tty.flags |= flags;
546*311827fbSnicm 
547*311827fbSnicm 	c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS);
548*311827fbSnicm }
549*311827fbSnicm 
550*311827fbSnicm /* Redraw client when locked. */
551*311827fbSnicm void
552*311827fbSnicm server_redraw_locked(struct client *c)
553*311827fbSnicm {
554*311827fbSnicm 	struct screen_write_ctx	ctx;
555*311827fbSnicm 	struct screen		screen;
556*311827fbSnicm 	u_int			colour, xx, yy, i;
557*311827fbSnicm 	int    			style;
558*311827fbSnicm 
559*311827fbSnicm 	xx = c->tty.sx;
560*311827fbSnicm 	yy = c->tty.sy - 1;
561*311827fbSnicm 	if (xx == 0 || yy == 0)
562*311827fbSnicm 		return;
563*311827fbSnicm 	colour = options_get_number(
564*311827fbSnicm 	    &global_window_options, "clock-mode-colour");
565*311827fbSnicm 	style = options_get_number(
566*311827fbSnicm 	    &global_window_options, "clock-mode-style");
567*311827fbSnicm 
568*311827fbSnicm 	screen_init(&screen, xx, yy, 0);
569*311827fbSnicm 
570*311827fbSnicm 	screen_write_start(&ctx, NULL, &screen);
571*311827fbSnicm 	clock_draw(&ctx, colour, style);
572*311827fbSnicm 	screen_write_stop(&ctx);
573*311827fbSnicm 
574*311827fbSnicm 	for (i = 0; i < screen_size_y(&screen); i++)
575*311827fbSnicm 		tty_draw_line(&c->tty, &screen, i, 0, 0);
576*311827fbSnicm 	screen_redraw_status(c);
577*311827fbSnicm 
578*311827fbSnicm 	screen_free(&screen);
579*311827fbSnicm }
580*311827fbSnicm 
581*311827fbSnicm /* Check for timers on client. */
582*311827fbSnicm void
583*311827fbSnicm server_check_timers(struct client *c)
584*311827fbSnicm {
585*311827fbSnicm 	struct session	*s;
586*311827fbSnicm 	struct timeval	 tv;
587*311827fbSnicm 	u_int		 interval;
588*311827fbSnicm 
589*311827fbSnicm 	if (c == NULL || c->session == NULL)
590*311827fbSnicm 		return;
591*311827fbSnicm 	s = c->session;
592*311827fbSnicm 
593*311827fbSnicm 	if (gettimeofday(&tv, NULL) != 0)
594*311827fbSnicm 		fatal("gettimeofday");
595*311827fbSnicm 
596*311827fbSnicm 	if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >))
597*311827fbSnicm 		status_message_clear(c);
598*311827fbSnicm 
599*311827fbSnicm 	if (c->message_string != NULL || c->prompt_string != NULL) {
600*311827fbSnicm 		/*
601*311827fbSnicm 		 * Don't need timed redraw for messages/prompts so bail now.
602*311827fbSnicm 		 * The status timer isn't reset when they are redrawn anyway.
603*311827fbSnicm 		 */
604*311827fbSnicm 		return;
605*311827fbSnicm 	}
606*311827fbSnicm 	if (!options_get_number(&s->options, "status"))
607*311827fbSnicm 		return;
608*311827fbSnicm 
609*311827fbSnicm 	/* Check timer; resolution is only a second so don't be too clever. */
610*311827fbSnicm 	interval = options_get_number(&s->options, "status-interval");
611*311827fbSnicm 	if (interval == 0)
612*311827fbSnicm 		return;
613*311827fbSnicm 	if (tv.tv_sec < c->status_timer.tv_sec ||
614*311827fbSnicm 	    ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval)
615*311827fbSnicm 		c->flags |= CLIENT_STATUS;
616*311827fbSnicm }
617*311827fbSnicm 
618*311827fbSnicm /* Fill client pollfds. */
619*311827fbSnicm void
620*311827fbSnicm server_fill_clients(struct pollfd **pfd)
621*311827fbSnicm {
622*311827fbSnicm 	struct client		*c;
623*311827fbSnicm 	struct window		*w;
624*311827fbSnicm 	struct window_pane	*wp;
625*311827fbSnicm 	u_int		 	 i;
626*311827fbSnicm 
627*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
628*311827fbSnicm 		c = ARRAY_ITEM(&clients, i);
629*311827fbSnicm 
630*311827fbSnicm 		server_check_timers(c);
631*311827fbSnicm 		server_check_redraw(c);
632*311827fbSnicm 
633*311827fbSnicm 		if (c == NULL)
634*311827fbSnicm 			(*pfd)->fd = -1;
635*311827fbSnicm 		else {
636*311827fbSnicm 			(*pfd)->fd = c->fd;
637*311827fbSnicm 			(*pfd)->events = POLLIN;
638*311827fbSnicm 			if (BUFFER_USED(c->out) > 0)
639*311827fbSnicm 				(*pfd)->events |= POLLOUT;
640*311827fbSnicm 		}
641*311827fbSnicm 		(*pfd)++;
642*311827fbSnicm 
643*311827fbSnicm 		if (c == NULL || c->flags & CLIENT_SUSPENDED ||
644*311827fbSnicm 		    c->tty.fd == -1 || c->session == NULL)
645*311827fbSnicm 			(*pfd)->fd = -1;
646*311827fbSnicm 		else {
647*311827fbSnicm 			(*pfd)->fd = c->tty.fd;
648*311827fbSnicm 			(*pfd)->events = POLLIN;
649*311827fbSnicm 			if (BUFFER_USED(c->tty.out) > 0)
650*311827fbSnicm 				(*pfd)->events |= POLLOUT;
651*311827fbSnicm 		}
652*311827fbSnicm 		(*pfd)++;
653*311827fbSnicm 	}
654*311827fbSnicm 
655*311827fbSnicm 	/*
656*311827fbSnicm 	 * Clear any window redraw flags (will have been redrawn as part of
657*311827fbSnicm 	 * client).
658*311827fbSnicm 	 */
659*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
660*311827fbSnicm 		w = ARRAY_ITEM(&windows, i);
661*311827fbSnicm 		if (w == NULL)
662*311827fbSnicm 			continue;
663*311827fbSnicm 
664*311827fbSnicm 		w->flags &= ~WINDOW_REDRAW;
665*311827fbSnicm 		TAILQ_FOREACH(wp, &w->panes, entry)
666*311827fbSnicm 			wp->flags &= ~PANE_REDRAW;
667*311827fbSnicm 	}
668*311827fbSnicm }
669*311827fbSnicm 
670*311827fbSnicm /* Handle client pollfds. */
671*311827fbSnicm void
672*311827fbSnicm server_handle_clients(struct pollfd **pfd)
673*311827fbSnicm {
674*311827fbSnicm 	struct client	*c;
675*311827fbSnicm 	u_int		 i;
676*311827fbSnicm 
677*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
678*311827fbSnicm 		c = ARRAY_ITEM(&clients, i);
679*311827fbSnicm 
680*311827fbSnicm 		if (c != NULL) {
681*311827fbSnicm 			if (buffer_poll(*pfd, c->in, c->out) != 0) {
682*311827fbSnicm 				server_lost_client(c);
683*311827fbSnicm 				(*pfd) += 2;
684*311827fbSnicm 				continue;
685*311827fbSnicm 			} else
686*311827fbSnicm 				server_msg_dispatch(c);
687*311827fbSnicm 		}
688*311827fbSnicm 		(*pfd)++;
689*311827fbSnicm 
690*311827fbSnicm 		if (c != NULL && !(c->flags & CLIENT_SUSPENDED) &&
691*311827fbSnicm 		    c->tty.fd != -1 && c->session != NULL) {
692*311827fbSnicm 			if (buffer_poll(*pfd, c->tty.in, c->tty.out) != 0)
693*311827fbSnicm 				server_lost_client(c);
694*311827fbSnicm 			else
695*311827fbSnicm 				server_handle_client(c);
696*311827fbSnicm 		}
697*311827fbSnicm 		(*pfd)++;
698*311827fbSnicm 	}
699*311827fbSnicm }
700*311827fbSnicm 
701*311827fbSnicm /* accept(2) and create new client. */
702*311827fbSnicm struct client *
703*311827fbSnicm server_accept_client(int srv_fd)
704*311827fbSnicm {
705*311827fbSnicm 	struct sockaddr_storage	sa;
706*311827fbSnicm 	socklen_t		slen = sizeof sa;
707*311827fbSnicm 	int			fd;
708*311827fbSnicm 
709*311827fbSnicm 	fd = accept(srv_fd, (struct sockaddr *) &sa, &slen);
710*311827fbSnicm 	if (fd == -1) {
711*311827fbSnicm 		if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
712*311827fbSnicm 			return (NULL);
713*311827fbSnicm 		fatal("accept failed");
714*311827fbSnicm 	}
715*311827fbSnicm 	if (sigterm) {
716*311827fbSnicm 		close(fd);
717*311827fbSnicm 		return (NULL);
718*311827fbSnicm 	}
719*311827fbSnicm 	return (server_create_client(fd));
720*311827fbSnicm }
721*311827fbSnicm 
722*311827fbSnicm /* Input data from client. */
723*311827fbSnicm void
724*311827fbSnicm server_handle_client(struct client *c)
725*311827fbSnicm {
726*311827fbSnicm 	struct window_pane	*wp;
727*311827fbSnicm 	struct screen		*s;
728*311827fbSnicm 	struct timeval	 	 tv;
729*311827fbSnicm 	struct key_binding	*bd;
730*311827fbSnicm 	int		 	 key, prefix, status, xtimeout;
731*311827fbSnicm 	int			 mode;
732*311827fbSnicm 	u_char			 mouse[3];
733*311827fbSnicm 
734*311827fbSnicm 	xtimeout = options_get_number(&c->session->options, "repeat-time");
735*311827fbSnicm 	if (xtimeout != 0 && c->flags & CLIENT_REPEAT) {
736*311827fbSnicm 		if (gettimeofday(&tv, NULL) != 0)
737*311827fbSnicm 			fatal("gettimeofday");
738*311827fbSnicm 		if (timercmp(&tv, &c->repeat_timer, >))
739*311827fbSnicm 			c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
740*311827fbSnicm 	}
741*311827fbSnicm 
742*311827fbSnicm 	/* Process keys. */
743*311827fbSnicm 	prefix = options_get_number(&c->session->options, "prefix");
744*311827fbSnicm 	while (tty_keys_next(&c->tty, &key, mouse) == 0) {
745*311827fbSnicm 		server_activity = time(NULL);
746*311827fbSnicm 
747*311827fbSnicm 		if (c->session == NULL)
748*311827fbSnicm 			return;
749*311827fbSnicm 		wp = c->session->curw->window->active;	/* could die */
750*311827fbSnicm 
751*311827fbSnicm 		status_message_clear(c);
752*311827fbSnicm 		if (c->prompt_string != NULL) {
753*311827fbSnicm 			status_prompt_key(c, key);
754*311827fbSnicm 			continue;
755*311827fbSnicm 		}
756*311827fbSnicm 		if (server_locked)
757*311827fbSnicm 			continue;
758*311827fbSnicm 
759*311827fbSnicm 		/* Check for mouse keys. */
760*311827fbSnicm 		if (key == KEYC_MOUSE) {
761*311827fbSnicm 			window_pane_mouse(wp, c, mouse[0], mouse[1], mouse[2]);
762*311827fbSnicm 			continue;
763*311827fbSnicm 		}
764*311827fbSnicm 
765*311827fbSnicm 		/* No previous prefix key. */
766*311827fbSnicm 		if (!(c->flags & CLIENT_PREFIX)) {
767*311827fbSnicm 			if (key == prefix)
768*311827fbSnicm 				c->flags |= CLIENT_PREFIX;
769*311827fbSnicm 			else
770*311827fbSnicm 				window_pane_key(wp, c, key);
771*311827fbSnicm 			continue;
772*311827fbSnicm 		}
773*311827fbSnicm 
774*311827fbSnicm 		/* Prefix key already pressed. Reset prefix and lookup key. */
775*311827fbSnicm 		c->flags &= ~CLIENT_PREFIX;
776*311827fbSnicm 		if ((bd = key_bindings_lookup(key)) == NULL) {
777*311827fbSnicm 			/* If repeating, treat this as a key, else ignore. */
778*311827fbSnicm 			if (c->flags & CLIENT_REPEAT) {
779*311827fbSnicm 				c->flags &= ~CLIENT_REPEAT;
780*311827fbSnicm 				if (key == prefix)
781*311827fbSnicm 					c->flags |= CLIENT_PREFIX;
782*311827fbSnicm 				else
783*311827fbSnicm 					window_pane_key(wp, c, key);
784*311827fbSnicm 			}
785*311827fbSnicm 			continue;
786*311827fbSnicm 		}
787*311827fbSnicm 
788*311827fbSnicm 		/* If already repeating, but this key can't repeat, skip it. */
789*311827fbSnicm 		if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
790*311827fbSnicm 			c->flags &= ~CLIENT_REPEAT;
791*311827fbSnicm 			if (key == prefix)
792*311827fbSnicm 				c->flags |= CLIENT_PREFIX;
793*311827fbSnicm 			else
794*311827fbSnicm 				window_pane_key(wp, c, key);
795*311827fbSnicm 			continue;
796*311827fbSnicm 		}
797*311827fbSnicm 
798*311827fbSnicm 		/* If this key can repeat, reset the repeat flags and timer. */
799*311827fbSnicm 		if (xtimeout != 0 && bd->can_repeat) {
800*311827fbSnicm 			c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
801*311827fbSnicm 
802*311827fbSnicm 			tv.tv_sec = xtimeout / 1000;
803*311827fbSnicm 			tv.tv_usec = (xtimeout % 1000) * 1000L;
804*311827fbSnicm 			if (gettimeofday(&c->repeat_timer, NULL) != 0)
805*311827fbSnicm 				fatal("gettimeofday");
806*311827fbSnicm 			timeradd(&c->repeat_timer, &tv, &c->repeat_timer);
807*311827fbSnicm 		}
808*311827fbSnicm 
809*311827fbSnicm 		/* Dispatch the command. */
810*311827fbSnicm 		key_bindings_dispatch(bd, c);
811*311827fbSnicm 	}
812*311827fbSnicm 	if (c->session == NULL)
813*311827fbSnicm 		return;
814*311827fbSnicm 	wp = c->session->curw->window->active;	/* could die - do each loop */
815*311827fbSnicm 	s = wp->screen;
816*311827fbSnicm 
817*311827fbSnicm 	/* Ensure cursor position and mode settings. */
818*311827fbSnicm 	status = options_get_number(&c->session->options, "status");
819*311827fbSnicm 	if (wp->yoff + s->cy < c->tty.sy - status)
820*311827fbSnicm 		tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff);
821*311827fbSnicm 
822*311827fbSnicm 	mode = s->mode;
823*311827fbSnicm 	if (server_locked)
824*311827fbSnicm 		mode &= ~TTY_NOCURSOR;
825*311827fbSnicm 	tty_update_mode(&c->tty, mode);
826*311827fbSnicm }
827*311827fbSnicm 
828*311827fbSnicm /* Lost a client. */
829*311827fbSnicm void
830*311827fbSnicm server_lost_client(struct client *c)
831*311827fbSnicm {
832*311827fbSnicm 	u_int	i;
833*311827fbSnicm 
834*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
835*311827fbSnicm 		if (ARRAY_ITEM(&clients, i) == c)
836*311827fbSnicm 			ARRAY_SET(&clients, i, NULL);
837*311827fbSnicm 	}
838*311827fbSnicm 
839*311827fbSnicm 	tty_free(&c->tty, c->flags & CLIENT_SUSPENDED);
840*311827fbSnicm 
841*311827fbSnicm 	screen_free(&c->status);
842*311827fbSnicm 
843*311827fbSnicm 	if (c->title != NULL)
844*311827fbSnicm 		xfree(c->title);
845*311827fbSnicm 
846*311827fbSnicm 	if (c->message_string != NULL)
847*311827fbSnicm 		xfree(c->message_string);
848*311827fbSnicm 
849*311827fbSnicm 	if (c->prompt_string != NULL)
850*311827fbSnicm 		xfree(c->prompt_string);
851*311827fbSnicm 	if (c->prompt_buffer != NULL)
852*311827fbSnicm 		xfree(c->prompt_buffer);
853*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++)
854*311827fbSnicm 		xfree(ARRAY_ITEM(&c->prompt_hdata, i));
855*311827fbSnicm 	ARRAY_FREE(&c->prompt_hdata);
856*311827fbSnicm 
857*311827fbSnicm 	if (c->cwd != NULL)
858*311827fbSnicm 		xfree(c->cwd);
859*311827fbSnicm 
860*311827fbSnicm 	close(c->fd);
861*311827fbSnicm 	buffer_destroy(c->in);
862*311827fbSnicm 	buffer_destroy(c->out);
863*311827fbSnicm 	xfree(c);
864*311827fbSnicm 
865*311827fbSnicm 	recalculate_sizes();
866*311827fbSnicm }
867*311827fbSnicm 
868*311827fbSnicm /* Handle window data. */
869*311827fbSnicm void
870*311827fbSnicm server_handle_window(struct window *w, struct window_pane *wp)
871*311827fbSnicm {
872*311827fbSnicm 	struct session	*s;
873*311827fbSnicm 	u_int		 i;
874*311827fbSnicm 	int		 update;
875*311827fbSnicm 
876*311827fbSnicm 	window_pane_parse(wp);
877*311827fbSnicm 
878*311827fbSnicm 	if ((w->flags & (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT)) == 0)
879*311827fbSnicm 		return;
880*311827fbSnicm 
881*311827fbSnicm 	update = 0;
882*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
883*311827fbSnicm 		s = ARRAY_ITEM(&sessions, i);
884*311827fbSnicm 		if (s == NULL || !session_has(s, w))
885*311827fbSnicm 			continue;
886*311827fbSnicm 
887*311827fbSnicm 		update += server_check_window_bell(s, w, wp);
888*311827fbSnicm 		update += server_check_window_activity(s, w);
889*311827fbSnicm 		update += server_check_window_content(s, w, wp);
890*311827fbSnicm 	}
891*311827fbSnicm 	if (update)
892*311827fbSnicm 		server_status_window(w);
893*311827fbSnicm 
894*311827fbSnicm 	w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT);
895*311827fbSnicm }
896*311827fbSnicm 
897*311827fbSnicm int
898*311827fbSnicm server_check_window_bell(
899*311827fbSnicm     struct session *s, struct window *w, struct window_pane *wp)
900*311827fbSnicm {
901*311827fbSnicm 	struct client	*c;
902*311827fbSnicm 	u_int		 i;
903*311827fbSnicm 	int		 action;
904*311827fbSnicm 
905*311827fbSnicm 	if (!(w->flags & WINDOW_BELL))
906*311827fbSnicm 		return (0);
907*311827fbSnicm 	if (session_alert_has_window(s, w, WINDOW_BELL))
908*311827fbSnicm 		return (0);
909*311827fbSnicm 	session_alert_add(s, w, WINDOW_BELL);
910*311827fbSnicm 
911*311827fbSnicm 	action = options_get_number(&s->options, "bell-action");
912*311827fbSnicm 	switch (action) {
913*311827fbSnicm 	case BELL_ANY:
914*311827fbSnicm 		if (s->flags & SESSION_UNATTACHED)
915*311827fbSnicm 			break;
916*311827fbSnicm 		for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
917*311827fbSnicm 			c = ARRAY_ITEM(&clients, i);
918*311827fbSnicm 			if (c != NULL && c->session == s)
919*311827fbSnicm 				tty_putcode(&c->tty, TTYC_BEL);
920*311827fbSnicm 		}
921*311827fbSnicm 		break;
922*311827fbSnicm 	case BELL_CURRENT:
923*311827fbSnicm 		if (w->active != wp)
924*311827fbSnicm 			break;
925*311827fbSnicm 		for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
926*311827fbSnicm 			c = ARRAY_ITEM(&clients, i);
927*311827fbSnicm 			if (c != NULL && c->session == s)
928*311827fbSnicm 				tty_putcode(&c->tty, TTYC_BEL);
929*311827fbSnicm 		}
930*311827fbSnicm 		break;
931*311827fbSnicm 	}
932*311827fbSnicm 	return (1);
933*311827fbSnicm }
934*311827fbSnicm 
935*311827fbSnicm int
936*311827fbSnicm server_check_window_activity(struct session *s, struct window *w)
937*311827fbSnicm {
938*311827fbSnicm 	if (!(w->flags & WINDOW_ACTIVITY))
939*311827fbSnicm 		return (0);
940*311827fbSnicm 	if (!options_get_number(&w->options, "monitor-activity"))
941*311827fbSnicm 		return (0);
942*311827fbSnicm 	if (session_alert_has_window(s, w, WINDOW_ACTIVITY))
943*311827fbSnicm 		return (0);
944*311827fbSnicm 	session_alert_add(s, w, WINDOW_ACTIVITY);
945*311827fbSnicm 	return (1);
946*311827fbSnicm }
947*311827fbSnicm 
948*311827fbSnicm int
949*311827fbSnicm server_check_window_content(
950*311827fbSnicm     struct session *s, struct window *w, struct window_pane *wp)
951*311827fbSnicm {
952*311827fbSnicm 	char	*found, *ptr;
953*311827fbSnicm 
954*311827fbSnicm 	if (!(w->flags & WINDOW_CONTENT))
955*311827fbSnicm 		return (0);
956*311827fbSnicm 	if ((ptr = options_get_string(&w->options, "monitor-content")) == NULL)
957*311827fbSnicm 		return (0);
958*311827fbSnicm 	if (*ptr == '\0')
959*311827fbSnicm 		return (0);
960*311827fbSnicm 	if (session_alert_has_window(s, w, WINDOW_CONTENT))
961*311827fbSnicm 		return (0);
962*311827fbSnicm 	if ((found = window_pane_search(wp, ptr)) == NULL)
963*311827fbSnicm 		return (0);
964*311827fbSnicm 	session_alert_add(s, w, WINDOW_CONTENT);
965*311827fbSnicm     	xfree(found);
966*311827fbSnicm 	return (1);
967*311827fbSnicm }
968*311827fbSnicm 
969*311827fbSnicm /* Check if window still exists.. */
970*311827fbSnicm void
971*311827fbSnicm server_check_window(struct window *w)
972*311827fbSnicm {
973*311827fbSnicm 	struct window_pane	*wp, *wq;
974*311827fbSnicm 	struct client		*c;
975*311827fbSnicm 	struct session		*s;
976*311827fbSnicm 	struct winlink		*wl;
977*311827fbSnicm 	u_int		 	 i, j;
978*311827fbSnicm 	int		 	 destroyed, flag;
979*311827fbSnicm 
980*311827fbSnicm 	flag = options_get_number(&w->options, "remain-on-exit");
981*311827fbSnicm 
982*311827fbSnicm 	destroyed = 1;
983*311827fbSnicm 
984*311827fbSnicm 	wp = TAILQ_FIRST(&w->panes);
985*311827fbSnicm 	while (wp != NULL) {
986*311827fbSnicm 		wq = TAILQ_NEXT(wp, entry);
987*311827fbSnicm 		if (wp->fd != -1)
988*311827fbSnicm 			destroyed = 0;
989*311827fbSnicm 		else if (!flag) {
990*311827fbSnicm 			window_remove_pane(w, wp);
991*311827fbSnicm 			server_redraw_window(w);
992*311827fbSnicm 			layout_refresh(w, 0);
993*311827fbSnicm 		}
994*311827fbSnicm 		wp = wq;
995*311827fbSnicm 	}
996*311827fbSnicm 
997*311827fbSnicm 	if (!destroyed)
998*311827fbSnicm 		return;
999*311827fbSnicm 
1000*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
1001*311827fbSnicm 		s = ARRAY_ITEM(&sessions, i);
1002*311827fbSnicm 		if (s == NULL)
1003*311827fbSnicm 			continue;
1004*311827fbSnicm 		if (!session_has(s, w))
1005*311827fbSnicm 			continue;
1006*311827fbSnicm 
1007*311827fbSnicm 	restart:
1008*311827fbSnicm 		/* Detach window and either redraw or kill clients. */
1009*311827fbSnicm 		RB_FOREACH(wl, winlinks, &s->windows) {
1010*311827fbSnicm 			if (wl->window != w)
1011*311827fbSnicm 				continue;
1012*311827fbSnicm 			destroyed = session_detach(s, wl);
1013*311827fbSnicm 			for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
1014*311827fbSnicm 				c = ARRAY_ITEM(&clients, j);
1015*311827fbSnicm 				if (c == NULL || c->session != s)
1016*311827fbSnicm 					continue;
1017*311827fbSnicm 				if (!destroyed) {
1018*311827fbSnicm 					server_redraw_client(c);
1019*311827fbSnicm 					continue;
1020*311827fbSnicm 				}
1021*311827fbSnicm 				c->session = NULL;
1022*311827fbSnicm 				server_write_client(c, MSG_EXIT, NULL, 0);
1023*311827fbSnicm 			}
1024*311827fbSnicm 			/* If the session was destroyed, bail now. */
1025*311827fbSnicm 			if (destroyed)
1026*311827fbSnicm 				break;
1027*311827fbSnicm 			goto restart;
1028*311827fbSnicm 		}
1029*311827fbSnicm 	}
1030*311827fbSnicm 
1031*311827fbSnicm 	recalculate_sizes();
1032*311827fbSnicm }
1033*311827fbSnicm 
1034*311827fbSnicm /* Call any once-per-second timers. */
1035*311827fbSnicm void
1036*311827fbSnicm server_second_timers(void)
1037*311827fbSnicm {
1038*311827fbSnicm 	struct window		*w;
1039*311827fbSnicm 	struct window_pane	*wp;
1040*311827fbSnicm 	u_int		 	 i;
1041*311827fbSnicm 	int			 xtimeout;
1042*311827fbSnicm 	struct tm	 	 now, then;
1043*311827fbSnicm 	static time_t	 	 last_t = 0;
1044*311827fbSnicm 	time_t		 	 t;
1045*311827fbSnicm 
1046*311827fbSnicm 	t = time(NULL);
1047*311827fbSnicm 	xtimeout = options_get_number(&global_options, "lock-after-time");
1048*311827fbSnicm 	if (xtimeout > 0 && t > server_activity + xtimeout)
1049*311827fbSnicm 		server_lock();
1050*311827fbSnicm 
1051*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
1052*311827fbSnicm 		w = ARRAY_ITEM(&windows, i);
1053*311827fbSnicm 		if (w == NULL)
1054*311827fbSnicm 			continue;
1055*311827fbSnicm 
1056*311827fbSnicm 		TAILQ_FOREACH(wp, &w->panes, entry) {
1057*311827fbSnicm 			if (wp->mode != NULL && wp->mode->timer != NULL)
1058*311827fbSnicm 				wp->mode->timer(wp);
1059*311827fbSnicm 		}
1060*311827fbSnicm 	}
1061*311827fbSnicm 
1062*311827fbSnicm 	/* Check for a minute having passed. */
1063*311827fbSnicm 	gmtime_r(&t, &now);
1064*311827fbSnicm 	gmtime_r(&last_t, &then);
1065*311827fbSnicm 	if (now.tm_min == then.tm_min)
1066*311827fbSnicm 		return;
1067*311827fbSnicm 	last_t = t;
1068*311827fbSnicm 
1069*311827fbSnicm 	/* If locked, redraw all clients. */
1070*311827fbSnicm 	if (server_locked) {
1071*311827fbSnicm 		for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
1072*311827fbSnicm 			if (ARRAY_ITEM(&clients, i) != NULL)
1073*311827fbSnicm 				server_redraw_client(ARRAY_ITEM(&clients, i));
1074*311827fbSnicm 		}
1075*311827fbSnicm 	}
1076*311827fbSnicm }
1077*311827fbSnicm 
1078*311827fbSnicm /* Update socket execute permissions based on whether sessions are attached. */
1079*311827fbSnicm int
1080*311827fbSnicm server_update_socket(void)
1081*311827fbSnicm {
1082*311827fbSnicm 	struct session	*s;
1083*311827fbSnicm 	u_int		 i;
1084*311827fbSnicm 	static int	 last = -1;
1085*311827fbSnicm 	int		 n;
1086*311827fbSnicm 
1087*311827fbSnicm 	n = 0;
1088*311827fbSnicm 	for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
1089*311827fbSnicm 		s = ARRAY_ITEM(&sessions, i);
1090*311827fbSnicm 		if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
1091*311827fbSnicm 			n++;
1092*311827fbSnicm 			break;
1093*311827fbSnicm 		}
1094*311827fbSnicm 	}
1095*311827fbSnicm 
1096*311827fbSnicm 	if (n != last) {
1097*311827fbSnicm 		last = n;
1098*311827fbSnicm 		if (n != 0)
1099*311827fbSnicm 			chmod(socket_path, S_IRWXU);
1100*311827fbSnicm 		else
1101*311827fbSnicm 			chmod(socket_path, S_IRUSR|S_IWUSR);
1102*311827fbSnicm 	}
1103*311827fbSnicm 
1104*311827fbSnicm 	return (n);
1105*311827fbSnicm }
1106