Mercurial > projects > pwm
changeset 26:5bdea77d0c1d
Add pwm-clip utility for setting the X11 CLIPBOARD selection
author | Guido Berhoerster <guido+pwm@berhoerster.name> |
---|---|
date | Thu, 21 Sep 2017 09:45:59 +0200 |
parents | 616385fa1fd9 |
children | 722a45b4028b |
files | Makefile compat.h compat/getline.c compat/getline.h pwm-clip.1.xml pwm-clip.c pwm.1.xml |
diffstat | 7 files changed, 464 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- 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))
--- 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 */
--- /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 <guido+pwm@berhoerster.name> + * + * 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 <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <sys/types.h> +#include <errno.h> + +#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)); +}
--- /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 <guido+pwm@berhoerster.name> + * + * 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 <sys/types.h> +#include <stdio.h> + +ssize_t getline(char **, size_t *, FILE *); +ssize_t getdelim(char **, size_t *, int, FILE *); + +#endif /* !GETLINE_H */
--- /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 @@ +<?xml version="1.0"?> +<!-- + +Copyright (C) 2017 Guido Berhoerster <guido+pwm@berhoerster.name> + +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. + +--> +<refentry xmlns="http://docbook.org/ns/docbook" xml:lang="en"> + <info> + <author> + <personname> + <firstname>Guido</firstname> + <surname>Berhoerster</surname> + </personname> + <email>guido+pwm@berhoerster.name</email> + <personblurb/> + </author> + <date>21 September, 2017</date> + </info> + <refmeta> + <refentrytitle>pwm-clip</refentrytitle> + <manvolnum>1</manvolnum> + <refmiscinfo class="source"/> + <refmiscinfo class="version"/> + <refmiscinfo class="manual">User Commands</refmiscinfo> + </refmeta> + <refnamediv> + <refname>pwm-clip</refname> + <refpurpose>set the system clipboard</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>pwm-clip</command> + </cmdsynopsis> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para>The <command>pwm-clip</command> 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.</para> + <para>The following terminals are currently supported: + <simplelist type="horiz" columns="3"> + <member>xterm</member> + <member>tmux</member> + <member>screen</member> + </simplelist> + </para> + <para>If <command>pwm-clip</command> is invoked in an unsupported terminal + it will print an error message and exit.</para> + </refsect1> + <refsect1> + <title>Environment Variables</title> + <variablelist> + <varlistentry> + <term> + <literal>TERM</literal> + </term> + <listitem> + <para>The name of the terminal used by <command>pwm-clip</command> to + determine whether setting the system clipboard is supported</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>Exit Status</title> + <para>The following exit values are returned:</para> + <variablelist> + <varlistentry> + <term>0</term> + <listitem> + <para>Command successfully executed.</para> + </listitem> + </varlistentry> + <varlistentry> + <term>1</term> + <listitem> + <para>An unspecified error has occured.</para> + </listitem> + </varlistentry> + <varlistentry> + <term>2</term> + <listitem> + <para>Invalid command line options were specified.</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>See Also</title> + <para><citerefentry><refentrytitle>pwm</refentrytitle> + <manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>xterm</refentrytitle> + <manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>tmux</refentrytitle> + <manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>screen</refentrytitle> + <manvolnum>1</manvolnum></citerefentry></para> + </refsect1> +</refentry>
--- /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 <guido+pwm@berhoerster.name> + * + * 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 <err.h> +#endif /* HAVE_ERR_H */ +#include <errno.h> +#include <nettle/base64.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +#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); +}
--- 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 @@ <command>pwm</command> 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.</para> + command such as the <citerefentry><refentrytitle>pwm-clip</refentrytitle> + <manvolnum>1</manvolnum></citerefentry> utility in order to copy the + content of the username or password field of an entry to the + clipboard.</para> <para>If specified, <command>pwm</command> will open or create <replaceable>database_file</replaceable> instead of the user's default database.</para> @@ -672,7 +674,9 @@ </refsect1> <refsect1> <title>See Also</title> - <para><citerefentry><refentrytitle>pwsafe</refentrytitle> + <para><citerefentry><refentrytitle>pwm-clip</refentrytitle> + <manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>pwsafe</refentrytitle> <manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>sh</refentrytitle> <manvolnum>1</manvolnum></citerefentry>,