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_redraw(struct client
*);
34 void server_client_set_title(struct client
*);
35 void server_client_reset_state(struct client
*);
36 void server_client_in_callback(struct bufferevent
*, short, void *);
37 void server_client_out_callback(struct bufferevent
*, short, void *);
38 void server_client_err_callback(struct bufferevent
*, short, void *);
40 int server_client_msg_dispatch(struct client
*);
41 void server_client_msg_command(struct client
*, struct msg_command_data
*);
42 void server_client_msg_identify(
43 struct client
*, struct msg_identify_data
*, int);
44 void server_client_msg_shell(struct client
*);
46 void printflike2
server_client_msg_error(struct cmd_ctx
*, const char *, ...);
47 void printflike2
server_client_msg_print(struct cmd_ctx
*, const char *, ...);
48 void printflike2
server_client_msg_info(struct cmd_ctx
*, const char *, ...);
50 /* Create a new client. */
52 server_client_create(int fd
)
58 if ((mode
= fcntl(fd
, F_GETFL
)) == -1)
59 fatal("fcntl failed");
60 if (fcntl(fd
, F_SETFL
, mode
|O_NONBLOCK
) == -1)
61 fatal("fcntl failed");
62 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
) == -1)
63 fatal("fcntl failed");
65 c
= xcalloc(1, sizeof *c
);
67 imsg_init(&c
->ibuf
, fd
);
68 server_update_event(c
);
70 if (gettimeofday(&c
->creation_time
, NULL
) != 0)
71 fatal("gettimeofday failed");
72 memcpy(&c
->activity_time
, &c
->creation_time
, sizeof c
->activity_time
);
74 ARRAY_INIT(&c
->prompt_hdata
);
76 c
->stdin_event
= NULL
;
77 c
->stdout_event
= NULL
;
78 c
->stderr_event
= NULL
;
87 screen_init(&c
->status
, c
->tty
.sx
, 1, 0);
88 job_tree_init(&c
->status_jobs
);
90 c
->message_string
= NULL
;
91 ARRAY_INIT(&c
->message_log
);
93 c
->prompt_string
= NULL
;
94 c
->prompt_buffer
= NULL
;
97 evtimer_set(&c
->repeat_timer
, server_client_repeat_timer
, c
);
99 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
100 if (ARRAY_ITEM(&clients
, i
) == NULL
) {
101 ARRAY_SET(&clients
, i
, c
);
105 ARRAY_ADD(&clients
, c
);
106 log_debug("new client %d", fd
);
111 server_client_lost(struct client
*c
)
113 struct message_entry
*msg
;
116 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
117 if (ARRAY_ITEM(&clients
, i
) == c
)
118 ARRAY_SET(&clients
, i
, NULL
);
120 log_debug("lost client %d", c
->ibuf
.fd
);
123 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
124 * and tty_free might close an unrelated fd.
126 if (c
->flags
& CLIENT_TERMINAL
)
129 if (c
->stdin_fd
!= -1)
131 if (c
->stdin_event
!= NULL
)
132 bufferevent_free(c
->stdin_event
);
133 if (c
->stdout_fd
!= -1)
135 if (c
->stdout_event
!= NULL
)
136 bufferevent_free(c
->stdout_event
);
137 if (c
->stderr_fd
!= -1)
139 if (c
->stderr_event
!= NULL
)
140 bufferevent_free(c
->stderr_event
);
142 screen_free(&c
->status
);
143 job_tree_free(&c
->status_jobs
);
145 if (c
->title
!= NULL
)
148 evtimer_del(&c
->repeat_timer
);
150 evtimer_del(&c
->identify_timer
);
152 if (c
->message_string
!= NULL
)
153 xfree(c
->message_string
);
154 evtimer_del(&c
->message_timer
);
155 for (i
= 0; i
< ARRAY_LENGTH(&c
->message_log
); i
++) {
156 msg
= &ARRAY_ITEM(&c
->message_log
, i
);
159 ARRAY_FREE(&c
->message_log
);
161 if (c
->prompt_string
!= NULL
)
162 xfree(c
->prompt_string
);
163 if (c
->prompt_buffer
!= NULL
)
164 xfree(c
->prompt_buffer
);
165 for (i
= 0; i
< ARRAY_LENGTH(&c
->prompt_hdata
); i
++)
166 xfree(ARRAY_ITEM(&c
->prompt_hdata
, i
));
167 ARRAY_FREE(&c
->prompt_hdata
);
173 imsg_clear(&c
->ibuf
);
174 event_del(&c
->event
);
176 for (i
= 0; i
< ARRAY_LENGTH(&dead_clients
); i
++) {
177 if (ARRAY_ITEM(&dead_clients
, i
) == NULL
) {
178 ARRAY_SET(&dead_clients
, i
, c
);
182 if (i
== ARRAY_LENGTH(&dead_clients
))
183 ARRAY_ADD(&dead_clients
, c
);
184 c
->flags
|= CLIENT_DEAD
;
187 server_update_socket();
190 /* Process a single client event. */
192 server_client_callback(int fd
, short events
, void *data
)
194 struct client
*c
= data
;
196 if (c
->flags
& CLIENT_DEAD
)
199 if (fd
== c
->ibuf
.fd
) {
200 if (events
& EV_WRITE
&& msgbuf_write(&c
->ibuf
.w
) < 0)
203 if (c
->flags
& CLIENT_BAD
) {
204 if (c
->ibuf
.w
.queued
== 0)
209 if (events
& EV_READ
&& server_client_msg_dispatch(c
) != 0)
213 server_update_event(c
);
217 server_client_lost(c
);
220 /* Handle client status timer. */
222 server_client_status_timer(void)
232 if (gettimeofday(&tv
, NULL
) != 0)
233 fatal("gettimeofday failed");
235 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
236 c
= ARRAY_ITEM(&clients
, i
);
237 if (c
== NULL
|| c
->session
== NULL
)
239 if (c
->message_string
!= NULL
|| c
->prompt_string
!= NULL
) {
241 * Don't need timed redraw for messages/prompts so bail
242 * now. The status timer isn't reset when they are
249 if (!options_get_number(&s
->options
, "status"))
251 interval
= options_get_number(&s
->options
, "status-interval");
253 difference
= tv
.tv_sec
- c
->status_timer
.tv_sec
;
254 if (difference
>= interval
) {
255 RB_FOREACH(job
, jobs
, &c
->status_jobs
)
257 c
->flags
|= CLIENT_STATUS
;
262 /* Handle data key input from client. */
264 server_client_handle_key(int key
, struct mouse_event
*mouse
, void *data
)
266 struct client
*c
= data
;
269 struct window_pane
*wp
;
272 struct key_binding
*bd
;
273 struct keylist
*keylist
;
274 int xtimeout
, isprefix
;
277 /* Check the client is good to accept input. */
278 if ((c
->flags
& (CLIENT_DEAD
|CLIENT_SUSPENDED
)) != 0)
280 if (c
->session
== NULL
)
284 /* Update the activity timer. */
285 if (gettimeofday(&c
->activity_time
, NULL
) != 0)
286 fatal("gettimeofday failed");
287 memcpy(&s
->activity_time
, &c
->activity_time
, sizeof s
->activity_time
);
289 w
= c
->session
->curw
->window
;
291 oo
= &c
->session
->options
;
293 /* Special case: number keys jump to pane in identify mode. */
294 if (c
->flags
& CLIENT_IDENTIFY
&& key
>= '0' && key
<= '9') {
295 if (c
->flags
& CLIENT_READONLY
)
297 wp
= window_pane_at_index(w
, key
- '0');
298 if (wp
!= NULL
&& window_pane_visible(wp
))
299 window_set_active_pane(w
, wp
);
300 server_clear_identify(c
);
304 /* Handle status line. */
305 if (!(c
->flags
& CLIENT_READONLY
)) {
306 status_message_clear(c
);
307 server_clear_identify(c
);
309 if (c
->prompt_string
!= NULL
) {
310 if (!(c
->flags
& CLIENT_READONLY
))
311 status_prompt_key(c
, key
);
315 /* Check for mouse keys. */
316 if (key
== KEYC_MOUSE
) {
317 if (c
->flags
& CLIENT_READONLY
)
319 if (options_get_number(oo
, "mouse-select-pane")) {
320 window_set_active_at(w
, mouse
->x
, mouse
->y
);
321 server_redraw_window_borders(w
);
324 window_pane_mouse(wp
, c
->session
, mouse
);
328 /* Is this a prefix key? */
329 keylist
= options_get_data(&c
->session
->options
, "prefix");
331 for (i
= 0; i
< ARRAY_LENGTH(keylist
); i
++) {
332 if (key
== ARRAY_ITEM(keylist
, i
)) {
338 /* No previous prefix key. */
339 if (!(c
->flags
& CLIENT_PREFIX
)) {
341 c
->flags
|= CLIENT_PREFIX
;
343 /* Try as a non-prefix key binding. */
344 if ((bd
= key_bindings_lookup(key
)) == NULL
) {
345 if (!(c
->flags
& CLIENT_READONLY
))
346 window_pane_key(wp
, c
->session
, key
);
348 key_bindings_dispatch(bd
, c
);
353 /* Prefix key already pressed. Reset prefix and lookup key. */
354 c
->flags
&= ~CLIENT_PREFIX
;
355 if ((bd
= key_bindings_lookup(key
| KEYC_PREFIX
)) == NULL
) {
356 /* If repeating, treat this as a key, else ignore. */
357 if (c
->flags
& CLIENT_REPEAT
) {
358 c
->flags
&= ~CLIENT_REPEAT
;
360 c
->flags
|= CLIENT_PREFIX
;
361 else if (!(c
->flags
& CLIENT_READONLY
))
362 window_pane_key(wp
, c
->session
, key
);
367 /* If already repeating, but this key can't repeat, skip it. */
368 if (c
->flags
& CLIENT_REPEAT
&& !bd
->can_repeat
) {
369 c
->flags
&= ~CLIENT_REPEAT
;
371 c
->flags
|= CLIENT_PREFIX
;
372 else if (!(c
->flags
& CLIENT_READONLY
))
373 window_pane_key(wp
, c
->session
, key
);
377 /* If this key can repeat, reset the repeat flags and timer. */
378 xtimeout
= options_get_number(&c
->session
->options
, "repeat-time");
379 if (xtimeout
!= 0 && bd
->can_repeat
) {
380 c
->flags
|= CLIENT_PREFIX
|CLIENT_REPEAT
;
382 tv
.tv_sec
= xtimeout
/ 1000;
383 tv
.tv_usec
= (xtimeout
% 1000) * 1000L;
384 evtimer_del(&c
->repeat_timer
);
385 evtimer_add(&c
->repeat_timer
, &tv
);
388 /* Dispatch the command. */
389 key_bindings_dispatch(bd
, c
);
392 /* Client functions that need to happen every loop. */
394 server_client_loop(void)
398 struct window_pane
*wp
;
401 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
402 c
= ARRAY_ITEM(&clients
, i
);
406 server_client_check_exit(c
);
407 if (c
->session
!= NULL
) {
408 server_client_check_redraw(c
);
409 server_client_reset_state(c
);
414 * Any windows will have been redrawn as part of clients, so clear
417 for (i
= 0; i
< ARRAY_LENGTH(&windows
); i
++) {
418 w
= ARRAY_ITEM(&windows
, i
);
422 w
->flags
&= ~WINDOW_REDRAW
;
423 TAILQ_FOREACH(wp
, &w
->panes
, entry
)
424 wp
->flags
&= ~PANE_REDRAW
;
429 * Update cursor position and mode settings. The scroll region and attributes
430 * are cleared when idle (waiting for an event) as this is the most likely time
431 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
432 * compromise between excessive resets and likelihood of an interrupt.
434 * tty_region/tty_reset/tty_update_mode already take care of not resetting
435 * things that are already in their default state.
438 server_client_reset_state(struct client
*c
)
440 struct window
*w
= c
->session
->curw
->window
;
441 struct window_pane
*wp
= w
->active
;
442 struct screen
*s
= wp
->screen
;
443 struct options
*oo
= &c
->session
->options
;
446 tty_region(&c
->tty
, 0, c
->tty
.sy
- 1);
448 status
= options_get_number(oo
, "status");
449 if (!window_pane_visible(wp
) || wp
->yoff
+ s
->cy
>= c
->tty
.sy
- status
)
450 tty_cursor(&c
->tty
, 0, 0);
452 tty_cursor(&c
->tty
, wp
->xoff
+ s
->cx
, wp
->yoff
+ s
->cy
);
455 if (TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
) != NULL
&&
456 options_get_number(oo
, "mouse-select-pane"))
458 tty_update_mode(&c
->tty
, mode
);
462 /* Repeat time callback. */
465 server_client_repeat_timer(unused
int fd
, unused
short events
, void *data
)
467 struct client
*c
= data
;
469 if (c
->flags
& CLIENT_REPEAT
)
470 c
->flags
&= ~(CLIENT_PREFIX
|CLIENT_REPEAT
);
473 /* Check if client should be exited. */
475 server_client_check_exit(struct client
*c
)
477 struct msg_exit_data exitdata
;
479 if (!(c
->flags
& CLIENT_EXIT
))
482 if (c
->stdout_fd
!= -1 && c
->stdout_event
!= NULL
&&
483 EVBUFFER_LENGTH(c
->stdout_event
->output
) != 0)
485 if (c
->stderr_fd
!= -1 && c
->stderr_event
!= NULL
&&
486 EVBUFFER_LENGTH(c
->stderr_event
->output
) != 0)
489 exitdata
.retcode
= c
->retcode
;
490 server_write_client(c
, MSG_EXIT
, &exitdata
, sizeof exitdata
);
492 c
->flags
&= ~CLIENT_EXIT
;
496 * Check if the client should backoff. During backoff, data from external
497 * programs is not written to the terminal. When the existing data drains, the
500 * There are two backoff phases - both the tty and client have backoff flags -
501 * the first to allow existing data to drain and the latter to ensure backoff
502 * is disabled until the redraw has finished and prevent the redraw triggering
506 server_client_check_backoff(struct client
*c
)
508 struct tty
*tty
= &c
->tty
;
511 used
= EVBUFFER_LENGTH(tty
->event
->output
);
514 * If in the second backoff phase (redrawing), don't check backoff
515 * until the redraw has completed (or enough of it to drop below the
516 * backoff threshold).
518 if (c
->flags
& CLIENT_BACKOFF
) {
519 if (used
> BACKOFF_THRESHOLD
)
521 c
->flags
&= ~CLIENT_BACKOFF
;
525 /* Once drained, allow data through again and schedule redraw. */
526 if (tty
->flags
& TTY_BACKOFF
) {
529 tty
->flags
&= ~TTY_BACKOFF
;
530 c
->flags
|= (CLIENT_BACKOFF
|CLIENT_REDRAWWINDOW
|CLIENT_STATUS
);
534 /* If too much data, start backoff. */
535 if (used
> BACKOFF_THRESHOLD
)
536 tty
->flags
|= TTY_BACKOFF
;
539 /* Check for client redraws. */
541 server_client_check_redraw(struct client
*c
)
543 struct session
*s
= c
->session
;
544 struct window_pane
*wp
;
547 flags
= c
->tty
.flags
& TTY_FREEZE
;
548 c
->tty
.flags
&= ~TTY_FREEZE
;
550 if (c
->flags
& (CLIENT_REDRAW
|CLIENT_STATUS
)) {
551 if (options_get_number(&s
->options
, "set-titles"))
552 server_client_set_title(c
);
554 if (c
->message_string
!= NULL
)
555 redraw
= status_message_redraw(c
);
556 else if (c
->prompt_string
!= NULL
)
557 redraw
= status_prompt_redraw(c
);
559 redraw
= status_redraw(c
);
561 c
->flags
&= ~CLIENT_STATUS
;
564 if (c
->flags
& CLIENT_REDRAW
) {
565 screen_redraw_screen(c
, 0, 0);
566 c
->flags
&= ~(CLIENT_STATUS
|CLIENT_BORDERS
);
567 } else if (c
->flags
& CLIENT_REDRAWWINDOW
) {
568 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
)
569 screen_redraw_pane(c
, wp
);
570 c
->flags
&= ~CLIENT_REDRAWWINDOW
;
572 TAILQ_FOREACH(wp
, &c
->session
->curw
->window
->panes
, entry
) {
573 if (wp
->flags
& PANE_REDRAW
)
574 screen_redraw_pane(c
, wp
);
578 if (c
->flags
& CLIENT_BORDERS
)
579 screen_redraw_screen(c
, 0, 1);
581 if (c
->flags
& CLIENT_STATUS
)
582 screen_redraw_screen(c
, 1, 0);
584 c
->tty
.flags
|= flags
;
586 c
->flags
&= ~(CLIENT_REDRAW
|CLIENT_STATUS
|CLIENT_BORDERS
);
589 /* Set client title. */
591 server_client_set_title(struct client
*c
)
593 struct session
*s
= c
->session
;
594 const char *template;
597 template = options_get_string(&s
->options
, "set-titles-string");
599 title
= status_replace(c
, NULL
, template, time(NULL
), 1);
600 if (c
->title
== NULL
|| strcmp(title
, c
->title
) != 0) {
601 if (c
->title
!= NULL
)
603 c
->title
= xstrdup(title
);
604 tty_set_title(&c
->tty
, c
->title
);
610 * Error callback for client stdin. Caller must increase reference count when
614 server_client_in_callback(
615 unused
struct bufferevent
*bufev
, unused
short what
, void *data
)
617 struct client
*c
= data
;
620 if (c
->flags
& CLIENT_DEAD
)
623 bufferevent_disable(c
->stdin_event
, EV_READ
|EV_WRITE
);
627 if (c
->stdin_callback
!= NULL
)
628 c
->stdin_callback(c
, c
->stdin_data
);
631 /* Error callback for client stdout. */
633 server_client_out_callback(
634 unused
struct bufferevent
*bufev
, unused
short what
, unused
void *data
)
636 struct client
*c
= data
;
638 bufferevent_disable(c
->stdout_event
, EV_READ
|EV_WRITE
);
643 /* Error callback for client stderr. */
645 server_client_err_callback(
646 unused
struct bufferevent
*bufev
, unused
short what
, unused
void *data
)
648 struct client
*c
= data
;
650 bufferevent_disable(c
->stderr_event
, EV_READ
|EV_WRITE
);
655 /* Dispatch message from client. */
657 server_client_msg_dispatch(struct client
*c
)
660 struct msg_command_data commanddata
;
661 struct msg_identify_data identifydata
;
662 struct msg_environ_data environdata
;
666 if ((n
= imsg_read(&c
->ibuf
)) == -1 || n
== 0)
670 if ((n
= imsg_get(&c
->ibuf
, &imsg
)) == -1)
674 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
676 if (imsg
.hdr
.peerid
!= PROTOCOL_VERSION
) {
677 server_write_client(c
, MSG_VERSION
, NULL
, 0);
678 c
->flags
|= CLIENT_BAD
;
683 log_debug("got %d from client %d", imsg
.hdr
.type
, c
->ibuf
.fd
);
684 switch (imsg
.hdr
.type
) {
686 if (datalen
!= sizeof commanddata
)
687 fatalx("bad MSG_COMMAND size");
688 memcpy(&commanddata
, imsg
.data
, sizeof commanddata
);
690 server_client_msg_command(c
, &commanddata
);
693 if (datalen
!= sizeof identifydata
)
694 fatalx("bad MSG_IDENTIFY size");
696 fatalx("MSG_IDENTIFY missing fd");
697 memcpy(&identifydata
, imsg
.data
, sizeof identifydata
);
699 c
->stdin_fd
= dup(imsg
.fd
);
700 if (c
->stdin_fd
== -1)
702 c
->stdin_event
= bufferevent_new(c
->stdin_fd
,
703 NULL
, NULL
, server_client_in_callback
, c
);
704 if (c
->stdin_event
== NULL
)
705 fatalx("failed to create stdin event");
707 if ((mode
= fcntl(imsg
.fd
, F_GETFL
)) != -1)
708 fcntl(imsg
.fd
, F_SETFL
, mode
|O_NONBLOCK
);
709 if (fcntl(imsg
.fd
, F_SETFD
, FD_CLOEXEC
) == -1)
710 fatal("fcntl failed");
712 server_client_msg_identify(c
, &identifydata
, imsg
.fd
);
716 fatalx("bad MSG_STDOUT size");
718 fatalx("MSG_STDOUT missing fd");
720 c
->stdout_fd
= imsg
.fd
;
721 c
->stdout_event
= bufferevent_new(c
->stdout_fd
,
722 NULL
, NULL
, server_client_out_callback
, c
);
723 if (c
->stdout_event
== NULL
)
724 fatalx("failed to create stdout event");
726 if ((mode
= fcntl(c
->stdout_fd
, F_GETFL
)) != -1)
727 fcntl(c
->stdout_fd
, F_SETFL
, mode
|O_NONBLOCK
);
728 if (fcntl(c
->stdout_fd
, F_SETFD
, FD_CLOEXEC
) == -1)
729 fatal("fcntl failed");
733 fatalx("bad MSG_STDERR size");
735 fatalx("MSG_STDERR missing fd");
737 c
->stderr_fd
= imsg
.fd
;
738 c
->stderr_event
= bufferevent_new(c
->stderr_fd
,
739 NULL
, NULL
, server_client_err_callback
, c
);
740 if (c
->stderr_event
== NULL
)
741 fatalx("failed to create stderr event");
743 if ((mode
= fcntl(c
->stderr_fd
, F_GETFL
)) != -1)
744 fcntl(c
->stderr_fd
, F_SETFL
, mode
|O_NONBLOCK
);
745 if (fcntl(c
->stderr_fd
, F_SETFD
, FD_CLOEXEC
) == -1)
746 fatal("fcntl failed");
750 fatalx("bad MSG_RESIZE size");
752 if (tty_resize(&c
->tty
)) {
754 server_redraw_client(c
);
759 fatalx("bad MSG_EXITING size");
763 server_write_client(c
, MSG_EXITED
, NULL
, 0);
768 fatalx("bad MSG_WAKEUP size");
770 if (!(c
->flags
& CLIENT_SUSPENDED
))
772 c
->flags
&= ~CLIENT_SUSPENDED
;
774 if (gettimeofday(&c
->activity_time
, NULL
) != 0)
775 fatal("gettimeofday");
776 if (c
->session
!= NULL
) {
777 memcpy(&c
->session
->activity_time
,
779 sizeof c
->session
->activity_time
);
782 tty_start_tty(&c
->tty
);
783 server_redraw_client(c
);
787 if (datalen
!= sizeof environdata
)
788 fatalx("bad MSG_ENVIRON size");
789 memcpy(&environdata
, imsg
.data
, sizeof environdata
);
791 environdata
.var
[(sizeof environdata
.var
) - 1] = '\0';
792 if (strchr(environdata
.var
, '=') != NULL
)
793 environ_put(&c
->environ
, environdata
.var
);
797 fatalx("bad MSG_SHELL size");
799 server_client_msg_shell(c
);
802 fatalx("unexpected message");
809 /* Callback to send error message to client. */
811 server_client_msg_error(struct cmd_ctx
*ctx
, const char *fmt
, ...)
816 evbuffer_add_vprintf(ctx
->cmdclient
->stderr_event
->output
, fmt
, ap
);
819 bufferevent_write(ctx
->cmdclient
->stderr_event
, "\n", 1);
820 ctx
->cmdclient
->retcode
= 1;
823 /* Callback to send print message to client. */
825 server_client_msg_print(struct cmd_ctx
*ctx
, const char *fmt
, ...)
830 evbuffer_add_vprintf(ctx
->cmdclient
->stdout_event
->output
, fmt
, ap
);
833 bufferevent_write(ctx
->cmdclient
->stdout_event
, "\n", 1);
836 /* Callback to send print message to client, if not quiet. */
838 server_client_msg_info(struct cmd_ctx
*ctx
, const char *fmt
, ...)
842 if (options_get_number(&global_options
, "quiet"))
846 evbuffer_add_vprintf(ctx
->cmdclient
->stdout_event
->output
, fmt
, ap
);
849 bufferevent_write(ctx
->cmdclient
->stdout_event
, "\n", 1);
852 /* Handle command message. */
854 server_client_msg_command(struct client
*c
, struct msg_command_data
*data
)
857 struct cmd_list
*cmdlist
= NULL
;
861 ctx
.error
= server_client_msg_error
;
862 ctx
.print
= server_client_msg_print
;
863 ctx
.info
= server_client_msg_info
;
866 ctx
.curclient
= NULL
;
871 data
->argv
[(sizeof data
->argv
) - 1] = '\0';
872 if (cmd_unpack_argv(data
->argv
, sizeof data
->argv
, argc
, &argv
) != 0) {
873 server_client_msg_error(&ctx
, "command too long");
879 argv
= xcalloc(1, sizeof *argv
);
880 *argv
= xstrdup("new-session");
883 if ((cmdlist
= cmd_list_parse(argc
, argv
, &cause
)) == NULL
) {
884 server_client_msg_error(&ctx
, "%s", cause
);
885 cmd_free_argv(argc
, argv
);
888 cmd_free_argv(argc
, argv
);
890 if (cmd_list_exec(cmdlist
, &ctx
) != 1)
891 c
->flags
|= CLIENT_EXIT
;
892 cmd_list_free(cmdlist
);
897 cmd_list_free(cmdlist
);
898 c
->flags
|= CLIENT_EXIT
;
901 /* Handle identify message. */
903 server_client_msg_identify(
904 struct client
*c
, struct msg_identify_data
*data
, int fd
)
909 data
->cwd
[(sizeof data
->cwd
) - 1] = '\0';
910 if (*data
->cwd
!= '\0')
911 c
->cwd
= xstrdup(data
->cwd
);
915 if ((tty_fd
= dup(fd
)) == -1)
917 data
->term
[(sizeof data
->term
) - 1] = '\0';
918 tty_init(&c
->tty
, tty_fd
, data
->term
);
919 if (data
->flags
& IDENTIFY_UTF8
)
920 c
->tty
.flags
|= TTY_UTF8
;
921 if (data
->flags
& IDENTIFY_256COLOURS
)
922 c
->tty
.term_flags
|= TERM_256COLOURS
;
923 else if (data
->flags
& IDENTIFY_88COLOURS
)
924 c
->tty
.term_flags
|= TERM_88COLOURS
;
925 c
->tty
.key_callback
= server_client_handle_key
;
930 c
->flags
|= CLIENT_TERMINAL
;
933 /* Handle shell message. */
935 server_client_msg_shell(struct client
*c
)
937 struct msg_shell_data data
;
940 shell
= options_get_string(&global_s_options
, "default-shell");
942 if (*shell
== '\0' || areshell(shell
))
943 shell
= _PATH_BSHELL
;
944 if (strlcpy(data
.shell
, shell
, sizeof data
.shell
) >= sizeof data
.shell
)
945 strlcpy(data
.shell
, _PATH_BSHELL
, sizeof data
.shell
);
947 server_write_client(c
, MSG_SHELL
, &data
, sizeof data
);
948 c
->flags
|= CLIENT_BAD
; /* it will die after exec */