[BACK]Return to server-client.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/server-client.c, Revision 1.91

1.91    ! nicm        1: /* $OpenBSD: server-client.c,v 1.90 2013/03/22 15:54:29 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>
1.77      nicm       26: #include <stdlib.h>
1.1       nicm       27: #include <unistd.h>
                     28:
                     29: #include "tmux.h"
                     30:
1.91    ! nicm       31: void   server_client_check_focus(struct window_pane *);
1.81      nicm       32: void   server_client_check_mouse(struct client *, struct window_pane *);
1.17      nicm       33: void   server_client_repeat_timer(int, short, void *);
1.36      nicm       34: void   server_client_check_exit(struct client *);
1.1       nicm       35: void   server_client_check_redraw(struct client *);
                     36: void   server_client_set_title(struct client *);
1.18      nicm       37: void   server_client_reset_state(struct client *);
1.82      nicm       38: int    server_client_assume_paste(struct session *);
1.1       nicm       39:
                     40: int    server_client_msg_dispatch(struct client *);
                     41: void   server_client_msg_command(struct client *, struct msg_command_data *);
                     42: void   server_client_msg_identify(
1.25      nicm       43:            struct client *, struct msg_identify_data *, int);
1.1       nicm       44: void   server_client_msg_shell(struct client *);
                     45:
                     46: void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...);
                     47: void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...);
                     48: void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...);
                     49:
                     50: /* Create a new client. */
                     51: void
                     52: server_client_create(int fd)
                     53: {
                     54:        struct client   *c;
                     55:        u_int            i;
                     56:
1.49      nicm       57:        setblocking(fd, 0);
1.1       nicm       58:
                     59:        c = xcalloc(1, sizeof *c);
                     60:        c->references = 0;
                     61:        imsg_init(&c->ibuf, fd);
1.14      nicm       62:        server_update_event(c);
1.25      nicm       63:
1.10      nicm       64:        if (gettimeofday(&c->creation_time, NULL) != 0)
1.1       nicm       65:                fatal("gettimeofday failed");
1.11      nicm       66:        memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
1.1       nicm       67:
1.73      nicm       68:        c->stdin_data = evbuffer_new ();
                     69:        c->stdout_data = evbuffer_new ();
                     70:        c->stderr_data = evbuffer_new ();
1.33      nicm       71:
1.1       nicm       72:        c->tty.fd = -1;
                     73:        c->title = NULL;
                     74:
                     75:        c->session = NULL;
1.45      nicm       76:        c->last_session = NULL;
1.1       nicm       77:        c->tty.sx = 80;
                     78:        c->tty.sy = 24;
                     79:
                     80:        screen_init(&c->status, c->tty.sx, 1, 0);
1.51      nicm       81:        RB_INIT(&c->status_new);
                     82:        RB_INIT(&c->status_old);
1.1       nicm       83:
                     84:        c->message_string = NULL;
1.21      nicm       85:        ARRAY_INIT(&c->message_log);
1.1       nicm       86:
                     87:        c->prompt_string = NULL;
                     88:        c->prompt_buffer = NULL;
                     89:        c->prompt_index = 0;
                     90:
1.81      nicm       91:        c->tty.mouse.xb = c->tty.mouse.button = 3;
                     92:        c->tty.mouse.x = c->tty.mouse.y = -1;
                     93:        c->tty.mouse.lx = c->tty.mouse.ly = -1;
                     94:        c->tty.mouse.sx = c->tty.mouse.sy = -1;
                     95:        c->tty.mouse.event = MOUSE_EVENT_UP;
                     96:        c->tty.mouse.flags = 0;
1.57      nicm       97:
1.17      nicm       98:        evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
                     99:
1.1       nicm      100:        for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
                    101:                if (ARRAY_ITEM(&clients, i) == NULL) {
                    102:                        ARRAY_SET(&clients, i, c);
                    103:                        return;
                    104:                }
                    105:        }
                    106:        ARRAY_ADD(&clients, c);
                    107:        log_debug("new client %d", fd);
1.72      nicm      108: }
                    109:
                    110: /* Open client terminal if needed. */
                    111: int
                    112: server_client_open(struct client *c, struct session *s, char **cause)
                    113: {
                    114:        struct options  *oo = s != NULL ? &s->options : &global_s_options;
                    115:        char            *overrides;
                    116:
1.75      nicm      117:        if (c->flags & CLIENT_CONTROL)
                    118:                return (0);
                    119:
1.72      nicm      120:        if (!(c->flags & CLIENT_TERMINAL)) {
                    121:                *cause = xstrdup ("not a terminal");
                    122:                return (-1);
                    123:        }
                    124:
                    125:        overrides = options_get_string(oo, "terminal-overrides");
                    126:        if (tty_open(&c->tty, overrides, cause) != 0)
                    127:                return (-1);
                    128:
                    129:        return (0);
1.1       nicm      130: }
                    131:
                    132: /* Lost a client. */
                    133: void
                    134: server_client_lost(struct client *c)
                    135: {
1.21      nicm      136:        struct message_entry    *msg;
                    137:        u_int                    i;
1.1       nicm      138:
                    139:        for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
                    140:                if (ARRAY_ITEM(&clients, i) == c)
                    141:                        ARRAY_SET(&clients, i, NULL);
                    142:        }
                    143:        log_debug("lost client %d", c->ibuf.fd);
                    144:
                    145:        /*
                    146:         * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
                    147:         * and tty_free might close an unrelated fd.
                    148:         */
                    149:        if (c->flags & CLIENT_TERMINAL)
                    150:                tty_free(&c->tty);
                    151:
