Typo, from Micah Cowan.
[tmux-openbsd.git] / server-client.c
blob34b99514ec48fb33b517645e3b5c3b15fcd704cd
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
21 #include <event.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <time.h>
25 #include <paths.h>
26 #include <unistd.h>
28 #include "tmux.h"
30 void server_client_handle_key(int, struct mouse_event *, void *);
31 void server_client_repeat_timer(int, short, void *);
32 void server_client_check_redraw(struct client *);
33 void server_client_set_title(struct client *);
34 void server_client_reset_state(struct client *);
36 int server_client_msg_dispatch(struct client *);
37 void server_client_msg_command(struct client *, struct msg_command_data *);
38 void server_client_msg_identify(
39 struct client *, struct msg_identify_data *, int);
40 void server_client_msg_shell(struct client *);
42 void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...);
43 void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...);
44 void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...);
46 /* Create a new client. */
47 void
48 server_client_create(int fd)
50 struct client *c;
51 int mode;
52 u_int i;
54 if ((mode = fcntl(fd, F_GETFL)) == -1)
55 fatal("fcntl failed");
56 if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
57 fatal("fcntl failed");
58 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
59 fatal("fcntl failed");
61 c = xcalloc(1, sizeof *c);
62 c->references = 0;
63 imsg_init(&c->ibuf, fd);
64 server_update_event(c);
66 if (gettimeofday(&c->creation_time, NULL) != 0)
67 fatal("gettimeofday failed");
68 memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
70 ARRAY_INIT(&c->prompt_hdata);
72 c->tty.fd = -1;
73 c->title = NULL;
75 c->session = NULL;
76 c->tty.sx = 80;
77 c->tty.sy = 24;
79 screen_init(&c->status, c->tty.sx, 1, 0);
80 job_tree_init(&c->status_jobs);
82 c->message_string = NULL;
83 ARRAY_INIT(&c->message_log);
85 c->prompt_string = NULL;
86 c->prompt_buffer = NULL;
87 c->prompt_index = 0;
89 evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
91 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
92 if (ARRAY_ITEM(&clients, i) == NULL) {
93 ARRAY_SET(&clients, i, c);
94 return;
97 ARRAY_ADD(&clients, c);
98 log_debug("new client %d", fd);
101 /* Lost a client. */
102 void
103 server_client_lost(struct client *c)
105 struct message_entry *msg;
106 u_int i;
108 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
109 if (ARRAY_ITEM(&clients, i) == c)
110 ARRAY_SET(&clients, i, NULL);
112 log_debug("lost client %d", c->ibuf.fd);
115 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
116 * and tty_free might close an unrelated fd.
118 if (c->flags & CLIENT_TERMINAL)
119 tty_free(&c->tty);
121 screen_free(&c->status);
122 job_tree_free(&c->status_jobs);
124 if (c->title != NULL)
125 xfree(c->title);
127 evtimer_del(&c->repeat_timer);
129 evtimer_del(&c->identify_timer);
131 if (c->message_string != NULL)
132 xfree(c->message_string);
133 evtimer_del(&c->message_timer);
134 for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) {
135 msg = &ARRAY_ITEM(&c->message_log, i);
136 xfree(msg->msg);
138 ARRAY_FREE(&c->message_log);
140 if (c->prompt_string != NULL)
141 xfree(c->prompt_string);
142 if (c->prompt_buffer != NULL)
143 xfree(c->prompt_buffer);
144 for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++)
145 xfree(ARRAY_ITEM(&c->prompt_hdata, i));
146 ARRAY_FREE(&c->prompt_hdata);
148 if (c->cwd != NULL)
149 xfree(c->cwd);
151 close(c->ibuf.fd);
152 imsg_clear(&c->ibuf);
153 event_del(&c->event);
155 for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
156 if (ARRAY_ITEM(&dead_clients, i) == NULL) {
157 ARRAY_SET(&dead_clients, i, c);
158 break;
161 if (i == ARRAY_LENGTH(&dead_clients))
162 ARRAY_ADD(&dead_clients, c);
163 c->flags |= CLIENT_DEAD;
165 recalculate_sizes();
166 server_update_socket();
169 /* Process a single client event. */
170 void
171 server_client_callback(int fd, short events, void *data)
173 struct client *c = data;
175 if (c->flags & CLIENT_DEAD)
176 return;
178 if (fd == c->ibuf.fd) {
179 if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) < 0)
180 goto client_lost;
182 if (c->flags & CLIENT_BAD) {
183 if (c->ibuf.w.queued == 0)
184 goto client_lost;
185 return;
188 if (events & EV_READ && server_client_msg_dispatch(c) != 0)
189 goto client_lost;
192 server_update_event(c);
193 return;
195 client_lost:
196 server_client_lost(c);
199 /* Handle client status timer. */
200 void
201 server_client_status_timer(void)
203 struct client *c;
204 struct session *s;
205 struct job *job;
206 struct timeval tv;
207 u_int i;
208 int interval;
209 time_t difference;
211 if (gettimeofday(&tv, NULL) != 0)
212 fatal("gettimeofday failed");
214 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
215 c = ARRAY_ITEM(&clients, i);
216 if (c == NULL || c->session == NULL)
217 continue;
218 if (c->message_string != NULL || c->prompt_string != NULL) {
220 * Don't need timed redraw for messages/prompts so bail
221 * now. The status timer isn't reset when they are
222 * redrawn anyway.
224 continue;
226 s = c->session;
228 if (!options_get_number(&s->options, "status"))
229 continue;
230 interval = options_get_number(&s->options, "status-interval");
232 difference = tv.tv_sec - c->status_timer.tv_sec;
233 if (difference >= interval) {
234 RB_FOREACH(job, jobs, &c->status_jobs)
235 job_run(job);
236 c->flags |= CLIENT_STATUS;
241 /* Handle data key input from client. */
242 void
243 server_client_handle_key(int key, struct mouse_event *mouse, void *data)
245 struct client *c = data;
246 struct session *s;
247 struct window *w;
248 struct window_pane *wp;
249 struct options *oo;
250 struct timeval tv;
251 struct key_binding *bd;
252 struct keylist *keylist;
253 int xtimeout, isprefix;
254 u_int i;
256 /* Check the client is good to accept input. */
257 if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
258 return;
259 if (c->session == NULL)
260 return;
261 s = c->session;
263 /* Update the activity timer. */
264 if (gettimeofday(&c->activity_time, NULL) != 0)
265 fatal("gettimeofday failed");
266 memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time);
268 w = c->session->curw->window;
269 wp = w->active;
270 oo = &c->session->options;
272 /* Special case: number keys jump to pane in identify mode. */
273 if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
274 wp = window_pane_at_index(w, key - '0');
275 if (wp != NULL && window_pane_visible(wp))
276 window_set_active_pane(w, wp);
277 server_clear_identify(c);
278 return;
281 /* Handle status line. */
282 status_message_clear(c);
283 server_clear_identify(c);
284 if (c->prompt_string != NULL) {
285 status_prompt_key(c, key);
286 return;
289 /* Check for mouse keys. */
290 if (key == KEYC_MOUSE) {
291 if (options_get_number(oo, "mouse-select-pane")) {
292 window_set_active_at(w, mouse->x, mouse->y);
293 server_redraw_window_borders(w);
294 wp = w->active;
296 window_pane_mouse(wp, c, mouse);
297 return;
300 /* Is this a prefix key? */
301 keylist = options_get_data(&c->session->options, "prefix");
302 isprefix = 0;
303 for (i = 0; i < ARRAY_LENGTH(keylist); i++) {
304 if (key == ARRAY_ITEM(keylist, i)) {
305 isprefix = 1;
306 break;
310 /* No previous prefix key. */
311 if (!(c->flags & CLIENT_PREFIX)) {
312 if (isprefix)
313 c->flags |= CLIENT_PREFIX;
314 else {
315 /* Try as a non-prefix key binding. */
316 if ((bd = key_bindings_lookup(key)) == NULL)
317 window_pane_key(wp, c, key);
318 else
319 key_bindings_dispatch(bd, c);
321 return;
324 /* Prefix key already pressed. Reset prefix and lookup key. */
325 c->flags &= ~CLIENT_PREFIX;
326 if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) {
327 /* If repeating, treat this as a key, else ignore. */
328 if (c->flags & CLIENT_REPEAT) {
329 c->flags &= ~CLIENT_REPEAT;
330 if (isprefix)
331 c->flags |= CLIENT_PREFIX;
332 else
333 window_pane_key(wp, c, key);
335 return;
338 /* If already repeating, but this key can't repeat, skip it. */
339 if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
340 c->flags &= ~CLIENT_REPEAT;
341 if (isprefix)
342 c->flags |= CLIENT_PREFIX;
343 else
344 window_pane_key(wp, c, key);
345 return;
348 /* If this key can repeat, reset the repeat flags and timer. */
349 xtimeout = options_get_number(&c->session->options, "repeat-time");
350 if (xtimeout != 0 && bd->can_repeat) {
351 c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
353 tv.tv_sec = xtimeout / 1000;
354 tv.tv_usec = (xtimeout % 1000) * 1000L;
355 evtimer_del(&c->repeat_timer);
356 evtimer_add(&c->repeat_timer, &tv);
359 /* Dispatch the command. */
360 key_bindings_dispatch(bd, c);
363 /* Client functions that need to happen every loop. */
364 void
365 server_client_loop(void)
367 struct client *c;
368 struct window *w;
369 struct window_pane *wp;
370 u_int i;
372 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
373 c = ARRAY_ITEM(&clients, i);
374 if (c == NULL || c->session == NULL)
375 continue;
377 server_client_check_redraw(c);
378 server_client_reset_state(c);
382 * Any windows will have been redrawn as part of clients, so clear
383 * their flags now.
385 for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
386 w = ARRAY_ITEM(&windows, i);
387 if (w == NULL)
388 continue;
390 w->flags &= ~WINDOW_REDRAW;
391 TAILQ_FOREACH(wp, &w->panes, entry)
392 wp->flags &= ~PANE_REDRAW;
397 * Update cursor position and mode settings. The scroll region and attributes
398 * are cleared when idle (waiting for an event) as this is the most likely time
399 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
400 * compromise between excessive resets and likelihood of an interrupt.
402 * tty_region/tty_reset/tty_update_mode already take care of not resetting
403 * things that are already in their default state.
405 void
406 server_client_reset_state(struct client *c)
408 struct window *w = c->session->curw->window;
409 struct window_pane *wp = w->active;
410 struct screen *s = wp->screen;
411 struct options *oo = &c->session->options;
412 int status, mode;
414 tty_region(&c->tty, 0, c->tty.sy - 1);
416 status = options_get_number(oo, "status");
417 if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)
418 tty_cursor(&c->tty, 0, 0);
419 else
420 tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy);
422 mode = s->mode;
423 if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL &&
424 options_get_number(oo, "mouse-select-pane"))
425 mode |= MODE_MOUSE;
426 tty_update_mode(&c->tty, mode);
427 tty_reset(&c->tty);
430 /* Repeat time callback. */
431 /* ARGSUSED */
432 void
433 server_client_repeat_timer(unused int fd, unused short events, void *data)
435 struct client *c = data;
437 if (c->flags & CLIENT_REPEAT)
438 c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
441 /* Check for client redraws. */
442 void
443 server_client_check_redraw(struct client *c)
445 struct session *s = c->session;
446 struct window_pane *wp;
447 int flags, redraw;
449 flags = c->tty.flags & TTY_FREEZE;
450 c->tty.flags &= ~TTY_FREEZE;
452 if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
453 if (options_get_number(&s->options, "set-titles"))
454 server_client_set_title(c);
456 if (c->message_string != NULL)
457 redraw = status_message_redraw(c);
458 else if (c->prompt_string != NULL)
459 redraw = status_prompt_redraw(c);
460 else
461 redraw = status_redraw(c);
462 if (!redraw)
463 c->flags &= ~CLIENT_STATUS;
466 if (c->flags & CLIENT_REDRAW) {
467 screen_redraw_screen(c, 0, 0);
468 c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS);
469 } else {
470 TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
471 if (wp->flags & PANE_REDRAW)
472 screen_redraw_pane(c, wp);
476 if (c->flags & CLIENT_BORDERS)
477 screen_redraw_screen(c, 0, 1);
479 if (c->flags & CLIENT_STATUS)
480 screen_redraw_screen(c, 1, 0);
482 c->tty.flags |= flags;
484 c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS|CLIENT_BORDERS);
487 /* Set client title. */
488 void
489 server_client_set_title(struct client *c)
491 struct session *s = c->session;
492 const char *template;
493 char *title;
495 template = options_get_string(&s->options, "set-titles-string");
497 title = status_replace(c, NULL, template, time(NULL), 1);
498 if (c->title == NULL || strcmp(title, c->title) != 0) {
499 if (c->title != NULL)
500 xfree(c->title);
501 c->title = xstrdup(title);
502 tty_set_title(&c->tty, c->title);
504 xfree(title);
507 /* Dispatch message from client. */
509 server_client_msg_dispatch(struct client *c)
511 struct imsg imsg;
512 struct msg_command_data commanddata;
513 struct msg_identify_data identifydata;
514 struct msg_environ_data environdata;
515 ssize_t n, datalen;
517 if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
518 return (-1);
520 for (;;) {
521 if ((n = imsg_get(&c->ibuf, &imsg)) == -1)
522 return (-1);
523 if (n == 0)
524 return (0);
525 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
527 if (imsg.hdr.peerid != PROTOCOL_VERSION) {
528 server_write_client(c, MSG_VERSION, NULL, 0);
529 c->flags |= CLIENT_BAD;
530 imsg_free(&imsg);
531 continue;
534 log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd);
535 switch (imsg.hdr.type) {
536 case MSG_COMMAND:
537 if (datalen != sizeof commanddata)
538 fatalx("bad MSG_COMMAND size");
539 memcpy(&commanddata, imsg.data, sizeof commanddata);
541 server_client_msg_command(c, &commanddata);
542 break;
543 case MSG_IDENTIFY:
544 if (datalen != sizeof identifydata)
545 fatalx("bad MSG_IDENTIFY size");
546 if (imsg.fd == -1)
547 fatalx("MSG_IDENTIFY missing fd");
548 memcpy(&identifydata, imsg.data, sizeof identifydata);
550 server_client_msg_identify(c, &identifydata, imsg.fd);
551 break;
552 case MSG_RESIZE:
553 if (datalen != 0)
554 fatalx("bad MSG_RESIZE size");
556 tty_resize(&c->tty);
557 recalculate_sizes();
558 server_redraw_client(c);
559 break;
560 case MSG_EXITING:
561 if (datalen != 0)
562 fatalx("bad MSG_EXITING size");
564 c->session = NULL;
565 tty_close(&c->tty);
566 server_write_client(c, MSG_EXITED, NULL, 0);
567 break;
568 case MSG_WAKEUP:
569 case MSG_UNLOCK:
570 if (datalen != 0)
571 fatalx("bad MSG_WAKEUP size");
573 if (!(c->flags & CLIENT_SUSPENDED))
574 break;
575 c->flags &= ~CLIENT_SUSPENDED;
577 if (gettimeofday(&c->activity_time, NULL) != 0)
578 fatal("gettimeofday");
579 if (c->session != NULL) {
580 memcpy(&c->session->activity_time,
581 &c->activity_time,
582 sizeof c->session->activity_time);
585 tty_start_tty(&c->tty);
586 server_redraw_client(c);
587 recalculate_sizes();
588 break;
589 case MSG_ENVIRON:
590 if (datalen != sizeof environdata)
591 fatalx("bad MSG_ENVIRON size");
592 memcpy(&environdata, imsg.data, sizeof environdata);
594 environdata.var[(sizeof environdata.var) - 1] = '\0';
595 if (strchr(environdata.var, '=') != NULL)
596 environ_put(&c->environ, environdata.var);
597 break;
598 case MSG_SHELL:
599 if (datalen != 0)
600 fatalx("bad MSG_SHELL size");
602 server_client_msg_shell(c);
603 break;
604 default:
605 fatalx("unexpected message");
608 imsg_free(&imsg);
612 /* Callback to send error message to client. */
613 void printflike2
614 server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
616 struct msg_print_data data;
617 va_list ap;
619 va_start(ap, fmt);
620 xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
621 va_end(ap);
623 server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data);
626 /* Callback to send print message to client. */
627 void printflike2
628 server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
630 struct msg_print_data data;
631 va_list ap;
633 va_start(ap, fmt);
634 xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
635 va_end(ap);
637 server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
640 /* Callback to send print message to client, if not quiet. */
641 void printflike2
642 server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
644 struct msg_print_data data;
645 va_list ap;
647 if (options_get_number(&global_options, "quiet"))
648 return;
650 va_start(ap, fmt);
651 xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
652 va_end(ap);
654 server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
657 /* Handle command message. */
658 void
659 server_client_msg_command(struct client *c, struct msg_command_data *data)
661 struct cmd_ctx ctx;
662 struct cmd_list *cmdlist = NULL;
663 struct cmd *cmd;
664 int argc;
665 char **argv, *cause;
667 ctx.error = server_client_msg_error;
668 ctx.print = server_client_msg_print;
669 ctx.info = server_client_msg_info;
671 ctx.msgdata = data;
672 ctx.curclient = NULL;
674 ctx.cmdclient = c;
676 argc = data->argc;
677 data->argv[(sizeof data->argv) - 1] = '\0';
678 if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) {
679 server_client_msg_error(&ctx, "command too long");
680 goto error;
683 if (argc == 0) {
684 argc = 1;
685 argv = xcalloc(1, sizeof *argv);
686 *argv = xstrdup("new-session");
689 if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
690 server_client_msg_error(&ctx, "%s", cause);
691 cmd_free_argv(argc, argv);
692 goto error;
694 cmd_free_argv(argc, argv);
696 if (data->pid != -1) {
697 TAILQ_FOREACH(cmd, cmdlist, qentry) {
698 if (cmd->entry->flags & CMD_CANTNEST) {
699 server_client_msg_error(&ctx,
700 "sessions should be nested with care. "
701 "unset $TMUX to force");
702 goto error;
707 if (cmd_list_exec(cmdlist, &ctx) != 1)
708 server_write_client(c, MSG_EXIT, NULL, 0);
709 cmd_list_free(cmdlist);
710 return;
712 error:
713 if (cmdlist != NULL)
714 cmd_list_free(cmdlist);
715 server_write_client(c, MSG_EXIT, NULL, 0);
718 /* Handle identify message. */
719 void
720 server_client_msg_identify(
721 struct client *c, struct msg_identify_data *data, int fd)
723 c->cwd = NULL;
724 data->cwd[(sizeof data->cwd) - 1] = '\0';
725 if (*data->cwd != '\0')
726 c->cwd = xstrdup(data->cwd);
728 data->term[(sizeof data->term) - 1] = '\0';
729 tty_init(&c->tty, fd, data->term);
730 if (data->flags & IDENTIFY_UTF8)
731 c->tty.flags |= TTY_UTF8;
732 if (data->flags & IDENTIFY_256COLOURS)
733 c->tty.term_flags |= TERM_256COLOURS;
734 else if (data->flags & IDENTIFY_88COLOURS)
735 c->tty.term_flags |= TERM_88COLOURS;
736 c->tty.key_callback = server_client_handle_key;
737 c->tty.key_data = c;
739 tty_resize(&c->tty);
741 c->flags |= CLIENT_TERMINAL;
744 /* Handle shell message. */
745 void
746 server_client_msg_shell(struct client *c)
748 struct msg_shell_data data;
749 const char *shell;
751 shell = options_get_string(&global_s_options, "default-shell");
753 if (*shell == '\0' || areshell(shell))
754 shell = _PATH_BSHELL;
755 if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell)
756 strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell);
758 server_write_client(c, MSG_SHELL, &data, sizeof data);
759 c->flags |= CLIENT_BAD; /* it will die after exec */