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 imsg
*);
44 void server_client_msg_identify(struct client
*, struct imsg
*);
45 void server_client_msg_shell(struct client
*);
47 /* Create a new client. */
49 server_client_create(int fd
)
56 c
= xcalloc(1, sizeof *c
);
58 imsg_init(&c
->ibuf
, fd
);
59 server_update_event(c
);
61 if (gettimeofday(&c
->creation_time
, NULL
) != 0)
62 fatal("gettimeofday failed");
63 memcpy(&c
->activity_time
, &c
->creation_time
, sizeof c
->activity_time
);
65 c
->cmdq
= cmdq_new(c
);
66 c
->cmdq
->client_exit
= 1;
68 c
->stdin_data
= evbuffer_new ();
69 c
->stdout_data
= evbuffer_new ();
70 c
->stderr_data
= evbuffer_new ();
76 c
->last_session
= NULL
;
80 screen_init(&c
->status
, c
->tty
.sx
, 1, 0);
81 RB_INIT(&c
->status_new
);
82 RB_INIT(&c
->status_old
);
84 c
->message_string
= NULL
;
85 ARRAY_INIT(&c
->message_log
);
87 c
->prompt_string
= NULL
;
88 c
->prompt_buffer
= NULL
;
91 c
->tty
.mouse
.xb
= c
->tty
.mouse
.button
= 3;
92 c
->tty
.mouse
.x
= c
->tty
.mouse
.y
= -1;
93 c
->tty
.mouse
.lx
= c
->tty
.mouse
.ly
= -1;
94 c
->tty
.mouse
.sx
= c
->tty
.mouse
.sy
= -1;
95 c
->tty
.mouse
.event
= MOUSE_EVENT_UP
;
96 c
->tty
.mouse
.flags
= 0;
98 c
->flags
|= CLIENT_FOCUSED
;
100 evtimer_set(&c
->repeat_timer
, server_client_repeat_timer
, c
);
102 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
103 if (ARRAY_ITEM(&clients
, i
) == NULL
) {
104 ARRAY_SET(&clients
, i
, c
);
108 ARRAY_ADD(&clients
, c
);
109 log_debug("new client %d", fd
);
112 /* Open client terminal if needed. */
114 server_client_open(struct client
*c
, struct session
*s
, char **cause
)
116 struct options
*oo
= s
!= NULL
? &s
->options
: &global_s_options
;
119 if (c
->flags
& CLIENT_CONTROL
)
122 if (!(c
->flags
& CLIENT_TERMINAL
)) {
123 *cause
= xstrdup ("not a terminal");
127 overrides
= options_get_string(oo
, "terminal-overrides");
128 if (tty_open(&c
->tty
, overrides
, cause
) != 0)
136 server_client_lost(struct client
*c
)
138 struct message_entry
*msg
;
141 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
142 if (ARRAY_ITEM(&clients
, i
) == c
)
143 ARRAY_SET(&clients
, i
, NULL
);
145 log_debug("lost client %d", c
->ibuf
.fd
);
148 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
149 * and tty_free might close an unrelated fd.
151 if (c
->flags
& CLIENT_TERMINAL
)
156 evbuffer_free (c
->stdin_data
);
157 evbuffer_free (c
->stdout_data
);
158 if (c
->stderr_data
!= c
->stdout_data
)
159 evbuffer_free (c
->stderr_data
);
161 status_free_jobs(&c
->status_new
);
162 status_free_jobs(&c
->status_old
);
163 screen_free(&c
->status
);
168 evtimer_del(&c
->repeat_timer
);
170 if (event_initialized(&c
->identify_timer
))
171 evtimer_del(&c
->identify_timer
);
173 free(c
->message_string
);
174 if (event_initialized (&c
->message_timer
))
175 evtimer_del(&c
->message_timer
);
176 for (i
= 0; i
< ARRAY_LENGTH(&c
->message_log
); i
++) {
177 msg
= &ARRAY_ITEM(&c
->message_log
, i
);
180 ARRAY_FREE(&c
->message_log
);
182 free(c
->prompt_string
);
183 free(c
->prompt_buffer
);
189 environ_free(&c
->environ
);
192 imsg_clear(&c
->ibuf
);
193 if (event_initialized(&c
->event
))
194 event_del(&c
->event
);
196 for (i
= 0; i
< ARRAY_LENGTH(&dead_clients
); i
++) {
197 if (ARRAY_ITEM(&dead_clients
, i
) == NULL
) {
198 ARRAY_SET(&dead_clients
, i
, c
);
202 if (i
== ARRAY_LENGTH(&dead_clients
))
203 ARRAY_ADD(&dead_clients
, c
);
204 c
->flags
|= CLIENT_DEAD
;
206 server_add_accept(0); /* may be more file descriptors now */
209 server_check_unattached();
210 server_update_socket();
213 /* Process a single client event. */
215 server_client_callback(int fd
, short events
, void *data
)
217 struct client
*c
= data
;
219 if (c
->flags
& CLIENT_DEAD
)
222 if (fd
== c
->ibuf
.fd
) {
223 if (events
& EV_WRITE
&& msgbuf_write(&c
->ibuf
.w
) < 0)
226 if (c
->flags
& CLIENT_BAD
) {
227 if (c
->ibuf
.w
.queued
== 0)
232 if (events
& EV_READ
&& server_client_msg_dispatch(c
) != 0)
236 server_push_stdout(c
);
237 server_push_stderr(c
);
239 server_update_event(c
);
243 server_client_lost(c
);
246 /* Handle client status timer. */
248 server_client_status_timer(void)
257 if (gettimeofday(&tv
, NULL
) != 0)
258 fatal("gettimeofday failed");
260 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
261 c
= ARRAY_ITEM(&clients
, i
);
262 if (c
== NULL
|| c
->session
== NULL
)
264 if (c
->message_string
!= NULL
|| c
->prompt_string
!= NULL
) {
266 * Don't need timed redraw for messages/prompts so bail
267 * now. The status timer isn't reset when they are
274 if (!options_get_number(&s
->options
, "status"))
276 interval
= options_get_number(&s
->options
, "status-interval");
278 difference
= tv
.tv_sec
- c
->status_timer
.tv_sec
;
279 if (difference
>= interval
) {
280 status_update_jobs(c
);
281 c
->flags
|= CLIENT_STATUS
;
286 /* Check for mouse keys. */
288 server_client_check_mouse(struct client
*c
, struct window_pane
*wp
)
290 struct session
*s
= c
->session
;
291 struct options
*oo
= &s
->options
;
292 struct mouse_event
*m
= &c
->tty
.mouse
;
295 statusat
= status_at_line(c
);
297 /* Is this a window selection click on the status line? */
298 if (statusat
!= -1 && m
->y
== (u_int
)statusat
&&
299 options_get_number(oo
, "mouse-select-window")) {
300 if (m
->event
& MOUSE_EVENT_CLICK
) {
301 status_set_window_at(c
, m
->x
);
302 } else if (m
->event
== MOUSE_EVENT_WHEEL
) {
303 if (m
->wheel
== MOUSE_WHEEL_UP
)
304 session_previous(c
->session
, 0);
305 else if (m
->wheel
== MOUSE_WHEEL_DOWN
)
306 session_next(c
->session
, 0);
307 server_redraw_session(s
);
314 * Not on status line - adjust mouse position if status line is at the
315 * top and limit if at the bottom. From here on a struct mouse
316 * represents the offset onto the window itself.
318 if (statusat
== 0 && m
->y
> 0)
320 else if (statusat
> 0 && m
->y
>= (u_int
)statusat
)
323 /* Is this a pane selection? Allow down only in copy mode. */
324 if (options_get_number(oo
, "mouse-select-pane") &&
325 (m
->event
== MOUSE_EVENT_DOWN
|| wp
->mode
!= &window_copy_mode
)) {
326 window_set_active_at(wp
->window
, m
->x
, m
->y
);
327 server_redraw_window_borders(wp
->window
);
328 wp
= wp
->window
->active
; /* may have changed */
331 /* Check if trying to resize pane. */
332 if (options_get_number(oo
, "mouse-resize-pane"))
333 layout_resize_pane_mouse(c
);
335 /* Update last and pass through to client. */
336 window_pane_mouse(wp
, c
->session
, m
);
339 /* Is this fast enough to probably be a paste? */
341 server_client_assume_paste(struct session
*s
)
346 if ((t
= options_get_number(&s
->options
, "assume-paste-time")) == 0)
349 timersub(&s
->activity_time
, &s
->last_activity_time
, &tv
);
350 if (tv
.tv_sec
== 0 && tv
.tv_usec
< t
* 1000)
355 /* Handle data key input from client. */
357 server_client_handle_key(struct client
*c
, int key
)
361 struct window_pane
*wp
;
363 struct key_binding
*bd
;
364 int xtimeout
, isprefix
, ispaste
;
366 /* Check the client is good to accept input. */
367 if ((c
->flags
& (CLIENT_DEAD
|CLIENT_SUSPENDED
)) != 0)
370 if (c
->session
== NULL
)
374 /* Update the activity timer. */
375 if (gettimeofday(&c
->activity_time
, NULL
) != 0)
376 fatal("gettimeofday failed");
378 memcpy(&s
->last_activity_time
, &s
->activity_time
,
379 sizeof s
->last_activity_time
);
380 memcpy(&s
->activity_time
, &c
->activity_time
, sizeof s
->activity_time
);
382 w
= c
->session
->curw
->window
;
385 /* Special case: number keys jump to pane in identify mode. */
386 if (c
->flags
& CLIENT_IDENTIFY
&& key
>= '0' && key
<= '9') {
387 if (c
->flags
& CLIENT_READONLY
)
390 wp
= window_pane_at_index(w
, key
- '0');
391 if (wp
!= NULL
&& window_pane_visible(wp
))
392 window_set_active_pane(w
, wp
);
393 server_clear_identify(c
);
397 /* Handle status line. */
398 if (!(c
->flags
& CLIENT_READONLY
)) {
399 status_message_clear(c
);
400 server_clear_identify(c
);
402 if (c
->prompt_string
!= NULL
) {
403 if (!(c
->flags
& CLIENT_READONLY
))
404 status_prompt_key(c
, key
);
408 /* Check for mouse keys. */
409 if (key
== KEYC_MOUSE
) {
410 if (c
->flags
& CLIENT_READONLY
)
412 server_client_check_mouse(c
, wp
);
416 /* Is this a prefix key? */
417 if (key
== options_get_number(&s
->options
, "prefix"))
419 else if (key
== options_get_number(&s
->options
, "prefix2"))
424 /* Treat prefix as a regular key when pasting is detected. */
425 ispaste
= server_client_assume_paste(s
);
429 /* No previous prefix key. */
430 if (!(c
->flags
& CLIENT_PREFIX
)) {
432 c
->flags
|= CLIENT_PREFIX
;
433 server_status_client(c
);
437 /* Try as a non-prefix key binding. */
438 if (ispaste
|| (bd
= key_bindings_lookup(key
)) == NULL
) {
439 if (!(c
->flags
& CLIENT_READONLY
))
440 window_pane_key(wp
, s
, key
);
442 key_bindings_dispatch(bd
, c
);
446 /* Prefix key already pressed. Reset prefix and lookup key. */
447 c
->flags
&= ~CLIENT_PREFIX
;
448 server_status_client(c
);
449 if ((bd
= key_bindings_lookup(key
| KEYC_PREFIX
)) == NULL
) {
450 /* If repeating, treat this as a key, else ignore. */
451 if (c
->flags
& CLIENT_REPEAT
) {
452 c
->flags
&= ~CLIENT_REPEAT
;
454 c
->flags
|= CLIENT_PREFIX
;
455 else if (!(c
->flags
& CLIENT_READONLY
))
456 window_pane_key(wp
, s
, key
);
461 /* If already repeating, but this key can't repeat, skip it. */
462 if (c
->flags
& CLIENT_REPEAT
&& !bd
->can_repeat
) {
463 c
->flags
&= ~CLIENT_REPEAT
;
465 c
->flags
|= CLIENT_PREFIX
;
466 else if (!(c
->flags
& CLIENT_READONLY
))
467 window_pane_key(wp
, s
, key
);
471 /* If this key can repeat, reset the repeat flags and timer. */
472 xtimeout
= options_get_number(&s
->options
, "repeat-time");
473 if (xtimeout
!= 0 && bd
->can_repeat
) {
474 c
->flags
|= CLIENT_PREFIX
|CLIENT_REPEAT
;
476 tv
.tv_sec
= xtimeout
/ 1000;
477 tv
.tv_usec
= (xtimeout
% 1000) * 1000L;
478 evtimer_del(&c
->repeat_timer
);
479 evtimer_add(&c
->repeat_timer
, &tv
);
482 /* Dispatch the command. */
483 key_bindings_dispatch(bd
, c
);
486 /* Client functions that need to happen every loop. */
488 server_client_loop(void)
492 struct window_pane
*wp
;
495 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
496 c
= ARRAY_ITEM(&clients
, i
);
500 server_client_check_exit(c
);
501 if (c
->session
!= NULL
) {
502 server_client_check_redraw(c
);
503 server_client_reset_state(c
);
508 * Any windows will have been redrawn as part of clients, so clear
509 * their flags now. Also check pane focus and resize.
511 for (i
= 0; i
< ARRAY_LENGTH(&windows
); i
++) {
512 w
= ARRAY_ITEM(&windows
, i
);
516 w
->flags
&= ~WINDOW_REDRAW
;
517 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
519 server_client_check_focus(wp
);
520 server_client_check_resize(wp
);
522 wp
->flags
&= ~PANE_REDRAW
;
527 /* Check if pane should be resized. */
529 server_client_check_resize(struct window_pane
*wp
)
533 if (!(wp
->flags
& PANE_RESIZE
))
536 memset(&ws
, 0, sizeof ws
);
540 if (ioctl(wp
->fd
, TIOCSWINSZ
, &ws
) == -1)
541 fatal("ioctl failed");
543 wp
->flags
&= ~PANE_RESIZE
;
546 /* Check whether pane should be focused. */
548 server_client_check_focus(struct window_pane
*wp
)
554 /* Are focus events off? */
555 if (!options_get_number(&global_options
, "focus-events"))
558 /* Do we need to push the focus state? */
559 push
= wp
->flags
& PANE_FOCUSPUSH
;
560 wp
->flags
&= ~PANE_FOCUSPUSH
;
562 /* If we don't care about focus, forget it. */
563 if (!(wp
->base
.mode
& MODE_FOCUSON
))
566 /* If we're not the active pane in our window, we're not focused. */
567 if (wp
->window
->active
!= wp
)
570 /* If we're in a mode, we're not focused. */
571 if (wp
->screen
!= &wp
->base
)
575 * If our window is the current window in any focused clients with an
576 * attached session, we're focused.
578 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
579 c
= ARRAY_ITEM(&clients
, i
);
580 if (c
== NULL
|| c
->session
== NULL
)
583 if (!(c
->flags
& CLIENT_FOCUSED
))
585 if (c
->session
->flags
& SESSION_UNATTACHED
)
588 if (c
->session
->curw
->window
== wp
->window
)
593 if (push
|| (wp
->flags
& PANE_FOCUSED
))
594 bufferevent_write(wp
->event
, "\033[O", 3);
595 wp
->flags
&= ~PANE_FOCUSED
;
599 if (push
|| !(wp
->flags
& PANE_FOCUSED
))
600 bufferevent_write(wp
->event
, "\033[I", 3);
601 wp
->flags
|= PANE_FOCUSED
;
605 * Update cursor position and mode settings. The scroll region and attributes
606 * are cleared when idle (waiting for an event) as this is the most likely time
607 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
608 * compromise between excessive resets and likelihood of an interrupt.
610 * tty_region/tty_reset/tty_update_mode already take care of not resetting
611 * things that are already in their default state.
614 server_client_reset_state(struct client
*c
)
616 struct window
*w
= c
->session
->curw
->window
;
617 struct window_pane
*wp
= w
->active
;
618 struct screen
*s
= wp
->screen
;
619 struct options
*oo
= &c
->session
->options
;
620 struct options
*wo
= &w
->options
;
623 if (c
->flags
& CLIENT_SUSPENDED
)
626 if (c
->flags
& CLIENT_CONTROL
)
629 tty_region(&c
->tty
, 0, c
->tty
.sy
- 1);
631 status
= options_get_number(oo
, "status");
632 if (!window_pane_visible(wp
) || wp
->yoff
+ s
->cy
>= c
->tty
.sy
- status
)
633 tty_cursor(&c
->tty
, 0, 0);
635 o
= status
&& options_get_number (oo
, "status-position") == 0;
636 tty_cursor(&c
->tty
, wp
->xoff
+ s
->cx
, o
+ wp
->yoff
+ s
->cy
);
640 * Resizing panes with the mouse requires at least button mode to give
641 * a smooth appearance.
644 if ((c
->tty
.mouse
.flags
& MOUSE_RESIZE_PANE
) &&
645 !(mode
& (MODE_MOUSE_BUTTON
|MODE_MOUSE_ANY
)))
646 mode
|= MODE_MOUSE_BUTTON
;
649 * Any mode will do for mouse-select-pane, but set standard mode if
652 if ((mode
& ALL_MOUSE_MODES
) == 0) {
653 if (TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
) != NULL
&&
654 options_get_number(oo
, "mouse-select-pane"))
655 mode
|= MODE_MOUSE_STANDARD
;
656 else if (options_get_number(oo
, "mouse-resize-pane"))
657 mode
|= MODE_MOUSE_STANDARD
;
658 else if (options_get_number(oo
, "mouse-select-window"))
659 mode
|= MODE_MOUSE_STANDARD
;
660 else if (options_get_number(wo
, "mode-mouse"))
661 mode
|= MODE_MOUSE_STANDARD
;
665 * Set UTF-8 mouse input if required. If the terminal is UTF-8, the
666 * user has set mouse-utf8 and any mouse mode is in effect, turn on
667 * UTF-8 mouse input. If the receiving terminal hasn't requested it
668 * (that is, it isn't in s->mode), then it'll be converted in
671 if ((c
->tty
.flags
& TTY_UTF8
) &&
672 (mode
& ALL_MOUSE_MODES
) && options_get_number(oo
, "mouse-utf8"))
673 mode
|= MODE_MOUSE_UTF8
;
675 mode
&= ~MODE_MOUSE_UTF8
;
677 /* Set the terminal mode and reset attributes. */
678 tty_update_mode(&c
->tty
, mode
, s
);
682 /* Repeat time callback. */
684 server_client_repeat_timer(unused
int fd
, unused
short events
, void *data
)
686 struct client
*c
= data
;
688 if (c
->flags
& CLIENT_REPEAT
) {
689 if (c
->flags
& CLIENT_PREFIX
)
690 server_status_client(c
);
691 c
->flags
&= ~(CLIENT_PREFIX
|CLIENT_REPEAT
);
695 /* Check if client should be exited. */
697 server_client_check_exit(struct client
*c
)
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 server_write_client(c
, MSG_EXIT
, &c
->retval
, sizeof c
->retval
);
710 c
->flags
&= ~CLIENT_EXIT
;
713 /* Check for client redraws. */
715 server_client_check_redraw(struct client
*c
)
717 struct session
*s
= c
->session
;
718 struct window_pane
*wp
;
721 if (c
->flags
& (CLIENT_CONTROL
|CLIENT_SUSPENDED
))
724 flags
= c
->tty
.flags
& TTY_FREEZE
;
725 c
->tty
.flags
&= ~TTY_FREEZE
;
727 if (c
->flags
& (CLIENT_REDRAW
|CLIENT_STATUS
)) {
728 if (options_get_number(&s
->options
, "set-titles"))
729 server_client_set_title(c
);
731 if (c
->message_string
!= NULL
)
732 redraw
= status_message_redraw(c
);
733 else if (c
->prompt_string
!= NULL
)
734 redraw
= status_prompt_redraw(c
);
736 redraw
= status_redraw(c
);
738 c
->flags
&= ~CLIENT_STATUS
;
741 if (c
->flags
& CLIENT_REDRAW
) {
742 screen_redraw_screen(c
, 0, 0);
743 c
->flags
&= ~(CLIENT_STATUS
|CLIENT_BORDERS
);
744 } else if (c
->flags
& CLIENT_REDRAWWINDOW
) {
745 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
)
746 screen_redraw_pane(c
, wp
);
747 c
->flags
&= ~CLIENT_REDRAWWINDOW
;
749 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
) {
750 if (wp
->flags
& PANE_REDRAW
)
751 screen_redraw_pane(c
, wp
);
755 if (c
->flags
& CLIENT_BORDERS
)
756 screen_redraw_screen(c
, 0, 1);
758 if (c
->flags
& CLIENT_STATUS
)
759 screen_redraw_screen(c
, 1, 0);
761 c
->tty
.flags
|= flags
;
763 c
->flags
&= ~(CLIENT_REDRAW
|CLIENT_STATUS
|CLIENT_BORDERS
);
766 /* Set client title. */
768 server_client_set_title(struct client
*c
)
770 struct session
*s
= c
->session
;
771 const char *template;
774 template = options_get_string(&s
->options
, "set-titles-string");
776 title
= status_replace(c
, NULL
, NULL
, NULL
, template, time(NULL
), 1);
777 if (c
->title
== NULL
|| strcmp(title
, c
->title
) != 0) {
779 c
->title
= xstrdup(title
);
780 tty_set_title(&c
->tty
, c
->title
);
785 /* Dispatch message from client. */
787 server_client_msg_dispatch(struct client
*c
)
790 struct msg_stdin_data stdindata
;
794 if ((n
= imsg_read(&c
->ibuf
)) == -1 || n
== 0)
798 if ((n
= imsg_get(&c
->ibuf
, &imsg
)) == -1)
804 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
806 if (imsg
.hdr
.peerid
!= PROTOCOL_VERSION
) {
807 server_write_client(c
, MSG_VERSION
, NULL
, 0);
808 c
->flags
|= CLIENT_BAD
;
813 log_debug("got %d from client %d", imsg
.hdr
.type
, c
->ibuf
.fd
);
814 switch (imsg
.hdr
.type
) {
815 case MSG_IDENTIFY_FLAGS
:
816 case MSG_IDENTIFY_TERM
:
817 case MSG_IDENTIFY_TTYNAME
:
818 case MSG_IDENTIFY_CWD
:
819 case MSG_IDENTIFY_STDIN
:
820 case MSG_IDENTIFY_ENVIRON
:
821 case MSG_IDENTIFY_DONE
:
822 server_client_msg_identify(c
, &imsg
);
825 server_client_msg_command(c
, &imsg
);
828 if (datalen
!= sizeof stdindata
)
829 fatalx("bad MSG_STDIN size");
830 memcpy(&stdindata
, data
, sizeof stdindata
);
832 if (c
->stdin_callback
== NULL
)
834 if (stdindata
.size
<= 0)
837 evbuffer_add(c
->stdin_data
, stdindata
.data
,
840 c
->stdin_callback(c
, c
->stdin_closed
,
841 c
->stdin_callback_data
);
845 fatalx("bad MSG_RESIZE size");
847 if (c
->flags
& CLIENT_CONTROL
)
849 if (tty_resize(&c
->tty
)) {
851 server_redraw_client(c
);
856 fatalx("bad MSG_EXITING size");
860 server_write_client(c
, MSG_EXITED
, NULL
, 0);
865 fatalx("bad MSG_WAKEUP size");
867 if (!(c
->flags
& CLIENT_SUSPENDED
))
869 c
->flags
&= ~CLIENT_SUSPENDED
;
871 if (gettimeofday(&c
->activity_time
, NULL
) != 0)
872 fatal("gettimeofday");
873 if (c
->session
!= NULL
)
874 session_update_activity(c
->session
);
876 tty_start_tty(&c
->tty
);
877 server_redraw_client(c
);
882 fatalx("bad MSG_SHELL size");
884 server_client_msg_shell(c
);
892 /* Handle command message. */
894 server_client_msg_command(struct client
*c
, struct imsg
*imsg
)
896 struct msg_command_data data
;
899 struct cmd_list
*cmdlist
= NULL
;
903 if (imsg
->hdr
.len
- IMSG_HEADER_SIZE
< sizeof data
)
904 fatalx("bad MSG_COMMAND size");
905 memcpy(&data
, imsg
->data
, sizeof data
);
907 buf
= (char*)imsg
->data
+ sizeof data
;
908 len
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
- sizeof data
;
909 if (len
> 0 && buf
[len
- 1] != '\0')
910 fatalx("bad MSG_COMMAND string");
913 if (cmd_unpack_argv(buf
, len
, argc
, &argv
) != 0) {
914 cmdq_error(c
->cmdq
, "command too long");
920 argv
= xcalloc(1, sizeof *argv
);
921 *argv
= xstrdup("new-session");
924 if ((cmdlist
= cmd_list_parse(argc
, argv
, NULL
, 0, &cause
)) == NULL
) {
925 cmdq_error(c
->cmdq
, "%s", cause
);
926 cmd_free_argv(argc
, argv
);
929 cmd_free_argv(argc
, argv
);
931 cmdq_run(c
->cmdq
, cmdlist
);
932 cmd_list_free(cmdlist
);
937 cmd_list_free(cmdlist
);
939 c
->flags
|= CLIENT_EXIT
;
942 /* Handle identify message. */
944 server_client_msg_identify(struct client
*c
, struct imsg
*imsg
)
950 if (c
->flags
& CLIENT_IDENTIFIED
)
951 fatalx("out-of-order identify message");
954 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
956 switch (imsg
->hdr
.type
) {
957 case MSG_IDENTIFY_FLAGS
:
958 if (datalen
!= sizeof flags
)
959 fatalx("bad MSG_IDENTIFY_FLAGS size");
960 memcpy(&flags
, data
, sizeof flags
);
963 case MSG_IDENTIFY_TERM
:
964 if (data
[datalen
- 1] != '\0')
965 fatalx("bad MSG_IDENTIFY_TERM string");
966 c
->term
= xstrdup(data
);
968 case MSG_IDENTIFY_TTYNAME
:
969 if (data
[datalen
- 1] != '\0')
970 fatalx("bad MSG_IDENTIFY_TTYNAME string");
971 c
->ttyname
= xstrdup(data
);
973 case MSG_IDENTIFY_CWD
:
975 fatalx("bad MSG_IDENTIFY_CWD size");
978 case MSG_IDENTIFY_STDIN
:
980 fatalx("bad MSG_IDENTIFY_STDIN size");
983 case MSG_IDENTIFY_ENVIRON
:
984 if (data
[datalen
- 1] != '\0')
985 fatalx("bad MSG_IDENTIFY_ENVIRON string");
986 if (strchr(data
, '=') != NULL
)
987 environ_put(&c
->environ
, data
);
993 if (imsg
->hdr
.type
!= MSG_IDENTIFY_DONE
)
995 c
->flags
|= CLIENT_IDENTIFIED
;
998 c
->fd
= open(c
->ttyname
, O_RDWR
|O_NOCTTY
);
999 c
->cwd
= open(".", O_RDONLY
);
1002 if (c
->flags
& CLIENT_CONTROL
) {
1003 c
->stdin_callback
= control_callback
;
1005 evbuffer_free(c
->stderr_data
);
1006 c
->stderr_data
= c
->stdout_data
;
1008 if (c
->flags
& CLIENT_CONTROLCONTROL
)
1009 evbuffer_add_printf(c
->stdout_data
, "\033P1000p");
1010 server_write_client(c
, MSG_STDIN
, NULL
, 0);
1023 if (!isatty(c
->fd
)) {
1028 tty_init(&c
->tty
, c
, c
->fd
, c
->term
);
1029 if (c
->flags
& CLIENT_UTF8
)
1030 c
->tty
.flags
|= TTY_UTF8
;
1031 if (c
->flags
& CLIENT_256COLOURS
)
1032 c
->tty
.term_flags
|= TERM_256COLOURS
;
1034 tty_resize(&c
->tty
);
1036 if (!(c
->flags
& CLIENT_CONTROL
))
1037 c
->flags
|= CLIENT_TERMINAL
;
1040 /* Handle shell message. */
1042 server_client_msg_shell(struct client
*c
)
1046 shell
= options_get_string(&global_s_options
, "default-shell");
1047 if (*shell
== '\0' || areshell(shell
))
1048 shell
= _PATH_BSHELL
;
1049 server_write_client(c
, MSG_SHELL
, shell
, strlen(shell
) + 1);
1051 c
->flags
|= CLIENT_BAD
; /* it will die after exec */