1 /* $OpenBSD: server-client.c,v 1.78 2012/07/11 07:10:15 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> 5 * 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. 9 * 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. 17 */ 18 19 #include <sys/types.h> 20 21 #include <event.h> 22 #include <fcntl.h> 23 #include <string.h> 24 #include <time.h> 25 #include <paths.h> 26 #include <stdlib.h> 27 #include <unistd.h> 28 29 #include "tmux.h" 30 31 void server_client_check_mouse(struct client *, struct window_pane *, 32 struct mouse_event *); 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 39 int server_client_msg_dispatch(struct client *); 40 void server_client_msg_command(struct client *, struct msg_command_data *); 41 void server_client_msg_identify( 42 struct client *, struct msg_identify_data *, int); 43 void server_client_msg_shell(struct client *); 44 45 void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...); 46 void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...); 47 void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...); 48 49 /* Create a new client. */ 50 void 51 server_client_create(int fd) 52 { 53 struct client *c; 54 u_int i; 55 56 setblocking(fd, 0); 57 58 c = xcalloc(1, sizeof *c); 59 c->references = 0; 60 imsg_init(&c->ibuf, fd); 61 server_update_event(c); 62 63 if (gettimeofday(&c->creation_time, NULL) != 0) 64 fatal("gettimeofday failed"); 65 memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time); 66 67 c->stdin_data = evbuffer_new (); 68 c->stdout_data = evbuffer_new (); 69 c->stderr_data = evbuffer_new (); 70 71 c->tty.fd = -1; 72 c->title = NULL; 73 74 c->session = NULL; 75 c->last_session = NULL; 76 c->tty.sx = 80; 77 c->tty.sy = 24; 78 79 screen_init(&c->status, c->tty.sx, 1, 0); 80 RB_INIT(&c->status_new); 81 RB_INIT(&c->status_old); 82 83 c->message_string = NULL; 84 ARRAY_INIT(&c->message_log); 85 86 c->prompt_string = NULL; 87 c->prompt_buffer = NULL; 88 c->prompt_index = 0; 89 90 c->last_mouse.b = MOUSE_UP; 91 c->last_mouse.x = c->last_mouse.y = -1; 92 93 evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); 94 95 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 96 if (ARRAY_ITEM(&clients, i) == NULL) { 97 ARRAY_SET(&clients, i, c); 98 return; 99 } 100 } 101 ARRAY_ADD(&clients, c); 102 log_debug("new client %d", fd); 103 } 104 105 /* Open client terminal if needed. */ 106 int 107 server_client_open(struct client *c, struct session *s, char **cause) 108 { 109 struct options *oo = s != NULL ? &s->options : &global_s_options; 110 char *overrides; 111 112 if (c->flags & CLIENT_CONTROL) 113 return (0); 114 115 if (!(c->flags & CLIENT_TERMINAL)) { 116 *cause = xstrdup ("not a terminal"); 117 return (-1); 118 } 119 120 overrides = options_get_string(oo, "terminal-overrides"); 121 if (tty_open(&c->tty, overrides, cause) != 0) 122 return (-1); 123 124 return (0); 125 } 126 127 /* Lost a client. */ 128 void 129 server_client_lost(struct client *c) 130 { 131 struct message_entry *msg; 132 u_int i; 133 134 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 135 if (ARRAY_ITEM(&clients, i) == c) 136 ARRAY_SET(&clients, i, NULL); 137 } 138 log_debug("lost client %d", c->ibuf.fd); 139 140 /* 141 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called 142 * and tty_free might close an unrelated fd. 143 */ 144 if (c->flags & CLIENT_TERMINAL) 145 tty_free(&c->tty); 146 147 evbuffer_free (c->stdin_data); 148 evbuffer_free (c->stdout_data); 149 evbuffer_free (c->stderr_data); 150 151 status_free_jobs(&c->status_new); 152 status_free_jobs(&c->status_old); 153 screen_free(&c->status); 154 155 free(c->title); 156 157 evtimer_del(&c->repeat_timer); 158 159 if (event_initialized(&c->identify_timer)) 160 evtimer_del(&c->identify_timer); 161 162 free(c->message_string); 163 if (event_initialized (&c->message_timer)) 164 evtimer_del(&c->message_timer); 165 for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { 166 msg = &ARRAY_ITEM(&c->message_log, i); 167 free(msg->msg); 168 } 169 ARRAY_FREE(&c->message_log); 170 171 free(c->prompt_string); 172 free(c->prompt_buffer); 173 free(c->cwd); 174 175 environ_free(&c->environ); 176 177 close(c->ibuf.fd); 178 imsg_clear(&c->ibuf); 179 if (event_initialized(&c->event)) 180 event_del(&c->event); 181 182 for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { 183 if (ARRAY_ITEM(&dead_clients, i) == NULL) { 184 ARRAY_SET(&dead_clients, i, c); 185 break; 186 } 187 } 188 if (i == ARRAY_LENGTH(&dead_clients)) 189 ARRAY_ADD(&dead_clients, c); 190 c->flags |= CLIENT_DEAD; 191 192 server_add_accept(0); /* may be more file descriptors now */ 193 194 recalculate_sizes(); 195 server_check_unattached(); 196 server_update_socket(); 197 } 198 199 /* Process a single client event. */ 200 void 201 server_client_callback(int fd, short events, void *data) 202 { 203 struct client *c = data; 204 205 if (c->flags & CLIENT_DEAD) 206 return; 207 208 if (fd == c->ibuf.fd) { 209 if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) < 0) 210 goto client_lost; 211 212 if (c->flags & CLIENT_BAD) { 213 if (c->ibuf.w.queued == 0) 214 goto client_lost; 215 return; 216 } 217 218 if (events & EV_READ && server_client_msg_dispatch(c) != 0) 219 goto client_lost; 220 } 221 222 server_push_stdout(c); 223 server_push_stderr(c); 224 225 server_update_event(c); 226 return; 227 228 client_lost: 229 server_client_lost(c); 230 } 231 232 /* Handle client status timer. */ 233 void 234 server_client_status_timer(void) 235 { 236 struct client *c; 237 struct session *s; 238 struct timeval tv; 239 u_int i; 240 int interval; 241 time_t difference; 242 243 if (gettimeofday(&tv, NULL) != 0) 244 fatal("gettimeofday failed"); 245 246 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 247 c = ARRAY_ITEM(&clients, i); 248 if (c == NULL || c->session == NULL) 249 continue; 250 if (c->message_string != NULL || c->prompt_string != NULL) { 251 /* 252 * Don't need timed redraw for messages/prompts so bail 253 * now. The status timer isn't reset when they are 254 * redrawn anyway. 255 */ 256 continue; 257 } 258 s = c->session; 259 260 if (!options_get_number(&s->options, "status")) 261 continue; 262 interval = options_get_number(&s->options, "status-interval"); 263 264 difference = tv.tv_sec - c->status_timer.tv_sec; 265 if (difference >= interval) { 266 status_update_jobs(c); 267 c->flags |= CLIENT_STATUS; 268 } 269 } 270 } 271 272 /* Check for mouse keys. */ 273 void 274 server_client_check_mouse( 275 struct client *c, struct window_pane *wp, struct mouse_event *mouse) 276 { 277 struct session *s = c->session; 278 struct options *oo = &s->options; 279 int statusat; 280 281 statusat = status_at_line(c); 282 283 /* Is this a window selection click on the status line? */ 284 if (statusat != -1 && mouse->y == (u_int)statusat && 285 options_get_number(oo, "mouse-select-window")) { 286 if (mouse->b == MOUSE_UP && c->last_mouse.b != MOUSE_UP) { 287 status_set_window_at(c, mouse->x); 288 recalculate_sizes(); 289 return; 290 } 291 if (mouse->b & MOUSE_45) { 292 if ((mouse->b & MOUSE_BUTTON) == MOUSE_1) { 293 session_previous(c->session, 0); 294 server_redraw_session(s); 295 recalculate_sizes(); 296 } 297 if ((mouse->b & MOUSE_BUTTON) == MOUSE_2) { 298 session_next(c->session, 0); 299 server_redraw_session(s); 300 recalculate_sizes(); 301 } 302 return; 303 } 304 memcpy(&c->last_mouse, mouse, sizeof c->last_mouse); 305 return; 306 } 307 308 /* 309 * Not on status line - adjust mouse position if status line is at the 310 * top and limit if at the bottom. From here on a struct mouse 311 * represents the offset onto the window itself. 312 */ 313 if (statusat == 0 &&mouse->y > 0) 314 mouse->y--; 315 else if (statusat > 0 && mouse->y >= (u_int)statusat) 316 mouse->y = statusat - 1; 317 318 /* Is this a pane selection? Allow down only in copy mode. */ 319 if (options_get_number(oo, "mouse-select-pane") && 320 ((!(mouse->b & MOUSE_DRAG) && mouse->b != MOUSE_UP) || 321 wp->mode != &window_copy_mode)) { 322 window_set_active_at(wp->window, mouse->x, mouse->y); 323 server_redraw_window_borders(wp->window); 324 wp = wp->window->active; /* may have changed */ 325 } 326 327 /* Check if trying to resize pane. */ 328 if (options_get_number(oo, "mouse-resize-pane")) 329 layout_resize_pane_mouse(c, mouse); 330 331 /* Update last and pass through to client. */ 332 memcpy(&c->last_mouse, mouse, sizeof c->last_mouse); 333 window_pane_mouse(wp, c->session, mouse); 334 } 335 336 /* Handle data key input from client. */ 337 void 338 server_client_handle_key(struct client *c, int key) 339 { 340 struct session *s; 341 struct window *w; 342 struct window_pane *wp; 343 struct timeval tv; 344 struct key_binding *bd; 345 int xtimeout, isprefix; 346 347 /* Check the client is good to accept input. */ 348 if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) 349 return; 350 if (c->session == NULL) 351 return; 352 s = c->session; 353 354 /* Update the activity timer. */ 355 if (gettimeofday(&c->activity_time, NULL) != 0) 356 fatal("gettimeofday failed"); 357 memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time); 358 359 w = c->session->curw->window; 360 wp = w->active; 361 362 /* Special case: number keys jump to pane in identify mode. */ 363 if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { 364 if (c->flags & CLIENT_READONLY) 365 return; 366 wp = window_pane_at_index(w, key - '0'); 367 if (wp != NULL && window_pane_visible(wp)) 368 window_set_active_pane(w, wp); 369 server_clear_identify(c); 370 return; 371 } 372 373 /* Handle status line. */ 374 if (!(c->flags & CLIENT_READONLY)) { 375 status_message_clear(c); 376 server_clear_identify(c); 377 } 378 if (c->prompt_string != NULL) { 379 if (!(c->flags & CLIENT_READONLY)) 380 status_prompt_key(c, key); 381 return; 382 } 383 384 /* Check for mouse keys. */ 385 if (key == KEYC_MOUSE) { 386 if (c->flags & CLIENT_READONLY) 387 return; 388 server_client_check_mouse(c, wp, &c->tty.mouse); 389 return; 390 } 391 392 /* Is this a prefix key? */ 393 if (key == options_get_number(&c->session->options, "prefix")) 394 isprefix = 1; 395 else if (key == options_get_number(&c->session->options, "prefix2")) 396 isprefix = 1; 397 else 398 isprefix = 0; 399 400 /* No previous prefix key. */ 401 if (!(c->flags & CLIENT_PREFIX)) { 402 if (isprefix) 403 c->flags |= CLIENT_PREFIX; 404 else { 405 /* Try as a non-prefix key binding. */ 406 if ((bd = key_bindings_lookup(key)) == NULL) { 407 if (!(c->flags & CLIENT_READONLY)) 408 window_pane_key(wp, c->session, key); 409 } else 410 key_bindings_dispatch(bd, c); 411 } 412 return; 413 } 414 415 /* Prefix key already pressed. Reset prefix and lookup key. */ 416 c->flags &= ~CLIENT_PREFIX; 417 if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { 418 /* If repeating, treat this as a key, else ignore. */ 419 if (c->flags & CLIENT_REPEAT) { 420 c->flags &= ~CLIENT_REPEAT; 421 if (isprefix) 422 c->flags |= CLIENT_PREFIX; 423 else if (!(c->flags & CLIENT_READONLY)) 424 window_pane_key(wp, c->session, key); 425 } 426 return; 427 } 428 429 /* If already repeating, but this key can't repeat, skip it. */ 430 if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { 431 c->flags &= ~CLIENT_REPEAT; 432 if (isprefix) 433 c->flags |= CLIENT_PREFIX; 434 else if (!(c->flags & CLIENT_READONLY)) 435 window_pane_key(wp, c->session, key); 436 return; 437 } 438 439 /* If this key can repeat, reset the repeat flags and timer. */ 440 xtimeout = options_get_number(&c->session->options, "repeat-time"); 441 if (xtimeout != 0 && bd->can_repeat) { 442 c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; 443 444 tv.tv_sec = xtimeout / 1000; 445 tv.tv_usec = (xtimeout % 1000) * 1000L; 446 evtimer_del(&c->repeat_timer); 447 evtimer_add(&c->repeat_timer, &tv); 448 } 449 450 /* Dispatch the command. */ 451 key_bindings_dispatch(bd, c); 452 } 453 454 /* Client functions that need to happen every loop. */ 455 void 456 server_client_loop(void) 457 { 458 struct client *c; 459 struct window *w; 460 struct window_pane *wp; 461 u_int i; 462 463 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 464 c = ARRAY_ITEM(&clients, i); 465 if (c == NULL) 466 continue; 467 468 server_client_check_exit(c); 469 if (c->session != NULL) { 470 server_client_check_redraw(c); 471 server_client_reset_state(c); 472 } 473 } 474 475 /* 476 * Any windows will have been redrawn as part of clients, so clear 477 * their flags now. 478 */ 479 for (i = 0; i < ARRAY_LENGTH(&windows); i++) { 480 w = ARRAY_ITEM(&windows, i); 481 if (w == NULL) 482 continue; 483 484 w->flags &= ~WINDOW_REDRAW; 485 TAILQ_FOREACH(wp, &w->panes, entry) 486 wp->flags &= ~PANE_REDRAW; 487 } 488 } 489 490 /* 491 * Update cursor position and mode settings. The scroll region and attributes 492 * are cleared when idle (waiting for an event) as this is the most likely time 493 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a 494 * compromise between excessive resets and likelihood of an interrupt. 495 * 496 * tty_region/tty_reset/tty_update_mode already take care of not resetting 497 * things that are already in their default state. 498 */ 499 void 500 server_client_reset_state(struct client *c) 501 { 502 struct window *w = c->session->curw->window; 503 struct window_pane *wp = w->active; 504 struct screen *s = wp->screen; 505 struct options *oo = &c->session->options; 506 struct options *wo = &w->options; 507 int status, mode, o; 508 509 if (c->flags & CLIENT_SUSPENDED) 510 return; 511 512 tty_region(&c->tty, 0, c->tty.sy - 1); 513 514 status = options_get_number(oo, "status"); 515 if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) 516 tty_cursor(&c->tty, 0, 0); 517 else { 518 o = status && options_get_number (oo, "status-position") == 0; 519 tty_cursor(&c->tty, wp->xoff + s->cx, o + wp->yoff + s->cy); 520 } 521 522 /* 523 * Resizing panes with the mouse requires at least button mode to give 524 * a smooth appearance. 525 */ 526 mode = s->mode; 527 if ((c->last_mouse.b & MOUSE_RESIZE_PANE) && 528 !(mode & (MODE_MOUSE_BUTTON|MODE_MOUSE_ANY))) 529 mode |= MODE_MOUSE_BUTTON; 530 531 /* 532 * Any mode will do for mouse-select-pane, but set standard mode if 533 * none. 534 */ 535 if ((mode & ALL_MOUSE_MODES) == 0) { 536 if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && 537 options_get_number(oo, "mouse-select-pane")) 538 mode |= MODE_MOUSE_STANDARD; 539 else if (options_get_number(oo, "mouse-resize-pane")) 540 mode |= MODE_MOUSE_STANDARD; 541 else if (options_get_number(oo, "mouse-select-window")) 542 mode |= MODE_MOUSE_STANDARD; 543 else if (options_get_number(wo, "mode-mouse")) 544 mode |= MODE_MOUSE_STANDARD; 545 } 546 547 /* 548 * Set UTF-8 mouse input if required. If the terminal is UTF-8, the 549 * user has set mouse-utf8 and any mouse mode is in effect, turn on 550 * UTF-8 mouse input. If the receiving terminal hasn't requested it 551 * (that is, it isn't in s->mode), then it'll be converted in 552 * input_mouse. 553 */ 554 if ((c->tty.flags & TTY_UTF8) && 555 (mode & ALL_MOUSE_MODES) && options_get_number(oo, "mouse-utf8")) 556 mode |= MODE_MOUSE_UTF8; 557 else 558 mode &= ~MODE_MOUSE_UTF8; 559 560 /* Set the terminal mode and reset attributes. */ 561 tty_update_mode(&c->tty, mode, s); 562 tty_reset(&c->tty); 563 } 564 565 /* Repeat time callback. */ 566 /* ARGSUSED */ 567 void 568 server_client_repeat_timer(unused int fd, unused short events, void *data) 569 { 570 struct client *c = data; 571 572 if (c->flags & CLIENT_REPEAT) 573 c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); 574 } 575 576 /* Check if client should be exited. */ 577 void 578 server_client_check_exit(struct client *c) 579 { 580 struct msg_exit_data exitdata; 581 582 if (!(c->flags & CLIENT_EXIT)) 583 return; 584 585 if (EVBUFFER_LENGTH(c->stdin_data) != 0) 586 return; 587 if (EVBUFFER_LENGTH(c->stdout_data) != 0) 588 return; 589 if (EVBUFFER_LENGTH(c->stderr_data) != 0) 590 return; 591 592 exitdata.retcode = c->retcode; 593 server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata); 594 595 c->flags &= ~CLIENT_EXIT; 596 } 597 598 /* Check for client redraws. */ 599 void 600 server_client_check_redraw(struct client *c) 601 { 602 struct session *s = c->session; 603 struct window_pane *wp; 604 int flags, redraw; 605 606 flags = c->tty.flags & TTY_FREEZE; 607 c->tty.flags &= ~TTY_FREEZE; 608 609 if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { 610 if (options_get_number(&s->options, "set-titles")) 611 server_client_set_title(c); 612 613 if (c->message_string != NULL) 614 redraw = status_message_redraw(c); 615 else if (c->prompt_string != NULL) 616 redraw = status_prompt_redraw(c); 617 else 618 redraw = status_redraw(c); 619 if (!redraw) 620 c->flags &= ~CLIENT_STATUS; 621 } 622 623 if (c->flags & CLIENT_REDRAW) { 624 screen_redraw_screen(c, 0, 0); 625 c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS); 626 } else if (c->flags & CLIENT_REDRAWWINDOW) { 627 TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) 628 screen_redraw_pane(c, wp); 629 c->flags &= ~CLIENT_REDRAWWINDOW; 630 } else { 631 TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { 632 if (wp->flags & PANE_REDRAW) 633 screen_redraw_pane(c, wp); 634 } 635 } 636 637 if (c->flags & CLIENT_BORDERS) 638 screen_redraw_screen(c, 0, 1); 639 640 if (c->flags & CLIENT_STATUS) 641 screen_redraw_screen(c, 1, 0); 642 643 c->tty.flags |= flags; 644 645 c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS|CLIENT_BORDERS); 646 } 647 648 /* Set client title. */ 649 void 650 server_client_set_title(struct client *c) 651 { 652 struct session *s = c->session; 653 const char *template; 654 char *title; 655 656 template = options_get_string(&s->options, "set-titles-string"); 657 658 title = status_replace(c, NULL, NULL, NULL, template, time(NULL), 1); 659 if (c->title == NULL || strcmp(title, c->title) != 0) { 660 free(c->title); 661 c->title = xstrdup(title); 662 tty_set_title(&c->tty, c->title); 663 } 664 free(title); 665 } 666 667 /* Dispatch message from client. */ 668 int 669 server_client_msg_dispatch(struct client *c) 670 { 671 struct imsg imsg; 672 struct msg_command_data commanddata; 673 struct msg_identify_data identifydata; 674 struct msg_environ_data environdata; 675 struct msg_stdin_data stdindata; 676 ssize_t n, datalen; 677 678 if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) 679 return (-1); 680 681 for (;;) { 682 if ((n = imsg_get(&c->ibuf, &imsg)) == -1) 683 return (-1); 684 if (n == 0) 685 return (0); 686 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 687 688 if (imsg.hdr.peerid != PROTOCOL_VERSION) { 689 server_write_client(c, MSG_VERSION, NULL, 0); 690 c->flags |= CLIENT_BAD; 691 imsg_free(&imsg); 692 continue; 693 } 694 695 log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd); 696 switch (imsg.hdr.type) { 697 case MSG_COMMAND: 698 if (datalen != sizeof commanddata) 699 fatalx("bad MSG_COMMAND size"); 700 memcpy(&commanddata, imsg.data, sizeof commanddata); 701 702 server_client_msg_command(c, &commanddata); 703 break; 704 case MSG_IDENTIFY: 705 if (datalen != sizeof identifydata) 706 fatalx("bad MSG_IDENTIFY size"); 707 if (imsg.fd == -1) 708 fatalx("MSG_IDENTIFY missing fd"); 709 memcpy(&identifydata, imsg.data, sizeof identifydata); 710 711 server_client_msg_identify(c, &identifydata, imsg.fd); 712 break; 713 case MSG_STDIN: 714 if (datalen != sizeof stdindata) 715 fatalx("bad MSG_STDIN size"); 716 memcpy(&stdindata, imsg.data, sizeof stdindata); 717 718 if (c->stdin_callback == NULL) 719 break; 720 if (stdindata.size <= 0) 721 c->stdin_closed = 1; 722 else { 723 evbuffer_add(c->stdin_data, stdindata.data, 724 stdindata.size); 725 } 726 c->stdin_callback(c, c->stdin_closed, 727 c->stdin_callback_data); 728 break; 729 case MSG_RESIZE: 730 if (datalen != 0) 731 fatalx("bad MSG_RESIZE size"); 732 733 if (tty_resize(&c->tty)) { 734 recalculate_sizes(); 735 server_redraw_client(c); 736 } 737 break; 738 case MSG_EXITING: 739 if (datalen != 0) 740 fatalx("bad MSG_EXITING size"); 741 742 c->session = NULL; 743 tty_close(&c->tty); 744 server_write_client(c, MSG_EXITED, NULL, 0); 745 break; 746 case MSG_WAKEUP: 747 case MSG_UNLOCK: 748 if (datalen != 0) 749 fatalx("bad MSG_WAKEUP size"); 750 751 if (!(c->flags & CLIENT_SUSPENDED)) 752 break; 753 c->flags &= ~CLIENT_SUSPENDED; 754 755 if (gettimeofday(&c->activity_time, NULL) != 0) 756 fatal("gettimeofday"); 757 if (c->session != NULL) 758 session_update_activity(c->session); 759 760 tty_start_tty(&c->tty); 761 server_redraw_client(c); 762 recalculate_sizes(); 763 break; 764 case MSG_ENVIRON: 765 if (datalen != sizeof environdata) 766 fatalx("bad MSG_ENVIRON size"); 767 memcpy(&environdata, imsg.data, sizeof environdata); 768 769 environdata.var[(sizeof environdata.var) - 1] = '\0'; 770 if (strchr(environdata.var, '=') != NULL) 771 environ_put(&c->environ, environdata.var); 772 break; 773 case MSG_SHELL: 774 if (datalen != 0) 775 fatalx("bad MSG_SHELL size"); 776 777 server_client_msg_shell(c); 778 break; 779 default: 780 fatalx("unexpected message"); 781 } 782 783 imsg_free(&imsg); 784 } 785 } 786 787 /* Callback to send error message to client. */ 788 void printflike2 789 server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...) 790 { 791 va_list ap; 792 793 va_start(ap, fmt); 794 evbuffer_add_vprintf(ctx->cmdclient->stderr_data, fmt, ap); 795 va_end(ap); 796 797 evbuffer_add(ctx->cmdclient->stderr_data, "\n", 1); 798 server_push_stderr(ctx->cmdclient); 799 ctx->cmdclient->retcode = 1; 800 } 801 802 /* Callback to send print message to client. */ 803 void printflike2 804 server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...) 805 { 806 va_list ap; 807 808 va_start(ap, fmt); 809 evbuffer_add_vprintf(ctx->cmdclient->stdout_data, fmt, ap); 810 va_end(ap); 811 812 evbuffer_add(ctx->cmdclient->stdout_data, "\n", 1); 813 server_push_stdout(ctx->cmdclient); 814 } 815 816 /* Callback to send print message to client, if not quiet. */ 817 void printflike2 818 server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...) 819 { 820 va_list ap; 821 822 if (options_get_number(&global_options, "quiet")) 823 return; 824 825 va_start(ap, fmt); 826 evbuffer_add_vprintf(ctx->cmdclient->stdout_data, fmt, ap); 827 va_end(ap); 828 829 evbuffer_add(ctx->cmdclient->stdout_data, "\n", 1); 830 server_push_stdout(ctx->cmdclient); 831 } 832 833 /* Handle command message. */ 834 void 835 server_client_msg_command(struct client *c, struct msg_command_data *data) 836 { 837 struct cmd_ctx ctx; 838 struct cmd_list *cmdlist = NULL; 839 int argc; 840 char **argv, *cause; 841 842 ctx.error = server_client_msg_error; 843 ctx.print = server_client_msg_print; 844 ctx.info = server_client_msg_info; 845 846 ctx.msgdata = data; 847 ctx.curclient = NULL; 848 849 ctx.cmdclient = c; 850 851 argc = data->argc; 852 data->argv[(sizeof data->argv) - 1] = '\0'; 853 if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) { 854 server_client_msg_error(&ctx, "command too long"); 855 goto error; 856 } 857 858 if (argc == 0) { 859 argc = 1; 860 argv = xcalloc(1, sizeof *argv); 861 *argv = xstrdup("new-session"); 862 } 863 864 if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { 865 server_client_msg_error(&ctx, "%s", cause); 866 cmd_free_argv(argc, argv); 867 goto error; 868 } 869 cmd_free_argv(argc, argv); 870 871 switch (cmd_list_exec(cmdlist, &ctx)) 872 { 873 case CMD_RETURN_ERROR: 874 case CMD_RETURN_NORMAL: 875 c->flags |= CLIENT_EXIT; 876 break; 877 case CMD_RETURN_ATTACH: 878 case CMD_RETURN_YIELD: 879 break; 880 } 881 cmd_list_free(cmdlist); 882 return; 883 884 error: 885 if (cmdlist != NULL) 886 cmd_list_free(cmdlist); 887 c->flags |= CLIENT_EXIT; 888 } 889 890 /* Handle identify message. */ 891 void 892 server_client_msg_identify( 893 struct client *c, struct msg_identify_data *data, int fd) 894 { 895 c->cwd = NULL; 896 data->cwd[(sizeof data->cwd) - 1] = '\0'; 897 if (*data->cwd != '\0') 898 c->cwd = xstrdup(data->cwd); 899 900 if (data->flags & IDENTIFY_CONTROL) { 901 c->stdin_callback = control_callback; 902 c->flags |= (CLIENT_CONTROL|CLIENT_SUSPENDED); 903 904 c->tty.fd = -1; 905 c->tty.log_fd = -1; 906 907 close(fd); 908 return; 909 } 910 911 if (!isatty(fd)) 912 return; 913 data->term[(sizeof data->term) - 1] = '\0'; 914 tty_init(&c->tty, c, fd, data->term); 915 if (data->flags & IDENTIFY_UTF8) 916 c->tty.flags |= TTY_UTF8; 917 if (data->flags & IDENTIFY_256COLOURS) 918 c->tty.term_flags |= TERM_256COLOURS; 919 else if (data->flags & IDENTIFY_88COLOURS) 920 c->tty.term_flags |= TERM_88COLOURS; 921 922 tty_resize(&c->tty); 923 924 c->flags |= CLIENT_TERMINAL; 925 } 926 927 /* Handle shell message. */ 928 void 929 server_client_msg_shell(struct client *c) 930 { 931 struct msg_shell_data data; 932 const char *shell; 933 934 shell = options_get_string(&global_s_options, "default-shell"); 935 936 if (*shell == '\0' || areshell(shell)) 937 shell = _PATH_BSHELL; 938 if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell) 939 strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell); 940 941 server_write_client(c, MSG_SHELL, &data, sizeof data); 942 c->flags |= CLIENT_BAD; /* it will die after exec */ 943 } 944