1 /* $OpenBSD$ */ 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_key_table(struct client *, const char *); 33 void server_client_free(int, short, void *); 34 void server_client_check_focus(struct window_pane *); 35 void server_client_check_resize(struct window_pane *); 36 int server_client_check_mouse(struct client *); 37 void server_client_repeat_timer(int, short, void *); 38 void server_client_check_exit(struct client *); 39 void server_client_check_redraw(struct client *); 40 void server_client_set_title(struct client *); 41 void server_client_reset_state(struct client *); 42 int server_client_assume_paste(struct session *); 43 44 int server_client_msg_dispatch(struct client *); 45 void server_client_msg_command(struct client *, struct imsg *); 46 void server_client_msg_identify(struct client *, struct imsg *); 47 void server_client_msg_shell(struct client *); 48 49 /* Check if this client is inside this server. */ 50 int 51 server_client_check_nested(struct client *c) 52 { 53 struct environ_entry *envent; 54 struct window_pane *wp; 55 56 if (c->tty.path == NULL) 57 return (0); 58 59 envent = environ_find(&c->environ, "TMUX"); 60 if (envent == NULL || *envent->value == '\0') 61 return (0); 62 63 RB_FOREACH(wp, window_pane_tree, &all_window_panes) { 64 if (strcmp(wp->tty, c->tty.path) == 0) 65 return (1); 66 } 67 return (0); 68 } 69 70 /* Set client key table. */ 71 void 72 server_client_key_table(struct client *c, const char *name) 73 { 74 key_bindings_unref_table(c->keytable); 75 c->keytable = key_bindings_get_table(name, 1); 76 c->keytable->references++; 77 } 78 79 /* Create a new client. */ 80 void 81 server_client_create(int fd) 82 { 83 struct client *c; 84 85 setblocking(fd, 0); 86 87 c = xcalloc(1, sizeof *c); 88 c->references = 1; 89 imsg_init(&c->ibuf, fd); 90 server_update_event(c); 91 92 if (gettimeofday(&c->creation_time, NULL) != 0) 93 fatal("gettimeofday failed"); 94 memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time); 95 96 environ_init(&c->environ); 97 98 c->fd = -1; 99 c->cwd = -1; 100 101 c->cmdq = cmdq_new(c); 102 c->cmdq->client_exit = 1; 103 104 c->stdin_data = evbuffer_new(); 105 c->stdout_data = evbuffer_new(); 106 c->stderr_data = evbuffer_new(); 107 108 c->tty.fd = -1; 109 c->title = NULL; 110 111 c->session = NULL; 112 c->last_session = NULL; 113 c->tty.sx = 80; 114 c->tty.sy = 24; 115 116 screen_init(&c->status, c->tty.sx, 1, 0); 117 118 c->message_string = NULL; 119 TAILQ_INIT(&c->message_log); 120 121 c->prompt_string = NULL; 122 c->prompt_buffer = NULL; 123 c->prompt_index = 0; 124 125 c->flags |= CLIENT_FOCUSED; 126 127 c->keytable = key_bindings_get_table("root", 1); 128 c->keytable->references++; 129 130 evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); 131 132 TAILQ_INSERT_TAIL(&clients, c, entry); 133 log_debug("new client %d", fd); 134 } 135 136 /* Open client terminal if needed. */ 137 int 138 server_client_open(struct client *c, char **cause) 139 { 140 if (c->flags & CLIENT_CONTROL) 141 return (0); 142 143 if (strcmp(c->ttyname, "/dev/tty") == 0) { 144 *cause = xstrdup("can't use /dev/tty"); 145 return (-1); 146 } 147 148 if (!(c->flags & CLIENT_TERMINAL)) { 149 *cause = xstrdup("not a terminal"); 150 return (-1); 151 } 152 153 if (tty_open(&c->tty, cause) != 0) 154 return (-1); 155 156 return (0); 157 } 158 159 /* Lost a client. */ 160 void 161 server_client_lost(struct client *c) 162 { 163 struct message_entry *msg, *msg1; 164 165 c->flags |= CLIENT_DEAD; 166 167 status_prompt_clear(c); 168 status_message_clear(c); 169 170 if (c->stdin_callback != NULL) 171 c->stdin_callback(c, 1, c->stdin_callback_data); 172 173 TAILQ_REMOVE(&clients, c, entry); 174 log_debug("lost client %d", c->ibuf.fd); 175 176 /* 177 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called 178 * and tty_free might close an unrelated fd. 179 */ 180 if (c->flags & CLIENT_TERMINAL) 181 tty_free(&c->tty); 182 free(c->ttyname); 183 free(c->term); 184 185 evbuffer_free(c->stdin_data); 186 evbuffer_free(c->stdout_data); 187 if (c->stderr_data != c->stdout_data) 188 evbuffer_free(c->stderr_data); 189 190 if (event_initialized(&c->status_timer)) 191 evtimer_del(&c->status_timer); 192 screen_free(&c->status); 193 194 free(c->title); 195 close(c->cwd); 196 197 evtimer_del(&c->repeat_timer); 198 199 key_bindings_unref_table(c->keytable); 200 201 if (event_initialized(&c->identify_timer)) 202 evtimer_del(&c->identify_timer); 203 204 free(c->message_string); 205 if (event_initialized(&c->message_timer)) 206 evtimer_del(&c->message_timer); 207 TAILQ_FOREACH_SAFE(msg, &c->message_log, entry, msg1) { 208 free(msg->msg); 209 TAILQ_REMOVE(&c->message_log, msg, entry); 210 free(msg); 211 } 212 213 free(c->prompt_string); 214 free(c->prompt_buffer); 215 216 c->cmdq->flags |= CMD_Q_DEAD; 217 cmdq_free(c->cmdq); 218 c->cmdq = NULL; 219 220 environ_free(&c->environ); 221 222 close(c->ibuf.fd); 223 imsg_clear(&c->ibuf); 224 if (event_initialized(&c->event)) 225 event_del(&c->event); 226 227 server_client_unref(c); 228 229 server_add_accept(0); /* may be more file descriptors now */ 230 231 recalculate_sizes(); 232 server_check_unattached(); 233 server_update_socket(); 234 } 235 236 /* Remove reference from a client. */ 237 void 238 server_client_unref(struct client *c) 239 { 240 log_debug("unref client %d (%d references)", c->ibuf.fd, c->references); 241 242 c->references--; 243 if (c->references == 0) 244 event_once(-1, EV_TIMEOUT, server_client_free, c, NULL); 245 } 246 247 /* Free dead client. */ 248 void 249 server_client_free(unused int fd, unused short events, void *arg) 250 { 251 struct client *c = arg; 252 253 log_debug("free client %d (%d references)", c->ibuf.fd, c->references); 254 255 if (c->references == 0) 256 free(c); 257 } 258 259 /* Process a single client event. */ 260 void 261 server_client_callback(int fd, short events, void *data) 262 { 263 struct client *c = data; 264 265 if (c->flags & CLIENT_DEAD) 266 return; 267 268 if (fd == c->ibuf.fd) { 269 if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) <= 0 && 270 errno != EAGAIN) 271 goto client_lost; 272 273 if (c->flags & CLIENT_BAD) { 274 if (c->ibuf.w.queued == 0) 275 goto client_lost; 276 return; 277 } 278 279 if (events & EV_READ && server_client_msg_dispatch(c) != 0) 280 goto client_lost; 281 } 282 283 server_push_stdout(c); 284 server_push_stderr(c); 285 286 server_update_event(c); 287 return; 288 289 client_lost: 290 server_client_lost(c); 291 } 292 293 /* Check for mouse keys. */ 294 int 295 server_client_check_mouse(struct client *c) 296 { 297 struct session *s = c->session; 298 struct mouse_event *m = &c->tty.mouse; 299 struct window *w; 300 struct window_pane *wp; 301 enum { NOTYPE, DOWN, UP, DRAG, WHEEL } type = NOTYPE; 302 enum { NOWHERE, PANE, STATUS, BORDER } where = NOWHERE; 303 u_int x, y, b; 304 int key; 305 306 log_debug("mouse %02x at %u,%u (last %u,%u) (%d)", m->b, m->x, m->y, 307 m->lx, m->ly, c->tty.mouse_drag_flag); 308 309 /* What type of event is this? */ 310 if (MOUSE_DRAG(m->b)) { 311 type = DRAG; 312 if (c->tty.mouse_drag_flag) { 313 x = m->x, y = m->y, b = m->b; 314 log_debug("drag update at %u,%u", x, y); 315 } else { 316 x = m->lx, y = m->ly, b = m->lb; 317 log_debug("drag start at %u,%u", x, y); 318 } 319 } else if (MOUSE_WHEEL(m->b)) { 320 type = WHEEL; 321 x = m->x, y = m->y, b = m->b; 322 log_debug("wheel at %u,%u", x, y); 323 } else if (MOUSE_BUTTONS(m->b) == 3) { 324 type = UP; 325 x = m->x, y = m->y, b = m->lb; 326 log_debug("up at %u,%u", x, y); 327 } else { 328 type = DOWN; 329 x = m->x, y = m->y, b = m->b; 330 log_debug("down at %u,%u", x, y); 331 } 332 if (type == NOTYPE) 333 return (KEYC_NONE); 334 335 /* Always save the session. */ 336 m->s = s->id; 337 338 /* Is this on the status line? */ 339 m->statusat = status_at_line(c); 340 if (m->statusat != -1 && y == (u_int)m->statusat) { 341 w = status_get_window_at(c, x); 342 if (w == NULL) 343 return (KEYC_NONE); 344 m->w = w->id; 345 where = STATUS; 346 } else 347 m->w = -1; 348 349 /* Not on status line. Adjust position and check for border or pane. */ 350 if (where == NOWHERE) { 351 if (m->statusat == 0 && y > 0) 352 y--; 353 else if (m->statusat > 0 && y >= (u_int)m->statusat) 354 y = m->statusat - 1; 355 356 TAILQ_FOREACH(wp, &s->curw->window->panes, entry) { 357 if ((wp->xoff + wp->sx == x && 358 wp->yoff <= 1 + y && 359 wp->yoff + wp->sy >= y) || 360 (wp->yoff + wp->sy == y && 361 wp->xoff <= 1 + x && 362 wp->xoff + wp->sx >= x)) 363 break; 364 } 365 if (wp != NULL) 366 where = BORDER; 367 else { 368 wp = window_get_active_at(s->curw->window, x, y); 369 if (wp != NULL) 370 where = PANE; 371 } 372 if (where == NOWHERE) 373 return (KEYC_NONE); 374 m->wp = wp->id; 375 m->w = wp->window->id; 376 } else 377 m->wp = -1; 378 379 /* Stop dragging if needed. */ 380 if (type != DRAG && c->tty.mouse_drag_flag) { 381 if (c->tty.mouse_drag_release != NULL) 382 c->tty.mouse_drag_release(c, m); 383 384 c->tty.mouse_drag_update = NULL; 385 c->tty.mouse_drag_release = NULL; 386 387 c->tty.mouse_drag_flag = 0; 388 return (KEYC_MOUSE); /* not a key, but still may want to pass */ 389 } 390 391 /* Convert to a key binding. */ 392 key = KEYC_NONE; 393 switch (type) { 394 case NOTYPE: 395 break; 396 case DRAG: 397 if (c->tty.mouse_drag_update != NULL) 398 c->tty.mouse_drag_update(c, m); 399 else { 400 switch (MOUSE_BUTTONS(b)) { 401 case 0: 402 if (where == PANE) 403 key = KEYC_MOUSEDRAG1_PANE; 404 if (where == STATUS) 405 key = KEYC_MOUSEDRAG1_STATUS; 406 if (where == BORDER) 407 key = KEYC_MOUSEDRAG1_BORDER; 408 break; 409 case 1: 410 if (where == PANE) 411 key = KEYC_MOUSEDRAG2_PANE; 412 if (where == STATUS) 413 key = KEYC_MOUSEDRAG2_STATUS; 414 if (where == BORDER) 415 key = KEYC_MOUSEDRAG2_BORDER; 416 break; 417 case 2: 418 if (where == PANE) 419 key = KEYC_MOUSEDRAG3_PANE; 420 if (where == STATUS) 421 key = KEYC_MOUSEDRAG3_STATUS; 422 if (where == BORDER) 423 key = KEYC_MOUSEDRAG3_BORDER; 424 break; 425 } 426 } 427 428 c->tty.mouse_drag_flag = 1; 429 break; 430 case WHEEL: 431 if (MOUSE_BUTTONS(b) == MOUSE_WHEEL_UP) { 432 if (where == PANE) 433 key = KEYC_WHEELUP_PANE; 434 if (where == STATUS) 435 key = KEYC_WHEELUP_STATUS; 436 if (where == BORDER) 437 key = KEYC_WHEELUP_BORDER; 438 } else { 439 if (where == PANE) 440 key = KEYC_WHEELDOWN_PANE; 441 if (where == STATUS) 442 key = KEYC_WHEELDOWN_STATUS; 443 if (where == BORDER) 444 key = KEYC_WHEELDOWN_BORDER; 445 } 446 break; 447 case UP: 448 switch (MOUSE_BUTTONS(b)) { 449 case 0: 450 if (where == PANE) 451 key = KEYC_MOUSEUP1_PANE; 452 if (where == STATUS) 453 key = KEYC_MOUSEUP1_STATUS; 454 if (where == BORDER) 455 key = KEYC_MOUSEUP1_BORDER; 456 break; 457 case 1: 458 if (where == PANE) 459 key = KEYC_MOUSEUP2_PANE; 460 if (where == STATUS) 461 key = KEYC_MOUSEUP2_STATUS; 462 if (where == BORDER) 463 key = KEYC_MOUSEUP2_BORDER; 464 break; 465 case 2: 466 if (where == PANE) 467 key = KEYC_MOUSEUP3_PANE; 468 if (where == STATUS) 469 key = KEYC_MOUSEUP3_STATUS; 470 if (where == BORDER) 471 key = KEYC_MOUSEUP3_BORDER; 472 break; 473 } 474 break; 475 case DOWN: 476 switch (MOUSE_BUTTONS(b)) { 477 case 0: 478 if (where == PANE) 479 key = KEYC_MOUSEDOWN1_PANE; 480 if (where == STATUS) 481 key = KEYC_MOUSEDOWN1_STATUS; 482 if (where == BORDER) 483 key = KEYC_MOUSEDOWN1_BORDER; 484 break; 485 case 1: 486 if (where == PANE) 487 key = KEYC_MOUSEDOWN2_PANE; 488 if (where == STATUS) 489 key = KEYC_MOUSEDOWN2_STATUS; 490 if (where == BORDER) 491 key = KEYC_MOUSEDOWN2_BORDER; 492 break; 493 case 2: 494 if (where == PANE) 495 key = KEYC_MOUSEDOWN3_PANE; 496 if (where == STATUS) 497 key = KEYC_MOUSEDOWN3_STATUS; 498 if (where == BORDER) 499 key = KEYC_MOUSEDOWN3_BORDER; 500 break; 501 } 502 break; 503 } 504 if (key == KEYC_NONE) 505 return (KEYC_NONE); 506 507 /* Apply modifiers if any. */ 508 if (b & MOUSE_MASK_META) 509 key |= KEYC_ESCAPE; 510 if (b & MOUSE_MASK_CTRL) 511 key |= KEYC_CTRL; 512 if (b & MOUSE_MASK_SHIFT) 513 key |= KEYC_SHIFT; 514 515 return (key); 516 } 517 518 /* Is this fast enough to probably be a paste? */ 519 int 520 server_client_assume_paste(struct session *s) 521 { 522 struct timeval tv; 523 int t; 524 525 if ((t = options_get_number(&s->options, "assume-paste-time")) == 0) 526 return (0); 527 528 timersub(&s->activity_time, &s->last_activity_time, &tv); 529 if (tv.tv_sec == 0 && tv.tv_usec < t * 1000) 530 return (1); 531 return (0); 532 } 533 534 /* Handle data key input from client. */ 535 void 536 server_client_handle_key(struct client *c, int key) 537 { 538 struct mouse_event *m = &c->tty.mouse; 539 struct session *s = c->session; 540 struct window *w; 541 struct window_pane *wp; 542 struct timeval tv; 543 struct key_table *table = c->keytable; 544 struct key_binding bd_find, *bd; 545 int xtimeout; 546 547 /* Check the client is good to accept input. */ 548 if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) 549 return; 550 w = s->curw->window; 551 wp = w->active; 552 553 /* Update the activity timer. */ 554 if (gettimeofday(&c->activity_time, NULL) != 0) 555 fatal("gettimeofday failed"); 556 session_update_activity(s, &c->activity_time); 557 558 /* Number keys jump to pane in identify mode. */ 559 if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { 560 if (c->flags & CLIENT_READONLY) 561 return; 562 window_unzoom(w); 563 wp = window_pane_at_index(w, key - '0'); 564 if (wp != NULL && window_pane_visible(wp)) 565 window_set_active_pane(w, wp); 566 server_clear_identify(c); 567 return; 568 } 569 570 /* Handle status line. */ 571 if (!(c->flags & CLIENT_READONLY)) { 572 status_message_clear(c); 573 server_clear_identify(c); 574 } 575 if (c->prompt_string != NULL) { 576 if (!(c->flags & CLIENT_READONLY)) 577 status_prompt_key(c, key); 578 return; 579 } 580 581 /* Check for mouse keys. */ 582 if (key == KEYC_MOUSE) { 583 if (c->flags & CLIENT_READONLY) 584 return; 585 key = server_client_check_mouse(c); 586 if (key == KEYC_NONE) 587 return; 588 589 m->valid = 1; 590 m->key = key; 591 592 if (!options_get_number(&s->options, "mouse")) { 593 window_pane_key(wp, c, s, key, m); 594 return; 595 } 596 } else 597 m->valid = 0; 598 599 /* Treat everything as a regular key when pasting is detected. */ 600 if (server_client_assume_paste(s)) { 601 if (!(c->flags & CLIENT_READONLY)) 602 window_pane_key(wp, c, s, key, m); 603 return; 604 } 605 606 retry: 607 /* Try to see if there is a key binding in the current table. */ 608 bd_find.key = key; 609 bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); 610 if (bd != NULL) { 611 /* 612 * Key was matched in this table. If currently repeating but a 613 * non-repeating binding was found, stop repeating and try 614 * again in the root table. 615 */ 616 if ((c->flags & CLIENT_REPEAT) && !bd->can_repeat) { 617 server_client_key_table(c, "root"); 618 c->flags &= ~CLIENT_REPEAT; 619 server_status_client(c); 620 goto retry; 621 } 622 623 /* 624 * Take a reference to this table to make sure the key binding 625 * doesn't disappear. 626 */ 627 table->references++; 628 629 /* 630 * If this is a repeating key, start the timer. Otherwise reset 631 * the client back to the root table. 632 */ 633 xtimeout = options_get_number(&s->options, "repeat-time"); 634 if (xtimeout != 0 && bd->can_repeat) { 635 c->flags |= CLIENT_REPEAT; 636 637 tv.tv_sec = xtimeout / 1000; 638 tv.tv_usec = (xtimeout % 1000) * 1000L; 639 evtimer_del(&c->repeat_timer); 640 evtimer_add(&c->repeat_timer, &tv); 641 } else { 642 c->flags &= ~CLIENT_REPEAT; 643 server_client_key_table(c, "root"); 644 } 645 server_status_client(c); 646 647 /* Dispatch the key binding. */ 648 key_bindings_dispatch(bd, c, m); 649 key_bindings_unref_table(table); 650 return; 651 } 652 653 /* 654 * No match in this table. If repeating, switch the client back to the 655 * root table and try again. 656 */ 657 if (c->flags & CLIENT_REPEAT) { 658 server_client_key_table(c, "root"); 659 c->flags &= ~CLIENT_REPEAT; 660 server_status_client(c); 661 goto retry; 662 } 663 664 /* If no match and we're not in the root table, that's it. */ 665 if (strcmp(c->keytable->name, "root") != 0) { 666 server_client_key_table(c, "root"); 667 server_status_client(c); 668 return; 669 } 670 671 /* 672 * No match, but in the root table. Prefix switches to the prefix table 673 * and everything else is passed through. 674 */ 675 if (key == options_get_number(&s->options, "prefix") || 676 key == options_get_number(&s->options, "prefix2")) { 677 server_client_key_table(c, "prefix"); 678 server_status_client(c); 679 } else if (!(c->flags & CLIENT_READONLY)) 680 window_pane_key(wp, c, s, key, m); 681 } 682 683 /* Client functions that need to happen every loop. */ 684 void 685 server_client_loop(void) 686 { 687 struct client *c; 688 struct window *w; 689 struct window_pane *wp; 690 691 TAILQ_FOREACH(c, &clients, entry) { 692 server_client_check_exit(c); 693 if (c->session != NULL) { 694 server_client_check_redraw(c); 695 server_client_reset_state(c); 696 } 697 } 698 699 /* 700 * Any windows will have been redrawn as part of clients, so clear 701 * their flags now. Also check pane focus and resize. 702 */ 703 RB_FOREACH(w, windows, &windows) { 704 w->flags &= ~WINDOW_REDRAW; 705 TAILQ_FOREACH(wp, &w->panes, entry) { 706 if (wp->fd != -1) { 707 server_client_check_focus(wp); 708 server_client_check_resize(wp); 709 } 710 wp->flags &= ~PANE_REDRAW; 711 } 712 check_window_name(w); 713 } 714 } 715 716 /* Check if pane should be resized. */ 717 void 718 server_client_check_resize(struct window_pane *wp) 719 { 720 struct winsize ws; 721 722 if (!(wp->flags & PANE_RESIZE)) 723 return; 724 725 memset(&ws, 0, sizeof ws); 726 ws.ws_col = wp->sx; 727 ws.ws_row = wp->sy; 728 729 if (ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) { 730 #ifdef __sun 731 /* 732 * Some versions of Solaris apparently can return an error when 733 * resizing; don't know why this happens, can't reproduce on 734 * other platforms and ignoring it doesn't seem to cause any 735 * issues. 736 */ 737 if (errno != EINVAL && errno != ENXIO) 738 #endif 739 fatal("ioctl failed"); 740 } 741 742 wp->flags &= ~PANE_RESIZE; 743 } 744 745 /* Check whether pane should be focused. */ 746 void 747 server_client_check_focus(struct window_pane *wp) 748 { 749 struct client *c; 750 int push; 751 752 /* Are focus events off? */ 753 if (!options_get_number(&global_options, "focus-events")) 754 return; 755 756 /* Do we need to push the focus state? */ 757 push = wp->flags & PANE_FOCUSPUSH; 758 wp->flags &= ~PANE_FOCUSPUSH; 759 760 /* If we don't care about focus, forget it. */ 761 if (!(wp->base.mode & MODE_FOCUSON)) 762 return; 763 764 /* If we're not the active pane in our window, we're not focused. */ 765 if (wp->window->active != wp) 766 goto not_focused; 767 768 /* If we're in a mode, we're not focused. */ 769 if (wp->screen != &wp->base) 770 goto not_focused; 771 772 /* 773 * If our window is the current window in any focused clients with an 774 * attached session, we're focused. 775 */ 776 TAILQ_FOREACH(c, &clients, entry) { 777 if (c->session == NULL || !(c->flags & CLIENT_FOCUSED)) 778 continue; 779 if (c->session->flags & SESSION_UNATTACHED) 780 continue; 781 782 if (c->session->curw->window == wp->window) 783 goto focused; 784 } 785 786 not_focused: 787 if (push || (wp->flags & PANE_FOCUSED)) 788 bufferevent_write(wp->event, "\033[O", 3); 789 wp->flags &= ~PANE_FOCUSED; 790 return; 791 792 focused: 793 if (push || !(wp->flags & PANE_FOCUSED)) 794 bufferevent_write(wp->event, "\033[I", 3); 795 wp->flags |= PANE_FOCUSED; 796 } 797 798 /* 799 * Update cursor position and mode settings. The scroll region and attributes 800 * are cleared when idle (waiting for an event) as this is the most likely time 801 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a 802 * compromise between excessive resets and likelihood of an interrupt. 803 * 804 * tty_region/tty_reset/tty_update_mode already take care of not resetting 805 * things that are already in their default state. 806 */ 807 void 808 server_client_reset_state(struct client *c) 809 { 810 struct window *w = c->session->curw->window; 811 struct window_pane *wp = w->active; 812 struct screen *s = wp->screen; 813 struct options *oo = &c->session->options; 814 int status, mode, o; 815 816 if (c->flags & CLIENT_SUSPENDED) 817 return; 818 819 if (c->flags & CLIENT_CONTROL) 820 return; 821 822 tty_region(&c->tty, 0, c->tty.sy - 1); 823 824 status = options_get_number(oo, "status"); 825 if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) 826 tty_cursor(&c->tty, 0, 0); 827 else { 828 o = status && options_get_number(oo, "status-position") == 0; 829 tty_cursor(&c->tty, wp->xoff + s->cx, o + wp->yoff + s->cy); 830 } 831 832 /* 833 * Set mouse mode if requested. To support dragging, always use button 834 * mode. 835 */ 836 mode = s->mode; 837 if (options_get_number(oo, "mouse")) 838 mode = (mode & ~ALL_MOUSE_MODES) | MODE_MOUSE_BUTTON; 839 840 /* 841 * Set UTF-8 mouse input if required. If the terminal is UTF-8, the 842 * user has set mouse-utf8 and any mouse mode is in effect, turn on 843 * UTF-8 mouse input. If the receiving terminal hasn't requested it 844 * (that is, it isn't in s->mode), then it'll be converted in 845 * input_mouse. 846 */ 847 if ((c->tty.flags & TTY_UTF8) && 848 (mode & ALL_MOUSE_MODES) && options_get_number(oo, "mouse-utf8")) 849 mode |= MODE_MOUSE_UTF8; 850 else 851 mode &= ~MODE_MOUSE_UTF8; 852 853 /* Set the terminal mode and reset attributes. */ 854 tty_update_mode(&c->tty, mode, s); 855 tty_reset(&c->tty); 856 } 857 858 /* Repeat time callback. */ 859 void 860 server_client_repeat_timer(unused int fd, unused short events, void *data) 861 { 862 struct client *c = data; 863 864 if (c->flags & CLIENT_REPEAT) { 865 server_client_key_table(c, "root"); 866 c->flags &= ~CLIENT_REPEAT; 867 server_status_client(c); 868 } 869 } 870 871 /* Check if client should be exited. */ 872 void 873 server_client_check_exit(struct client *c) 874 { 875 if (!(c->flags & CLIENT_EXIT)) 876 return; 877 878 if (EVBUFFER_LENGTH(c->stdin_data) != 0) 879 return; 880 if (EVBUFFER_LENGTH(c->stdout_data) != 0) 881 return; 882 if (EVBUFFER_LENGTH(c->stderr_data) != 0) 883 return; 884 885 server_write_client(c, MSG_EXIT, &c->retval, sizeof c->retval); 886 c->flags &= ~CLIENT_EXIT; 887 } 888 889 /* Check for client redraws. */ 890 void 891 server_client_check_redraw(struct client *c) 892 { 893 struct session *s = c->session; 894 struct tty *tty = &c->tty; 895 struct window_pane *wp; 896 int flags, redraw; 897 898 if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) 899 return; 900 901 if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { 902 if (options_get_number(&s->options, "set-titles")) 903 server_client_set_title(c); 904 905 if (c->message_string != NULL) 906 redraw = status_message_redraw(c); 907 else if (c->prompt_string != NULL) 908 redraw = status_prompt_redraw(c); 909 else 910 redraw = status_redraw(c); 911 if (!redraw) 912 c->flags &= ~CLIENT_STATUS; 913 } 914 915 flags = tty->flags & (TTY_FREEZE|TTY_NOCURSOR); 916 tty->flags = (tty->flags & ~TTY_FREEZE) | TTY_NOCURSOR; 917 918 if (c->flags & CLIENT_REDRAW) { 919 tty_update_mode(tty, tty->mode, NULL); 920 screen_redraw_screen(c, 1, 1, 1); 921 c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS); 922 } else if (c->flags & CLIENT_REDRAWWINDOW) { 923 tty_update_mode(tty, tty->mode, NULL); 924 TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) 925 screen_redraw_pane(c, wp); 926 c->flags &= ~CLIENT_REDRAWWINDOW; 927 } else { 928 TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { 929 if (wp->flags & PANE_REDRAW) { 930 tty_update_mode(tty, tty->mode, NULL); 931 screen_redraw_pane(c, wp); 932 } 933 } 934 } 935 936 if (c->flags & CLIENT_BORDERS) { 937 tty_update_mode(tty, tty->mode, NULL); 938 screen_redraw_screen(c, 0, 0, 1); 939 } 940 941 if (c->flags & CLIENT_STATUS) { 942 tty_update_mode(tty, tty->mode, NULL); 943 screen_redraw_screen(c, 0, 1, 0); 944 } 945 946 tty->flags = (tty->flags & ~(TTY_FREEZE|TTY_NOCURSOR)) | flags; 947 tty_update_mode(tty, tty->mode, NULL); 948 949 c->flags &= ~(CLIENT_REDRAW|CLIENT_BORDERS|CLIENT_STATUS| 950 CLIENT_STATUSFORCE); 951 } 952 953 /* Set client title. */ 954 void 955 server_client_set_title(struct client *c) 956 { 957 struct session *s = c->session; 958 const char *template; 959 char *title; 960 struct format_tree *ft; 961 962 template = options_get_string(&s->options, "set-titles-string"); 963 964 ft = format_create(); 965 format_defaults(ft, c, NULL, NULL, NULL); 966 967 title = format_expand_time(ft, template, time(NULL)); 968 if (c->title == NULL || strcmp(title, c->title) != 0) { 969 free(c->title); 970 c->title = xstrdup(title); 971 tty_set_title(&c->tty, c->title); 972 } 973 free(title); 974 975 format_free(ft); 976 } 977 978 /* Dispatch message from client. */ 979 int 980 server_client_msg_dispatch(struct client *c) 981 { 982 struct imsg imsg; 983 struct msg_stdin_data stdindata; 984 const char *data; 985 ssize_t n, datalen; 986 struct session *s; 987 988 if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) 989 return (-1); 990 991 for (;;) { 992 if ((n = imsg_get(&c->ibuf, &imsg)) == -1) 993 return (-1); 994 if (n == 0) 995 return (0); 996 997 data = imsg.data; 998 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 999 1000 if (imsg.hdr.peerid != PROTOCOL_VERSION) { 1001 server_write_client(c, MSG_VERSION, NULL, 0); 1002 c->flags |= CLIENT_BAD; 1003 if (imsg.fd != -1) 1004 close(imsg.fd); 1005 imsg_free(&imsg); 1006 continue; 1007 } 1008 1009 log_debug("got %u from client %d", imsg.hdr.type, c->ibuf.fd); 1010 switch (imsg.hdr.type) { 1011 case MSG_IDENTIFY_FLAGS: 1012 case MSG_IDENTIFY_TERM: 1013 case MSG_IDENTIFY_TTYNAME: 1014 case MSG_IDENTIFY_CWD: 1015 case MSG_IDENTIFY_STDIN: 1016 case MSG_IDENTIFY_ENVIRON: 1017 case MSG_IDENTIFY_CLIENTPID: 1018 case MSG_IDENTIFY_DONE: 1019 server_client_msg_identify(c, &imsg); 1020 break; 1021 case MSG_COMMAND: 1022 server_client_msg_command(c, &imsg); 1023 break; 1024 case MSG_STDIN: 1025 if (datalen != sizeof stdindata) 1026 fatalx("bad MSG_STDIN size"); 1027 memcpy(&stdindata, data, sizeof stdindata); 1028 1029 if (c->stdin_callback == NULL) 1030 break; 1031 if (stdindata.size <= 0) 1032 c->stdin_closed = 1; 1033 else { 1034 evbuffer_add(c->stdin_data, stdindata.data, 1035 stdindata.size); 1036 } 1037 c->stdin_callback(c, c->stdin_closed, 1038 c->stdin_callback_data); 1039 break; 1040 case MSG_RESIZE: 1041 if (datalen != 0) 1042 fatalx("bad MSG_RESIZE size"); 1043 1044 if (c->flags & CLIENT_CONTROL) 1045 break; 1046 if (tty_resize(&c->tty)) { 1047 recalculate_sizes(); 1048 server_redraw_client(c); 1049 } 1050 break; 1051 case MSG_EXITING: 1052 if (datalen != 0) 1053 fatalx("bad MSG_EXITING size"); 1054 1055 c->session = NULL; 1056 tty_close(&c->tty); 1057 server_write_client(c, MSG_EXITED, NULL, 0); 1058 break; 1059 case MSG_WAKEUP: 1060 case MSG_UNLOCK: 1061 if (datalen != 0) 1062 fatalx("bad MSG_WAKEUP size"); 1063 1064 if (!(c->flags & CLIENT_SUSPENDED)) 1065 break; 1066 c->flags &= ~CLIENT_SUSPENDED; 1067 1068 if (c->tty.fd == -1) /* exited in the meantime */ 1069 break; 1070 s = c->session; 1071 1072 if (gettimeofday(&c->activity_time, NULL) != 0) 1073 fatal("gettimeofday failed"); 1074 if (s != NULL) 1075 session_update_activity(s, &c->activity_time); 1076 1077 tty_start_tty(&c->tty); 1078 server_redraw_client(c); 1079 recalculate_sizes(); 1080 break; 1081 case MSG_SHELL: 1082 if (datalen != 0) 1083 fatalx("bad MSG_SHELL size"); 1084 1085 server_client_msg_shell(c); 1086 break; 1087 } 1088 1089 imsg_free(&imsg); 1090 } 1091 } 1092 1093 /* Handle command message. */ 1094 void 1095 server_client_msg_command(struct client *c, struct imsg *imsg) 1096 { 1097 struct msg_command_data data; 1098 char *buf; 1099 size_t len; 1100 struct cmd_list *cmdlist = NULL; 1101 int argc; 1102 char **argv, *cause; 1103 1104 if (imsg->hdr.len - IMSG_HEADER_SIZE < sizeof data) 1105 fatalx("bad MSG_COMMAND size"); 1106 memcpy(&data, imsg->data, sizeof data); 1107 1108 buf = (char *)imsg->data + sizeof data; 1109 len = imsg->hdr.len - IMSG_HEADER_SIZE - sizeof data; 1110 if (len > 0 && buf[len - 1] != '\0') 1111 fatalx("bad MSG_COMMAND string"); 1112 1113 argc = data.argc; 1114 if (cmd_unpack_argv(buf, len, argc, &argv) != 0) { 1115 cmdq_error(c->cmdq, "command too long"); 1116 goto error; 1117 } 1118 1119 if (argc == 0) { 1120 argc = 1; 1121 argv = xcalloc(1, sizeof *argv); 1122 *argv = xstrdup("new-session"); 1123 } 1124 1125 if ((cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause)) == NULL) { 1126 cmdq_error(c->cmdq, "%s", cause); 1127 cmd_free_argv(argc, argv); 1128 goto error; 1129 } 1130 cmd_free_argv(argc, argv); 1131 1132 if (c != cfg_client || cfg_finished) 1133 cmdq_run(c->cmdq, cmdlist, NULL); 1134 else 1135 cmdq_append(c->cmdq, cmdlist, NULL); 1136 cmd_list_free(cmdlist); 1137 return; 1138 1139 error: 1140 if (cmdlist != NULL) 1141 cmd_list_free(cmdlist); 1142 1143 c->flags |= CLIENT_EXIT; 1144 } 1145 1146 /* Handle identify message. */ 1147 void 1148 server_client_msg_identify(struct client *c, struct imsg *imsg) 1149 { 1150 const char *data; 1151 size_t datalen; 1152 int flags; 1153 1154 if (c->flags & CLIENT_IDENTIFIED) 1155 fatalx("out-of-order identify message"); 1156 1157 data = imsg->data; 1158 datalen = imsg->hdr.len - IMSG_HEADER_SIZE; 1159 1160 switch (imsg->hdr.type) { 1161 case MSG_IDENTIFY_FLAGS: 1162 if (datalen != sizeof flags) 1163 fatalx("bad MSG_IDENTIFY_FLAGS size"); 1164 memcpy(&flags, data, sizeof flags); 1165 c->flags |= flags; 1166 break; 1167 case MSG_IDENTIFY_TERM: 1168 if (datalen == 0 || data[datalen - 1] != '\0') 1169 fatalx("bad MSG_IDENTIFY_TERM string"); 1170 c->term = xstrdup(data); 1171 break; 1172 case MSG_IDENTIFY_TTYNAME: 1173 if (datalen == 0 || data[datalen - 1] != '\0') 1174 fatalx("bad MSG_IDENTIFY_TTYNAME string"); 1175 c->ttyname = xstrdup(data); 1176 break; 1177 case MSG_IDENTIFY_CWD: 1178 if (datalen != 0) 1179 fatalx("bad MSG_IDENTIFY_CWD size"); 1180 c->cwd = imsg->fd; 1181 break; 1182 case MSG_IDENTIFY_STDIN: 1183 if (datalen != 0) 1184 fatalx("bad MSG_IDENTIFY_STDIN size"); 1185 c->fd = imsg->fd; 1186 break; 1187 case MSG_IDENTIFY_ENVIRON: 1188 if (datalen == 0 || data[datalen - 1] != '\0') 1189 fatalx("bad MSG_IDENTIFY_ENVIRON string"); 1190 if (strchr(data, '=') != NULL) 1191 environ_put(&c->environ, data); 1192 break; 1193 case MSG_IDENTIFY_CLIENTPID: 1194 if (datalen != sizeof c->pid) 1195 fatalx("bad MSG_IDENTIFY_CLIENTPID size"); 1196 memcpy(&c->pid, data, sizeof c->pid); 1197 break; 1198 default: 1199 break; 1200 } 1201 1202 if (imsg->hdr.type != MSG_IDENTIFY_DONE) 1203 return; 1204 c->flags |= CLIENT_IDENTIFIED; 1205 1206 #ifdef __CYGWIN__ 1207 c->fd = open(c->ttyname, O_RDWR|O_NOCTTY); 1208 c->cwd = open(".", O_RDONLY); 1209 #endif 1210 1211 if (c->flags & CLIENT_CONTROL) { 1212 c->stdin_callback = control_callback; 1213 1214 evbuffer_free(c->stderr_data); 1215 c->stderr_data = c->stdout_data; 1216 1217 if (c->flags & CLIENT_CONTROLCONTROL) 1218 evbuffer_add_printf(c->stdout_data, "\033P1000p"); 1219 server_write_client(c, MSG_STDIN, NULL, 0); 1220 1221 c->tty.fd = -1; 1222 c->tty.log_fd = -1; 1223 1224 close(c->fd); 1225 c->fd = -1; 1226 1227 return; 1228 } 1229 1230 if (c->fd == -1) 1231 return; 1232 if (tty_init(&c->tty, c, c->fd, c->term) != 0) { 1233 close(c->fd); 1234 c->fd = -1; 1235 return; 1236 } 1237 if (c->flags & CLIENT_UTF8) 1238 c->tty.flags |= TTY_UTF8; 1239 if (c->flags & CLIENT_256COLOURS) 1240 c->tty.term_flags |= TERM_256COLOURS; 1241 1242 tty_resize(&c->tty); 1243 1244 if (!(c->flags & CLIENT_CONTROL)) 1245 c->flags |= CLIENT_TERMINAL; 1246 } 1247 1248 /* Handle shell message. */ 1249 void 1250 server_client_msg_shell(struct client *c) 1251 { 1252 const char *shell; 1253 1254 shell = options_get_string(&global_s_options, "default-shell"); 1255 if (*shell == '\0' || areshell(shell)) 1256 shell = _PATH_BSHELL; 1257 server_write_client(c, MSG_SHELL, shell, strlen(shell) + 1); 1258 1259 c->flags |= CLIENT_BAD; /* it will die after exec */ 1260 } 1261