1.73      nicm      152:        evbuffer_free (c->stdin_data);
                    153:        evbuffer_free (c->stdout_data);
                    154:        evbuffer_free (c->stderr_data);
1.33      nicm      155:
1.51      nicm      156:        status_free_jobs(&c->status_new);
                    157:        status_free_jobs(&c->status_old);
1.1       nicm      158:        screen_free(&c->status);
                    159:
1.77      nicm      160:        free(c->title);
1.1       nicm      161:
1.17      nicm      162:        evtimer_del(&c->repeat_timer);
                    163:
1.69      nicm      164:        if (event_initialized(&c->identify_timer))
                    165:                evtimer_del(&c->identify_timer);
1.15      nicm      166:
1.77      nicm      167:        free(c->message_string);
1.69      nicm      168:        if (event_initialized (&c->message_timer))
                    169:                evtimer_del(&c->message_timer);
1.21      nicm      170:        for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) {
                    171:                msg = &ARRAY_ITEM(&c->message_log, i);
1.77      nicm      172:                free(msg->msg);
1.21      nicm      173:        }
                    174:        ARRAY_FREE(&c->message_log);
1.1       nicm      175:
1.77      nicm      176:        free(c->prompt_string);
                    177:        free(c->prompt_buffer);
                    178:        free(c->cwd);
1.61      nicm      179:
                    180:        environ_free(&c->environ);
1.1       nicm      181:
                    182:        close(c->ibuf.fd);
                    183:        imsg_clear(&c->ibuf);
1.69      nicm      184:        if (event_initialized(&c->event))
                    185:                event_del(&c->event);
1.13      nicm      186:
1.1       nicm      187:        for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
                    188:                if (ARRAY_ITEM(&dead_clients, i) == NULL) {
                    189:                        ARRAY_SET(&dead_clients, i, c);
                    190:                        break;
                    191:                }
                    192:        }
                    193:        if (i == ARRAY_LENGTH(&dead_clients))
                    194:                ARRAY_ADD(&dead_clients, c);
                    195:        c->flags |= CLIENT_DEAD;
1.71      nicm      196:
                    197:        server_add_accept(0); /* may be more file descriptors now */
1.1       nicm      198:
                    199:        recalculate_sizes();
1.41      nicm      200:        server_check_unattached();
1.19      nicm      201:        server_update_socket();
1.9       nicm      202: }
                    203:
1.1       nicm      204: /* Process a single client event. */
                    205: void
1.12      nicm      206: server_client_callback(int fd, short events, void *data)
1.1       nicm      207: {
                    208:        struct client   *c = data;
1.7       nicm      209:
                    210:        if (c->flags & CLIENT_DEAD)
                    211:                return;
1.1       nicm      212:
                    213:        if (fd == c->ibuf.fd) {
1.12      nicm      214:                if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) < 0)
1.1       nicm      215:                        goto client_lost;
                    216:
                    217:                if (c->flags & CLIENT_BAD) {
                    218:                        if (c->ibuf.w.queued == 0)
                    219:                                goto client_lost;
                    220:                        return;
                    221:                }
                    222:
1.12      nicm      223:                if (events & EV_READ && server_client_msg_dispatch(c) != 0)
1.1       nicm      224:                        goto client_lost;
                    225:        }
1.14      nicm      226:
1.73      nicm      227:        server_push_stdout(c);
                    228:        server_push_stderr(c);
                    229:
1.25      nicm      230:        server_update_event(c);
1.1       nicm      231:        return;
                    232:
                    233: client_lost:
                    234:        server_client_lost(c);
                    235: }
                    236:
1.16      nicm      237: /* Handle client status timer. */
                    238: void
                    239: server_client_status_timer(void)
                    240: {
                    241:        struct client   *c;
                    242:        struct session  *s;
                    243:        struct timeval   tv;
1.20      nicm      244:        u_int            i;
                    245:        int              interval;
                    246:        time_t           difference;
1.16      nicm      247:
                    248:        if (gettimeofday(&tv, NULL) != 0)
                    249:                fatal("gettimeofday failed");
                    250:
                    251:        for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
                    252:                c = ARRAY_ITEM(&clients, i);
                    253:                if (c == NULL || c->session == NULL)
                    254:                        continue;
                    255:                if (c->message_string != NULL || c->prompt_string != NULL) {
                    256:                        /*
                    257:                         * Don't need timed redraw for messages/prompts so bail
                    258:                         * now. The status timer isn't reset when they are
                    259:                         * redrawn anyway.
                    260:                         */
                    261:                        continue;
                    262:                }
                    263:                s = c->session;
                    264:
                    265:                if (!options_get_number(&s->options, "status"))
                    266:                        continue;
                    267:                interval = options_get_number(&s->options, "status-interval");
                    268:
1.20      nicm      269:                difference = tv.tv_sec - c->status_timer.tv_sec;
                    270:                if (difference >= interval) {
1.51      nicm      271:                        status_update_jobs(c);
1.16      nicm      272:                        c->flags |= CLIENT_STATUS;
                    273:                }
                    274:        }
                    275: }
                    276:
1.66      nicm      277: /* Check for mouse keys. */
                    278: void
