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>
30 void server_client_handle_key(int, struct mouse_event
*, void *);
31 void server_client_repeat_timer(int, short, void *);
32 void server_client_check_exit(struct client
*);
33 void server_client_check_backoff(struct client
*);
34 void server_client_check_redraw(struct client
*);
35 void server_client_set_title(struct client
*);
36 void server_client_reset_state(struct client
*);
37 void server_client_in_callback(struct bufferevent
*, short, void *);
38 void server_client_out_callback(struct bufferevent
*, short, void *);
39 void server_client_err_callback(struct bufferevent
*, short, void *);
41 int server_client_msg_dispatch(struct client
*);
42 void server_client_msg_command(struct client
*, struct msg_command_data
*);
43 void server_client_msg_identify(
44 struct client
*, struct msg_identify_data
*, int);
45 void server_client_msg_shell(struct client
*);
47 void printflike2
server_client_msg_error(struct cmd_ctx
*, const char *, ...);
48 void printflike2
server_client_msg_print(struct cmd_ctx
*, const char *, ...);
49 void printflike2
server_client_msg_info(struct cmd_ctx
*, const char *, ...);
51 /* Create a new client. */
53 server_client_create(int fd
)
60 c
= xcalloc(1, sizeof *c
);
62 imsg_init(&c
->ibuf
, fd
);
63 server_update_event(c
);
65 if (gettimeofday(&c
->creation_time
, NULL
) != 0)
66 fatal("gettimeofday failed");
67 memcpy(&c
->activity_time
, &c
->creation_time
, sizeof c
->activity_time
);
69 c
->stdin_event
= NULL
;
70 c
->stdout_event
= NULL
;
71 c
->stderr_event
= NULL
;
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
->last_mouse
.b
= MOUSE_UP
;
93 c
->last_mouse
.x
= c
->last_mouse
.y
= -1;
95 evtimer_set(&c
->repeat_timer
, server_client_repeat_timer
, c
);
97 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
98 if (ARRAY_ITEM(&clients
, i
) == NULL
) {
99 ARRAY_SET(&clients
, i
, c
);
103 ARRAY_ADD(&clients
, c
);
104 log_debug("new client %d", fd
);
109 server_client_lost(struct client
*c
)
111 struct message_entry
*msg
;
114 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
115 if (ARRAY_ITEM(&clients
, i
) == c
)
116 ARRAY_SET(&clients
, i
, NULL
);
118 log_debug("lost client %d", c
->ibuf
.fd
);
121 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
122 * and tty_free might close an unrelated fd.
124 if (c
->flags
& CLIENT_TERMINAL
)
127 if (c
->stdin_fd
!= -1) {
128 setblocking(c
->stdin_fd
, 1);
131 if (c
->stdin_event
!= NULL
)
132 bufferevent_free(c
->stdin_event
);
133 if (c
->stdout_fd
!= -1) {
134 setblocking(c
->stdout_fd
, 1);
137 if (c
->stdout_event
!= NULL
)
138 bufferevent_free(c
->stdout_event
);
139 if (c
->stderr_fd
!= -1) {
140 setblocking(c
->stderr_fd
, 1);
143 if (c
->stderr_event
!= NULL
)
144 bufferevent_free(c
->stderr_event
);
146 status_free_jobs(&c
->status_new
);
147 status_free_jobs(&c
->status_old
);
148 screen_free(&c
->status
);
150 if (c
->title
!= NULL
)
153 evtimer_del(&c
->repeat_timer
);
155 evtimer_del(&c
->identify_timer
);
157 if (c
->message_string
!= NULL
)
158 xfree(c
->message_string
);
159 evtimer_del(&c
->message_timer
);
160 for (i
= 0; i
< ARRAY_LENGTH(&c
->message_log
); i
++) {
161 msg
= &ARRAY_ITEM(&c
->message_log
, i
);
164 ARRAY_FREE(&c
->message_log
);
166 if (c
->prompt_string
!= NULL
)
167 xfree(c
->prompt_string
);
168 if (c
->prompt_buffer
!= NULL
)
169 xfree(c
->prompt_buffer
);
174 environ_free(&c
->environ
);
177 imsg_clear(&c
->ibuf
);
178 event_del(&c
->event
);
180 for (i
= 0; i
< ARRAY_LENGTH(&dead_clients
); i
++) {
181 if (ARRAY_ITEM(&dead_clients
, i
) == NULL
) {
182 ARRAY_SET(&dead_clients
, i
, c
);
186 if (i
== ARRAY_LENGTH(&dead_clients
))
187 ARRAY_ADD(&dead_clients
, c
);
188 c
->flags
|= CLIENT_DEAD
;
191 server_check_unattached();
192 server_update_socket();
195 /* Process a single client event. */
197 server_client_callback(int fd
, short events
, void *data
)
199 struct client
*c
= data
;
201 if (c
->flags
& CLIENT_DEAD
)
204 if (fd
== c
->ibuf
.fd
) {
205 if (events
& EV_WRITE
&& msgbuf_write(&c
->ibuf
.w
) < 0)
208 if (c
->flags
& CLIENT_BAD
) {
209 if (c
->ibuf
.w
.queued
== 0)
214 if (events
& EV_READ
&& server_client_msg_dispatch(c
) != 0)
218 server_update_event(c
);
222 server_client_lost(c
);
225 /* Handle client status timer. */
227 server_client_status_timer(void)
236 if (gettimeofday(&tv
, NULL
) != 0)
237 fatal("gettimeofday failed");
239 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
240 c
= ARRAY_ITEM(&clients
, i
);
241 if (c
== NULL
|| c
->session
== NULL
)
243 if (c
->message_string
!= NULL
|| c
->prompt_string
!= NULL
) {
245 * Don't need timed redraw for messages/prompts so bail
246 * now. The status timer isn't reset when they are
253 if (!options_get_number(&s
->options
, "status"))
255 interval
= options_get_number(&s
->options
, "status-interval");
257 difference
= tv
.tv_sec
- c
->status_timer
.tv_sec
;
258 if (difference
>= interval
) {
259 status_update_jobs(c
);
260 c
->flags
|= CLIENT_STATUS
;
265 /* Handle data key input from client. */
267 server_client_handle_key(int key
, struct mouse_event
*mouse
, void *data
)
269 struct client
*c
= data
;
272 struct window_pane
*wp
;
275 struct key_binding
*bd
;
276 struct keylist
*keylist
;
277 int xtimeout
, isprefix
;
280 /* Check the client is good to accept input. */
281 if ((c
->flags
& (CLIENT_DEAD
|CLIENT_SUSPENDED
)) != 0)
283 if (c
->session
== NULL
)
287 /* Update the activity timer. */
288 if (gettimeofday(&c
->activity_time
, NULL
) != 0)
289 fatal("gettimeofday failed");
290 memcpy(&s
->activity_time
, &c
->activity_time
, sizeof s
->activity_time
);
292 w
= c
->session
->curw
->window
;
294 oo
= &c
->session
->options
;
296 /* Special case: number keys jump to pane in identify mode. */
297 if (c
->flags
& CLIENT_IDENTIFY
&& key
>= '0' && key
<= '9') {
298 if (c
->flags
& CLIENT_READONLY
)
300 wp
= window_pane_at_index(w
, key
- '0');
301 if (wp
!= NULL
&& window_pane_visible(wp
))
302 window_set_active_pane(w
, wp
);
303 server_clear_identify(c
);
307 /* Handle status line. */
308 if (!(c
->flags
& CLIENT_READONLY
)) {
309 status_message_clear(c
);
310 server_clear_identify(c
);
312 if (c
->prompt_string
!= NULL
) {
313 if (!(c
->flags
& CLIENT_READONLY
))
314 status_prompt_key(c
, key
);
318 /* Check for mouse keys. */
319 if (key
== KEYC_MOUSE
) {
320 if (c
->flags
& CLIENT_READONLY
)
322 if (options_get_number(oo
, "mouse-select-pane") &&
323 (!(options_get_number(oo
, "status") &&
324 mouse
->y
+ 1 == c
->tty
.sy
)) &&
325 ((!(mouse
->b
& MOUSE_DRAG
) && mouse
->b
!= MOUSE_UP
) ||
326 wp
->mode
!= &window_copy_mode
)) {
328 * Allow pane switching in copy mode only by mouse down
331 window_set_active_at(w
, mouse
->x
, mouse
->y
);
332 server_redraw_window_borders(w
);
335 if (mouse
->y
+ 1 == c
->tty
.sy
&&
336 options_get_number(oo
, "mouse-select-window") &&
337 options_get_number(oo
, "status")) {
338 if (mouse
->b
== MOUSE_UP
&&
339 c
->last_mouse
.b
!= MOUSE_UP
) {
340 status_set_window_at(c
, mouse
->x
);
343 if (mouse
->b
& MOUSE_45
) {
344 if ((mouse
->b
& MOUSE_BUTTON
) == MOUSE_1
) {
345 session_previous(c
->session
, 0);
346 server_redraw_session(s
);
348 if ((mouse
->b
& MOUSE_BUTTON
) == MOUSE_2
) {
349 session_next(c
->session
, 0);
350 server_redraw_session(s
);
355 if (options_get_number(oo
, "mouse-resize-pane"))
356 layout_resize_pane_mouse(c
, mouse
);
357 memcpy(&c
->last_mouse
, mouse
, sizeof c
->last_mouse
);
358 window_pane_mouse(wp
, c
->session
, mouse
);
362 /* Is this a prefix key? */
363 keylist
= options_get_data(&c
->session
->options
, "prefix");
365 for (i
= 0; i
< ARRAY_LENGTH(keylist
); i
++) {
366 if (key
== ARRAY_ITEM(keylist
, i
)) {
372 /* No previous prefix key. */
373 if (!(c
->flags
& CLIENT_PREFIX
)) {
375 c
->flags
|= CLIENT_PREFIX
;
377 /* Try as a non-prefix key binding. */
378 if ((bd
= key_bindings_lookup(key
)) == NULL
) {
379 if (!(c
->flags
& CLIENT_READONLY
))
380 window_pane_key(wp
, c
->session
, key
);
382 key_bindings_dispatch(bd
, c
);
387 /* Prefix key already pressed. Reset prefix and lookup key. */
388 c
->flags
&= ~CLIENT_PREFIX
;
389 if ((bd
= key_bindings_lookup(key
| KEYC_PREFIX
)) == NULL
) {
390 /* If repeating, treat this as a key, else ignore. */
391 if (c
->flags
& CLIENT_REPEAT
) {
392 c
->flags
&= ~CLIENT_REPEAT
;
394 c
->flags
|= CLIENT_PREFIX
;
395 else if (!(c
->flags
& CLIENT_READONLY
))
396 window_pane_key(wp
, c
->session
, key
);
401 /* If already repeating, but this key can't repeat, skip it. */
402 if (c
->flags
& CLIENT_REPEAT
&& !bd
->can_repeat
) {
403 c
->flags
&= ~CLIENT_REPEAT
;
405 c
->flags
|= CLIENT_PREFIX
;
406 else if (!(c
->flags
& CLIENT_READONLY
))
407 window_pane_key(wp
, c
->session
, key
);
411 /* If this key can repeat, reset the repeat flags and timer. */
412 xtimeout
= options_get_number(&c
->session
->options
, "repeat-time");
413 if (xtimeout
!= 0 && bd
->can_repeat
) {
414 c
->flags
|= CLIENT_PREFIX
|CLIENT_REPEAT
;
416 tv
.tv_sec
= xtimeout
/ 1000;
417 tv
.tv_usec
= (xtimeout
% 1000) * 1000L;
418 evtimer_del(&c
->repeat_timer
);
419 evtimer_add(&c
->repeat_timer
, &tv
);
422 /* Dispatch the command. */
423 key_bindings_dispatch(bd
, c
);
426 /* Client functions that need to happen every loop. */
428 server_client_loop(void)
432 struct window_pane
*wp
;
435 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
436 c
= ARRAY_ITEM(&clients
, i
);
440 server_client_check_exit(c
);
441 if (c
->session
!= NULL
) {
442 server_client_check_redraw(c
);
443 server_client_reset_state(c
);
448 * Any windows will have been redrawn as part of clients, so clear
451 for (i
= 0; i
< ARRAY_LENGTH(&windows
); i
++) {
452 w
= ARRAY_ITEM(&windows
, i
);
456 w
->flags
&= ~WINDOW_REDRAW
;
457 TAILQ_FOREACH(wp
, &w
->panes
, entry
)
458 wp
->flags
&= ~PANE_REDRAW
;
463 * Update cursor position and mode settings. The scroll region and attributes
464 * are cleared when idle (waiting for an event) as this is the most likely time
465 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
466 * compromise between excessive resets and likelihood of an interrupt.
468 * tty_region/tty_reset/tty_update_mode already take care of not resetting
469 * things that are already in their default state.
472 server_client_reset_state(struct client
*c
)
474 struct window
*w
= c
->session
->curw
->window
;
475 struct window_pane
*wp
= w
->active
;
476 struct screen
*s
= wp
->screen
;
477 struct options
*oo
= &c
->session
->options
;
478 struct options
*wo
= &w
->options
;
481 if (c
->flags
& CLIENT_SUSPENDED
)
484 tty_region(&c
->tty
, 0, c
->tty
.sy
- 1);
486 status
= options_get_number(oo
, "status");
487 if (!window_pane_visible(wp
) || wp
->yoff
+ s
->cy
>= c
->tty
.sy
- status
)
488 tty_cursor(&c
->tty
, 0, 0);
490 tty_cursor(&c
->tty
, wp
->xoff
+ s
->cx
, wp
->yoff
+ s
->cy
);
493 * Resizing panes with the mouse requires at least button mode to give
494 * a smooth appearance.
497 if ((c
->last_mouse
.b
& MOUSE_RESIZE_PANE
) &&
498 !(mode
& (MODE_MOUSE_BUTTON
|MODE_MOUSE_ANY
)))
499 mode
|= MODE_MOUSE_BUTTON
;
502 * Any mode will do for mouse-select-pane, but set standard mode if
505 if ((mode
& ALL_MOUSE_MODES
) == 0) {
506 if (TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
) != NULL
&&
507 options_get_number(oo
, "mouse-select-pane"))
508 mode
|= MODE_MOUSE_STANDARD
;
509 else if (options_get_number(oo
, "mouse-resize-pane"))
510 mode
|= MODE_MOUSE_STANDARD
;
511 else if (options_get_number(oo
, "mouse-select-window"))
512 mode
|= MODE_MOUSE_STANDARD
;
513 else if (options_get_number(wo
, "mode-mouse"))
514 mode
|= MODE_MOUSE_STANDARD
;
518 * Set UTF-8 mouse input if required. If the terminal is UTF-8, the
519 * user has set mouse-utf8 and any mouse mode is in effect, turn on
520 * UTF-8 mouse input. If the receiving terminal hasn't requested it
521 * (that is, it isn't in s->mode), then it'll be converted in
524 if ((c
->tty
.flags
& TTY_UTF8
) &&
525 (mode
& ALL_MOUSE_MODES
) && options_get_number(oo
, "mouse-utf8"))
526 mode
|= MODE_MOUSE_UTF8
;
528 mode
&= ~MODE_MOUSE_UTF8
;
530 /* Set the terminal mode and reset attributes. */
531 tty_update_mode(&c
->tty
, mode
, s
);
535 /* Repeat time callback. */
538 server_client_repeat_timer(unused
int fd
, unused
short events
, void *data
)
540 struct client
*c
= data
;
542 if (c
->flags
& CLIENT_REPEAT
)
543 c
->flags
&= ~(CLIENT_PREFIX
|CLIENT_REPEAT
);
546 /* Check if client should be exited. */
548 server_client_check_exit(struct client
*c
)
550 struct msg_exit_data exitdata
;
552 if (!(c
->flags
& CLIENT_EXIT
))
555 if (c
->stdout_fd
!= -1 && c
->stdout_event
!= NULL
&&
556 EVBUFFER_LENGTH(c
->stdout_event
->output
) != 0)
558 if (c
->stderr_fd
!= -1 && c
->stderr_event
!= NULL
&&
559 EVBUFFER_LENGTH(c
->stderr_event
->output
) != 0)
562 exitdata
.retcode
= c
->retcode
;
563 server_write_client(c
, MSG_EXIT
, &exitdata
, sizeof exitdata
);
565 c
->flags
&= ~CLIENT_EXIT
;
569 * Check if the client should backoff. During backoff, data from external
570 * programs is not written to the terminal. When the existing data drains, the
573 * There are two backoff phases - both the tty and client have backoff flags -
574 * the first to allow existing data to drain and the latter to ensure backoff
575 * is disabled until the redraw has finished and prevent the redraw triggering
579 server_client_check_backoff(struct client
*c
)
581 struct tty
*tty
= &c
->tty
;
584 used
= EVBUFFER_LENGTH(tty
->event
->output
);
587 * If in the second backoff phase (redrawing), don't check backoff
588 * until the redraw has completed (or enough of it to drop below the
589 * backoff threshold).
591 if (c
->flags
& CLIENT_BACKOFF
) {
592 if (used
> BACKOFF_THRESHOLD
)
594 c
->flags
&= ~CLIENT_BACKOFF
;
598 /* Once drained, allow data through again and schedule redraw. */
599 if (tty
->flags
& TTY_BACKOFF
) {
602 tty
->flags
&= ~TTY_BACKOFF
;
603 c
->flags
|= (CLIENT_BACKOFF
|CLIENT_REDRAWWINDOW
|CLIENT_STATUS
);
607 /* If too much data, start backoff. */
608 if (used
> BACKOFF_THRESHOLD
)
609 tty
->flags
|= TTY_BACKOFF
;
612 /* Check for client redraws. */
614 server_client_check_redraw(struct client
*c
)
616 struct session
*s
= c
->session
;
617 struct window_pane
*wp
;
620 flags
= c
->tty
.flags
& TTY_FREEZE
;
621 c
->tty
.flags
&= ~TTY_FREEZE
;
623 if (c
->flags
& (CLIENT_REDRAW
|CLIENT_STATUS
)) {
624 if (options_get_number(&s
->options
, "set-titles"))
625 server_client_set_title(c
);
627 if (c
->message_string
!= NULL
)
628 redraw
= status_message_redraw(c
);
629 else if (c
->prompt_string
!= NULL
)
630 redraw
= status_prompt_redraw(c
);
632 redraw
= status_redraw(c
);
634 c
->flags
&= ~CLIENT_STATUS
;
637 if (c
->flags
& CLIENT_REDRAW
) {
638 screen_redraw_screen(c
, 0, 0);
639 c
->flags
&= ~(CLIENT_STATUS
|CLIENT_BORDERS
);
640 } else if (c
->flags
& CLIENT_REDRAWWINDOW
) {
641 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
)
642 screen_redraw_pane(c
, wp
);
643 c
->flags
&= ~CLIENT_REDRAWWINDOW
;
645 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
) {
646 if (wp
->flags
& PANE_REDRAW
)
647 screen_redraw_pane(c
, wp
);
651 if (c
->flags
& CLIENT_BORDERS
)
652 screen_redraw_screen(c
, 0, 1);
654 if (c
->flags
& CLIENT_STATUS
)
655 screen_redraw_screen(c
, 1, 0);
657 c
->tty
.flags
|= flags
;
659 c
->flags
&= ~(CLIENT_REDRAW
|CLIENT_STATUS
|CLIENT_BORDERS
);
662 /* Set client title. */
664 server_client_set_title(struct client
*c
)
666 struct session
*s
= c
->session
;
667 const char *template;
670 template = options_get_string(&s
->options
, "set-titles-string");
672 title
= status_replace(c
, NULL
, NULL
, NULL
, template, time(NULL
), 1);
673 if (c
->title
== NULL
|| strcmp(title
, c
->title
) != 0) {
674 if (c
->title
!= NULL
)
676 c
->title
= xstrdup(title
);
677 tty_set_title(&c
->tty
, c
->title
);
683 * Error callback for client stdin. Caller must increase reference count when
687 server_client_in_callback(
688 unused
struct bufferevent
*bufev
, unused
short what
, void *data
)
690 struct client
*c
= data
;
693 if (c
->flags
& CLIENT_DEAD
)
696 bufferevent_disable(c
->stdin_event
, EV_READ
|EV_WRITE
);
697 setblocking(c
->stdin_fd
, 1);
701 if (c
->stdin_callback
!= NULL
)
702 c
->stdin_callback(c
, c
->stdin_data
);
705 /* Error callback for client stdout. */
707 server_client_out_callback(
708 unused
struct bufferevent
*bufev
, unused
short what
, unused
void *data
)
710 struct client
*c
= data
;
712 bufferevent_disable(c
->stdout_event
, EV_READ
|EV_WRITE
);
713 setblocking(c
->stdout_fd
, 1);
718 /* Error callback for client stderr. */
720 server_client_err_callback(
721 unused
struct bufferevent
*bufev
, unused
short what
, unused
void *data
)
723 struct client
*c
= data
;
725 bufferevent_disable(c
->stderr_event
, EV_READ
|EV_WRITE
);
726 setblocking(c
->stderr_fd
, 1);
731 /* Dispatch message from client. */
733 server_client_msg_dispatch(struct client
*c
)
736 struct msg_command_data commanddata
;
737 struct msg_identify_data identifydata
;
738 struct msg_environ_data environdata
;
741 if ((n
= imsg_read(&c
->ibuf
)) == -1 || n
== 0)
745 if ((n
= imsg_get(&c
->ibuf
, &imsg
)) == -1)
749 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
751 if (imsg
.hdr
.peerid
!= PROTOCOL_VERSION
) {
752 server_write_client(c
, MSG_VERSION
, NULL
, 0);
753 c
->flags
|= CLIENT_BAD
;
758 log_debug("got %d from client %d", imsg
.hdr
.type
, c
->ibuf
.fd
);
759 switch (imsg
.hdr
.type
) {
761 if (datalen
!= sizeof commanddata
)
762 fatalx("bad MSG_COMMAND size");
763 memcpy(&commanddata
, imsg
.data
, sizeof commanddata
);
765 server_client_msg_command(c
, &commanddata
);
768 if (datalen
!= sizeof identifydata
)
769 fatalx("bad MSG_IDENTIFY size");
771 fatalx("MSG_IDENTIFY missing fd");
772 memcpy(&identifydata
, imsg
.data
, sizeof identifydata
);
774 c
->stdin_fd
= imsg
.fd
;
775 c
->stdin_event
= bufferevent_new(c
->stdin_fd
,
776 NULL
, NULL
, server_client_in_callback
, c
);
777 if (c
->stdin_event
== NULL
)
778 fatalx("failed to create stdin event");
779 setblocking(c
->stdin_fd
, 0);
781 server_client_msg_identify(c
, &identifydata
, imsg
.fd
);
785 fatalx("bad MSG_STDOUT size");
787 fatalx("MSG_STDOUT missing fd");
789 c
->stdout_fd
= imsg
.fd
;
790 c
->stdout_event
= bufferevent_new(c
->stdout_fd
,
791 NULL
, NULL
, server_client_out_callback
, c
);
792 if (c
->stdout_event
== NULL
)
793 fatalx("failed to create stdout event");
794 setblocking(c
->stdout_fd
, 0);
799 fatalx("bad MSG_STDERR size");
801 fatalx("MSG_STDERR missing fd");
803 c
->stderr_fd
= imsg
.fd
;
804 c
->stderr_event
= bufferevent_new(c
->stderr_fd
,
805 NULL
, NULL
, server_client_err_callback
, c
);
806 if (c
->stderr_event
== NULL
)
807 fatalx("failed to create stderr event");
808 setblocking(c
->stderr_fd
, 0);
813 fatalx("bad MSG_RESIZE size");
815 if (tty_resize(&c
->tty
)) {
817 server_redraw_client(c
);
822 fatalx("bad MSG_EXITING size");
826 server_write_client(c
, MSG_EXITED
, NULL
, 0);
831 fatalx("bad MSG_WAKEUP size");
833 if (!(c
->flags
& CLIENT_SUSPENDED
))
835 c
->flags
&= ~CLIENT_SUSPENDED
;
837 if (gettimeofday(&c
->activity_time
, NULL
) != 0)
838 fatal("gettimeofday");
839 if (c
->session
!= NULL
)
840 session_update_activity(c
->session
);
842 tty_start_tty(&c
->tty
);
843 server_redraw_client(c
);
847 if (datalen
!= sizeof environdata
)
848 fatalx("bad MSG_ENVIRON size");
849 memcpy(&environdata
, imsg
.data
, sizeof environdata
);
851 environdata
.var
[(sizeof environdata
.var
) - 1] = '\0';
852 if (strchr(environdata
.var
, '=') != NULL
)
853 environ_put(&c
->environ
, environdata
.var
);
857 fatalx("bad MSG_SHELL size");
859 server_client_msg_shell(c
);
862 fatalx("unexpected message");
869 /* Callback to send error message to client. */
871 server_client_msg_error(struct cmd_ctx
*ctx
, const char *fmt
, ...)
876 evbuffer_add_vprintf(ctx
->cmdclient
->stderr_event
->output
, fmt
, ap
);
879 bufferevent_write(ctx
->cmdclient
->stderr_event
, "\n", 1);
880 ctx
->cmdclient
->retcode
= 1;
883 /* Callback to send print message to client. */
885 server_client_msg_print(struct cmd_ctx
*ctx
, const char *fmt
, ...)
890 evbuffer_add_vprintf(ctx
->cmdclient
->stdout_event
->output
, fmt
, ap
);
893 bufferevent_write(ctx
->cmdclient
->stdout_event
, "\n", 1);
896 /* Callback to send print message to client, if not quiet. */
898 server_client_msg_info(struct cmd_ctx
*ctx
, const char *fmt
, ...)
902 if (options_get_number(&global_options
, "quiet"))
906 evbuffer_add_vprintf(ctx
->cmdclient
->stdout_event
->output
, fmt
, ap
);
909 bufferevent_write(ctx
->cmdclient
->stdout_event
, "\n", 1);
912 /* Handle command message. */
914 server_client_msg_command(struct client
*c
, struct msg_command_data
*data
)
917 struct cmd_list
*cmdlist
= NULL
;
921 ctx
.error
= server_client_msg_error
;
922 ctx
.print
= server_client_msg_print
;
923 ctx
.info
= server_client_msg_info
;
926 ctx
.curclient
= NULL
;
931 data
->argv
[(sizeof data
->argv
) - 1] = '\0';
932 if (cmd_unpack_argv(data
->argv
, sizeof data
->argv
, argc
, &argv
) != 0) {
933 server_client_msg_error(&ctx
, "command too long");
939 argv
= xcalloc(1, sizeof *argv
);
940 *argv
= xstrdup("new-session");
943 if ((cmdlist
= cmd_list_parse(argc
, argv
, &cause
)) == NULL
) {
944 server_client_msg_error(&ctx
, "%s", cause
);
945 cmd_free_argv(argc
, argv
);
948 cmd_free_argv(argc
, argv
);
950 if (cmd_list_exec(cmdlist
, &ctx
) != 1)
951 c
->flags
|= CLIENT_EXIT
;
952 cmd_list_free(cmdlist
);
957 cmd_list_free(cmdlist
);
958 c
->flags
|= CLIENT_EXIT
;
961 /* Handle identify message. */
963 server_client_msg_identify(
964 struct client
*c
, struct msg_identify_data
*data
, int fd
)
969 data
->cwd
[(sizeof data
->cwd
) - 1] = '\0';
970 if (*data
->cwd
!= '\0')
971 c
->cwd
= xstrdup(data
->cwd
);
975 if ((tty_fd
= dup(fd
)) == -1)
977 data
->term
[(sizeof data
->term
) - 1] = '\0';
978 tty_init(&c
->tty
, tty_fd
, data
->term
);
979 if (data
->flags
& IDENTIFY_UTF8
)
980 c
->tty
.flags
|= TTY_UTF8
;
981 if (data
->flags
& IDENTIFY_256COLOURS
)
982 c
->tty
.term_flags
|= TERM_256COLOURS
;
983 else if (data
->flags
& IDENTIFY_88COLOURS
)
984 c
->tty
.term_flags
|= TERM_88COLOURS
;
985 c
->tty
.key_callback
= server_client_handle_key
;
990 c
->flags
|= CLIENT_TERMINAL
;
993 /* Handle shell message. */
995 server_client_msg_shell(struct client
*c
)
997 struct msg_shell_data data
;
1000 shell
= options_get_string(&global_s_options
, "default-shell");
1002 if (*shell
== '\0' || areshell(shell
))
1003 shell
= _PATH_BSHELL
;
1004 if (strlcpy(data
.shell
, shell
, sizeof data
.shell
) >= sizeof data
.shell
)
1005 strlcpy(data
.shell
, _PATH_BSHELL
, sizeof data
.shell
);
1007 server_write_client(c
, MSG_SHELL
, &data
, sizeof data
);
1008 c
->flags
|= CLIENT_BAD
; /* it will die after exec */