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