1.81      nicm      279: server_client_check_mouse(struct client *c, struct window_pane *wp)
1.66      nicm      280: {
1.81      nicm      281:        struct session          *s = c->session;
                    282:        struct options          *oo = &s->options;
                    283:        struct mouse_event      *m = &c->tty.mouse;
                    284:        int                      statusat;
1.66      nicm      285:
                    286:        statusat = status_at_line(c);
                    287:
                    288:        /* Is this a window selection click on the status line? */
1.81      nicm      289:        if (statusat != -1 && m->y == (u_int)statusat &&
1.66      nicm      290:            options_get_number(oo, "mouse-select-window")) {
1.81      nicm      291:                if (m->event & MOUSE_EVENT_CLICK) {
                    292:                        status_set_window_at(c, m->x);
                    293:                } else if (m->event == MOUSE_EVENT_WHEEL) {
                    294:                        if (m->wheel == MOUSE_WHEEL_UP)
1.66      nicm      295:                                session_previous(c->session, 0);
1.81      nicm      296:                        else if (m->wheel == MOUSE_WHEEL_DOWN)
1.66      nicm      297:                                session_next(c->session, 0);
1.81      nicm      298:                        server_redraw_session(s);
1.66      nicm      299:                }
1.81      nicm      300:                recalculate_sizes();
1.67      nicm      301:                return;
1.66      nicm      302:        }
                    303:
                    304:        /*
                    305:         * Not on status line - adjust mouse position if status line is at the
                    306:         * top and limit if at the bottom. From here on a struct mouse
                    307:         * represents the offset onto the window itself.
                    308:         */
1.81      nicm      309:        if (statusat == 0 && m->y > 0)
                    310:                m->y--;
                    311:        else if (statusat > 0 && m->y >= (u_int)statusat)
                    312:                m->y = statusat - 1;
1.66      nicm      313:
                    314:        /* Is this a pane selection? Allow down only in copy mode. */
                    315:        if (options_get_number(oo, "mouse-select-pane") &&
1.81      nicm      316:            (m->event == MOUSE_EVENT_DOWN || wp->mode != &window_copy_mode)) {
                    317:                window_set_active_at(wp->window, m->x, m->y);
1.66      nicm      318:                server_redraw_window_borders(wp->window);
                    319:                wp = wp->window->active; /* may have changed */
                    320:        }
                    321:
                    322:        /* Check if trying to resize pane. */
                    323:        if (options_get_number(oo, "mouse-resize-pane"))
1.81      nicm      324:                layout_resize_pane_mouse(c);
1.66      nicm      325:
                    326:        /* Update last and pass through to client. */
1.81      nicm      327:        window_pane_mouse(wp, c->session, m);
1.66      nicm      328: }
                    329:
1.82      nicm      330: /* Is this fast enough to probably be a paste? */
                    331: int
                    332: server_client_assume_paste(struct session *s)
                    333: {
                    334:        struct timeval  tv;
1.84      nicm      335:        int             t;
1.82      nicm      336:
                    337:        if ((t = options_get_number(&s->options, "assume-paste-time")) == 0)
1.83      nicm      338:                return (0);
1.82      nicm      339:
                    340:        timersub(&s->activity_time, &s->last_activity_time, &tv);
                    341:        if (tv.tv_sec == 0 && tv.tv_usec < t * 1000)
1.83      nicm      342:                return (1);
                    343:        return (0);
1.82      nicm      344: }
                    345:
1.18      nicm      346: /* Handle data key input from client. */
                    347: void
1.74      nicm      348: server_client_handle_key(struct client *c, int key)
1.18      nicm      349: {
                    350:        struct session          *s;
                    351:        struct window           *w;
                    352:        struct window_pane      *wp;
                    353:        struct timeval           tv;
                    354:        struct key_binding      *bd;
1.82      nicm      355:        int                      xtimeout, isprefix, ispaste;
1.18      nicm      356:
                    357:        /* Check the client is good to accept input. */
                    358:        if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
                    359:                return;
1.86      nicm      360:
1.18      nicm      361:        if (c->session == NULL)
                    362:                return;
                    363:        s = c->session;
                    364:
                    365:        /* Update the activity timer. */
                    366:        if (gettimeofday(&c->activity_time, NULL) != 0)
                    367:                fatal("gettimeofday failed");
1.82      nicm      368:
                    369:        memcpy(&s->last_activity_time, &s->activity_time,
                    370:            sizeof s->last_activity_time);
1.18      nicm      371:        memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time);
                    372:
                    373:        w = c->session->curw->window;
                    374:        wp = w->active;
                    375:
                    376:        /* Special case: number keys jump to pane in identify mode. */
1.25      nicm      377:        if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
1.30      nicm      378:                if (c->flags & CLIENT_READONLY)
                    379:                        return;
1.18      nicm      380:                wp = window_pane_at_index(w, key - '0');
                    381:                if (wp != NULL && window_pane_visible(wp))
                    382:                        window_set_active_pane(w, wp);
                    383:                server_clear_identify(c);
                    384:                return;
                    385:        }
                    386:
                    387:        /* Handle status line. */
1.30      nicm      388:        if (!(c->flags & CLIENT_READONLY)) {
                    389:                status_message_clear(c);
                    390:                server_clear_identify(c);
                    391:        }
1.18      nicm      392:        if (c->prompt_string != NULL) {
1.30      nicm      393:                if (!(c->flags & CLIENT_READONLY))
                    394:                        status_prompt_key(c, key);
1.18      nicm      395:                return;
                    396:        }
                    397:
                    398:        /* Check for mouse keys. */
                    399:        if (key == KEYC_MOUSE) {
1.30      nicm      400:                if (c->flags & CLIENT_READONLY)
                    401:                        return;
1.81      nicm      402:                server_client_check_mouse(c, wp);
1.18      nicm      403:                return;
                    404:        }
                    405:
                    406:        /* Is this a prefix key? */
