adji

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

we_redirect.c
1/**
2 * Copyright (C) 2023 Chris Noxz
3 * Author(s): Chris Noxz <chris@noxz.tech>
4 *
5 * This program is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation, either version 3 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19#include <stdio.h>
20#include <glib.h>
21#include <webkit2/webkit-web-extension.h>
22
23#define     RULE_FILE               "redirect"
24
25GSList      *redirect_patterns      = NULL,
26            *redirect_destinations  = NULL;
27gboolean    verbose                 = FALSE;
28
29
30void
31redirect_load(void)
32{
33	GRegex         *r = NULL;                   /* regex rule */
34	GError         *e = NULL;                   /* errors */
35	GIOChannel     *c = NULL;                   /* reading io channel */
36	gchar          *p = NULL,                   /* path to redirect file */
37	               *l = NULL,                   /* line buffer */
38	                s;                          /* separator holder */
39	int             i,
40	                j,
41	                d;                          /* destination index */
42
43	/* make it possible to debug redirect rules */
44	verbose = g_getenv(__NAME_UPPERCASE__"_VERBOSE") != NULL;
45
46	p = g_build_filename(g_get_user_config_dir(), __NAME__, RULE_FILE, NULL);
47	if ((c = g_io_channel_new_file(p, "r", NULL)) != NULL) {
48		while (g_io_channel_read_line(c, &l, NULL, NULL, NULL)
49		       == G_IO_STATUS_NORMAL) {
50			g_strstrip(l);
51			/* ignore if separator is comment indicator, if not then parse as:
52			   /pattern/replacement/ where '/' can be anything but '#' */
53			if ((s = l[0]) != '#') {
54				for (d = j = i = 0; l[i] && j <= 2; i++) {
55					if (d == 0 && j == 1)
56						d = i;
57					l[i] = l[i + 1];
58					if (l[i] == s) {
59						l[i] = '\0';
60						j++;
61					}
62				}
63
64				if (j == 2) { /* make sure to pass 2 null-terminated strings */
65					r = g_regex_new(
66					    l,
67					    G_REGEX_CASELESS | G_REGEX_OPTIMIZE,
68					    G_REGEX_MATCH_PARTIAL,
69					    &e
70					);
71					if (e != NULL) {
72						fprintf(
73						    stderr,
74						    __NAME__": Could not compile regex: %s\n",
75						    l
76						);
77						g_error_free(e);
78						e = NULL;
79					} else {
80						redirect_patterns = g_slist_append(
81						    redirect_patterns, r
82						);
83						redirect_destinations = g_slist_append(
84						    redirect_destinations, g_strdup(l + d)
85						);
86					}
87				}
88			}
89			g_free(l);
90		}
91		g_io_channel_shutdown(c, FALSE, NULL);
92	}
93	g_free(p);
94}
95
96gboolean
97cb_web_page_send_request(WebKitWebPage *web_page, WebKitURIRequest *request,
98                         WebKitURIResponse *redirected_response, gpointer data)
99{
100	GSList         *p = redirect_patterns,      /* pattern holder */
101	               *d = redirect_destinations;  /* destination holder */
102	const gchar    *i;                          /* incoming uri */
103	gchar          *o = NULL;                   /* outgoing uri */
104
105	(void)web_page;
106	(void)redirected_response;
107	(void)data;
108
109	i = webkit_uri_request_get_uri(request);
110
111	/* go through every rule and apply accordingly */
112	while (p && d) {
113		/* find matching rule for incoming uri */
114		if (g_regex_match((GRegex *)(p->data), i, 0, NULL)) {
115			/* check if destination exists for rule */
116			if (((gchar*)d->data)[0])
117				o = g_regex_replace(
118				    (GRegex *)(p->data),
119				    i,
120				    -1,
121				    0,
122				    ((gchar*)d->data),
123				    G_REGEX_MATCH_DEFAULT,
124				    NULL
125				);
126			if (verbose)
127				fprintf(stderr,
128				    "redirect: %s %s -> %s\n",
129				    g_regex_get_pattern(p->data),
130				    i,
131				    o ? o : "[blocked]"
132				);
133			/* if outgoing uri was constructed, then redirect... */
134			if (o) {
135				webkit_uri_request_set_uri(request, o);
136				g_free(o);
137				return FALSE;
138			/* ...else, block */
139			} else {
140				return TRUE;
141			}
142		}
143		p = g_slist_next(p);
144		d = g_slist_next(d);
145	}
146
147	return FALSE;
148}
149
150void
151cb_web_page_created(WebKitWebExtension *extension, WebKitWebPage *web_page,
152                    gpointer data)
153{
154	(void)extension;
155	(void)data;
156
157	g_signal_connect_object(
158	    web_page, "send-request", G_CALLBACK(cb_web_page_send_request), NULL, 0
159	);
160}
161
162G_MODULE_EXPORT void
163webkit_web_extension_initialize(WebKitWebExtension *extension)
164{
165	redirect_load();
166	g_signal_connect(
167	    extension, "page-created", G_CALLBACK(cb_web_page_created), NULL
168	);
169}