Simplify xterm modifier detection by treating as a bitmask + 1. Spotted
[tmux-openbsd.git] / server-client.c
blob27a5d20766abf064258f759d1b1b69e85f0c2537
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_exit(struct client *);
33 void server_client_check_backoff(struct client *);
34 void server_client_check_redraw(struct client *);
35 void server_client_set_title(struct client *);
36 void server_client_reset_state(struct client *);
37 void server_client_in_callback(struct bufferevent *, short, void *);
38 void server_client_out_callback(struct bufferevent *, short, void *);
39 void server_client_err_callback(struct bufferevent *, short, void *);
41 int server_client_msg_dispatch(struct client *);
42 void server_client_msg_command(struct client *, struct msg_command_data *);
43 void server_client_msg_identify(
44 struct client *, struct msg_identify_data *, int);
45 void server_client_msg_shell(struct client *);
47 void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...);
48 void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...);
49 void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...);
51 /* Create a new client. */
52 void
53 server_client_create(int fd)
55 struct client *c;
56 int mode;
57 u_int i;
59 if ((mode = fcntl(fd, F_GETFL)) == -1)
60 fatal("fcntl failed");
61 if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
62 fatal("fcntl failed");
63 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
64 fatal("fcntl failed");
66 c = xcalloc(1, sizeof *c);
67 c->references = 0;
68 imsg_init(&c->ibuf, fd);
69 server_update_event(c);
71 if (gettimeofday(&c->creation_time, NULL) != 0)
72 fatal("gettimeofday failed");
73 memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
75 ARRAY_INIT(&c->prompt_hdata);
77 c->stdin_event = NULL;
78 c->stdout_event = NULL;
79 c->stderr_event = NULL;
81 c->tty.fd = -1;
82 c->title = NULL;
84 c->session = NULL;
85 c->tty.sx = 80;
86 c->tty.sy = 24;
88 screen_init(&c->status, c->tty.sx, 1, 0);
89 job_tree_init(&c->status_jobs);
91 c->message_string = NULL;
92 ARRAY_INIT(&c->message_log);
94 c->prompt_string = NULL;
95 c->prompt_buffer = NULL;
96 c->prompt_index = 0;
98 evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
100 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
101 if (ARRAY_ITEM(&clients, i) == NULL) {
102 ARRAY_SET(&clients, i, c);
103 return;
106 ARRAY_ADD(&clients, c);
107 log_debug("new client %d", fd);
110 /* Lost a client. */
111 void
112 server_client_lost(struct client *c)
114 struct message_entry *msg;
115 u_int i;
117 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
118 if (ARRAY_ITEM(&clients, i) == c)
119 ARRAY_SET(&clients, i, NULL);
121 log_debug("lost client %d", c->ibuf.fd);
124 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
125 * and tty_free might close an unrelated fd.
127 if (c->flags & CLIENT_TERMINAL)
128 tty_free(&c->tty);
130 if (c->stdin_fd != -1)
131 close(c->stdin_fd);
132 if (c->stdin_event != NULL)
133 bufferevent_free(c->stdin_event);
134 if (c->stdout_fd != -1)
135 close(c->stdout_fd);
136 if (c->stdout_event != NULL)
137 bufferevent_free(c->stdout_event);
138 if (c->stderr_fd != -1)
139 close(c->stderr_fd);
140 if (c->stderr_event != NULL)
141 bufferevent_free(c->stderr_event);
143 screen_free(&c->status);
144 job_tree_free(&c->status_jobs);
146 if (c->title != NULL)
147 xfree(c->title);
149 evtimer_del(&c->repeat_timer);
151 evtimer_del(&c->identify_timer);
153 if (c->message_string != NULL)
154 xfree(c->message_string);
155 evtimer_del(&c->message_timer);
156 for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) {
157 msg = &ARRAY_ITEM(&c->message_log, i);
158 xfree(msg->msg);
160 ARRAY_FREE(&c->message_log);
162 if (c->prompt_string != NULL)
163 xfree(c->prompt_string);
164 if (c->prompt_buffer != NULL)
165 xfree(c->prompt_buffer);
166 for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++)
167 xfree(ARRAY_ITEM(&c->prompt_hdata, i));
168 ARRAY_FREE(&c->prompt_hdata);
170 if (c->cwd != NULL)
171 xfree(c->cwd);
173 close(c->ibuf.fd);
174 imsg_clear(&c->ibuf);
175 event_del(&c->event);
177 for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
178 if (ARRAY_ITEM(&dead_clients, i) == NULL) {
179 ARRAY_SET(&dead_clients, i, c);
180 break;
183 if (i == ARRAY_LENGTH(&dead_clients))
184 ARRAY_ADD(&dead_clients, c);
185 c->flags |= CLIENT_DEAD;
187 recalculate_sizes();
188 server_update_socket();
191 /* Process a single client event. */
192 void
193 server_client_callback(int fd, short events, void *data)
195 struct client *c = data;
197 if (c->flags & CLIENT_DEAD)
198 return;
200 if (fd == c->ibuf.fd) {
201 if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) < 0)
202 goto client_lost;
204 if (c->flags & CLIENT_BAD) {
205 if (c->ibuf.w.queued == 0)
206 goto client_lost;
207 return;
210 if (events & EV_READ && server_client_msg_dispatch(c) != 0)
211 goto client_lost;
214 server_update_event(c);
215 return;
217 client_lost:
218 server_client_lost(c);
221 /* Handle client status timer. */
222 void
223 server_client_status_timer(void)
225 struct client *c;
226 struct session *s;
227 struct job *job;
228 struct timeval tv;
229 u_int i;
230 int interval;
231 time_t difference;
233 if (gettimeofday(&tv, NULL) != 0)
234 fatal("gettimeofday failed");
236 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
237 c = ARRAY_ITEM(&clients, i);
238 if (c == NULL || c->session == NULL)
239 continue;
240 if (c->message_string != NULL || c->prompt_string != NULL) {
242 * Don't need timed redraw for messages/prompts so bail
243 * now. The status timer isn't reset when they are
244 * redrawn anyway.
246 continue;
248 s = c->session;
250 if (!options_get_number(&s->options, "status"))
251 continue;
252 interval = options_get_number(&s->options, "status-interval");
254 difference = tv.tv_sec - c->status_timer.tv_sec;
255 if (difference >= interval) {
256 RB_FOREACH(job, jobs, &c->status_jobs)
257 job_run(job);
258 c->flags |= CLIENT_STATUS;
263 /* Handle data key input from client. */
264 void
265 server_client_handle_key(int key, struct mouse_event *mouse, void *data)
267 struct client *c = data;
268 struct session *s;
269 struct window *w;
270 struct window_pane *wp;
271 struct options *oo;
272 struct timeval tv;
273 struct key_binding *bd;
274 struct keylist *keylist;
275 int xtimeout, isprefix;
276 u_int i;
278 /* Check the client is good to accept input. */
279 if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
280 return;
281 if (c->session == NULL)
282 return;
283 s = c->session;
285 /* Update the activity timer. */
286 if (gettimeofday(&c->activity_time, NULL) != 0)
287 fatal("gettimeofday failed");
288 memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time);
290 w = c->session->curw->window;
291 wp = w->active;
292 oo = &c->session->options;
294 /* Special case: number keys jump to pane in identify mode. */
295 if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
296 if (c->flags & CLIENT_READONLY)
297 return;
298 wp = window_pane_at_index(w, key - '0');
299 if (wp != NULL && window_pane_visible(wp))
300 window_set_active_pane(w, wp);
301 server_clear_identify(c);
302 return;
305 /* Handle status line. */
306 if (!(c->flags & CLIENT_READONLY)) {
307 status_message_clear(c);
308 server_clear_identify(c);
310 if (c->prompt_string != NULL) {
311 if (!(c->flags & CLIENT_READONLY))
312 status_prompt_key(c, key);
313 return;
316 /* Check for mouse keys. */
317 if (key == KEYC_MOUSE) {
318 if (c->flags & CLIENT_READONLY)
319 return;
320 if (options_get_number(oo, "mouse-select-pane")) {
321 window_set_active_at(w, mouse->x, mouse->y);
322 server_redraw_window_borders(w);
323 wp = w->active;
325 window_pane_mouse(wp, c->session, mouse);
326 return;
329 /* Is this a prefix key? */
330 keylist = options_get_data(&c->session->options, "prefix");
331 isprefix = 0;
332 for (i = 0; i < ARRAY_LENGTH(keylist); i++) {
333 if (key == ARRAY_ITEM(keylist, i)) {
334 isprefix = 1;
335 break;
339 /* No previous prefix key. */
340 if (!(c->flags & CLIENT_PREFIX)) {
341 if (isprefix)
342 c->flags |= CLIENT_PREFIX;
343 else {
344 /* Try as a non-prefix key binding. */
345 if ((bd = key_bindings_lookup(key)) == NULL) {
346 if (!(c->flags & CLIENT_READONLY))
347 window_pane_key(wp, c->session, key);
348 } else
349 key_bindings_dispatch(bd, c);
351 return;
354 /* Prefix key already pressed. Reset prefix and lookup key. */
355 c->flags &= ~CLIENT_PREFIX;
356 if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) {
357 /* If repeating, treat this as a key, else ignore. */
358 if (c->flags & CLIENT_REPEAT) {
359 c->flags &= ~CLIENT_REPEAT;
360 if (isprefix)
361 c->flags |= CLIENT_PREFIX;
362 else if (!(c->flags & CLIENT_READONLY))
363 window_pane_key(wp, c->session, key);
365 return;
368 /* If already repeating, but this key can't repeat, skip it. */
369 if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
370 c->flags &= ~CLIENT_REPEAT;
371 if (isprefix)
372 c->flags |= CLIENT_PREFIX;
373 else if (!(c->flags & CLIENT_READONLY))
374 window_pane_key(wp, c->session, key);
375 return;
378 /* If this key can repeat, reset the repeat flags and timer. */
379 xtimeout = options_get_number(&c->session->options, "repeat-time");
380 if (xtimeout != 0 && bd->can_repeat) {
381 c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
383 tv.tv_sec = xtimeout / 1000;
384 tv.tv_usec = (xtimeout % 1000) * 1000L;
385 evtimer_del(&c->repeat_timer);
386 evtimer_add(&c->repeat_timer, &tv);
389 /* Dispatch the command. */
390 key_bindings_dispatch(bd, c);
393 /* Client functions that need to happen every loop. */
394 void
395 server_client_loop(void)
397 struct client *c;
398 struct window *w;
399 struct window_pane *wp;
400 u_int i;
402 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
403 c = ARRAY_ITEM(&clients, i);
404 if (c == NULL)
405 continue;
407 server_client_check_exit(c);
408 if (c->session != NULL) {
409 server_client_check_redraw(c);
410 server_client_reset_state(c);
415 * Any windows will have been redrawn as part of clients, so clear
416 * their flags now.
418 for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
419 w = ARRAY_ITEM(&windows, i);
420 if (w == NULL)
421 continue;
423 w->flags &= ~WINDOW_REDRAW;
424 TAILQ_FOREACH(wp, &w->panes, entry)
425 wp->flags &= ~PANE_REDRAW;
430 * Update cursor position and mode settings. The scroll region and attributes
431 * are cleared when idle (waiting for an event) as this is the most likely time
432 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
433 * compromise between excessive resets and likelihood of an interrupt.
435 * tty_region/tty_reset/tty_update_mode already take care of not resetting
436 * things that are already in their default state.
438 void
439 server_client_reset_state(struct client *c)
441 struct window *w = c->session->curw->window;
442 struct window_pane *wp = w->active;
443 struct screen *s = wp->screen;
444 struct options *oo = &c->session->options;
445 int status, mode;
447 tty_region(&c->tty, 0, c->tty.sy - 1);
449 status = options_get_number(oo, "status");
450 if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)
451 tty_cursor(&c->tty, 0, 0);
452 else
453 tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy);
455 mode = s->mode;
456 if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL &&
457 options_get_number(oo, "mouse-select-pane"))
458 mode |= MODE_MOUSE;
459 tty_update_mode(&c->tty, mode);
460 tty_reset(&c->tty);
463 /* Repeat time callback. */
464 /* ARGSUSED */
465 void
466 server_client_repeat_timer(unused int fd, unused short events, void *data)
468 struct client *c = data;
470 if (c->flags & CLIENT_REPEAT)
471 c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
474 /* Check if client should be exited. */
475 void
476 server_client_check_exit(struct client *c)
478 struct msg_exit_data exitdata;
480 if (!(c->flags & CLIENT_EXIT))
481 return;
483 if (c->stdout_fd != -1 && c->stdout_event != NULL &&
484 EVBUFFER_LENGTH(c->stdout_event->output) != 0)
485 return;
486 if (c->stderr_fd != -1 && c->stderr_event != NULL &&
487 EVBUFFER_LENGTH(c->stderr_event->output) != 0)
488 return;
490 exitdata.retcode = c->retcode;
491 server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata);
493 c->flags &= ~CLIENT_EXIT;
497 * Check if the client should backoff. During backoff, data from external
498 * programs is not written to the terminal. When the existing data drains, the
499 * client is redrawn.
501 * There are two backoff phases - both the tty and client have backoff flags -
502 * the first to allow existing data to drain and the latter to ensure backoff
503 * is disabled until the redraw has finished and prevent the redraw triggering
504 * another backoff.
506 void
507 server_client_check_backoff(struct client *c)
509 struct tty *tty = &c->tty;
510 size_t used;
512 used = EVBUFFER_LENGTH(tty->event->output);
515 * If in the second backoff phase (redrawing), don't check backoff
516 * until the redraw has completed (or enough of it to drop below the
517 * backoff threshold).
519 if (c->flags & CLIENT_BACKOFF) {
520 if (used > BACKOFF_THRESHOLD)
521 return;
522 c->flags &= ~CLIENT_BACKOFF;
523 return;
526 /* Once drained, allow data through again and schedule redraw. */
527 if (tty->flags & TTY_BACKOFF) {
528 if (used != 0)
529 return;
530 tty->flags &= ~TTY_BACKOFF;
531 c->flags |= (CLIENT_BACKOFF|CLIENT_REDRAWWINDOW|CLIENT_STATUS);
532 return;
535 /* If too much data, start backoff. */
536 if (used > BACKOFF_THRESHOLD)
537 tty->flags |= TTY_BACKOFF;
540 /* Check for client redraws. */
541 void
542 server_client_check_redraw(struct client *c)
544 struct session *s = c->session;
545 struct window_pane *wp;
546 int flags, redraw;
548 flags = c->tty.flags & TTY_FREEZE;
549 c->tty.flags &= ~TTY_FREEZE;
551 if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
552 if (options_get_number(&s->options, "set-titles"))
553 server_client_set_title(c);
555 if (c->message_string != NULL)
556 redraw = status_message_redraw(c);
557 else if (c->prompt_string != NULL)
558 redraw = status_prompt_redraw(c);
559 else
560 redraw = status_redraw(c);
561 if (!redraw)
562 c->flags &= ~CLIENT_STATUS;
565 if (c->flags & CLIENT_REDRAW) {
566 screen_redraw_screen(c, 0, 0);
567 c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS);
568 } else if (c->flags & CLIENT_REDRAWWINDOW) {
569 TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry)
570 screen_redraw_pane(c, wp);
571 c->flags &= ~CLIENT_REDRAWWINDOW;
572 } else {
573 TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
574 if (wp->flags & PANE_REDRAW)
575 screen_redraw_pane(c, wp);
579 if (c->flags & CLIENT_BORDERS)
580 screen_redraw_screen(c, 0, 1);
582 if (c->flags & CLIENT_STATUS)
583 screen_redraw_screen(c, 1, 0);
585 c->tty.flags |= flags;
587 c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS|CLIENT_BORDERS);
590 /* Set client title. */
591 void
592 server_client_set_title(struct client *c)
594 struct session *s = c->session;
595 const char *template;
596 char *title;
598 template = options_get_string(&s->options, "set-titles-string");
600 title = status_replace(c, NULL, template, time(NULL), 1);
601 if (c->title == NULL || strcmp(title, c->title) != 0) {
602 if (c->title != NULL)
603 xfree(c->title);
604 c->title = xstrdup(title);
605 tty_set_title(&c->tty, c->title);
607 xfree(title);
611 * Error callback for client stdin. Caller must increase reference count when
612 * enabling event!
614 void
615 server_client_in_callback(
616 unused struct bufferevent *bufev, unused short what, void *data)
618 struct client *c = data;
620 c->references--;
621 if (c->flags & CLIENT_DEAD)
622 return;
624 bufferevent_disable(c->stdin_event, EV_READ|EV_WRITE);
625 close(c->stdin_fd);
626 c->stdin_fd = -1;
628 if (c->stdin_callback != NULL)
629 c->stdin_callback(c, c->stdin_data);
632 /* Error callback for client stdout. */
633 void
634 server_client_out_callback(
635 unused struct bufferevent *bufev, unused short what, unused void *data)
637 struct client *c = data;
639 bufferevent_disable(c->stdout_event, EV_READ|EV_WRITE);
640 close(c->stdout_fd);
641 c->stdout_fd = -1;
644 /* Error callback for client stderr. */
645 void
646 server_client_err_callback(
647 unused struct bufferevent *bufev, unused short what, unused void *data)
649 struct client *c = data;
651 bufferevent_disable(c->stderr_event, EV_READ|EV_WRITE);
652 close(c->stderr_fd);
653 c->stderr_fd = -1;
656 /* Dispatch message from client. */
658 server_client_msg_dispatch(struct client *c)
660 struct imsg imsg;
661 struct msg_command_data commanddata;
662 struct msg_identify_data identifydata;
663 struct msg_environ_data environdata;
664 ssize_t n, datalen;
665 int mode;
667 if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
668 return (-1);
670 for (;;) {
671 if ((n = imsg_get(&c->ibuf, &imsg)) == -1)
672 return (-1);
673 if (n == 0)
674 return (0);
675 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
677 if (imsg.hdr.peerid != PROTOCOL_VERSION) {
678 server_write_client(c, MSG_VERSION, NULL, 0);
679 c->flags |= CLIENT_BAD;
680 imsg_free(&imsg);
681 continue;
684 log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd);
685 switch (imsg.hdr.type) {
686 case MSG_COMMAND:
687 if (datalen != sizeof commanddata)
688 fatalx("bad MSG_COMMAND size");
689 memcpy(&commanddata, imsg.data, sizeof commanddata);
691 server_client_msg_command(c, &commanddata);
692 break;
693 case MSG_IDENTIFY:
694 if (datalen != sizeof identifydata)
695 fatalx("bad MSG_IDENTIFY size");
696 if (imsg.fd == -1)
697 fatalx("MSG_IDENTIFY missing fd");
698 memcpy(&identifydata, imsg.data, sizeof identifydata);
700 c->stdin_fd = imsg.fd;
701 c->stdin_event = bufferevent_new(c->stdin_fd,
702 NULL, NULL, server_client_in_callback, c);
703 if (c->stdin_event == NULL)
704 fatalx("failed to create stdin event");
706 if ((mode = fcntl(c->stdin_fd, F_GETFL)) != -1)
707 fcntl(c->stdin_fd, F_SETFL, mode|O_NONBLOCK);
708 if (fcntl(c->stdin_fd, F_SETFD, FD_CLOEXEC) == -1)
709 fatal("fcntl failed");
711 server_client_msg_identify(c, &identifydata, imsg.fd);
712 break;
713 case MSG_STDOUT:
714 if (datalen != 0)
715 fatalx("bad MSG_STDOUT size");
716 if (imsg.fd == -1)
717 fatalx("MSG_STDOUT missing fd");
719 c->stdout_fd = imsg.fd;
720 c->stdout_event = bufferevent_new(c->stdout_fd,
721 NULL, NULL, server_client_out_callback, c);
722 if (c->stdout_event == NULL)
723 fatalx("failed to create stdout event");
725 if ((mode = fcntl(c->stdout_fd, F_GETFL)) != -1)
726 fcntl(c->stdout_fd, F_SETFL, mode|O_NONBLOCK);
727 if (fcntl(c->stdout_fd, F_SETFD, FD_CLOEXEC) == -1)
728 fatal("fcntl failed");
729 break;
730 case MSG_STDERR:
731 if (datalen != 0)
732 fatalx("bad MSG_STDERR size");
733 if (imsg.fd == -1)
734 fatalx("MSG_STDERR missing fd");
736 c->stderr_fd = imsg.fd;
737 c->stderr_event = bufferevent_new(c->stderr_fd,
738 NULL, NULL, server_client_err_callback, c);
739 if (c->stderr_event == NULL)
740 fatalx("failed to create stderr event");
742 if ((mode = fcntl(c->stderr_fd, F_GETFL)) != -1)
743 fcntl(c->stderr_fd, F_SETFL, mode|O_NONBLOCK);
744 if (fcntl(c->stderr_fd, F_SETFD, FD_CLOEXEC) == -1)
745 fatal("fcntl failed");
746 break;
747 case MSG_RESIZE:
748 if (datalen != 0)
749 fatalx("bad MSG_RESIZE size");
751 if (tty_resize(&c->tty)) {
752 recalculate_sizes();
753 server_redraw_client(c);
755 break;
756 case MSG_EXITING:
757 if (datalen != 0)
758 fatalx("bad MSG_EXITING size");
760 c->session = NULL;
761 tty_close(&c->tty);
762 server_write_client(c, MSG_EXITED, NULL, 0);
763 break;
764 case MSG_WAKEUP:
765 case MSG_UNLOCK:
766 if (datalen != 0)
767 fatalx("bad MSG_WAKEUP size");
769 if (!(c->flags & CLIENT_SUSPENDED))
770 break;
771 c->flags &= ~CLIENT_SUSPENDED;
773 if (gettimeofday(&c->activity_time, NULL) != 0)
774 fatal("gettimeofday");
775 if (c->session != NULL) {
776 memcpy(&c->session->activity_time,
777 &c->activity_time,
778 sizeof c->session->activity_time);
781 tty_start_tty(&c->tty);
782 server_redraw_client(c);
783 recalculate_sizes();
784 break;
785 case MSG_ENVIRON:
786 if (datalen != sizeof environdata)
787 fatalx("bad MSG_ENVIRON size");
788 memcpy(&environdata, imsg.data, sizeof environdata);
790 environdata.var[(sizeof environdata.var) - 1] = '\0';
791 if (strchr(environdata.var, '=') != NULL)
792 environ_put(&c->environ, environdata.var);
793 break;
794 case MSG_SHELL:
795 if (datalen != 0)
796 fatalx("bad MSG_SHELL size");
798 server_client_msg_shell(c);
799 break;
800 default:
801 fatalx("unexpected message");
804 imsg_free(&imsg);
808 /* Callback to send error message to client. */
809 void printflike2
810 server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
812 va_list ap;
814 va_start(ap, fmt);
815 evbuffer_add_vprintf(ctx->cmdclient->stderr_event->output, fmt, ap);
816 va_end(ap);
818 bufferevent_write(ctx->cmdclient->stderr_event, "\n", 1);
819 ctx->cmdclient->retcode = 1;
822 /* Callback to send print message to client. */
823 void printflike2
824 server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
826 va_list ap;
828 va_start(ap, fmt);
829 evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap);
830 va_end(ap);
832 bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1);
835 /* Callback to send print message to client, if not quiet. */
836 void printflike2
837 server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
839 va_list ap;
841 if (options_get_number(&global_options, "quiet"))
842 return;
844 va_start(ap, fmt);
845 evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap);
846 va_end(ap);
848 bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1);
851 /* Handle command message. */
852 void
853 server_client_msg_command(struct client *c, struct msg_command_data *data)
855 struct cmd_ctx ctx;
856 struct cmd_list *cmdlist = NULL;
857 int argc;
858 char **argv, *cause;
860 ctx.error = server_client_msg_error;
861 ctx.print = server_client_msg_print;
862 ctx.info = server_client_msg_info;
864 ctx.msgdata = data;
865 ctx.curclient = NULL;
867 ctx.cmdclient = c;
869 argc = data->argc;
870 data->argv[(sizeof data->argv) - 1] = '\0';
871 if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) {
872 server_client_msg_error(&ctx, "command too long");
873 goto error;
876 if (argc == 0) {
877 argc = 1;
878 argv = xcalloc(1, sizeof *argv);
879 *argv = xstrdup("new-session");
882 if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
883 server_client_msg_error(&ctx, "%s", cause);
884 cmd_free_argv(argc, argv);
885 goto error;
887 cmd_free_argv(argc, argv);
889 if (cmd_list_exec(cmdlist, &ctx) != 1)
890 c->flags |= CLIENT_EXIT;
891 cmd_list_free(cmdlist);
892 return;
894 error:
895 if (cmdlist != NULL)
896 cmd_list_free(cmdlist);
897 c->flags |= CLIENT_EXIT;
900 /* Handle identify message. */
901 void
902 server_client_msg_identify(
903 struct client *c, struct msg_identify_data *data, int fd)
905 int tty_fd;
907 c->cwd = NULL;
908 data->cwd[(sizeof data->cwd) - 1] = '\0';
909 if (*data->cwd != '\0')
910 c->cwd = xstrdup(data->cwd);
912 if (!isatty(fd))
913 return;
914 if ((tty_fd = dup(fd)) == -1)
915 fatal("dup failed");
916 data->term[(sizeof data->term) - 1] = '\0';
917 tty_init(&c->tty, tty_fd, data->term);
918 if (data->flags & IDENTIFY_UTF8)
919 c->tty.flags |= TTY_UTF8;
920 if (data->flags & IDENTIFY_256COLOURS)
921 c->tty.term_flags |= TERM_256COLOURS;
922 else if (data->flags & IDENTIFY_88COLOURS)
923 c->tty.term_flags |= TERM_88COLOURS;
924 c->tty.key_callback = server_client_handle_key;
925 c->tty.key_data = c;
927 tty_resize(&c->tty);
929 c->flags |= CLIENT_TERMINAL;
932 /* Handle shell message. */
933 void
934 server_client_msg_shell(struct client *c)
936 struct msg_shell_data data;
937 const char *shell;
939 shell = options_get_string(&global_s_options, "default-shell");
941 if (*shell == '\0' || areshell(shell))
942 shell = _PATH_BSHELL;
943 if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell)
944 strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell);
946 server_write_client(c, MSG_SHELL, &data, sizeof data);
947 c->flags |= CLIENT_BAD; /* it will die after exec */