From e3feb067a503b53da253e4ed877d212d6d73842c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 11 Jan 2009 00:48:42 +0000 Subject: [PATCH] Server locking. set-password and lock-server commands, plus automatic locking. --- CHANGES | 9 ++- GNUmakefile | 10 +-- Makefile | 6 +- TODO | 7 +- client.c | 3 +- clock.c | 160 ++++++++++++++++++++++++++++++++++++++++ cmd-command-prompt.c | 22 +++--- cmd-lock-server.c | 55 ++++++++++++++ cmd-new-session.c | 4 +- cmd-paste-buffer.c | 4 +- cmd-select-prompt.c | 18 +++-- cmd-set-option.c | 3 +- cmd-set-password.c | 169 +++++++++++++++++++++++++++++++++++++++++++ cmd.c | 8 +- server-fn.c | 69 +++++++++++++++++- server-msg.c | 30 +++++++- server.c | 154 +++++++++++++++++++++++++++++---------- status.c | 26 ++++--- tmux.c | 111 +++++++++++++++++----------- tmux.h | 36 ++++++--- window-clock.c | 152 +++++--------------------------------- 21 files changed, 778 insertions(+), 278 deletions(-) create mode 100644 clock.c create mode 100644 cmd-lock-server.c create mode 100644 cmd-set-password.c diff --git a/CHANGES b/CHANGES index 9d9c8651..945e09c8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,12 @@ 10 January 2009 +* New option, lock-after-time. If there is no activity in the period specified + by this option (in seconds), tmux will lock the server. Default is 1800 (30 + minutes), set to 0 to disable. +* Server locking. Two new commands: set-password to set a password (a + preencrypted password may be specified with -c); and lock-server to lock the + server until the password is entered. Also an additional command line flag, + -U, to unlock from the shell. * If a window is created from the command line, tmux will now use the same current working directory for the new process. A new default-path option to sets the working directory for processes created from keys or interactively @@ -845,7 +852,7 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.189 2009-01-10 19:37:35 nicm Exp $ +$Id: CHANGES,v 1.190 2009-01-11 00:48:41 nicm Exp $ LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB diff --git a/GNUmakefile b/GNUmakefile index ecb1eb0e..bb8144c8 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,4 +1,4 @@ -# $Id: GNUmakefile,v 1.48 2009-01-10 19:40:01 nicm Exp $ +# $Id: GNUmakefile,v 1.49 2009-01-11 00:48:42 nicm Exp $ .PHONY: clean @@ -32,9 +32,9 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ cmd-show-buffer.c cmd-list-buffers.c cmd-delete-buffer.c \ cmd-list-commands.c cmd-move-window.c cmd-select-prompt.c \ cmd-respawn-window.c cmd-source-file.c cmd-server-info.c \ - cmd-clock-mode.c \ + cmd-clock-mode.c cmd-lock-server.c cmd-set-password.c \ window-clock.c window-scroll.c window-more.c window-copy.c \ - options.c options-cmd.c paste.c colour.c utf8.c \ + options.c options-cmd.c paste.c colour.c utf8.c clock.c \ tty.c tty-term.c tty-keys.c tty-write.c CC?= gcc @@ -73,7 +73,7 @@ endif ifeq ($(shell uname),SunOS) INCDIRS+= -Icompat -I/usr/local/include/ncurses SRCS+= compat/strtonum.c compat/daemon.c compat/forkpty-sunos.c \ - compat/asprintf.c compat/fgetln.c + compat/asprintf.c compat/fgetln.c compat/vis.c CFLAGS+= -DNO_STRTONUM -DNO_TREE_H -DNO_PATHS_H -DNO_SETPROCTITLE \ -DNO_DAEMON -DNO_FORKPTY -DNO_PROGNAME -DNO_ASPRINTF -DNO_FGETLN LDFLAGS+= -L/usr/local/lib @@ -95,7 +95,7 @@ CFLAGS+= $(shell getconf LFS_CFLAGS) -D_GNU_SOURCE \ -DNO_STRLCPY -DNO_STRLCAT -DNO_STRTONUM -DNO_SETPROCTITLE \ -DNO_QUEUE_H -DNO_TREE_H -DUSE_PTY_H -DNO_FGETLN \ -DBROKEN_GETOPT -std=c99 -LIBS+= -lrt -lutil +LIBS+= -lcrypt -lutil endif OBJS= $(patsubst %.c,%.o,$(SRCS)) diff --git a/Makefile b/Makefile index a323334f..ac0ae27b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.85 2009-01-10 19:35:39 nicm Exp $ +# $Id: Makefile,v 1.86 2009-01-11 00:48:42 nicm Exp $ .SUFFIXES: .c .o .y .h .PHONY: clean update-index.html upload-index.html @@ -36,9 +36,9 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ cmd-show-buffer.c cmd-list-buffers.c cmd-delete-buffer.c \ cmd-list-commands.c cmd-move-window.c cmd-select-prompt.c \ cmd-respawn-window.c cmd-source-file.c cmd-server-info.c \ - cmd-clock-mode.c \ + cmd-clock-mode.c cmd-lock-server.c cmd-set-password.c \ window-clock.c window-scroll.c window-more.c window-copy.c \ - options.c options-cmd.c paste.c colour.c utf8.c \ + options.c options-cmd.c paste.c colour.c utf8.c clock.c \ tty.c tty-term.c tty-keys.c tty-write.c CC?= cc diff --git a/TODO b/TODO index 2d825c0a..8e976fd5 100644 --- a/TODO +++ b/TODO @@ -64,8 +64,9 @@ - document server-info - document window options changes - document clock-mode -- automatic lock/screensaver after $time inactivity (switch all windows into - clock mode/blank) -- a key binding to display the status line when it is turned off +- document password/locking commands +- document lock-after-time +- automatic lock/screensaver after $time inactivity +- a key binding to display the status line briefly when it is turned off - FAQ "Can I have some examples of cool things I can do with tmux?" -- linkw - clone session command diff --git a/client.c b/client.c index 4e012a1b..3e985b35 100644 --- a/client.c +++ b/client.c @@ -1,4 +1,4 @@ -/* $Id: client.c,v 1.36 2009-01-10 19:37:35 nicm Exp $ */ +/* $Id: client.c,v 1.37 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -24,6 +24,7 @@ #include #include +#include #include #include #include diff --git a/clock.c b/clock.c new file mode 100644 index 00000000..f79546d0 --- /dev/null +++ b/clock.c @@ -0,0 +1,160 @@ +/* $Id: clock.c,v 1.1 2009-01-11 00:48:42 nicm Exp $ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +char clock_table[14][5][5] = { + { { 1,1,1,1,1 }, /* 0 */ + { 1,0,0,0,1 }, + { 1,0,0,0,1 }, + { 1,0,0,0,1 }, + { 1,1,1,1,1 } }, + { { 0,0,0,0,1 }, /* 1 */ + { 0,0,0,0,1 }, + { 0,0,0,0,1 }, + { 0,0,0,0,1 }, + { 0,0,0,0,1 } }, + { { 1,1,1,1,1 }, /* 2 */ + { 0,0,0,0,1 }, + { 1,1,1,1,1 }, + { 1,0,0,0,0 }, + { 1,1,1,1,1 } }, + { { 1,1,1,1,1 }, /* 3 */ + { 0,0,0,0,1 }, + { 1,1,1,1,1 }, + { 0,0,0,0,1 }, + { 1,1,1,1,1 } }, + { { 1,0,0,0,1 }, /* 4 */ + { 1,0,0,0,1 }, + { 1,1,1,1,1 }, + { 0,0,0,0,1 }, + { 0,0,0,0,1 } }, + { { 1,1,1,1,1 }, /* 5 */ + { 1,0,0,0,0 }, + { 1,1,1,1,1 }, + { 0,0,0,0,1 }, + { 1,1,1,1,1 } }, + { { 1,1,1,1,1 }, /* 6 */ + { 1,0,0,0,0 }, + { 1,1,1,1,1 }, + { 1,0,0,0,1 }, + { 1,1,1,1,1 } }, + { { 1,1,1,1,1 }, /* 7 */ + { 0,0,0,0,1 }, + { 0,0,0,0,1 }, + { 0,0,0,0,1 }, + { 0,0,0,0,1 } }, + { { 1,1,1,1,1 }, /* 8 */ + { 1,0,0,0,1 }, + { 1,1,1,1,1 }, + { 1,0,0,0,1 }, + { 1,1,1,1,1 } }, + { { 1,1,1,1,1 }, /* 9 */ + { 1,0,0,0,1 }, + { 1,1,1,1,1 }, + { 0,0,0,0,1 }, + { 1,1,1,1,1 } }, + { { 0,0,0,0,0 }, /* : */ + { 0,0,1,0,0 }, + { 0,0,0,0,0 }, + { 0,0,1,0,0 }, + { 0,0,0,0,0 } }, + { { 1,1,1,1,1 }, /* A */ + { 1,0,0,0,1 }, + { 1,1,1,1,1 }, + { 1,0,0,0,1 }, + { 1,0,0,0,1 } }, + { { 1,1,1,1,1 }, /* P */ + { 1,0,0,0,1 }, + { 1,1,1,1,1 }, + { 1,0,0,0,0 }, + { 1,0,0,0,0 } }, + { { 1,0,0,0,1 }, /* M */ + { 1,1,0,1,1 }, + { 1,0,1,0,1 }, + { 1,0,0,0,1 }, + { 1,0,0,0,1 } }, +}; + +void +clock_draw(struct screen_write_ctx *ctx, u_int colour, int style) +{ + struct screen *s = ctx->s; + struct grid_cell gc; + char tim[64], *ptr; + time_t t; + u_int i, j, x, y, idx; + + t = time(NULL); + if (style == 0) + strftime(tim, sizeof tim, "%l:%M %p", localtime(&t)); + else + strftime(tim, sizeof tim, "%H:%M", localtime(&t)); + + screen_write_clearscreen(ctx); + memcpy(&gc, &grid_default_cell, sizeof gc); + + if (screen_size_x(s) < 6 * strlen(tim) || screen_size_y(s) < 6) { + if (screen_size_x(s) >= strlen(tim) && screen_size_y(s) != 0) { + x = (screen_size_x(s) / 2) - (strlen(tim) / 2); + y = screen_size_y(s) / 2; + screen_write_cursormove(ctx, x, y); + + gc.fg = colour; + screen_write_puts(ctx, &gc, "%s", tim); + } + return; + } + + x = (screen_size_x(s) / 2) - 3 * strlen(tim); + y = (screen_size_y(s) / 2) - 3; + + for (ptr = tim; *ptr != '\0'; ptr++) { + if (*ptr >= '0' && *ptr <= '9') + idx = *ptr - '0'; + else if (*ptr == ':') + idx = 10; + else if (*ptr == 'A') + idx = 11; + else if (*ptr == 'P') + idx = 12; + else if (*ptr == 'M') + idx = 13; + else { + x += 6; + continue; + } + + for (j = 0; j < 5; j++) { + screen_write_cursormove(ctx, x, y + j); + for (i = 0; i < 5; i++) { + if (clock_table[idx][j][i]) + gc.bg = colour; + else + gc.bg = 0; + screen_write_putc(ctx, &gc, ' '); + } + } + x += 6; + } +} diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 752ec7e8..0bf3c084 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -1,4 +1,4 @@ -/* $Id: cmd-command-prompt.c,v 1.6 2008-09-26 06:45:25 nicm Exp $ */ +/* $Id: cmd-command-prompt.c,v 1.7 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -28,7 +28,7 @@ void cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); -void cmd_command_prompt_callback(void *, char *); +int cmd_command_prompt_callback(void *, const char *); const struct cmd_entry cmd_command_prompt_entry = { "command-prompt", NULL, @@ -55,14 +55,14 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) if (c->prompt_string != NULL) return; - server_set_client_prompt(c, ":", cmd_command_prompt_callback, c); + server_set_client_prompt(c, ":", cmd_command_prompt_callback, c, 0); if (ctx->cmdclient != NULL) server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); } -void -cmd_command_prompt_callback(void *data, char *s) +int +cmd_command_prompt_callback(void *data, const char *s) { struct client *c = data; struct cmd *cmd; @@ -70,18 +70,18 @@ cmd_command_prompt_callback(void *data, char *s) char *cause; if (s == NULL) - return; + return (0); if (cmd_string_parse(s, &cmd, &cause) != 0) { if (cause == NULL) - return; + return (0); *cause = toupper((u_char) *cause); server_set_client_message(c, cause); xfree(cause); - return; + return (0); } if (cmd == NULL) - return; + return (0); ctx.msgdata = NULL; ctx.cursession = c->session; @@ -94,4 +94,8 @@ cmd_command_prompt_callback(void *data, char *s) ctx.cmdclient = NULL; cmd_exec(cmd, &ctx); + + if (c->prompt_callback != (void *) &cmd_command_prompt_callback) + return (1); + return (0); } diff --git a/cmd-lock-server.c b/cmd-lock-server.c new file mode 100644 index 00000000..f1cf4d48 --- /dev/null +++ b/cmd-lock-server.c @@ -0,0 +1,55 @@ +/* $Id: cmd-lock-server.c,v 1.1 2009-01-11 00:48:42 nicm Exp $ */ + +/* + * Copyright (c) 2008 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" + +/* + * Lock server. + */ + +void cmd_lock_server_exec(struct cmd *, struct cmd_ctx *); + +int cmd_lock_server_callback(void *, const char *); + +const struct cmd_entry cmd_lock_server_entry = { + "lock-server", "lock", + "", + 0, + NULL, + NULL, + cmd_lock_server_exec, + NULL, + NULL, + NULL, + NULL, +}; + +void +cmd_lock_server_exec(unused struct cmd *self, struct cmd_ctx *ctx) +{ + server_lock(); + + if (ctx->cmdclient != NULL) + server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); +} diff --git a/cmd-new-session.c b/cmd-new-session.c index 711e0776..fbb92894 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -1,4 +1,4 @@ -/* $Id: cmd-new-session.c,v 1.33 2009-01-10 19:37:35 nicm Exp $ */ +/* $Id: cmd-new-session.c,v 1.34 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -118,7 +118,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) if (ctx->curclient != NULL) return; - + if (!data->flag_detached) { if (c == NULL) { ctx->error(ctx, "no client to attach to"); diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 7f69a155..93ad57b5 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -1,4 +1,4 @@ -/* $Id: cmd-paste-buffer.c,v 1.12 2009-01-07 19:52:36 nicm Exp $ */ +/* $Id: cmd-paste-buffer.c,v 1.13 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -70,6 +70,6 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) paste_free_index(&s->buffers, data->buffer); } - if (ctx->cmdclient != NULL) + if (ctx->cmdclient != NULL) server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); } diff --git a/cmd-select-prompt.c b/cmd-select-prompt.c index 8b1fb76b..16c6fe53 100644 --- a/cmd-select-prompt.c +++ b/cmd-select-prompt.c @@ -1,4 +1,4 @@ -/* $Id: cmd-select-prompt.c,v 1.4 2009-01-05 11:04:06 nicm Exp $ */ +/* $Id: cmd-select-prompt.c,v 1.5 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -28,7 +28,7 @@ void cmd_select_prompt_exec(struct cmd *, struct cmd_ctx *); -void cmd_select_prompt_callback(void *, char *); +int cmd_select_prompt_callback(void *, const char *); const struct cmd_entry cmd_select_prompt_entry = { "select-prompt", NULL, @@ -55,14 +55,14 @@ cmd_select_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) if (c->prompt_string != NULL) return; - server_set_client_prompt(c, "index ", cmd_select_prompt_callback, c); + server_set_client_prompt(c, "index ", cmd_select_prompt_callback, c, 0); if (ctx->cmdclient != NULL) server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); } -void -cmd_select_prompt_callback(void *data, char *s) +int +cmd_select_prompt_callback(void *data, const char *s) { struct client *c = data; const char *errstr; @@ -70,23 +70,25 @@ cmd_select_prompt_callback(void *data, char *s) u_int idx; if (s == NULL) - return; + return (0); idx = strtonum(s, 0, UINT_MAX, &errstr); if (errstr != NULL) { xsnprintf(msg, sizeof msg, "Index %s: %s", errstr, s); server_set_client_message(c, msg); - return; + return (0); } if (winlink_find_by_index(&c->session->windows, idx) == NULL) { xsnprintf(msg, sizeof msg, "Window not found: %s:%d", c->session->name, idx); server_set_client_message(c, msg); - return; + return (0); } if (session_select(c->session, idx) == 0) server_redraw_session(c->session); recalculate_sizes(); + + return (0); } diff --git a/cmd-set-option.c b/cmd-set-option.c index 55d1a7cf..4af2e06c 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -1,4 +1,4 @@ -/* $Id: cmd-set-option.c,v 1.50 2009-01-10 19:37:35 nicm Exp $ */ +/* $Id: cmd-set-option.c,v 1.51 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -52,6 +52,7 @@ const struct set_option_entry set_option_table[NSETOPTION] = { { "default-path", SET_OPTION_STRING, 0, 0, NULL }, { "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "history-limit", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, + { "lock-after", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, { "message-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "message-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "prefix", SET_OPTION_KEY, 0, 0, NULL }, diff --git a/cmd-set-password.c b/cmd-set-password.c new file mode 100644 index 00000000..583914c9 --- /dev/null +++ b/cmd-set-password.c @@ -0,0 +1,169 @@ +/* $Id: cmd-set-password.c,v 1.1 2009-01-11 00:48:42 nicm Exp $ */ + +/* + * Copyright (c) 2009 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 "tmux.h" + +/* + * Set server password. + */ + +int cmd_set_password_parse(struct cmd *, int, char **, char **); +void cmd_set_password_exec(struct cmd *, struct cmd_ctx *); +void cmd_set_password_send(struct cmd *, struct buffer *); +void cmd_set_password_recv(struct cmd *, struct buffer *); +void cmd_set_password_free(struct cmd *); +void cmd_set_password_init(struct cmd *, int); +void cmd_set_password_print(struct cmd *, char *, size_t); + +struct cmd_set_password_data { + char *password; + int flag_encrypted; +}; + +const struct cmd_entry cmd_set_password_entry = { + "set-password", "pass", + "[-c] password", + 0, + cmd_set_password_init, + cmd_set_password_parse, + cmd_set_password_exec, + cmd_set_password_send, + cmd_set_password_recv, + cmd_set_password_free, + cmd_set_password_print +}; + +void +cmd_set_password_init(struct cmd *self, unused int arg) +{ + struct cmd_set_password_data *data; + + self->data = data = xmalloc(sizeof *data); + data->password = NULL; + data->flag_encrypted = 0; +} + +int +cmd_set_password_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_set_password_data *data; + int opt; + char *out; + + self->entry->init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "c")) != -1) { + switch (opt) { + case 'c': + data->flag_encrypted = 1; + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + if (argc != 1) + goto usage; + + if (!data->flag_encrypted) { + if ((out = crypt(argv[0], "$1")) != NULL) + data->password = xstrdup(out); + } else + data->password = xstrdup(argv[0]); + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + + self->entry->free(self); + return (-1); +} + +void +cmd_set_password_exec(struct cmd *self, struct cmd_ctx *ctx) +{ + struct cmd_set_password_data *data = self->data; + + if (data->password == NULL) { + ctx->error(ctx, "failed to encrypt password"); + return; + } + + if (server_password != NULL) + xfree(server_password); + if (*data->password == '\0') + server_password = NULL; + else + server_password = xstrdup(data->password); + log_debug("pw now %s", server_password); + + if (ctx->cmdclient != NULL) + server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); +} + +void +cmd_set_password_send(struct cmd *self, struct buffer *b) +{ + struct cmd_set_password_data *data = self->data; + + buffer_write(b, data, sizeof *data); + cmd_send_string(b, data->password); +} + +void +cmd_set_password_recv(struct cmd *self, struct buffer *b) +{ + struct cmd_set_password_data *data; + + self->data = data = xmalloc(sizeof *data); + buffer_read(b, data, sizeof *data); + data->password = cmd_recv_string(b); +} + +void +cmd_set_password_free(struct cmd *self) +{ + struct cmd_set_password_data *data = self->data; + + if (data->password != NULL) + xfree(data->password); + xfree(data); +} + +void +cmd_set_password_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_set_password_data *data = self->data; + size_t off = 0; + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return; + if (off < len && data->flag_encrypted) + off += xsnprintf(buf + off, len - off, " -c"); + if (off < len && data->password != NULL) + off += xsnprintf(buf + off, len - off, " password"); +} diff --git a/cmd.c b/cmd.c index f73ab7d3..7fc213f7 100644 --- a/cmd.c +++ b/cmd.c @@ -1,4 +1,4 @@ -/* $Id: cmd.c,v 1.71 2009-01-10 19:35:39 nicm Exp $ */ +/* $Id: cmd.c,v 1.72 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -45,6 +45,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_list_keys_entry, &cmd_list_sessions_entry, &cmd_list_windows_entry, + &cmd_lock_server_entry, &cmd_move_window_entry, &cmd_new_session_entry, &cmd_new_window_entry, @@ -63,6 +64,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_server_info_entry, &cmd_set_buffer_entry, &cmd_set_option_entry, + &cmd_set_password_entry, &cmd_set_window_option_entry, &cmd_show_buffer_entry, &cmd_show_options_entry, @@ -159,6 +161,10 @@ usage: void cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx) { + if (server_locked) { + ctx->error(ctx, "server is locked"); + return; + } cmd->entry->exec(cmd, ctx); } diff --git a/server-fn.c b/server-fn.c index fd158b9f..c24fc49a 100644 --- a/server-fn.c +++ b/server-fn.c @@ -1,4 +1,4 @@ -/* $Id: server-fn.c,v 1.52 2009-01-10 14:43:43 nicm Exp $ */ +/* $Id: server-fn.c,v 1.53 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -24,6 +24,8 @@ #include "tmux.h" +int server_lock_callback(void *, const char *); + void server_set_client_message(struct client *c, const char *msg) { @@ -57,8 +59,8 @@ server_clear_client_message(struct client *c) } void -server_set_client_prompt( - struct client *c, const char *msg, void (*fn)(void *, char *), void *data) +server_set_client_prompt(struct client *c, + const char *msg, int (*fn)(void *, const char *), void *data, int hide) { c->prompt_string = xstrdup(msg); @@ -70,6 +72,8 @@ server_set_client_prompt( c->prompt_hindex = 0; + c->prompt_hidden = hide; + c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE); c->flags |= CLIENT_STATUS; } @@ -213,3 +217,62 @@ server_status_window(struct window *w) server_status_session(s); } } + +void +server_lock(void) +{ + struct client *c; + u_int i; + + if (server_locked) + return; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL) + continue; + + server_clear_client_prompt(c); + server_set_client_prompt( + c, "Password: ", server_lock_callback, c, 1); + server_redraw_client(c); + } + server_locked = 1; +} + +int +server_lock_callback(unused void *data, const char *s) +{ + return (server_unlock(s)); +} + +int +server_unlock(const char *s) +{ + struct client *c; + u_int i; + char *out; + + if (!server_locked) + return (0); + + if (server_password != NULL) { + if (s == NULL) + return (-1); + out = crypt(s, server_password); + if (strcmp(out, server_password) != 0) + return (-1); + } + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL) + continue; + + server_clear_client_prompt(c); + server_redraw_client(c); + } + server_locked = 0; + + return (0); +} diff --git a/server-msg.c b/server-msg.c index 2f1fc681..1912a829 100644 --- a/server-msg.c +++ b/server-msg.c @@ -1,4 +1,4 @@ -/* $Id: server-msg.c,v 1.55 2009-01-10 19:37:35 nicm Exp $ */ +/* $Id: server-msg.c,v 1.56 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -29,6 +29,7 @@ int server_msg_fn_command(struct hdr *, struct client *); int server_msg_fn_identify(struct hdr *, struct client *); int server_msg_fn_resize(struct hdr *, struct client *); int server_msg_fn_exiting(struct hdr *, struct client *); +int server_msg_fn_unlock(struct hdr *, struct client *); void printflike2 server_msg_fn_command_error( struct cmd_ctx *, const char *, ...); @@ -45,7 +46,8 @@ const struct server_msg server_msg_table[] = { { MSG_IDENTIFY, server_msg_fn_identify }, { MSG_COMMAND, server_msg_fn_command }, { MSG_RESIZE, server_msg_fn_resize }, - { MSG_EXITING, server_msg_fn_exiting } + { MSG_EXITING, server_msg_fn_exiting }, + { MSG_UNLOCK, server_msg_fn_unlock } }; int @@ -135,6 +137,7 @@ server_msg_fn_command(struct hdr *hdr, struct client *c) cmd = cmd_recv(c->in); log_debug("got command %s from client %d", cmd->entry->name, c->fd); + server_activity = time(NULL); ctx.error = server_msg_fn_command_error; ctx.print = server_msg_fn_command_print; @@ -244,3 +247,26 @@ server_msg_fn_exiting(struct hdr *hdr, struct client *c) return (0); } + +int +server_msg_fn_unlock(struct hdr *hdr, struct client *c) +{ + char *pass; + + if (hdr->size == 0) + fatalx("bad MSG_UNLOCK size"); + pass = cmd_recv_string(c->in); + + log_debug("unlock msg from client"); + + if (server_unlock(pass) != 0) { +#define MSG "bad password" + server_write_client(c, MSG_ERROR, MSG, (sizeof MSG) - 1); + return (0); +#undef MSG + } + + server_write_client(c, MSG_EXIT, NULL, 0); + + return (0); +} diff --git a/server.c b/server.c index 078183b3..1c617092 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* $Id: server.c,v 1.93 2009-01-10 19:37:35 nicm Exp $ */ +/* $Id: server.c,v 1.94 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -53,6 +53,8 @@ void server_handle_window(struct window *); void server_lost_client(struct client *); void server_lost_window(struct window *); void server_check_redraw(struct client *); +void server_do_redraw_client(struct client *); +void server_do_redraw_locked(struct client *); void server_check_timers(struct client *); void server_second_timers(void); int server_update_socket(const char *); @@ -101,7 +103,7 @@ server_start(const char *path) * Must daemonise before loading configuration as the PID changes so * $TMUX would be wrong for sessions created in the config file. */ - if (daemon(0, 1) != 0) + if (daemon(1, 1) != 0) fatal("daemon failed"); ARRAY_INIT(&windows); @@ -109,6 +111,10 @@ server_start(const char *path) ARRAY_INIT(&sessions); key_bindings_init(); + server_locked = 0; + server_password = NULL; + server_activity = time(NULL); + if (cfg_file != NULL && load_cfg(cfg_file, &cause) != 0) { log_warnx("%s", cause); exit(1); @@ -121,7 +127,7 @@ server_start(const char *path) log_debug("server started, pid %ld", (long) getpid()); start_time = time(NULL); socket_path = path; - + memset(&sa, 0, sizeof sa); sa.sun_family = AF_UNIX; size = strlcpy(sa.sun_path, path, sizeof sa.sun_path); @@ -215,7 +221,7 @@ server_main(const char *srv_path, int srv_fd) } pfd++; - /* Call seconds-based timers. */ + /* Call second-based timers. */ now = time(NULL); if (now != last) { last = now; @@ -311,13 +317,9 @@ server_handle_windows(struct pollfd **pfd) void server_check_redraw(struct client *c) { - struct session *s; - struct screen_redraw_ctx ctx; - struct screen screen; - struct grid_cell gc; - u_int xx, yy, sx, sy; - char *title; - int flags; + struct session *s; + char *title; + int flags; if (c == NULL || c->session == NULL) return; @@ -336,36 +338,11 @@ server_check_redraw(struct client *c) } } - xx = c->sx; - yy = c->sy - 1; if (c->flags & CLIENT_REDRAW) { - sx = screen_size_x(s->curw->window->screen); - sy = screen_size_y(s->curw->window->screen); - if (sx < xx || sy < yy) { - /* - * Fake up a blank(ish) screen and use it to draw the - * empty regions. NOTE: because this uses - * tty_write_client but doesn't write the client's - * screen, this can't use anything which relies on - * cursor position. - */ - screen_init(&screen, xx, yy, 0); - screen_redraw_start(&ctx, &screen, tty_write_client, c); - if (sx < xx) - screen_redraw_columns(&ctx, sx, xx - sx); - if (sy < yy) { - memcpy(&gc, &grid_default_cell, sizeof gc); - gc.data = '-'; - grid_view_fill(screen.grid, &gc, 0, sy, xx, 1); - screen_redraw_lines(&ctx, sy, yy - sy); - } - screen_redraw_stop(&ctx); - screen_free(&screen); - } - - screen_redraw_start_client(&ctx, c); - screen_redraw_lines(&ctx, 0, screen_size_y(ctx.s)); - screen_redraw_stop(&ctx); + if (server_locked) + server_do_redraw_locked(c); + else + server_do_redraw_client(c); c->flags |= CLIENT_STATUS; } @@ -384,6 +361,76 @@ server_check_redraw(struct client *c) c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS); } +/* Redraw client normally. */ +void +server_do_redraw_client(struct client *c) +{ + struct session *s = c->session; + struct screen_redraw_ctx ctx; + struct screen screen; + struct grid_cell gc; + u_int xx, yy, sx, sy; + + xx = c->sx; + yy = c->sy - 1; + + sx = screen_size_x(s->curw->window->screen); + sy = screen_size_y(s->curw->window->screen); + + if (sx < xx || sy < yy) { + /* + * Fake up a blank(ish) screen and use it to draw the empty + * regions. NOTE: because this uses tty_write_client but + * doesn't write the client's screen, this can't use anything + * which relies on cursor position. + */ + + screen_init(&screen, xx, yy, 0); + screen_redraw_start(&ctx, &screen, tty_write_client, c); + if (sx < xx) + screen_redraw_columns(&ctx, sx, xx - sx); + if (sy < yy) { + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.data = '-'; + grid_view_fill(screen.grid, &gc, 0, sy, xx, 1); + screen_redraw_lines(&ctx, sy, yy - sy); + } + screen_redraw_stop(&ctx); + screen_free(&screen); + } + + screen_redraw_start_client(&ctx, c); + screen_redraw_lines(&ctx, 0, screen_size_y(ctx.s)); + screen_redraw_stop(&ctx); +} + +/* Redraw client when locked. */ +void +server_do_redraw_locked(struct client *c) +{ + struct session *s = c->session; + struct window *w = s->curw->window; + struct screen_write_ctx ctx; + struct screen screen; + u_int colour, xx, yy; + int style; + + xx = c->sx; + yy = c->sy - 1; + if (xx == 0 || yy == 0) + return; + colour = options_get_number(&w->options, "clock-mode-colour"); + style = options_get_number(&w->options, "clock-mode-style"); + + screen_init(&screen, xx, yy, 0); + + screen_write_start(&ctx, &screen, tty_write_client, c); + clock_draw(&ctx, colour, style); + screen_write_stop(&ctx); + + screen_free(&screen); +} + /* Check for timers on client. */ void server_check_timers(struct client *c) @@ -546,11 +593,15 @@ server_handle_client(struct client *c) prefix = options_get_number(&c->session->options, "prefix"); while (tty_keys_next(&c->tty, &key) == 0) { + server_activity = time(NULL); + server_clear_client_message(c); if (c->prompt_string != NULL) { status_prompt_key(c, key); continue; } + if (server_locked) + continue; if (c->flags & CLIENT_PREFIX) { key_bindings_dispatch(key, c); @@ -708,12 +759,35 @@ server_second_timers(void) { struct window *w; u_int i; + int xtimeout; + struct tm now, then; + static time_t last_t = 0; + time_t t; + + t = time(NULL); + xtimeout = options_get_number(&global_options, "lock-after-time"); + if (xtimeout > 0 && t > server_activity + xtimeout) + server_lock(); for (i = 0; i < ARRAY_LENGTH(&windows); i++) { w = ARRAY_ITEM(&windows, i); if (w->mode != NULL && w->mode->timer != NULL) w->mode->timer(w); } + + gmtime_r(&t, &now); + gmtime_r(&last_t, &then); + if (now.tm_min == then.tm_min) + return; + last_t = t; + + /* If locked, redraw all clients. */ + if (server_locked) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + if (ARRAY_ITEM(&clients, i) != NULL) + server_redraw_client(ARRAY_ITEM(&clients, i)); + } + } } /* Update socket execute permissions based on whether sessions are attached. */ diff --git a/status.c b/status.c index ab094cce..2a8a7efa 100644 --- a/status.c +++ b/status.c @@ -1,4 +1,4 @@ -/* $Id: status.c,v 1.58 2009-01-10 01:51:22 nicm Exp $ */ +/* $Id: status.c,v 1.59 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -407,7 +407,7 @@ status_prompt_redraw(struct client *c) { struct screen_redraw_ctx ctx; struct session *s = c->session; - size_t i, xx, yy, left, size, offset; + size_t i, xx, yy, left, size, offset, n; char ch; struct grid_cell gc; @@ -439,8 +439,16 @@ status_prompt_redraw(struct client *c) left--; size = left; } - screen_redraw_puts( - &ctx, &gc, "%.*s", (int) left, c->prompt_buffer + offset); + if (c->prompt_hidden) { + n = strlen(c->prompt_buffer); + if (n > left) + n = left; + for (i = 0; i < n; i++) + screen_redraw_putc(&ctx, &gc, '*'); + } else { + screen_redraw_puts(&ctx, &gc, + "%.*s", (int) left, c->prompt_buffer + offset); + } for (i = xx + size; i < c->sx; i++) { screen_redraw_putc(&ctx, &gc, ' '); @@ -601,15 +609,15 @@ status_prompt_key(struct client *c, int key) case '\r': /* enter */ if (*c->prompt_buffer != '\0') { status_prompt_add_history(c); - - c->prompt_callback(c->prompt_data, c->prompt_buffer); - server_clear_client_prompt(c); + if (c->prompt_callback( + c->prompt_data, c->prompt_buffer) == 0) + server_clear_client_prompt(c); break; } /* FALLTHROUGH */ case '\033': /* escape */ - c->prompt_callback(c->prompt_data, NULL); - server_clear_client_prompt(c); + if (c->prompt_callback(c->prompt_data, NULL) == 0) + server_clear_client_prompt(c); break; default: if (key < 32) diff --git a/tmux.c b/tmux.c index 64d50743..580c59e4 100644 --- a/tmux.c +++ b/tmux.c @@ -1,4 +1,4 @@ -/* $Id: tmux.c,v 1.91 2009-01-10 19:37:35 nicm Exp $ */ +/* $Id: tmux.c,v 1.92 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -50,6 +50,10 @@ char *cfg_file; struct options global_options; struct options global_window_options; +int server_locked; +char *server_password; +time_t server_activity; + int debug_level; int be_quiet; time_t start_time; @@ -170,20 +174,20 @@ int main(int argc, char **argv) { struct client_ctx cctx; - struct msg_command_data data; + struct msg_command_data cmddata; struct buffer *b; struct cmd *cmd; struct pollfd pfd; struct hdr hdr; const char *shell; struct passwd *pw; - char *path, *cause, *home; + char *path, *cause, *home, *pass = NULL; char rpath[MAXPATHLEN], cwd[MAXPATHLEN]; - int n, opt, flags; + int n, opt, flags, unlock, start_server; - flags = 0; + unlock = flags = 0; path = NULL; - while ((opt = getopt(argc, argv, "2df:qS:uVv")) != -1) { + while ((opt = getopt(argc, argv, "2df:qS:uUVv")) != -1) { switch (opt) { case '2': flags |= IDENTIFY_256COLOURS; @@ -200,6 +204,9 @@ main(int argc, char **argv) case 'u': flags |= IDENTIFY_UTF8; break; + case 'U': + unlock = 1; + break; case 'd': flags |= IDENTIFY_HASDEFAULTS; break; @@ -220,36 +227,37 @@ main(int argc, char **argv) siginit(); options_init(&global_options, NULL); - options_set_number(&global_options, "status", 1); - options_set_number(&global_options, "status-fg", 0); - options_set_number(&global_options, "status-bg", 2); options_set_number(&global_options, "bell-action", BELL_ANY); - options_set_number(&global_options, "history-limit", 2000); + options_set_number(&global_options, "buffer-limit", 9); options_set_number(&global_options, "display-time", 750); + options_set_number(&global_options, "history-limit", 2000); + options_set_number(&global_options, "message-bg", 3); + options_set_number(&global_options, "message-fg", 0); options_set_number(&global_options, "prefix", META); + options_set_number(&global_options, "set-titles", 1); + options_set_number(&global_options, "lock-after-time", 1800); + options_set_number(&global_options, "status", 1); + options_set_number(&global_options, "status-bg", 2); + options_set_number(&global_options, "status-fg", 0); + options_set_number(&global_options, "status-interval", 15); + options_set_number(&global_options, "status-left-length", 10); + options_set_number(&global_options, "status-right-length", 40); options_set_string(&global_options, "status-left", "%s", ""); /* ugh */ options_set_string( &global_options, "status-right", "\"#24T\" %%H:%%M %%d-%%b-%%y"); - options_set_number(&global_options, "status-left-length", 10); - options_set_number(&global_options, "status-right-length", 40); - options_set_number(&global_options, "status-interval", 15); - options_set_number(&global_options, "set-titles", 1); - options_set_number(&global_options, "buffer-limit", 9); - options_set_number(&global_options, "message-fg", 0); - options_set_number(&global_options, "message-bg", 3); options_init(&global_window_options, NULL); - options_set_number(&global_window_options, "xterm-keys", 0); - options_set_number(&global_window_options, "monitor-activity", 0); options_set_number(&global_window_options, "aggressive-resize", 0); - options_set_number(&global_window_options, "remain-on-exit", 0); - options_set_number(&global_window_options, "utf8", 0); - options_set_number(&global_window_options, "mode-fg", 0); - options_set_number(&global_window_options, "mode-bg", 3); - options_set_number(&global_window_options, "mode-keys", MODEKEY_EMACS); - options_set_number(&global_window_options, "force-width", 0); - options_set_number(&global_window_options, "force-height", 0); options_set_number(&global_window_options, "clock-mode-colour", 4); options_set_number(&global_window_options, "clock-mode-style", 1); + options_set_number(&global_window_options, "force-height", 0); + options_set_number(&global_window_options, "force-width", 0); + options_set_number(&global_window_options, "mode-bg", 3); + options_set_number(&global_window_options, "mode-fg", 0); + options_set_number(&global_window_options, "mode-keys", MODEKEY_EMACS); + options_set_number(&global_window_options, "monitor-activity", 0); + options_set_number(&global_window_options, "utf8", 0); + options_set_number(&global_window_options, "xterm-keys", 0); + options_set_number(&global_window_options, "remain-on-exit", 0); if (cfg_file == NULL) { home = getenv("HOME"); @@ -311,26 +319,43 @@ main(int argc, char **argv) } options_set_string(&global_options, "default-path", "%s", cwd); - if (argc == 0) { - cmd = xmalloc(sizeof *cmd); - cmd->entry = &cmd_new_session_entry; - cmd->entry->init(cmd, 0); - } else if ((cmd = cmd_parse(argc, argv, &cause)) == NULL) { - log_warnx("%s", cause); - exit(1); + if (unlock) { + if (argc != 0) { + log_warnx("can't specify a command when unlocking"); + exit(1); + } + cmd = NULL; + if ((pass = getpass("Password: ")) == NULL) + exit(1); + start_server = 0; + } else { + if (argc == 0) { + cmd = xmalloc(sizeof *cmd); + cmd->entry = &cmd_new_session_entry; + cmd->entry->init(cmd, 0); + } else if ((cmd = cmd_parse(argc, argv, &cause)) == NULL) { + log_warnx("%s", cause); + exit(1); + } + start_server = cmd->entry->flags & CMD_STARTSERVER; } - - memset(&cctx, 0, sizeof cctx); - client_fill_session(&data); - if (client_init( - rpath, &cctx, cmd->entry->flags & CMD_STARTSERVER, flags) != 0) + + memset(&cctx, 0, sizeof cctx); + if (client_init(rpath, &cctx, start_server, flags) != 0) exit(1); - b = buffer_create(BUFSIZ); - cmd_send(cmd, b); - cmd_free(cmd); - client_write_server2(&cctx, - MSG_COMMAND, &data, sizeof data, BUFFER_OUT(b), BUFFER_USED(b)); + b = buffer_create(BUFSIZ); + if (unlock) { + cmd_send_string(b, pass); + client_write_server( + &cctx, MSG_UNLOCK, BUFFER_OUT(b), BUFFER_USED(b)); + } else { + cmd_send(cmd, b); + cmd_free(cmd); + client_fill_session(&cmddata); + client_write_server2(&cctx, MSG_COMMAND, + &cmddata, sizeof cmddata, BUFFER_OUT(b), BUFFER_USED(b)); + } buffer_destroy(b); for (;;) { diff --git a/tmux.h b/tmux.h index 96e387e6..c280845b 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.220 2009-01-10 22:28:40 nicm Exp $ */ +/* $Id: tmux.h,v 1.221 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION -4 +#define PROTOCOL_VERSION -6 /* Shut up gcc warnings about empty if bodies. */ #define RB_AUGMENT(x) do {} while (0) @@ -361,15 +361,16 @@ enum tty_cmd { /* Message codes. */ enum hdrtype { MSG_COMMAND, - MSG_ERROR, - MSG_PRINT, - MSG_EXIT, - MSG_EXITING, - MSG_EXITED, MSG_DETACH, + MSG_ERROR, + MSG_EXIT, + MSG_EXITED, + MSG_EXITING, MSG_IDENTIFY, + MSG_PRINT, MSG_READY, MSG_RESIZE, + MSG_UNLOCK, }; /* Message header structure. */ @@ -754,8 +755,9 @@ struct client { char *prompt_string; char *prompt_buffer; size_t prompt_index; - void (*prompt_callback)(void *, char *); + int (*prompt_callback)(void *, const char *); void *prompt_data; + int prompt_hidden; u_int prompt_hindex; ARRAY_DECL(, char *) prompt_hdata; @@ -872,7 +874,7 @@ struct set_option_entry { }; extern const struct set_option_entry set_option_table[]; extern const struct set_option_entry set_window_option_table[]; -#define NSETOPTION 18 +#define NSETOPTION 19 #define NSETWINDOWOPTION 12 /* Edit keys. */ @@ -938,6 +940,9 @@ extern volatile sig_atomic_t sigterm; extern struct options global_options; extern struct options global_window_options; extern char *cfg_file; +extern int server_locked; +extern char *server_password; +extern time_t server_activity; extern int debug_level; extern int be_quiet; extern time_t start_time; @@ -1029,6 +1034,9 @@ int paste_free_index(struct paste_stack *, u_int); void paste_add(struct paste_stack *, const char *, u_int); int paste_replace(struct paste_stack *, u_int, const char *); +/* clock.c */ +void clock_draw(struct screen_write_ctx *, u_int, int); + /* arg.c */ struct client *arg_parse_client(const char *); struct session *arg_parse_session(const char *); @@ -1067,6 +1075,7 @@ extern const struct cmd_entry cmd_list_commands_entry; extern const struct cmd_entry cmd_list_keys_entry; extern const struct cmd_entry cmd_list_sessions_entry; extern const struct cmd_entry cmd_list_windows_entry; +extern const struct cmd_entry cmd_lock_server_entry; extern const struct cmd_entry cmd_move_window_entry; extern const struct cmd_entry cmd_new_session_entry; extern const struct cmd_entry cmd_new_window_entry; @@ -1078,13 +1087,14 @@ extern const struct cmd_entry cmd_rename_session_entry; extern const struct cmd_entry cmd_rename_window_entry; extern const struct cmd_entry cmd_respawn_window_entry; extern const struct cmd_entry cmd_scroll_mode_entry; +extern const struct cmd_entry cmd_select_prompt_entry; extern const struct cmd_entry cmd_select_window_entry; extern const struct cmd_entry cmd_send_keys_entry; extern const struct cmd_entry cmd_send_prefix_entry; extern const struct cmd_entry cmd_server_info_entry; -extern const struct cmd_entry cmd_select_prompt_entry; extern const struct cmd_entry cmd_set_buffer_entry; extern const struct cmd_entry cmd_set_option_entry; +extern const struct cmd_entry cmd_set_password_entry; extern const struct cmd_entry cmd_set_window_option_entry; extern const struct cmd_entry cmd_show_buffer_entry; extern const struct cmd_entry cmd_show_options_entry; @@ -1183,8 +1193,8 @@ int server_msg_dispatch(struct client *); /* server-fn.c */ void server_set_client_message(struct client *, const char *); void server_clear_client_message(struct client *); -void server_set_client_prompt( - struct client *, const char *, void (*)(void *, char *), void *); +void server_set_client_prompt(struct client *, + const char *, int (*)(void *, const char *), void *, int); void server_clear_client_prompt(struct client *); struct session *server_extract_session( struct msg_command_data *, char *, char **); @@ -1200,6 +1210,8 @@ void server_redraw_session(struct session *); void server_status_session(struct session *); void server_redraw_window(struct window *); void server_status_window(struct window *); +void server_lock(void); +int server_unlock(const char *); /* status.c */ void status_redraw(struct client *); diff --git a/window-clock.c b/window-clock.c index 9e075000..0462142d 100644 --- a/window-clock.c +++ b/window-clock.c @@ -1,4 +1,4 @@ -/* $Id: window-clock.c,v 1.2 2009-01-10 19:40:01 nicm Exp $ */ +/* $Id: window-clock.c,v 1.3 2009-01-11 00:48:42 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -41,6 +41,7 @@ const struct window_mode window_clock_mode = { struct window_clock_mode_data { struct screen screen; + time_t tim; }; struct screen * @@ -50,6 +51,7 @@ window_clock_init(struct window *w) struct screen *s; w->modedata = data = xmalloc(sizeof *data); + data->tim = time(NULL); s = &data->screen; screen_init(s, screen_size_x(&w->base), screen_size_y(&w->base), 0); @@ -88,6 +90,17 @@ window_clock_key(struct window *w, unused struct client *c, unused int key) void window_clock_timer(struct window *w) { + struct window_clock_mode_data *data = w->modedata; + struct tm *now, *then; + time_t t; + + t = time(NULL); + now = gmtime(&t); + then = gmtime(&data->tim); + if (now->tm_min == then->tm_min) + return; + data->tim = t; + window_clock_draw_screen(w); server_redraw_window(w); } @@ -96,141 +109,14 @@ void window_clock_draw_screen(struct window *w) { struct window_clock_mode_data *data = w->modedata; - struct screen *s = &data->screen; struct screen_write_ctx ctx; - struct grid_cell gc; - char tim[64], *ptr; - time_t t; - u_int colour, i, j, x, y, idx; - char table[14][5][5] = { - { { 1,1,1,1,1 }, /* 0 */ - { 1,0,0,0,1 }, - { 1,0,0,0,1 }, - { 1,0,0,0,1 }, - { 1,1,1,1,1 } }, - { { 0,0,0,0,1 }, /* 1 */ - { 0,0,0,0,1 }, - { 0,0,0,0,1 }, - { 0,0,0,0,1 }, - { 0,0,0,0,1 } }, - { { 1,1,1,1,1 }, /* 2 */ - { 0,0,0,0,1 }, - { 1,1,1,1,1 }, - { 1,0,0,0,0 }, - { 1,1,1,1,1 } }, - { { 1,1,1,1,1 }, /* 3 */ - { 0,0,0,0,1 }, - { 1,1,1,1,1 }, - { 0,0,0,0,1 }, - { 1,1,1,1,1 } }, - { { 1,0,0,0,1 }, /* 4 */ - { 1,0,0,0,1 }, - { 1,1,1,1,1 }, - { 0,0,0,0,1 }, - { 0,0,0,0,1 } }, - { { 1,1,1,1,1 }, /* 5 */ - { 1,0,0,0,0 }, - { 1,1,1,1,1 }, - { 0,0,0,0,1 }, - { 1,1,1,1,1 } }, - { { 1,1,1,1,1 }, /* 6 */ - { 1,0,0,0,0 }, - { 1,1,1,1,1 }, - { 1,0,0,0,1 }, - { 1,1,1,1,1 } }, - { { 1,1,1,1,1 }, /* 7 */ - { 0,0,0,0,1 }, - { 0,0,0,0,1 }, - { 0,0,0,0,1 }, - { 0,0,0,0,1 } }, - { { 1,1,1,1,1 }, /* 8 */ - { 1,0,0,0,1 }, - { 1,1,1,1,1 }, - { 1,0,0,0,1 }, - { 1,1,1,1,1 } }, - { { 1,1,1,1,1 }, /* 9 */ - { 1,0,0,0,1 }, - { 1,1,1,1,1 }, - { 0,0,0,0,1 }, - { 1,1,1,1,1 } }, - { { 0,0,0,0,0 }, /* : */ - { 0,0,1,0,0 }, - { 0,0,0,0,0 }, - { 0,0,1,0,0 }, - { 0,0,0,0,0 } }, - { { 1,1,1,1,1 }, /* A */ - { 1,0,0,0,1 }, - { 1,1,1,1,1 }, - { 1,0,0,0,1 }, - { 1,0,0,0,1 } }, - { { 1,1,1,1,1 }, /* P */ - { 1,0,0,0,1 }, - { 1,1,1,1,1 }, - { 1,0,0,0,0 }, - { 1,0,0,0,0 } }, - { { 1,0,0,0,1 }, /* M */ - { 1,1,0,1,1 }, - { 1,0,1,0,1 }, - { 1,0,0,0,1 }, - { 1,0,0,0,1 } }, - }; + u_int colour; + int style; colour = options_get_number(&w->options, "clock-mode-colour"); + style = options_get_number(&w->options, "clock-mode-style"); - t = time(NULL); - if (options_get_number(&w->options, "clock-mode-style") == 0) - strftime(tim, sizeof tim, "%l:%M %p", localtime(&t)); - else - strftime(tim, sizeof tim, "%H:%M", localtime(&t)); - - screen_write_start(&ctx, s, NULL, NULL); - screen_write_clearscreen(&ctx); - memcpy(&gc, &grid_default_cell, sizeof gc); - - if (screen_size_x(s) < 6 * strlen(tim) || screen_size_y(s) < 6) { - if (screen_size_x(s) >= strlen(tim) && screen_size_y(s) != 0) { - x = (screen_size_x(s) / 2) - (strlen(tim) / 2); - y = screen_size_y(s) / 2; - screen_write_cursormove(&ctx, x, y); - - gc.fg = colour; - screen_write_puts(&ctx, &gc, "%s", tim); - } - screen_write_stop(&ctx); - return; - } - - x = (screen_size_x(s) / 2) - 3 * strlen(tim); - y = (screen_size_y(s) / 2) - 3; - - for (ptr = tim; *ptr != '\0'; ptr++) { - if (*ptr >= '0' && *ptr <= '9') - idx = *ptr - '0'; - else if (*ptr == ':') - idx = 10; - else if (*ptr == 'A') - idx = 11; - else if (*ptr == 'P') - idx = 12; - else if (*ptr == 'M') - idx = 13; - else { - x += 6; - continue; - } - - for (j = 0; j < 5; j++) { - screen_write_cursormove(&ctx, x, y + j); - for (i = 0; i < 5; i++) { - if (table[idx][j][i]) - gc.bg = colour; - else - gc.bg = 0; - screen_write_putc(&ctx, &gc, ' '); - } - } - x += 6; - } - + screen_write_start(&ctx, &data->screen, NULL, NULL); + clock_draw(&ctx, colour, style); screen_write_stop(&ctx); }