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_check_mouse(struct client
*c
,
31 struct window_pane
*wp
, struct mouse_event
*mouse
);
32 void server_client_handle_key(int, struct mouse_event
*, void *);
33 void server_client_repeat_timer(int, short, void *);
34 void server_client_check_exit(struct client
*);
35 void server_client_check_redraw(struct client
*);
36 void server_client_set_title(struct client
*);
37 void server_client_reset_state(struct client
*);
38 void server_client_in_callback(struct bufferevent
*, short, void *);
39 void server_client_out_callback(struct bufferevent
*, short, void *);
40 void server_client_err_callback(struct bufferevent
*, short, void *);
42 int server_client_msg_dispatch(struct client
*);
43 void server_client_msg_command(struct client
*, struct msg_command_data
*);
44 void server_client_msg_identify(
45 struct client
*, struct msg_identify_data
*, int);
46 void server_client_msg_shell(struct client
*);
48 void printflike2
server_client_msg_error(struct cmd_ctx
*, const char *, ...);
49 void printflike2
server_client_msg_print(struct cmd_ctx
*, const char *, ...);
50 void printflike2
server_client_msg_info(struct cmd_ctx
*, const char *, ...);
52 /* Create a new client. */
54 server_client_create(int fd
)
61 c
= xcalloc(1, sizeof *c
);
63 imsg_init(&c
->ibuf
, fd
);
64 server_update_event(c
);
66 if (gettimeofday(&c
->creation_time
, NULL
) != 0)
67 fatal("gettimeofday failed");
68 memcpy(&c
->activity_time
, &c
->creation_time
, sizeof c
->activity_time
);
70 c
->stdin_event
= NULL
;
71 c
->stdout_event
= NULL
;
72 c
->stderr_event
= NULL
;
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
->last_mouse
.b
= MOUSE_UP
;
94 c
->last_mouse
.x
= c
->last_mouse
.y
= -1;
96 evtimer_set(&c
->repeat_timer
, server_client_repeat_timer
, c
);
98 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
99 if (ARRAY_ITEM(&clients
, i
) == NULL
) {
100 ARRAY_SET(&clients
, i
, c
);
104 ARRAY_ADD(&clients
, c
);
105 log_debug("new client %d", fd
);
110 server_client_lost(struct client
*c
)
112 struct message_entry
*msg
;
115 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
116 if (ARRAY_ITEM(&clients
, i
) == c
)
117 ARRAY_SET(&clients
, i
, NULL
);
119 log_debug("lost client %d", c
->ibuf
.fd
);
122 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
123 * and tty_free might close an unrelated fd.
125 if (c
->flags
& CLIENT_TERMINAL
)
128 if (c
->stdin_event
!= NULL
)
129 bufferevent_free(c
->stdin_event
);
130 if (c
->stdin_fd
!= -1) {
131 setblocking(c
->stdin_fd
, 1);
134 if (c
->stdout_event
!= NULL
)
135 bufferevent_free(c
->stdout_event
);
136 if (c
->stdout_fd
!= -1) {
137 setblocking(c
->stdout_fd
, 1);
140 if (c
->stderr_event
!= NULL
)
141 bufferevent_free(c
->stderr_event
);
142 if (c
->stderr_fd
!= -1) {
143 setblocking(c
->stderr_fd
, 1);
147 status_free_jobs(&c
->status_new
);
148 status_free_jobs(&c
->status_old
);
149 screen_free(&c
->status
);
151 if (c
->title
!= NULL
)
154 evtimer_del(&c
->repeat_timer
);
156 if (event_initialized(&c
->identify_timer
))
157 evtimer_del(&c
->identify_timer
);
159 if (c
->message_string
!= NULL
)
160 xfree(c
->message_string
);
161 if (event_initialized (&c
->message_timer
))
162 evtimer_del(&c
->message_timer
);
163 for (i
= 0; i
< ARRAY_LENGTH(&c
->message_log
); i
++) {
164 msg
= &ARRAY_ITEM(&c
->message_log
, i
);
167 ARRAY_FREE(&c
->message_log
);
169 if (c
->prompt_string
!= NULL
)
170 xfree(c
->prompt_string
);
171 if (c
->prompt_buffer
!= NULL
)
172 xfree(c
->prompt_buffer
);
177 environ_free(&c
->environ
);
180 imsg_clear(&c
->ibuf
);
181 if (event_initialized(&c
->event
))
182 event_del(&c
->event
);
184 for (i
= 0; i
< ARRAY_LENGTH(&dead_clients
); i
++) {
185 if (ARRAY_ITEM(&dead_clients
, i
) == NULL
) {
186 ARRAY_SET(&dead_clients
, i
, c
);
190 if (i
== ARRAY_LENGTH(&dead_clients
))
191 ARRAY_ADD(&dead_clients
, c
);
192 c
->flags
|= CLIENT_DEAD
;
194 server_add_accept(0); /* may be more file descriptors now */
197 server_check_unattached();
198 server_update_socket();
201 /* Process a single client event. */
203 server_client_callback(int fd
, short events
, void *data
)
205 struct client
*c
= data
;
207 if (c
->flags
& CLIENT_DEAD
)
210 if (fd
== c
->ibuf
.fd
) {
211 if (events
& EV_WRITE
&& msgbuf_write(&c
->ibuf
.w
) < 0)
214 if (c
->flags
& CLIENT_BAD
) {
215 if (c
->ibuf
.w
.queued
== 0)
220 if (events
& EV_READ
&& server_client_msg_dispatch(c
) != 0)
224 server_update_event(c
);
228 server_client_lost(c
);
231 /* Handle client status timer. */
233 server_client_status_timer(void)
242 if (gettimeofday(&tv
, NULL
) != 0)
243 fatal("gettimeofday failed");
245 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
246 c
= ARRAY_ITEM(&clients
, i
);
247 if (c
== NULL
|| c
->session
== NULL
)
249 if (c
->message_string
!= NULL
|| c
->prompt_string
!= NULL
) {
251 * Don't need timed redraw for messages/prompts so bail
252 * now. The status timer isn't reset when they are
259 if (!options_get_number(&s
->options
, "status"))
261 interval
= options_get_number(&s
->options
, "status-interval");
263 difference
= tv
.tv_sec
- c
->status_timer
.tv_sec
;
264 if (difference
>= interval
) {
265 status_update_jobs(c
);
266 c
->flags
|= CLIENT_STATUS
;
271 /* Check for mouse keys. */
273 server_client_check_mouse(
274 struct client
*c
, struct window_pane
*wp
, struct mouse_event
*mouse
)
276 struct session
*s
= c
->session
;
277 struct options
*oo
= &s
->options
;
280 statusat
= status_at_line(c
);
282 /* Is this a window selection click on the status line? */
283 if (statusat
!= -1 && mouse
->y
== (u_int
)statusat
&&
284 options_get_number(oo
, "mouse-select-window")) {
285 if (mouse
->b
== MOUSE_UP
&& c
->last_mouse
.b
!= MOUSE_UP
) {
286 status_set_window_at(c
, mouse
->x
);
290 if (mouse
->b
& MOUSE_45
) {
291 if ((mouse
->b
& MOUSE_BUTTON
) == MOUSE_1
) {
292 session_previous(c
->session
, 0);
293 server_redraw_session(s
);
296 if ((mouse
->b
& MOUSE_BUTTON
) == MOUSE_2
) {
297 session_next(c
->session
, 0);
298 server_redraw_session(s
);
303 memcpy(&c
->last_mouse
, mouse
, sizeof c
->last_mouse
);
308 * Not on status line - adjust mouse position if status line is at the
309 * top and limit if at the bottom. From here on a struct mouse
310 * represents the offset onto the window itself.
312 if (statusat
== 0 &&mouse
->y
> 0)
314 else if (statusat
> 0 && mouse
->y
>= (u_int
)statusat
)
315 mouse
->y
= statusat
- 1;
317 /* Is this a pane selection? Allow down only in copy mode. */
318 if (options_get_number(oo
, "mouse-select-pane") &&
319 ((!(mouse
->b
& MOUSE_DRAG
) && mouse
->b
!= MOUSE_UP
) ||
320 wp
->mode
!= &window_copy_mode
)) {
321 window_set_active_at(wp
->window
, mouse
->x
, mouse
->y
);
322 server_redraw_window_borders(wp
->window
);
323 wp
= wp
->window
->active
; /* may have changed */
326 /* Check if trying to resize pane. */
327 if (options_get_number(oo
, "mouse-resize-pane"))
328 layout_resize_pane_mouse(c
, mouse
);
330 /* Update last and pass through to client. */
331 memcpy(&c
->last_mouse
, mouse
, sizeof c
->last_mouse
);
332 window_pane_mouse(wp
, c
->session
, mouse
);
335 /* Handle data key input from client. */
337 server_client_handle_key(int key
, struct mouse_event
*mouse
, void *data
)
339 struct client
*c
= data
;
342 struct window_pane
*wp
;
345 struct key_binding
*bd
;
346 int xtimeout
, isprefix
;
348 /* Check the client is good to accept input. */
349 if ((c
->flags
& (CLIENT_DEAD
|CLIENT_SUSPENDED
)) != 0)
351 if (c
->session
== NULL
)
355 /* Update the activity timer. */
356 if (gettimeofday(&c
->activity_time
, NULL
) != 0)
357 fatal("gettimeofday failed");
358 memcpy(&s
->activity_time
, &c
->activity_time
, sizeof s
->activity_time
);
360 w
= c
->session
->curw
->window
;
362 oo
= &c
->session
->options
;
364 /* Special case: number keys jump to pane in identify mode. */
365 if (c
->flags
& CLIENT_IDENTIFY
&& key
>= '0' && key
<= '9') {
366 if (c
->flags
& CLIENT_READONLY
)
368 wp
= window_pane_at_index(w
, key
- '0');
369 if (wp
!= NULL
&& window_pane_visible(wp
))
370 window_set_active_pane(w
, wp
);
371 server_clear_identify(c
);
375 /* Handle status line. */
376 if (!(c
->flags
& CLIENT_READONLY
)) {
377 status_message_clear(c
);
378 server_clear_identify(c
);
380 if (c
->prompt_string
!= NULL
) {
381 if (!(c
->flags
& CLIENT_READONLY
))
382 status_prompt_key(c
, key
);
386 /* Check for mouse keys. */
387 if (key
== KEYC_MOUSE
) {
388 if (c
->flags
& CLIENT_READONLY
)
390 server_client_check_mouse(c
, wp
, mouse
);
394 /* Is this a prefix key? */
395 if (key
== options_get_number(&c
->session
->options
, "prefix"))
397 else if (key
== options_get_number(&c
->session
->options
, "prefix2"))
402 /* No previous prefix key. */
403 if (!(c
->flags
& CLIENT_PREFIX
)) {
405 c
->flags
|= CLIENT_PREFIX
;
407 /* Try as a non-prefix key binding. */
408 if ((bd
= key_bindings_lookup(key
)) == NULL
) {
409 if (!(c
->flags
& CLIENT_READONLY
))
410 window_pane_key(wp
, c
->session
, key
);
412 key_bindings_dispatch(bd
, c
);
417 /* Prefix key already pressed. Reset prefix and lookup key. */
418 c
->flags
&= ~CLIENT_PREFIX
;
419 if ((bd
= key_bindings_lookup(key
| KEYC_PREFIX
)) == NULL
) {
420 /* If repeating, treat this as a key, else ignore. */
421 if (c
->flags
& CLIENT_REPEAT
) {
422 c
->flags
&= ~CLIENT_REPEAT
;
424 c
->flags
|= CLIENT_PREFIX
;
425 else if (!(c
->flags
& CLIENT_READONLY
))
426 window_pane_key(wp
, c
->session
, key
);
431 /* If already repeating, but this key can't repeat, skip it. */
432 if (c
->flags
& CLIENT_REPEAT
&& !bd
->can_repeat
) {
433 c
->flags
&= ~CLIENT_REPEAT
;
435 c
->flags
|= CLIENT_PREFIX
;
436 else if (!(c
->flags
& CLIENT_READONLY
))
437 window_pane_key(wp
, c
->session
, key
);
441 /* If this key can repeat, reset the repeat flags and timer. */
442 xtimeout
= options_get_number(&c
->session
->options
, "repeat-time");
443 if (xtimeout
!= 0 && bd
->can_repeat
) {
444 c
->flags
|= CLIENT_PREFIX
|CLIENT_REPEAT
;
446 tv
.tv_sec
= xtimeout
/ 1000;
447 tv
.tv_usec
= (xtimeout
% 1000) * 1000L;
448 evtimer_del(&c
->repeat_timer
);
449 evtimer_add(&c
->repeat_timer
, &tv
);
452 /* Dispatch the command. */
453 key_bindings_dispatch(bd
, c
);
456 /* Client functions that need to happen every loop. */
458 server_client_loop(void)
462 struct window_pane
*wp
;
465 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
466 c
= ARRAY_ITEM(&clients
, i
);
470 server_client_check_exit(c
);
471 if (c
->session
!= NULL
) {
472 server_client_check_redraw(c
);
473 server_client_reset_state(c
);
478 * Any windows will have been redrawn as part of clients, so clear
481 for (i
= 0; i
< ARRAY_LENGTH(&windows
); i
++) {
482 w
= ARRAY_ITEM(&windows
, i
);
486 w
->flags
&= ~WINDOW_REDRAW
;
487 TAILQ_FOREACH(wp
, &w
->panes
, entry
)
488 wp
->flags
&= ~PANE_REDRAW
;
493 * Update cursor position and mode settings. The scroll region and attributes
494 * are cleared when idle (waiting for an event) as this is the most likely time
495 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
496 * compromise between excessive resets and likelihood of an interrupt.
498 * tty_region/tty_reset/tty_update_mode already take care of not resetting
499 * things that are already in their default state.
502 server_client_reset_state(struct client
*c
)
504 struct window
*w
= c
->session
->curw
->window
;
505 struct window_pane
*wp
= w
->active
;
506 struct screen
*s
= wp
->screen
;
507 struct options
*oo
= &c
->session
->options
;
508 struct options
*wo
= &w
->options
;
511 if (c
->flags
& CLIENT_SUSPENDED
)
514 tty_region(&c
->tty
, 0, c
->tty
.sy
- 1);
516 status
= options_get_number(oo
, "status");
517 if (!window_pane_visible(wp
) || wp
->yoff
+ s
->cy
>= c
->tty
.sy
- status
)
518 tty_cursor(&c
->tty
, 0, 0);
520 o
= status
&& options_get_number (oo
, "status-position") == 0;
521 tty_cursor(&c
->tty
, wp
->xoff
+ s
->cx
, o
+ wp
->yoff
+ s
->cy
);
525 * Resizing panes with the mouse requires at least button mode to give
526 * a smooth appearance.
529 if ((c
->last_mouse
.b
& MOUSE_RESIZE_PANE
) &&
530 !(mode
& (MODE_MOUSE_BUTTON
|MODE_MOUSE_ANY
)))
531 mode
|= MODE_MOUSE_BUTTON
;
534 * Any mode will do for mouse-select-pane, but set standard mode if
537 if ((mode
& ALL_MOUSE_MODES
) == 0) {
538 if (TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
) != NULL
&&
539 options_get_number(oo
, "mouse-select-pane"))
540 mode
|= MODE_MOUSE_STANDARD
;
541 else if (options_get_number(oo
, "mouse-resize-pane"))
542 mode
|= MODE_MOUSE_STANDARD
;
543 else if (options_get_number(oo
, "mouse-select-window"))
544 mode
|= MODE_MOUSE_STANDARD
;
545 else if (options_get_number(wo
, "mode-mouse"))
546 mode
|= MODE_MOUSE_STANDARD
;
550 * Set UTF-8 mouse input if required. If the terminal is UTF-8, the
551 * user has set mouse-utf8 and any mouse mode is in effect, turn on
552 * UTF-8 mouse input. If the receiving terminal hasn't requested it
553 * (that is, it isn't in s->mode), then it'll be converted in
556 if ((c
->tty
.flags
& TTY_UTF8
) &&
557 (mode
& ALL_MOUSE_MODES
) && options_get_number(oo
, "mouse-utf8"))
558 mode
|= MODE_MOUSE_UTF8
;
560 mode
&= ~MODE_MOUSE_UTF8
;
562 /* Set the terminal mode and reset attributes. */
563 tty_update_mode(&c
->tty
, mode
, s
);
567 /* Repeat time callback. */
570 server_client_repeat_timer(unused
int fd
, unused
short events
, void *data
)
572 struct client
*c
= data
;
574 if (c
->flags
& CLIENT_REPEAT
)
575 c
->flags
&= ~(CLIENT_PREFIX
|CLIENT_REPEAT
);
578 /* Check if client should be exited. */
580 server_client_check_exit(struct client
*c
)
582 struct msg_exit_data exitdata
;
584 if (!(c
->flags
& CLIENT_EXIT
))
587 if (c
->stdout_fd
!= -1 && c
->stdout_event
!= NULL
&&
588 EVBUFFER_LENGTH(c
->stdout_event
->output
) != 0)
590 if (c
->stderr_fd
!= -1 && c
->stderr_event
!= NULL
&&
591 EVBUFFER_LENGTH(c
->stderr_event
->output
) != 0)
594 exitdata
.retcode
= c
->retcode
;
595 server_write_client(c
, MSG_EXIT
, &exitdata
, sizeof exitdata
);
597 c
->flags
&= ~CLIENT_EXIT
;
600 /* Check for client redraws. */
602 server_client_check_redraw(struct client
*c
)
604 struct session
*s
= c
->session
;
605 struct window_pane
*wp
;
608 flags
= c
->tty
.flags
& TTY_FREEZE
;
609 c
->tty
.flags
&= ~TTY_FREEZE
;
611 if (c
->flags
& (CLIENT_REDRAW
|CLIENT_STATUS
)) {
612 if (options_get_number(&s
->options
, "set-titles"))
613 server_client_set_title(c
);
615 if (c
->message_string
!= NULL
)
616 redraw
= status_message_redraw(c
);
617 else if (c
->prompt_string
!= NULL
)
618 redraw
= status_prompt_redraw(c
);
620 redraw
= status_redraw(c
);
622 c
->flags
&= ~CLIENT_STATUS
;
625 if (c
->flags
& CLIENT_REDRAW
) {
626 screen_redraw_screen(c
, 0, 0);
627 c
->flags
&= ~(CLIENT_STATUS
|CLIENT_BORDERS
);
628 } else if (c
->flags
& CLIENT_REDRAWWINDOW
) {
629 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
)
630 screen_redraw_pane(c
, wp
);
631 c
->flags
&= ~CLIENT_REDRAWWINDOW
;
633 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
) {
634 if (wp
->flags
& PANE_REDRAW
)
635 screen_redraw_pane(c
, wp
);
639 if (c
->flags
& CLIENT_BORDERS
)
640 screen_redraw_screen(c
, 0, 1);
642 if (c
->flags
& CLIENT_STATUS
)
643 screen_redraw_screen(c
, 1, 0);
645 c
->tty
.flags
|= flags
;
647 c
->flags
&= ~(CLIENT_REDRAW
|CLIENT_STATUS
|CLIENT_BORDERS
);
650 /* Set client title. */
652 server_client_set_title(struct client
*c
)
654 struct session
*s
= c
->session
;
655 const char *template;
658 template = options_get_string(&s
->options
, "set-titles-string");
660 title
= status_replace(c
, NULL
, NULL
, NULL
, template, time(NULL
), 1);
661 if (c
->title
== NULL
|| strcmp(title
, c
->title
) != 0) {
662 if (c
->title
!= NULL
)
664 c
->title
= xstrdup(title
);
665 tty_set_title(&c
->tty
, c
->title
);
671 * Error callback for client stdin. Caller must increase reference count when
675 server_client_in_callback(
676 unused
struct bufferevent
*bufev
, unused
short what
, void *data
)
678 struct client
*c
= data
;
681 if (c
->flags
& CLIENT_DEAD
)
684 bufferevent_disable(c
->stdin_event
, EV_READ
|EV_WRITE
);
685 setblocking(c
->stdin_fd
, 1);
689 if (c
->stdin_callback
!= NULL
)
690 c
->stdin_callback(c
, c
->stdin_data
);
693 /* Error callback for client stdout. */
695 server_client_out_callback(
696 unused
struct bufferevent
*bufev
, unused
short what
, unused
void *data
)
698 struct client
*c
= data
;
700 bufferevent_disable(c
->stdout_event
, EV_READ
|EV_WRITE
);
701 setblocking(c
->stdout_fd
, 1);
706 /* Error callback for client stderr. */
708 server_client_err_callback(
709 unused
struct bufferevent
*bufev
, unused
short what
, unused
void *data
)
711 struct client
*c
= data
;
713 bufferevent_disable(c
->stderr_event
, EV_READ
|EV_WRITE
);
714 setblocking(c
->stderr_fd
, 1);
719 /* Dispatch message from client. */
721 server_client_msg_dispatch(struct client
*c
)
724 struct msg_command_data commanddata
;
725 struct msg_identify_data identifydata
;
726 struct msg_environ_data environdata
;
729 if ((n
= imsg_read(&c
->ibuf
)) == -1 || n
== 0)
733 if ((n
= imsg_get(&c
->ibuf
, &imsg
)) == -1)
737 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
739 if (imsg
.hdr
.peerid
!= PROTOCOL_VERSION
) {
740 server_write_client(c
, MSG_VERSION
, NULL
, 0);
741 c
->flags
|= CLIENT_BAD
;
746 log_debug("got %d from client %d", imsg
.hdr
.type
, c
->ibuf
.fd
);
747 switch (imsg
.hdr
.type
) {
749 if (datalen
!= sizeof commanddata
)
750 fatalx("bad MSG_COMMAND size");
751 memcpy(&commanddata
, imsg
.data
, sizeof commanddata
);
753 server_client_msg_command(c
, &commanddata
);
756 if (datalen
!= sizeof identifydata
)
757 fatalx("bad MSG_IDENTIFY size");
759 fatalx("MSG_IDENTIFY missing fd");
760 memcpy(&identifydata
, imsg
.data
, sizeof identifydata
);
762 c
->stdin_fd
= imsg
.fd
;
763 c
->stdin_event
= bufferevent_new(c
->stdin_fd
,
764 NULL
, NULL
, server_client_in_callback
, c
);
765 if (c
->stdin_event
== NULL
)
766 fatalx("failed to create stdin event");
767 setblocking(c
->stdin_fd
, 0);
769 server_client_msg_identify(c
, &identifydata
, imsg
.fd
);
773 fatalx("bad MSG_STDOUT size");
775 fatalx("MSG_STDOUT missing fd");
777 c
->stdout_fd
= imsg
.fd
;
778 c
->stdout_event
= bufferevent_new(c
->stdout_fd
,
779 NULL
, NULL
, server_client_out_callback
, c
);
780 if (c
->stdout_event
== NULL
)
781 fatalx("failed to create stdout event");
782 setblocking(c
->stdout_fd
, 0);
787 fatalx("bad MSG_STDERR size");
789 fatalx("MSG_STDERR missing fd");
791 c
->stderr_fd
= imsg
.fd
;
792 c
->stderr_event
= bufferevent_new(c
->stderr_fd
,
793 NULL
, NULL
, server_client_err_callback
, c
);
794 if (c
->stderr_event
== NULL
)
795 fatalx("failed to create stderr event");
796 setblocking(c
->stderr_fd
, 0);
801 fatalx("bad MSG_RESIZE size");
803 if (tty_resize(&c
->tty
)) {
805 server_redraw_client(c
);
810 fatalx("bad MSG_EXITING size");
814 server_write_client(c
, MSG_EXITED
, NULL
, 0);
819 fatalx("bad MSG_WAKEUP size");
821 if (!(c
->flags
& CLIENT_SUSPENDED
))
823 c
->flags
&= ~CLIENT_SUSPENDED
;
825 if (gettimeofday(&c
->activity_time
, NULL
) != 0)
826 fatal("gettimeofday");
827 if (c
->session
!= NULL
)
828 session_update_activity(c
->session
);
830 tty_start_tty(&c
->tty
);
831 server_redraw_client(c
);
835 if (datalen
!= sizeof environdata
)
836 fatalx("bad MSG_ENVIRON size");
837 memcpy(&environdata
, imsg
.data
, sizeof environdata
);
839 environdata
.var
[(sizeof environdata
.var
) - 1] = '\0';
840 if (strchr(environdata
.var
, '=') != NULL
)
841 environ_put(&c
->environ
, environdata
.var
);
845 fatalx("bad MSG_SHELL size");
847 server_client_msg_shell(c
);
850 fatalx("unexpected message");
857 /* Callback to send error message to client. */
859 server_client_msg_error(struct cmd_ctx
*ctx
, const char *fmt
, ...)
864 evbuffer_add_vprintf(ctx
->cmdclient
->stderr_event
->output
, fmt
, ap
);
867 bufferevent_write(ctx
->cmdclient
->stderr_event
, "\n", 1);
868 ctx
->cmdclient
->retcode
= 1;
871 /* Callback to send print message to client. */
873 server_client_msg_print(struct cmd_ctx
*ctx
, const char *fmt
, ...)
878 evbuffer_add_vprintf(ctx
->cmdclient
->stdout_event
->output
, fmt
, ap
);
881 bufferevent_write(ctx
->cmdclient
->stdout_event
, "\n", 1);
884 /* Callback to send print message to client, if not quiet. */
886 server_client_msg_info(struct cmd_ctx
*ctx
, const char *fmt
, ...)
890 if (options_get_number(&global_options
, "quiet"))
894 evbuffer_add_vprintf(ctx
->cmdclient
->stdout_event
->output
, fmt
, ap
);
897 bufferevent_write(ctx
->cmdclient
->stdout_event
, "\n", 1);
900 /* Handle command message. */
902 server_client_msg_command(struct client
*c
, struct msg_command_data
*data
)
905 struct cmd_list
*cmdlist
= NULL
;
909 ctx
.error
= server_client_msg_error
;
910 ctx
.print
= server_client_msg_print
;
911 ctx
.info
= server_client_msg_info
;
914 ctx
.curclient
= NULL
;
919 data
->argv
[(sizeof data
->argv
) - 1] = '\0';
920 if (cmd_unpack_argv(data
->argv
, sizeof data
->argv
, argc
, &argv
) != 0) {
921 server_client_msg_error(&ctx
, "command too long");
927 argv
= xcalloc(1, sizeof *argv
);
928 *argv
= xstrdup("new-session");
931 if ((cmdlist
= cmd_list_parse(argc
, argv
, &cause
)) == NULL
) {
932 server_client_msg_error(&ctx
, "%s", cause
);
933 cmd_free_argv(argc
, argv
);
936 cmd_free_argv(argc
, argv
);
938 if (cmd_list_exec(cmdlist
, &ctx
) != 1)
939 c
->flags
|= CLIENT_EXIT
;
940 cmd_list_free(cmdlist
);
945 cmd_list_free(cmdlist
);
946 c
->flags
|= CLIENT_EXIT
;
949 /* Handle identify message. */
951 server_client_msg_identify(
952 struct client
*c
, struct msg_identify_data
*data
, int fd
)
957 data
->cwd
[(sizeof data
->cwd
) - 1] = '\0';
958 if (*data
->cwd
!= '\0')
959 c
->cwd
= xstrdup(data
->cwd
);
963 if ((tty_fd
= dup(fd
)) == -1)
965 data
->term
[(sizeof data
->term
) - 1] = '\0';
966 tty_init(&c
->tty
, tty_fd
, data
->term
);
967 if (data
->flags
& IDENTIFY_UTF8
)
968 c
->tty
.flags
|= TTY_UTF8
;
969 if (data
->flags
& IDENTIFY_256COLOURS
)
970 c
->tty
.term_flags
|= TERM_256COLOURS
;
971 else if (data
->flags
& IDENTIFY_88COLOURS
)
972 c
->tty
.term_flags
|= TERM_88COLOURS
;
973 c
->tty
.key_callback
= server_client_handle_key
;
978 c
->flags
|= CLIENT_TERMINAL
;
981 /* Handle shell message. */
983 server_client_msg_shell(struct client
*c
)
985 struct msg_shell_data data
;
988 shell
= options_get_string(&global_s_options
, "default-shell");
990 if (*shell
== '\0' || areshell(shell
))
991 shell
= _PATH_BSHELL
;
992 if (strlcpy(data
.shell
, shell
, sizeof data
.shell
) >= sizeof data
.shell
)
993 strlcpy(data
.shell
, _PATH_BSHELL
, sizeof data
.shell
);
995 server_write_client(c
, MSG_SHELL
, &data
, sizeof data
);
996 c
->flags
|= CLIENT_BAD
; /* it will die after exec */