1.82      nicm      407:        if (key == options_get_number(&s->options, "prefix"))
1.63      nicm      408:                isprefix = 1;
1.82      nicm      409:        else if (key == options_get_number(&s->options, "prefix2"))
1.63      nicm      410:                isprefix = 1;
                    411:        else
                    412:                isprefix = 0;
1.18      nicm      413:
1.82      nicm      414:        /* Treat prefix as a regular key when pasting is detected. */
                    415:        ispaste = server_client_assume_paste(s);
                    416:        if (ispaste)
                    417:                isprefix = 0;
                    418:
1.18      nicm      419:        /* No previous prefix key. */
                    420:        if (!(c->flags & CLIENT_PREFIX)) {
1.82      nicm      421:                if (isprefix) {
1.18      nicm      422:                        c->flags |= CLIENT_PREFIX;
1.85      nicm      423:                        server_status_client(c);
1.82      nicm      424:                        return;
1.18      nicm      425:                }
1.82      nicm      426:
                    427:                /* Try as a non-prefix key binding. */
                    428:                if (ispaste || (bd = key_bindings_lookup(key)) == NULL) {
                    429:                        if (!(c->flags & CLIENT_READONLY))
                    430:                                window_pane_key(wp, s, key);
                    431:                } else
                    432:                        key_bindings_dispatch(bd, c);
1.18      nicm      433:                return;
                    434:        }
                    435:
                    436:        /* Prefix key already pressed. Reset prefix and lookup key. */
                    437:        c->flags &= ~CLIENT_PREFIX;
1.85      nicm      438:        server_status_client(c);
1.18      nicm      439:        if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) {
                    440:                /* If repeating, treat this as a key, else ignore. */
                    441:                if (c->flags & CLIENT_REPEAT) {
                    442:                        c->flags &= ~CLIENT_REPEAT;
                    443:                        if (isprefix)
                    444:                                c->flags |= CLIENT_PREFIX;
1.30      nicm      445:                        else if (!(c->flags & CLIENT_READONLY))
1.82      nicm      446:                                window_pane_key(wp, s, key);
1.18      nicm      447:                }
                    448:                return;
                    449:        }
                    450:
                    451:        /* If already repeating, but this key can't repeat, skip it. */
                    452:        if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
                    453:                c->flags &= ~CLIENT_REPEAT;
                    454:                if (isprefix)
                    455:                        c->flags |= CLIENT_PREFIX;
1.30      nicm      456:                else if (!(c->flags & CLIENT_READONLY))
1.82      nicm      457:                        window_pane_key(wp, s, key);
1.18      nicm      458:                return;
                    459:        }
                    460:
                    461:        /* If this key can repeat, reset the repeat flags and timer. */
1.82      nicm      462:        xtimeout = options_get_number(&s->options, "repeat-time");
1.18      nicm      463:        if (xtimeout != 0 && bd->can_repeat) {
                    464:                c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
1.25      nicm      465:
1.18      nicm      466:                tv.tv_sec = xtimeout / 1000;
                    467:                tv.tv_usec = (xtimeout % 1000) * 1000L;
                    468:                evtimer_del(&c->repeat_timer);
                    469:                evtimer_add(&c->repeat_timer, &tv);
                    470:        }
                    471:
                    472:        /* Dispatch the command. */
                    473:        key_bindings_dispatch(bd, c);
                    474: }
                    475:
1.2       nicm      476: /* Client functions that need to happen every loop. */
                    477: void
                    478: server_client_loop(void)
                    479: {
                    480:        struct client           *c;
                    481:        struct window           *w;
                    482:        struct window_pane      *wp;
                    483:        u_int                    i;
                    484:
                    485:        for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
                    486:                c = ARRAY_ITEM(&clients, i);
1.36      nicm      487:                if (c == NULL)
1.2       nicm      488:                        continue;
                    489:
1.36      nicm      490:                server_client_check_exit(c);
                    491:                if (c->session != NULL) {
                    492:                        server_client_check_redraw(c);
                    493:                        server_client_reset_state(c);
                    494:                }
1.2       nicm      495:        }
                    496:
                    497:        /*
                    498:         * Any windows will have been redrawn as part of clients, so clear
1.91    ! nicm      499:         * their flags now. Also check and update pane focus.
1.2       nicm      500:         */
                    501:        for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
                    502:                w = ARRAY_ITEM(&windows, i);
                    503:                if (w == NULL)
                    504:                        continue;
                    505:
                    506:                w->flags &= ~WINDOW_REDRAW;
