aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Marriott <nicholas.marriott@gmail.com>2007-09-26 13:43:15 +0000
committerNicholas Marriott <nicholas.marriott@gmail.com>2007-09-26 13:43:15 +0000
commitfb39b22a2e7b7c12c56b26abc8ca18f38c2d7bda (patch)
tree758fbaec376b741c12ab0382ff31fea819256e45
parent671694ac3037055c35521f438615e4ce9daafda3 (diff)
downloadrtmux-fb39b22a2e7b7c12c56b26abc8ca18f38c2d7bda.tar.gz
rtmux-fb39b22a2e7b7c12c56b26abc8ca18f38c2d7bda.tar.bz2
rtmux-fb39b22a2e7b7c12c56b26abc8ca18f38c2d7bda.zip
Cleanup part II: split up client stuff and ops. More to come.
-rw-r--r--Makefile4
-rw-r--r--client-cmd.c108
-rw-r--r--client-msg.c99
-rw-r--r--client.c251
-rw-r--r--command.c113
-rw-r--r--op-list.c126
-rw-r--r--op.c64
-rw-r--r--server-msg.c190
-rw-r--r--server.c54
-rw-r--r--tmux.c578
-rw-r--r--tmux.h58
11 files changed, 913 insertions, 732 deletions
diff --git a/Makefile b/Makefile
index 80a3b003..a300e0c4 100644
--- a/Makefile
+++ b/Makefile
@@ -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");
+ }
+ }
+}
diff --git a/op.c b/op.c
new file mode 100644
index 00000000..393ca69f
--- /dev/null
+++ b/op.c
@@ -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-