diff --git a/Makefile.am b/Makefile.am index e8b35802..fe520a01 100644 --- a/Makefile.am +++ b/Makefile.am @@ -178,6 +178,7 @@ dist_tmate_SOURCES = \ tmate-ssh-client.c \ tmate-encoder.c \ tmate-decoder.c \ + tmate-env.c \ tmate-msg.c \ tmate-session.c \ tmux.c \ diff --git a/cmd-wait-for.c b/cmd-wait-for.c index d40ba49e..ea36255d 100644 --- a/cmd-wait-for.c +++ b/cmd-wait-for.c @@ -23,6 +23,7 @@ #include #include "tmux.h" +#include "tmate.h" /* * Block or wake a client on a named wait channel. @@ -116,10 +117,44 @@ cmd_wait_for_signal(struct cmd_q *cmdq, const char *name, return (CMD_RETURN_NORMAL); } +#ifdef TMATE +void signal_waiting_clients(const char *name) +{ + struct wait_channel *wc, wc0; + struct cmd_q *wq, *wq1; + + wc0.name = name; + wc = RB_FIND(wait_channels, &wait_channels, &wc0); + + if (wc == NULL || TAILQ_EMPTY(&wc->waiters)) { + return; + } + + TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) { + TAILQ_REMOVE(&wc->waiters, wq, waitentry); + if (!cmdq_free(wq)) + cmdq_continue(wq); + } + + if (!wc->locked) { + RB_REMOVE(wait_channels, &wait_channels, wc); + free((void*) wc->name); + free(wc); + } +} +#endif + enum cmd_retval cmd_wait_for_wait(struct cmd_q *cmdq, const char *name, struct wait_channel *wc) { + +#ifdef TMATE + if (!strcmp(name, "tmate-ready") && tmate_session.decoder.ready) + return (CMD_RETURN_NORMAL); +#endif + + if (cmdq->client == NULL || cmdq->client->session != NULL) { cmdq_error(cmdq, "not able to wait"); return (CMD_RETURN_ERROR); diff --git a/format.c b/format.c index fa2dd0b2..4acae393 100644 --- a/format.c +++ b/format.c @@ -26,6 +26,7 @@ #include #include "tmux.h" +#include "tmate.h" /* * Build a list of key-value pairs and use them to expand #{key} entries in a @@ -214,6 +215,10 @@ format_expand(struct format_tree *ft, const char *fmt) size_t off, len, n; int ch; +#ifdef TMATE + tmate_format(ft); +#endif + len = 64; buf = xmalloc(len); off = 0; diff --git a/tmate-decoder.c b/tmate-decoder.c index 3e780dc5..7489d76f 100644 --- a/tmate-decoder.c +++ b/tmate-decoder.c @@ -148,7 +148,27 @@ out: free(cmd_str); } -static void handle_message(msgpack_object obj) +static void tmate_client_env(struct tmate_unpacker *uk) +{ + char *name = unpack_string(uk); + char *value = unpack_string(uk); + + tmate_set_env(name, value); + + free(name); + free(value); +} + + +extern void signal_waiting_clients(const char *name); +static void tmate_client_ready(struct tmate_decoder *decoder, + struct tmate_unpacker *uk) +{ + decoder->ready = 1; + signal_waiting_clients("tmate-ready"); +} + +static void handle_message(struct tmate_decoder *decoder, msgpack_object obj) { struct tmate_unpacker _uk; struct tmate_unpacker *uk = &_uk; @@ -160,6 +180,8 @@ static void handle_message(msgpack_object obj) case TMATE_CLIENT_PANE_KEY: tmate_client_pane_key(uk); break; case TMATE_CLIENT_RESIZE: tmate_client_resize(uk); break; case TMATE_CLIENT_EXEC_CMD: tmate_client_exec_cmd(uk); break; + case TMATE_CLIENT_ENV: tmate_client_env(uk); break; + case TMATE_CLIENT_READY: tmate_client_ready(decoder, uk); break; default: decoder_error(); } } @@ -172,7 +194,7 @@ void tmate_decoder_commit(struct tmate_decoder *decoder, size_t len) msgpack_unpacked_init(&result); while (msgpack_unpacker_next(&decoder->unpacker, &result)) { - handle_message(result.data); + handle_message(decoder, result.data); } msgpack_unpacked_destroy(&result); @@ -199,4 +221,5 @@ void tmate_decoder_init(struct tmate_decoder *decoder) { if (!msgpack_unpacker_init(&decoder->unpacker, 2*TMATE_MAX_MESSAGE_SIZE)) tmate_fatal("cannot initialize the unpacker"); + decoder->ready = 0; } diff --git a/tmate-env.c b/tmate-env.c new file mode 100644 index 00000000..92abf069 --- /dev/null +++ b/tmate-env.c @@ -0,0 +1,36 @@ +#include "tmate.h" + +struct tmate_env { + TAILQ_ENTRY(tmate_env) entry; + char *name; + char *value; +}; + +TAILQ_HEAD(, tmate_env) tmate_env_list; + +void tmate_set_env(const char *name, const char *value) +{ + struct tmate_env *tmate_env; + + TAILQ_FOREACH(tmate_env, &tmate_env_list, entry) { + if (!strcmp(tmate_env->name, name)) { + free(tmate_env->value); + tmate_env->value = xstrdup(value); + return; + } + } + + tmate_env = xmalloc(sizeof(*tmate_env)); + tmate_env->name = xstrdup(name); + tmate_env->value = xstrdup(value); + TAILQ_INSERT_HEAD(&tmate_env_list, tmate_env, entry); +} + +void tmate_format(struct format_tree *ft) +{ + struct tmate_env *tmate_env; + + TAILQ_FOREACH(tmate_env, &tmate_env_list, entry) { + format_add(ft, tmate_env->name, "%s", tmate_env->value); + } +} diff --git a/tmate.h b/tmate.h index ab202cf7..344015d1 100644 --- a/tmate.h +++ b/tmate.h @@ -18,7 +18,7 @@ #define TMATE_MAX_MESSAGE_SIZE (16*1024) -#define TMATE_PROTOCOL_VERSION 3 +#define TMATE_PROTOCOL_VERSION 4 enum tmate_commands { TMATE_HEADER, @@ -56,10 +56,13 @@ enum tmate_client_commands { TMATE_CLIENT_PANE_KEY, TMATE_CLIENT_RESIZE, TMATE_CLIENT_EXEC_CMD, + TMATE_CLIENT_ENV, + TMATE_CLIENT_READY, }; struct tmate_decoder { struct msgpack_unpacker unpacker; + int ready; }; extern int tmate_sx; @@ -147,4 +150,10 @@ extern void tmate_catch_sigsegv(void); extern void __tmate_status_message(const char *fmt, va_list ap); extern void printflike1 tmate_status_message(const char *fmt, ...); +/* tmate-env.c */ + +extern int tmate_has_received_env(void); +extern void tmate_set_env(const char *name, const char *value); +extern void tmate_format(struct format_tree *ft); + #endif