2013-06-02 05:16:06 +02:00
|
|
|
#include "tmate.h"
|
|
|
|
|
|
|
|
static int msgpack_write(void *data, const char *buf, unsigned int len)
|
|
|
|
{
|
|
|
|
struct tmate_encoder *encoder = data;
|
|
|
|
|
|
|
|
evbuffer_add(encoder->buffer, buf, len);
|
|
|
|
|
|
|
|
if ((encoder->ev_readable.ev_flags & EVLIST_INSERTED) &&
|
|
|
|
!(encoder->ev_readable.ev_flags & EVLIST_ACTIVE)) {
|
|
|
|
event_active(&encoder->ev_readable, EV_READ, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tmate_encoder_init(struct tmate_encoder *encoder)
|
|
|
|
{
|
|
|
|
msgpack_packer_init(&encoder->pk, encoder, &msgpack_write);
|
|
|
|
encoder->buffer = evbuffer_new();
|
|
|
|
}
|
|
|
|
|
|
|
|
#define msgpack_pack_string(pk, str) do { \
|
|
|
|
int __strlen = strlen(str); \
|
|
|
|
msgpack_pack_raw(pk, __strlen); \
|
|
|
|
msgpack_pack_raw_body(pk, str, __strlen); \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
#define pack(what, ...) msgpack_pack_##what(&tmate_encoder->pk, __VA_ARGS__)
|
|
|
|
|
|
|
|
void tmate_write_header(void)
|
|
|
|
{
|
|
|
|
pack(array, 2);
|
|
|
|
pack(int, TMATE_HEADER);
|
|
|
|
pack(int, TMATE_PROTOCOL_VERSION);
|
|
|
|
}
|
|
|
|
|
2013-06-12 08:53:44 +02:00
|
|
|
void tmate_sync_layout(void)
|
2013-06-02 05:16:06 +02:00
|
|
|
{
|
2013-06-12 08:53:44 +02:00
|
|
|
struct session *s;
|
|
|
|
struct winlink *wl;
|
|
|
|
struct window *w;
|
2013-06-02 05:16:06 +02:00
|
|
|
struct window_pane *wp;
|
|
|
|
int num_panes = 0;
|
2013-06-12 08:53:44 +02:00
|
|
|
int num_windows = 0;
|
2013-06-02 05:16:06 +02:00
|
|
|
int active_pane_id = -1;
|
2013-06-12 23:58:31 +02:00
|
|
|
int active_window_idx = -1;
|
2013-06-12 08:53:44 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We only allow one session, it makes our lives easier.
|
|
|
|
* Especially when the HTML5 client will come along.
|
2013-06-12 23:58:31 +02:00
|
|
|
* We make no distinction between a winlink and its window except
|
|
|
|
* that we send the winlink idx to draw the status bar properly.
|
2013-06-12 08:53:44 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
s = RB_MIN(sessions, &sessions);
|
|
|
|
if (!s)
|
|
|
|
return;
|
|
|
|
|
|
|
|
num_windows = 0;
|
|
|
|
RB_FOREACH(wl, winlinks, &s->windows) {
|
|
|
|
if (wl->window)
|
|
|
|
num_windows++;
|
|
|
|
}
|
2013-06-02 05:16:06 +02:00
|
|
|
|
2013-06-12 08:53:44 +02:00
|
|
|
if (!num_windows)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pack(array, 5);
|
|
|
|
pack(int, TMATE_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;
|
|
|
|
|
2013-06-12 23:58:31 +02:00
|
|
|
if (active_window_idx == -1)
|
|
|
|
active_window_idx = wl->idx;
|
|
|
|
|
2013-06-12 08:53:44 +02:00
|
|
|
pack(array, 4);
|
2013-06-12 23:58:31 +02:00
|
|
|
pack(int, wl->idx);
|
2013-06-12 08:53:44 +02:00
|
|
|
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)
|
|
|
|
active_pane_id = wp->id;
|
|
|
|
}
|
|
|
|
pack(int, active_pane_id);
|
|
|
|
}
|
2013-06-02 05:16:06 +02:00
|
|
|
|
2013-06-12 23:58:31 +02:00
|
|
|
if (s->curw)
|
|
|
|
active_window_idx = s->curw->idx;
|
2013-06-12 08:53:44 +02:00
|
|
|
|
2013-06-12 23:58:31 +02:00
|
|
|
pack(int, active_window_idx);
|
2013-06-02 05:16:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void tmate_pty_data(struct window_pane *wp, const char *buf, size_t len)
|
|
|
|
{
|
|
|
|
size_t max_write, to_write;
|
|
|
|
|
|
|
|
max_write = TMATE_MAX_MESSAGE_SIZE - 4;
|
|
|
|
while (len > 0) {
|
|
|
|
to_write = len < max_write ? len : max_write;
|
|
|
|
|
|
|
|
pack(array, 3);
|
|
|
|
pack(int, TMATE_PTY_DATA);
|
|
|
|
pack(int, wp->id);
|
|
|
|
pack(raw, to_write);
|
|
|
|
pack(raw_body, buf, to_write);
|
|
|
|
|
|
|
|
buf += to_write;
|
|
|
|
len -= to_write;
|
|
|
|
}
|
|
|
|
}
|
2013-06-12 04:45:33 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:09:43 +02:00
|
|
|
void tmate_exec_cmd(const char *cmd)
|
2013-06-12 04:45:33 +02:00
|
|
|
{
|
|
|
|
pack(array, 2);
|
2013-06-13 02:09:43 +02:00
|
|
|
pack(int, TMATE_EXEC_CMD);
|
2013-06-12 04:45:33 +02:00
|
|
|
pack(string, cmd);
|
|
|
|
}
|
2013-06-12 05:50:16 +02:00
|
|
|
|
2013-06-13 02:09:43 +02:00
|
|
|
void tmate_failed_cmd(int client_id, const char *cause)
|
|
|
|
{
|
|
|
|
pack(array, 3);
|
|
|
|
pack(int, TMATE_FAILED_CMD);
|
|
|
|
pack(int, client_id);
|
|
|
|
pack(string, cause);
|
|
|
|
}
|
|
|
|
|
2013-06-12 05:50:16 +02:00
|
|
|
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_STATUS);
|
|
|
|
pack(string, left);
|
|
|
|
pack(string, right);
|
|
|
|
|
|
|
|
free(old_left);
|
|
|
|
free(old_right);
|
|
|
|
old_left = xstrdup(left);
|
|
|
|
old_right = xstrdup(right);
|
|
|
|
}
|
2013-06-13 04:38:41 +02:00
|
|
|
|
|
|
|
void tmate_sync_copy_mode(struct window_pane *wp)
|
|
|
|
{
|
|
|
|
struct window_copy_mode_data *data = wp->modedata;
|
|
|
|
|
|
|
|
pack(array, 3);
|
|
|
|
pack(int, TMATE_SYNC_COPY_MODE);
|
|
|
|
|
|
|
|
pack(int, wp->id);
|
|
|
|
|
|
|
|
if (wp->mode != &window_copy_mode) {
|
|
|
|
pack(array, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pack(array, 5);
|
|
|
|
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
}
|