1.91    ! nicm      507:                TAILQ_FOREACH(wp, &w->panes, entry) {
        !           508:                        server_client_check_focus(wp);
1.2       nicm      509:                        wp->flags &= ~PANE_REDRAW;
1.91    ! nicm      510:                }
1.2       nicm      511:        }
1.91    ! nicm      512: }
        !           513:
        !           514: /* Check whether pane should be focused. */
        !           515: void
        !           516: server_client_check_focus(struct window_pane *wp)
        !           517: {
        !           518:        struct session  *s;
        !           519:
        !           520:        /* If we don't care about focus, forget it. */
        !           521:        if (!(wp->base.mode & MODE_FOCUSON))
        !           522:                return;
        !           523:
        !           524:        /* If we're not the active pane in our window, we're not focused. */
        !           525:        if (wp->window->active != wp)
        !           526:                goto not_focused;
        !           527:
        !           528:        /* If we're in a mode, we're not focused. */
        !           529:        if (wp->screen != &wp->base)
        !           530:                goto not_focused;
        !           531:
        !           532:        /*
        !           533:         * If our window is the current window in any attached sessions, we're
        !           534:         * focused.
        !           535:         */
        !           536:        RB_FOREACH(s, sessions, &sessions) {
        !           537:                if (s->flags & SESSION_UNATTACHED)
        !           538:                        continue;
        !           539:                if (s->curw->window == wp->window)
        !           540:                        goto focused;
        !           541:        }
        !           542:
        !           543: not_focused:
        !           544:        if (wp->flags & PANE_FOCUSED)
        !           545:                bufferevent_write(wp->event, "\033[O", 3);
        !           546:        wp->flags &= ~PANE_FOCUSED;
        !           547:        return;
        !           548:
        !           549: focused:
        !           550:        if (!(wp->flags & PANE_FOCUSED))
        !           551:                bufferevent_write(wp->event, "\033[I", 3);
        !           552:        wp->flags |= PANE_FOCUSED;
1.2       nicm      553: }
                    554:
1.18      nicm      555: /*
                    556:  * Update cursor position and mode settings. The scroll region and attributes
                    557:  * are cleared when idle (waiting for an event) as this is the most likely time
                    558:  * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
                    559:  * compromise between excessive resets and likelihood of an interrupt.
                    560:  *
                    561:  * tty_region/tty_reset/tty_update_mode already take care of not resetting
                    562:  * things that are already in their default state.
                    563:  */
1.1       nicm      564: void
1.18      nicm      565: server_client_reset_state(struct client *c)
1.1       nicm      566: {
1.18      nicm      567:        struct window           *w = c->session->curw->window;
                    568:        struct window_pane      *wp = w->active;
                    569:        struct screen           *s = wp->screen;
                    570:        struct options          *oo = &c->session->options;
1.54      nicm      571:        struct options          *wo = &w->options;
1.66      nicm      572:        int                      status, mode, o;
1.60      nicm      573:
                    574:        if (c->flags & CLIENT_SUSPENDED)
                    575:                return;
1.1       nicm      576:
1.86      nicm      577:        if (c->flags & CLIENT_CONTROL)
                    578:                return;
                    579:
1.1       nicm      580:        tty_region(&c->tty, 0, c->tty.sy - 1);
                    581:
                    582:        status = options_get_number(oo, "status");
                    583:        if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)
                    584:                tty_cursor(&c->tty, 0, 0);
1.66      nicm      585:        else {
                    586:                o = status && options_get_number (oo, "status-position") == 0;
                    587:                tty_cursor(&c->tty, wp->xoff + s->cx, o + wp->yoff + s->cy);
                    588:        }
1.1       nicm      589:
1.50      nicm      590:        /*
1.57      nicm      591:         * Resizing panes with the mouse requires at least button mode to give
                    592:         * a smooth appearance.
                    593:         */
                    594:        mode = s->mode;
1.81      nicm      595:        if ((c->tty.mouse.flags & MOUSE_RESIZE_PANE) &&
1.57      nicm      596:            !(mode & (MODE_MOUSE_BUTTON|MODE_MOUSE_ANY)))
                    597:                mode |= MODE_MOUSE_BUTTON;
                    598:
                    599:        /*
1.50      nicm      600:         * Any mode will do for mouse-select-pane, but set standard mode if
                    601:         * none.
                    602:         */
1.54      nicm      603:        if ((mode & ALL_MOUSE_MODES) == 0) {
                    604:                if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL &&
1.55      nicm      605:                    options_get_number(oo, "mouse-select-pane"))
1.57      nicm      606:                        mode |= MODE_MOUSE_STANDARD;
                    607:                else if (options_get_number(oo, "mouse-resize-pane"))
1.54      nicm      608:                        mode |= MODE_MOUSE_STANDARD;
                    609:                else if (options_get_number(oo, "mouse-select-window"))
                    610:                        mode |= MODE_MOUSE_STANDARD;
                    611:                else if (options_get_number(wo, "mode-mouse"))
                    612:                        mode |= MODE_MOUSE_STANDARD;
                    613:        }
1.48      nicm      614:
                    615:        /*
                    616:         * Set UTF-8 mouse input if required. If the terminal is UTF-8, the
                    617:         * user has set mouse-utf8 and any mouse mode is in effect, turn on
                    618:         * UTF-8 mouse input. If the receiving terminal hasn't requested it
                    619:         * (that is, it isn't in s->mode), then it'll be converted in
                    620:         * input_mouse.
                    621:         */
                    622:        if ((c->tty.flags & TTY_UTF8) &&
                    623:            (mode & ALL_MOUSE_MODES) && options_get_number(oo, "mouse-utf8"))
                    624:                mode |= MODE_MOUSE_UTF8;
                    625:        else
                    626:                mode &= ~MODE_MOUSE_UTF8;
                    627:
                    628:        /* Set the terminal mode and reset attributes. */
1.59      nicm      629:        tty_update_mode(&c->tty, mode, s);
1.1       nicm      630:        tty_reset(&c->tty);
1.17      nicm      631: }
                    632:
                    633: /* Repeat time callback. */
                    634: void
                    635: server_client_repeat_timer(unused int fd, unused short events, void *data)
                    636: {
                    637:        struct client   *c = data;
                    638:
1.85      nicm      639:        if (c->flags & CLIENT_REPEAT) {
                    640:                if (c->flags & CLIENT_PREFIX)
                    641:                        server_status_client(c);
1.17      nicm      642:                c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
1.85      nicm      643:        }
1.1       nicm      644: }
                    645:
