# HG changeset patch # User Guido Berhoerster # Date 1505979959 -7200 # Node ID 5bdea77d0c1d41f69a631ddadb05d20b24074d22 # Parent 616385fa1fd9e19a76f07f6734e3bbd5d0ca5c99 Add pwm-clip utility for setting the X11 CLIPBOARD selection diff -r 616385fa1fd9 -r 5bdea77d0c1d Makefile --- a/Makefile Wed Sep 20 23:57:51 2017 +0200 +++ b/Makefile Thu Sep 21 09:45:59 2017 +0200 @@ -83,6 +83,7 @@ HAVE_ASPRINTF ?= 1 HAVE_CLOSEFROM ?= 0 HAVE_ERR_H ?= 1 + HAVE_GETLINE ?= 0 HAVE_GETRANDOM ?= 0 HAVE_SYS_QUEUE_H ?= 0 HAVE_SETPROGNAME ?= 0 @@ -92,6 +93,7 @@ HAVE_ASPRINTF ?= 1 HAVE_CLOSEFROM ?= 1 HAVE_ERR_H ?= 1 + HAVE_GETLINE ?= 1 HAVE_GETRANDOM ?= 0 HAVE_SYS_QUEUE_H ?= 1 HAVE_SETPROGNAME ?= 1 @@ -101,6 +103,7 @@ HAVE_ASPRINTF ?= 1 HAVE_CLOSEFROM ?= 1 HAVE_ERR_H ?= 1 + HAVE_GETLINE ?= 1 HAVE_GETRANDOM ?= 0 HAVE_SYS_QUEUE_H ?= 1 HAVE_SYS_TREE_H ?= 1 @@ -110,6 +113,7 @@ HAVE_ASPRINTF ?= 1 HAVE_CLOSEFROM ?= 1 HAVE_ERR_H ?= 1 + HAVE_GETLINE ?= 1 HAVE_GETRANDOM ?= 0 HAVE_SYS_QUEUE_H ?= 1 HAVE_SYS_TREE_H ?= 1 @@ -119,11 +123,13 @@ HAVE_ARC4RANDOM ?= 0 HAVE_ASPRINTF ?= 0 HAVE_ERR_H ?= 0 + HAVE_GETLINE ?= 0 HAVE_GETRANDOM ?= 0 else HAVE_ARC4RANDOM ?= 1 HAVE_ASPRINTF ?= 1 HAVE_ERR_H ?= 1 + HAVE_GETLINE ?= 1 HAVE_GETRANDOM ?= 1 endif HAVE_CLOSEFROM ?= 1 @@ -135,6 +141,7 @@ HAVE_ASPRINTF ?= 0 HAVE_CLOSEFROM ?= 0 HAVE_ERR_H ?= 0 + HAVE_GETLINE ?= 0 HAVE_GETRANDOM ?= 0 HAVE_SYS_QUEUE_H ?= 0 HAVE_SETPROGNAME ?= 0 @@ -149,6 +156,10 @@ LIBPWM_LIB = libpwm.a LIBPWM_LIB_MEMBERS = $(LIBPWM_OBJS:%.o=$(LIBPWM_LIB)(%.o)) +PWM_CLIP_OBJS = pwm-clip.o +PWM_CLIP_BIN = pwm-clip +PWM_CLIP_MAN1 = pwm-clip.1 + PWM_OBJS = cmd.o \ io.o \ pager.o \ @@ -158,20 +169,23 @@ pwm.o \ tok.o PWM_BIN = $(PACKAGE) +PWM_MAN1 = pwm.1 -OBJS = $(LIBCOMPAT_OBJS) $(LIBPWM_OBJS) $(PWM_OBJS) +OBJS = $(LIBCOMPAT_OBJS) $(LIBPWM_OBJS) $(PWM_CLIP_OBJS) $(PWM_OBJS) -MANPAGES = pwm.1 +MANPAGES = $(PWM_MAN1) $(PWM_CLIP_MAN1) .DEFAULT_TARGET = all .PHONY: all clean clobber dist install -all: $(PWM_BIN) $(MANPAGES) +all: $(PWM_BIN) $(PWM_CLIP_BIN) $(MANPAGES) $(PWM_BIN): XCPPFLAGS += -DPACKAGE=\"$(PACKAGE)\" \ -DVERSION=\"$(VERSION)\" $(PWM_BIN): LDLIBS = -ltecla -lcurses -lpws -lnettle +$(PWM_CLIP_BIN): XCPPFLAGS += -Icompat/include +$(PWM_CLIP_BIN): LDLIBS = -lnettle ifeq ($(HAVE_ASPRINTF),1) XCPPFLAGS += -DHAVE_ASPRINTF else @@ -196,6 +210,11 @@ else LIBCOMPAT_OBJS += compat/err.o endif +ifeq ($(HAVE_GETLINE),1) + XCPPFLAGS += -DHAVE_GETLINE +else + LIBCOMPAT_OBJS += compat/getline.o +endif ifeq ($(HAVE_SETPROGNAME),1) XCPPFLAGS += -DHAVE_SETPROGNAME else @@ -223,10 +242,15 @@ $(LIBPWM_LIB): $(LIBPWM_LIB_MEMBERS) +$(PWM_CLIP_BIN): $(PWM_CLIP_OBJS) $(LIBPWM_LIB) $(LIBCOMPAT_LIB) + $(LINK.o) $^ $(LDLIBS) -o $@ + +$(eval $(call generate-manpage-rule,$(PWM_CLIP_MAN1))) + $(PWM_BIN): $(PWM_OBJS) $(LIBPWM_LIB) $(LIBCOMPAT_LIB) $(LINK.o) $^ $(LDLIBS) -o $@ -$(eval $(call generate-manpage-rule,$(MANPAGES))) +$(eval $(call generate-manpage-rule,$(PWM_MAN1))) %.o: %.c $(MAKEDEPEND.c) $< | $(SED) -f deps.sed >$*.d @@ -238,6 +262,7 @@ install: all $(INSTALL.exec) $(PWM_BIN) "$(DESTDIR)$(bindir)/$(PWM_BIN)" + $(INSTALL.exec) $(PWM_CLIP_BIN) "$(DESTDIR)$(bindir)/$(PWM_CLIP_BIN)" for manpage in $(MANPAGES); do \ if [ -L $${manpage} ]; then \ $(INSTALL.link) $${manpage} \ @@ -249,7 +274,8 @@ done clean: - rm -f $(LIBCOMPAT_LIB) $(LIBPWM_LIB) $(PWM_BIN) $(OBJS) $(MANPAGES) + rm -f $(LIBCOMPAT_LIB) $(LIBPWM_LIB) $(PWM_CLIP_BIN) $(PWM_BIN) \ + $(OBJS) $(MANPAGES) clobber: clean rm -f $(patsubst %.o,%.d,$(OBJS)) diff -r 616385fa1fd9 -r 5bdea77d0c1d compat.h --- a/compat.h Wed Sep 20 23:57:51 2017 +0200 +++ b/compat.h Thu Sep 21 09:45:59 2017 +0200 @@ -39,6 +39,10 @@ #include "compat/err.h" #endif /* !HAVE_ERR_H */ +#ifndef HAVE_GETLINE +#include "compat/getline.h" +#endif /* !HAVE_GETLINE */ + #ifndef HAVE_GETENTROPY #include "compat/getentropy.h" #endif /* !HAVE_GETENTROPY */ diff -r 616385fa1fd9 -r 5bdea77d0c1d compat/getline.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/compat/getline.c Thu Sep 21 09:45:59 2017 +0200 @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2016 Guido Berhoerster + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "getline.h" + +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + +ssize_t +getdelim(char **linep, size_t *sizep, int delim, FILE *fp) +{ + ssize_t len; + char *line = *linep; + size_t size = *sizep; + size_t pos = 0; + char *line_new; + int c; + + if (*linep == NULL) { + size = 0; + } + + flockfile(fp); + + for (;;) { + if (size - pos < 2) { + size = MIN((size_t)SSIZE_MAX + 1, + (size < BUFSIZ) ? BUFSIZ : size * 1.5); + if (size - pos < 2) { + len = -1; + errno = EOVERFLOW; + break; + } + line_new = realloc(line, size); + if (line_new == NULL) { + len = -1; + break; + } + *linep = line = line_new; + *sizep = size; + } + c = fgetc(fp); + if (c == EOF) { + len = -1; + break; + } + line[pos] = c; + pos++; + len = pos; + if (c == delim) { + break; + } + } + + if (*linep != NULL) { + (*linep)[pos] = '\0'; + } + + funlockfile(fp); + + return (len); +} + +ssize_t +getline(char **linep, size_t *sizep, FILE *fp) +{ + return (getdelim(linep, sizep, '\n', fp)); +} diff -r 616385fa1fd9 -r 5bdea77d0c1d compat/getline.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/compat/getline.h Thu Sep 21 09:45:59 2017 +0200 @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Guido Berhoerster + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GETLINE_H +#define GETLINE_H + +#include +#include + +ssize_t getline(char **, size_t *, FILE *); +ssize_t getdelim(char **, size_t *, int, FILE *); + +#endif /* !GETLINE_H */ diff -r 616385fa1fd9 -r 5bdea77d0c1d pwm-clip.1.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pwm-clip.1.xml Thu Sep 21 09:45:59 2017 +0200 @@ -0,0 +1,120 @@ + + + + + + + Guido + Berhoerster + + guido+pwm@berhoerster.name + + + 21 September, 2017 + + + pwm-clip + 1 + + + User Commands + + + pwm-clip + set the system clipboard + + + + pwm-clip + + + + Description + The pwm-clip utility reads from the standard input + stream until it encounters a newline character or the stream is at + end-of-file, then removes any newline character at the end and places the + data in the system clipboard. On X11 systems it sets the CLIPBOARD + selection. + The following terminals are currently supported: + + xterm + tmux + screen + + + If pwm-clip is invoked in an unsupported terminal + it will print an error message and exit. + + + Environment Variables + + + + TERM + + + The name of the terminal used by pwm-clip to + determine whether setting the system clipboard is supported + + + + + + Exit Status + The following exit values are returned: + + + 0 + + Command successfully executed. + + + + 1 + + An unspecified error has occured. + + + + 2 + + Invalid command line options were specified. + + + + + + See Also + pwm + 1, + xterm + 1, + tmux + 1, + screen + 1 + + diff -r 616385fa1fd9 -r 5bdea77d0c1d pwm-clip.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pwm-clip.c Thu Sep 21 09:45:59 2017 +0200 @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2017 Guido Berhoerster + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "compat.h" + +#ifdef HAVE_ERR_H +#include +#endif /* HAVE_ERR_H */ +#include +#include +#include +#include +#include +#include + +#include "util.h" + +#define CHUNK_SIZE 128 + +static char * +base64_encode(const unsigned char *src, size_t size) +{ + char *dst = NULL; + struct base64_encode_ctx b64_ctx; + size_t len = 0; + + dst = xmalloc(BASE64_ENCODE_LENGTH(size) + + BASE64_ENCODE_FINAL_LENGTH); + + base64_encode_init(&b64_ctx); + len += base64_encode_update(&b64_ctx, (unsigned char *)dst, size, src); + len += base64_encode_final(&b64_ctx, (unsigned char *)dst); + dst[len] = '\0'; + + dst = xrealloc(dst, len + 1); + + return (dst); +} + +static void +set_clipboard(const char *s) +{ + char *b64 = NULL; + + b64 = base64_encode((const unsigned char *)s, strlen(s)); + printf("\033]52;c;%s\a\n", b64); + free(b64); +} + +static void +set_clipboard_dcs_tmux(const char *s) +{ + char *b64 = NULL; + + b64 = base64_encode((const unsigned char *)s, strlen(s)); + printf("\033Ptmux;\033\033]52;c;%s\a\033\\", b64); + free(b64); +} + +static void +set_clipboard_dcs_chunked(const char *s) +{ + char *b64 = NULL; + size_t i; + + b64 = base64_encode((const unsigned char *)s, strlen(s)); + + printf("\033P\033]52;c;"); + for (i = 0; b64[i] != '\0'; i++) { + if ((i > 0) && (i % CHUNK_SIZE == 0)) { + printf("\033\\\033P"); + } + putchar(b64[i]); + } + printf("\a\033\\"); + + free(b64); +} + +static void +usage(void) +{ + fprintf(stderr, "usage: %s\n", getprogname()); +} + +int +main(int argc, char *argv[]) +{ + int status = EXIT_FAILURE; + char *term; + void (*set_clipboard_func)(const char *); + int errflag = 0; + int c; + ssize_t len; + char *s = NULL; + size_t size = 0; + + setprogname(argv[0]); + + term = getenv("TERM"); + if (term == NULL) { + fprintf(stderr, "error: unknown terminal\n"); + goto out; + } else if (strncmp(term, "xterm", strlen("xterm")) == 0) { + set_clipboard_func = set_clipboard; + } else if (strncmp(term, "tmux", strlen("tmux")) == 0) { + set_clipboard_func = set_clipboard_dcs_tmux; + } else if (strncmp(term, "screen", strlen("screen")) == 0) { + if (getenv("TMUX") != NULL) { + set_clipboard_func = set_clipboard_dcs_tmux; + } else { + set_clipboard_func = set_clipboard_dcs_chunked; + } + } else { + fprintf(stderr, "terminal does not support setting " + "X11 CLIPBOARD selection\n"); + goto out; + } + + while (!errflag && (c = getopt(argc, argv, "h")) != -1) { + switch (c) { + case 'h': + usage(); + exit(EXIT_SUCCESS); + default: + errflag = 1; + } + } + if (errflag || (optind + 1 < argc)) { + usage(); + exit(EXIT_USAGE); + } + + errno = 0; + len = getline(&s, &size, stdin); + if (len < 0) { + if (errno == 0) { + fprintf(stderr, "failed to read line\n"); + goto out; + } else { + err(1, "getline"); + } + } + if ((len > 0) && (s[len - 1] == '\n')) { + s[--len] = '\0'; + } + + set_clipboard_func(s); + + status = EXIT_SUCCESS; + +out: + free(s); + + exit(status); +} diff -r 616385fa1fd9 -r 5bdea77d0c1d pwm.1.xml --- a/pwm.1.xml Wed Sep 20 23:57:51 2017 +0200 +++ b/pwm.1.xml Thu Sep 21 09:45:59 2017 +0200 @@ -74,8 +74,10 @@ pwm provides commands to create, modify, delete, and display password database entries which may be organized in groups. The contents of a field of a given entry can also be piped to an external - command, e.g. in order to copy the content of the username or password - field of an entry to the clipboard. + command such as the pwm-clip + 1 utility in order to copy the + content of the username or password field of an entry to the + clipboard. If specified, pwm will open or create database_file instead of the user's default database. @@ -672,7 +674,9 @@ See Also - pwsafe + pwm-clip + 1, + pwsafe 1, sh 1,