Introduction
Introduction Statistics Contact Development Disclaimer Help
Initial commit of 2.0. - thinglaunch - A simple command and password promtper f…
git clone git://bitreich.org/thinglaunch
Log
Files
Refs
Tags
LICENSE
---
commit 606c0f24754b284bacbb8de22ef5d0c73f065e8f
Author: Christoph Lohmann <[email protected]>
Date: Sun, 27 Mar 2011 18:50:19 +0200
Initial commit of 2.0.
Diffstat:
A LICENSE | 23 +++++++++++++++++++++++
A LICENSE.orig | 41 +++++++++++++++++++++++++++++…
A Makefile | 58 ++++++++++++++++++++++++++++++
A README.md | 36 +++++++++++++++++++++++++++++…
A config.h | 5 +++++
A config.mk | 26 ++++++++++++++++++++++++++
A thinglaunch.c | 466 +++++++++++++++++++++++++++++…
7 files changed, 655 insertions(+), 0 deletions(-)
---
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,23 @@
+MIT/X Consortium License
+
+© 2011 Christoph Lohmann <[email protected]>
+
+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.
+
+SEE LICENSE.orig FOR FURTHER APPLYING LICENSE TERMS.
diff --git a/LICENSE.orig b/LICENSE.orig
@@ -0,0 +1,41 @@
+/* This program is a quick little launcher program for X.
+ *
+ * You run the program, it grabs the display (hopefully nothing else has it
+ * grabbed), and you type what you want to run. The styling is minimalist.
+ *
+ * (c) 2003 Matt Johnston
+ * matt (at) ucc.asn.au
+ *
+ * Compile it with
+ * cc thinglaunch.c -o thinglaunch -lX11 -L/usr/X11R6/lib -lpthread
+ * (works for Linux and OSF/1 anyway, for static you might need -ldl, and you
+ * mightn't need -lpthread.)
+ *
+ * This program can be freely distributed in source or binary form, under a
+ * quite permissive license. See the bottom of this file for the full license.
+ * If that license is too restrictive, mail me and you can choose another one.
+ *
+ * $Id: thinglaunch.c,v 1.8 2004/09/20 14:27:48 matt Exp $
+ */
+/*
+Copyright (c) 2003 Matt Johnston
+All rights reserved.
+
+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.
+*/
diff --git a/Makefile b/Makefile
@@ -0,0 +1,58 @@
+# thinglaunch
+# See LICENSE file for copyright and license details.
+
+include config.mk
+
+SRC = ${NAME}.c
+
+OBJ = ${SRC:.c=.o}
+
+all: options ${NAME}
+
+options:
+ @echo ${NAME} build options:
+ @echo "CFLAGS = ${CFLAGS}"
+ @echo "LDFLAGS = ${LDFLAGS}"
+ @echo "CC = ${CC}"
+
+.c.o:
+ @echo CC $<
+ @${CC} -c ${CFLAGS} $<
+
+${OBJ}: config.mk
+
+${NAME}: ${OBJ}
+ @echo CC -o $@
+ @${CC} -o $@ ${OBJ} ${LDFLAGS}
+ @ln -s ${NAME} thingaskpass
+
+clean:
+ @echo cleaning
+ @rm -f ${NAME} thingaskpass ${OBJ} ${NAME}-${VERSION}.tar.gz
+
+dist: clean
+ @echo creating dist tarball
+ @mkdir -p ${NAME}-${VERSION}
+ @cp -R LICENSE LICENSE.orig Makefile README.md config.mk \
+ ${SRC} *.h ${NAME}-${VERSION}
+ @tar -cf ${NAME}-${VERSION}.tar ${NAME}-${VERSION}
+ @gzip ${NAME}-${VERSION}.tar
+ @rm -rf ${NAME}-${VERSION}
+
+etc:
+ @echo installing etc files into ${DESTDIR}/etc/${NAME}
+ @mkdir -p ${DESTDIR}/etc/${NAME}
+ @cp -R etc/${NAME}/* ${DESTDIR}/etc/${NAME}
+
+install: all
+ @echo installing executable file to ${DESTDIR}${PREFIX}/bin
+ @mkdir -p ${DESTDIR}${PREFIX}/bin
+ @cp -f ${NAME} thingaskpass ${DESTDIR}${PREFIX}/bin
+ @chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME}
+
+uninstall:
+ @echo removing executable file from ${DESTDIR}${PREFIX}/bin
+ @rm -f ${DESTDIR}${PREFIX}/bin/${NAME}
+ @rm -f ${DESTDIR}${PREFIX}/bin/thingaskpass
+
+.PHONY: all options clean dist install uninstall
diff --git a/README.md b/README.md
@@ -0,0 +1,36 @@
+# Thinglaunch - a simple entry box for X11
+
+The first intention, as done by the original creator Matt Johnston
+<[email protected]>, was to launch simple commandlines.
+
+In 2011 the single file project was extended by features like Unicode
+support, a prompt and an ssh-askpass compatibility layer.
+
+## Installation
+
+ % tar -xzvf thinglaunch-*.tar.gz
+ % cd thinglaunch
+ % make
+ % sudo PREFIX=/usr make install
+
+This will create the executable »thinglaunch« and »thingaskpass« in
+»/usr/bin«. Thinglaunch will ask for a command and execute it and
+thingaskpass can be used as a SSH_ASKPASS parameter value, which will
+be used by ssh-agent to gather the password for private keys.
+
+## Usage
+
+ # Get some input string and print it to stdout. There will
+ # be the prompt prepended "to stdout> ".
+ % thinglaunch -o -p "to stdout> "
+
+ # Ask for a command, which will be executed. During entering
+ # the command, the entered string will be replaced by asterisks.
+ % thinglaunch -s -p "secret cmd> "
+
+ # This symlink predefines -s, -o and -p "secret> ".
+ % ln -s thinglaunch thingaskpass
+ % ./thingaskpass
+
+Have fun!
+
diff --git a/config.h b/config.h
@@ -0,0 +1,5 @@
+static const char *font = "-*-*-medium-*-*-*-14-*-*-*-*-*-*-*";
+static const char *prompt = "exec> ";
+static const char *normbgcolor = "#222222";
+static const char *normfgcolor = "#cccccc";
+
diff --git a/config.mk b/config.mk
@@ -0,0 +1,26 @@
+# thinglaunch metadata
+NAME = thinglaunch
+VERSION = 2.00
+
+# Customize below to fit your system
+
+# paths
+PREFIX ?= /usr
+MANPREFIX = ${PREFIX}/share/man
+
+X11INC = /usr/X11R6/include
+X11LIB = /usr/X11R6/lib
+
+# includes and libs
+INCS = -I. -I/usr/include
+LIBS = -L/usr/lib -L${X11LIB} -lc -lX11
+
+# flags
+CPPFLAGS = -DVERSION=\"${VERSION}\"
+CFLAGS = -g -std=gnu99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
+LDFLAGS = -g ${LIBS}
+#LDFLAGS = -s ${LIBS}
+
+# compiler and linker
+CC = cc
+
diff --git a/thinglaunch.c b/thinglaunch.c
@@ -0,0 +1,466 @@
+/*
+ * Copy me if you can.
+ * by 20h
+ *
+ * For now this is a slightly modified version of the original from
+ * Matt Johnston <[email protected]>. See LICENSE.orig for his messages.
+ */
+#include <unistd.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+#include <X11/Xlocale.h>
+#include <locale.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <strings.h>
+#include <libgen.h>
+#include <wchar.h>
+
+#include "config.h"
+
+unsigned long getcolor(const char *colstr);
+void createwindow(void);
+void setupgc(void);
+void eventloop(void);
+void grabhack(void);
+void redraw(void);
+void keypress(XKeyEvent *keyevent);
+void execcmd(void);
+void die(char *errstr, ...);
+
+Display *dpy;
+GC gc;
+GC rectgc;
+XIM im;
+XIC ic;
+Window win;
+XFontStruct *font_info;
+XFontSet fontset;
+int screen, issecret = 0, tostdout = 0;
+unsigned long fgcol, bgcol;
+
+#define MAXCMD 255
+#define WINWIDTH 640
+#define WINHEIGHT 25
+
+/* the actual commandline */
+wchar_t command[MAXCMD+1];
+wchar_t secret[MAXCMD+1];
+char cbuf[MAXCMD*4+1];
+
+void
+usage(char *argv0)
+{
+ fprintf(stderr, "usage: %s [-hos] [-p prompt]\n", argv0);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+
+ if (strstr(argv[0], "thingaskpass")) {
+ issecret = 1;
+ tostdout = 1;
+ prompt = "secret> ";
+ }
+ if (argc > 1) {
+ for (i = 1; argv[i]; i++) {
+ if (argv[i][0] == '-') {
+ switch (argv[i][1]) {
+ case 'o':
+ tostdout = 1;
+ break;
+ case 's':
+ issecret = 1;
+ break;
+ case 'p':
+ if (!argv[i+1])
+ usage(argv[0]);
+ prompt = argv[i+1];
+ i++;
+ break;
+ default:
+ case 'h':
+ usage(argv[0]);
+ break;
+ }
+ }
+ }
+ }
+
+ bzero(command, sizeof(command));
+ bzero(secret, sizeof(secret));
+
+ createwindow();
+ setupgc();
+ grabhack();
+ eventloop();
+
+ return 0;
+}
+
+unsigned long
+getcolor(const char *colstr)
+{
+ Colormap cmap = DefaultColormap(dpy, screen);
+ XColor color;
+
+ if (!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
+ die("error, canno allocate color '%s'\n", colstr);
+ return color.pixel;
+}
+
+/*
+ * Stolen from:
+ * http://menehune.opt.wfu.edu/Kokua/Irix_6.5.21_doc_cd/usr/share/\
+ * Insight/library/SGI_bookshelves/SGI_Developer/books/XLib_PG/sgi_\
+ * html/ch11.html#S2-1002-11-11
+ */
+XIMStyle
+choosebetterstyle(XIMStyle style1, XIMStyle style2)
+{
+ XIMStyle s,t;
+ XIMStyle preedit = XIMPreeditArea | XIMPreeditCallbacks |
+ XIMPreeditPosition | XIMPreeditNothing | XIMPreeditNone;
+ XIMStyle status = XIMStatusArea | XIMStatusCallbacks |
+ XIMStatusNothing | XIMStatusNone;
+ if (style1 == 0) return style2;
+ if (style2 == 0) return style1;
+ if ((style1 & (preedit | status)) == (style2 & (preedit | status)))
+ return style1;
+ s = style1 & preedit;
+ t = style2 & preedit;
+ if (s != t) {
+ if (s | t | XIMPreeditCallbacks)
+ return (s == XIMPreeditCallbacks)?style1:style2;
+ else if (s | t | XIMPreeditPosition)
+ return (s == XIMPreeditPosition)?style1:style2;
+ else if (s | t | XIMPreeditArea)
+ return (s == XIMPreeditArea)?style1:style2;
+ else if (s | t | XIMPreeditNothing)
+ return (s == XIMPreeditNothing)?style1:style2;
+ }
+ else { /* if preedit flags are the same, compare status flags */
+ s = style1 & status;
+ t = style2 & status;
+ if (s | t | XIMStatusCallbacks)
+ return (s == XIMStatusCallbacks)?style1:style2;
+ else if (s | t | XIMStatusArea)
+ return (s == XIMStatusArea)?style1:style2;
+ else if (s | t | XIMStatusNothing)
+ return (s == XIMStatusNothing)?style1:style2;
+ }
+}
+
+void
+initim(void)
+{
+ XIMStyles *im_supported_styles;
+ XIMStyle app_supported_styles;
+ XIMStyle style;
+ XIMStyle best_style;
+ XVaNestedList list;
+ char **missing_charsets;
+ int num_missing_charsets = 0;
+ char *default_string;
+ int i;
+
+ fontset = XCreateFontSet(dpy, font, &missing_charsets,
+ &num_missing_charsets, &default_string);
+ if (num_missing_charsets > 0)
+ XFreeStringList(missing_charsets);
+
+ if (!(im = XOpenIM(dpy, NULL, NULL, NULL)))
+ die("Couldn't open input method.\n");
+
+ XGetIMValues(im, XNQueryInputStyle, &im_supported_styles, NULL);
+ app_supported_styles = XIMPreeditNone | XIMPreeditNothing \
+ | XIMPreeditArea;
+ app_supported_styles |= XIMStatusNone | XIMStatusNothing \
+ | XIMStatusArea;
+
+ for(i = 0, best_style = 0; i < im_supported_styles->count_styles;
+ i++) {
+ style = im_supported_styles->supported_styles[i];
+ if ((style & app_supported_styles) == style)
+ best_style = choosebetterstyle(style, best_style);
+ }
+ if (best_style == 0)
+ die("no common shared interaction style found.\n");
+ XFree(im_supported_styles);
+
+ list = XVaCreateNestedList(0, XNFontSet, fontset, NULL);
+ ic = XCreateIC(im, XNInputStyle, best_style, XNClientWindow, win,
+ XNPreeditAttributes, list, XNStatusAttributes,
+ list, NULL);
+ XFree(list);
+ if (ic == NULL)
+ die("Could not create input context.\n");
+}
+
+void
+createwindow(void)
+{
+ char *display_name;
+ int display_width, display_height;
+ int top, left;
+ XSizeHints *win_size_hints;
+ XSetWindowAttributes attrib;
+
+ if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
+ fprintf(stderr, "warning: no locale support.\n");
+
+ display_name = getenv("DISPLAY");
+ if (display_name == NULL)
+ die("DISPLAY not set");
+
+ dpy = XOpenDisplay(display_name);
+ if (dpy == NULL)
+ die("Couldn't connect to DISPLAY");
+
+ if (!XSetLocaleModifiers(""))
+ fprintf(stderr, "warning: could not set local modifiers.\n");
+
+ initim();
+
+ screen = DefaultScreen(dpy);
+ display_width = DisplayWidth(dpy, screen);
+ display_height = DisplayHeight(dpy, screen);
+
+ top = (display_height/2 - WINHEIGHT/2);
+ left = (display_width/2 - WINWIDTH/2);
+
+ bgcol = getcolor(normbgcolor);
+ fgcol = getcolor(normfgcolor);
+
+ /*win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen),
+ left, top, WINWIDTH, WINHEIGHT, borderwidth,
+ bgcol, bgcol);*/
+
+ attrib.override_redirect= True;
+ win = XCreateWindow(dpy, RootWindow(dpy, screen),
+ left, top, WINWIDTH, WINHEIGHT,
+ 0, CopyFromParent,InputOutput,CopyFromParent,
+ CWOverrideRedirect,&attrib);
+
+ /* set up the window hints etc */
+ win_size_hints = XAllocSizeHints();
+ if (!win_size_hints)
+ die("out of memory allocating hints");
+
+ win_size_hints->flags = PMaxSize | PMinSize;
+ win_size_hints->min_width = win_size_hints->max_width = WINWIDTH;
+
+ win_size_hints->min_height = win_size_hints->max_height = WINHEIGHT;
+ XSetWMNormalHints(dpy, win, win_size_hints);
+
+ XFree(win_size_hints);
+
+ XMapWindow(dpy, win);
+}
+
+void
+setupgc(void)
+{
+ XGCValues values;
+ int valuemask = 0;
+ int line_width = 1;
+ int line_style = LineSolid;
+ int cap_style = CapButt;
+ int join_style = JoinBevel;
+
+ gc = XCreateGC(dpy, win, valuemask, &values);
+ rectgc = XCreateGC(dpy, win, valuemask, &values);
+ XSetForeground(dpy, gc, fgcol);
+ XSetBackground(dpy, gc, bgcol);
+
+ XSetForeground(dpy, rectgc, bgcol);
+ XSetBackground(dpy, rectgc, bgcol);
+
+ XSetLineAttributes(dpy, gc, line_width, line_style,
+ cap_style, join_style);
+
+ /* setup the font */
+ font_info = XLoadQueryFont(dpy, font);
+ if (!font_info)
+ die("couldn't load font");
+
+ XSetFont(dpy, gc, font_info->fid);
+}
+
+void
+eventloop(void)
+{
+ XEvent e;
+
+ redraw();
+
+ XSelectInput(dpy, win, ExposureMask | KeyPressMask);
+
+ for (;;) {
+ XNextEvent(dpy, &e);
+ switch(e.type) {
+ case Expose:
+ redraw();
+ break;
+ case KeyPress:
+ keypress(&e.xkey);
+ break;
+ default:
+ break;
+ }
+
+ }
+}
+
+/* this loop is required since pwm grabs the keyboard during the event loop */
+void
+grabhack(void)
+{
+ int maxwait = 3000000; /* 3 seconds */
+ int interval = 5000; /* 5 millisec */
+ int i, x;
+
+ redraw();
+
+ /* if it takes longer than maxwait, just die */
+ for (i = 0; i < (maxwait / interval); i++) {
+ usleep(interval);
+ x = XGrabKeyboard(dpy, win, False, GrabModeAsync,
+ GrabModeAsync, CurrentTime);
+ if (x == 0)
+ return;
+ }
+
+ die("Couldn't grab keyboard");
+}
+
+void
+redraw(void)
+{
+ int font_height, textwidth, promptwidth, dir, ascent, descent;
+ XCharStruct cs;
+ XRectangle ink, logical;
+
+ font_height = font_info->ascent + font_info->descent;
+ XTextExtents(font_info, prompt, strlen(prompt), &dir, &ascent,
+ &descent, &cs);
+ promptwidth = cs.width;
+ XwcTextExtents(fontset, command, wcslen(command), &ink, &logical);
+ textwidth = logical.width;
+ textwidth += promptwidth;
+
+ XFillRectangle(dpy, win, rectgc, 0, 0, WINWIDTH, WINHEIGHT);
+ XDrawRectangle(dpy, win, gc, 0, 0, WINWIDTH-1, WINHEIGHT-1);
+ XDrawString(dpy, win, gc, 2, font_height+2, prompt,
+ strlen(prompt));
+ XwcDrawString(dpy, win, fontset, gc, 4 + promptwidth,
+ font_height+2, command, wcslen(command));
+ XDrawLine(dpy, win, gc, 4 + textwidth, font_height + 2,
+ 4 + textwidth + 10, font_height+2);
+
+ XFlush(dpy);
+}
+
+void
+keypress(XKeyEvent *keyevent)
+{
+ KeySym key_symbol;
+ int len;
+ wchar_t buffer[3];
+
+ len = XwcLookupString(ic, keyevent, buffer, 3, &key_symbol, NULL);
+ buffer[len] = L'\0';
+
+ switch(key_symbol) {
+ case XK_Escape:
+ exit(0);
+ break;
+ case XK_BackSpace:
+ len = wcslen(command);
+ if (len > 0) {
+ command[len-1] = L'\0';
+ if (issecret)
+ secret[len-1] = L'\0';
+ }
+ break;
+ case XK_Return:
+ case XK_KP_Enter:
+ execcmd();
+ break;
+ default:
+ if (key_symbol > 255)
+ break;
+
+ len = wcslen(command);
+ if (len < MAXCMD) {
+ if (issecret) {
+ secret[len] = buffer[0];
+ secret[len+1] = L'\0';
+ command[len] = L'*';
+ command[len+1] = L'\0';
+ } else {
+ command[len] = buffer[0];
+ command[len+1] = L'\0';
+ }
+ }
+ break;
+ }
+ redraw();
+}
+
+void
+execcmd(void)
+{
+ char *shell;
+ char *argv[4];
+
+ XDestroyWindow(dpy, win);
+
+ bzero(cbuf, sizeof(cbuf));
+ if (issecret)
+ wcstombs(cbuf, secret, sizeof(cbuf)-1);
+ else
+ wcstombs(cbuf, command, sizeof(cbuf)-1);
+
+ if (tostdout) {
+ printf("%s\n", cbuf);
+ exit(0);
+ }
+
+ if (fork())
+ exit(0);
+
+ shell = getenv("SHELL");
+ if (!shell)
+ shell = "/bin/sh";
+
+ argv[0] = basename(shell);
+ argv[1] = "-c";
+ argv[2] = cbuf;
+ argv[3] = NULL;
+
+ execv(shell, argv);
+ die("aiee, after exec");
+
+}
+
+
+void
+die(char *errstr, ...)
+{
+ va_list ap;
+
+ va_start(ap, errstr);
+ vfprintf(stderr, errstr, ap);
+ va_end(ap);
+
+ exit(1);
+}
+
You are viewing proxied material from bitreich.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.