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