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>
20 #include <sys/ioctl.h>
32 void server_client_check_focus(struct window_pane
*);
33 void server_client_check_resize(struct window_pane
*);
34 void server_client_check_mouse(struct client
*, struct window_pane
*);
35 void server_client_repeat_timer(int, short, void *);
36 void server_client_check_exit(struct client
*);
37 void server_client_check_redraw(struct client
*);
38 void server_client_set_title(struct client
*);
39 void server_client_reset_state(struct client
*);
40 int server_client_assume_paste(struct session
*);
42 int server_client_msg_dispatch(struct client
*);
43 void server_client_msg_command(struct client
*, struct msg_command_data
*);
44 void server_client_msg_identify(
45 struct client
*, struct msg_identify_data
*, int);
46 void server_client_msg_shell(struct client
*);
48 /* Create a new client. */
50 server_client_create(int fd
)
57 c
= xcalloc(1, sizeof *c
);
59 imsg_init(&c
->ibuf
, fd
);
60 server_update_event(c
);
62 if (gettimeofday(&c
->creation_time
, NULL
) != 0)
63 fatal("gettimeofday failed");
64 memcpy(&c
->activity_time
, &c
->creation_time
, sizeof c
->activity_time
);
66 c
->cmdq
= cmdq_new(c
);
67 c
->cmdq
->client_exit
= 1;
69 c
->stdin_data
= evbuffer_new ();
70 c
->stdout_data
= evbuffer_new ();
71 c
->stderr_data
= evbuffer_new ();
77 c
->last_session
= NULL
;
81 screen_init(&c
->status
, c
->tty
.sx
, 1, 0);
82 RB_INIT(&c
->status_new
);
83 RB_INIT(&c
->status_old
);
85 c
->message_string
= NULL
;
86 ARRAY_INIT(&c
->message_log
);
88 c
->prompt_string
= NULL
;
89 c
->prompt_buffer
= NULL
;
92 c
->tty
.mouse
.xb
= c
->tty
.mouse
.button
= 3;
93 c
->tty
.mouse
.x
= c
->tty
.mouse
.y
= -1;
94 c
->tty
.mouse
.lx
= c
->tty
.mouse
.ly
= -1;
95 c
->tty
.mouse
.sx
= c
->tty
.mouse
.sy
= -1;
96 c
->tty
.mouse
.event
= MOUSE_EVENT_UP
;
97 c
->tty
.mouse
.flags
= 0;
99 c
->flags
|= CLIENT_FOCUSED
;
101 evtimer_set(&c
->repeat_timer
, server_client_repeat_timer
, c
);
103 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
104 if (ARRAY_ITEM(&clients
, i
) == NULL
) {
105 ARRAY_SET(&clients
, i
, c
);
109 ARRAY_ADD(&clients
, c
);
110 log_debug("new client %d", fd
);
113 /* Open client terminal if needed. */
115 server_client_open(struct client
*c
, struct session
*s
, char **cause
)
117 struct options
*oo
= s
!= NULL
? &s
->options
: &global_s_options
;
120 if (c
->flags
& CLIENT_CONTROL
)
123 if (!(c
->flags
& CLIENT_TERMINAL
)) {
124 *cause
= xstrdup ("not a terminal");
128 overrides
= options_get_string(oo
, "terminal-overrides");
129 if (tty_open(&c
->tty
, overrides
, cause
) != 0)
137 server_client_lost(struct client
*c
)
139 struct message_entry
*msg
;
142 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
143 if (ARRAY_ITEM(&clients
, i
) == c
)
144 ARRAY_SET(&clients
, i
, NULL
);
146 log_debug("lost client %d", c
->ibuf
.fd
);
149 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
150 * and tty_free might close an unrelated fd.
152 if (c
->flags
& CLIENT_TERMINAL
)
155 evbuffer_free (c
->stdin_data
);
156 evbuffer_free (c
->stdout_data
);
157 if (c
->stderr_data
!= c
->stdout_data
)
158 evbuffer_free (c
->stderr_data
);
160 status_free_jobs(&c
->status_new
);
161 status_free_jobs(&c
->status_old
);
162 screen_free(&c
->status
);
166 evtimer_del(&c
->repeat_timer
);
168 if (event_initialized(&c
->identify_timer
))
169 evtimer_del(&c
->identify_timer
);
171 free(c
->message_string
);
172 if (event_initialized (&c
->message_timer
))
173 evtimer_del(&c
->message_timer
);
174 for (i
= 0; i
< ARRAY_LENGTH(&c
->message_log
); i
++) {
175 msg
= &ARRAY_ITEM(&c
->message_log
, i
);
178 ARRAY_FREE(&c
->message_log
);
180 free(c
->prompt_string
);
181 free(c
->prompt_buffer
);
188 environ_free(&c
->environ
);
191 imsg_clear(&c
->ibuf
);
192 if (event_initialized(&c
->event
))
193 event_del(&c
->event
);
195 for (i
= 0; i
< ARRAY_LENGTH(&dead_clients
); i
++) {
196 if (ARRAY_ITEM(&dead_clients
, i
) == NULL
) {
197 ARRAY_SET(&dead_clients
, i
, c
);
201 if (i
== ARRAY_LENGTH(&dead_clients
))
202 ARRAY_ADD(&dead_clients
, c
);
203 c
->flags
|= CLIENT_DEAD
;
205 server_add_accept(0); /* may be more file descriptors now */
208 server_check_unattached();
209 server_update_socket();
212 /* Process a single client event. */
214 server_client_callback(int fd
, short events
, void *data
)
216 struct client
*c
= data
;
218 if (c
->flags
& CLIENT_DEAD
)
221 if (fd
== c
->ibuf
.fd
) {
222 if (events
& EV_WRITE
&& msgbuf_write(&c
->ibuf
.w
) < 0)
225 if (c
->flags
& CLIENT_BAD
) {
226 if (c
->ibuf
.w
.queued
== 0)
231 if (events
& EV_READ
&& server_client_msg_dispatch(c
) != 0)
235 server_push_stdout(c
);
236 server_push_stderr(c
);
238 server_update_event(c
);
242 server_client_lost(c
);
245 /* Handle client status timer. */
247 server_client_status_timer(void)
256 if (gettimeofday(&tv
, NULL
) != 0)
257 fatal("gettimeofday failed");
259 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
260 c
= ARRAY_ITEM(&clients
, i
);
261 if (c
== NULL
|| c
->session
== NULL
)
263 if (c
->message_string
!= NULL
|| c
->prompt_string
!= NULL
) {
265 * Don't need timed redraw for messages/prompts so bail
266 * now. The status timer isn't reset when they are
273 if (!options_get_number(&s
->options
, "status"))
275 interval
= options_get_number(&s
->options
, "status-interval");
277 difference
= tv
.tv_sec
- c
->status_timer
.tv_sec
;
278 if (difference
>= interval
) {
279 status_update_jobs(c
);
280 c
->flags
|= CLIENT_STATUS
;
285 /* Check for mouse keys. */
287 server_client_check_mouse(struct client
*c
, struct window_pane
*wp
)
289 struct session
*s
= c
->session
;
290 struct options
*oo
= &s
->options
;
291 struct mouse_event
*m
= &c
->tty
.mouse
;
294 statusat
= status_at_line(c
);
296 /* Is this a window selection click on the status line? */
297 if (statusat
!= -1 && m
->y
== (u_int
)statusat
&&
298 options_get_number(oo
, "mouse-select-window")) {
299 if (m
->event
& MOUSE_EVENT_CLICK
) {
300 status_set_window_at(c
, m
->x
);
301 } else if (m
->event
== MOUSE_EVENT_WHEEL
) {
302 if (m
->wheel
== MOUSE_WHEEL_UP
)
303 session_previous(c
->session
, 0);
304 else if (m
->wheel
== MOUSE_WHEEL_DOWN
)
305 session_next(c
->session
, 0);
306 server_redraw_session(s
);
313 * Not on status line - adjust mouse position if status line is at the
314 * top and limit if at the bottom. From here on a struct mouse
315 * represents the offset onto the window itself.
317 if (statusat
== 0 && m
->y
> 0)
319 else if (statusat
> 0 && m
->y
>= (u_int
)statusat
)
322 /* Is this a pane selection? Allow down only in copy mode. */
323 if (options_get_number(oo
, "mouse-select-pane") &&
324 (m
->event
== MOUSE_EVENT_DOWN
|| wp
->mode
!= &window_copy_mode
)) {
325 window_set_active_at(wp
->window
, m
->x
, m
->y
);
326 server_redraw_window_borders(wp
->window
);
327 wp
= wp
->window
->active
; /* may have changed */
330 /* Check if trying to resize pane. */
331 if (options_get_number(oo
, "mouse-resize-pane"))
332 layout_resize_pane_mouse(c
);
334 /* Update last and pass through to client. */
335 window_pane_mouse(wp
, c
->session
, m
);
338 /* Is this fast enough to probably be a paste? */
340 server_client_assume_paste(struct session
*s
)
345 if ((t
= options_get_number(&s
->options
, "assume-paste-time")) == 0)
348 timersub(&s
->activity_time
, &s
->last_activity_time
, &tv
);
349 if (tv
.tv_sec
== 0 && tv
.tv_usec
< t
* 1000)
354 /* Handle data key input from client. */
356 server_client_handle_key(struct client
*c
, int key
)
360 struct window_pane
*wp
;
362 struct key_binding
*bd
;
363 int xtimeout
, isprefix
, ispaste
;
365 /* Check the client is good to accept input. */
366 if ((c
->flags
& (CLIENT_DEAD
|CLIENT_SUSPENDED
)) != 0)
369 if (c
->session
== NULL
)
373 /* Update the activity timer. */
374 if (gettimeofday(&c
->activity_time
, NULL
) != 0)
375 fatal("gettimeofday failed");
377 memcpy(&s
->last_activity_time
, &s
->activity_time
,
378 sizeof s
->last_activity_time
);
379 memcpy(&s
->activity_time
, &c
->activity_time
, sizeof s
->activity_time
);
381 w
= c
->session
->curw
->window
;
384 /* Special case: number keys jump to pane in identify mode. */
385 if (c
->flags
& CLIENT_IDENTIFY
&& key
>= '0' && key
<= '9') {
386 if (c
->flags
& CLIENT_READONLY
)
389 wp
= window_pane_at_index(w
, key
- '0');
390 if (wp
!= NULL
&& window_pane_visible(wp
))
391 window_set_active_pane(w
, wp
);
392 server_clear_identify(c
);
396 /* Handle status line. */
397 if (!(c
->flags
& CLIENT_READONLY
)) {
398 status_message_clear(c
);
399 server_clear_identify(c
);
401 if (c
->prompt_string
!= NULL
) {
402 if (!(c
->flags
& CLIENT_READONLY
))
403 status_prompt_key(c
, key
);
407 /* Check for mouse keys. */
408 if (key
== KEYC_MOUSE
) {
409 if (c
->flags
& CLIENT_READONLY
)
411 server_client_check_mouse(c
, wp
);
415 /* Is this a prefix key? */
416 if (key
== options_get_number(&s
->options
, "prefix"))
418 else if (key
== options_get_number(&s
->options
, "prefix2"))
423 /* Treat prefix as a regular key when pasting is detected. */
424 ispaste
= server_client_assume_paste(s
);
428 /* No previous prefix key. */
429 if (!(c
->flags
& CLIENT_PREFIX
)) {
431 c
->flags
|= CLIENT_PREFIX
;
432 server_status_client(c
);
436 /* Try as a non-prefix key binding. */
437 if (ispaste
|| (bd
= key_bindings_lookup(key
)) == NULL
) {
438 if (!(c
->flags
& CLIENT_READONLY
))
439 window_pane_key(wp
, s
, key
);
441 key_bindings_dispatch(bd
, c
);
445 /* Prefix key already pressed. Reset prefix and lookup key. */
446 c
->flags
&= ~CLIENT_PREFIX
;
447 server_status_client(c
);
448 if ((bd
= key_bindings_lookup(key
| KEYC_PREFIX
)) == NULL
) {
449 /* If repeating, treat this as a key, else ignore. */
450 if (c
->flags
& CLIENT_REPEAT
) {
451 c
->flags
&= ~CLIENT_REPEAT
;
453 c
->flags
|= CLIENT_PREFIX
;
454 else if (!(c
->flags
& CLIENT_READONLY
))
455 window_pane_key(wp
, s
, key
);
460 /* If already repeating, but this key can't repeat, skip it. */
461 if (c
->flags
& CLIENT_REPEAT
&& !bd
->can_repeat
) {
462 c
->flags
&= ~CLIENT_REPEAT
;
464 c
->flags
|= CLIENT_PREFIX
;
465 else if (!(c
->flags
& CLIENT_READONLY
))
466 window_pane_key(wp
, s
, key
);
470 /* If this key can repeat, reset the repeat flags and timer. */
471 xtimeout
= options_get_number(&s
->options
, "repeat-time");
472 if (xtimeout
!= 0 && bd
->can_repeat
) {
473 c
->flags
|= CLIENT_PREFIX
|CLIENT_REPEAT
;
475 tv
.tv_sec
= xtimeout
/ 1000;
476 tv
.tv_usec
= (xtimeout
% 1000) * 1000L;
477 evtimer_del(&c
->repeat_timer
);
478 evtimer_add(&c
->repeat_timer
, &tv
);
481 /* Dispatch the command. */
482 key_bindings_dispatch(bd
, c
);
485 /* Client functions that need to happen every loop. */
487 server_client_loop(void)
491 struct window_pane
*wp
;
494 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
495 c
= ARRAY_ITEM(&clients
, i
);
499 server_client_check_exit(c
);
500 if (c
->session
!= NULL
) {
501 server_client_check_redraw(c
);
502 server_client_reset_state(c
);
507 * Any windows will have been redrawn as part of clients, so clear
508 * their flags now. Also check pane focus and resize.
510 for (i
= 0; i
< ARRAY_LENGTH(&windows
); i
++) {
511 w
= ARRAY_ITEM(&windows
, i
);
515 w
->flags
&= ~WINDOW_REDRAW
;
516 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
517 server_client_check_focus(wp
);
518 server_client_check_resize(wp
);
519 wp
->flags
&= ~PANE_REDRAW
;
524 /* Check if pane should be resized. */
526 server_client_check_resize(struct window_pane
*wp
)
530 if (wp
->fd
== -1 || !(wp
->flags
& PANE_RESIZE
))
533 memset(&ws
, 0, sizeof ws
);
537 if (ioctl(wp
->fd
, TIOCSWINSZ
, &ws
) == -1) {
540 * Some versions of Solaris apparently can return an error when
541 * resizing; don't know why this happens, can't reproduce on
542 * other platforms and ignoring it doesn't seem to cause any
547 fatal("ioctl failed");
550 wp
->flags
&= ~PANE_RESIZE
;
553 /* Check whether pane should be focused. */
555 server_client_check_focus(struct window_pane
*wp
)
560 /* If we don't care about focus, forget it. */
561 if (!(wp
->base
.mode
& MODE_FOCUSON
))
564 /* If we're not the active pane in our window, we're not focused. */
565 if (wp
->window
->active
!= wp
)
568 /* If we're in a mode, we're not focused. */
569 if (wp
->screen
!= &wp
->base
)
573 * If our window is the current window in any focused clients with an
574 * attached session, we're focused.
576 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
577 c
= ARRAY_ITEM(&clients
, i
);
578 if (c
== NULL
|| c
->session
== NULL
)
581 if (!(c
->flags
& CLIENT_FOCUSED
))
583 if (c
->session
->flags
& SESSION_UNATTACHED
)
586 if (c
->session
->curw
->window
== wp
->window
)
591 if (wp
->flags
& PANE_FOCUSED
)
592 bufferevent_write(wp
->event
, "\033[O", 3);
593 wp
->flags
&= ~PANE_FOCUSED
;
597 if (!(wp
->flags
& PANE_FOCUSED
))
598 bufferevent_write(wp
->event
, "\033[I", 3);
599 wp
->flags
|= PANE_FOCUSED
;
603 * Update cursor position and mode settings. The scroll region and attributes
604 * are cleared when idle (waiting for an event) as this is the most likely time
605 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
606 * compromise between excessive resets and likelihood of an interrupt.
608 * tty_region/tty_reset/tty_update_mode already take care of not resetting
609 * things that are already in their default state.
612 server_client_reset_state(struct client
*c
)
614 struct window
*w
= c
->session
->curw
->window
;
615 struct window_pane
*wp
= w
->active
;
616 struct screen
*s
= wp
->screen
;
617 struct options
*oo
= &c
->session
->options
;
618 struct options
*wo
= &w
->options
;
621 if (c
->flags
& CLIENT_SUSPENDED
)
624 if (c
->flags
& CLIENT_CONTROL
)
627 tty_region(&c
->tty
, 0, c
->tty
.sy
- 1);
629 status
= options_get_number(oo
, "status");
630 if (!window_pane_visible(wp
) || wp
->yoff
+ s
->cy
>= c
->tty
.sy
- status
)
631 tty_cursor(&c
->tty
, 0, 0);
633 o
= status
&& options_get_number (oo
, "status-position") == 0;
634 tty_cursor(&c
->tty
, wp
->xoff
+ s
->cx
, o
+ wp
->yoff
+ s
->cy
);
638 * Resizing panes with the mouse requires at least button mode to give
639 * a smooth appearance.
642 if ((c
->tty
.mouse
.flags
& MOUSE_RESIZE_PANE
) &&
643 !(mode
& (MODE_MOUSE_BUTTON
|MODE_MOUSE_ANY
)))
644 mode
|= MODE_MOUSE_BUTTON
;
647 * Any mode will do for mouse-select-pane, but set standard mode if
650 if ((mode
& ALL_MOUSE_MODES
) == 0) {
651 if (TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
) != NULL
&&
652 options_get_number(oo
, "mouse-select-pane"))
653 mode
|= MODE_MOUSE_STANDARD
;
654 else if (options_get_number(oo
, "mouse-resize-pane"))
655 mode
|= MODE_MOUSE_STANDARD
;
656 else if (options_get_number(oo
, "mouse-select-window"))
657 mode
|= MODE_MOUSE_STANDARD
;
658 else if (options_get_number(wo
, "mode-mouse"))
659 mode
|= MODE_MOUSE_STANDARD
;
663 * Set UTF-8 mouse input if required. If the terminal is UTF-8, the
664 * user has set mouse-utf8 and any mouse mode is in effect, turn on
665 * UTF-8 mouse input. If the receiving terminal hasn't requested it
666 * (that is, it isn't in s->mode), then it'll be converted in
669 if ((c
->tty
.flags
& TTY_UTF8
) &&
670 (mode
& ALL_MOUSE_MODES
) && options_get_number(oo
, "mouse-utf8"))
671 mode
|= MODE_MOUSE_UTF8
;
673 mode
&= ~MODE_MOUSE_UTF8
;
675 /* Set the terminal mode and reset attributes. */
676 tty_update_mode(&c
->tty
, mode
, s
);
680 /* Repeat time callback. */
682 server_client_repeat_timer(unused
int fd
, unused
short events
, void *data
)
684 struct client
*c
= data
;
686 if (c
->flags
& CLIENT_REPEAT
) {
687 if (c
->flags
& CLIENT_PREFIX
)
688 server_status_client(c
);
689 c
->flags
&= ~(CLIENT_PREFIX
|CLIENT_REPEAT
);
693 /* Check if client should be exited. */
695 server_client_check_exit(struct client
*c
)
697 struct msg_exit_data exitdata
;
699 if (!(c
->flags
& CLIENT_EXIT
))
702 if (EVBUFFER_LENGTH(c
->stdin_data
) != 0)
704 if (EVBUFFER_LENGTH(c
->stdout_data
) != 0)
706 if (EVBUFFER_LENGTH(c
->stderr_data
) != 0)
709 exitdata
.retcode
= c
->retcode
;
710 server_write_client(c
, MSG_EXIT
, &exitdata
, sizeof exitdata
);
712 c
->flags
&= ~CLIENT_EXIT
;
715 /* Check for client redraws. */
717 server_client_check_redraw(struct client
*c
)
719 struct session
*s
= c
->session
;
720 struct window_pane
*wp
;
723 if (c
->flags
& (CLIENT_CONTROL
|CLIENT_SUSPENDED
))
726 flags
= c
->tty
.flags
& TTY_FREEZE
;
727 c
->tty
.flags
&= ~TTY_FREEZE
;
729 if (c
->flags
& (CLIENT_REDRAW
|CLIENT_STATUS
)) {
730 if (options_get_number(&s
->options
, "set-titles"))
731 server_client_set_title(c
);
733 if (c
->message_string
!= NULL
)
734 redraw
= status_message_redraw(c
);
735 else if (c
->prompt_string
!= NULL
)
736 redraw
= status_prompt_redraw(c
);
738 redraw
= status_redraw(c
);
740 c
->flags
&= ~CLIENT_STATUS
;
743 if (c
->flags
& CLIENT_REDRAW
) {
744 screen_redraw_screen(c
, 0, 0);
745 c
->flags
&= ~(CLIENT_STATUS
|CLIENT_BORDERS
);
746 } else if (c
->flags
& CLIENT_REDRAWWINDOW
) {
747 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
)
748 screen_redraw_pane(c
, wp
);
749 c
->flags
&= ~CLIENT_REDRAWWINDOW
;
751 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
) {
752 if (wp
->flags
& PANE_REDRAW
)
753 screen_redraw_pane(c
, wp
);
757 if (c
->flags
& CLIENT_BORDERS
)
758 screen_redraw_screen(c
, 0, 1);
760 if (c
->flags
& CLIENT_STATUS
)
761 screen_redraw_screen(c
, 1, 0);
763 c
->tty
.flags
|= flags
;
765 c
->flags
&= ~(CLIENT_REDRAW
|CLIENT_STATUS
|CLIENT_BORDERS
);
768 /* Set client title. */
770 server_client_set_title(struct client
*c
)
772 struct session
*s
= c
->session
;
773 const char *template;
776 template = options_get_string(&s
->options
, "set-titles-string");
778 title
= status_replace(c
, NULL
, NULL
, NULL
, template, time(NULL
), 1);
779 if (c
->title
== NULL
|| strcmp(title
, c
->title
) != 0) {
781 c
->title
= xstrdup(title
);
782 tty_set_title(&c
->tty
, c
->title
);
787 /* Dispatch message from client. */
789 server_client_msg_dispatch(struct client
*c
)
792 struct msg_command_data commanddata
;
793 struct msg_identify_data identifydata
;
794 struct msg_environ_data environdata
;
795 struct msg_stdin_data stdindata
;
798 if ((n
= imsg_read(&c
->ibuf
)) == -1 || n
== 0)
802 if ((n
= imsg_get(&c
->ibuf
, &imsg
)) == -1)
806 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
808 if (imsg
.hdr
.peerid
!= PROTOCOL_VERSION
) {
809 server_write_client(c
, MSG_VERSION
, NULL
, 0);
810 c
->flags
|= CLIENT_BAD
;
815 log_debug("got %d from client %d", imsg
.hdr
.type
, c
->ibuf
.fd
);
816 switch (imsg
.hdr
.type
) {
818 if (datalen
!= sizeof commanddata
)
819 fatalx("bad MSG_COMMAND size");
820 memcpy(&commanddata
, imsg
.data
, sizeof commanddata
);
822 server_client_msg_command(c
, &commanddata
);
825 if (datalen
!= sizeof identifydata
)
826 fatalx("bad MSG_IDENTIFY size");
828 fatalx("MSG_IDENTIFY missing fd");
829 memcpy(&identifydata
, imsg
.data
, sizeof identifydata
);
831 server_client_msg_identify(c
, &identifydata
, imsg
.fd
);
834 if (datalen
!= sizeof stdindata
)
835 fatalx("bad MSG_STDIN size");
836 memcpy(&stdindata
, imsg
.data
, sizeof stdindata
);
838 if (c
->stdin_callback
== NULL
)
840 if (stdindata
.size
<= 0)
843 evbuffer_add(c
->stdin_data
, stdindata
.data
,
846 c
->stdin_callback(c
, c
->stdin_closed
,
847 c
->stdin_callback_data
);
851 fatalx("bad MSG_RESIZE size");
853 if (c
->flags
& CLIENT_CONTROL
)
855 if (tty_resize(&c
->tty
)) {
857 server_redraw_client(c
);
862 fatalx("bad MSG_EXITING size");
866 server_write_client(c
, MSG_EXITED
, NULL
, 0);
871 fatalx("bad MSG_WAKEUP size");
873 if (!(c
->flags
& CLIENT_SUSPENDED
))
875 c
->flags
&= ~CLIENT_SUSPENDED
;
877 if (gettimeofday(&c
->activity_time
, NULL
) != 0)
878 fatal("gettimeofday");
879 if (c
->session
!= NULL
)
880 session_update_activity(c
->session
);
882 tty_start_tty(&c
->tty
);
883 server_redraw_client(c
);
887 if (datalen
!= sizeof environdata
)
888 fatalx("bad MSG_ENVIRON size");
889 memcpy(&environdata
, imsg
.data
, sizeof environdata
);
891 environdata
.var
[(sizeof environdata
.var
) - 1] = '\0';
892 if (strchr(environdata
.var
, '=') != NULL
)
893 environ_put(&c
->environ
, environdata
.var
);
897 fatalx("bad MSG_SHELL size");
899 server_client_msg_shell(c
);
902 fatalx("unexpected message");
909 /* Handle command message. */
911 server_client_msg_command(struct client
*c
, struct msg_command_data
*data
)
913 struct cmd_list
*cmdlist
= NULL
;
918 data
->argv
[(sizeof data
->argv
) - 1] = '\0';
919 if (cmd_unpack_argv(data
->argv
, sizeof data
->argv
, argc
, &argv
) != 0) {
920 cmdq_error(c
->cmdq
, "command too long");
926 argv
= xcalloc(1, sizeof *argv
);
927 *argv
= xstrdup("new-session");
930 if ((cmdlist
= cmd_list_parse(argc
, argv
, NULL
, 0, &cause
)) == NULL
) {
931 cmdq_error(c
->cmdq
, "%s", cause
);
932 cmd_free_argv(argc
, argv
);
935 cmd_free_argv(argc
, argv
);
937 cmdq_run(c
->cmdq
, cmdlist
);
938 cmd_list_free(cmdlist
);
943 cmd_list_free(cmdlist
);
945 c
->flags
|= CLIENT_EXIT
;
948 /* Handle identify message. */
950 server_client_msg_identify(
951 struct client
*c
, struct msg_identify_data
*data
, int fd
)
954 data
->cwd
[(sizeof data
->cwd
) - 1] = '\0';
955 if (*data
->cwd
!= '\0')
956 c
->cwd
= xstrdup(data
->cwd
);
958 if (data
->flags
& IDENTIFY_CONTROL
) {
959 c
->stdin_callback
= control_callback
;
960 evbuffer_free(c
->stderr_data
);
961 c
->stderr_data
= c
->stdout_data
;
962 c
->flags
|= CLIENT_CONTROL
;
963 if (data
->flags
& IDENTIFY_TERMIOS
)
964 evbuffer_add_printf(c
->stdout_data
, "\033P1000p");
965 server_write_client(c
, MSG_STDIN
, NULL
, 0);
978 data
->term
[(sizeof data
->term
) - 1] = '\0';
979 tty_init(&c
->tty
, c
, fd
, data
->term
);
980 if (data
->flags
& IDENTIFY_UTF8
)
981 c
->tty
.flags
|= TTY_UTF8
;
982 if (data
->flags
& IDENTIFY_256COLOURS
)
983 c
->tty
.term_flags
|= TERM_256COLOURS
;
987 if (!(data
->flags
& IDENTIFY_CONTROL
))
988 c
->flags
|= CLIENT_TERMINAL
;
991 /* Handle shell message. */
993 server_client_msg_shell(struct client
*c
)
995 struct msg_shell_data data
;
998 shell
= options_get_string(&global_s_options
, "default-shell");
1000 if (*shell
== '\0' || areshell(shell
))
1001 shell
= _PATH_BSHELL
;
1002 if (strlcpy(data
.shell
, shell
, sizeof data
.shell
) >= sizeof data
.shell
)
1003 strlcpy(data
.shell
, _PATH_BSHELL
, sizeof data
.shell
);
1005 server_write_client(c
, MSG_SHELL
, &data
, sizeof data
);
1006 c
->flags
|= CLIENT_BAD
; /* it will die after exec */