1.36      nicm      646: /* Check if client should be exited. */
                    647: void
                    648: server_client_check_exit(struct client *c)
                    649: {
                    650:        struct msg_exit_data    exitdata;
                    651:
                    652:        if (!(c->flags & CLIENT_EXIT))
                    653:                return;
                    654:
1.73      nicm      655:        if (EVBUFFER_LENGTH(c->stdin_data) != 0)
                    656:                return;
                    657:        if (EVBUFFER_LENGTH(c->stdout_data) != 0)
1.36      nicm      658:                return;
1.73      nicm      659:        if (EVBUFFER_LENGTH(c->stderr_data) != 0)
1.36      nicm      660:                return;
                    661:
                    662:        exitdata.retcode = c->retcode;
                    663:        server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata);
                    664:
                    665:        c->flags &= ~CLIENT_EXIT;
1.38      nicm      666: }
                    667:
1.1       nicm      668: /* Check for client redraws. */
                    669: void
                    670: server_client_check_redraw(struct client *c)
                    671: {
                    672:        struct session          *s = c->session;
                    673:        struct window_pane      *wp;
                    674:        int                      flags, redraw;
                    675:
1.86      nicm      676:        if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
1.79      nicm      677:                return;
                    678:
1.1       nicm      679:        flags = c->tty.flags & TTY_FREEZE;
                    680:        c->tty.flags &= ~TTY_FREEZE;
                    681:
                    682:        if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
                    683:                if (options_get_number(&s->options, "set-titles"))
                    684:                        server_client_set_title(c);
1.12      nicm      685:
1.1       nicm      686:                if (c->message_string != NULL)
                    687:                        redraw = status_message_redraw(c);
                    688:                else if (c->prompt_string != NULL)
                    689:                        redraw = status_prompt_redraw(c);
                    690:                else
                    691:                        redraw = status_redraw(c);
                    692:                if (!redraw)
                    693:                        c->flags &= ~CLIENT_STATUS;
                    694:        }
                    695:
                    696:        if (c->flags & CLIENT_REDRAW) {
1.27      nicm      697:                screen_redraw_screen(c, 0, 0);
                    698:                c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS);
1.38      nicm      699:        } else if (c->flags & CLIENT_REDRAWWINDOW) {
                    700:                TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry)
                    701:                        screen_redraw_pane(c, wp);
                    702:                c->flags &= ~CLIENT_REDRAWWINDOW;
1.1       nicm      703:        } else {
                    704:                TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
                    705:                        if (wp->flags & PANE_REDRAW)
                    706:                                screen_redraw_pane(c, wp);
                    707:                }
                    708:        }
                    709:
1.27      nicm      710:        if (c->flags & CLIENT_BORDERS)
                    711:                screen_redraw_screen(c, 0, 1);
                    712:
1.1       nicm      713:        if (c->flags & CLIENT_STATUS)
1.27      nicm      714:                screen_redraw_screen(c, 1, 0);
1.1       nicm      715:
                    716:        c->tty.flags |= flags;
                    717:
