123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- #include "tmate.h"
- #include "tmate-protocol.h"
- #include "window-copy.h"
- #define pack(what, ...) _pack(&tmate_session.encoder, what, ##__VA_ARGS__)
- void tmate_write_header(void)
- {
- pack(array, 3);
- pack(int, TMATE_OUT_HEADER);
- pack(int, TMATE_PROTOCOL_VERSION);
- pack(string, VERSION);
- }
- void tmate_write_ready(void)
- {
- pack(array, 1);
- pack(int, TMATE_OUT_READY);
- }
- void tmate_sync_layout(void)
- {
- struct session *s;
- struct winlink *wl;
- struct window *w;
- struct window_pane *wp;
- int num_panes = 0;
- int num_windows = 0;
- int active_pane_id;
- int active_window_idx = -1;
- /*
- * TODO this can get a little heavy.
- * We are shipping the full layout whenever a window name changes,
- * that is, at every shell command.
- * Might be better to do something incremental.
- */
- /*
- * We only allow one session, it makes our lives easier.
- * Especially when the HTML5 client will come along.
- * We make no distinction between a winlink and its window except
- * that we send the winlink idx to draw the status bar properly.
- */
- s = RB_MIN(sessions, &sessions);
- if (!s)
- return;
- num_windows = 0;
- RB_FOREACH(wl, winlinks, &s->windows) {
- if (wl->window)
- num_windows++;
- }
- if (!num_windows)
- return;
- pack(array, 5);
- pack(int, TMATE_OUT_SYNC_LAYOUT);
- pack(int, s->sx);
- pack(int, s->sy);
- pack(array, num_windows);
- RB_FOREACH(wl, winlinks, &s->windows) {
- w = wl->window;
- if (!w)
- continue;
- w->tmate_last_sync_active_pane = NULL;
- active_pane_id = -1;
- if (active_window_idx == -1)
- active_window_idx = wl->idx;
- pack(array, 4);
- pack(int, wl->idx);
- pack(string, w->name);
- num_panes = 0;
- TAILQ_FOREACH(wp, &w->panes, entry)
- num_panes++;
- pack(array, num_panes);
- TAILQ_FOREACH(wp, &w->panes, entry) {
- pack(array, 5);
- pack(int, wp->id);
- pack(int, wp->sx);
- pack(int, wp->sy);
- pack(int, wp->xoff);
- pack(int, wp->yoff);
- if (wp == w->active) {
- w->tmate_last_sync_active_pane = wp;
- active_pane_id = wp->id;
- }
- }
- pack(int, active_pane_id);
- }
- if (s->curw)
- active_window_idx = s->curw->idx;
- pack(int, active_window_idx);
- }
- /* TODO add a buffer for pty_data ? */
- #define TMATE_MAX_PTY_SIZE (16*1024)
- void tmate_pty_data(struct window_pane *wp, const char *buf, size_t len)
- {
- size_t to_write;
- while (len > 0) {
- to_write = len < TMATE_MAX_PTY_SIZE ? len : TMATE_MAX_PTY_SIZE;
- pack(array, 3);
- pack(int, TMATE_OUT_PTY_DATA);
- pack(int, wp->id);
- pack(str, to_write);
- pack(str_body, buf, to_write);
- buf += to_write;
- len -= to_write;
- }
- }
- extern const struct cmd_entry cmd_bind_key_entry;
- extern const struct cmd_entry cmd_unbind_key_entry;
- extern const struct cmd_entry cmd_set_option_entry;
- extern const struct cmd_entry cmd_set_window_option_entry;
- static const struct cmd_entry *replicated_cmds[] = {
- &cmd_bind_key_entry,
- &cmd_unbind_key_entry,
- &cmd_set_option_entry,
- &cmd_set_window_option_entry,
- NULL
- };
- int tmate_should_replicate_cmd(const struct cmd_entry *cmd)
- {
- const struct cmd_entry **ptr;
- for (ptr = replicated_cmds; *ptr; ptr++)
- if (*ptr == cmd)
- return 1;
- return 0;
- }
- #define sc (&session->saved_tmux_cmds)
- #define SAVED_TMUX_CMD_INITIAL_SIZE 256
- static void __tmate_exec_cmd_args(int argc, const char **argv);
- static void append_saved_cmd(struct tmate_session *session,
- int argc, const char **argv)
- {
- if (!sc->cmds) {
- sc->capacity = SAVED_TMUX_CMD_INITIAL_SIZE;
- sc->cmds = xmalloc(sizeof(*sc->cmds) * sc->capacity);
- sc->tail = 0;
- }
- if (sc->tail == sc->capacity) {
- sc->capacity *= 2;
- sc->cmds = xrealloc(sc->cmds, sizeof(*sc->cmds) * sc->capacity);
- }
- sc->cmds[sc->tail].argc = argc;
- sc->cmds[sc->tail].argv = cmd_copy_argv(argc, (char **)argv);
- sc->tail++;
- }
- static void replay_saved_cmd(struct tmate_session *session)
- {
- unsigned int i;
- for (i = 0; i < sc->tail; i++)
- __tmate_exec_cmd_args(sc->cmds[i].argc, (const char **)sc->cmds[i].argv);
- }
- #undef sc
- struct args_entry {
- u_char flag;
- char *value;
- RB_ENTRY(args_entry) entry;
- };
- static void extract_cmd(struct cmd *cmd, int *_argc, char ***_argv)
- {
- struct args_entry *entry;
- struct args* args = cmd->args;
- int argc = 0;
- char **argv;
- int next = 0, i;
- argc++; /* cmd name */
- RB_FOREACH(entry, args_tree, &args->tree) {
- argc++;
- if (entry->value != NULL)
- argc++;
- }
- argc += args->argc;
- argv = xmalloc(sizeof(char *) * argc);
- argv[next++] = xstrdup(cmd->entry->name);
- RB_FOREACH(entry, args_tree, &args->tree) {
- xasprintf(&argv[next++], "-%c", entry->flag);
- if (entry->value != NULL)
- argv[next++] = xstrdup(entry->value);
- }
- for (i = 0; i < args->argc; i++)
- argv[next++] = xstrdup(args->argv[i]);
- *_argc = argc;
- *_argv = argv;
- }
- static void __tmate_exec_cmd_args(int argc, const char **argv)
- {
- int i;
- pack(array, argc + 1);
- pack(int, TMATE_OUT_EXEC_CMD);
- for (i = 0; i < argc; i++)
- pack(string, argv[i]);
- }
- void tmate_exec_cmd_args(int argc, const char **argv)
- {
- __tmate_exec_cmd_args(argc, argv);
- append_saved_cmd(&tmate_session, argc, argv);
- }
- void tmate_exec_cmd(struct cmd *cmd)
- {
- int argc;
- char **argv;
- extract_cmd(cmd, &argc, &argv);
- tmate_exec_cmd_args(argc, (const char **)argv);
- cmd_free_argv(argc, argv);
- }
- void tmate_failed_cmd(int client_id, const char *cause)
- {
- pack(array, 3);
- pack(int, TMATE_OUT_FAILED_CMD);
- pack(int, client_id);
- pack(string, cause);
- }
- void tmate_status(const char *left, const char *right)
- {
- static char *old_left, *old_right;
- if (old_left && !strcmp(old_left, left) &&
- old_right && !strcmp(old_right, right))
- return;
- pack(array, 3);
- pack(int, TMATE_OUT_STATUS);
- pack(string, left);
- pack(string, right);
- free(old_left);
- free(old_right);
- old_left = xstrdup(left);
- old_right = xstrdup(right);
- }
- void tmate_sync_copy_mode(struct window_pane *wp)
- {
- struct window_copy_mode_data *data = wp->modedata;
- pack(array, 3);
- pack(int, TMATE_OUT_SYNC_COPY_MODE);
- pack(int, wp->id);
- if (wp->mode != &window_copy_mode ||
- data->inputtype == WINDOW_COPY_PASSWORD) {
- pack(array, 0);
- return;
- }
- pack(array, 6);
- pack(int, data->backing == &wp->base);
- pack(int, data->oy);
- pack(int, data->cx);
- pack(int, data->cy);
- if (data->screen.sel.flag) {
- pack(array, 3);
- pack(int, data->selx);
- pack(int, -data->sely + screen_hsize(data->backing)
- + screen_size_y(data->backing) - 1);
- pack(int, data->rectflag);
- } else
- pack(array, 0);
- if (data->inputprompt) {
- pack(array, 3);
- pack(int, data->inputtype);
- pack(string, data->inputprompt);
- pack(string, data->inputstr);
- } else
- pack(array, 0);
- }
- void tmate_write_copy_mode(struct window_pane *wp, const char *str)
- {
- pack(array, 3);
- pack(int, TMATE_OUT_WRITE_COPY_MODE);
- pack(int, wp->id);
- pack(string, str);
- }
- void tmate_write_fin(void)
- {
- pack(array, 1);
- pack(int, TMATE_OUT_FIN);
- }
- static void do_snapshot_grid(struct grid *grid, unsigned int max_history_lines)
- {
- struct grid_line *line;
- struct grid_cell gc;
- unsigned int line_i, i;
- unsigned int max_lines;
- size_t str_len;
- max_lines = max_history_lines + grid->sy;
- #define grid_num_lines(grid) (grid->hsize + grid->sy)
- if (grid_num_lines(grid) > max_lines)
- line_i = grid_num_lines(grid) - max_lines;
- else
- line_i = 0;
- pack(array, grid_num_lines(grid) - line_i);
- for (; line_i < grid_num_lines(grid); line_i++) {
- line = &grid->linedata[line_i];
- pack(array, 2);
- str_len = 0;
- for (i = 0; i < line->cellsize; i++) {
- grid_get_cell(grid, i, line_i, &gc);
- str_len += gc.data.size;
- }
- pack(str, str_len);
- for (i = 0; i < line->cellsize; i++) {
- grid_get_cell(grid, i, line_i, &gc);
- pack(str_body, gc.data.data, gc.data.size);
- }
- pack(array, line->cellsize);
- for (i = 0; i < line->cellsize; i++) {
- grid_get_cell(grid, i, line_i, &gc);
- pack(unsigned_int, ((gc.flags << 24) |
- (gc.attr << 16) |
- (gc.bg << 8) |
- gc.fg ));
- }
- }
- }
- static void do_snapshot_pane(struct window_pane *wp, unsigned int max_history_lines)
- {
- struct screen *screen = &wp->base;
- pack(array, 4);
- pack(int, wp->id);
- pack(unsigned_int, screen->mode);
- pack(array, 3);
- pack(int, screen->cx);
- pack(int, screen->cy);
- do_snapshot_grid(screen->grid, max_history_lines);
- if (wp->saved_grid) {
- pack(array, 3);
- pack(int, wp->saved_cx);
- pack(int, wp->saved_cy);
- do_snapshot_grid(wp->saved_grid, max_history_lines);
- } else {
- pack(nil);
- }
- }
- static void tmate_send_session_snapshot(unsigned int max_history_lines)
- {
- struct session *s;
- struct winlink *wl;
- struct window *w;
- struct window_pane *pane;
- int num_panes;
- pack(array, 2);
- pack(int, TMATE_OUT_SNAPSHOT);
- s = RB_MIN(sessions, &sessions);
- if (!s)
- tmate_fatal("no session?");
- num_panes = 0;
- RB_FOREACH(wl, winlinks, &s->windows) {
- w = wl->window;
- if (!w)
- continue;
- TAILQ_FOREACH(pane, &w->panes, entry)
- num_panes++;
- }
- pack(array, num_panes);
- RB_FOREACH(wl, winlinks, &s->windows) {
- w = wl->window;
- if (!w)
- continue;
- TAILQ_FOREACH(pane, &w->panes, entry)
- do_snapshot_pane(pane, max_history_lines);
- }
- }
- static void tmate_send_reconnection_data(struct tmate_session *session)
- {
- if (!session->reconnection_data)
- return;
- pack(array, 2);
- pack(int, TMATE_OUT_RECONNECT);
- pack(string, session->reconnection_data);
- }
- #define RECONNECTION_MAX_HISTORY_LINE 300
- void tmate_send_reconnection_state(struct tmate_session *session)
- {
- /* Start with a fresh encoder */
- tmate_encoder_destroy(&session->encoder);
- tmate_encoder_init(&session->encoder, NULL, session);
- tmate_write_header();
- tmate_send_reconnection_data(session);
- replay_saved_cmd(session);
- /* TODO send all option variables */
- tmate_write_ready();
- tmate_sync_layout();
- tmate_send_session_snapshot(RECONNECTION_MAX_HISTORY_LINE);
- }
|