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