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
) {
518 server_client_check_focus(wp
);
519 server_client_check_resize(wp
);
521 wp
->flags
&= ~PANE_REDRAW
;
526 /* Check if pane should be resized. */
528 server_client_check_resize(struct window_pane
*wp
)
532 if (!(wp
->flags
& PANE_RESIZE
))
535 memset(&ws
, 0, sizeof ws
);
539 if (ioctl(wp
->fd
, TIOCSWINSZ
, &ws
) == -1)
540 fatal("ioctl failed");
542 wp
->flags
&= ~PANE_RESIZE
;
545 /* Check whether pane should be focused. */
547 server_client_check_focus(struct window_pane
*wp
)
553 /* Are focus events off? */
554 if (!options_get_number(&global_options
, "focus-events"))
557 /* Do we need to push the focus state? */
558 push
= wp
->flags
& PANE_FOCUSPUSH
;
559 wp
->flags
&= ~PANE_FOCUSPUSH
;
561 /* If we don't care about focus, forget it. */
562 if (!(wp
->base
.mode
& MODE_FOCUSON
))
565 /* If we're not the active pane in our window, we're not focused. */
566 if (wp
->window
->active
!= wp
)
569 /* If we're in a mode, we're not focused. */
570 if (wp
->screen
!= &wp
->base
)
574 * If our window is the current window in any focused clients with an
575 * attached session, we're focused.
577 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
578 c
= ARRAY_ITEM(&clients
, i
);
579 if (c
== NULL
|| c
->session
== NULL
)
582 if (!(c
->flags
& CLIENT_FOCUSED
))
584 if (c
->session
->flags
& SESSION_UNATTACHED
)
587 if (c
->session
->curw
->window
== wp
->window
)
592 if (push
|| (wp
->flags
& PANE_FOCUSED
))
593 bufferevent_write(wp
->event
, "\033[O", 3);
594 wp
->flags
&= ~PANE_FOCUSED
;
598 if (push
|| !(wp
->flags
& PANE_FOCUSED
))
599 bufferevent_write(wp
->event
, "\033[I", 3);
600 wp
->flags
|= PANE_FOCUSED
;
604 * Update cursor position and mode settings. The scroll region and attributes
605 * are cleared when idle (waiting for an event) as this is the most likely time
606 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
607 * compromise between excessive resets and likelihood of an interrupt.
609 * tty_region/tty_reset/tty_update_mode already take care of not resetting
610 * things that are already in their default state.
613 server_client_reset_state(struct client
*c
)
615 struct window
*w
= c
->session
->curw
->window
;
616 struct window_pane
*wp
= w
->active
;
617 struct screen
*s
= wp
->screen
;
618 struct options
*oo
= &c
->session
->options
;
619 struct options
*wo
= &w
->options
;
622 if (c
->flags
& CLIENT_SUSPENDED
)
625 if (c
->flags
& CLIENT_CONTROL
)
628 tty_region(&c
->tty
, 0, c
->tty
.sy
- 1);
630 status
= options_get_number(oo
, "status");
631 if (!window_pane_visible(wp
) || wp
->yoff
+ s
->cy
>= c
->tty
.sy
- status
)
632 tty_cursor(&c
->tty
, 0, 0);
634 o
= status
&& options_get_number (oo
, "status-position") == 0;
635 tty_cursor(&c
->tty
, wp
->xoff
+ s
->cx
, o
+ wp
->yoff
+ s
->cy
);
639 * Resizing panes with the mouse requires at least button mode to give
640 * a smooth appearance.
643 if ((c
->tty
.mouse
.flags
& MOUSE_RESIZE_PANE
) &&
644 !(mode
& (MODE_MOUSE_BUTTON
|MODE_MOUSE_ANY
)))
645 mode
|= MODE_MOUSE_BUTTON
;
648 * Any mode will do for mouse-select-pane, but set standard mode if
651 if ((mode
& ALL_MOUSE_MODES
) == 0) {
652 if (TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
) != NULL
&&
653 options_get_number(oo
, "mouse-select-pane"))
654 mode
|= MODE_MOUSE_STANDARD
;
655 else if (options_get_number(oo
, "mouse-resize-pane"))
656 mode
|= MODE_MOUSE_STANDARD
;
657 else if (options_get_number(oo
, "mouse-select-window"))
658 mode
|= MODE_MOUSE_STANDARD
;
659 else if (options_get_number(wo
, "mode-mouse"))
660 mode
|= MODE_MOUSE_STANDARD
;
664 * Set UTF-8 mouse input if required. If the terminal is UTF-8, the
665 * user has set mouse-utf8 and any mouse mode is in effect, turn on
666 * UTF-8 mouse input. If the receiving terminal hasn't requested it
667 * (that is, it isn't in s->mode), then it'll be converted in
670 if ((c
->tty
.flags
& TTY_UTF8
) &&
671 (mode
& ALL_MOUSE_MODES
) && options_get_number(oo
, "mouse-utf8"))
672 mode
|= MODE_MOUSE_UTF8
;
674 mode
&= ~MODE_MOUSE_UTF8
;
676 /* Set the terminal mode and reset attributes. */
677 tty_update_mode(&c
->tty
, mode
, s
);
681 /* Repeat time callback. */
683 server_client_repeat_timer(unused
int fd
, unused
short events
, void *data
)
685 struct client
*c
= data
;
687 if (c
->flags
& CLIENT_REPEAT
) {
688 if (c
->flags
& CLIENT_PREFIX
)
689 server_status_client(c
);
690 c
->flags
&= ~(CLIENT_PREFIX
|CLIENT_REPEAT
);
694 /* Check if client should be exited. */
696 server_client_check_exit(struct client
*c
)
698 struct msg_exit_data exitdata
;
700 if (!(c
->flags
& CLIENT_EXIT
))
703 if (EVBUFFER_LENGTH(c
->stdin_data
) != 0)
705 if (EVBUFFER_LENGTH(c
->stdout_data
) != 0)
707 if (EVBUFFER_LENGTH(c
->stderr_data
) != 0)
710 exitdata
.retcode
= c
->retcode
;
711 server_write_client(c
, MSG_EXIT
, &exitdata
, sizeof exitdata
);
713 c
->flags
&= ~CLIENT_EXIT
;
716 /* Check for client redraws. */
718 server_client_check_redraw(struct client
*c
)
720 struct session
*s
= c
->session
;
721 struct window_pane
*wp
;
724 if (c
->flags
& (CLIENT_CONTROL
|CLIENT_SUSPENDED
))
727 flags
= c
->tty
.flags
& TTY_FREEZE
;
728 c
->tty
.flags
&= ~TTY_FREEZE
;
730 if (c
->flags
& (CLIENT_REDRAW
|CLIENT_STATUS
)) {
731 if (options_get_number(&s
->options
, "set-titles"))
732 server_client_set_title(c
);
734 if (c
->message_string
!= NULL
)
735 redraw
= status_message_redraw(c
);
736 else if (c
->prompt_string
!= NULL
)
737 redraw
= status_prompt_redraw(c
);
739 redraw
= status_redraw(c
);
741 c
->flags
&= ~CLIENT_STATUS
;
744 if (c
->flags
& CLIENT_REDRAW
) {
745 screen_redraw_screen(c
, 0, 0);
746 c
->flags
&= ~(CLIENT_STATUS
|CLIENT_BORDERS
);
747 } else if (c
->flags
& CLIENT_REDRAWWINDOW
) {
748 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
)
749 screen_redraw_pane(c
, wp
);
750 c
->flags
&= ~CLIENT_REDRAWWINDOW
;
752 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
) {
753 if (wp
->flags
& PANE_REDRAW
)
754 screen_redraw_pane(c
, wp
);
758 if (c
->flags
& CLIENT_BORDERS
)
759 screen_redraw_screen(c
, 0, 1);
761 if (c
->flags
& CLIENT_STATUS
)
762 screen_redraw_screen(c
, 1, 0);
764 c
->tty
.flags
|= flags
;
766 c
->flags
&= ~(CLIENT_REDRAW
|CLIENT_STATUS
|CLIENT_BORDERS
);
769 /* Set client title. */
771 server_client_set_title(struct client
*c
)
773 struct session
*s
= c
->session
;
774 const char *template;
777 template = options_get_string(&s
->options
, "set-titles-string");
779 title
= status_replace(c
, NULL
, NULL
, NULL
, template, time(NULL
), 1);
780 if (c
->title
== NULL
|| strcmp(title
, c
->title
) != 0) {
782 c
->title
= xstrdup(title
);
783 tty_set_title(&c
->tty
, c
->title
);
788 /* Dispatch message from client. */
790 server_client_msg_dispatch(struct client
*c
)
793 struct msg_command_data commanddata
;
794 struct msg_identify_data identifydata
;
795 struct msg_environ_data environdata
;
796 struct msg_stdin_data stdindata
;
799 if ((n
= imsg_read(&c
->ibuf
)) == -1 || n
== 0)
803 if ((n
= imsg_get(&c
->ibuf
, &imsg
)) == -1)
807 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
809 if (imsg
.hdr
.peerid
!= PROTOCOL_VERSION
) {
810 server_write_client(c
, MSG_VERSION
, NULL
, 0);
811 c
->flags
|= CLIENT_BAD
;
816 log_debug("got %d from client %d", imsg
.hdr
.type
, c
->ibuf
.fd
);
817 switch (imsg
.hdr
.type
) {
819 if (datalen
!= sizeof commanddata
)
820 fatalx("bad MSG_COMMAND size");
821 memcpy(&commanddata
, imsg
.data
, sizeof commanddata
);
823 server_client_msg_command(c
, &commanddata
);
826 if (datalen
!= sizeof identifydata
)
827 fatalx("bad MSG_IDENTIFY size");
828 memcpy(&identifydata
, imsg
.data
, sizeof identifydata
);
830 server_client_msg_identify(c
, &identifydata
, imsg
.fd
);
833 if (datalen
!= sizeof stdindata
)
834 fatalx("bad MSG_STDIN size");
835 memcpy(&stdindata
, imsg
.data
, sizeof stdindata
);
837 if (c
->stdin_callback
== NULL
)
839 if (stdindata
.size
<= 0)
842 evbuffer_add(c
->stdin_data
, stdindata
.data
,
845 c
->stdin_callback(c
, c
->stdin_closed
,
846 c
->stdin_callback_data
);
850 fatalx("bad MSG_RESIZE size");
852 if (c
->flags
& CLIENT_CONTROL
)
854 if (tty_resize(&c
->tty
)) {
856 server_redraw_client(c
);
861 fatalx("bad MSG_EXITING size");
865 server_write_client(c
, MSG_EXITED
, NULL
, 0);
870 fatalx("bad MSG_WAKEUP size");
872 if (!(c
->flags
& CLIENT_SUSPENDED
))
874 c
->flags
&= ~CLIENT_SUSPENDED
;
876 if (gettimeofday(&c
->activity_time
, NULL
) != 0)
877 fatal("gettimeofday");
878 if (c
->session
!= NULL
)
879 session_update_activity(c
->session
);
881 tty_start_tty(&c
->tty
);
882 server_redraw_client(c
);
886 if (datalen
!= sizeof environdata
)
887 fatalx("bad MSG_ENVIRON size");
888 memcpy(&environdata
, imsg
.data
, sizeof environdata
);
890 environdata
.var
[(sizeof environdata
.var
) - 1] = '\0';
891 if (strchr(environdata
.var
, '=') != NULL
)
892 environ_put(&c
->environ
, environdata
.var
);
896 fatalx("bad MSG_SHELL size");
898 server_client_msg_shell(c
);
901 fatalx("unexpected message");
908 /* Handle command message. */
910 server_client_msg_command(struct client
*c
, struct msg_command_data
*data
)
912 struct cmd_list
*cmdlist
= NULL
;
917 data
->argv
[(sizeof data
->argv
) - 1] = '\0';
918 if (cmd_unpack_argv(data
->argv
, sizeof data
->argv
, argc
, &argv
) != 0) {
919 cmdq_error(c
->cmdq
, "command too long");
925 argv
= xcalloc(1, sizeof *argv
);
926 *argv
= xstrdup("new-session");
929 if ((cmdlist
= cmd_list_parse(argc
, argv
, NULL
, 0, &cause
)) == NULL
) {
930 cmdq_error(c
->cmdq
, "%s", cause
);
931 cmd_free_argv(argc
, argv
);
934 cmd_free_argv(argc
, argv
);
936 cmdq_run(c
->cmdq
, cmdlist
);
937 cmd_list_free(cmdlist
);
942 cmd_list_free(cmdlist
);
944 c
->flags
|= CLIENT_EXIT
;
947 /* Handle identify message. */
949 server_client_msg_identify(
950 struct client
*c
, struct msg_identify_data
*data
, int fd
)
953 data
->cwd
[(sizeof data
->cwd
) - 1] = '\0';
954 if (*data
->cwd
!= '\0')
955 c
->cwd
= xstrdup(data
->cwd
);
957 if (data
->flags
& IDENTIFY_CONTROL
) {
958 c
->stdin_callback
= control_callback
;
959 evbuffer_free(c
->stderr_data
);
960 c
->stderr_data
= c
->stdout_data
;
961 c
->flags
|= CLIENT_CONTROL
;
962 if (data
->flags
& IDENTIFY_TERMIOS
)
963 evbuffer_add_printf(c
->stdout_data
, "\033P1000p");
964 server_write_client(c
, MSG_STDIN
, NULL
, 0);
979 data
->term
[(sizeof data
->term
) - 1] = '\0';
980 tty_init(&c
->tty
, c
, fd
, data
->term
);
981 if (data
->flags
& IDENTIFY_UTF8
)
982 c
->tty
.flags
|= TTY_UTF8
;
983 if (data
->flags
& IDENTIFY_256COLOURS
)
984 c
->tty
.term_flags
|= TERM_256COLOURS
;
988 if (!(data
->flags
& IDENTIFY_CONTROL
))
989 c
->flags
|= CLIENT_TERMINAL
;
992 /* Handle shell message. */
994 server_client_msg_shell(struct client
*c
)
996 struct msg_shell_data data
;
999 shell
= options_get_string(&global_s_options
, "default-shell");
1001 if (*shell
== '\0' || areshell(shell
))
1002 shell
= _PATH_BSHELL
;
1003 if (strlcpy(data
.shell
, shell
, sizeof data
.shell
) >= sizeof data
.shell
)
1004 strlcpy(data
.shell
, _PATH_BSHELL
, sizeof data
.shell
);
1006 server_write_client(c
, MSG_SHELL
, &data
, sizeof data
);
1007 c
->flags
|= CLIENT_BAD
; /* it will die after exec */