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