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>
33 void server_client_check_focus(struct window_pane
*);
34 void server_client_check_resize(struct window_pane
*);
35 void server_client_check_mouse(struct client
*, struct window_pane
*);
36 void server_client_repeat_timer(int, short, void *);
37 void server_client_check_exit(struct client
*);
38 void server_client_check_redraw(struct client
*);
39 void server_client_set_title(struct client
*);
40 void server_client_reset_state(struct client
*);
41 int server_client_assume_paste(struct session
*);
43 int server_client_msg_dispatch(struct client
*);
44 void server_client_msg_command(struct client
*, struct imsg
*);
45 void server_client_msg_identify(struct client
*, struct imsg
*);
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 environ_init(&c
->environ
);
68 c
->cmdq
= cmdq_new(c
);
69 c
->cmdq
->client_exit
= 1;
71 c
->stdin_data
= evbuffer_new ();
72 c
->stdout_data
= evbuffer_new ();
73 c
->stderr_data
= evbuffer_new ();
79 c
->last_session
= NULL
;
83 screen_init(&c
->status
, c
->tty
.sx
, 1, 0);
84 RB_INIT(&c
->status_new
);
85 RB_INIT(&c
->status_old
);
87 c
->message_string
= NULL
;
88 ARRAY_INIT(&c
->message_log
);
90 c
->prompt_string
= NULL
;
91 c
->prompt_buffer
= NULL
;
94 c
->tty
.mouse
.xb
= c
->tty
.mouse
.button
= 3;
95 c
->tty
.mouse
.x
= c
->tty
.mouse
.y
= -1;
96 c
->tty
.mouse
.lx
= c
->tty
.mouse
.ly
= -1;
97 c
->tty
.mouse
.sx
= c
->tty
.mouse
.sy
= -1;
98 c
->tty
.mouse
.event
= MOUSE_EVENT_UP
;
99 c
->tty
.mouse
.flags
= 0;
101 c
->flags
|= CLIENT_FOCUSED
;
103 evtimer_set(&c
->repeat_timer
, server_client_repeat_timer
, c
);
105 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
106 if (ARRAY_ITEM(&clients
, i
) == NULL
) {
107 ARRAY_SET(&clients
, i
, c
);
111 ARRAY_ADD(&clients
, c
);
112 log_debug("new client %d", fd
);
115 /* Open client terminal if needed. */
117 server_client_open(struct client
*c
, struct session
*s
, char **cause
)
119 struct options
*oo
= s
!= NULL
? &s
->options
: &global_s_options
;
122 if (c
->flags
& CLIENT_CONTROL
)
125 if (!(c
->flags
& CLIENT_TERMINAL
)) {
126 *cause
= xstrdup ("not a terminal");
130 overrides
= options_get_string(oo
, "terminal-overrides");
131 if (tty_open(&c
->tty
, overrides
, cause
) != 0)
139 server_client_lost(struct client
*c
)
141 struct message_entry
*msg
;
144 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
145 if (ARRAY_ITEM(&clients
, i
) == c
)
146 ARRAY_SET(&clients
, i
, NULL
);
148 log_debug("lost client %d", c
->ibuf
.fd
);
151 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
152 * and tty_free might close an unrelated fd.
154 if (c
->flags
& CLIENT_TERMINAL
)
159 evbuffer_free(c
->stdin_data
);
160 evbuffer_free(c
->stdout_data
);
161 if (c
->stderr_data
!= c
->stdout_data
)
162 evbuffer_free (c
->stderr_data
);
164 status_free_jobs(&c
->status_new
);
165 status_free_jobs(&c
->status_old
);
166 screen_free(&c
->status
);
171 evtimer_del(&c
->repeat_timer
);
173 if (event_initialized(&c
->identify_timer
))
174 evtimer_del(&c
->identify_timer
);
176 free(c
->message_string
);
177 if (event_initialized (&c
->message_timer
))
178 evtimer_del(&c
->message_timer
);
179 for (i
= 0; i
< ARRAY_LENGTH(&c
->message_log
); i
++) {
180 msg
= &ARRAY_ITEM(&c
->message_log
, i
);
183 ARRAY_FREE(&c
->message_log
);
185 free(c
->prompt_string
);
186 free(c
->prompt_buffer
);
192 environ_free(&c
->environ
);
195 imsg_clear(&c
->ibuf
);
196 if (event_initialized(&c
->event
))
197 event_del(&c
->event
);
199 for (i
= 0; i
< ARRAY_LENGTH(&dead_clients
); i
++) {
200 if (ARRAY_ITEM(&dead_clients
, i
) == NULL
) {
201 ARRAY_SET(&dead_clients
, i
, c
);
205 if (i
== ARRAY_LENGTH(&dead_clients
))
206 ARRAY_ADD(&dead_clients
, c
);
207 c
->flags
|= CLIENT_DEAD
;
209 server_add_accept(0); /* may be more file descriptors now */
212 server_check_unattached();
213 server_update_socket();
216 /* Process a single client event. */
218 server_client_callback(int fd
, short events
, void *data
)
220 struct client
*c
= data
;
222 if (c
->flags
& CLIENT_DEAD
)
225 if (fd
== c
->ibuf
.fd
) {
226 if (events
& EV_WRITE
&& msgbuf_write(&c
->ibuf
.w
) < 0 &&
230 if (c
->flags
& CLIENT_BAD
) {
231 if (c
->ibuf
.w
.queued
== 0)
236 if (events
& EV_READ
&& server_client_msg_dispatch(c
) != 0)
240 server_push_stdout(c
);
241 server_push_stderr(c
);
243 server_update_event(c
);
247 server_client_lost(c
);
250 /* Handle client status timer. */
252 server_client_status_timer(void)
261 if (gettimeofday(&tv
, NULL
) != 0)
262 fatal("gettimeofday failed");
264 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
265 c
= ARRAY_ITEM(&clients
, i
);
266 if (c
== NULL
|| c
->session
== NULL
)
268 if (c
->message_string
!= NULL
|| c
->prompt_string
!= NULL
) {
270 * Don't need timed redraw for messages/prompts so bail
271 * now. The status timer isn't reset when they are
278 if (!options_get_number(&s
->options
, "status"))
280 interval
= options_get_number(&s
->options
, "status-interval");
282 difference
= tv
.tv_sec
- c
->status_timer
.tv_sec
;
283 if (difference
>= interval
) {
284 status_update_jobs(c
);
285 c
->flags
|= CLIENT_STATUS
;
290 /* Check for mouse keys. */
292 server_client_check_mouse(struct client
*c
, struct window_pane
*wp
)
294 struct session
*s
= c
->session
;
295 struct options
*oo
= &s
->options
;
296 struct mouse_event
*m
= &c
->tty
.mouse
;
299 statusat
= status_at_line(c
);
301 /* Is this a window selection click on the status line? */
302 if (statusat
!= -1 && m
->y
== (u_int
)statusat
&&
303 options_get_number(oo
, "mouse-select-window")) {
304 if (m
->event
& MOUSE_EVENT_CLICK
) {
305 status_set_window_at(c
, m
->x
);
306 } else if (m
->event
== MOUSE_EVENT_WHEEL
) {
307 if (m
->wheel
== MOUSE_WHEEL_UP
)
308 session_previous(c
->session
, 0);
309 else if (m
->wheel
== MOUSE_WHEEL_DOWN
)
310 session_next(c
->session
, 0);
311 server_redraw_session(s
);
318 * Not on status line - adjust mouse position if status line is at the
319 * top and limit if at the bottom. From here on a struct mouse
320 * represents the offset onto the window itself.
322 if (statusat
== 0 && m
->y
> 0)
324 else if (statusat
> 0 && m
->y
>= (u_int
)statusat
)
327 /* Is this a pane selection? Allow down only in copy mode. */
328 if (options_get_number(oo
, "mouse-select-pane") &&
329 (m
->event
== MOUSE_EVENT_DOWN
|| wp
->mode
!= &window_copy_mode
)) {
330 window_set_active_at(wp
->window
, m
->x
, m
->y
);
331 server_redraw_window_borders(wp
->window
);
332 wp
= wp
->window
->active
; /* may have changed */
335 /* Check if trying to resize pane. */
336 if (options_get_number(oo
, "mouse-resize-pane"))
337 layout_resize_pane_mouse(c
);
339 /* Update last and pass through to client. */
340 window_pane_mouse(wp
, c
->session
, m
);
343 /* Is this fast enough to probably be a paste? */
345 server_client_assume_paste(struct session
*s
)
350 if ((t
= options_get_number(&s
->options
, "assume-paste-time")) == 0)
353 timersub(&s
->activity_time
, &s
->last_activity_time
, &tv
);
354 if (tv
.tv_sec
== 0 && tv
.tv_usec
< t
* 1000)
359 /* Handle data key input from client. */
361 server_client_handle_key(struct client
*c
, int key
)
365 struct window_pane
*wp
;
367 struct key_binding
*bd
;
368 int xtimeout
, isprefix
, ispaste
;
370 /* Check the client is good to accept input. */
371 if ((c
->flags
& (CLIENT_DEAD
|CLIENT_SUSPENDED
)) != 0)
374 if (c
->session
== NULL
)
378 /* Update the activity timer. */
379 if (gettimeofday(&c
->activity_time
, NULL
) != 0)
380 fatal("gettimeofday failed");
382 memcpy(&s
->last_activity_time
, &s
->activity_time
,
383 sizeof s
->last_activity_time
);
384 memcpy(&s
->activity_time
, &c
->activity_time
, sizeof s
->activity_time
);
386 w
= c
->session
->curw
->window
;
389 /* Special case: number keys jump to pane in identify mode. */
390 if (c
->flags
& CLIENT_IDENTIFY
&& key
>= '0' && key
<= '9') {
391 if (c
->flags
& CLIENT_READONLY
)
394 wp
= window_pane_at_index(w
, key
- '0');
395 if (wp
!= NULL
&& window_pane_visible(wp
))
396 window_set_active_pane(w
, wp
);
397 server_clear_identify(c
);
401 /* Handle status line. */
402 if (!(c
->flags
& CLIENT_READONLY
)) {
403 status_message_clear(c
);
404 server_clear_identify(c
);
406 if (c
->prompt_string
!= NULL
) {
407 if (!(c
->flags
& CLIENT_READONLY
))
408 status_prompt_key(c
, key
);
412 /* Check for mouse keys. */
413 if (key
== KEYC_MOUSE
) {
414 if (c
->flags
& CLIENT_READONLY
)
416 server_client_check_mouse(c
, wp
);
420 /* Is this a prefix key? */
421 if (key
== options_get_number(&s
->options
, "prefix"))
423 else if (key
== options_get_number(&s
->options
, "prefix2"))
428 /* Treat prefix as a regular key when pasting is detected. */
429 ispaste
= server_client_assume_paste(s
);
433 /* No previous prefix key. */
434 if (!(c
->flags
& CLIENT_PREFIX
)) {
436 c
->flags
|= CLIENT_PREFIX
;
437 server_status_client(c
);
441 /* Try as a non-prefix key binding. */
442 if (ispaste
|| (bd
= key_bindings_lookup(key
)) == NULL
) {
443 if (!(c
->flags
& CLIENT_READONLY
))
444 window_pane_key(wp
, s
, key
);
446 key_bindings_dispatch(bd
, c
);
450 /* Prefix key already pressed. Reset prefix and lookup key. */
451 c
->flags
&= ~CLIENT_PREFIX
;
452 server_status_client(c
);
453 if ((bd
= key_bindings_lookup(key
| KEYC_PREFIX
)) == NULL
) {
454 /* If repeating, treat this as a key, else ignore. */
455 if (c
->flags
& CLIENT_REPEAT
) {
456 c
->flags
&= ~CLIENT_REPEAT
;
458 c
->flags
|= CLIENT_PREFIX
;
459 else if (!(c
->flags
& CLIENT_READONLY
))
460 window_pane_key(wp
, s
, key
);
465 /* If already repeating, but this key can't repeat, skip it. */
466 if (c
->flags
& CLIENT_REPEAT
&& !bd
->can_repeat
) {
467 c
->flags
&= ~CLIENT_REPEAT
;
469 c
->flags
|= CLIENT_PREFIX
;
470 else if (!(c
->flags
& CLIENT_READONLY
))
471 window_pane_key(wp
, s
, key
);
475 /* If this key can repeat, reset the repeat flags and timer. */
476 xtimeout
= options_get_number(&s
->options
, "repeat-time");
477 if (xtimeout
!= 0 && bd
->can_repeat
) {
478 c
->flags
|= CLIENT_PREFIX
|CLIENT_REPEAT
;
480 tv
.tv_sec
= xtimeout
/ 1000;
481 tv
.tv_usec
= (xtimeout
% 1000) * 1000L;
482 evtimer_del(&c
->repeat_timer
);
483 evtimer_add(&c
->repeat_timer
, &tv
);
486 /* Dispatch the command. */
487 key_bindings_dispatch(bd
, c
);
490 /* Client functions that need to happen every loop. */
492 server_client_loop(void)
496 struct window_pane
*wp
;
499 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
500 c
= ARRAY_ITEM(&clients
, i
);
504 server_client_check_exit(c
);
505 if (c
->session
!= NULL
) {
506 server_client_check_redraw(c
);
507 server_client_reset_state(c
);
512 * Any windows will have been redrawn as part of clients, so clear
513 * their flags now. Also check pane focus and resize.
515 for (i
= 0; i
< ARRAY_LENGTH(&windows
); i
++) {
516 w
= ARRAY_ITEM(&windows
, i
);
520 w
->flags
&= ~WINDOW_REDRAW
;
521 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
523 server_client_check_focus(wp
);
524 server_client_check_resize(wp
);
526 wp
->flags
&= ~PANE_REDRAW
;
531 /* Check if pane should be resized. */
533 server_client_check_resize(struct window_pane
*wp
)
537 if (!(wp
->flags
& PANE_RESIZE
))
540 memset(&ws
, 0, sizeof ws
);
544 if (ioctl(wp
->fd
, TIOCSWINSZ
, &ws
) == -1)
545 fatal("ioctl failed");
547 wp
->flags
&= ~PANE_RESIZE
;
550 /* Check whether pane should be focused. */
552 server_client_check_focus(struct window_pane
*wp
)
558 /* Are focus events off? */
559 if (!options_get_number(&global_options
, "focus-events"))
562 /* Do we need to push the focus state? */
563 push
= wp
->flags
& PANE_FOCUSPUSH
;
564 wp
->flags
&= ~PANE_FOCUSPUSH
;
566 /* If we don't care about focus, forget it. */
567 if (!(wp
->base
.mode
& MODE_FOCUSON
))
570 /* If we're not the active pane in our window, we're not focused. */
571 if (wp
->window
->active
!= wp
)
574 /* If we're in a mode, we're not focused. */
575 if (wp
->screen
!= &wp
->base
)
579 * If our window is the current window in any focused clients with an
580 * attached session, we're focused.
582 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
583 c
= ARRAY_ITEM(&clients
, i
);
584 if (c
== NULL
|| c
->session
== NULL
)
587 if (!(c
->flags
& CLIENT_FOCUSED
))
589 if (c
->session
->flags
& SESSION_UNATTACHED
)
592 if (c
->session
->curw
->window
== wp
->window
)
597 if (push
|| (wp
->flags
& PANE_FOCUSED
))
598 bufferevent_write(wp
->event
, "\033[O", 3);
599 wp
->flags
&= ~PANE_FOCUSED
;
603 if (push
|| !(wp
->flags
& PANE_FOCUSED
))
604 bufferevent_write(wp
->event
, "\033[I", 3);
605 wp
->flags
|= PANE_FOCUSED
;
609 * Update cursor position and mode settings. The scroll region and attributes
610 * are cleared when idle (waiting for an event) as this is the most likely time
611 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
612 * compromise between excessive resets and likelihood of an interrupt.
614 * tty_region/tty_reset/tty_update_mode already take care of not resetting
615 * things that are already in their default state.
618 server_client_reset_state(struct client
*c
)
620 struct window
*w
= c
->session
->curw
->window
;
621 struct window_pane
*wp
= w
->active
;
622 struct screen
*s
= wp
->screen
;
623 struct options
*oo
= &c
->session
->options
;
624 struct options
*wo
= &w
->options
;
627 if (c
->flags
& CLIENT_SUSPENDED
)
630 if (c
->flags
& CLIENT_CONTROL
)
633 tty_region(&c
->tty
, 0, c
->tty
.sy
- 1);
635 status
= options_get_number(oo
, "status");
636 if (!window_pane_visible(wp
) || wp
->yoff
+ s
->cy
>= c
->tty
.sy
- status
)
637 tty_cursor(&c
->tty
, 0, 0);
639 o
= status
&& options_get_number (oo
, "status-position") == 0;
640 tty_cursor(&c
->tty
, wp
->xoff
+ s
->cx
, o
+ wp
->yoff
+ s
->cy
);
644 * Resizing panes with the mouse requires at least button mode to give
645 * a smooth appearance.
648 if ((c
->tty
.mouse
.flags
& MOUSE_RESIZE_PANE
) &&
649 !(mode
& (MODE_MOUSE_BUTTON
|MODE_MOUSE_ANY
)))
650 mode
|= MODE_MOUSE_BUTTON
;
653 * Any mode will do for mouse-select-pane, but set standard mode if
656 if ((mode
& ALL_MOUSE_MODES
) == 0) {
657 if (TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
) != NULL
&&
658 options_get_number(oo
, "mouse-select-pane"))
659 mode
|= MODE_MOUSE_STANDARD
;
660 else if (options_get_number(oo
, "mouse-resize-pane"))
661 mode
|= MODE_MOUSE_STANDARD
;
662 else if (options_get_number(oo
, "mouse-select-window"))
663 mode
|= MODE_MOUSE_STANDARD
;
664 else if (options_get_number(wo
, "mode-mouse"))
665 mode
|= MODE_MOUSE_STANDARD
;
669 * Set UTF-8 mouse input if required. If the terminal is UTF-8, the
670 * user has set mouse-utf8 and any mouse mode is in effect, turn on
671 * UTF-8 mouse input. If the receiving terminal hasn't requested it
672 * (that is, it isn't in s->mode), then it'll be converted in
675 if ((c
->tty
.flags
& TTY_UTF8
) &&
676 (mode
& ALL_MOUSE_MODES
) && options_get_number(oo
, "mouse-utf8"))
677 mode
|= MODE_MOUSE_UTF8
;
679 mode
&= ~MODE_MOUSE_UTF8
;
681 /* Set the terminal mode and reset attributes. */
682 tty_update_mode(&c
->tty
, mode
, s
);
686 /* Repeat time callback. */
688 server_client_repeat_timer(unused
int fd
, unused
short events
, void *data
)
690 struct client
*c
= data
;
692 if (c
->flags
& CLIENT_REPEAT
) {
693 if (c
->flags
& CLIENT_PREFIX
)
694 server_status_client(c
);
695 c
->flags
&= ~(CLIENT_PREFIX
|CLIENT_REPEAT
);
699 /* Check if client should be exited. */
701 server_client_check_exit(struct client
*c
)
703 if (!(c
->flags
& CLIENT_EXIT
))
706 if (EVBUFFER_LENGTH(c
->stdin_data
) != 0)
708 if (EVBUFFER_LENGTH(c
->stdout_data
) != 0)
710 if (EVBUFFER_LENGTH(c
->stderr_data
) != 0)
713 server_write_client(c
, MSG_EXIT
, &c
->retval
, sizeof c
->retval
);
714 c
->flags
&= ~CLIENT_EXIT
;
717 /* Check for client redraws. */
719 server_client_check_redraw(struct client
*c
)
721 struct session
*s
= c
->session
;
722 struct window_pane
*wp
;
725 if (c
->flags
& (CLIENT_CONTROL
|CLIENT_SUSPENDED
))
728 flags
= c
->tty
.flags
& TTY_FREEZE
;
729 c
->tty
.flags
&= ~TTY_FREEZE
;
731 if (c
->flags
& (CLIENT_REDRAW
|CLIENT_STATUS
)) {
732 if (options_get_number(&s
->options
, "set-titles"))
733 server_client_set_title(c
);
735 if (c
->message_string
!= NULL
)
736 redraw
= status_message_redraw(c
);
737 else if (c
->prompt_string
!= NULL
)
738 redraw
= status_prompt_redraw(c
);
740 redraw
= status_redraw(c
);
742 c
->flags
&= ~CLIENT_STATUS
;
745 if (c
->flags
& CLIENT_REDRAW
) {
746 screen_redraw_screen(c
, 0, 0);
747 c
->flags
&= ~(CLIENT_STATUS
|CLIENT_BORDERS
);
748 } else if (c
->flags
& CLIENT_REDRAWWINDOW
) {
749 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
)
750 screen_redraw_pane(c
, wp
);
751 c
->flags
&= ~CLIENT_REDRAWWINDOW
;
753 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
) {
754 if (wp
->flags
& PANE_REDRAW
)
755 screen_redraw_pane(c
, wp
);
759 if (c
->flags
& CLIENT_BORDERS
)
760 screen_redraw_screen(c
, 0, 1);
762 if (c
->flags
& CLIENT_STATUS
)
763 screen_redraw_screen(c
, 1, 0);
765 c
->tty
.flags
|= flags
;
767 c
->flags
&= ~(CLIENT_REDRAW
|CLIENT_STATUS
|CLIENT_BORDERS
);
770 /* Set client title. */
772 server_client_set_title(struct client
*c
)
774 struct session
*s
= c
->session
;
775 const char *template;
778 template = options_get_string(&s
->options
, "set-titles-string");
780 title
= status_replace(c
, NULL
, NULL
, NULL
, template, time(NULL
), 1);
781 if (c
->title
== NULL
|| strcmp(title
, c
->title
) != 0) {
783 c
->title
= xstrdup(title
);
784 tty_set_title(&c
->tty
, c
->title
);
789 /* Dispatch message from client. */
791 server_client_msg_dispatch(struct client
*c
)
794 struct msg_stdin_data stdindata
;
798 if ((n
= imsg_read(&c
->ibuf
)) == -1 || n
== 0)
802 if ((n
= imsg_get(&c
->ibuf
, &imsg
)) == -1)
808 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
810 if (imsg
.hdr
.peerid
!= PROTOCOL_VERSION
) {
811 server_write_client(c
, MSG_VERSION
, NULL
, 0);
812 c
->flags
|= CLIENT_BAD
;
819 log_debug("got %d from client %d", imsg
.hdr
.type
, c
->ibuf
.fd
);
820 switch (imsg
.hdr
.type
) {
821 case MSG_IDENTIFY_FLAGS
:
822 case MSG_IDENTIFY_TERM
:
823 case MSG_IDENTIFY_TTYNAME
:
824 case MSG_IDENTIFY_CWD
:
825 case MSG_IDENTIFY_STDIN
:
826 case MSG_IDENTIFY_ENVIRON
:
827 case MSG_IDENTIFY_DONE
:
828 server_client_msg_identify(c
, &imsg
);
831 server_client_msg_command(c
, &imsg
);
834 if (datalen
!= sizeof stdindata
)
835 fatalx("bad MSG_STDIN size");
836 memcpy(&stdindata
, 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
);
888 fatalx("bad MSG_SHELL size");
890 server_client_msg_shell(c
);
898 /* Handle command message. */
900 server_client_msg_command(struct client
*c
, struct imsg
*imsg
)
902 struct msg_command_data data
;
905 struct cmd_list
*cmdlist
= NULL
;
909 if (imsg
->hdr
.len
- IMSG_HEADER_SIZE
< sizeof data
)
910 fatalx("bad MSG_COMMAND size");
911 memcpy(&data
, imsg
->data
, sizeof data
);
913 buf
= (char*)imsg
->data
+ sizeof data
;
914 len
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
- sizeof data
;
915 if (len
> 0 && buf
[len
- 1] != '\0')
916 fatalx("bad MSG_COMMAND string");
919 if (cmd_unpack_argv(buf
, len
, 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 if (c
!= cfg_client
|| cfg_finished
)
938 cmdq_run(c
->cmdq
, cmdlist
);
940 cmdq_append(c
->cmdq
, cmdlist
);
941 cmd_list_free(cmdlist
);
946 cmd_list_free(cmdlist
);
948 c
->flags
|= CLIENT_EXIT
;
951 /* Handle identify message. */
953 server_client_msg_identify(struct client
*c
, struct imsg
*imsg
)
959 if (c
->flags
& CLIENT_IDENTIFIED
)
960 fatalx("out-of-order identify message");
963 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
965 switch (imsg
->hdr
.type
) {
966 case MSG_IDENTIFY_FLAGS
:
967 if (datalen
!= sizeof flags
)
968 fatalx("bad MSG_IDENTIFY_FLAGS size");
969 memcpy(&flags
, data
, sizeof flags
);
972 case MSG_IDENTIFY_TERM
:
973 if (datalen
== 0 || data
[datalen
- 1] != '\0')
974 fatalx("bad MSG_IDENTIFY_TERM string");
975 c
->term
= xstrdup(data
);
977 case MSG_IDENTIFY_TTYNAME
:
978 if (datalen
== 0 || data
[datalen
- 1] != '\0')
979 fatalx("bad MSG_IDENTIFY_TTYNAME string");
980 c
->ttyname
= xstrdup(data
);
982 case MSG_IDENTIFY_CWD
:
984 fatalx("bad MSG_IDENTIFY_CWD size");
987 case MSG_IDENTIFY_STDIN
:
989 fatalx("bad MSG_IDENTIFY_STDIN size");
992 case MSG_IDENTIFY_ENVIRON
:
993 if (datalen
== 0 || data
[datalen
- 1] != '\0')
994 fatalx("bad MSG_IDENTIFY_ENVIRON string");
995 if (strchr(data
, '=') != NULL
)
996 environ_put(&c
->environ
, data
);
1002 if (imsg
->hdr
.type
!= MSG_IDENTIFY_DONE
)
1004 c
->flags
|= CLIENT_IDENTIFIED
;
1007 c
->fd
= open(c
->ttyname
, O_RDWR
|O_NOCTTY
);
1008 c
->cwd
= open(".", O_RDONLY
);
1011 if (c
->flags
& CLIENT_CONTROL
) {
1012 c
->stdin_callback
= control_callback
;
1014 evbuffer_free(c
->stderr_data
);
1015 c
->stderr_data
= c
->stdout_data
;
1017 if (c
->flags
& CLIENT_CONTROLCONTROL
)
1018 evbuffer_add_printf(c
->stdout_data
, "\033P1000p");
1019 server_write_client(c
, MSG_STDIN
, NULL
, 0);
1032 if (!isatty(c
->fd
)) {
1037 tty_init(&c
->tty
, c
, c
->fd
, c
->term
);
1038 if (c
->flags
& CLIENT_UTF8
)
1039 c
->tty
.flags
|= TTY_UTF8
;
1040 if (c
->flags
& CLIENT_256COLOURS
)
1041 c
->tty
.term_flags
|= TERM_256COLOURS
;
1043 tty_resize(&c
->tty
);
1045 if (!(c
->flags
& CLIENT_CONTROL
))
1046 c
->flags
|= CLIENT_TERMINAL
;
1049 /* Handle shell message. */
1051 server_client_msg_shell(struct client
*c
)
1055 shell
= options_get_string(&global_s_options
, "default-shell");
1056 if (*shell
== '\0' || areshell(shell
))
1057 shell
= _PATH_BSHELL
;
1058 server_write_client(c
, MSG_SHELL
, shell
, strlen(shell
) + 1);
1060 c
->flags
|= CLIENT_BAD
; /* it will die after exec */