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