Annotation of src/usr.bin/tmux/server-client.c, Revision 1.10
1.10 ! nicm 1: /* $OpenBSD: server-client.c,v 1.9 2009/10/27 13:03:33 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:
21: #include <fcntl.h>
22: #include <string.h>
1.4 nicm 23: #include <time.h>
1.1 nicm 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:
1.10 ! nicm 64: if (gettimeofday(&c->creation_time, NULL) != 0)
1.1 nicm 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();
1.9 nicm 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: }
1.1 nicm 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;
1.7 nicm 185:
186: if (c->flags & CLIENT_DEAD)
187: return;
1.1 nicm 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:
1.2 nicm 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:
1.3 nicm 234: server_client_handle_data(c);
1.6 nicm 235: if (c->session != NULL) {
236: server_client_check_timers(c);
237: server_client_check_redraw(c);
238: }
1.2 nicm 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. */
1.1 nicm 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;
1.10 ! nicm 264: struct timeval tv_add, tv_now;
1.1 nicm 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:
1.10 ! nicm 271: /* Check and update repeat flag. */
! 272: if (gettimeofday(&tv_now, NULL) != 0)
! 273: fatal("gettimeofday failed");
1.1 nicm 274: xtimeout = options_get_number(&c->session->options, "repeat-time");
275: if (xtimeout != 0 && c->flags & CLIENT_REPEAT) {
1.10 ! nicm 276: if (timercmp(&tv_now, &c->repeat_timer, >))
1.1 nicm 277: c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
278: }
279:
280: /* Process keys. */
281: keylist = options_get_data(&c->session->options, "prefix");
282: while (tty_keys_next(&c->tty, &key, &mouse) == 0) {
283: if (c->session == NULL)
284: return;
285: w = c->session->curw->window;
286: wp = w->active; /* could die */
287: oo = &c->session->options;
288:
1.10 ! nicm 289: /* Update activity timer. */
! 290: memcpy(&c->session->activity_time,
! 291: &tv_now, sizeof c->session->activity_time);
! 292:
1.1 nicm 293: /* Special case: number keys jump to pane in identify mode. */
294: if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
295: wp = window_pane_at_index(w, key - '0');
296: if (wp != NULL && window_pane_visible(wp))
297: window_set_active_pane(w, wp);
298: server_clear_identify(c);
299: continue;
300: }
301:
302: status_message_clear(c);
303: server_clear_identify(c);
304: if (c->prompt_string != NULL) {
305: status_prompt_key(c, key);
306: continue;
307: }
308:
309: /* Check for mouse keys. */
310: if (key == KEYC_MOUSE) {
311: if (options_get_number(oo, "mouse-select-pane")) {
312: window_set_active_at(w, mouse.x, mouse.y);
313: wp = w->active;
314: }
315: window_pane_mouse(wp, c, &mouse);
316: continue;
317: }
318:
319: /* Is this a prefix key? */
320: isprefix = 0;
321: for (i = 0; i < ARRAY_LENGTH(keylist); i++) {
322: if (key == ARRAY_ITEM(keylist, i)) {
323: isprefix = 1;
324: break;
325: }
326: }
327:
328: /* No previous prefix key. */
329: if (!(c->flags & CLIENT_PREFIX)) {
330: if (isprefix)
331: c->flags |= CLIENT_PREFIX;
332: else {
333: /* Try as a non-prefix key binding. */
334: if ((bd = key_bindings_lookup(key)) == NULL)
335: window_pane_key(wp, c, key);
336: else
337: key_bindings_dispatch(bd, c);
338: }
339: continue;
340: }
341:
342: /* Prefix key already pressed. Reset prefix and lookup key. */
343: c->flags &= ~CLIENT_PREFIX;
344: if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) {
345: /* If repeating, treat this as a key, else ignore. */
346: if (c->flags & CLIENT_REPEAT) {
347: c->flags &= ~CLIENT_REPEAT;
348: if (isprefix)
349: c->flags |= CLIENT_PREFIX;
350: else
351: window_pane_key(wp, c, key);
352: }
353: continue;
354: }
355:
356: /* If already repeating, but this key can't repeat, skip it. */
357: if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
358: c->flags &= ~CLIENT_REPEAT;
359: if (isprefix)
360: c->flags |= CLIENT_PREFIX;
361: else
362: window_pane_key(wp, c, key);
363: continue;
364: }
365:
366: /* If this key can repeat, reset the repeat flags and timer. */
367: if (xtimeout != 0 && bd->can_repeat) {
368: c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
369:
1.10 ! nicm 370: tv_add.tv_sec = xtimeout / 1000;
! 371: tv_add.tv_usec = (xtimeout % 1000) * 1000L;
! 372: timeradd(&tv_now, &tv_add, &c->repeat_timer);
1.1 nicm 373: }
374:
375: /* Dispatch the command. */
376: key_bindings_dispatch(bd, c);
377: }
378: if (c->session == NULL)
379: return;
380: w = c->session->curw->window;
381: wp = w->active;
382: oo = &c->session->options;
383: s = wp->screen;
384:
385: /*
386: * Update cursor position and mode settings. The scroll region and
387: * attributes are cleared across poll(2) as this is the most likely
388: * time a user may interrupt tmux, for example with ~^Z in ssh(1). This
389: * is a compromise between excessive resets and likelihood of an
390: * interrupt.
391: *
392: * tty_region/tty_reset/tty_update_mode already take care of not
393: * resetting things that are already in their default state.
394: */
395: tty_region(&c->tty, 0, c->tty.sy - 1);
396:
397: status = options_get_number(oo, "status");
398: if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)
399: tty_cursor(&c->tty, 0, 0);
400: else
401: tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy);
402:
403: mode = s->mode;
404: if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL &&
405: options_get_number(oo, "mouse-select-pane"))
406: mode |= MODE_MOUSE;
407: tty_update_mode(&c->tty, mode);
408: tty_reset(&c->tty);
409: }
410:
411: /* Check for client redraws. */
412: void
413: server_client_check_redraw(struct client *c)
414: {
415: struct session *s = c->session;
416: struct window_pane *wp;
417: int flags, redraw;
418:
419: flags = c->tty.flags & TTY_FREEZE;
420: c->tty.flags &= ~TTY_FREEZE;
421:
422: if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
423: if (options_get_number(&s->options, "set-titles"))
424: server_client_set_title(c);
425:
426: if (c->message_string != NULL)
427: redraw = status_message_redraw(c);
428: else if (c->prompt_string != NULL)
429: redraw = status_prompt_redraw(c);
430: else
431: redraw = status_redraw(c);
432: if (!redraw)
433: c->flags &= ~CLIENT_STATUS;
434: }
435:
436: if (c->flags & CLIENT_REDRAW) {
437: screen_redraw_screen(c, 0);
438: c->flags &= ~CLIENT_STATUS;
439: } else {
440: TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
441: if (wp->flags & PANE_REDRAW)
442: screen_redraw_pane(c, wp);
443: }
444: }
445:
446: if (c->flags & CLIENT_STATUS)
447: screen_redraw_screen(c, 1);
448:
449: c->tty.flags |= flags;
450:
451: c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS);
452: }
453:
454: /* Set client title. */
455: void
456: server_client_set_title(struct client *c)
457: {
458: struct session *s = c->session;
459: const char *template;
460: char *title;
461:
462: template = options_get_string(&s->options, "set-titles-string");
463:
464: title = status_replace(c, template, time(NULL));
465: if (c->title == NULL || strcmp(title, c->title) != 0) {
466: if (c->title != NULL)
467: xfree(c->title);
468: c->title = xstrdup(title);
469: tty_set_title(&c->tty, c->title);
470: }
471: xfree(title);
472: }
473:
474: /* Check client timers. */
475: void
476: server_client_check_timers(struct client *c)
477: {
478: struct session *s = c->session;
479: struct job *job;
480: struct timeval tv;
481: u_int interval;
482:
483: if (gettimeofday(&tv, NULL) != 0)
484: fatal("gettimeofday failed");
485:
486: if (c->flags & CLIENT_IDENTIFY && timercmp(&tv, &c->identify_timer, >))
487: server_clear_identify(c);
488:
489: if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >))
490: status_message_clear(c);
491:
492: if (c->message_string != NULL || c->prompt_string != NULL) {
493: /*
494: * Don't need timed redraw for messages/prompts so bail now.
495: * The status timer isn't reset when they are redrawn anyway.
496: */
497: return;
498:
499: }
500: if (!options_get_number(&s->options, "status"))
501: return;
502:
503: /* Check timer; resolution is only a second so don't be too clever. */
504: interval = options_get_number(&s->options, "status-interval");
505: if (interval == 0)
506: return;
507: if (tv.tv_sec < c->status_timer.tv_sec ||
508: ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) {
509: /* Run the jobs for this client and schedule for redraw. */
510: RB_FOREACH(job, jobs, &c->status_jobs)
511: job_run(job);
512: c->flags |= CLIENT_STATUS;
513: }
514: }
515:
516: /* Dispatch message from client. */
517: int
518: server_client_msg_dispatch(struct client *c)
519: {
520: struct imsg imsg;
521: struct msg_command_data commanddata;
522: struct msg_identify_data identifydata;
523: struct msg_environ_data environdata;
524: ssize_t n, datalen;
525:
1.8 deraadt 526: if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
527: return (-1);
1.1 nicm 528:
529: for (;;) {
530: if ((n = imsg_get(&c->ibuf, &imsg)) == -1)
531: return (-1);
532: if (n == 0)
533: return (0);
534: datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
535:
536: if (imsg.hdr.peerid != PROTOCOL_VERSION) {
537: server_write_client(c, MSG_VERSION, NULL, 0);
538: c->flags |= CLIENT_BAD;
539: imsg_free(&imsg);
540: continue;
541: }
542:
543: log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd);
544: switch (imsg.hdr.type) {
545: case MSG_COMMAND:
546: if (datalen != sizeof commanddata)
547: fatalx("bad MSG_COMMAND size");
548: memcpy(&commanddata, imsg.data, sizeof commanddata);
549:
550: server_client_msg_command(c, &commanddata);
551: break;
552: case MSG_IDENTIFY:
553: if (datalen != sizeof identifydata)
554: fatalx("bad MSG_IDENTIFY size");
555: if (imsg.fd == -1)
556: fatalx("MSG_IDENTIFY missing fd");
557: memcpy(&identifydata, imsg.data, sizeof identifydata);
558:
559: server_client_msg_identify(c, &identifydata, imsg.fd);
560: break;
561: case MSG_RESIZE:
562: if (datalen != 0)
563: fatalx("bad MSG_RESIZE size");
564:
565: tty_resize(&c->tty);
566: recalculate_sizes();
567: server_redraw_client(c);
568: break;
569: case MSG_EXITING:
570: if (datalen != 0)
571: fatalx("bad MSG_EXITING size");
572:
573: c->session = NULL;
574: tty_close(&c->tty);
575: server_write_client(c, MSG_EXITED, NULL, 0);
576: break;
577: case MSG_WAKEUP:
578: case MSG_UNLOCK:
579: if (datalen != 0)
580: fatalx("bad MSG_WAKEUP size");
581:
582: if (!(c->flags & CLIENT_SUSPENDED))
583: break;
584: c->flags &= ~CLIENT_SUSPENDED;
1.10 ! nicm 585:
! 586: if (c->session != NULL &&
! 587: gettimeofday(&c->session->activity_time, NULL) != 0)
! 588: fatal("gettimeofday failed");
! 589:
1.1 nicm 590: tty_start_tty(&c->tty);
591: server_redraw_client(c);
592: recalculate_sizes();
593: break;
594: case MSG_ENVIRON:
595: if (datalen != sizeof environdata)
596: fatalx("bad MSG_ENVIRON size");
597: memcpy(&environdata, imsg.data, sizeof environdata);
598:
599: environdata.var[(sizeof environdata.var) - 1] = '\0';
600: if (strchr(environdata.var, '=') != NULL)
601: environ_put(&c->environ, environdata.var);
602: break;
603: case MSG_SHELL:
604: if (datalen != 0)
605: fatalx("bad MSG_SHELL size");
606:
607: server_client_msg_shell(c);
608: break;
609: default:
610: fatalx("unexpected message");
611: }
612:
613: imsg_free(&imsg);
614: }
615: }
616:
617: /* Callback to send error message to client. */
618: void printflike2
619: server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
620: {
621: struct msg_print_data data;
622: va_list ap;
623:
624: va_start(ap, fmt);
625: xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
626: va_end(ap);
627:
628: server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data);
629: }
630:
631: /* Callback to send print message to client. */
632: void printflike2
633: server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
634: {
635: struct msg_print_data data;
636: va_list ap;
637:
638: va_start(ap, fmt);
639: xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
640: va_end(ap);
641:
642: server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
643: }
644:
645: /* Callback to send print message to client, if not quiet. */
646: void printflike2
647: server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
648: {
649: struct msg_print_data data;
650: va_list ap;
651:
652: if (be_quiet)
653: return;
654:
655: va_start(ap, fmt);
656: xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
657: va_end(ap);
658:
659: server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
660: }
661:
662: /* Handle command message. */
663: void
664: server_client_msg_command(struct client *c, struct msg_command_data *data)
665: {
666: struct cmd_ctx ctx;
667: struct cmd_list *cmdlist = NULL;
668: struct cmd *cmd;
669: int argc;
670: char **argv, *cause;
671:
672: ctx.error = server_client_msg_error;
673: ctx.print = server_client_msg_print;
674: ctx.info = server_client_msg_info;
675:
676: ctx.msgdata = data;
677: ctx.curclient = NULL;
678:
679: ctx.cmdclient = c;
680:
681: argc = data->argc;
682: data->argv[(sizeof data->argv) - 1] = '\0';
683: if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) {
684: server_client_msg_error(&ctx, "command too long");
685: goto error;
686: }
687:
688: if (argc == 0) {
689: argc = 1;
690: argv = xcalloc(1, sizeof *argv);
691: *argv = xstrdup("new-session");
692: }
693:
694: if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
695: server_client_msg_error(&ctx, "%s", cause);
696: cmd_free_argv(argc, argv);
697: goto error;
698: }
699: cmd_free_argv(argc, argv);
700:
701: if (data->pid != -1) {
702: TAILQ_FOREACH(cmd, cmdlist, qentry) {
703: if (cmd->entry->flags & CMD_CANTNEST) {
704: server_client_msg_error(&ctx,
705: "sessions should be nested with care. "
706: "unset $TMUX to force");
707: goto error;
708: }
709: }
710: }
711:
712: if (cmd_list_exec(cmdlist, &ctx) != 1)
713: server_write_client(c, MSG_EXIT, NULL, 0);
714: cmd_list_free(cmdlist);
715: return;
716:
717: error:
718: if (cmdlist != NULL)
719: cmd_list_free(cmdlist);
720: server_write_client(c, MSG_EXIT, NULL, 0);
721: }
722:
723: /* Handle identify message. */
724: void
725: server_client_msg_identify(
726: struct client *c, struct msg_identify_data *data, int fd)
727: {
728: c->cwd = NULL;
729: data->cwd[(sizeof data->cwd) - 1] = '\0';
730: if (*data->cwd != '\0')
731: c->cwd = xstrdup(data->cwd);
732:
733: data->term[(sizeof data->term) - 1] = '\0';
734: tty_init(&c->tty, fd, data->term);
735: if (data->flags & IDENTIFY_UTF8)
736: c->tty.flags |= TTY_UTF8;
737: if (data->flags & IDENTIFY_256COLOURS)
738: c->tty.term_flags |= TERM_256COLOURS;
739: else if (data->flags & IDENTIFY_88COLOURS)
740: c->tty.term_flags |= TERM_88COLOURS;
741:
742: tty_resize(&c->tty);
743:
744: c->flags |= CLIENT_TERMINAL;
745: }
746:
747: /* Handle shell message. */
748: void
749: server_client_msg_shell(struct client *c)
750: {
751: struct msg_shell_data data;
752: const char *shell;
753:
754: shell = options_get_string(&global_s_options, "default-shell");
755:
756: if (*shell == '\0' || areshell(shell))
757: shell = _PATH_BSHELL;
758: if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell)
759: strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell);
760:
761: server_write_client(c, MSG_SHELL, &data, sizeof data);
762: c->flags |= CLIENT_BAD; /* it will die after exec */
763: }