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