aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--calmwm.h7
-rw-r--r--conf.c3
-rw-r--r--cwm.16
-rw-r--r--kbfunc.c156
-rw-r--r--search.c55
5 files changed, 204 insertions, 23 deletions
diff --git a/calmwm.h b/calmwm.h
index 49da89c..5a47cb9 100644
--- a/calmwm.h
+++ b/calmwm.h
@@ -4,7 +4,7 @@
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
- * $Id: calmwm.h,v 1.6 2007/06/05 19:03:20 jasper Exp $
+ * $Id: calmwm.h,v 1.7 2007/06/26 19:34:26 niallo Exp $
*/
#ifndef _CALMWM_H_
@@ -257,6 +257,7 @@ struct menu {
char print[MENU_MAXENTRY + 1];
void *ctx;
short lasthit;
+ short dummy;
};
TAILQ_HEAD(menu_q, menu);
@@ -427,6 +428,7 @@ void kbfunc_client_maximize(struct client_ctx *, void *);
void kbfunc_client_vmaximize(struct client_ctx *, void *);
void kbfunc_menu_search(struct client_ctx *, void *);
void kbfunc_exec(struct client_ctx *, void *);
+void kbfunc_ssh(struct client_ctx *, void *);
void kbfunc_term(struct client_ctx *cc, void *arg);
void kbfunc_lock(struct client_ctx *cc, void *arg);
@@ -437,10 +439,11 @@ struct menu *search_start(struct menu_q *menuq,
void (*match)(struct menu_q *, struct menu_q *, char *),
void (*rank)(struct menu_q *, char *),
void (*print)(struct menu *mi, int),
- char *);
+ char *, int);
void search_match_client(struct menu_q *, struct menu_q *, char *);
void search_print_client(struct menu *mi, int list);
void search_match_text(struct menu_q *, struct menu_q *, char *);
+void search_match_exec(struct menu_q *, struct menu_q *, char *);
void search_rank_text(struct menu_q *, char *);
void group_init(void);
diff --git a/conf.c b/conf.c
index 4c74966..4b96323 100644
--- a/conf.c
+++ b/conf.c
@@ -4,7 +4,7 @@
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
- * $Id: conf.c,v 1.6 2007/06/05 19:03:20 jasper Exp $
+ * $Id: conf.c,v 1.7 2007/06/26 19:34:26 niallo Exp $
*/
#include "headers.h"
@@ -189,6 +189,7 @@ conf_setup(struct conf *c)
conf_bindkey(c, kbfunc_lock,
XK_Delete, ControlMask|Mod1Mask, 0, NULL);
conf_bindkey(c, kbfunc_exec, XK_question, Mod1Mask, 0, NULL);
+ conf_bindkey(c, kbfunc_ssh, XK_period, Mod1Mask, 0, NULL);
conf_bindkey(c, kbfunc_client_hide,
XK_Return, Mod1Mask, KBFLAG_NEEDCLIENT, 0);
conf_bindkey(c, kbfunc_client_lower,
diff --git a/cwm.1 b/cwm.1
index da648ba..540ec7f 100644
--- a/cwm.1
+++ b/cwm.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: cwm.1,v 1.6 2007/06/06 22:08:02 jasper Exp $
+.\" $OpenBSD: cwm.1,v 1.7 2007/06/26 19:34:26 niallo Exp $
.\"
.\" The following requests are required for all man pages.
.Dd July 10, 2004
@@ -87,6 +87,10 @@ Toggle full-screen size of window.
Toggle vertical maximization of window.
.It Fa M-?
Spawn \&"Exec program\&" dialog.
+.It Fa M-.
+Spawn \&"Ssh to\&" dialog.
+This parses your $HOME/.ssh/known_hosts file to provide host auto-completion.
+Ssh will be executed via the configured terminal emulator.
.El
.Pp
The mouse bindings are also important, they are:
diff --git a/kbfunc.c b/kbfunc.c
index dbd0dc7..a206320 100644
--- a/kbfunc.c
+++ b/kbfunc.c
@@ -4,12 +4,17 @@
* Copyright (c) 2004 Martin Murray <mmurray@monkey.org>
* All rights reserved.
*
- * $Id: kbfunc.c,v 1.4 2007/06/05 19:03:20 jasper Exp $
+ * $Id: kbfunc.c,v 1.5 2007/06/26 19:34:26 niallo Exp $
*/
+#include <paths.h>
+
#include "headers.h"
#include "calmwm.h"
+#define KNOWN_HOSTS ".ssh/known_hosts"
+#define HASH_MARKER "|1|"
+
void
kbfunc_client_lower(struct client_ctx *cc, void *arg)
{
@@ -41,7 +46,7 @@ kbfunc_client_search(struct client_ctx *scratch, void *arg)
if ((mi = search_start(&menuq,
search_match_client, NULL,
- search_print_client, "window")) != NULL) {
+ search_print_client, "window", 0)) != NULL) {
cc = (struct client_ctx *)mi->ctx;
if (cc->flags & CLIENT_HIDDEN)
client_unhide(cc);
@@ -75,7 +80,7 @@ kbfunc_menu_search(struct client_ctx *scratch, void *arg)
}
if ((mi = search_start(&menuq,
- search_match_text, NULL, NULL, "application")) != NULL)
+ search_match_text, NULL, NULL, "application", 0)) != NULL)
u_spawn(((struct cmd *)mi->ctx)->image);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
@@ -125,7 +130,150 @@ kbfunc_lock(struct client_ctx *cc, void *arg)
void
kbfunc_exec(struct client_ctx *scratch, void *arg)
{
- grab_exec();
+ char **ap, *paths[256], *path, tpath[MAXPATHLEN];
+ int l, i, j, ngroups;
+ gid_t mygroups[NGROUPS_MAX];
+ uid_t ruid, euid, suid;
+ DIR *dirp;
+ struct dirent *dp;
+ struct stat sb;
+ struct menu_q menuq;
+ struct menu *mi;
+
+ if (getgroups(0, mygroups) == -1)
+ err(1, "getgroups failure");
+ if ((ngroups = getresuid(&ruid, &euid, &suid)) == -1)
+ err(1, "getresuid failure");
+
+ TAILQ_INIT(&menuq);
+ /* just use default path until we have config to set this */
+ path = xstrdup(_PATH_DEFPATH);
+ for (ap = paths; ap < &paths[sizeof(paths) - 1] &&
+ (*ap = strsep(&path, ":")) != NULL;) {
+ if (**ap != '\0')
+ ap++;
+ }
+ *ap = NULL;
+ for (i = 0; i < sizeof(paths) && paths[i] != NULL; i++) {
+ if ((dirp = opendir(paths[i])) == NULL)
+ continue;
+
+ while ((dp = readdir(dirp)) != NULL) {
+ /* skip everything but regular files and symlinks */
+ if (dp->d_type != DT_REG && dp->d_type != DT_LNK)
+ continue;
+ memset(tpath, '\0', sizeof(tpath));
+ l = snprintf(tpath, sizeof(tpath), "%s/%s", paths[i],
+ dp->d_name);
+ /* check for truncation etc */
+ if (l == -1 || l >= (int)sizeof(tpath))
+ continue;
+ /* just ignore on stat failure */
+ if (stat(tpath, &sb) == -1)
+ continue;
+ /* may we execute this file? */
+ if (euid == sb.st_uid)
+ if (sb.st_mode & S_IXUSR)
+ goto executable;
+ else
+ continue;
+ for (j = 0; j < ngroups; j++)
+ if (mygroups[j] == sb.st_gid)
+ if (sb.st_mode & S_IXGRP)
+ goto executable;
+ else
+ continue;
+ if (sb.st_mode & S_IXOTH)
+ goto executable;
+ continue;
+ executable:
+ /* the thing in tpath, we may execute */
+ XCALLOC(mi, struct menu);
+ strlcpy(mi->text, dp->d_name, sizeof(mi->text));
+ TAILQ_INSERT_TAIL(&menuq, mi, entry);
+ }
+ (void) closedir(dirp);
+ }
+
+ if ((mi = search_start(&menuq,
+ search_match_exec, NULL, NULL, "exec", 1)) != NULL)
+ u_spawn(mi->text);
+
+ if (mi != NULL && mi->dummy)
+ xfree(mi);
+ while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
+ TAILQ_REMOVE(&menuq, mi, entry);
+ xfree(mi);
+ }
+ xfree(path);
+}
+
+void
+kbfunc_ssh(struct client_ctx *scratch, void *arg)
+{
+ struct menu_q menuq;
+ struct menu *mi;
+ FILE *fp;
+ size_t len;
+ char *buf, *lbuf, *p, *home;
+ char hostbuf[MAXHOSTNAMELEN], filename[MAXPATHLEN], cmd[256];
+ int l;
+
+ if ((home = getenv("HOME")) == NULL)
+ return;
+
+ l = snprintf(filename, sizeof(filename), "%s/%s", home, KNOWN_HOSTS);
+ if (l == -1 || l >= sizeof(filename))
+ return;
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ return;
+
+ TAILQ_INIT(&menuq);
+ lbuf = NULL;
+ while ((buf = fgetln(fp, &len))) {
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+ else {
+ /* EOF without EOL, copy and add the NUL */
+ lbuf = xmalloc(len + 1);
+ memcpy(lbuf, buf, len);
+ lbuf[len] = '\0';
+ buf = lbuf;
+ }
+ /* skip hashed hosts */
+ if (strncmp(buf, HASH_MARKER, strlen(HASH_MARKER)) == 0)
+ continue;
+ for (p = buf; *p != ',' && *p != ' ' && p != buf + len; p++) {
+ /* do nothing */
+ }
+ /* ignore badness */
+ if (p - buf + 1 > sizeof(hostbuf))
+ continue;
+ (void) strlcpy(hostbuf, buf, p - buf + 1);
+ XCALLOC(mi, struct menu);
+ (void) strlcpy(mi->text, hostbuf, sizeof(mi->text));
+ TAILQ_INSERT_TAIL(&menuq, mi, entry);
+ }
+ xfree(lbuf);
+ fclose(fp);
+
+
+ if ((mi = search_start(&menuq,
+ search_match_exec, NULL, NULL, "ssh", 1)) != NULL) {
+ conf_cmd_refresh(&Conf);
+ l = snprintf(cmd, sizeof(cmd), "%s -e ssh %s", Conf.termpath,
+ mi->text);
+ if (l != -1 && l < sizeof(cmd))
+ u_spawn(cmd);
+ }
+
+ if (mi != NULL && mi->dummy)
+ xfree(mi);
+ while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
+ TAILQ_REMOVE(&menuq, mi, entry);
+ xfree(mi);
+ }
}
void
diff --git a/search.c b/search.c
index 968de63..075c1d2 100644
--- a/search.c
+++ b/search.c
@@ -4,7 +4,7 @@
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
- * $Id: search.c,v 1.2 2007/05/28 18:34:27 jasper Exp $
+ * $Id: search.c,v 1.3 2007/06/26 19:34:26 niallo Exp $
*/
#include "headers.h"
@@ -12,7 +12,7 @@
#define SearchMask (KeyPressMask|ExposureMask)
-static int _strsubmatch(char *, char *);
+static int _strsubmatch(char *, char *, int);
void
search_init(struct screen_ctx *sc)
@@ -37,7 +37,7 @@ search_start(struct menu_q *menuq,
void (*match)(struct menu_q *, struct menu_q *, char *),
void (*rank)(struct menu_q *resultq, char *search),
void (*print)(struct menu *mi, int print),
- char *prompt)
+ char *prompt, int dummy)
{
struct screen_ctx *sc = screen_current();
int x, y, dx, dy, fontheight,
@@ -47,7 +47,7 @@ search_start(struct menu_q *menuq,
char dispstr[MENU_MAXENTRY*2 + 1];
char promptstr[MENU_MAXENTRY + 1];
Window focuswin;
- struct menu *mi = NULL;
+ struct menu *mi = NULL, *dummy_mi = NULL;
struct menu_q resultq;
char chr;
enum ctltype ctl;
@@ -133,16 +133,22 @@ search_start(struct menu_q *menuq,
case CTL_RETURN:
/* This is just picking the match the
* cursor is over. */
- if ((mi = TAILQ_FIRST(&resultq)) != NULL)
+ if ((mi = TAILQ_FIRST(&resultq)) != NULL) {
goto found;
- else
- goto out;
+ } else if (dummy) {
+ dummy_mi = xmalloc(sizeof *dummy_mi);
+ (void) strlcpy(dummy_mi->text,
+ searchstr, sizeof(dummy_mi->text));
+ dummy_mi->dummy = 1;
+ goto found;
+ }
+ goto out;
case CTL_WIPE:
searchstr[0] = '\0';
mutated = 1;
break;
case CTL_ALL:
- list = !list;
+ list = !list;
break;
case CTL_ABORT:
goto out;
@@ -273,9 +279,12 @@ out:
/* (if no match) */
xu_ptr_ungrab();
XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
+
found:
XUnmapWindow(X_Dpy, sc->searchwin);
+ if (dummy && dummy_mi != NULL)
+ return (dummy_mi);
return (mi);
}
@@ -307,7 +316,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
struct client_ctx *cc = mi->ctx;
/* First, try to match on labels. */
- if (cc->label != NULL && _strsubmatch(search, cc->label)) {
+ if (cc->label != NULL && _strsubmatch(search, cc->label, 0)) {
cc->matchname = cc->label;
tier = 0;
}
@@ -315,7 +324,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
/* Then, on window names. */
if (tier < 0) {
TAILQ_FOREACH_REVERSE(wn, &cc->nameq, winname_q, entry)
- if (_strsubmatch(search, wn->name)) {
+ if (_strsubmatch(search, wn->name, 0)) {
cc->matchname = wn->name;
tier = 2;
break;
@@ -327,7 +336,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
* name.
*/
- if (tier < 0 && _strsubmatch(search, cc->app_class)) {
+ if (tier < 0 && _strsubmatch(search, cc->app_class, 0)) {
cc->matchname = cc->app_class;
tier = 3;
}
@@ -417,7 +426,19 @@ search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry)
- if (_strsubmatch(search, mi->text))
+ if (_strsubmatch(search, mi->text, 0))
+ TAILQ_INSERT_TAIL(resultq, mi, resultentry);
+}
+
+void
+search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
+{
+ struct menu *mi;
+
+ TAILQ_INIT(resultq);
+
+ TAILQ_FOREACH(mi, menuq, entry)
+ if (_strsubmatch(search, mi->text, 1))
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
@@ -428,10 +449,10 @@ search_rank_text(struct menu_q *resultq, char *search)
}
static int
-_strsubmatch(char *sub, char *str)
+_strsubmatch(char *sub, char *str, int zeroidx)
{
size_t len, sublen;
- u_int n;
+ u_int n, flen;
if (sub == NULL || str == NULL)
return (0);
@@ -442,7 +463,11 @@ _strsubmatch(char *sub, char *str)
if (sublen > len)
return (0);
- for (n = 0; n <= len - sublen; n++)
+ if (!zeroidx)
+ flen = len - sublen;
+ else
+ flen = 0;
+ for (n = 0; n <= flen; n++)
if (strncasecmp(sub, str + n, sublen) == 0)
return (1);