summaryrefslogtreecommitdiff
path: root/src/backend/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/plugins')
-rw-r--r--src/backend/plugins/config-env/config-env.c167
-rw-r--r--src/backend/plugins/config-env/config-env.h34
-rw-r--r--src/backend/plugins/config-env/meson.build9
-rw-r--r--src/backend/plugins/config-gnome/config-gnome.c246
-rw-r--r--src/backend/plugins/config-gnome/config-gnome.h34
-rw-r--r--src/backend/plugins/config-gnome/meson.build9
-rw-r--r--src/backend/plugins/config-kde/config-kde.c303
-rw-r--r--src/backend/plugins/config-kde/config-kde.h34
-rw-r--r--src/backend/plugins/config-kde/meson.build9
-rw-r--r--src/backend/plugins/config-osx/config-osx.c341
-rw-r--r--src/backend/plugins/config-osx/config-osx.h34
-rw-r--r--src/backend/plugins/config-osx/meson.build16
-rw-r--r--src/backend/plugins/config-sysconfig/config-sysconfig.c252
-rw-r--r--src/backend/plugins/config-sysconfig/config-sysconfig.h34
-rw-r--r--src/backend/plugins/config-sysconfig/meson.build9
-rw-r--r--src/backend/plugins/config-windows/config-windows.c252
-rw-r--r--src/backend/plugins/config-windows/config-windows.h34
-rw-r--r--src/backend/plugins/config-windows/meson.build9
-rw-r--r--src/backend/plugins/meson.build18
-rw-r--r--src/backend/plugins/pacrunner-duktape/meson.build17
-rw-r--r--src/backend/plugins/pacrunner-duktape/pacrunner-duktape.c201
-rw-r--r--src/backend/plugins/pacrunner-duktape/pacrunner-duktape.h32
22 files changed, 2094 insertions, 0 deletions
diff --git a/src/backend/plugins/config-env/config-env.c b/src/backend/plugins/config-env/config-env.c
new file mode 100644
index 0000000..6a326e0
--- /dev/null
+++ b/src/backend/plugins/config-env/config-env.c
@@ -0,0 +1,167 @@
+/* config-env.c
+ *
+ * Copyright 2022-2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <gio/gio.h>
+
+#include "config-env.h"
+
+#include "px-manager.h"
+#include "px-plugin-config.h"
+
+static void px_config_iface_init (PxConfigInterface *iface);
+
+struct _PxConfigEnv {
+ GObject parent_instance;
+
+ GStrv no_proxy;
+ const char *ftp_proxy;
+ const char *http_proxy;
+ const char *https_proxy;
+};
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (PxConfigEnv,
+ px_config_env,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (PX_TYPE_CONFIG, px_config_iface_init))
+
+enum {
+ PROP_0,
+ PROP_CONFIG_OPTION
+};
+
+static void
+px_config_env_init (PxConfigEnv *self)
+{
+ const char *no_proxy;
+
+ /* Collect data in init() to speed up get_config() calls */
+ no_proxy = g_getenv ("no_proxy");
+ if (!no_proxy)
+ no_proxy = g_getenv ("NO_PROXY");
+
+ if (no_proxy)
+ self->no_proxy = g_strsplit (no_proxy, ",", -1);
+
+ self->ftp_proxy = g_getenv ("ftp_proxy");
+ if (!self->ftp_proxy)
+ self->ftp_proxy = g_getenv ("FTP_PROXY");
+
+ self->https_proxy = g_getenv ("https_proxy");
+ if (!self->https_proxy)
+ self->https_proxy = g_getenv ("HTTPS_PROXY");
+
+ self->http_proxy = g_getenv ("http_proxy");
+ if (!self->http_proxy)
+ self->http_proxy = g_getenv ("HTTP_PROXY");
+}
+
+static void
+px_config_env_dispose (GObject *object)
+{
+ PxConfigEnv *self = PX_CONFIG_ENV (object);
+
+ g_clear_pointer (&self->no_proxy, g_strfreev);
+
+ G_OBJECT_CLASS (px_config_env_parent_class)->dispose (object);
+}
+
+static void
+px_config_env_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_CONFIG_OPTION:
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_env_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_CONFIG_OPTION:
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_env_class_init (PxConfigEnvClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = px_config_env_dispose;
+ object_class->set_property = px_config_env_set_property;
+ object_class->get_property = px_config_env_get_property;
+
+ g_object_class_override_property (object_class, PROP_CONFIG_OPTION, "config-option");
+}
+
+static gboolean
+px_config_env_is_available (PxConfig *self)
+{
+ return TRUE;
+}
+
+static void
+px_config_env_get_config (PxConfig *config,
+ GUri *uri,
+ GStrvBuilder *builder)
+{
+ PxConfigEnv *self = PX_CONFIG_ENV (config);
+ const char *proxy = NULL;
+ const char *scheme = g_uri_get_scheme (uri);
+
+ if (px_manager_is_ignore (uri, self->no_proxy))
+ return;
+
+ if (g_strcmp0 (scheme, "ftp") == 0)
+ proxy = self->ftp_proxy;
+ else if (g_strcmp0 (scheme, "https") == 0)
+ proxy = self->https_proxy;
+
+ if (!proxy)
+ proxy = self->http_proxy;
+
+ if (proxy)
+ px_strv_builder_add_proxy (builder, proxy);
+}
+
+static void
+px_config_iface_init (PxConfigInterface *iface)
+{
+ iface->name = "config-env";
+ iface->priority = PX_CONFIG_PRIORITY_FIRST;
+ iface->is_available = px_config_env_is_available;
+ iface->get_config = px_config_env_get_config;
+}
diff --git a/src/backend/plugins/config-env/config-env.h b/src/backend/plugins/config-env/config-env.h
new file mode 100644
index 0000000..6b654bd
--- /dev/null
+++ b/src/backend/plugins/config-env/config-env.h
@@ -0,0 +1,34 @@
+/* config-env.h
+ *
+ * Copyright 2022-2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define PX_CONFIG_TYPE_ENV (px_config_env_get_type ())
+
+G_DECLARE_FINAL_TYPE (PxConfigEnv, px_config_env, PX, CONFIG_ENV, GObject)
+
+G_END_DECLS
+
+
diff --git a/src/backend/plugins/config-env/meson.build b/src/backend/plugins/config-env/meson.build
new file mode 100644
index 0000000..00f3cc3
--- /dev/null
+++ b/src/backend/plugins/config-env/meson.build
@@ -0,0 +1,9 @@
+plugin_name = 'config-env'
+
+if get_option(plugin_name)
+
+px_backend_sources += [
+ 'plugins/@0@/@0@.c'.format(plugin_name),
+]
+
+endif \ No newline at end of file
diff --git a/src/backend/plugins/config-gnome/config-gnome.c b/src/backend/plugins/config-gnome/config-gnome.c
new file mode 100644
index 0000000..9d6fd68
--- /dev/null
+++ b/src/backend/plugins/config-gnome/config-gnome.c
@@ -0,0 +1,246 @@
+/* config-gnome.c
+ *
+ * Copyright 2022-2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <gio/gio.h>
+
+#include "config-gnome.h"
+
+#include "px-plugin-config.h"
+#include "px-manager.h"
+
+struct _PxConfigGnome {
+ GObject parent_instance;
+ GSettings *proxy_settings;
+ GSettings *http_proxy_settings;
+ GSettings *https_proxy_settings;
+ GSettings *ftp_proxy_settings;
+ GSettings *socks_proxy_settings;
+ gboolean available;
+};
+
+typedef enum {
+ GNOME_PROXY_MODE_NONE,
+ GNOME_PROXY_MODE_MANUAL,
+ GNOME_PROXY_MODE_AUTO
+} GnomeProxyMode;
+
+static void px_config_iface_init (PxConfigInterface *iface);
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (PxConfigGnome,
+ px_config_gnome,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (PX_TYPE_CONFIG, px_config_iface_init))
+
+enum {
+ PROP_0,
+ PROP_CONFIG_OPTION
+};
+
+static void
+px_config_gnome_init (PxConfigGnome *self)
+{
+ GSettingsSchemaSource *source;
+ GSettingsSchema *proxy_schema;
+ const char *desktops;
+
+ self->available = FALSE;
+
+ desktops = getenv ("XDG_CURRENT_DESKTOP");
+ if (!desktops)
+ return;
+
+ /* Remember that XDG_CURRENT_DESKTOP is a list of strings. */
+ if (strstr (desktops, "GNOME") == NULL)
+ return;
+
+ source = g_settings_schema_source_get_default ();
+ if (!source) {
+ g_warning ("GNOME desktop detected but no schemes installed, aborting.");
+ return;
+ }
+
+ proxy_schema = g_settings_schema_source_lookup (source, "org.gnome.system.proxy", TRUE);
+
+ self->available = proxy_schema != NULL;
+ g_clear_pointer (&proxy_schema, g_settings_schema_unref);
+
+ if (!self->available)
+ return;
+
+ self->proxy_settings = g_settings_new ("org.gnome.system.proxy");
+ self->http_proxy_settings = g_settings_new ("org.gnome.system.proxy.http");
+ self->https_proxy_settings = g_settings_new ("org.gnome.system.proxy.https");
+ self->ftp_proxy_settings = g_settings_new ("org.gnome.system.proxy.ftp");
+ self->socks_proxy_settings = g_settings_new ("org.gnome.system.proxy.socks");
+}
+
+static void
+px_config_gnome_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_CONFIG_OPTION:
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_gnome_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_CONFIG_OPTION:
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_gnome_class_init (PxConfigGnomeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = px_config_gnome_set_property;
+ object_class->get_property = px_config_gnome_get_property;
+
+ g_object_class_override_property (object_class, PROP_CONFIG_OPTION, "config-option");
+}
+
+static gboolean
+px_config_gnome_is_available (PxConfig *config)
+{
+ PxConfigGnome *self = PX_CONFIG_GNOME (config);
+
+ return self->available;
+}
+
+static void
+store_response (GStrvBuilder *builder,
+ const char *type,
+ char *host,
+ int port,
+ gboolean auth,
+ char *username,
+ char *password)
+{
+ if (type && host && strlen (type) > 0 && strlen (host) > 0 && port != 0) {
+ g_autoptr (GString) tmp = g_string_new (type);
+
+ g_string_append (tmp, "://");
+ if (auth)
+ g_string_append_printf (tmp, "%s:%s@", username, password);
+
+ g_string_append_printf (tmp, "%s:%d", host, port);
+
+ px_strv_builder_add_proxy (builder, tmp->str);
+ }
+}
+
+static void
+px_config_gnome_get_config (PxConfig *config,
+ GUri *uri,
+ GStrvBuilder *builder)
+{
+ PxConfigGnome *self = PX_CONFIG_GNOME (config);
+ g_autofree char *proxy = NULL;
+ GnomeProxyMode mode;
+
+ if (!self->available)
+ return;
+
+ if (px_manager_is_ignore (uri, g_settings_get_strv (self->proxy_settings, "ignore-hosts")))
+ return;
+
+ mode = g_settings_get_enum (self->proxy_settings, "mode");
+ if (mode == GNOME_PROXY_MODE_AUTO) {
+ char *autoconfig_url = g_settings_get_string (self->proxy_settings, "autoconfig-url");
+
+ if (strlen (autoconfig_url) != 0)
+ proxy = g_strdup_printf ("pac+%s", autoconfig_url);
+ else
+ proxy = g_strdup ("wpad://");
+
+ px_strv_builder_add_proxy (builder, proxy);
+ } else if (mode == GNOME_PROXY_MODE_MANUAL) {
+ g_autofree char *username = g_settings_get_string (self->http_proxy_settings, "authentication-user");
+ g_autofree char *password = g_settings_get_string (self->http_proxy_settings, "authentication-password");
+ const char *scheme = g_uri_get_scheme (uri);
+ gboolean auth = g_settings_get_boolean (self->http_proxy_settings, "use-authentication");
+
+ if (g_strcmp0 (scheme, "http") == 0) {
+ g_autofree char *host = g_settings_get_string (self->http_proxy_settings, "host");
+ store_response (builder,
+ "http",
+ host,
+ g_settings_get_int (self->http_proxy_settings, "port"),
+ auth,
+ username,
+ password);
+ } else if (g_strcmp0 (scheme, "https") == 0) {
+ g_autofree char *host = g_settings_get_string (self->https_proxy_settings, "host");
+ store_response (builder,
+ "http",
+ host,
+ g_settings_get_int (self->https_proxy_settings, "port"),
+ auth,
+ username,
+ password);
+ } else if (g_strcmp0 (scheme, "ftp") == 0) {
+ g_autofree char *host = g_settings_get_string (self->ftp_proxy_settings, "host");
+ store_response (builder,
+ "http",
+ host,
+ g_settings_get_int (self->ftp_proxy_settings, "port"),
+ auth,
+ username,
+ password);
+ } else {
+ g_autofree char *host = g_settings_get_string (self->socks_proxy_settings, "host");
+ store_response (builder,
+ "socks",
+ host,
+ g_settings_get_int (self->socks_proxy_settings, "port"),
+ auth,
+ username,
+ password);
+ }
+ }
+}
+
+static void
+px_config_iface_init (PxConfigInterface *iface)
+{
+ iface->name = "config-gnome";
+ iface->priority = PX_CONFIG_PRIORITY_DEFAULT;
+ iface->is_available = px_config_gnome_is_available;
+ iface->get_config = px_config_gnome_get_config;
+}
diff --git a/src/backend/plugins/config-gnome/config-gnome.h b/src/backend/plugins/config-gnome/config-gnome.h
new file mode 100644
index 0000000..c5e8c6e
--- /dev/null
+++ b/src/backend/plugins/config-gnome/config-gnome.h
@@ -0,0 +1,34 @@
+/* config-gnome.h
+ *
+ * Copyright 2022-2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PX_CONFIG_TYPE_GNOME (px_config_gnome_get_type ())
+
+G_DECLARE_FINAL_TYPE (PxConfigGnome, px_config_gnome, PX, CONFIG_GNOME, GObject)
+
+G_END_DECLS
+
+
diff --git a/src/backend/plugins/config-gnome/meson.build b/src/backend/plugins/config-gnome/meson.build
new file mode 100644
index 0000000..e6a9b20
--- /dev/null
+++ b/src/backend/plugins/config-gnome/meson.build
@@ -0,0 +1,9 @@
+plugin_name = 'config-gnome'
+
+if get_option(plugin_name)
+
+px_backend_sources += [
+ 'plugins/@0@/@0@.c'.format(plugin_name),
+]
+
+endif \ No newline at end of file
diff --git a/src/backend/plugins/config-kde/config-kde.c b/src/backend/plugins/config-kde/config-kde.c
new file mode 100644
index 0000000..ccec002
--- /dev/null
+++ b/src/backend/plugins/config-kde/config-kde.c
@@ -0,0 +1,303 @@
+/* config-kde.c
+ *
+ * Copyright 2022-2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <gio/gio.h>
+
+#include "config-kde.h"
+
+#include "px-plugin-config.h"
+#include "px-manager.h"
+
+static void px_config_iface_init (PxConfigInterface *iface);
+
+typedef enum {
+ KDE_PROXY_TYPE_NONE = 0,
+ KDE_PROXY_TYPE_MANUAL,
+ KDE_PROXY_TYPE_PAC,
+ KDE_PROXY_TYPE_WPAD,
+ KDE_PROXY_TYPE_SYSTEM,
+} KdeProxyType;
+
+struct _PxConfigKde {
+ GObject parent_instance;
+
+ char *config_file;
+ gboolean available;
+ GFileMonitor *monitor;
+
+ GStrv no_proxy;
+ char *http_proxy;
+ char *https_proxy;
+ char *ftp_proxy;
+ char *socks_proxy;
+ KdeProxyType proxy_type;
+ char *pac_script;
+};
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (PxConfigKde,
+ px_config_kde,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (PX_TYPE_CONFIG, px_config_iface_init))
+
+enum {
+ PROP_0,
+ PROP_CONFIG_OPTION
+};
+
+static void px_config_kde_set_config_file (PxConfigKde *self,
+ char *proxy_file);
+
+static void
+on_file_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ gpointer user_data)
+{
+ PxConfigKde *self = PX_CONFIG_KDE (user_data);
+
+ g_debug ("%s: Reloading configuration\n", __FUNCTION__);
+ px_config_kde_set_config_file (self, g_file_get_path (file));
+}
+
+static void
+px_config_kde_set_config_file (PxConfigKde *self,
+ char *proxy_file)
+{
+ g_autoptr (GError) error = NULL;
+ g_autofree char *line = NULL;
+ g_autoptr (GFile) file = NULL;
+ g_autoptr (GFileInputStream) istr = NULL;
+ g_autoptr (GDataInputStream) dstr = NULL;
+ const char *desktops;
+
+ self->available = FALSE;
+
+ desktops = getenv ("XDG_CURRENT_DESKTOP");
+ if (!desktops)
+ return;
+
+ /* Remember that XDG_CURRENT_DESKTOP is a list of strings. */
+ if (strstr (desktops, "KDE") == NULL)
+ return;
+
+ g_clear_pointer (&self->config_file, g_free);
+ self->config_file = proxy_file ? g_strdup (proxy_file) : g_build_filename (g_get_user_config_dir (), "kioslaverc", NULL);
+
+ file = g_file_new_for_path (self->config_file);
+ if (!file) {
+ g_debug ("%s: Could not create file for %s", __FUNCTION__, self->config_file);
+ return;
+ }
+
+ istr = g_file_read (file, NULL, NULL);
+ if (!istr) {
+ g_debug ("%s: Could not read file %s", __FUNCTION__, self->config_file);
+ return;
+ }
+
+ dstr = g_data_input_stream_new (G_INPUT_STREAM (istr));
+ if (!dstr)
+ return;
+
+ g_clear_object (&self->monitor);
+ self->monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, &error);
+ if (!self->monitor)
+ g_warning ("Could not add a file monitor for %s, error: %s", g_file_get_uri (file), error->message);
+ else
+ g_signal_connect_object (G_OBJECT (self->monitor), "changed", G_CALLBACK (on_file_changed), self, 0);
+
+ do {
+ g_clear_pointer (&line, g_free);
+
+ line = g_data_input_stream_read_line (dstr, NULL, NULL, &error);
+ if (line) {
+ g_auto (GStrv) kv = NULL;
+ g_autoptr (GString) value = NULL;
+ kv = g_strsplit (line, "=", 2);
+
+ if (g_strv_length (kv) != 2)
+ continue;
+
+ value = g_string_new (kv[1]);
+ g_string_replace (value, "\"", "", 0);
+ g_string_replace (value, " ", ":", 0);
+
+ if (strcmp (kv[0], "httpsProxy") == 0) {
+ self->https_proxy = g_strdup (value->str);
+ } else if (strcmp (kv[0], "httpProxy") == 0) {
+ self->http_proxy = g_strdup (value->str);
+ } else if (strcmp (kv[0], "ftpProxy") == 0) {
+ self->ftp_proxy = g_strdup (value->str);
+ } else if (strcmp (kv[0], "socksProxy") == 0) {
+ self->socks_proxy = g_strdup (value->str);
+ } else if (strcmp (kv[0], "NoProxyFor") == 0) {
+ self->no_proxy = g_strsplit (value->str, ",", -1);
+ } else if (strcmp (kv[0], "Proxy Config Script") == 0) {
+ self->pac_script = g_strdup (value->str);
+ } else if (strcmp (kv[0], "ProxyType") == 0) {
+ self->proxy_type = atoi (value->str);
+ }
+ }
+ } while (line);
+
+ self->available = TRUE;
+}
+
+
+static void
+px_config_kde_init (PxConfigKde *self)
+{
+ px_config_kde_set_config_file (self, NULL);
+}
+
+static void
+px_config_kde_dispose (GObject *object)
+{
+ PxConfigKde *self = PX_CONFIG_KDE (object);
+
+ g_clear_pointer (&self->config_file, g_free);
+ g_clear_object (&self->monitor);
+ g_clear_pointer (&self->no_proxy, g_strfreev);
+ g_clear_pointer (&self->http_proxy, g_free);
+ g_clear_pointer (&self->https_proxy, g_free);
+ g_clear_pointer (&self->ftp_proxy, g_free);
+ g_clear_pointer (&self->socks_proxy, g_free);
+ g_clear_pointer (&self->pac_script, g_free);
+
+ G_OBJECT_CLASS (px_config_kde_parent_class)->dispose (object);
+}
+
+static void
+px_config_kde_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PxConfigKde *config = PX_CONFIG_KDE (object);
+
+ switch (prop_id) {
+ case PROP_CONFIG_OPTION:
+ px_config_kde_set_config_file (config, g_value_dup_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_kde_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PxConfigKde *config = PX_CONFIG_KDE (object);
+
+ switch (prop_id) {
+ case PROP_CONFIG_OPTION:
+ g_value_set_string (value, config->config_file);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_kde_class_init (PxConfigKdeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = px_config_kde_dispose;
+ object_class->set_property = px_config_kde_set_property;
+ object_class->get_property = px_config_kde_get_property;
+
+ g_object_class_override_property (object_class, PROP_CONFIG_OPTION, "config-option");
+}
+
+static gboolean
+px_config_kde_is_available (PxConfig *config)
+{
+ PxConfigKde *self = PX_CONFIG_KDE (config);
+
+ return self->available;
+}
+
+static void
+px_config_kde_get_config (PxConfig *config,
+ GUri *uri,
+ GStrvBuilder *builder)
+{
+ PxConfigKde *self = PX_CONFIG_KDE (config);
+ const char *scheme = g_uri_get_scheme (uri);
+ g_autofree char *proxy = NULL;
+
+ if (!self->available)
+ return;
+
+ if (!self->proxy_type)
+ return;
+
+ if (px_manager_is_ignore (uri, self->no_proxy))
+ return;
+
+ switch (self->proxy_type) {
+ case KDE_PROXY_TYPE_MANUAL:
+ case KDE_PROXY_TYPE_SYSTEM:
+ /* System is the same as manual, except that a button for auto dection
+ * is shown. Based on this manual fields are set.
+ */
+ if (g_strcmp0 (scheme, "ftp") == 0) {
+ proxy = g_strdup (self->ftp_proxy);
+ } else if (g_strcmp0 (scheme, "https") == 0) {
+ proxy = g_strdup (self->https_proxy);
+ } else if (g_strcmp0 (scheme, "http") == 0) {
+ proxy = g_strdup (self->http_proxy);
+ } else if (self->socks_proxy && strlen (self->socks_proxy) > 0) {
+ proxy = g_strdup (self->socks_proxy);
+ }
+ break;
+ case KDE_PROXY_TYPE_WPAD:
+ proxy = g_strdup ("wpad://");
+ break;
+ case KDE_PROXY_TYPE_PAC:
+ proxy = g_strdup_printf ("pac+%s", self->pac_script);
+ break;
+ case KDE_PROXY_TYPE_NONE:
+ default:
+ break;
+ }
+
+ if (proxy)
+ px_strv_builder_add_proxy (builder, proxy);
+}
+
+static void
+px_config_iface_init (PxConfigInterface *iface)
+{
+ iface->name = "config-kde";
+ iface->priority = PX_CONFIG_PRIORITY_DEFAULT;
+ iface->is_available = px_config_kde_is_available;
+ iface->get_config = px_config_kde_get_config;
+}
diff --git a/src/backend/plugins/config-kde/config-kde.h b/src/backend/plugins/config-kde/config-kde.h
new file mode 100644
index 0000000..892c45a
--- /dev/null
+++ b/src/backend/plugins/config-kde/config-kde.h
@@ -0,0 +1,34 @@
+/* config-kde.h
+ *
+ * Copyright 2022-2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define PX_CONFIG_TYPE_KDE (px_config_kde_get_type ())
+
+G_DECLARE_FINAL_TYPE (PxConfigKde, px_config_kde, PX, CONFIG_KDE, GObject)
+
+G_END_DECLS
+
+
diff --git a/src/backend/plugins/config-kde/meson.build b/src/backend/plugins/config-kde/meson.build
new file mode 100644
index 0000000..b34d78d
--- /dev/null
+++ b/src/backend/plugins/config-kde/meson.build
@@ -0,0 +1,9 @@
+plugin_name = 'config-kde'
+
+if get_option(plugin_name)
+
+px_backend_sources += [
+ 'plugins/@0@/@0@.c'.format(plugin_name),
+]
+
+endif \ No newline at end of file
diff --git a/src/backend/plugins/config-osx/config-osx.c b/src/backend/plugins/config-osx/config-osx.c
new file mode 100644
index 0000000..16813a0
--- /dev/null
+++ b/src/backend/plugins/config-osx/config-osx.c
@@ -0,0 +1,341 @@
+/* config-osx.c
+ *
+ * Copyright 2022-2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <SystemConfiguration/SystemConfiguration.h>
+
+#include <gio/gio.h>
+
+#include "config-osx.h"
+
+#include "px-plugin-config.h"
+#include "px-manager.h"
+
+static void px_config_iface_init (PxConfigInterface *iface);
+
+struct _PxConfigOsX {
+ GObject parent_instance;
+};
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (PxConfigOsX,
+ px_config_osx,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (PX_TYPE_CONFIG, px_config_iface_init))
+
+enum {
+ PROP_0,
+ PROP_CONFIG_OPTION
+};
+
+static void
+px_config_osx_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_CONFIG_OPTION:
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_osx_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_osx_init (PxConfigOsX *self)
+{
+}
+
+static void
+px_config_osx_class_init (PxConfigOsXClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = px_config_osx_set_property;
+ object_class->get_property = px_config_osx_get_property;
+
+ g_object_class_override_property (object_class, PROP_CONFIG_OPTION, "config-option");
+}
+
+static gboolean
+px_config_osx_is_available (PxConfig *self)
+{
+ return TRUE;
+}
+
+static CFNumberRef
+getobj (CFDictionaryRef settings,
+ char *key)
+{
+ CFStringRef k;
+ CFNumberRef retval;
+
+ if (!settings)
+ return NULL;
+
+ k = CFStringCreateWithCString (NULL, key, kCFStringEncodingMacRoman);
+ if (!k)
+ return NULL;
+
+ retval = (CFNumberRef)CFDictionaryGetValue (settings, k);
+
+ CFRelease (k);
+ return retval;
+}
+
+static CFStringRef
+getobj_str (CFDictionaryRef settings,
+ char *key)
+{
+ CFStringRef k;
+ CFStringRef retval;
+
+ if (!settings)
+ return NULL;
+
+ k = CFStringCreateWithCString (NULL, key, kCFStringEncodingMacRoman);
+ if (!k)
+ return NULL;
+
+ retval = (CFStringRef)CFDictionaryGetValue (settings, k);
+
+ CFRelease (k);
+ return retval;
+}
+
+static CFArrayRef
+getobj_array (CFDictionaryRef settings,
+ char *key)
+{
+ CFStringRef k;
+ CFArrayRef retval;
+
+ if (!settings)
+ return NULL;
+
+ k = CFStringCreateWithCString (NULL, key, kCFStringEncodingMacRoman);
+ if (!k)
+ return NULL;
+
+ retval = (CFArrayRef)CFDictionaryGetValue (settings, k);
+
+ CFRelease (k);
+ return retval;
+}
+
+static char *
+str (CFStringRef ref)
+{
+ CFIndex size = CFStringGetLength (ref) + 1;
+ char *ret = g_malloc0 (size);
+
+ CFStringGetCString (ref, ret, size, kCFStringEncodingUTF8);
+
+ return ret;
+}
+
+static gboolean
+getint (CFDictionaryRef settings,
+ char *key,
+ int64_t *answer)
+{
+ CFNumberRef n = getobj (settings, key);
+
+ if (!n)
+ return FALSE;
+
+ if (!CFNumberGetValue (n, kCFNumberSInt64Type, answer))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+getbool (CFDictionaryRef settings,
+ char *key)
+{
+ int64_t i = 0;
+
+ if (!getint (settings, key, &i))
+ return FALSE;
+
+ return i != 0;
+}
+
+static char *
+str_to_upper (const char *str)
+{
+ char *ret = NULL;
+ int idx;
+
+ if (!str)
+ return NULL;
+
+ ret = g_malloc0 (strlen (str) + 1);
+
+ for (idx = 0; idx < strlen (str); idx++)
+ ret[idx] = g_ascii_toupper (str[idx]);
+
+ return ret;
+}
+
+static char *
+protocol_url (CFDictionaryRef settings,
+ char *protocol)
+{
+ g_autofree char *tmp = NULL;
+ g_autoptr (GString) ret = NULL;
+ g_autofree char *host = NULL;
+ int64_t port;
+ CFStringRef ref;
+
+ /* Check ProtocolEnabled */
+ tmp = g_strconcat (protocol, "Enable", NULL);
+ if (!getbool (settings, tmp)) {
+ g_debug ("%s: %s not set", __FUNCTION__, tmp);
+ return NULL;
+ }
+ g_clear_pointer (&tmp, g_free);
+
+ /* Get ProtocolPort */
+ tmp = g_strconcat (protocol, "Port", NULL);
+ getint (settings, tmp, &port);
+ if (!port) {
+ g_debug ("%s: %s not set", __FUNCTION__, tmp);
+ return NULL;
+ }
+ g_clear_pointer (&tmp, g_free);
+
+ /* Get ProtocolProxy */
+ tmp = g_strconcat (protocol, "Proxy", NULL);
+ ref = getobj_str (settings, tmp);
+ g_clear_pointer (&tmp, g_free);
+
+ host = str (ref);
+ if (!host || strlen (host) == 0)
+ return NULL;
+
+ if (strcmp (protocol, "HTTP") == 0 || strcmp (protocol, "HTTPS") == 0 || strcmp (protocol, "FTP") == 0 || strcmp (protocol, "Gopher") == 0)
+ ret = g_string_new ("http://");
+ else if (strcmp (protocol, "RTSP") == 0)
+ ret = g_string_new ("rtsp://");
+ else if (strcmp (protocol, "SOCKS") == 0)
+ ret = g_string_new ("socks://");
+ else
+ return NULL;
+
+ g_string_append_printf (ret, "%s:%lld", host, port);
+
+ return g_strdup (ret->str);
+}
+
+static GStrv
+get_ignore_list (CFDictionaryRef proxies)
+{
+ CFArrayRef ref = getobj_array (proxies, "ExceptionsList");
+ g_autoptr (GStrvBuilder) ret = g_strv_builder_new ();
+
+ if (!ref)
+ return g_strv_builder_end (ret);
+
+ for (int idx = 0; idx < CFArrayGetCount (ref); idx++) {
+ CFStringRef s = (CFStringRef)CFArrayGetValueAtIndex (ref, idx);
+
+ px_strv_builder_add_proxy (ret, str (s));
+ }
+
+ if (getbool (proxies, "ExcludeSimpleHostnames"))
+ px_strv_builder_add_proxy (ret, "127.0.0.1");
+
+ return g_strv_builder_end (ret);
+}
+
+static void
+px_config_osx_get_config (PxConfig *self,
+ GUri *uri,
+ GStrvBuilder *builder)
+{
+ const char *proxy = NULL;
+ CFDictionaryRef proxies = SCDynamicStoreCopyProxies (NULL);
+ g_auto (GStrv) ignore_list = NULL;
+
+ if (!proxies) {
+ g_warning ("Unable to fetch proxy configuration");
+ return;
+ }
+
+ ignore_list = get_ignore_list (proxies);
+
+ if (px_manager_is_ignore (uri, ignore_list))
+ return;
+
+ if (getbool (proxies, "ProxyAutoDiscoveryEnable")) {
+ CFRelease (proxies);
+ px_strv_builder_add_proxy (builder, "wpad://");
+ return;
+ }
+
+ if (getbool (proxies, "ProxyAutoConfigEnable")) {
+ CFStringRef ref = getobj_str (proxies, "ProxyAutoConfigURLString");
+ g_autofree char *tmp = str (ref);
+ GUri *tmp_uri = g_uri_parse (tmp, G_URI_FLAGS_PARSE_RELAXED, NULL);
+
+ if (tmp_uri) {
+ g_autofree char *ret = g_strdup_printf ("pac+%s", g_uri_to_string (tmp_uri));
+ CFRelease (proxies);
+ px_strv_builder_add_proxy (builder, ret);
+ return;
+ }
+ } else {
+ const char *scheme = g_uri_get_scheme (uri);
+ g_autofree char *capital_scheme = str_to_upper (scheme);
+
+ proxy = protocol_url (proxies, capital_scheme);
+
+ if (!proxy)
+ proxy = protocol_url (proxies, "SOCKS");
+ }
+
+ if (proxy)
+ px_strv_builder_add_proxy (builder, proxy);
+}
+
+static void
+px_config_iface_init (PxConfigInterface *iface)
+{
+ iface->name = "config-osx";
+ iface->priority = PX_CONFIG_PRIORITY_DEFAULT;
+ iface->is_available = px_config_osx_is_available;
+ iface->get_config = px_config_osx_get_config;
+}
diff --git a/src/backend/plugins/config-osx/config-osx.h b/src/backend/plugins/config-osx/config-osx.h
new file mode 100644
index 0000000..797b51e
--- /dev/null
+++ b/src/backend/plugins/config-osx/config-osx.h
@@ -0,0 +1,34 @@
+/* config-osx.h
+ *
+ * Copyright 2022-2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define PX_CONFIG_TYPE_OSX (px_config_osx_get_type ())
+
+G_DECLARE_FINAL_TYPE (PxConfigOsX, px_config_osx, PX, CONFIG_OSX, GObject)
+
+G_END_DECLS
+
+
diff --git a/src/backend/plugins/config-osx/meson.build b/src/backend/plugins/config-osx/meson.build
new file mode 100644
index 0000000..f801d90
--- /dev/null
+++ b/src/backend/plugins/config-osx/meson.build
@@ -0,0 +1,16 @@
+plugin_name = 'config-osx'
+
+if get_option(plugin_name) and with_platform_darwin
+
+foundation_dep = dependency('Foundation')
+system_configuration_dep = dependency('SystemConfiguration')
+px_backend_deps += [
+ foundation_dep,
+ system_configuration_dep,
+]
+
+px_backend_sources += [
+ 'plugins/@0@/@0@.c'.format(plugin_name),
+]
+
+endif
diff --git a/src/backend/plugins/config-sysconfig/config-sysconfig.c b/src/backend/plugins/config-sysconfig/config-sysconfig.c
new file mode 100644
index 0000000..c640f1c
--- /dev/null
+++ b/src/backend/plugins/config-sysconfig/config-sysconfig.c
@@ -0,0 +1,252 @@
+/* config-sysconfig.c
+ *
+ * Copyright 2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <gio/gio.h>
+
+#include "config-sysconfig.h"
+
+#include "px-manager.h"
+#include "px-plugin-config.h"
+
+struct _PxConfigSysConfig {
+ GObject parent_instance;
+ GFileMonitor *monitor;
+
+ char *config_file;
+ gboolean available;
+
+ gboolean proxy_enabled;
+ char *https_proxy;
+ char *http_proxy;
+ char *ftp_proxy;
+ GStrv no_proxy;
+};
+
+static void px_config_iface_init (PxConfigInterface *iface);
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (PxConfigSysConfig,
+ px_config_sysconfig,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (PX_TYPE_CONFIG, px_config_iface_init))
+
+enum {
+ PROP_0,
+ PROP_CONFIG_OPTION
+};
+
+static void px_config_sysconfig_set_config_file (PxConfigSysConfig *self,
+ const char *config_file);
+
+static void
+on_file_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ gpointer user_data)
+{
+ PxConfigSysConfig *self = PX_CONFIG_SYSCONFIG (user_data);
+
+ g_debug ("%s: Reloading configuration", __FUNCTION__);
+ px_config_sysconfig_set_config_file (self, g_file_get_path (file));
+}
+
+static
+void
+px_config_sysconfig_set_config_file (PxConfigSysConfig *self,
+ const char *config_file)
+{
+ g_autofree char *config = NULL;
+ g_autoptr (GFile) file = NULL;
+ g_autoptr (GError) error = NULL;
+ g_autoptr (GFileInputStream) istr = NULL;
+ g_autoptr (GDataInputStream) dstr = NULL;
+ char *line = NULL;
+
+ g_clear_pointer (&self->config_file, g_free);
+ self->config_file = g_strdup (config_file ? config_file : "/etc/sysconfig/proxy");
+ self->available = FALSE;
+
+ file = g_file_new_for_path (self->config_file);
+ if (!file) {
+ g_debug ("%s: Could not create file for %s", __FUNCTION__, self->config_file);
+ return;
+ }
+
+ istr = g_file_read (file, NULL, NULL);
+ if (!istr) {
+ g_debug ("%s: Could not read file %s", __FUNCTION__, self->config_file);
+ return;
+ }
+
+ dstr = g_data_input_stream_new (G_INPUT_STREAM (istr));
+ if (!dstr)
+ return;
+
+ g_clear_object (&self->monitor);
+ self->monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, &error);
+ if (!self->monitor)
+ g_warning ("Could not add a file monitor for %s, error: %s", g_file_get_uri (file), error->message);
+ else
+ g_signal_connect_object (G_OBJECT (self->monitor), "changed", G_CALLBACK (on_file_changed), self, 0);
+
+ do {
+ g_clear_pointer (&line, g_free);
+
+ line = g_data_input_stream_read_line (dstr, NULL, NULL, &error);
+ if (line) {
+ g_auto (GStrv) kv = NULL;
+ g_autoptr (GString) value = NULL;
+ kv = g_strsplit (line, "=", -1);
+
+ if (g_strv_length (kv) != 2)
+ continue;
+
+ value = g_string_new (kv[1]);
+ g_string_replace (value, "\"", "", 0);
+ g_string_replace (value, "\r", "", 0);
+
+ if (strcmp (kv[0], "PROXY_ENABLED") == 0) {
+ self->proxy_enabled = g_ascii_strncasecmp (value->str, "yes", 3) == 0;
+ } else if (strcmp (kv[0], "HTTPS_PROXY") == 0) {
+ self->https_proxy = g_strdup (value->str);
+ } else if (strcmp (kv[0], "HTTP_PROXY") == 0) {
+ self->http_proxy = g_strdup (value->str);
+ } else if (strcmp (kv[0], "FTP_PROXY") == 0) {
+ self->ftp_proxy = g_strdup (value->str);
+ } else if (strcmp (kv[0], "NO_PROXY") == 0) {
+ g_autofree char *tmp = g_strdup (value->str);
+ self->no_proxy = g_strsplit (tmp, ",", -1);
+ }
+ }
+ } while (line);
+
+ self->available = TRUE;
+}
+
+static void
+px_config_sysconfig_init (PxConfigSysConfig *self)
+{
+}
+
+static void
+px_config_sysconfig_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PxConfigSysConfig *config = PX_CONFIG_SYSCONFIG (object);
+
+ switch (prop_id) {
+ case PROP_CONFIG_OPTION:
+ px_config_sysconfig_set_config_file (config, g_value_dup_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_sysconfig_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PxConfigSysConfig *config = PX_CONFIG_SYSCONFIG (object);
+
+ switch (prop_id) {
+ case PROP_CONFIG_OPTION:
+ g_value_set_string (value, config->config_file);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_sysconfig_dispose (GObject *object)
+{
+ PxConfigSysConfig *self = PX_CONFIG_SYSCONFIG (object);
+
+ g_clear_object (&self->monitor);
+ g_clear_pointer (&self->no_proxy, g_strfreev);
+
+ G_OBJECT_CLASS (px_config_sysconfig_parent_class)->dispose (object);
+}
+
+static void
+px_config_sysconfig_class_init (PxConfigSysConfigClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = px_config_sysconfig_dispose;
+ object_class->set_property = px_config_sysconfig_set_property;
+ object_class->get_property = px_config_sysconfig_get_property;
+
+ g_object_class_override_property (object_class, PROP_CONFIG_OPTION, "config-option");
+}
+
+static gboolean
+px_config_sysconfig_is_available (PxConfig *config)
+{
+ PxConfigSysConfig *self = PX_CONFIG_SYSCONFIG (config);
+
+ return self->available;
+}
+
+static void
+px_config_sysconfig_get_config (PxConfig *config,
+ GUri *uri,
+ GStrvBuilder *builder)
+{
+ PxConfigSysConfig *self = PX_CONFIG_SYSCONFIG (config);
+ const char *scheme = g_uri_get_scheme (uri);
+ g_autofree char *proxy = NULL;
+
+ if (!self->proxy_enabled)
+ return;
+
+ if (px_manager_is_ignore (uri, self->no_proxy))
+ return;
+
+ if (g_strcmp0 (scheme, "ftp") == 0) {
+ proxy = g_strdup (self->ftp_proxy);
+ } else if (g_strcmp0 (scheme, "https") == 0) {
+ proxy = g_strdup (self->https_proxy);
+ } else if (g_strcmp0 (scheme, "http") == 0) {
+ proxy = g_strdup (self->http_proxy);
+ }
+
+ if (proxy)
+ px_strv_builder_add_proxy (builder, proxy);
+}
+
+static void
+px_config_iface_init (PxConfigInterface *iface)
+{
+ iface->name = "config-sysconfig";
+ iface->priority = PX_CONFIG_PRIORITY_LAST;
+ iface->is_available = px_config_sysconfig_is_available;
+ iface->get_config = px_config_sysconfig_get_config;
+}
diff --git a/src/backend/plugins/config-sysconfig/config-sysconfig.h b/src/backend/plugins/config-sysconfig/config-sysconfig.h
new file mode 100644
index 0000000..daa4672
--- /dev/null
+++ b/src/backend/plugins/config-sysconfig/config-sysconfig.h
@@ -0,0 +1,34 @@
+/* config-sysconfig.h
+ *
+ * Copyright 2022-2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define PX_CONFIG_TYPE_SYSCONFIG (px_config_sysconfig_get_type ())
+
+G_DECLARE_FINAL_TYPE (PxConfigSysConfig, px_config_sysconfig, PX, CONFIG_SYSCONFIG, GObject)
+
+G_END_DECLS
+
+
diff --git a/src/backend/plugins/config-sysconfig/meson.build b/src/backend/plugins/config-sysconfig/meson.build
new file mode 100644
index 0000000..6d6789b
--- /dev/null
+++ b/src/backend/plugins/config-sysconfig/meson.build
@@ -0,0 +1,9 @@
+plugin_name = 'config-sysconfig'
+
+if get_option(plugin_name)
+
+px_backend_sources += [
+ 'plugins/@0@/@0@.c'.format(plugin_name),
+]
+
+endif
diff --git a/src/backend/plugins/config-windows/config-windows.c b/src/backend/plugins/config-windows/config-windows.c
new file mode 100644
index 0000000..cc9c92d
--- /dev/null
+++ b/src/backend/plugins/config-windows/config-windows.c
@@ -0,0 +1,252 @@
+/* config-windows.c
+ *
+ * Copyright 2022-2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <windows.h>
+#include <winreg.h>
+
+#include <gio/gio.h>
+
+#include "config-windows.h"
+
+#include "px-plugin-config.h"
+#include "px-manager.h"
+
+#define W32REG_OFFSET_PAC (1 << 2)
+#define W32REG_OFFSET_WPAD (1 << 3)
+#define W32REG_BASEKEY "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
+#define W32REG_BUFFLEN 1024
+
+struct _PxConfigWindows {
+ GObject parent_instance;
+};
+
+static void px_config_iface_init (PxConfigInterface *iface);
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (PxConfigWindows,
+ px_config_windows,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (PX_TYPE_CONFIG, px_config_iface_init))
+
+enum {
+ PROP_0,
+ PROP_CONFIG_OPTION
+};
+
+static void
+px_config_windows_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_CONFIG_OPTION:
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_windows_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_windows_init (PxConfigWindows *self)
+{
+}
+
+static void
+px_config_windows_class_init (PxConfigWindowsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = px_config_windows_set_property;
+ object_class->get_property = px_config_windows_get_property;
+
+ g_object_class_override_property (object_class, PROP_CONFIG_OPTION, "config-option");
+}
+
+static gboolean
+px_config_windows_is_available (PxConfig *self)
+{
+ return TRUE;
+}
+
+static gboolean
+get_registry (const char *key,
+ const char *name,
+ char **sval,
+ guint32 *slen,
+ guint32 *ival)
+{
+ HKEY hkey;
+ LONG result;
+ DWORD type;
+ DWORD buflen = W32REG_BUFFLEN;
+ BYTE buffer[W32REG_BUFFLEN];
+
+ if (sval && ival)
+ return FALSE;
+
+ if (RegOpenKeyExA (HKEY_CURRENT_USER, key, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
+ return FALSE;
+
+ result = RegQueryValueExA (hkey, name, NULL, &type, buffer, &buflen);
+ RegCloseKey (hkey);
+
+ if (result != ERROR_SUCCESS)
+ return FALSE;
+
+ switch (type) {
+ case REG_BINARY:
+ case REG_EXPAND_SZ:
+ case REG_SZ:
+ if (!sval)
+ return FALSE;
+ if (slen)
+ *slen = buflen;
+
+ *sval = g_malloc0 (buflen);
+ return memcpy (*sval, buffer, buflen) != NULL;
+ case REG_DWORD:
+ if (ival)
+ return memcpy (ival, buffer, buflen < sizeof (guint32) ? buflen : sizeof (guint32)) != NULL;
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static GHashTable *
+parse_manual (char *manual)
+{
+ g_auto (GStrv) split = NULL;
+ GHashTable *ret = g_hash_table_new (g_str_hash, g_str_equal);
+
+ /* We have to check for two formats:
+ * - 1.2.3.4:8080
+ * - ftp=1.2.4.5:8080;https=1.2.3.4:8080
+ */
+
+ split = g_strsplit (manual, ";", -1);
+ for (int idx = 0; idx < g_strv_length (split); idx++) {
+ if (!strchr (split[idx], '=')) {
+ g_hash_table_insert (ret, (char *)"http", g_strdup_printf ("http://%s", split[idx]));
+ } else {
+ g_auto (GStrv) split_kv = g_strsplit (split[idx], "=", -1);
+
+ if (g_strv_length (split_kv) == 2) {
+ g_hash_table_insert (ret, g_strdup (split_kv[0]), g_strdup_printf ("%s://%s", split_kv[0], split_kv[1]));
+ }
+ }
+ }
+
+ return ret;
+}
+
+static gboolean
+is_enabled (char type)
+{
+ g_autofree char *data = NULL;
+ guint32 dlen = 0;
+ gboolean result = FALSE;
+
+ if (!get_registry (W32REG_BASEKEY "\\Connections", "DefaultConnectionSettings", &data, &dlen, NULL))
+ return FALSE;
+
+ if (dlen >= 9)
+ result = (data[8] & type) == type;
+
+ return result;
+}
+
+static void
+px_config_windows_get_config (PxConfig *self,
+ GUri *uri,
+ GStrvBuilder *builder)
+{
+ char *tmp = NULL;
+ guint32 enabled = 0;
+
+ if (get_registry (W32REG_BASEKEY, "ProxyOverride", &tmp, NULL, NULL)) {
+ g_auto (GStrv) no_proxy = g_strsplit (tmp, ",", -1);
+
+ if (px_manager_is_ignore (uri, no_proxy))
+ return;
+ }
+
+ /* WPAD */
+ if (is_enabled (W32REG_OFFSET_WPAD)) {
+ px_strv_builder_add_proxy (builder, "wpad://");
+ return;
+ }
+
+ /* PAC */
+ if (is_enabled (W32REG_OFFSET_PAC) && get_registry (W32REG_BASEKEY, "AutoConfigURL", &tmp, NULL, NULL)) {
+ g_autofree char *pac_uri = g_strconcat ("pac+", tmp, NULL);
+ GUri *ac_uri = g_uri_parse (tmp, G_URI_FLAGS_PARSE_RELAXED, NULL);
+
+ if (ac_uri) {
+ px_strv_builder_add_proxy (builder, pac_uri);
+ return;
+ }
+ }
+
+ /* Manual proxy */
+ if (get_registry (W32REG_BASEKEY, "ProxyEnable", NULL, NULL, &enabled) && enabled && get_registry (W32REG_BASEKEY, "ProxyServer", &tmp, NULL, NULL)) {
+ g_autoptr (GHashTable) table = parse_manual (tmp);
+ const char *scheme = g_uri_get_scheme (uri);
+
+ if (table) {
+ char *ret = g_hash_table_lookup (table, scheme);
+ if (ret) {
+ px_strv_builder_add_proxy (builder, ret);
+ return;
+ }
+
+ ret = g_hash_table_lookup (table, "socks");
+ if (ret) {
+ px_strv_builder_add_proxy (builder, ret);
+ return;
+ }
+ }
+ }
+}
+
+static void
+px_config_iface_init (PxConfigInterface *iface)
+{
+ iface->name = "config-windows";
+ iface->priority = PX_CONFIG_PRIORITY_DEFAULT;
+ iface->is_available = px_config_windows_is_available;
+ iface->get_config = px_config_windows_get_config;
+}
diff --git a/src/backend/plugins/config-windows/config-windows.h b/src/backend/plugins/config-windows/config-windows.h
new file mode 100644
index 0000000..7c2afcf
--- /dev/null
+++ b/src/backend/plugins/config-windows/config-windows.h
@@ -0,0 +1,34 @@
+/* config-windows.h
+ *
+ * Copyright 2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define PX_CONFIG_TYPE_WINDOWS (px_config_windows_get_type ())
+
+G_DECLARE_FINAL_TYPE (PxConfigWindows, px_config_windows, PX, CONFIG_WINDOWS, GObject)
+
+G_END_DECLS
+
+
diff --git a/src/backend/plugins/config-windows/meson.build b/src/backend/plugins/config-windows/meson.build
new file mode 100644
index 0000000..302a33e
--- /dev/null
+++ b/src/backend/plugins/config-windows/meson.build
@@ -0,0 +1,9 @@
+plugin_name = 'config-windows'
+
+if get_option(plugin_name) and with_platform_windows
+
+px_backend_sources += [
+ 'plugins/@0@/@0@.c'.format(plugin_name),
+]
+
+endif \ No newline at end of file
diff --git a/src/backend/plugins/meson.build b/src/backend/plugins/meson.build
new file mode 100644
index 0000000..c7943d2
--- /dev/null
+++ b/src/backend/plugins/meson.build
@@ -0,0 +1,18 @@
+subdir('config-env')
+subdir('config-gnome')
+subdir('config-kde')
+subdir('config-osx')
+subdir('config-sysconfig')
+subdir('config-windows')
+
+subdir('pacrunner-duktape')
+
+summary({
+ 'Configuration Environment' : get_option('config-env'),
+ 'Configuration GNOME ' : get_option('config-gnome'),
+ 'Configuration KDE ' : get_option('config-kde'),
+ 'Configuration Windows ' : get_option('config-windows'),
+ 'Configuration sysconfig ' : get_option('config-sysconfig'),
+ 'Configuration OS X ' : get_option('config-osx'),
+ 'PAC Runner Duktape ' : get_option('pacrunner-duktape'),
+}, section: 'Plugins') \ No newline at end of file
diff --git a/src/backend/plugins/pacrunner-duktape/meson.build b/src/backend/plugins/pacrunner-duktape/meson.build
new file mode 100644
index 0000000..f391b6d
--- /dev/null
+++ b/src/backend/plugins/pacrunner-duktape/meson.build
@@ -0,0 +1,17 @@
+plugin_name = 'pacrunner-duktape'
+
+if get_option(plugin_name)
+
+duktape_dep = dependency('duktape')
+m_dep = cc.find_library('m', required : false)
+
+px_backend_sources += [
+ 'plugins/@0@/@0@.c'.format(plugin_name),
+]
+
+px_backend_deps += [
+ duktape_dep,
+ m_dep
+]
+
+endif \ No newline at end of file
diff --git a/src/backend/plugins/pacrunner-duktape/pacrunner-duktape.c b/src/backend/plugins/pacrunner-duktape/pacrunner-duktape.c
new file mode 100644
index 0000000..3676e48
--- /dev/null
+++ b/src/backend/plugins/pacrunner-duktape/pacrunner-duktape.c
@@ -0,0 +1,201 @@
+/* pacrunner-duktape.c
+ *
+ * Copyright 2022-2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <gio/gio.h>
+
+#include <unistd.h>
+#ifdef __WIN32__
+#include <ws2tcpip.h>
+#else
+#include <netdb.h>
+#endif
+
+#include "pacrunner-duktape.h"
+#include "pacutils.h"
+#include "px-plugin-pacrunner.h"
+
+#include "duktape.h"
+
+struct _PxPacRunnerDuktape {
+ GObject parent_instance;
+ duk_context *ctx;
+};
+
+static void px_pacrunner_iface_init (PxPacRunnerInterface *iface);
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (PxPacRunnerDuktape,
+ px_pacrunner_duktape,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (PX_TYPE_PACRUNNER, px_pacrunner_iface_init))
+
+
+static duk_ret_t
+dns_resolve (duk_context *ctx)
+{
+ const char *hostname = NULL;
+ struct addrinfo *info;
+ char tmp[INET6_ADDRSTRLEN + 1];
+
+ if (duk_get_top (ctx) != 1) {
+ /* Invalid number of arguments */
+ return 0;
+ }
+
+ /* We do not need to free the string - It's managed by Duktape. */
+ hostname = duk_get_string (ctx, 0);
+ if (!hostname)
+ return 0;
+
+ /* Look it up */
+ if (getaddrinfo (hostname, NULL, NULL, &info))
+ return 0;
+
+ /* Try for IPv4 */
+ if (getnameinfo (info->ai_addr,
+ info->ai_addrlen,
+ tmp,
+ INET6_ADDRSTRLEN + 1,
+ NULL,
+ 0,
+ NI_NUMERICHOST)) {
+ freeaddrinfo (info);
+ duk_push_null (ctx);
+ return 1;
+ }
+ freeaddrinfo (info);
+
+ /* Create the return value */
+ duk_push_string (ctx, tmp);
+
+ return 1;
+}
+
+static duk_ret_t
+my_ip_address (duk_context *ctx)
+{
+ char hostname[1024];
+
+ hostname[sizeof (hostname) - 1] = '\0';
+
+ if (!gethostname (hostname, sizeof (hostname) - 1)) {
+ duk_push_string (ctx, hostname);
+ return dns_resolve (ctx);
+ }
+
+ return duk_error (ctx, DUK_ERR_ERROR, "Unable to find hostname!");
+}
+
+static void
+px_pacrunner_duktape_init (PxPacRunnerDuktape *self)
+{
+ self->ctx = duk_create_heap_default ();
+ if (!self->ctx)
+ return;
+
+ duk_push_c_function (self->ctx, dns_resolve, 1);
+ duk_put_global_string (self->ctx, "dnsResolve");
+
+ duk_push_c_function (self->ctx, my_ip_address, 1);
+ duk_put_global_string (self->ctx, "myIpAddress");
+
+ duk_push_string (self->ctx, JAVASCRIPT_ROUTINES);
+ if (duk_peval_noresult (self->ctx))
+ goto error;
+
+ return;
+
+error:
+ duk_destroy_heap (self->ctx);
+}
+
+static void
+px_pacrunner_duktape_dispose (GObject *object)
+{
+ PxPacRunnerDuktape *self = PX_PACRUNNER_DUKTAPE (object);
+
+ g_clear_pointer (&self->ctx, duk_destroy_heap);
+
+ G_OBJECT_CLASS (px_pacrunner_duktape_parent_class)->dispose (object);
+}
+
+static void
+px_pacrunner_duktape_class_init (PxPacRunnerDuktapeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = px_pacrunner_duktape_dispose;
+}
+
+static gboolean
+px_pacrunner_duktape_set_pac (PxPacRunner *pacrunner,
+ GBytes *pac_data)
+{
+ PxPacRunnerDuktape *self = PX_PACRUNNER_DUKTAPE (pacrunner);
+ gsize len;
+ gconstpointer content = g_bytes_get_data (pac_data, &len);
+
+ duk_push_lstring (self->ctx, content, len);
+
+ if (duk_peval_noresult (self->ctx)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static char *
+px_pacrunner_duktape_run (PxPacRunner *pacrunner,
+ GUri *uri)
+{
+ PxPacRunnerDuktape *self = PX_PACRUNNER_DUKTAPE (pacrunner);
+ duk_int_t result;
+
+ duk_get_global_string (self->ctx, "FindProxyForURL");
+ duk_push_string (self->ctx, g_uri_to_string (uri));
+ duk_push_string (self->ctx, g_uri_get_host (uri));
+ result = duk_pcall (self->ctx, 2);
+
+ if (result == 0) {
+ const char *proxy = duk_get_string (self->ctx, 0);
+ char *proxy_string;
+
+ if (!proxy) {
+ duk_pop (self->ctx);
+ return g_strdup ("");
+ }
+
+ proxy_string = g_strdup (proxy);
+
+ duk_pop (self->ctx);
+
+ return proxy_string;
+ }
+
+ duk_pop (self->ctx);
+ return g_strdup ("");
+}
+
+static void
+px_pacrunner_iface_init (PxPacRunnerInterface *iface)
+{
+ iface->set_pac = px_pacrunner_duktape_set_pac;
+ iface->run = px_pacrunner_duktape_run;
+}
diff --git a/src/backend/plugins/pacrunner-duktape/pacrunner-duktape.h b/src/backend/plugins/pacrunner-duktape/pacrunner-duktape.h
new file mode 100644
index 0000000..8721a62
--- /dev/null
+++ b/src/backend/plugins/pacrunner-duktape/pacrunner-duktape.h
@@ -0,0 +1,32 @@
+/* pacrunner-duktape.h
+ *
+ * Copyright 2022-2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PX_PACRUNNER_TYPE_DUKTAPE (px_pacrunner_duktape_get_type ())
+
+G_DECLARE_FINAL_TYPE (PxPacRunnerDuktape, px_pacrunner_duktape, PX, PACRUNNER_DUKTAPE, GObject)
+
+G_END_DECLS