Introduction
Introduction Statistics Contact Development Disclaimer Help
thinglaunch.c - thinglaunch - A simple command and password promtper for X11.
git clone git://bitreich.org/thinglaunch
Log
Files
Refs
Tags
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 <[email protected]>. 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.…
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 = WINHEI…
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 l…
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
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.