1.27      nicm      718:        c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS|CLIENT_BORDERS);
1.1       nicm      719: }
                    720:
                    721: /* Set client title. */
                    722: void
                    723: server_client_set_title(struct client *c)
                    724: {
                    725:        struct session  *s = c->session;
                    726:        const char      *template;
                    727:        char            *title;
                    728:
                    729:        template = options_get_string(&s->options, "set-titles-string");
1.25      nicm      730:
1.52      nicm      731:        title = status_replace(c, NULL, NULL, NULL, template, time(NULL), 1);
1.1       nicm      732:        if (c->title == NULL || strcmp(title, c->title) != 0) {
1.77      nicm      733:                free(c->title);
1.1       nicm      734:                c->title = xstrdup(title);
                    735:                tty_set_title(&c->tty, c->title);
                    736:        }
1.77      nicm      737:        free(title);
1.1       nicm      738: }
                    739:
                    740: /* Dispatch message from client. */
                    741: int
                    742: server_client_msg_dispatch(struct client *c)
                    743: {
                    744:        struct imsg              imsg;
                    745:        struct msg_command_data  commanddata;
                    746:        struct msg_identify_data identifydata;
                    747:        struct msg_environ_data  environdata;
1.73      nicm      748:        struct msg_stdin_data    stdindata;
1.1       nicm      749:        ssize_t                  n, datalen;
                    750:
1.8       deraadt   751:        if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
                    752:                return (-1);
1.1       nicm      753:
                    754:        for (;;) {
                    755:                if ((n = imsg_get(&c->ibuf, &imsg)) == -1)
                    756:                        return (-1);
                    757:                if (n == 0)
                    758:                        return (0);
                    759:                datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
                    760:
                    761:                if (imsg.hdr.peerid != PROTOCOL_VERSION) {
                    762:                        server_write_client(c, MSG_VERSION, NULL, 0);
                    763:                        c->flags |= CLIENT_BAD;
                    764:                        imsg_free(&imsg);
                    765:                        continue;
                    766:                }
                    767:
                    768:                log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd);
                    769:                switch (imsg.hdr.type) {
                    770:                case MSG_COMMAND:
                    771:                        if (datalen != sizeof commanddata)
                    772:                                fatalx("bad MSG_COMMAND size");
                    773:                        memcpy(&commanddata, imsg.data, sizeof commanddata);
                    774:
                    775:                        server_client_msg_command(c, &commanddata);
                    776:                        break;
                    777:                case MSG_IDENTIFY:
                    778:                        if (datalen != sizeof identifydata)
                    779:                                fatalx("bad MSG_IDENTIFY size");
                    780:                        if (imsg.fd == -1)
                    781:                                fatalx("MSG_IDENTIFY missing fd");
                    782:                        memcpy(&identifydata, imsg.data, sizeof identifydata);
                    783:
                    784:                        server_client_msg_identify(c, &identifydata, imsg.fd);
                    785:                        break;
1.73      nicm      786:                case MSG_STDIN:
                    787:                        if (datalen != sizeof stdindata)
                    788:                                fatalx("bad MSG_STDIN size");
                    789:                        memcpy(&stdindata, imsg.data, sizeof stdindata);
1.36      nicm      790:
1.73      nicm      791:                        if (c->stdin_callback == NULL)
                    792:                                break;
                    793:                        if (stdindata.size <= 0)
                    794:                                c->stdin_closed = 1;
                    795:                        else {
                    796:                                evbuffer_add(c->stdin_data, stdindata.data,
                    797:                                    stdindata.size);
                    798:                        }
                    799:                        c->stdin_callback(c, c->stdin_closed,
                    800:                            c->stdin_callback_data);
1.33      nicm      801:                        break;
1.1       nicm      802:                case MSG_RESIZE:
                    803:                        if (datalen != 0)
                    804:                                fatalx("bad MSG_RESIZE size");
                    805:
1.86      nicm      806:                        if (c->flags & CLIENT_CONTROL)
                    807:                                break;
1.32      nicm      808:                        if (tty_resize(&c->tty)) {
                    809:                                recalculate_sizes();
                    810:                                server_redraw_client(c);
                    811:                        }
1.1       nicm      812:                        break;
                    813:                case MSG_EXITING:
                    814:                        if (datalen != 0)
                    815:                                fatalx("bad MSG_EXITING size");
                    816:
                    817:                        c->session = NULL;
                    818:                        tty_close(&c->tty);
                    819:                        server_write_client(c, MSG_EXITED, NULL, 0);
                    820:                        break;
                    821:                case MSG_WAKEUP:
                    822:                case MSG_UNLOCK:
                    823:                        if (datalen != 0)
                    824:                                fatalx("bad MSG_WAKEUP size");
                    825:
                    826:                        if (!(c->flags & CLIENT_SUSPENDED))
                    827:                                break;
                    828:                        c->flags &= ~CLIENT_SUSPENDED;
1.10      nicm      829:
1.11      nicm      830:                        if (gettimeofday(&c->activity_time, NULL) != 0)
                    831:                                fatal("gettimeofday");
1.47      nicm      832:                        if (c->session != NULL)
                    833:                                session_update_activity(c->session);
1.10      nicm      834:
1.1       nicm      835:                        tty_start_tty(&c->tty);
                    836:                        server_redraw_client(c);
                    837:                        recalculate_sizes();
                    838:                        break;
                    839:                case MSG_ENVIRON:
                    840:                        if (datalen != sizeof environdata)
                    841:                                fatalx("bad MSG_ENVIRON size");
                    842:                        memcpy(&environdata, imsg.data, sizeof environdata);
                    843:
                    844:                        environdata.var[(sizeof environdata.var) - 1] = '\0';
                    845:                        if (strchr(environdata.var, '=') != NULL)
                    846:                                environ_put(&c->environ, environdata.var);
                    847:                        break;
                    848:                case MSG_SHELL:
                    849:                        if (datalen != 0)
                    850:                                fatalx("bad MSG_SHELL size");
                    851:
                    852:                        server_client_msg_shell(c);
                    853:                        break;
                    854:                default:
                    855:                        fatalx("unexpected message");
                    856:                }
                    857:
                    858:                imsg_free(&imsg);
                    859:        }
                    860: }
                    861:
                    862: /* Callback to send error message to client. */
                    863: void printflike2
                    864: server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
                    865: {
1.33      nicm      866:        va_list ap;
1.1       nicm      867:
                    868:        va_start(ap, fmt);
1.73      nicm      869:        evbuffer_add_vprintf(ctx->cmdclient->stderr_data, fmt, ap);
1.1       nicm      870:        va_end(ap);
                    871:
1.73      nicm      872:        evbuffer_add(ctx->cmdclient->stderr_data, "\n", 1);
                    873:        server_push_stderr(ctx->cmdclient);
1.34      nicm      874:        ctx->cmdclient->retcode = 1;
1.1       nicm      875: }
                    876:
                    877: /* Callback to send print message to client. */
                    878: void printflike2
                    879: server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
                    880: {
1.33      nicm      881:        va_list ap;
1.1       nicm      882:
                    883:        va_start(ap, fmt);
1.73      nicm      884:        evbuffer_add_vprintf(ctx->cmdclient->stdout_data, fmt, ap);
1.1       nicm      885:        va_end(ap);
                    886:
1.73      nicm      887:        evbuffer_add(ctx->cmdclient->stdout_data, "\n", 1);
                    888:        server_push_stdout(ctx->cmdclient);
1.1       nicm      889: }
                    890:
                    891: /* Callback to send print message to client, if not quiet. */
                    892: void printflike2
                    893: server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
                    894: {
1.33      nicm      895:        va_list ap;
1.1       nicm      896:
1.26      nicm      897:        if (options_get_number(&global_options, "quiet"))
1.1       nicm      898:                return;
                    899:
                    900:        va_start(ap, fmt);
1.73      nicm      901:        evbuffer_add_vprintf(ctx->cmdclient->stdout_data, fmt, ap);
1.1       nicm      902:        va_end(ap);
                    903:
1.73      nicm      904:        evbuffer_add(ctx->cmdclient->stdout_data, "\n", 1);
                    905:        server_push_stdout(ctx->cmdclient);
1.1       nicm      906: }
                    907:
                    908: /* Handle command message. */
                    909: void
                    910: server_client_msg_command(struct client *c, struct msg_command_data *data)
                    911: {
1.88      nicm      912:        struct cmd_ctx  *ctx;
1.36      nicm      913:        struct cmd_list *cmdlist = NULL;
                    914:        int              argc;
                    915:        char           **argv, *cause;
1.1       nicm      916:
1.90      nicm      917:        ctx = cmd_get_ctx(c, NULL);
1.88      nicm      918:        ctx->msgdata = data;
                    919:        ctx->error = server_client_msg_error;
                    920:        ctx->print = server_client_msg_print;
                    921:        ctx->info = server_client_msg_info;
1.1       nicm      922:
                    923:        argc = data->argc;
                    924:        data->argv[(sizeof data->argv) - 1] = '\0';
                    925:        if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) {
1.88      nicm      926:                server_client_msg_error(ctx, "command too long");
1.1       nicm      927:                goto error;
                    928:        }
                    929:
                    930:        if (argc == 0) {
                    931:                argc = 1;
                    932:                argv = xcalloc(1, sizeof *argv);
                    933:                *argv = xstrdup("new-session");
                    934:        }
                    935:
                    936:        if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
