diff --git a/Makefile b/Makefile index 043aedb9..80a3b003 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.3 2007-09-20 18:48:04 nicm Exp $ +# $Id: Makefile,v 1.4 2007-09-26 10:35:24 nicm Exp $ .SUFFIXES: .c .o .y .h .PHONY: clean @@ -16,8 +16,9 @@ DEBUG= # Command prefix. This will go when we get a configuration file... META?= \002 # C-b -SRCS= tmux.c server.c buffer.c buffer-poll.c xmalloc.c xmalloc-debug.c \ - input.c screen.c window.c session.c local.c log.c command.c +SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c \ + xmalloc.c xmalloc-debug.c input.c screen.c window.c session.c local.c \ + log.c command.c YACC= yacc -d diff --git a/server-fn.c b/server-fn.c new file mode 100644 index 00000000..1332d03d --- /dev/null +++ b/server-fn.c @@ -0,0 +1,162 @@ +/* $Id: server-fn.c,v 1.1 2007-09-26 10:35:24 nicm Exp $ */ + +/* + * Copyright (c) 2007 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include "tmux.h" + +/* Write command to a client. */ +void +write_client(struct client *c, u_int cmd, void *buf, size_t len) +{ + struct hdr hdr; + + hdr.type = cmd; + hdr.size = len; + + buffer_write(c->out, &hdr, sizeof hdr); + if (buf != NULL) + buffer_write(c->out, buf, len); +} + +/* Write command to a client with two buffers. */ +void +write_client2(struct client *c, + u_int cmd, void *buf1, size_t len1, void *buf2, size_t len2) +{ + struct hdr hdr; + + hdr.type = cmd; + hdr.size = len1 + len2; + + buffer_write(c->out, &hdr, sizeof hdr); + if (buf1 != NULL) + buffer_write(c->out, buf1, len1); + if (buf2 != NULL) + buffer_write(c->out, buf2, len2); +} + +/* Write command to all clients attached to a specific window. */ +void +write_clients(struct window *w, u_int cmd, void *buf, size_t len) +{ + struct client *c; + struct hdr hdr; + u_int i; + + hdr.type = cmd; + hdr.size = len; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL && c->session != NULL) { + if (c->session->window == w) { + buffer_write(c->out, &hdr, sizeof hdr); + if (buf != NULL) + buffer_write(c->out, buf, len); + } + } + } +} + +/* Changed client window. */ +void +changed_window(struct client *c) +{ + struct window *w; + + w = c->session->window; + if (c->sx != w->screen.sx || c->sy != w->screen.sy) + window_resize(w, c->sx, c->sy); + draw_client(c, 0, c->sy - 1); +} + +/* Draw window on client. */ +void +draw_client(struct client *c, u_int py_upper, u_int py_lower) +{ + struct hdr hdr; + size_t size; + + buffer_ensure(c->out, sizeof hdr); + buffer_add(c->out, sizeof hdr); + size = BUFFER_USED(c->out); + + screen_draw(&c->session->window->screen, c->out, py_upper, py_lower); + + size = BUFFER_USED(c->out) - size; + log_debug("redrawing screen, %zu bytes", size); + if (size != 0) { + hdr.type = MSG_OUTPUT; + hdr.size = size; + memcpy( + BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); + } else + buffer_reverse_add(c->out, sizeof hdr); +} + + +/* Write message command to a client. */ +void +write_message(struct client *c, const char *fmt, ...) +{ + struct hdr hdr; + va_list ap; + char *msg; + size_t size; + u_int i; + + buffer_ensure(c->out, sizeof hdr); + buffer_add(c->out, sizeof hdr); + size = BUFFER_USED(c->out); + + input_store_zero(c->out, CODE_CURSOROFF); + input_store_two(c->out, CODE_CURSORMOVE, c->sy, 1); + input_store_one(c->out, CODE_ATTRIBUTES, 2); + input_store16(c->out, 0); + input_store16(c->out, 7); + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); + buffer_write(c->out, msg, strlen(msg)); + for (i = strlen(msg); i < c->sx; i++) + input_store8(c->out, ' '); + xfree(msg); + + size = BUFFER_USED(c->out) - size; + hdr.type = MSG_OUTPUT; + hdr.size = size; + memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); + + hdr.type = MSG_PAUSE; + hdr.size = 0; + buffer_write(c->out, &hdr, sizeof hdr); + + buffer_ensure(c->out, sizeof hdr); + buffer_add(c->out, sizeof hdr); + size = BUFFER_USED(c->out); + + screen_draw(&c->session->window->screen, c->out, c->sy - 1, c->sy - 1); + + size = BUFFER_USED(c->out) - size; + hdr.type = MSG_OUTPUT; + hdr.size = size; + memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); +} diff --git a/server-msg.c b/server-msg.c new file mode 100644 index 00000000..8bf5af2a --- /dev/null +++ b/server-msg.c @@ -0,0 +1,420 @@ +/* $Id: server-msg.c,v 1.1 2007-09-26 10:35:24 nicm Exp $ */ + +/* + * Copyright (c) 2007 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include + +#include "tmux.h" + +void server_msg_fn_attach(struct client *, struct hdr *); +void server_msg_fn_create(struct client *, struct hdr *); +void server_msg_fn_input(struct client *, struct hdr *); +void server_msg_fn_last(struct client *, struct hdr *); +void server_msg_fn_new(struct client *, struct hdr *); +void server_msg_fn_next(struct client *, struct hdr *); +void server_msg_fn_previous(struct client *, struct hdr *); +void server_msg_fn_refresh(struct client *, struct hdr *); +void server_msg_fn_rename(struct client *, struct hdr *); +void server_msg_fn_select(struct client *, struct hdr *); +void server_msg_fn_sessions(struct client *, struct hdr *); +void server_msg_fn_size(struct client *, struct hdr *); +void server_msg_fn_windowlist(struct client *, struct hdr *); +void server_msg_fn_windows(struct client *, struct hdr *); + +struct server_msg { + enum hdrtype type; + + void (*fn)(struct client *, struct hdr *); +}; +struct server_msg server_msg_table[] = { + { MSG_ATTACH, server_msg_fn_attach }, + { MSG_CREATE, server_msg_fn_create }, + { MSG_INPUT, server_msg_fn_input }, + { MSG_LAST, server_msg_fn_last }, + { MSG_NEW, server_msg_fn_new }, + { MSG_NEXT, server_msg_fn_next }, + { MSG_PREVIOUS, server_msg_fn_previous }, + { MSG_REFRESH, server_msg_fn_refresh }, + { MSG_RENAME, server_msg_fn_rename }, + { MSG_SELECT, server_msg_fn_select }, + { MSG_SESSIONS, server_msg_fn_sessions }, + { MSG_SIZE, server_msg_fn_size }, + { MSG_WINDOWLIST, server_msg_fn_windowlist }, + { MSG_WINDOWS, server_msg_fn_windows }, +}; +#define NSERVERMSG (sizeof server_msg_table / sizeof server_msg_table[0]) + +void +server_msg_dispatch(struct client *c) +{ + struct hdr hdr; + struct server_msg *msg; + u_int i; + + if (BUFFER_USED(c->in) < sizeof hdr) + return; + memcpy(&hdr, BUFFER_OUT(c->in), sizeof hdr); + if (BUFFER_USED(c->in) < (sizeof hdr) + hdr.size) + return; + buffer_remove(c->in, sizeof hdr); + + for (i = 0; i < NSERVERMSG; i++) { + msg = server_msg_table + i; + if (msg->type == hdr.type) { + msg->fn(c, &hdr); + return; + } + } + + fatalx("unexpected message"); +} + +/* New message from client. */ +void +server_msg_fn_new(struct client *c, struct hdr *hdr) +{ + struct new_data data; + const char *shell; + char *cmd, *msg; + + if (c->session != NULL) + return; + if (hdr->size != sizeof data) + fatalx("bad MSG_NEW size"); + buffer_read(c->in, &data, hdr->size); + + c->sx = data.sx; + if (c->sx == 0) + c->sx = 80; + c->sy = data.sy; + if (c->sy == 0) + c->sy = 25; + + if (*data.name != '\0' && session_find(data.name) != NULL) { + xasprintf(&msg, "duplicate session: %s", data.name); + write_client(c, MSG_READY, msg, strlen(msg)); + xfree(msg); + return; + } + + shell = getenv("SHELL"); + if (shell == NULL) + shell = "/bin/ksh"; + xasprintf(&cmd, "%s -l", shell); + c->session = session_create(data.name, cmd, c->sx, c->sy); + if (c->session == NULL) + fatalx("session_create failed"); + xfree(cmd); + + write_client(c, MSG_READY, NULL, 0); + draw_client(c, 0, c->sy - 1); +} + +/* Attach message from client. */ +void +server_msg_fn_attach(struct client *c, struct hdr *hdr) +{ + struct attach_data data; + char *msg; + + if (c->session != NULL) + return; + if (hdr->size != sizeof data) + fatalx("bad MSG_ATTACH size"); + buffer_read(c->in, &data, hdr->size); + + c->sx = data.sx; + if (c->sx == 0) + c->sx = 80; + c->sy = data.sy; + if (c->sy == 0) + c->sy = 25; + + if (*data.name != '\0') + c->session = session_find(data.name); + if (c->session == NULL) { + xasprintf(&msg, "session not found: %s", data.name); + write_client(c, MSG_READY, msg, strlen(msg)); + xfree(msg); + return; + } + + write_client(c, MSG_READY, NULL, 0); + draw_client(c, 0, c->sy - 1); +} + +/* Create message from client. */ +void +server_msg_fn_create(struct client *c, struct hdr *hdr) +{ + const char *shell; + char *cmd; + + if (c->session == NULL) + return; + if (hdr->size != 0) + fatalx("bad MSG_CREATE size"); + + shell = getenv("SHELL"); + if (shell == NULL) + shell = "/bin/ksh"; + xasprintf(&cmd, "%s -l", shell); + if (session_new(c->session, cmd, c->sx, c->sy) != 0) + fatalx("session_new failed"); + xfree(cmd); + + draw_client(c, 0, c->sy - 1); +} + +/* Next message from client. */ +void +server_msg_fn_next(struct client *c, struct hdr *hdr) +{ + if (c->session == NULL) + return; + if (hdr->size != 0) + fatalx("bad MSG_NEXT size"); + + if (session_next(c->session) == 0) + changed_window(c); + else + write_message(c, "No next window"); +} + +/* Previous message from client. */ +void +server_msg_fn_previous(struct client *c, struct hdr *hdr) +{ + if (c->session == NULL) + return; + if (hdr->size != 0) + fatalx("bad MSG_PREVIOUS size"); + + if (session_previous(c->session) == 0) + changed_window(c); + else + write_message(c, "No previous window"); +} + +/* Size message from client. */ +void +server_msg_fn_size(struct client *c, struct hdr *hdr) +{ + struct size_data data; + + if (c->session == NULL) + return; + if (hdr->size != sizeof data) + fatalx("bad MSG_SIZE size"); + buffer_read(c->in, &data, hdr->size); + + c->sx = data.sx; + if (c->sx == 0) + c->sx = 80; + c->sy = data.sy; + if (c->sy == 0) + c->sy = 25; + + if (window_resize(c->session->window, c->sx, c->sy) != 0) + draw_client(c, 0, c->sy - 1); +} + +/* Input message from client. */ +void +server_msg_fn_input(struct client *c, struct hdr *hdr) +{ + if (c->session == NULL) + return; + + window_input(c->session->window, c->in, hdr->size); +} + +/* Refresh message from client. */ +void +server_msg_fn_refresh(struct client *c, struct hdr *hdr) +{ + struct refresh_data data; + + if (c->session == NULL) + return; + if (hdr->size != 0 && hdr->size != sizeof data) + fatalx("bad MSG_REFRESH size"); + + draw_client(c, 0, c->sy - 1); +} + +/* Select message from client. */ +void +server_msg_fn_select(struct client *c, struct hdr *hdr) +{ + struct select_data data; + + if (c->session == NULL) + return; + if (hdr->size != sizeof data) + fatalx("bad MSG_SELECT size"); + buffer_read(c->in, &data, hdr->size); + + if (c->session == NULL) + return; + if (session_select(c->session, data.idx) == 0) + changed_window(c); + else + write_message(c, "Window %u not present", data.idx); +} + +/* Sessions message from client. */ +void +server_msg_fn_sessions(struct client *c, struct hdr *hdr) +{ + struct sessions_data data; + struct sessions_entry entry; + struct session *s; + u_int i, j; + + if (hdr->size != sizeof data) + fatalx("bad MSG_SESSIONS size"); + buffer_read(c->in, &data, hdr->size); + + data.sessions = 0; + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + if (ARRAY_ITEM(&sessions, i) != NULL) + data.sessions++; + } + write_client2(c, MSG_SESSIONS, + &data, sizeof data, NULL, data.sessions * sizeof entry); + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL) + continue; + strlcpy(entry.name, s->name, sizeof entry.name); + entry.tim = s->tim; + entry.windows = 0; + for (j = 0; j < ARRAY_LENGTH(&s->windows); j++) { + if (ARRAY_ITEM(&s->windows, j) != NULL) + entry.windows++; + } + buffer_write(c->out, &entry, sizeof entry); + } +} + +/* Windows message from client. */ +void +server_msg_fn_windows(struct client *c, struct hdr *hdr) +{ + struct windows_data data; + struct windows_entry entry; + struct session *s; + struct window *w; + u_int i; + + if (hdr->size != sizeof data) + fatalx("bad MSG_WINDOWS size"); + buffer_read(c->in, &data, hdr->size); + + s = session_find(data.name); + if (s == NULL) { + data.windows = 0; + write_client(c, MSG_WINDOWS, &data, sizeof data); + return; + } + + data.windows = 0; + for (i = 0; i < ARRAY_LENGTH(&s->windows); i++) { + if (ARRAY_ITEM(&windows, i) != NULL) + data.windows++; + } + write_client2(c, MSG_WINDOWS, + &data, sizeof data, NULL, data.windows * sizeof entry); + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + entry.idx = i; + strlcpy(entry.name, w->name, sizeof entry.name); + strlcpy(entry.title, w->screen.title, sizeof entry.title); + if (ttyname_r(w->fd, entry.tty, sizeof entry.tty) != 0) + *entry.tty = '\0'; + buffer_write(c->out, &entry, sizeof entry); + } +} + +/* Rename message from client. */ +void +server_msg_fn_rename(struct client *c, struct hdr *hdr) +{ + if (c->session == NULL) + return; + if (hdr->size != 0) + fatalx("bad MSG_RENAME size"); + + fatalx("not implemented"); +} + +/* Last window message from client */ +void +server_msg_fn_last(struct client *c, struct hdr *hdr) +{ + if (c->session == NULL) + return; + if (hdr->size != 0) + fatalx("bad MSG_LAST size"); + + if (session_last(c->session) == 0) + changed_window(c); + else + write_message(c, "No last window"); +} + +/* Window list message from client */ +void +server_msg_fn_windowlist(struct client *c, struct hdr *hdr) +{ + struct window *w; + char *buf; + size_t len, off; + u_int i; + + if (c->session == NULL) + return; + if (hdr->size != 0) + fatalx("bad MSG_WINDOWLIST size"); + + len = c->sx + 1; + buf = xmalloc(len); + off = 0; + + *buf = '\0'; + for (i = 0; i < ARRAY_LENGTH(&c->session->windows); i++) { + w = ARRAY_ITEM(&c->session->windows, i); + if (w == NULL) + continue; + off += xsnprintf(buf + off, len - off, "%u:%s%s ", i, w->name, + w == c->session->window ? "*" : ""); + if (off >= len) + break; + } + + write_message(c, "%s", buf); + xfree(buf); +} diff --git a/server.c b/server.c index 253725a5..21a35f4f 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* $Id: server.c,v 1.11 2007-09-22 11:50:33 nicm Exp $ */ +/* $Id: server.c,v 1.12 2007-09-26 10:35:24 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -50,34 +50,7 @@ void fill_clients(struct pollfd **); void handle_clients(struct pollfd **); struct client *accept_client(int); void lost_client(struct client *); -void user_start(struct client *, const char *, const char *, - size_t, void (*)(struct client *, const char *)); -void user_input(struct client *, size_t); -void write_message(struct client *, const char *, ...); -void write_client(struct client *, u_int, void *, size_t); -void write_client2( - struct client *, u_int, void *, size_t, void *, size_t); -void write_clients(struct window *, u_int, void *, size_t); -void new_window(struct window *); -void lost_window(struct window *); -void changed_window(struct client *); -void draw_client(struct client *, u_int, u_int); -void process_client(struct client *); -void process_new_msg(struct client *, struct hdr *); -void process_attach_msg(struct client *, struct hdr *); -void process_create_msg(struct client *, struct hdr *); -void process_next_msg(struct client *, struct hdr *); -void process_previous_msg(struct client *, struct hdr *); -void process_select_msg(struct client *, struct hdr *); -void process_size_msg(struct client *, struct hdr *); -void process_input_msg(struct client *, struct hdr *); -void process_refresh_msg(struct client *, struct hdr *); -void process_sessions_msg(struct client *, struct hdr *); -void process_windows_msg(struct client *, struct hdr *); -void process_rename_msg(struct client *, struct hdr *); -void process_last_msg(struct client *, struct hdr *); -void process_windowlist_msg(struct client *, struct hdr *); -void rename_callback(struct client *, const char *); +void lost_window(struct window *); /* Fork and start server process. */ int @@ -302,7 +275,7 @@ handle_clients(struct pollfd *(*pfd)) if (buffer_poll((*pfd), c->in, c->out) != 0) lost_client(c); else - process_client(c); + server_msg_dispatch(c); } (*pfd)++; } @@ -334,7 +307,6 @@ accept_client(int srv_fd) c->in = buffer_create(BUFSIZ); c->out = buffer_create(BUFSIZ); c->session = NULL; - c->prompt = NULL; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { if (ARRAY_ITEM(&clients, i) == NULL) { @@ -363,302 +335,6 @@ lost_client(struct client *c) xfree(c); } -/* Write message command to a client. */ -void -write_message(struct client *c, const char *fmt, ...) -{ - struct hdr hdr; - va_list ap; - char *msg; - size_t size; - u_int i; - - buffer_ensure(c->out, sizeof hdr); - buffer_add(c->out, sizeof hdr); - size = BUFFER_USED(c->out); - - input_store_zero(c->out, CODE_CURSOROFF); - input_store_two(c->out, CODE_CURSORMOVE, c->sy, 1); - input_store_one(c->out, CODE_ATTRIBUTES, 2); - input_store16(c->out, 0); - input_store16(c->out, 7); - va_start(ap, fmt); - xvasprintf(&msg, fmt, ap); - va_end(ap); - buffer_write(c->out, msg, strlen(msg)); - for (i = strlen(msg); i < c->sx; i++) - input_store8(c->out, ' '); - xfree(msg); - - size = BUFFER_USED(c->out) - size; - hdr.type = MSG_OUTPUT; - hdr.size = size; - memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); - - hdr.type = MSG_PAUSE; - hdr.size = 0; - buffer_write(c->out, &hdr, sizeof hdr); - - buffer_ensure(c->out, sizeof hdr); - buffer_add(c->out, sizeof hdr); - size = BUFFER_USED(c->out); - - screen_draw(&c->session->window->screen, c->out, c->sy - 1, c->sy - 1); - - size = BUFFER_USED(c->out) - size; - hdr.type = MSG_OUTPUT; - hdr.size = size; - memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); -} - -/* Start user input. */ -void -user_start(struct client *c, const char *prompt, const char *now, - size_t len, void (*callback)(struct client *, const char *)) -{ - struct hdr hdr; - size_t size; - u_int i; - - c->callback = callback; - c->prompt = prompt; - - c->len = len; - if (c->len > c->sx - strlen(c->prompt)) - c->len = c->sx - strlen(c->prompt); - c->buf = xmalloc(c->len + 1); - strlcpy(c->buf, now, c->len + 1); - c->idx = strlen(c->buf); - - buffer_ensure(c->out, sizeof hdr); - buffer_add(c->out, sizeof hdr); - size = BUFFER_USED(c->out); - - input_store_zero(c->out, CODE_CURSOROFF); - input_store_two(c->out, CODE_CURSORMOVE, c->sy, 1); - input_store_one(c->out, CODE_ATTRIBUTES, 2); - input_store16(c->out, 0); - input_store16(c->out, 7); - - i = 0; - buffer_write(c->out, c->prompt, strlen(c->prompt)); - i += strlen(c->prompt); - if (*c->buf != '\0') { - buffer_write(c->out, c->buf, strlen(c->buf)); - i += strlen(c->buf); - } - for (; i < c->sx; i++) - input_store8(c->out, ' '); - - input_store_two(c->out, - CODE_CURSORMOVE, c->sy, 1 + strlen(c->prompt) + c->idx); - input_store_zero(c->out, CODE_CURSORON); - - size = BUFFER_USED(c->out) - size; - hdr.type = MSG_OUTPUT; - hdr.size = size; - memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); -} - -/* Handle user input. */ -void -user_input(struct client *c, size_t in) -{ - struct hdr hdr; - size_t size; - int key; - u_int i; - - buffer_ensure(c->out, sizeof hdr); - buffer_add(c->out, sizeof hdr); - size = BUFFER_USED(c->out); - - while (in != 0) { - if (in < 1) - break; - in--; - key = input_extract8(c->in); - if (key == '\e') { - if (in < 2) - fatalx("underflow"); - in -= 2; - key = (int16_t) input_extract16(c->in); - } - - again: - if (key == '\r') { - screen_draw(&c->session->window->screen, - c->out, c->sy - 1, c->sy - 1); - - c->callback(c, c->buf); - c->prompt = NULL; - xfree(c->buf); - break; - } - - switch (key) { - case KEYC_LEFT: - if (c->idx > 0) - c->idx--; - input_store_two(c->out, CODE_CURSORMOVE, - c->sy, 1 + strlen(c->prompt) + c->idx); - break; - case KEYC_RIGHT: - if (c->idx < strlen(c->buf)) - c->idx++; - input_store_two(c->out, CODE_CURSORMOVE, - c->sy, 1 + strlen(c->prompt) + c->idx); - break; - case KEYC_HOME: - c->idx = 0; - input_store_two(c->out, CODE_CURSORMOVE, - c->sy, 1 + strlen(c->prompt) + c->idx); - break; - case KEYC_LL: - c->idx = strlen(c->buf); - input_store_two(c->out, CODE_CURSORMOVE, - c->sy, 1 + strlen(c->prompt) + c->idx); - break; - case KEYC_BACKSPACE: - if (c->idx == 0) - break; - if (strlen(c->buf) == 0) - break; - if (c->idx == strlen(c->buf)) - c->buf[c->idx - 1] = '\0'; - else { - memmove(c->buf + c->idx - 1, - c->buf + c->idx, c->len - c->idx); - } - c->idx--; - input_store_one(c->out, CODE_CURSORLEFT, 1); - input_store_one(c->out, CODE_DELETECHARACTER, 1); - input_store_zero(c->out, CODE_CURSOROFF); - input_store_two(c->out, CODE_CURSORMOVE, c->sy, c->sx); - input_store8(c->out, ' '); - input_store_two(c->out, CODE_CURSORMOVE, - c->sy, 1 + strlen(c->prompt) + c->idx); - input_store_zero(c->out, CODE_CURSORON); - break; - case KEYC_DC: - if (strlen(c->buf) == 0) - break; - if (c->idx == strlen(c->buf)) - break; - memmove(c->buf + c->idx, - c->buf + c->idx + 1, c->len - c->idx - 1); - input_store_one(c->out, CODE_DELETECHARACTER, 1); - input_store_zero(c->out, CODE_CURSOROFF); - input_store_two(c->out,CODE_CURSORMOVE, c->sy, c->sx); - input_store8(c->out, ' '); - input_store_two(c->out, CODE_CURSORMOVE, - c->sy, 1 + strlen(c->prompt) + c->idx); - input_store_zero(c->out, CODE_CURSORON); - break; - default: - if (key >= ' ' && key != '\177') { - if (c->idx == c->len) - break; - if (strlen(c->buf) == c->len) - break; - memmove(c->buf + c->idx + 1, - c->buf + c->idx, c->len - c->idx); - c->buf[c->idx++] = key; - input_store_one( - c->out, CODE_INSERTCHARACTER, 1); - input_store8(c->out, key); - break; - } - switch (key) { - case '\001': - key = KEYC_HOME; - goto again; - case '\005': - key = KEYC_LL; - goto again; - case '\010': - key = KEYC_BACKSPACE; - goto again; - case '\177': - key = KEYC_DC; - goto again; - case '\013': - c->buf[c->idx + 1] = '\0'; - input_store_zero(c->out, CODE_CURSOROFF); - i = 1 + strlen(c->prompt) + c->idx; - for (; i < c->sx; i++) - input_store8(c->out, ' '); - input_store_two(c->out, CODE_CURSORMOVE, - c->sy, 1 + strlen(c->prompt) + c->idx); - input_store_zero(c->out, CODE_CURSORON); - break; - } - } - } - - size = BUFFER_USED(c->out) - size; - if (size != 0) { - hdr.type = MSG_OUTPUT; - hdr.size = size; - memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); - } else - buffer_reverse_add(c->out, sizeof hdr); -} - -/* Write command to a client. */ -void -write_client(struct client *c, u_int cmd, void *buf, size_t len) -{ - struct hdr hdr; - - hdr.type = cmd; - hdr.size = len; - - buffer_write(c->out, &hdr, sizeof hdr); - if (buf != NULL) - buffer_write(c->out, buf, len); -} - -/* Write command to a client with two buffers. */ -void -write_client2(struct client *c, - u_int cmd, void *buf1, size_t len1, void *buf2, size_t len2) -{ - struct hdr hdr; - - hdr.type = cmd; - hdr.size = len1 + len2; - - buffer_write(c->out, &hdr, sizeof hdr); - if (buf1 != NULL) - buffer_write(c->out, buf1, len1); - if (buf2 != NULL) - buffer_write(c->out, buf2, len2); -} - -/* Write command to all clients attached to a specific window. */ -void -write_clients(struct window *w, u_int cmd, void *buf, size_t len) -{ - struct client *c; - struct hdr hdr; - u_int i; - - hdr.type = cmd; - hdr.size = len; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c != NULL && c->session != NULL) { - if (c->session->window == w) { - buffer_write(c->out, &hdr, sizeof hdr); - if (buf != NULL) - buffer_write(c->out, buf, len); - } - } - } -} - /* Lost window: move clients on to next window. */ void lost_window(struct window *w) @@ -690,443 +366,3 @@ lost_window(struct window *w) } } -/* Changed client window. */ -void -changed_window(struct client *c) -{ - struct window *w; - - w = c->session->window; - if (c->sx != w->screen.sx || c->sy != w->screen.sy) - window_resize(w, c->sx, c->sy); - draw_client(c, 0, c->sy - 1); -} - -/* Draw window on client. */ -void -draw_client(struct client *c, u_int py_upper, u_int py_lower) -{ - struct hdr hdr; - size_t size; - - buffer_ensure(c->out, sizeof hdr); - buffer_add(c->out, sizeof hdr); - size = BUFFER_USED(c->out); - - screen_draw(&c->session->window->screen, c->out, py_upper, py_lower); - - size = BUFFER_USED(c->out) - size; - log_debug("redrawing screen, %zu bytes", size); - if (size != 0) { - hdr.type = MSG_OUTPUT; - hdr.size = size; - memcpy( - BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); - } else - buffer_reverse_add(c->out, sizeof hdr); -} - -/* Process a command from the client. */ -void -process_client(struct client *c) -{ - struct hdr hdr; - - if (BUFFER_USED(c->in) < sizeof hdr) - return; - memcpy(&hdr, BUFFER_OUT(c->in), sizeof hdr); - if (BUFFER_USED(c->in) < (sizeof hdr) + hdr.size) - return; - buffer_remove(c->in, sizeof hdr); - - switch (hdr.type) { - case MSG_NEW: - process_new_msg(c, &hdr); - break; - case MSG_ATTACH: - process_attach_msg(c, &hdr); - break; - case MSG_CREATE: - process_create_msg(c, &hdr); - break; - case MSG_NEXT: - process_next_msg(c, &hdr); - break; - case MSG_PREVIOUS: - process_previous_msg(c, &hdr); - break; - case MSG_SIZE: - process_size_msg(c, &hdr); - break; - case MSG_INPUT: - process_input_msg(c, &hdr); - break; - case MSG_REFRESH: - process_refresh_msg(c, &hdr); - break; - case MSG_SELECT: - process_select_msg(c, &hdr); - break; - case MSG_SESSIONS: - process_sessions_msg(c, &hdr); - break; - case MSG_WINDOWS: - process_windows_msg(c, &hdr); - break; - case MSG_RENAME: - process_rename_msg(c, &hdr); - break; - case MSG_LAST: - process_last_msg(c, &hdr); - break; - case MSG_WINDOWLIST: - process_windowlist_msg(c, &hdr); - break; - default: - fatalx("unexpected message"); - } -} - -/* New message from client. */ -void -process_new_msg(struct client *c, struct hdr *hdr) -{ - struct new_data data; - const char *shell; - char *cmd, *msg; - - if (c->session != NULL) - return; - if (hdr->size != sizeof data) - fatalx("bad MSG_NEW size"); - buffer_read(c->in, &data, hdr->size); - - c->sx = data.sx; - if (c->sx == 0) - c->sx = 80; - c->sy = data.sy; - if (c->sy == 0) - c->sy = 25; - - if (*data.name != '\0' && session_find(data.name) != NULL) { - xasprintf(&msg, "duplicate session: %s", data.name); - write_client(c, MSG_READY, msg, strlen(msg)); - xfree(msg); - return; - } - - shell = getenv("SHELL"); - if (shell == NULL) - shell = "/bin/ksh"; - xasprintf(&cmd, "%s -l", shell); - c->session = session_create(data.name, cmd, c->sx, c->sy); - if (c->session == NULL) - fatalx("session_create failed"); - xfree(cmd); - - write_client(c, MSG_READY, NULL, 0); - draw_client(c, 0, c->sy - 1); -} - -/* Attach message from client. */ -void -process_attach_msg(struct client *c, struct hdr *hdr) -{ - struct attach_data data; - char *msg; - - if (c->session != NULL) - return; - if (hdr->size != sizeof data) - fatalx("bad MSG_ATTACH size"); - buffer_read(c->in, &data, hdr->size); - - c->sx = data.sx; - if (c->sx == 0) - c->sx = 80; - c->sy = data.sy; - if (c->sy == 0) - c->sy = 25; - - if (*data.name != '\0') - c->session = session_find(data.name); - if (c->session == NULL) { - xasprintf(&msg, "session not found: %s", data.name); - write_client(c, MSG_READY, msg, strlen(msg)); - xfree(msg); - return; - } - - write_client(c, MSG_READY, NULL, 0); - draw_client(c, 0, c->sy - 1); -} - -/* Create message from client. */ -void -process_create_msg(struct client *c, struct hdr *hdr) -{ - const char *shell; - char *cmd; - - if (c->session == NULL) - return; - if (hdr->size != 0) - fatalx("bad MSG_CREATE size"); - - shell = getenv("SHELL"); - if (shell == NULL) - shell = "/bin/ksh"; - xasprintf(&cmd, "%s -l", shell); - if (session_new(c->session, cmd, c->sx, c->sy) != 0) - fatalx("session_new failed"); - xfree(cmd); - - draw_client(c, 0, c->sy - 1); -} - -/* Next message from client. */ -void -process_next_msg(struct client *c, struct hdr *hdr) -{ - if (c->session == NULL) - return; - if (hdr->size != 0) - fatalx("bad MSG_NEXT size"); - - if (session_next(c->session) == 0) - changed_window(c); - else - write_message(c, "No next window"); -} - -/* Previous message from client. */ -void -process_previous_msg(struct client *c, struct hdr *hdr) -{ - if (c->session == NULL) - return; - if (hdr->size != 0) - fatalx("bad MSG_PREVIOUS size"); - - if (session_previous(c->session) == 0) - changed_window(c); - else - write_message(c, "No previous window"); -} - -/* Size message from client. */ -void -process_size_msg(struct client *c, struct hdr *hdr) -{ - struct size_data data; - - if (c->session == NULL) - return; - if (hdr->size != sizeof data) - fatalx("bad MSG_SIZE size"); - buffer_read(c->in, &data, hdr->size); - - c->sx = data.sx; - if (c->sx == 0) - c->sx = 80; - c->sy = data.sy; - if (c->sy == 0) - c->sy = 25; - - if (window_resize(c->session->window, c->sx, c->sy) != 0) - draw_client(c, 0, c->sy - 1); -} - -/* Input message from client. */ -void -process_input_msg(struct client *c, struct hdr *hdr) -{ - if (c->session == NULL) - return; - - if (c->prompt == NULL) - window_input(c->session->window, c->in, hdr->size); - else - user_input(c, hdr->size); -} - -/* Refresh message from client. */ -void -process_refresh_msg(struct client *c, struct hdr *hdr) -{ - struct refresh_data data; - - if (c->session == NULL) - return; - if (hdr->size != 0 && hdr->size != sizeof data) - fatalx("bad MSG_REFRESH size"); - - draw_client(c, 0, c->sy - 1); -} - -/* Select message from client. */ -void -process_select_msg(struct client *c, struct hdr *hdr) -{ - struct select_data data; - - if (c->session == NULL) - return; - if (hdr->size != sizeof data) - fatalx("bad MSG_SELECT size"); - buffer_read(c->in, &data, hdr->size); - - if (c->session == NULL) - return; - if (session_select(c->session, data.idx) == 0) - changed_window(c); - else - write_message(c, "Window %u not present", data.idx); -} - -/* Sessions message from client. */ -void -process_sessions_msg(struct client *c, struct hdr *hdr) -{ - struct sessions_data data; - struct sessions_entry entry; - struct session *s; - u_int i, j; - - if (hdr->size != sizeof data) - fatalx("bad MSG_SESSIONS size"); - buffer_read(c->in, &data, hdr->size); - - data.sessions = 0; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - if (ARRAY_ITEM(&sessions, i) != NULL) - data.sessions++; - } - write_client2(c, MSG_SESSIONS, - &data, sizeof data, NULL, data.sessions * sizeof entry); - - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL) - continue; - strlcpy(entry.name, s->name, sizeof entry.name); - entry.tim = s->tim; - entry.windows = 0; - for (j = 0; j < ARRAY_LENGTH(&s->windows); j++) { - if (ARRAY_ITEM(&s->windows, j) != NULL) - entry.windows++; - } - buffer_write(c->out, &entry, sizeof entry); - } -} - -/* Windows message from client. */ -void -process_windows_msg(struct client *c, struct hdr *hdr) -{ - struct windows_data data; - struct windows_entry entry; - struct session *s; - struct window *w; - u_int i; - - if (hdr->size != sizeof data) - fatalx("bad MSG_WINDOWS size"); - buffer_read(c->in, &data, hdr->size); - - s = session_find(data.name); - if (s == NULL) { - data.windows = 0; - write_client(c, MSG_WINDOWS, &data, sizeof data); - return; - } - - data.windows = 0; - for (i = 0; i < ARRAY_LENGTH(&s->windows); i++) { - if (ARRAY_ITEM(&windows, i) != NULL) - data.windows++; - } - write_client2(c, MSG_WINDOWS, - &data, sizeof data, NULL, data.windows * sizeof entry); - - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - entry.idx = i; - strlcpy(entry.name, w->name, sizeof entry.name); - strlcpy(entry.title, w->screen.title, sizeof entry.title); - if (ttyname_r(w->fd, entry.tty, sizeof entry.tty) != 0) - *entry.tty = '\0'; - buffer_write(c->out, &entry, sizeof entry); - } -} - -/* Rename message from client. */ -void -process_rename_msg(struct client *c, struct hdr *hdr) -{ - if (c->session == NULL) - return; - if (hdr->size != 0) - fatalx("bad MSG_RENAME size"); - - user_start(c, "Window name: ", - c->session->window->name, MAXNAMELEN, rename_callback); -} - -/* Last window message from client */ -void -process_last_msg(struct client *c, struct hdr *hdr) -{ - if (c->session == NULL) - return; - if (hdr->size != 0) - fatalx("bad MSG_LAST size"); - - if (session_last(c->session) == 0) - changed_window(c); - else - write_message(c, "No last window"); -} - -/* Window list message from client */ -void -process_windowlist_msg(struct client *c, struct hdr *hdr) -{ - struct window *w; - char *buf; - size_t len, off; - u_int i; - - if (c->session == NULL) - return; - if (hdr->size != 0) - fatalx("bad MSG_WINDOWLIST size"); - - len = c->sx + 1; - buf = xmalloc(len); - off = 0; - - *buf = '\0'; - for (i = 0; i < ARRAY_LENGTH(&c->session->windows); i++) { - w = ARRAY_ITEM(&c->session->windows, i); - if (w == NULL) - continue; - off += xsnprintf(buf + off, len - off, "%u:%s%s ", i, w->name, - w == c->session->window ? "*" : ""); - if (off >= len) - break; - } - - write_message(c, "%s", buf); - xfree(buf); -} - -/* Callback for rename. */ -void -rename_callback(struct client *c, const char *string) -{ - strlcpy( - c->session->window->name, string, sizeof c->session->window->name); -} diff --git a/tmux.h b/tmux.h index 4745e5cf..cb10a3cf 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.10 2007-09-22 11:50:33 nicm Exp $ */ +/* $Id: tmux.h,v 1.11 2007-09-26 10:35:24 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -420,14 +420,6 @@ struct client { u_int sy; struct session *session; - - /* User input. */ - const char *prompt; - char *buf; - size_t len; - size_t idx; - void (*callback)(struct client *, const char *); - }; ARRAY_DECL(clients, struct client *); @@ -437,8 +429,21 @@ extern int debug_level; extern char socket_path[MAXPATHLEN]; /* server.c */ +extern struct clients clients; int server_start(void); +/* server-msg.c */ +void server_msg_dispatch(struct client *); + +/* server-fn.c */ +void write_message(struct client *, const char *, ...); +void write_client(struct client *, u_int, void *, size_t); +void write_client2( + struct client *, u_int, void *, size_t, void *, size_t); +void write_clients(struct window *, u_int, void *, size_t); +void changed_window(struct client *); +void draw_client(struct client *, u_int, u_int); + /* ansi.c */ void input_key(struct buffer *, int); size_t input_parse(u_char *, size_t, struct buffer *, struct screen *);