adji

Adji's a Decisive and Joyful Internet browser
git clone https://noxz.tech/git/adji.git
adji

commit: f365a16b73bc181f503278e2e0523891187d5394
parent: 004303e8f062d2dc66c45a11851a65d646010bd8
author: Chris Noxz <chris@noxz.tech>
date:   Thu, 18 Jan 2024 20:59:00 +0100
implement expansion of file://~ and full word check

when matching the uri scheme file with an unexpanded path the path
won't be expanded. this is solved using:

	if (strncmp("file://", t, 6) == 0 && (t[7] == '~' || t[7] == '$'))
		return resolve_uri(t + 7)

also implement the "bloated" solution mentioned in 37a54a7d. as it
turns out, only checking the first word cause issues with false
positives. for example searching for "mail applications" will
reference directories named "mail" in $HOME instead of searching
for the phrase "mail applications".
Mbrowser.c45++++++++++++++++----
Mbrowser.h1+
2 files changed, 38 insertions(+), 8 deletions(-)
diff --git a/browser.c b/browser.c
@@ -30,6 +30,7 @@ client_create(const gchar                      *uri,
 	gchar                  *u = NULL;           /* translated uri */
 	GtkWidget              *e,                  /* event box */
 	                       *t;                  /* tab box */
+	int                     i;
 
 	/* communicate uri through ipc if constructed */
 	if (uri != NULL && gl.ipc == IPC_CLIENT) {
@@ -73,7 +74,7 @@ client_create(const gchar                      *uri,
 
 	/* load config into webkit settings */
 	c->settings = webkit_settings_new();
-	for (int i = 0; i < LastConfig; i++)
+	for (i = 0; i < LastConfig; i++)
 		if (cfg[i].s != NULL)
 			g_object_set(
 			    G_OBJECT(c->settings),
@@ -1286,20 +1287,20 @@ resolve_uri(const gchar *t)
 	wordexp_t               x;                  /* wordexp struct */
 	int                     r = -1;             /* result holder for wordexp */
 
+	/* cannot expand string in file scheme, so try without scheme */
+	if (strncmp("file://", t, 6) == 0 && (t[7] == '~' || t[7] == '$'))
+		return resolve_uri(t + 7);
+
 	/* check if valid scheme, and if so just create a copy of the text */
 	if ((s = g_uri_peek_scheme(t)) && g_strv_contains(CFG_L(UriSchemes), s))
 		u = g_strdup(t);
-	/* if no match with, test xdg schemes (schemes that are redirected) */
+	/* if no match, then test xdg schemes (schemes that are redirected) */
 	else if (s && CFG_L(XdgSchemes) && g_strv_contains(CFG_L(XdgSchemes), s))
 		xdg_open(s, t);
 	/* if path is local, use the file scheme, else try to see if the string is
-	 * expandable and is a local path.
-	 * note: only the first word is checked. to check path with spaces, the
-	 * spaces need to be escaped:
-	 *      ~/dir with space   -> $HOME/dir
-	 *      ~/dir\ with\ space -> $HOME/dir with space */
+	 * expandable and is a local path */
 	else if ((l = realpath(t, NULL)) != NULL || ((r = wordexp(t, &x, 0)) == 0
-	          && (l = realpath(x.we_wordv[0], NULL)) != NULL))
+	          && (l = resolve_uri_words(x.we_wordc, x.we_wordv)) != NULL))
 		u = g_strdup_printf("file://%s", l);
 	/* else, check if the text can be interpreted as a valid https uri; it's
 	 * not enough to check if uri is valid - check for period and no spaces */
@@ -1320,6 +1321,34 @@ resolve_uri(const gchar *t)
 	return u; /* return a pointer that the caller is responsible for freeing */
 }
 
+char *
+resolve_uri_words(int c, char **w)
+{
+	gchar                  *d = NULL,           /* uri decoded string */
+	                       *p = NULL,           /* path to return */
+	                       *s = NULL;           /* concatenated string */
+	size_t                  l,                  /* arbitrary length holder */
+	                        wl[c];              /* word length */
+	int                     i;
+
+	for (i = 0, l = 0; i < c; l += (wl[i] = strlen(w[i])) + 1, i++);
+
+	if (!(s = (char *)malloc(l * sizeof(char))))
+		die(__NAME__ ": fatal: malloc failed\n");
+
+	/* concatenate, or join, words into a space separated string */
+	for (i = 0, l = 0; i < c; l += wl[i], i++) {
+		memcpy(s + l, w[i], wl[i]);
+		memcpy(s + l++ + wl[i], i == c - 1 ? "\0" : " ", 1);
+	}
+
+	p = realpath((d = g_uri_unescape_string(s, NULL)), NULL);
+
+	g_free(d);
+	g_free(s);
+	return p; /* return a pointer that the caller is responsible for freeing */
+}
+
 void
 update_download_button(WebKitDownload          *d,
                        GtkButton               *btn,
diff --git a/browser.h b/browser.h
@@ -247,6 +247,7 @@ static void show_web_view(struct Client *);
 static void toggle_inspector(struct Client *);
 static void toggle_tls_error_policy(struct Client *);
 static gchar *resolve_uri(const gchar *);
+static char *resolve_uri_words(int, char **);
 static void update_download_button(WebKitDownload *, GtkButton *, gboolean);
 static void update_favicon(struct Client *);
 static void update_load_progress(struct Client *);