URI: 
       thinglaunch.c - thinglaunch - A simple command and password promtper for X11.
  HTML git clone git://bitreich.org/thinglaunch
   DIR Log
   DIR Files
   DIR Refs
   DIR Tags
   DIR LICENSE
       ---
       thinglaunch.c (10624B)
       ---
            1 /*
            2  * Copy me if you can.
            3  * by 20h
            4  *
            5  * For now this is a slightly modified version of the original from
            6  * Matt Johnston <matt@ucc.asn.au>. See LICENSE.orig for his messages.
            7  */
            8 
            9 #include <X11/keysym.h>
           10 #include <X11/Xlib.h>
           11 #include <X11/Xatom.h>
           12 #include <X11/Xutil.h>
           13 #include <X11/Xlocale.h>
           14 
           15 #include <errno.h>
           16 #include <libgen.h>
           17 #include <locale.h>
           18 #include <stdio.h>
           19 #include <stdlib.h>
           20 #include <stdarg.h>
           21 #include <string.h>
           22 #include <strings.h>
           23 #include <unistd.h>
           24 #include <wchar.h>
           25 
           26 #include "arg.h"
           27 #include "config.h"
           28 
           29 unsigned long getcolor(const char *colstr);
           30 XIMStyle choosebetterstyle(XIMStyle style1, XIMStyle style2);
           31 void initim(void);
           32 void createwindow(void);
           33 void setupgc(void);
           34 void eventloop(void);
           35 void grabhack(void);
           36 void redraw(void);
           37 void keypress(XKeyEvent *keyevent);
           38 void execcmd(void);
           39 void die(char *errstr, ...);
           40 
           41 Display *dpy;
           42 GC gc;
           43 GC rectgc;
           44 XIM im;
           45 XIC ic;
           46 Window win;
           47 XFontStruct *font_info;
           48 XFontSet fontset;
           49 int screen, issecret = 0, tostdout = 0;
           50 unsigned long fgcol, bgcol;
           51 static char *name = "thinglaunch";
           52 
           53 char *argv0;
           54 
           55 #define MAXCMD 255
           56 #define WINWIDTH 640
           57 #define WINHEIGHT 25
           58 
           59 /* the actual commandline */
           60 wchar_t command[MAXCMD+1];
           61 wchar_t secret[MAXCMD+1];
           62 char cbuf[MAXCMD*4+1];
           63 
           64 void
           65 usage(void)
           66 {
           67         fprintf(stderr, "usage: %s [-hos] [-p prompt]\n", argv0);
           68         exit(1);
           69 }
           70 
           71 int
           72 main(int argc, char *argv[])
           73 {
           74         char promptb[256];
           75 
           76         if (strstr(argv[0], "thingaskpass")) {
           77                 issecret = 1;
           78                 tostdout = 1;
           79                 prompt = "secret> ";
           80         }
           81         if (strstr(argv[0], "thingsudoaskpass")) {
           82                 issecret = 1;
           83                 tostdout = 1;
           84                 if (argc > 1) {
           85                         snprintf(promptb, sizeof(promptb),
           86                                         "sudo('%s')> ", argv[1]);
           87                         prompt = promptb;
           88                 } else {
           89                         prompt = "sudo> ";
           90                 }
           91                 argc = 0;
           92         }
           93 
           94         if (argc > 1) {
           95                 ARGBEGIN {
           96                 case 'o':
           97                         tostdout = 1;
           98                         break;
           99                 case 's':
          100                         issecret = 1;
          101                         break;
          102                 case 'p':
          103                         prompt = EARGF(usage());
          104                         break;
          105                 default:
          106                 case 'h':
          107                         usage();
          108                         break;
          109                 } ARGEND;
          110 
          111                 if (argc > 0)
          112                         prompt = argv[0];
          113         }
          114 
          115         bzero(command, sizeof(command));
          116         bzero(secret, sizeof(secret));
          117 
          118         createwindow();
          119         setupgc();
          120         grabhack();
          121         eventloop();
          122 
          123         return 0;
          124 }
          125 
          126 unsigned long
          127 getcolor(const char *colstr)
          128 {
          129         Colormap cmap = DefaultColormap(dpy, screen);
          130         XColor color;
          131 
          132         if (!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
          133                 die("error, cannot allocate color '%s'\n", colstr);
          134         return color.pixel;
          135 }
          136 
          137 /*
          138  * Stolen from:
          139  * http://menehune.opt.wfu.edu/Kokua/Irix_6.5.21_doc_cd/usr/share/\
          140  * Insight/library/SGI_bookshelves/SGI_Developer/books/XLib_PG/sgi_\
          141  * html/ch11.html#S2-1002-11-11
          142  */
          143 XIMStyle
          144 choosebetterstyle(XIMStyle style1, XIMStyle style2)
          145 {
          146         XIMStyle s,t;
          147         XIMStyle preedit = XIMPreeditArea | XIMPreeditCallbacks |
          148                 XIMPreeditPosition | XIMPreeditNothing | XIMPreeditNone;
          149         XIMStyle status = XIMStatusArea | XIMStatusCallbacks |
          150                 XIMStatusNothing | XIMStatusNone;
          151         if (style1 == 0) return style2;
          152         if (style2 == 0) return style1;
          153         if ((style1 & (preedit | status)) == (style2 & (preedit | status)))
          154                 return style1;
          155         s = style1 & preedit;
          156         t = style2 & preedit;
          157         if (s != t) {
          158                 if (s | t | XIMPreeditCallbacks)
          159                         return (s == XIMPreeditCallbacks)?style1:style2;
          160                 else if (s | t | XIMPreeditPosition)
          161                         return (s == XIMPreeditPosition)?style1:style2;
          162                 else if (s | t | XIMPreeditArea)
          163                         return (s == XIMPreeditArea)?style1:style2;
          164                 else if (s | t | XIMPreeditNothing)
          165                         return (s == XIMPreeditNothing)?style1:style2;
          166         }
          167         else { /* if preedit flags are the same, compare status flags */
          168                 s = style1 & status;
          169                 t = style2 & status;
          170                 if (s | t | XIMStatusCallbacks)
          171                         return (s == XIMStatusCallbacks)?style1:style2;
          172                 else if (s | t | XIMStatusArea)
          173                         return (s == XIMStatusArea)?style1:style2;
          174                 else if (s | t | XIMStatusNothing)
          175                         return (s == XIMStatusNothing)?style1:style2;
          176         }
          177 }
          178 
          179 void
          180 initim(void)
          181 {
          182         XIMStyles *im_supported_styles;
          183         XIMStyle app_supported_styles;
          184         XIMStyle style;
          185         XIMStyle best_style;
          186         XVaNestedList list;
          187         char **missing_charsets;
          188         int num_missing_charsets = 0;
          189         char *default_string;
          190         int i;
          191 
          192         fontset = XCreateFontSet(dpy, font, &missing_charsets,
          193                         &num_missing_charsets, &default_string);
          194         if (num_missing_charsets > 0)
          195                 XFreeStringList(missing_charsets);
          196 
          197         if (!(im = XOpenIM(dpy, NULL, NULL, NULL)))
          198                 die("Couldn't open input method.\n");
          199 
          200         XGetIMValues(im, XNQueryInputStyle, &im_supported_styles, NULL);
          201         app_supported_styles = XIMPreeditNone | XIMPreeditNothing \
          202                | XIMPreeditArea;
          203         app_supported_styles |= XIMStatusNone | XIMStatusNothing \
          204                                 | XIMStatusArea;
          205 
          206         for(i = 0, best_style = 0; i < im_supported_styles->count_styles;
          207                         i++) {
          208                 style = im_supported_styles->supported_styles[i];
          209                 if ((style & app_supported_styles) == style)
          210                         best_style = choosebetterstyle(style, best_style);
          211         }
          212         if (best_style == 0)
          213                 die("no common shared interaction style found.\n");
          214         XFree(im_supported_styles);
          215 
          216         list = XVaCreateNestedList(0, XNFontSet, fontset, NULL);
          217         ic = XCreateIC(im, XNInputStyle, best_style, XNClientWindow, win,
          218                         XNPreeditAttributes, list, XNStatusAttributes,
          219                         list, NULL);
          220         XFree(list);
          221         if (ic == NULL)
          222                 die("Could not create input context.\n");
          223 }
          224 
          225 void
          226 createwindow(void)
          227 {
          228         char *display_name;
          229         int display_width, display_height;
          230         int top, left;
          231         XSizeHints *win_size_hints;
          232         XSetWindowAttributes attrib;
          233         XClassHint *ch;
          234         XTextProperty str;
          235 
          236         if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
          237                 fprintf(stderr, "warning: no locale support.\n");
          238 
          239         display_name = getenv("DISPLAY");
          240         if (display_name == NULL)
          241                 die("DISPLAY not set.\n");
          242 
          243         dpy = XOpenDisplay(display_name);
          244         if (dpy == NULL)
          245                 die("Couldn't connect to DISPLAY.\n");
          246 
          247         if (!XSetLocaleModifiers(""))
          248                 fprintf(stderr, "warning: could not set local modifiers.\n");
          249 
          250         initim();
          251 
          252         screen = DefaultScreen(dpy);
          253         display_width = DisplayWidth(dpy, screen);
          254         display_height = DisplayHeight(dpy, screen);
          255 
          256         top = (display_height/2 - WINHEIGHT/2);
          257         left = (display_width/2 - WINWIDTH/2);
          258 
          259         bgcol = getcolor(normbgcolor);
          260         fgcol = getcolor(normfgcolor);
          261 
          262         /*win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen),
          263                         left, top, WINWIDTH, WINHEIGHT, borderwidth,
          264                         bgcol, bgcol);*/
          265 
          266         attrib.override_redirect = True;
          267         win = XCreateWindow(dpy, RootWindow(dpy, screen),
          268                         left, top, WINWIDTH, WINHEIGHT,
          269                         0, CopyFromParent,InputOutput,CopyFromParent,
          270                         CWOverrideRedirect,&attrib);
          271 
          272         /* set up the window hints etc */
          273         win_size_hints = XAllocSizeHints();
          274         if (!win_size_hints)
          275                 die("out of memory allocating hints.\n");
          276 
          277         win_size_hints->flags = PMaxSize | PMinSize;
          278         win_size_hints->min_width = win_size_hints->max_width = WINWIDTH;
          279 
          280         win_size_hints->min_height = win_size_hints->max_height = WINHEIGHT;
          281 
          282         XStringListToTextProperty(&name, 1, &str);
          283         ch = XAllocClassHint();
          284         ch->res_class = name;
          285         ch->res_name = name;
          286 
          287         XSetWMProperties(dpy, win, &str, &str, NULL, 0, win_size_hints,
          288                         NULL, ch);
          289 
          290         XFree(win_size_hints);
          291         XFree(ch);
          292         XFree(str.value);
          293 
          294         XMapWindow(dpy, win);
          295 }
          296 
          297 void
          298 setupgc(void)
          299 {
          300         XGCValues values;
          301         int valuemask = 0;
          302         int line_width = 1;
          303         int line_style = LineSolid;
          304         int cap_style = CapButt;
          305         int join_style = JoinBevel;
          306 
          307         gc = XCreateGC(dpy, win, valuemask, &values);
          308         rectgc = XCreateGC(dpy, win, valuemask, &values);
          309         XSetForeground(dpy, gc, fgcol);
          310         XSetBackground(dpy, gc, bgcol);
          311 
          312         XSetForeground(dpy, rectgc, bgcol);
          313         XSetBackground(dpy, rectgc, bgcol);
          314 
          315         XSetLineAttributes(dpy, gc, line_width, line_style,
          316                         cap_style, join_style);
          317 
          318         /* setup the font */
          319         font_info = XLoadQueryFont(dpy, font);
          320         if (!font_info)
          321                 die("couldn't load font.\n");
          322 
          323         XSetFont(dpy, gc, font_info->fid);
          324 }
          325 
          326 void
          327 eventloop(void)
          328 {
          329         XEvent e;
          330 
          331         redraw();
          332 
          333         XSelectInput(dpy, win, ExposureMask | KeyPressMask);
          334 
          335         for (;;) {
          336                 XNextEvent(dpy, &e);
          337                 switch(e.type) {
          338                 case Expose:
          339                         redraw();
          340                         break;
          341                 case KeyPress:
          342                         keypress(&e.xkey);
          343                         break;
          344                 default:
          345                         break;
          346                 }
          347         }
          348 }
          349 
          350 /* this loop is required since pwm grabs the keyboard during the event loop */
          351 void
          352 grabhack(void)
          353 {
          354         long maxwait = 3000000; /* 3 seconds */
          355         long interval = 5000; /* 5 millisec */
          356         long i;
          357         int x;
          358 
          359         redraw();
          360 
          361         /* if it takes longer than maxwait, just die */
          362         for (i = 0; i < (maxwait / interval); i++) {
          363                 usleep(interval);
          364                 x = XGrabKeyboard(dpy, win, False, GrabModeAsync,
          365                                 GrabModeAsync, CurrentTime);
          366                 if (x == 0)
          367                         return;
          368         }
          369 
          370         die("Couldn't grab keyboard.\n");
          371 }
          372 
          373 void
          374 redraw(void)
          375 {
          376         int font_height, textwidth, promptwidth, dir, ascent, descent;
          377         XCharStruct cs;
          378         XRectangle ink, logical;
          379 
          380         font_height = font_info->ascent + font_info->descent;
          381         XTextExtents(font_info, prompt, strlen(prompt), &dir, &ascent,
          382                         &descent, &cs);
          383         promptwidth = cs.width;
          384         XwcTextExtents(fontset, command, wcslen(command), &ink, &logical);
          385         textwidth = logical.width;
          386         textwidth += promptwidth;
          387 
          388         XFillRectangle(dpy, win, rectgc, 0, 0, WINWIDTH, WINHEIGHT);
          389         XDrawRectangle(dpy, win, gc, 0, 0, WINWIDTH-1, WINHEIGHT-1);
          390         XDrawString(dpy, win, gc, 2, font_height+2, prompt,
          391                         strlen(prompt));
          392         XwcDrawString(dpy, win, fontset, gc, 4 + promptwidth,
          393                         font_height+2, command, wcslen(command));
          394         XDrawLine(dpy, win, gc, 4 + textwidth, font_height + 2,
          395                         4 + textwidth + 10, font_height+2);
          396 
          397         XFlush(dpy);
          398 }
          399 
          400 void
          401 keypress(XKeyEvent *keyevent)
          402 {
          403         KeySym key_symbol;
          404         int len;
          405         wchar_t buffer[3];
          406 
          407         len = XwcLookupString(ic, keyevent, buffer, 3, &key_symbol, NULL);
          408         buffer[len] = L'\0';
          409 
          410         switch(key_symbol) {
          411         case XK_Escape:
          412                 exit(1);
          413                 break;
          414         case XK_BackSpace:
          415                 len = wcslen(command);
          416                 if (len > 0) {
          417                         command[len-1] = L'\0';
          418                         if (issecret)
          419                                 secret[len-1] = L'\0';
          420                 }
          421                 break;
          422         case XK_Return:
          423         case XK_KP_Enter:
          424                 execcmd();
          425                 break;
          426         case XK_c:
          427                 if (keyevent->state & ControlMask)
          428                         exit(1);
          429         default:
          430                 if (key_symbol > 255)
          431                         break;
          432 
          433                 len = wcslen(command);
          434                 if (len < MAXCMD) {
          435                         if (issecret) {
          436                                 secret[len] = buffer[0];
          437                                 secret[len+1] = L'\0';
          438                                 command[len] = L'*';
          439                                 command[len+1] = L'\0';
          440                         } else {
          441                                 command[len] = buffer[0];
          442                                 command[len+1] = L'\0';
          443                         }
          444                 }
          445                 break;
          446         }
          447         redraw();
          448 }
          449 
          450 void
          451 execcmd(void)
          452 {
          453         char *shell;
          454         pid_t pid;
          455 
          456         XDestroyWindow(dpy, win);
          457 
          458         bzero(cbuf, sizeof(cbuf));
          459         if (issecret)
          460                 wcstombs(cbuf, secret, sizeof(cbuf)-1);
          461         else
          462                 wcstombs(cbuf, command, sizeof(cbuf)-1);
          463 
          464         if (tostdout) {
          465                 printf("%s\n", cbuf);
          466                 exit(0);
          467         }
          468 
          469         switch ((pid = fork())) {
          470         case -1:
          471                 die("fork: %s\n", strerror(errno));
          472         case 0:
          473                 break;
          474         default:
          475                 _exit(0);
          476         }
          477 
          478         shell = getenv("SHELL");
          479         if (!shell)
          480                 shell = "/bin/sh";
          481 
          482         execlp(shell, basename(shell), "-c", cbuf, (char *)NULL);
          483         die("execlp: %s\n", strerror(errno));
          484 }
          485 
          486 void
          487 die(char *errstr, ...)
          488 {
          489         va_list ap;
          490 
          491         va_start(ap, errstr);
          492         vfprintf(stderr, errstr, ap);
          493         va_end(ap);
          494 
          495         exit(1);
          496 }
          497