diff options
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | client-cmd.c | 108 | ||||
| -rw-r--r-- | client-msg.c | 99 | ||||
| -rw-r--r-- | client.c | 251 | ||||
| -rw-r--r-- | command.c | 113 | ||||
| -rw-r--r-- | op-list.c | 126 | ||||
| -rw-r--r-- | op.c | 64 | ||||
| -rw-r--r-- | server-msg.c | 190 | ||||
| -rw-r--r-- | server.c | 54 | ||||
| -rw-r--r-- | tmux.c | 578 | ||||
| -rw-r--r-- | tmux.h | 58 |
11 files changed, 913 insertions, 732 deletions
@@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.4 2007-09-26 10:35:24 nicm Exp $ +# $Id: Makefile,v 1.5 2007-09-26 13:43:14 nicm Exp $ .SUFFIXES: .c .o .y .h .PHONY: clean @@ -18,7 +18,7 @@ META?= \002 # C-b 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 + log.c client.c client-msg.c client-cmd.c op.c YACC= yacc -d diff --git a/client-cmd.c b/client-cmd.c new file mode 100644 index 00000000..998fee2c --- /dev/null +++ b/client-cmd.c @@ -0,0 +1,108 @@ +/* $Id: client-cmd.c,v 1.1 2007-09-26 13:43:14 nicm Exp $ */ + +/* + * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> + * + * 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 <sys/types.h> + +#include "tmux.h" + +int client_cmd_prefix = META; + +int client_cmd_fn_select(int, struct client_ctx *, const char **); +int client_cmd_fn_detach(int, struct client_ctx *, const char **); +int client_cmd_fn_msg(int, struct client_ctx *, const char **); + +struct cmd { + int key; + int (*fn)(int, struct client_ctx *, const char **); + int arg; +}; + +struct cmd client_cmd_table[] = { + { '0', client_cmd_fn_select, 0 }, + { '1', client_cmd_fn_select, 1 }, + { '2', client_cmd_fn_select, 2 }, + { '3', client_cmd_fn_select, 3 }, + { '4', client_cmd_fn_select, 4 }, + { '5', client_cmd_fn_select, 5 }, + { '6', client_cmd_fn_select, 6 }, + { '7', client_cmd_fn_select, 7 }, + { '8', client_cmd_fn_select, 8 }, + { '9', client_cmd_fn_select, 9 }, + { 'C', client_cmd_fn_msg, MSG_CREATE }, + { 'c', client_cmd_fn_msg, MSG_CREATE }, + { 'D', client_cmd_fn_detach, 0 }, + { 'd', client_cmd_fn_detach, 0 }, + { 'N', client_cmd_fn_msg, MSG_NEXT }, + { 'n', client_cmd_fn_msg, MSG_NEXT }, + { 'P', client_cmd_fn_msg, MSG_PREVIOUS }, + { 'p', client_cmd_fn_msg, MSG_PREVIOUS }, + { 'R', client_cmd_fn_msg, MSG_REFRESH }, + { 'r', client_cmd_fn_msg, MSG_REFRESH }, + { 'T', client_cmd_fn_msg, MSG_RENAME }, + { 't', client_cmd_fn_msg, MSG_RENAME }, + { 'L', client_cmd_fn_msg, MSG_LAST }, + { 'l', client_cmd_fn_msg, MSG_LAST }, + { 'W', client_cmd_fn_msg, MSG_WINDOWLIST }, + { 'w', client_cmd_fn_msg, MSG_WINDOWLIST } +}; +#define NCLIENTCMD (sizeof client_cmd_table / sizeof client_cmd_table[0]) + +/* Dispatch to a command. */ +int +client_cmd_dispatch(int key, struct client_ctx *cctx, const char **error) +{ + struct cmd *cmd; + u_int i; + + for (i = 0; i < NCLIENTCMD; i++) { + cmd = client_cmd_table + i; + if (cmd->key == key) + return (cmd->fn(cmd->arg, cctx, error)); + } + return (0); +} + +/* Handle generic command. */ +int +client_cmd_fn_msg(int arg, struct client_ctx *cctx, unused const char **error) +{ + client_write_server(cctx, arg, NULL, 0); + + return (0); +} + +/* Handle select command. */ +int +client_cmd_fn_select( + int arg, struct client_ctx *cctx, unused const char **error) +{ + struct select_data data; + + data.idx = arg; + client_write_server(cctx, MSG_SELECT, &data, sizeof data); + + return (0); +} + +/* Handle detach command. */ +int +client_cmd_fn_detach( + unused int arg, unused struct client_ctx *cctx, unused const char **error) +{ + return (-1); +} diff --git a/client-msg.c b/client-msg.c new file mode 100644 index 00000000..6639d915 --- /dev/null +++ b/client-msg.c @@ -0,0 +1,99 @@ +/* $Id: client-msg.c,v 1.1 2007-09-26 13:43:14 nicm Exp $ */ + +/* + * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> + * + * 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 <sys/types.h> + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "tmux.h" + +int client_msg_fn_output(struct hdr *, struct client_ctx *, const char **); +int client_msg_fn_pause(struct hdr *, struct client_ctx *, const char **); +int client_msg_fn_exit(struct hdr *, struct client_ctx *, const char **); + +struct client_msg { + enum hdrtype type; + + int (*fn)(struct hdr *, struct client_ctx *, const char **); +}; +struct client_msg client_msg_table[] = { + { MSG_OUTPUT, client_msg_fn_output }, + { MSG_PAUSE, client_msg_fn_pause }, + { MSG_EXIT, client_msg_fn_exit }, +}; +#define NCLIENTMSG (sizeof client_msg_table / sizeof client_msg_table[0]) + +int +client_msg_dispatch(struct client_ctx *cctx, const char **error) +{ + struct hdr hdr; + struct client_msg *msg; + u_int i; + int n; + + for (;;) { + if (BUFFER_USED(cctx->srv_in) < sizeof hdr) + return (0); + memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr); + if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size) + return (0); + buffer_remove(cctx->srv_in, sizeof hdr); + + for (i = 0; i < NCLIENTMSG; i++) { + msg = client_msg_table + i; + if (msg->type == hdr.type) { + if ((n = msg->fn(&hdr, cctx, error)) != 0) + return (n); + break; + } + } + if (i == NCLIENTMSG) + fatalx("unexpected message"); + } +} + +/* Output message from client. */ +int +client_msg_fn_output( + struct hdr *hdr, struct client_ctx *cctx, unused const char **error) +{ + local_output(cctx->srv_in, hdr->size); + return (0); +} + +/* Pause message from server. */ +int +client_msg_fn_pause( + struct hdr *hdr, unused struct client_ctx *cctx, unused const char **error) +{ + if (hdr->size != 0) + fatalx("bad MSG_PAUSE size"); + return (1); +} + +/* Exit message from server. */ +int +client_msg_fn_exit( + struct hdr *hdr, unused struct client_ctx *cctx, unused const char **error) +{ + if (hdr->size != 0) + fatalx("bad MSG_EXIT size"); + return (-1); +} diff --git a/client.c b/client.c new file mode 100644 index 00000000..8c120aa6 --- /dev/null +++ b/client.c @@ -0,0 +1,251 @@ +/* $Id: client.c,v 1.1 2007-09-26 13:43:15 nicm Exp $ */ + +/* + * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> + * + * 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 <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> + +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> + +#include "tmux.h" + +void client_handle_winch(struct client_ctx *); +int client_process_local(struct client_ctx *, const char **); + +int +client_init(char *path, struct client_ctx *cctx, int ws) +{ + struct sockaddr_un sa; + struct stat sb; + size_t sz; + int mode; + + if (path == NULL) { + xasprintf(&path, + "%s/%s-%lu", _PATH_TMP, __progname, (u_long) getuid()); + } + +retry: + if (stat(path, &sb) != 0) { + if (errno != ENOENT) { + log_warn("%s", path); + return (-1); + } + if (server_start(path) != 0) + return (-1); + sleep(1); /* XXX */ + goto retry; + } + if (!S_ISSOCK(sb.st_mode)) { + log_warnx("%s: %s", path, strerror(ENOTSOCK)); + return (-1); + } + + if (ws) { + if (!isatty(STDIN_FILENO)) { + log_warnx("stdin is not a tty"); + return (-1); + } + if (!isatty(STDOUT_FILENO)) { + log_warnx("stdout is not a tty"); + return (-1); + } + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &cctx->ws) == -1) { + log_warn("ioctl(TIOCGWINSZ)"); + return (-1); + } + } + + memset(&sa, 0, sizeof sa); + sa.sun_family = AF_UNIX; + sz = strlcpy(sa.sun_path, path, sizeof sa.sun_path); + if (sz >= sizeof sa.sun_path) { + log_warnx("%s: %s", path, strerror(ENAMETOOLONG)); + return (-1); + } + + if ((cctx->srv_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + log_warn("%s: socket", path); + return (-1); + } + if (connect( + cctx->srv_fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { + log_warn("%s: connect", path); + return (-1); + } + + if ((mode = fcntl(cctx->srv_fd, F_GETFL)) == -1) { + log_warn("%s: fcntl", path); + return (-1); + } + if (fcntl(cctx->srv_fd, F_SETFL, mode|O_NONBLOCK) == -1) { + log_warn("%s: fcntl", path); + return (-1); + } + cctx->srv_in = buffer_create(BUFSIZ); + cctx->srv_out = buffer_create(BUFSIZ); + + return (0); +} + +int +client_main(struct client_ctx *cctx) +{ + struct pollfd pfds[2]; + const char *error; + int n; + + logfile("client"); + setproctitle("client"); + + siginit(); + if ((cctx->loc_fd = local_init(&cctx->loc_in, &cctx->loc_out)) == -1) + return (1); + + n = 0; + error = NULL; + while (!sigterm) { + if (sigwinch) + client_handle_winch(cctx); + + pfds[0].fd = cctx->srv_fd; + pfds[0].events = POLLIN; + if (BUFFER_USED(cctx->srv_out) > 0) + pfds[0].events |= POLLOUT; + pfds[1].fd = cctx->loc_fd; + pfds[1].events = POLLIN; + if (BUFFER_USED(cctx->loc_out) > 0) + pfds[1].events |= POLLOUT; + + if (poll(pfds, 2, INFTIM) == -1) { + if (errno == EAGAIN || errno == EINTR) + continue; + fatal("poll failed"); + } + + if (buffer_poll(&pfds[0], cctx->srv_in, cctx->srv_out) != 0) + goto server_dead; + if (buffer_poll(&pfds[1], cctx->loc_in, cctx->loc_out) != 0) + goto local_dead; + + /* XXX Output flushed; pause if required. */ + if (n) + usleep(750000); + /* XXX XXX special return code for pause */ + if ((n = client_process_local(cctx, &error)) == -1) + break; + if ((n = client_msg_dispatch(cctx, &error)) == -1) + break; + } + + local_done(); + + if (sigterm) + error = "received SIGTERM"; + if (error != NULL) { + printf("[terminated: %s]\n", error); + return (0); + } + printf("[detached]\n"); + return (0); + +server_dead: + local_done(); + + printf("[lost server]\n"); + return (1); + +local_dead: + /* Can't do much here. Log and die. */ + fatalx("local socket dead"); +} + +void +client_write_server( + struct client_ctx *cctx, enum hdrtype type, void *buf, size_t len) +{ + struct hdr hdr; + + hdr.type = type; + hdr.size = len; + buffer_write(cctx->srv_out, &hdr, sizeof hdr); + if (len > 0) + buffer_write(cctx->srv_out, buf, len); +} + +void +client_handle_winch(struct client_ctx *cctx) +{ + struct size_data data; + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &cctx->ws) == -1) + fatal("ioctl failed"); + + data.sx = cctx->ws.ws_col; + data.sy = cctx->ws.ws_row; + client_write_server(cctx, MSG_SIZE, &data, sizeof data); + + sigwinch = 0; +} + +int +client_process_local(struct client_ctx *cctx, const char **error) +{ + struct buffer *b; + size_t size; + int n, key; + + n = 0; + b = buffer_create(BUFSIZ); + + while ((key = local_key(&size)) != KEYC_NONE) { + log_debug("key code: %d", key); + + if (key == client_cmd_prefix) { + if ((key = local_key(NULL)) == KEYC_NONE) { + /* XXX sux */ + buffer_reverse_remove(cctx->loc_in, size); + break; + } + n = client_cmd_dispatch(key, cctx, error); + break; + } + + input_store8(b, '\e'); + input_store16(b, (uint16_t) key /*XXX*/); + } + + log_debug("transmitting %zu bytes of input", BUFFER_USED(b)); + if (BUFFER_USED(b) == 0) { + buffer_destroy(b); + return (n); + } + client_write_server(cctx, MSG_INPUT, BUFFER_OUT(b), BUFFER_USED(b)); + buffer_destroy(b); + return (n); +} + diff --git a/command.c b/command.c deleted file mode 100644 index d07bd35f..00000000 --- a/command.c +++ /dev/null @@ -1,113 +0,0 @@ -/* $Id: command.c,v 1.7 2007-09-22 11:50:33 nicm Exp $ */ - -/* - * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> - * - * 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 <sys/types.h> - -#include "tmux.h" - -int cmd_prefix = META; - -int cmd_fn_select(struct buffer *, int); -int cmd_fn_detach(struct buffer *, int); -int cmd_fn_msg(struct buffer *, int); - -struct cmd { - int key; - int (*fn)(struct buffer *, int); - int arg; -}; - -struct cmd cmd_table[] = { - { '0', cmd_fn_select, 0 }, - { '1', cmd_fn_select, 1 }, - { '2', cmd_fn_select, 2 }, - { '3', cmd_fn_select, 3 }, - { '4', cmd_fn_select, 4 }, - { '5', cmd_fn_select, 5 }, - { '6', cmd_fn_select, 6 }, - { '7', cmd_fn_select, 7 }, - { '8', cmd_fn_select, 8 }, - { '9', cmd_fn_select, 9 }, - { 'C', cmd_fn_msg, MSG_CREATE }, - { 'c', cmd_fn_msg, MSG_CREATE }, - { 'D', cmd_fn_detach, 0 }, - { 'd', cmd_fn_detach, 0 }, - { 'N', cmd_fn_msg, MSG_NEXT }, - { 'n', cmd_fn_msg, MSG_NEXT }, - { 'P', cmd_fn_msg, MSG_PREVIOUS }, - { 'p', cmd_fn_msg, MSG_PREVIOUS }, - { 'R', cmd_fn_msg, MSG_REFRESH }, - { 'r', cmd_fn_msg, MSG_REFRESH }, - { 'T', cmd_fn_msg, MSG_RENAME }, - { 't', cmd_fn_msg, MSG_RENAME }, - { 'L', cmd_fn_msg, MSG_LAST }, - { 'l', cmd_fn_msg, MSG_LAST }, - { 'W', cmd_fn_msg, MSG_WINDOWLIST }, - { 'w', cmd_fn_msg, MSG_WINDOWLIST } -}; - -/* Dispatch to a command. */ -int -cmd_execute(int key, struct buffer *srv_out) -{ - struct cmd *cmd; - u_int i; - - for (i = 0; i < (sizeof cmd_table / sizeof cmd_table[0]); i++) { - cmd = cmd_table + i; - if (cmd->key == key) - return (cmd->fn(srv_out, cmd->arg)); - } - return (0); -} - -/* Handle generic command. */ -int -cmd_fn_msg(struct buffer *srv_out, int type) -{ - struct hdr hdr; - - hdr.type = type; - hdr.size = 0; - buffer_write(srv_out, &hdr, sizeof hdr); - - return (0); -} - -/* Handle select command. */ -int -cmd_fn_select(struct buffer *srv_out, int arg) -{ - struct hdr hdr; - struct select_data data; - - hdr.type = MSG_SELECT; - hdr.size = sizeof data; - buffer_write(srv_out, &hdr, sizeof hdr); - data.idx = arg; - buffer_write(srv_out, &data, sizeof data); - - return (0); -} - -/* Handle detach command. */ -int -cmd_fn_detach(unused struct buffer *srv_out, unused int arg) -{ - return (-1); -} diff --git a/op-list.c b/op-list.c new file mode 100644 index 00000000..e2f78efe --- /dev/null +++ b/op-list.c @@ -0,0 +1,126 @@ +/* $Id: op-list.c,v 1.1 2007-09-26 13:43:15 nicm Exp $ */ + +/* + * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> + * + * 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. + */ + +/* List sessions or windows. */ +void +op_list(char *name) +{ + struct sessions_data sd; + struct windows_data wd; + struct pollfd pfd; + struct hdr hdr; + + /* Send query data. */ + if (*name == '\0') { + hdr.type = MSG_SESSIONS; + hdr.size = sizeof sd; + buffer_write(server_out, &hdr, sizeof hdr); + buffer_write(server_out, &sd, hdr.size); + } else { + hdr.type = MSG_WINDOWS; + hdr.size = sizeof wd; + buffer_write(server_out, &hdr, sizeof hdr); + strlcpy(wd.name, name, sizeof wd.name); + buffer_write(server_out, &wd, hdr.size); + } + + /* Main loop. */ + for (;;) { + /* Set up pollfd. */ + pfd.fd = server_fd; + pfd.events = POLLIN; + if (BUFFER_USED(server_out) > 0) + pfd.events |= POLLOUT; + + /* Do the poll. */ + if (poll(&pfd, 1, INFTIM) == -1) { + if (errno == EAGAIN || errno == EINTR) + continue; + err(1, "poll"); + } + + /* Read/write from sockets. */ + if (buffer_poll(&pfd, server_in, server_out) != 0) + errx(1, "lost server"); + + /* Process data. */ + process_list(name); + } +} + +void +op_list_process(const char *name) +{ + struct sessions_data sd; + struct sessions_entry se; + struct windows_data wd; + struct windows_entry we; + struct hdr hdr; + char *tim; + + for (;;) { + if (BUFFER_USED(server_in) < sizeof hdr) + break; + memcpy(&hdr, BUFFER_OUT(server_in), sizeof hdr); + if (BUFFER_USED(server_in) < (sizeof hdr) + hdr.size) + break; + buffer_remove(server_in, sizeof hdr); + + switch (hdr.type) { + case MSG_SESSIONS: + if (hdr.size < sizeof sd) + errx(1, "bad MSG_SESSIONS size"); + buffer_read(server_in, &sd, sizeof sd); + hdr.size -= sizeof sd; + if (sd.sessions == 0 && hdr.size == 0) + exit(0); + if (hdr.size < sd.sessions * sizeof se) + errx(1, "bad MSG_SESSIONS size"); + while (sd.sessions-- > 0) { + buffer_read(server_in, &se, sizeof se); + tim = ctime(&se.tim); + *strchr(tim, '\n') = '\0'; + printf("%s: %u windows (created %s)\n", + se.name, se.windows, tim); + } + exit(0); + case MSG_WINDOWS: + if (hdr.size < sizeof wd) + errx(1, "bad MSG_WINDOWS size"); + buffer_read(server_in, &wd, sizeof wd); + hdr.size -= sizeof wd; + if (wd.windows == 0 && hdr.size == 0) + errx(1, "session not found: %s", name); + if (hdr.size < wd.windows * sizeof we) + errx(1, "bad MSG_WINDOWS size"); + while (wd.windows-- > 0) { + buffer_read(server_in, &we, sizeof we); + if (*we.title != '\0') { + printf("%u: %s \"%s\" (%s)\n", + we.idx, we.name, we.title, we.tty); + } else { + printf("%u: %s (%s)\n", + we.idx, we.name, we.tty); + } + } + exit(0); + default: + fatalx("unexpected message"); + } + } +} @@ -0,0 +1,64 @@ +/* $Id: op.c,v 1.1 2007-09-26 13:43:15 nicm Exp $ */ + +/* + * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> + * + * 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 <sys/types.h> + +#include <string.h> + +#include "tmux.h" + +int +op_new(char *path, int argc, unused char **argv) +{ + struct new_data data; + struct client_ctx cctx; + + if (argc != 0) /* XXX -n */ + return (usage("new")); + + if (client_init(path, &cctx, 1) != 0) + return (1); + + strlcpy(data.name, "XXX"/*XXX*/, sizeof data.name); + data.sx = cctx.ws.ws_col; + data.sy = cctx.ws.ws_row; + client_write_server(&cctx, MSG_NEW, &data, sizeof data); + + return (client_main(&cctx)); +} + +int +op_attach(char *path, int argc, unused char **argv) +{ + struct attach_data data; + struct client_ctx cctx; + + if (argc != 0) /* XXX -n */ + return (usage("attach")); + + if (client_init(path, &cctx, 1) != 0) + return (1); + + strlcpy(data.name, "XXX"/*XXX*/, sizeof data.name); + data.sx = cctx.ws.ws_col; + data.sy = cctx.ws.ws_row; + client_write_server(&cctx, MSG_ATTACH, &data, sizeof data); + + return (client_main(&cctx)); +} + diff --git a/server-msg.c b/server-msg.c index 8bf5af2a..1c0de755 100644 --- a/server-msg.c +++ b/server-msg.c @@ -1,4 +1,4 @@ -/* $Id: server-msg.c,v 1.1 2007-09-26 10:35:24 nicm Exp $ */ +/* $Id: server-msg.c,v 1.2 2007-09-26 13:43:15 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -24,25 +24,25 @@ #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 *); +int server_msg_fn_attach(struct hdr *, struct client *); +int server_msg_fn_create(struct hdr *, struct client *); +int server_msg_fn_input(struct hdr *, struct client *); +int server_msg_fn_last(struct hdr *, struct client *); +int server_msg_fn_new(struct hdr *, struct client *); +int server_msg_fn_next(struct hdr *, struct client *); +int server_msg_fn_previous(struct hdr *, struct client *); +int server_msg_fn_refresh(struct hdr *, struct client *); +int server_msg_fn_rename(struct hdr *, struct client *); +int server_msg_fn_select(struct hdr *, struct client *); +int server_msg_fn_sessions(struct hdr *, struct client *); +int server_msg_fn_size(struct hdr *, struct client *); +int server_msg_fn_windowlist(struct hdr *, struct client *); +int server_msg_fn_windows(struct hdr *, struct client *); struct server_msg { enum hdrtype type; - void (*fn)(struct client *, struct hdr *); + int (*fn)(struct hdr *, struct client *); }; struct server_msg server_msg_table[] = { { MSG_ATTACH, server_msg_fn_attach }, @@ -62,41 +62,45 @@ struct server_msg server_msg_table[] = { }; #define NSERVERMSG (sizeof server_msg_table / sizeof server_msg_table[0]) -void +int 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; - } + int n; + + for (;;) { + if (BUFFER_USED(c->in) < sizeof hdr) + return (0); + memcpy(&hdr, BUFFER_OUT(c->in), sizeof hdr); + if (BUFFER_USED(c->in) < (sizeof hdr) + hdr.size) + return (0); + buffer_remove(c->in, sizeof hdr); + + for (i = 0; i < NSERVERMSG; i++) { + msg = server_msg_table + i; + if (msg->type == hdr.type) { + if ((n = msg->fn(&hdr, c)) != 0) + return (n); + break; + } + } + if (i == NSERVERMSG) + fatalx("unexpected message"); } - - fatalx("unexpected message"); } /* New message from client. */ -void -server_msg_fn_new(struct client *c, struct hdr *hdr) +int +server_msg_fn_new(struct hdr *hdr, struct client *c) { struct new_data data; const char *shell; char *cmd, *msg; if (c->session != NULL) - return; + return (0); if (hdr->size != sizeof data) fatalx("bad MSG_NEW size"); buffer_read(c->in, &data, hdr->size); @@ -110,9 +114,9 @@ server_msg_fn_new(struct client *c, struct hdr *hdr) if (*data.name != '\0' && session_find(data.name) != NULL) { xasprintf(&msg, "duplicate session: %s", data.name); - write_client(c, MSG_READY, msg, strlen(msg)); + write_client(c, MSG_ERROR, msg, strlen(msg)); xfree(msg); - return; + return (0); } shell = getenv("SHELL"); @@ -124,19 +128,20 @@ server_msg_fn_new(struct client *c, struct hdr *hdr) fatalx("session_create failed"); xfree(cmd); - write_client(c, MSG_READY, NULL, 0); draw_client(c, 0, c->sy - 1); + + return (0); } /* Attach message from client. */ -void -server_msg_fn_attach(struct client *c, struct hdr *hdr) +int +server_msg_fn_attach(struct hdr *hdr, struct client *c) { struct attach_data data; char *msg; if (c->session != NULL) - return; + return (0); if (hdr->size != sizeof data) fatalx("bad MSG_ATTACH size"); buffer_read(c->in, &data, hdr->size); @@ -152,24 +157,25 @@ server_msg_fn_attach(struct client *c, struct hdr *hdr) 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)); + write_client(c, MSG_ERROR, msg, strlen(msg)); xfree(msg); - return; + return (0); } - write_client(c, MSG_READY, NULL, 0); draw_client(c, 0, c->sy - 1); + + return (0); } /* Create message from client. */ -void -server_msg_fn_create(struct client *c, struct hdr *hdr) +int +server_msg_fn_create(struct hdr *hdr, struct client *c) { const char *shell; char *cmd; if (c->session == NULL) - return; + return (0); if (hdr->size != 0) fatalx("bad MSG_CREATE size"); @@ -182,14 +188,16 @@ server_msg_fn_create(struct client *c, struct hdr *hdr) xfree(cmd); draw_client(c, 0, c->sy - 1); + + return (0); } /* Next message from client. */ -void -server_msg_fn_next(struct client *c, struct hdr *hdr) +int +server_msg_fn_next(struct hdr *hdr, struct client *c) { if (c->session == NULL) - return; + return (0); if (hdr->size != 0) fatalx("bad MSG_NEXT size"); @@ -197,14 +205,16 @@ server_msg_fn_next(struct client *c, struct hdr *hdr) changed_window(c); else write_message(c, "No next window"); + + return (0); } /* Previous message from client. */ -void -server_msg_fn_previous(struct client *c, struct hdr *hdr) +int +server_msg_fn_previous(struct hdr *hdr, struct client *c) { if (c->session == NULL) - return; + return (0); if (hdr->size != 0) fatalx("bad MSG_PREVIOUS size"); @@ -212,16 +222,18 @@ server_msg_fn_previous(struct client *c, struct hdr *hdr) changed_window(c); else write_message(c, "No previous window"); + + return (0); } /* Size message from client. */ -void -server_msg_fn_size(struct client *c, struct hdr *hdr) +int +server_msg_fn_size(struct hdr *hdr, struct client *c) { struct size_data data; if (c->session == NULL) - return; + return (0); if (hdr->size != sizeof data) fatalx("bad MSG_SIZE size"); buffer_read(c->in, &data, hdr->size); @@ -235,55 +247,63 @@ server_msg_fn_size(struct client *c, struct hdr *hdr) if (window_resize(c->session->window, c->sx, c->sy) != 0) draw_client(c, 0, c->sy - 1); + + return (0); } /* Input message from client. */ -void -server_msg_fn_input(struct client *c, struct hdr *hdr) +int +server_msg_fn_input(struct hdr *hdr, struct client *c) { if (c->session == NULL) - return; + return (0); window_input(c->session->window, c->in, hdr->size); + + return (0); } /* Refresh message from client. */ -void -server_msg_fn_refresh(struct client *c, struct hdr *hdr) +int +server_msg_fn_refresh(struct hdr *hdr, struct client *c) { struct refresh_data data; if (c->session == NULL) - return; + return (0); if (hdr->size != 0 && hdr->size != sizeof data) fatalx("bad MSG_REFRESH size"); draw_client(c, 0, c->sy - 1); + + return (0); } /* Select message from client. */ -void -server_msg_fn_select(struct client *c, struct hdr *hdr) +int +server_msg_fn_select(struct hdr *hdr, struct client *c) { struct select_data data; if (c->session == NULL) - return; + return (0); if (hdr->size != sizeof data) fatalx("bad MSG_SELECT size"); buffer_read(c->in, &data, hdr->size); if (c->session == NULL) - return; + return (0); if (session_select(c->session, data.idx) == 0) changed_window(c); else write_message(c, "Window %u not present", data.idx); + + return (0); } /* Sessions message from client. */ -void -server_msg_fn_sessions(struct client *c, struct hdr *hdr) +int +server_msg_fn_sessions(struct hdr *hdr, struct client *c) { struct sessions_data data; struct sessions_entry entry; @@ -315,11 +335,13 @@ server_msg_fn_sessions(struct client *c, struct hdr *hdr) } buffer_write(c->out, &entry, sizeof entry); } + + return (0); } /* Windows message from client. */ -void -server_msg_fn_windows(struct client *c, struct hdr *hdr) +int +server_msg_fn_windows(struct hdr *hdr, struct client *c) { struct windows_data data; struct windows_entry entry; @@ - |