1 /* $OpenBSD: server-client.c,v 1.9 2009/10/27 13:03:33 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 21 #include <fcntl.h> 22 #include <string.h> 23 #include <time.h> 24 #include <paths.h> 25 #include <unistd.h> 26 27 #include "tmux.h" 28 29 void server_client_handle_data(struct client *); 30 void server_client_check_redraw(struct client *); 31 void server_client_set_title(struct client *); 32 void server_client_check_timers(struct client *); 33 34 int server_client_msg_dispatch(struct client *); 35 void server_client_msg_command(struct client *, struct msg_command_data *); 36 void server_client_msg_identify( 37 struct client *, struct msg_identify_data *, int); 38 void server_client_msg_shell(struct client *); 39 40 void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...); 41 void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...); 42 void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...); 43 44 45 /* Create a new client. */ 46 void 47 server_client_create(int fd) 48 { 49 struct client *c; 50 int mode; 51 u_int i; 52 53 if ((mode = fcntl(fd, F_GETFL)) == -1) 54 fatal("fcntl failed"); 55 if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) 56 fatal("fcntl failed"); 57 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) 58 fatal("fcntl failed"); 59 60 c = xcalloc(1, sizeof *c); 61 c->references = 0; 62 imsg_init(&c->ibuf, fd); 63 64 if (gettimeofday(&c->tv, NULL) != 0) 65 fatal("gettimeofday failed"); 66 67 ARRAY_INIT(&c->prompt_hdata); 68 69 c->tty.fd = -1; 70 c->title = NULL; 71 72 c->session = NULL; 73 c->tty.sx = 80; 74 c->tty.sy = 24; 75 76 screen_init(&c->status, c->tty.sx, 1, 0); 77 job_tree_init(&c->status_jobs); 78 79 c->message_string = NULL; 80 81 c->prompt_string = NULL; 82 c->prompt_buffer = NULL; 83 c->prompt_index = 0; 84 85 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 86 if (ARRAY_ITEM(&clients, i) == NULL) { 87 ARRAY_SET(&clients, i, c); 88 return; 89 } 90 } 91 ARRAY_ADD(&clients, c); 92 log_debug("new client %d", fd); 93 } 94 95 /* Lost a client. */ 96 void 97 server_client_lost(struct client *c) 98 { 99 u_int i; 100 101 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 102 if (ARRAY_ITEM(&clients, i) == c) 103 ARRAY_SET(&clients, i, NULL); 104 } 105 log_debug("lost client %d", c->ibuf.fd); 106 107 /* 108 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called 109 * and tty_free might close an unrelated fd. 110 */ 111 if (c->flags & CLIENT_TERMINAL) 112 tty_free(&c->tty); 113 114 screen_free(&c->status); 115 job_tree_free(&c->status_jobs); 116 117 if (c->title != NULL) 118 xfree(c->title); 119 120 if (c->message_string != NULL) 121 xfree(c->message_string); 122 123 if (c->prompt_string != NULL) 124 xfree(c->prompt_string); 125 if (c->prompt_buffer != NULL) 126 xfree(c->prompt_buffer); 127 for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++) 128 xfree(ARRAY_ITEM(&c->prompt_hdata, i)); 129 ARRAY_FREE(&c->prompt_hdata); 130 131 if (c->cwd != NULL) 132 xfree(c->cwd); 133 134 close(c->ibuf.fd); 135 imsg_clear(&c->ibuf); 136 137 for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { 138 if (ARRAY_ITEM(&dead_clients, i) == NULL) { 139 ARRAY_SET(&dead_clients, i, c); 140 break; 141 } 142 } 143 if (i == ARRAY_LENGTH(&dead_clients)) 144 ARRAY_ADD(&dead_clients, c); 145 c->flags |= CLIENT_DEAD; 146 147 recalculate_sizes(); 148 } 149 150 /* Register clients for poll. */ 151 void 152 server_client_prepare(void) 153 { 154 struct client *c; 155 u_int i; 156 int events; 157 158 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 159 if ((c = ARRAY_ITEM(&clients, i)) == NULL) 160 continue; 161 162 events = 0; 163 if (!(c->flags & CLIENT_BAD)) 164 events |= POLLIN; 165 if (c->ibuf.w.queued > 0) 166 events |= POLLOUT; 167 server_poll_add(c->ibuf.fd, events, server_client_callback, c); 168 169 if (c->tty.fd == -1) 170 continue; 171 if (c->flags & CLIENT_SUSPENDED || c->session == NULL) 172 continue; 173 events = POLLIN; 174 if (BUFFER_USED(c->tty.out) > 0) 175 events |= POLLOUT; 176 server_poll_add(c->tty.fd, events, server_client_callback, c); 177 } 178 } 179 180 /* Process a single client event. */ 181 void 182 server_client_callback(int fd, int events, void *data) 183 { 184 struct client *c = data; 185 186 if (c->flags & CLIENT_DEAD) 187 return; 188 189 if (fd == c->ibuf.fd) { 190 if (events & (POLLERR|POLLNVAL|POLLHUP)) 191 goto client_lost; 192 193 if (events & POLLOUT && msgbuf_write(&c->ibuf.w) < 0) 194 goto client_lost; 195 196 if (c->flags & CLIENT_BAD) { 197 if (c->ibuf.w.queued == 0) 198 goto client_lost; 199 return; 200 } 201 202 if (events & POLLIN && server_client_msg_dispatch(c) != 0) 203 goto client_lost; 204 } 205 206 if (c->tty.fd != -1 && fd == c->tty.fd) { 207 if (c->flags & CLIENT_SUSPENDED || c->session == NULL) 208 return; 209 210 if (buffer_poll(fd, events, c->tty.in, c->tty.out) != 0) 211 goto client_lost; 212 } 213 214 return; 215 216 client_lost: 217 server_client_lost(c); 218 } 219 220 /* Client functions that need to happen every loop. */ 221 void 222 server_client_loop(void) 223 { 224 struct client *c; 225 struct window *w; 226 struct window_pane *wp; 227 u_int i; 228 229 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 230 c = ARRAY_ITEM(&clients, i); 231 if (c == NULL || c->session == NULL) 232 continue; 233 234 server_client_handle_data(c); 235 if (c->session != NULL) { 236 server_client_check_timers(c); 237 server_client_check_redraw(c); 238 } 239 } 240 241 /* 242 * Any windows will have been redrawn as part of clients, so clear 243 * their flags now. 244 */ 245 for (i = 0; i < ARRAY_LENGTH(&windows); i++) { 246 w = ARRAY_ITEM(&windows, i); 247 if (w == NULL) 248 continue; 249 250 w->flags &= ~WINDOW_REDRAW; 251 TAILQ_FOREACH(wp, &w->panes, entry) 252 wp->flags &= ~PANE_REDRAW; 253 } 254 } 255 256 /* Handle data input or output from client. */ 257 void 258 server_client_handle_data(struct client *c) 259 { 260 struct window *w; 261 struct window_pane *wp; 262 struct screen *s; 263 struct options *oo; 264 struct timeval tv; 265 struct key_binding *bd; 266 struct keylist *keylist; 267 struct mouse_event mouse; 268 int key, status, xtimeout, mode, isprefix; 269 u_int i; 270 271 xtimeout = options_get_number(&c->session->options, "repeat-time"); 272 if (xtimeout != 0 && c->flags & CLIENT_REPEAT) { 273 if (gettimeofday(&tv, NULL) != 0) 274 fatal("gettimeofday failed"); 275 if (timercmp(&tv, &c->repeat_timer, >)) 276 c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); 277 } 278 279 /* Process keys. */ 280 keylist = options_get_data(&c->session->options, "prefix"); 281 while (tty_keys_next(&c->tty, &key, &mouse) == 0) { 282 if (c->session == NULL) 283 return; 284 285 c->session->activity = time(NULL); 286 w = c->session->curw->window; 287 wp = w->active; /* could die */ 288 oo = &c->session->options; 289 290 /* Special case: number keys jump to pane in identify mode. */ 291 if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { 292 wp = window_pane_at_index(w, key - '0'); 293 if (wp != NULL && window_pane_visible(wp)) 294 window_set_active_pane(w, wp); 295 server_clear_identify(c); 296 continue; 297 } 298 299 status_message_clear(c); 300 server_clear_identify(c); 301 if (c->prompt_string != NULL) { 302 status_prompt_key(c, key); 303 continue; 304 } 305 306 /* Check for mouse keys. */ 307 if (key == KEYC_MOUSE) { 308 if (options_get_number(oo, "mouse-select-pane")) { 309 window_set_active_at(w, mouse.x, mouse.y); 310 wp = w->active; 311 } 312 window_pane_mouse(wp, c, &mouse); 313 continue; 314 } 315 316 /* Is this a prefix key? */ 317 isprefix = 0; 318 for (i = 0; i < ARRAY_LENGTH(keylist); i++) { 319 if (key == ARRAY_ITEM(keylist, i)) { 320 isprefix = 1; 321 break; 322 } 323 } 324 325 /* No previous prefix key. */ 326 if (!(c->flags & CLIENT_PREFIX)) { 327 if (isprefix) 328 c->flags |= CLIENT_PREFIX; 329 else { 330 /* Try as a non-prefix key binding. */ 331 if ((bd = key_bindings_lookup(key)) == NULL) 332 window_pane_key(wp, c, key); 333 else 334 key_bindings_dispatch(bd, c); 335 } 336 continue; 337 } 338 339 /* Prefix key already pressed. Reset prefix and lookup key. */ 340 c->flags &= ~CLIENT_PREFIX; 341 if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { 342 /* If repeating, treat this as a key, else ignore. */ 343 if (c->flags & CLIENT_REPEAT) { 344 c->flags &= ~CLIENT_REPEAT; 345 if (isprefix) 346 c->flags |= CLIENT_PREFIX; 347 else 348 window_pane_key(wp, c, key); 349 } 350 continue; 351 } 352 353 /* If already repeating, but this key can't repeat, skip it. */ 354 if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { 355 c->flags &= ~CLIENT_REPEAT; 356 if (isprefix) 357 c->flags |= CLIENT_PREFIX; 358 else 359 window_pane_key(wp, c, key); 360 continue; 361 } 362 363 /* If this key can repeat, reset the repeat flags and timer. */ 364 if (xtimeout != 0 && bd->can_repeat) { 365 c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; 366 367 tv.tv_sec = xtimeout / 1000; 368 tv.tv_usec = (xtimeout % 1000) * 1000L; 369 if (gettimeofday(&c->repeat_timer, NULL) != 0) 370 fatal("gettimeofday failed"); 371 timeradd(&c->repeat_timer, &tv, &c->repeat_timer); 372 } 373 374 /* Dispatch the command. */ 375 key_bindings_dispatch(bd, c); 376 } 377 if (c->session == NULL) 378 return; 379 w = c->session->curw->window; 380 wp = w->active; 381 oo = &c->session->options; 382 s = wp->screen; 383 384 /* 385 * Update cursor position and mode settings. The scroll region and 386 * attributes are cleared across poll(2) as this is the most likely 387 * time a user may interrupt tmux, for example with ~^Z in ssh(1). This 388 * is a compromise between excessive resets and likelihood of an 389 * interrupt. 390 * 391 * tty_region/tty_reset/tty_update_mode already take care of not 392 * resetting things that are already in their default state. 393 */ 394 tty_region(&c->tty, 0, c->tty.sy - 1); 395 396 status = options_get_number(oo, "status"); 397 if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) 398 tty_cursor(&c->tty, 0, 0); 399 else 400 tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy); 401 402 mode = s->mode; 403 if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && 404 options_get_number(oo, "mouse-select-pane")) 405 mode |= MODE_MOUSE; 406 tty_update_mode(&c->tty, mode); 407 tty_reset(&c->tty); 408 } 409 410 /* Check for client redraws. */ 411 void 412 server_client_check_redraw(struct client *c) 413 { 414 struct session *s = c->session; 415 struct window_pane *wp; 416 int flags, redraw; 417 418 flags = c->tty.flags & TTY_FREEZE; 419 c->tty.flags &= ~TTY_FREEZE; 420 421 if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { 422 if (options_get_number(&s->options, "set-titles")) 423 server_client_set_title(c); 424 425 if (c->message_string != NULL) 426 redraw = status_message_redraw(c); 427 else if (c->prompt_string != NULL) 428 redraw = status_prompt_redraw(c); 429 else 430 redraw = status_redraw(c); 431 if (!redraw) 432 c->flags &= ~CLIENT_STATUS; 433 } 434 435 if (c->flags & CLIENT_REDRAW) { 436 screen_redraw_screen(c, 0); 437 c->flags &= ~CLIENT_STATUS; 438 } else { 439 TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { 440 if (wp->flags & PANE_REDRAW) 441 screen_redraw_pane(c, wp); 442 } 443 } 444 445 if (c->flags & CLIENT_STATUS) 446 screen_redraw_screen(c, 1); 447 448 c->tty.flags |= flags; 449 450 c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS); 451 } 452 453 /* Set client title. */ 454 void 455 server_client_set_title(struct client *c) 456 { 457 struct session *s = c->session; 458 const char *template; 459 char *title; 460 461 template = options_get_string(&s->options, "set-titles-string"); 462 463 title = status_replace(c, template, time(NULL)); 464 if (c->title == NULL || strcmp(title, c->title) != 0) { 465 if (c->title != NULL) 466 xfree(c->title); 467 c->title = xstrdup(title); 468 tty_set_title(&c->tty, c->title); 469 } 470 xfree(title); 471 } 472 473 /* Check client timers. */ 474 void 475 server_client_check_timers(struct client *c) 476 { 477 struct session *s = c->session; 478 struct job *job; 479 struct timeval tv; 480 u_int interval; 481 482 if (gettimeofday(&tv, NULL) != 0) 483 fatal("gettimeofday failed"); 484 485 if (c->flags & CLIENT_IDENTIFY && timercmp(&tv, &c->identify_timer, >)) 486 server_clear_identify(c); 487 488 if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >)) 489 status_message_clear(c); 490 491 if (c->message_string != NULL || c->prompt_string != NULL) { 492 /* 493 * Don't need timed redraw for messages/prompts so bail now. 494 * The status timer isn't reset when they are redrawn anyway. 495 */ 496 return; 497 498 } 499 if (!options_get_number(&s->options, "status")) 500 return; 501 502 /* Check timer; resolution is only a second so don't be too clever. */ 503 interval = options_get_number(&s->options, "status-interval"); 504 if (interval == 0) 505 return; 506 if (tv.tv_sec < c->status_timer.tv_sec || 507 ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) { 508 /* Run the jobs for this client and schedule for redraw. */ 509 RB_FOREACH(job, jobs, &c->status_jobs) 510 job_run(job); 511 c->flags |= CLIENT_STATUS; 512 } 513 } 514 515 /* Dispatch message from client. */ 516 int 517 server_client_msg_dispatch(struct client *c) 518 { 519 struct imsg imsg; 520 struct msg_command_data commanddata; 521 struct msg_identify_data identifydata; 522 struct msg_environ_data environdata; 523 ssize_t n, datalen; 524 525 if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) 526 return (-1); 527 528 for (;;) { 529 if ((n = imsg_get(&c->ibuf, &imsg)) == -1) 530 return (-1); 531 if (n == 0) 532 return (0); 533 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 534 535 if (imsg.hdr.peerid != PROTOCOL_VERSION) { 536 server_write_client(c, MSG_VERSION, NULL, 0); 537 c->flags |= CLIENT_BAD; 538 imsg_free(&imsg); 539 continue; 540 } 541 542 log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd); 543 switch (imsg.hdr.type) { 544 case MSG_COMMAND: 545 if (datalen != sizeof commanddata) 546 fatalx("bad MSG_COMMAND size"); 547 memcpy(&commanddata, imsg.data, sizeof commanddata); 548 549 server_client_msg_command(c, &commanddata); 550 break; 551 case MSG_IDENTIFY: 552 if (datalen != sizeof identifydata) 553 fatalx("bad MSG_IDENTIFY size"); 554 if (imsg.fd == -1) 555 fatalx("MSG_IDENTIFY missing fd"); 556 memcpy(&identifydata, imsg.data, sizeof identifydata); 557 558 server_client_msg_identify(c, &identifydata, imsg.fd); 559 break; 560 case MSG_RESIZE: 561 if (datalen != 0) 562 fatalx("bad MSG_RESIZE size"); 563 564 tty_resize(&c->tty); 565 recalculate_sizes(); 566 server_redraw_client(c); 567 break; 568 case MSG_EXITING: 569 if (datalen != 0) 570 fatalx("bad MSG_EXITING size"); 571 572 c->session = NULL; 573 tty_close(&c->tty); 574 server_write_client(c, MSG_EXITED, NULL, 0); 575 break; 576 case MSG_WAKEUP: 577 case MSG_UNLOCK: 578 if (datalen != 0) 579 fatalx("bad MSG_WAKEUP size"); 580 581 if (!(c->flags & CLIENT_SUSPENDED)) 582 break; 583 c->flags &= ~CLIENT_SUSPENDED; 584 tty_start_tty(&c->tty); 585 server_redraw_client(c); 586 recalculate_sizes(); 587 if (c->session != NULL) 588 c->session->activity = time(NULL); 589 break; 590 case MSG_ENVIRON: 591 if (datalen != sizeof environdata) 592 fatalx("bad MSG_ENVIRON size"); 593 memcpy(&environdata, imsg.data, sizeof environdata); 594 595 environdata.var[(sizeof environdata.var) - 1] = '\0'; 596 if (strchr(environdata.var, '=') != NULL) 597 environ_put(&c->environ, environdata.var); 598 break; 599 case MSG_SHELL: 600 if (datalen != 0) 601 fatalx("bad MSG_SHELL size"); 602 603 server_client_msg_shell(c); 604 break; 605 default: 606 fatalx("unexpected message"); 607 } 608 609 imsg_free(&imsg); 610 } 611 } 612 613 /* Callback to send error message to client. */ 614 void printflike2 615 server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...) 616 { 617 struct msg_print_data data; 618 va_list ap; 619 620 va_start(ap, fmt); 621 xvsnprintf(data.msg, sizeof data.msg, fmt, ap); 622 va_end(ap); 623 624 server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data); 625 } 626 627 /* Callback to send print message to client. */ 628 void printflike2 629 server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...) 630 { 631 struct msg_print_data data; 632 va_list ap; 633 634 va_start(ap, fmt); 635 xvsnprintf(data.msg, sizeof data.msg, fmt, ap); 636 va_end(ap); 637 638 server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); 639 } 640 641 /* Callback to send print message to client, if not quiet. */ 642 void printflike2 643 server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...) 644 { 645 struct msg_print_data data; 646 va_list ap; 647 648 if (be_quiet) 649 return; 650 651 va_start(ap, fmt); 652 xvsnprintf(data.msg, sizeof data.msg, fmt, ap); 653 va_end(ap); 654 655 server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data); 656 } 657 658 /* Handle command message. */ 659 void 660 server_client_msg_command(struct client *c, struct msg_command_data *data) 661 { 662 struct cmd_ctx ctx; 663 struct cmd_list *cmdlist = NULL; 664 struct cmd *cmd; 665 int argc; 666 char **argv, *cause; 667 668 if (c->session != NULL) 669 c->session->activity = time(NULL); 670 671 ctx.error = server_client_msg_error; 672 ctx.print = server_client_msg_print; 673 ctx.info = server_client_msg_info; 674 675 ctx.msgdata = data; 676 ctx.curclient = NULL; 677 678 ctx.cmdclient = c; 679 680 argc = data->argc; 681 data->argv[(sizeof data->argv) - 1] = '\0'; 682 if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) { 683 server_client_msg_error(&ctx, "command too long"); 684 goto error; 685 } 686 687 if (argc == 0) { 688 argc = 1; 689 argv = xcalloc(1, sizeof *argv); 690 *argv = xstrdup("new-session"); 691 } 692 693 if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { 694 server_client_msg_error(&ctx, "%s", cause); 695 cmd_free_argv(argc, argv); 696 goto error; 697 } 698 cmd_free_argv(argc, argv); 699 700 if (data->pid != -1) { 701 TAILQ_FOREACH(cmd, cmdlist, qentry) { 702 if (cmd->entry->flags & CMD_CANTNEST) { 703 server_client_msg_error(&ctx, 704 "sessions should be nested with care. " 705 "unset $TMUX to force"); 706 goto error; 707 } 708 } 709 } 710 711 if (cmd_list_exec(cmdlist, &ctx) != 1) 712 server_write_client(c, MSG_EXIT, NULL, 0); 713 cmd_list_free(cmdlist); 714 return; 715 716 error: 717 if (cmdlist != NULL) 718 cmd_list_free(cmdlist); 719 server_write_client(c, MSG_EXIT, NULL, 0); 720 } 721 722 /* Handle identify message. */ 723 void 724 server_client_msg_identify( 725 struct client *c, struct msg_identify_data *data, int fd) 726 { 727 c->cwd = NULL; 728 data->cwd[(sizeof data->cwd) - 1] = '\0'; 729 if (*data->cwd != '\0') 730 c->cwd = xstrdup(data->cwd); 731 732 data->term[(sizeof data->term) - 1] = '\0'; 733 tty_init(&c->tty, fd, data->term); 734 if (data->flags & IDENTIFY_UTF8) 735 c->tty.flags |= TTY_UTF8; 736 if (data->flags & IDENTIFY_256COLOURS) 737 c->tty.term_flags |= TERM_256COLOURS; 738 else if (data->flags & IDENTIFY_88COLOURS) 739 c->tty.term_flags |= TERM_88COLOURS; 740 741 tty_resize(&c->tty); 742 743 c->flags |= CLIENT_TERMINAL; 744 } 745 746 /* Handle shell message. */ 747 void 748 server_client_msg_shell(struct client *c) 749 { 750 struct msg_shell_data data; 751 const char *shell; 752 753 shell = options_get_string(&global_s_options, "default-shell"); 754 755 if (*shell == '\0' || areshell(shell)) 756 shell = _PATH_BSHELL; 757 if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell) 758 strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell); 759 760 server_write_client(c, MSG_SHELL, &data, sizeof data); 761 c->flags |= CLIENT_BAD; /* it will die after exec */ 762 } 763