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 environ_init(&c
->environ
);
67 c
->cmdq
= cmdq_new(c
);
68 c
->cmdq
->client_exit
= 1;
70 c
->stdin_data
= evbuffer_new();
71 c
->stdout_data
= evbuffer_new();
72 c
->stderr_data
= evbuffer_new();
78 c
->last_session
= NULL
;
82 screen_init(&c
->status
, c
->tty
.sx
, 1, 0);
83 RB_INIT(&c
->status_new
);
84 RB_INIT(&c
->status_old
);
86 c
->message_string
= NULL
;
87 ARRAY_INIT(&c
->message_log
);
89 c
->prompt_string
= NULL
;
90 c
->prompt_buffer
= NULL
;
93 c
->tty
.mouse
.xb
= c
->tty
.mouse
.button
= 3;
94 c
->tty
.mouse
.x
= c
->tty
.mouse
.y
= -1;
95 c
->tty
.mouse
.lx
= c
->tty
.mouse
.ly
= -1;
96 c
->tty
.mouse
.sx
= c
->tty
.mouse
.sy
= -1;
97 c
->tty
.mouse
.event
= MOUSE_EVENT_UP
;
98 c
->tty
.mouse
.flags
= 0;
100 c
->flags
|= CLIENT_FOCUSED
;
102 evtimer_set(&c
->repeat_timer
, server_client_repeat_timer
, c
);
104 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
105 if (ARRAY_ITEM(&clients
, i
) == NULL
) {
106 ARRAY_SET(&clients
, i
, c
);
110 ARRAY_ADD(&clients
, c
);
111 log_debug("new client %d", fd
);
114 /* Open client terminal if needed. */
116 server_client_open(struct client
*c
, struct session
*s
, char **cause
)
118 struct options
*oo
= s
!= NULL
? &s
->options
: &global_s_options
;
121 if (c
->flags
& CLIENT_CONTROL
)
124 if (!(c
->flags
& CLIENT_TERMINAL
)) {
125 *cause
= xstrdup("not a terminal");
129 overrides
= options_get_string(oo
, "terminal-overrides");
130 if (tty_open(&c
->tty
, overrides
, cause
) != 0)
138 server_client_lost(struct client
*c
)
140 struct message_entry
*msg
;
143 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
144 if (ARRAY_ITEM(&clients
, i
) == c
)
145 ARRAY_SET(&clients
, i
, NULL
);
147 log_debug("lost client %d", c
->ibuf
.fd
);
150 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
151 * and tty_free might close an unrelated fd.
153 if (c
->flags
& CLIENT_TERMINAL
)
158 evbuffer_free(c
->stdin_data
);
159 evbuffer_free(c
->stdout_data
);
160 if (c
->stderr_data
!= c
->stdout_data
)
161 evbuffer_free (c
->stderr_data
);
163 status_free_jobs(&c
->status_new
);
164 status_free_jobs(&c
->status_old
);
165 screen_free(&c
->status
);
170 evtimer_del(&c
->repeat_timer
);
172 if (event_initialized(&c
->identify_timer
))
173 evtimer_del(&c
->identify_timer
);
175 free(c
->message_string
);
176 if (event_initialized(&c
->message_timer
))
177 evtimer_del(&c
->message_timer
);
178 for (i
= 0; i
< ARRAY_LENGTH(&c
->message_log
); i
++) {
179 msg
= &ARRAY_ITEM(&c
->message_log
, i
);
182 ARRAY_FREE(&c
->message_log
);
184 free(c
->prompt_string
);
185 free(c
->prompt_buffer
);
191 environ_free(&c
->environ
);
194 imsg_clear(&c
->ibuf
);
195 if (event_initialized(&c
->event
))
196 event_del(&c
->event
);
198 for (i
= 0; i
< ARRAY_LENGTH(&dead_clients
); i
++) {
199 if (ARRAY_ITEM(&dead_clients
, i
) == NULL
) {
200 ARRAY_SET(&dead_clients
, i
, c
);
204 if (i
== ARRAY_LENGTH(&dead_clients
))
205 ARRAY_ADD(&dead_clients
, c
);
206 c
->flags
|= CLIENT_DEAD
;
208 server_add_accept(0); /* may be more file descriptors now */
211 server_check_unattached();
212 server_update_socket();
215 /* Process a single client event. */
217 server_client_callback(int fd
, short events
, void *data
)
219 struct client
*c
= data
;
221 if (c
->flags
& CLIENT_DEAD
)
224 if (fd
== c
->ibuf
.fd
) {
225 if (events
& EV_WRITE
&& msgbuf_write(&c
->ibuf
.w
) < 0 &&
229 if (c
->flags
& CLIENT_BAD
) {
230 if (c
->ibuf
.w
.queued
== 0)
235 if (events
& EV_READ
&& server_client_msg_dispatch(c
) != 0)
239 server_push_stdout(c
);
240 server_push_stderr(c
);
242 server_update_event(c
);
246 server_client_lost(c
);
249 /* Handle client status timer. */
251 server_client_status_timer(void)
260 if (gettimeofday(&tv
, NULL
) != 0)
261 fatal("gettimeofday failed");
263 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
264 c
= ARRAY_ITEM(&clients
, i
);
265 if (c
== NULL
|| c
->session
== NULL
)
267 if (c
->message_string
!= NULL
|| c
->prompt_string
!= NULL
) {
269 * Don't need timed redraw for messages/prompts so bail
270 * now. The status timer isn't reset when they are
277 if (!options_get_number(&s
->options
, "status"))
279 interval
= options_get_number(&s
->options
, "status-interval");
281 difference
= tv
.tv_sec
- c
->status_timer
.tv_sec
;
282 if (interval
!= 0 && difference
>= interval
) {
283 status_update_jobs(c
);
284 c
->flags
|= CLIENT_STATUS
;
289 /* Check for mouse keys. */
291 server_client_check_mouse(struct client
*c
, struct window_pane
*wp
)
293 struct session
*s
= c
->session
;
294 struct options
*oo
= &s
->options
;
295 struct mouse_event
*m
= &c
->tty
.mouse
;
298 statusat
= status_at_line(c
);
300 /* Is this a window selection click on the status line? */
301 if (statusat
!= -1 && m
->y
== (u_int
)statusat
&&
302 options_get_number(oo
, "mouse-select-window")) {
303 if (m
->event
& MOUSE_EVENT_CLICK
) {
304 status_set_window_at(c
, m
->x
);
305 } else if (m
->event
== MOUSE_EVENT_WHEEL
) {
306 if (m
->wheel
== MOUSE_WHEEL_UP
)
307 session_previous(c
->session
, 0);
308 else if (m
->wheel
== MOUSE_WHEEL_DOWN
)
309 session_next(c
->session
, 0);
310 server_redraw_session(s
);
317 * Not on status line - adjust mouse position if status line is at the
318 * top and limit if at the bottom. From here on a struct mouse
319 * represents the offset onto the window itself.
321 if (statusat
== 0 && m
->y
> 0)
323 else if (statusat
> 0 && m
->y
>= (u_int
)statusat
)
326 /* Is this a pane selection? */
327 if (options_get_number(oo
, "mouse-select-pane") &&
328 (m
->event
== MOUSE_EVENT_DOWN
|| m
->event
== MOUSE_EVENT_WHEEL
)) {
329 window_set_active_at(wp
->window
, m
->x
, m
->y
);
330 server_redraw_window_borders(wp
->window
);
331 wp
= wp
->window
->active
; /* may have changed */
334 /* Check if trying to resize pane. */
335 if (options_get_number(oo
, "mouse-resize-pane"))
336 layout_resize_pane_mouse(c
);
338 /* Update last and pass through to client. */
339 window_pane_mouse(wp
, c
->session
, m
);
342 /* Is this fast enough to probably be a paste? */
344 server_client_assume_paste(struct session
*s
)
349 if ((t
= options_get_number(&s
->options
, "assume-paste-time")) == 0)
352 timersub(&s
->activity_time
, &s
->last_activity_time
, &tv
);
353 if (tv
.tv_sec
== 0 && tv
.tv_usec
< t
* 1000)
358 /* Handle data key input from client. */
360 server_client_handle_key(struct client
*c
, int key
)
364 struct window_pane
*wp
;
366 struct key_binding
*bd
;
367 int xtimeout
, isprefix
, ispaste
;
369 /* Check the client is good to accept input. */
370 if ((c
->flags
& (CLIENT_DEAD
|CLIENT_SUSPENDED
)) != 0)
373 if (c
->session
== NULL
)
377 /* Update the activity timer. */
378 if (gettimeofday(&c
->activity_time
, NULL
) != 0)
379 fatal("gettimeofday failed");
381 memcpy(&s
->last_activity_time
, &s
->activity_time
,
382 sizeof s
->last_activity_time
);
383 memcpy(&s
->activity_time
, &c
->activity_time
, sizeof s
->activity_time
);
385 w
= c
->session
->curw
->window
;
388 /* Special case: number keys jump to pane in identify mode. */
389 if (c
->flags
& CLIENT_IDENTIFY
&& key
>= '0' && key
<= '9') {
390 if (c
->flags
& CLIENT_READONLY
)
393 wp
= window_pane_at_index(w
, key
- '0');
394 if (wp
!= NULL
&& window_pane_visible(wp
))
395 window_set_active_pane(w
, wp
);
396 server_clear_identify(c
);
400 /* Handle status line. */
401 if (!(c
->flags
& CLIENT_READONLY
)) {
402 status_message_clear(c
);
403 server_clear_identify(c
);
405 if (c
->prompt_string
!= NULL
) {
406 if (!(c
->flags
& CLIENT_READONLY
))
407 status_prompt_key(c
, key
);
411 /* Check for mouse keys. */
412 if (key
== KEYC_MOUSE
) {
413 if (c
->flags
& CLIENT_READONLY
)
415 server_client_check_mouse(c
, wp
);
419 /* Is this a prefix key? */
420 if (key
== options_get_number(&s
->options
, "prefix"))
422 else if (key
== options_get_number(&s
->options
, "prefix2"))
427 /* Treat prefix as a regular key when pasting is detected. */
428 ispaste
= server_client_assume_paste(s
);
432 /* No previous prefix key. */
433 if (!(c
->flags
& CLIENT_PREFIX
)) {
435 c
->flags
|= CLIENT_PREFIX
;
436 server_status_client(c
);
440 /* Try as a non-prefix key binding. */
441 if (ispaste
|| (bd
= key_bindings_lookup(key
)) == NULL
) {
442 if (!(c
->flags
& CLIENT_READONLY
))
443 window_pane_key(wp
, s
, key
);
445 key_bindings_dispatch(bd
, c
);
449 /* Prefix key already pressed. Reset prefix and lookup key. */
450 c
->flags
&= ~CLIENT_PREFIX
;
451 server_status_client(c
);
452 if ((bd
= key_bindings_lookup(key
| KEYC_PREFIX
)) == NULL
) {
453 /* If repeating, treat this as a key, else ignore. */
454 if (c
->flags
& CLIENT_REPEAT
) {
455 c
->flags
&= ~CLIENT_REPEAT
;
457 c
->flags
|= CLIENT_PREFIX
;
458 else if (!(c
->flags
& CLIENT_READONLY
))
459 window_pane_key(wp
, s
, key
);
464 /* If already repeating, but this key can't repeat, skip it. */
465 if (c
->flags
& CLIENT_REPEAT
&& !bd
->can_repeat
) {
466 c
->flags
&= ~CLIENT_REPEAT
;
468 c
->flags
|= CLIENT_PREFIX
;
469 else if (!(c
->flags
& CLIENT_READONLY
))
470 window_pane_key(wp
, s
, key
);
474 /* If this key can repeat, reset the repeat flags and timer. */
475 xtimeout
= options_get_number(&s
->options
, "repeat-time");
476 if (xtimeout
!= 0 && bd
->can_repeat
) {
477 c
->flags
|= CLIENT_PREFIX
|CLIENT_REPEAT
;
479 tv
.tv_sec
= xtimeout
/ 1000;
480 tv
.tv_usec
= (xtimeout
% 1000) * 1000L;
481 evtimer_del(&c
->repeat_timer
);
482 evtimer_add(&c
->repeat_timer
, &tv
);
485 /* Dispatch the command. */
486 key_bindings_dispatch(bd
, c
);
489 /* Client functions that need to happen every loop. */
491 server_client_loop(void)
495 struct window_pane
*wp
;
498 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
499 c
= ARRAY_ITEM(&clients
, i
);
503 server_client_check_exit(c
);
504 if (c
->session
!= NULL
) {
505 server_client_check_redraw(c
);
506 server_client_reset_state(c
);
511 * Any windows will have been redrawn as part of clients, so clear
512 * their flags now. Also check pane focus and resize.
514 for (i
= 0; i
< ARRAY_LENGTH(&windows
); i
++) {
515 w
= ARRAY_ITEM(&windows
, i
);
519 w
->flags
&= ~WINDOW_REDRAW
;
520 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
522 server_client_check_focus(wp
);
523 server_client_check_resize(wp
);
525 wp
->flags
&= ~PANE_REDRAW
;
530 /* Check if pane should be resized. */
532 server_client_check_resize(struct window_pane
*wp
)
536 if (!(wp
->flags
& PANE_RESIZE
))
539 memset(&ws
, 0, sizeof ws
);
543 if (ioctl(wp
->fd
, TIOCSWINSZ
, &ws
) == -1)
544 fatal("ioctl failed");
546 wp
->flags
&= ~PANE_RESIZE
;
549 /* Check whether pane should be focused. */
551 server_client_check_focus(struct window_pane
*wp
)
557 /* Are focus events off? */
558 if (!options_get_number(&global_options
, "focus-events"))
561 /* Do we need to push the focus state? */
562 push
= wp
->flags
& PANE_FOCUSPUSH
;
563 wp
->flags
&= ~PANE_FOCUSPUSH
;
565 /* If we don't care about focus, forget it. */
566 if (!(wp
->base
.mode
& MODE_FOCUSON
))
569 /* If we're not the active pane in our window, we're not focused. */
570 if (wp
->window
->active
!= wp
)
573 /* If we're in a mode, we're not focused. */
574 if (wp
->screen
!= &wp
->base
)
578 * If our window is the current window in any focused clients with an
579 * attached session, we're focused.
581 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
582 c
= ARRAY_ITEM(&clients
, i
);
583 if (c
== NULL
|| c
->session
== NULL
)
586 if (!(c
->flags
& CLIENT_FOCUSED
))
588 if (c
->session
->flags
& SESSION_UNATTACHED
)
591 if (c
->session
->curw
->window
== wp
->window
)
596 if (push
|| (wp
->flags
& PANE_FOCUSED
))
597 bufferevent_write(wp
->event
, "\033[O", 3);
598 wp
->flags
&= ~PANE_FOCUSED
;
602 if (push
|| !(wp
->flags
& PANE_FOCUSED
))
603 bufferevent_write(wp
->event
, "\033[I", 3);
604 wp
->flags
|= PANE_FOCUSED
;
608 * Update cursor position and mode settings. The scroll region and attributes
609 * are cleared when idle (waiting for an event) as this is the most likely time
610 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
611 * compromise between excessive resets and likelihood of an interrupt.
613 * tty_region/tty_reset/tty_update_mode already take care of not resetting
614 * things that are already in their default state.
617 server_client_reset_state(struct client
*c
)
619 struct window
*w
= c
->session
->curw
->window
;
620 struct window_pane
*wp
= w
->active
;
621 struct screen
*s
= wp
->screen
;
622 struct options
*oo
= &c
->session
->options
;
623 struct options
*wo
= &w
->options
;
626 if (c
->flags
& CLIENT_SUSPENDED
)
629 if (c
->flags
& CLIENT_CONTROL
)
632 tty_region(&c
->tty
, 0, c
->tty
.sy
- 1);
634 status
= options_get_number(oo
, "status");
635 if (!window_pane_visible(wp
) || wp
->yoff
+ s
->cy
>= c
->tty
.sy
- status
)
636 tty_cursor(&c
->tty
, 0, 0);
638 o
= status
&& options_get_number (oo
, "status-position") == 0;
639 tty_cursor(&c
->tty
, wp
->xoff
+ s
->cx
, o
+ wp
->yoff
+ s
->cy
);
643 * Resizing panes with the mouse requires at least button mode to give
644 * a smooth appearance.
647 if ((c
->tty
.mouse
.flags
& MOUSE_RESIZE_PANE
) &&
648 !(mode
& (MODE_MOUSE_BUTTON
|MODE_MOUSE_ANY
)))
649 mode
|= MODE_MOUSE_BUTTON
;
652 * Any mode will do for mouse-select-pane, but set standard mode if
655 if ((mode
& ALL_MOUSE_MODES
) == 0) {
656 if (TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
) != NULL
&&
657 options_get_number(oo
, "mouse-select-pane"))
658 mode
|= MODE_MOUSE_STANDARD
;
659 else if (options_get_number(oo
, "mouse-resize-pane"))
660 mode
|= MODE_MOUSE_STANDARD
;
661 else if (options_get_number(oo
, "mouse-select-window"))
662 mode
|= MODE_MOUSE_STANDARD
;
663 else if (options_get_number(wo
, "mode-mouse"))
664 mode
|= MODE_MOUSE_STANDARD
;
668 * Set UTF-8 mouse input if required. If the terminal is UTF-8, the
669 * user has set mouse-utf8 and any mouse mode is in effect, turn on
670 * UTF-8 mouse input. If the receiving terminal hasn't requested it
671 * (that is, it isn't in s->mode), then it'll be converted in
674 if ((c
->tty
.flags
& TTY_UTF8
) &&
675 (mode
& ALL_MOUSE_MODES
) && options_get_number(oo
, "mouse-utf8"))
676 mode
|= MODE_MOUSE_UTF8
;
678 mode
&= ~MODE_MOUSE_UTF8
;
680 /* Set the terminal mode and reset attributes. */
681 tty_update_mode(&c
->tty
, mode
, s
);
685 /* Repeat time callback. */
687 server_client_repeat_timer(unused
int fd
, unused
short events
, void *data
)
689 struct client
*c
= data
;
691 if (c
->flags
& CLIENT_REPEAT
) {
692 if (c
->flags
& CLIENT_PREFIX
)
693 server_status_client(c
);
694 c
->flags
&= ~(CLIENT_PREFIX
|CLIENT_REPEAT
);
698 /* Check if client should be exited. */
700 server_client_check_exit(struct client
*c
)
702 if (!(c
->flags
& CLIENT_EXIT
))
705 if (EVBUFFER_LENGTH(c
->stdin_data
) != 0)
707 if (EVBUFFER_LENGTH(c
->stdout_data
) != 0)
709 if (EVBUFFER_LENGTH(c
->stderr_data
) != 0)
712 server_write_client(c
, MSG_EXIT
, &c
->retval
, sizeof c
->retval
);
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
, 1, 1, 1);
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, 0, 1);
761 if (c
->flags
& CLIENT_STATUS
)
762 screen_redraw_screen(c
, 0, 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_stdin_data stdindata
;
797 if ((n
= imsg_read(&c
->ibuf
)) == -1 || n
== 0)
801 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
;
818 log_debug("got %d from client %d", imsg
.hdr
.type
, c
->ibuf
.fd
);
819 switch (imsg
.hdr
.type
) {
820 case MSG_IDENTIFY_FLAGS
:
821 case MSG_IDENTIFY_TERM
:
822 case MSG_IDENTIFY_TTYNAME
:
823 case MSG_IDENTIFY_CWD
:
824 case MSG_IDENTIFY_STDIN
:
825 case MSG_IDENTIFY_ENVIRON
:
826 case MSG_IDENTIFY_DONE
:
827 server_client_msg_identify(c
, &imsg
);
830 server_client_msg_command(c
, &imsg
);
833 if (datalen
!= sizeof stdindata
)
834 fatalx("bad MSG_STDIN size");
835 memcpy(&stdindata
, 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
);
887 fatalx("bad MSG_SHELL size");
889 server_client_msg_shell(c
);
897 /* Handle command message. */
899 server_client_msg_command(struct client
*c
, struct imsg
*imsg
)
901 struct msg_command_data data
;
904 struct cmd_list
*cmdlist
= NULL
;
908 if (imsg
->hdr
.len
- IMSG_HEADER_SIZE
< sizeof data
)
909 fatalx("bad MSG_COMMAND size");
910 memcpy(&data
, imsg
->data
, sizeof data
);
912 buf
= (char*)imsg
->data
+ sizeof data
;
913 len
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
- sizeof data
;
914 if (len
> 0 && buf
[len
- 1] != '\0')
915 fatalx("bad MSG_COMMAND string");
918 if (cmd_unpack_argv(buf
, len
, 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 if (c
!= cfg_client
|| cfg_finished
)
937 cmdq_run(c
->cmdq
, cmdlist
);
939 cmdq_append(c
->cmdq
, cmdlist
);
940 cmd_list_free(cmdlist
);
945 cmd_list_free(cmdlist
);
947 c
->flags
|= CLIENT_EXIT
;
950 /* Handle identify message. */
952 server_client_msg_identify(struct client
*c
, struct imsg
*imsg
)
958 if (c
->flags
& CLIENT_IDENTIFIED
)
959 fatalx("out-of-order identify message");
962 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
964 switch (imsg
->hdr
.type
) {
965 case MSG_IDENTIFY_FLAGS
:
966 if (datalen
!= sizeof flags
)
967 fatalx("bad MSG_IDENTIFY_FLAGS size");
968 memcpy(&flags
, data
, sizeof flags
);
971 case MSG_IDENTIFY_TERM
:
972 if (datalen
== 0 || data
[datalen
- 1] != '\0')
973 fatalx("bad MSG_IDENTIFY_TERM string");
974 c
->term
= xstrdup(data
);
976 case MSG_IDENTIFY_TTYNAME
:
977 if (datalen
== 0 || data
[datalen
- 1] != '\0')
978 fatalx("bad MSG_IDENTIFY_TTYNAME string");
979 c
->ttyname
= xstrdup(data
);
981 case MSG_IDENTIFY_CWD
:
983 fatalx("bad MSG_IDENTIFY_CWD size");
986 case MSG_IDENTIFY_STDIN
:
988 fatalx("bad MSG_IDENTIFY_STDIN size");
991 case MSG_IDENTIFY_ENVIRON
:
992 if (datalen
== 0 || data
[datalen
- 1] != '\0')
993 fatalx("bad MSG_IDENTIFY_ENVIRON string");
994 if (strchr(data
, '=') != NULL
)
995 environ_put(&c
->environ
, data
);
1001 if (imsg
->hdr
.type
!= MSG_IDENTIFY_DONE
)
1003 c
->flags
|= CLIENT_IDENTIFIED
;
1006 c
->fd
= open(c
->ttyname
, O_RDWR
|O_NOCTTY
);
1007 c
->cwd
= open(".", O_RDONLY
);
1010 if (c
->flags
& CLIENT_CONTROL
) {
1011 c
->stdin_callback
= control_callback
;
1013 evbuffer_free(c
->stderr_data
);
1014 c
->stderr_data
= c
->stdout_data
;
1016 if (c
->flags
& CLIENT_CONTROLCONTROL
)
1017 evbuffer_add_printf(c
->stdout_data
, "\033P1000p");
1018 server_write_client(c
, MSG_STDIN
, NULL
, 0);
1031 if (!isatty(c
->fd
)) {
1036 tty_init(&c
->tty
, c
, c
->fd
, c
->term
);
1037 if (c
->flags
& CLIENT_UTF8
)
1038 c
->tty
.flags
|= TTY_UTF8
;
1039 if (c
->flags
& CLIENT_256COLOURS
)
1040 c
->tty
.term_flags
|= TERM_256COLOURS
;
1042 tty_resize(&c
->tty
);
1044 if (!(c
->flags
& CLIENT_CONTROL
))
1045 c
->flags
|= CLIENT_TERMINAL
;
1048 /* Handle shell message. */
1050 server_client_msg_shell(struct client
*c
)
1054 shell
= options_get_string(&global_s_options
, "default-shell");
1055 if (*shell
== '\0' || areshell(shell
))
1056 shell
= _PATH_BSHELL
;
1057 server_write_client(c
, MSG_SHELL
, shell
, strlen(shell
) + 1);
1059 c
->flags
|= CLIENT_BAD
; /* it will die after exec */