1.88      nicm      937:                server_client_msg_error(ctx, "%s", cause);
1.1       nicm      938:                cmd_free_argv(argc, argv);
                    939:                goto error;
                    940:        }
                    941:        cmd_free_argv(argc, argv);
                    942:
1.88      nicm      943:        switch (cmd_list_exec(cmdlist, ctx))
1.78      nicm      944:        {
                    945:        case CMD_RETURN_ERROR:
                    946:        case CMD_RETURN_NORMAL:
1.36      nicm      947:                c->flags |= CLIENT_EXIT;
1.78      nicm      948:                break;
                    949:        case CMD_RETURN_ATTACH:
                    950:        case CMD_RETURN_YIELD:
                    951:                break;
                    952:        }
1.1       nicm      953:        cmd_list_free(cmdlist);
1.88      nicm      954:        cmd_free_ctx(ctx);
1.1       nicm      955:        return;
                    956:
                    957: error:
                    958:        if (cmdlist != NULL)
                    959:                cmd_list_free(cmdlist);
1.88      nicm      960:        cmd_free_ctx(ctx);
                    961:
1.36      nicm      962:        c->flags |= CLIENT_EXIT;
1.1       nicm      963: }
                    964:
                    965: /* Handle identify message. */
                    966: void
                    967: server_client_msg_identify(
                    968:     struct client *c, struct msg_identify_data *data, int fd)
                    969: {
                    970:        c->cwd = NULL;
                    971:        data->cwd[(sizeof data->cwd) - 1] = '\0';
                    972:        if (*data->cwd != '\0')
                    973:                c->cwd = xstrdup(data->cwd);
1.75      nicm      974:
                    975:        if (data->flags & IDENTIFY_CONTROL) {
                    976:                c->stdin_callback = control_callback;
1.86      nicm      977:                c->flags |= CLIENT_CONTROL;
1.79      nicm      978:                server_write_client(c, MSG_STDIN, NULL, 0);
1.75      nicm      979:
                    980:                c->tty.fd = -1;
                    981:                c->tty.log_fd = -1;
                    982:
                    983:                close(fd);
                    984:                return;
                    985:        }
1.1       nicm      986:
1.80      nicm      987:        if (!isatty(fd)) {
                    988:                close(fd);
                    989:                return;
                    990:        }
1.1       nicm      991:        data->term[(sizeof data->term) - 1] = '\0';
1.74      nicm      992:        tty_init(&c->tty, c, fd, data->term);
1.1       nicm      993:        if (data->flags & IDENTIFY_UTF8)
                    994:                c->tty.flags |= TTY_UTF8;
                    995:        if (data->flags & IDENTIFY_256COLOURS)
                    996:                c->tty.term_flags |= TERM_256COLOURS;
                    997:        else if (data->flags & IDENTIFY_88COLOURS)
                    998:                c->tty.term_flags |= TERM_88COLOURS;
                    999:
                   1000:        tty_resize(&c->tty);
                   1001:
1.86      nicm     1002:        if (!(data->flags & IDENTIFY_CONTROL))
                   1003:                c->flags |= CLIENT_TERMINAL;
1.1       nicm     1004: }
                   1005:
                   1006: /* Handle shell message. */
                   1007: void
                   1008: server_client_msg_shell(struct client *c)
                   1009: {
                   1010:        struct msg_shell_data    data;
                   1011:        const char              *shell;
1.25      nicm     1012:
1.1       nicm     1013:        shell = options_get_string(&global_s_options, "default-shell");
                   1014:
                   1015:        if (*shell == '\0' || areshell(shell))
                   1016:                shell = _PATH_BSHELL;
                   1017:        if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell)
                   1018:                strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell);
1.25      nicm     1019:
1.1       nicm     1020:        server_write_client(c, MSG_SHELL, &data, sizeof data);
                   1021:        c->flags |= CLIENT_BAD; /* it will die after exec */
                   1022: }