/*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
* 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.
*
* 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, see .
*
* Authors: Jeffrey Stedfast
* Veerapuram Varadhan
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#ifdef _WIN32
#include
#include
#ifndef IN6_ARE_ADDR_EQUAL
#define IN6_ARE_ADDR_EQUAL(a, b) \
(memcmp ((gpointer)(a), (gpointer)(b), sizeof (struct in6_addr)) == 0)
#endif
#else
#include
#include
#endif
#include
#include
#include "e-proxy.h"
#define E_PROXY_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_PROXY, EProxyPrivate))
G_DEFINE_TYPE (EProxy, e_proxy, G_TYPE_OBJECT)
/* Debug */
#define d(x)
enum ProxyType {
PROXY_TYPE_SYSTEM = 0,
PROXY_TYPE_NO_PROXY,
PROXY_TYPE_MANUAL,
PROXY_TYPE_AUTO_URL /* no auto-proxy at the moment */
};
typedef enum {
E_PROXY_KEY_MODE,
E_PROXY_KEY_USE_HTTP_PROXY,
E_PROXY_KEY_HTTP_HOST,
E_PROXY_KEY_HTTP_PORT,
E_PROXY_KEY_HTTP_USE_AUTH,
E_PROXY_KEY_HTTP_AUTH_USER,
E_PROXY_KEY_HTTP_AUTH_PWD,
E_PROXY_KEY_HTTP_IGNORE_HOSTS,
E_PROXY_KEY_HTTPS_HOST,
E_PROXY_KEY_HTTPS_PORT,
E_PROXY_KEY_SOCKS_HOST,
E_PROXY_KEY_SOCKS_PORT,
E_PROXY_KEY_AUTOCONFIG_URL
} EProxyKey;
struct _EProxyPrivate {
SoupURI *uri_http, *uri_https, *uri_socks;
GSList * ign_hosts; /* List of hostnames. (Strings) */
GSList * ign_addrs; /* List of hostaddrs. (ProxyHostAddrs) */
gboolean use_proxy; /* Is our-proxy enabled? */
enum ProxyType type;
GSettings *evolution_proxy_settings;
GSettings *proxy_settings;
GSettings *proxy_http_settings;
GSettings *proxy_https_settings;
GSettings *proxy_socks_settings;
};
/* Enum definition is copied from gnome-vfs/modules/http-proxy.c */
typedef enum {
PROXY_IPV4 = 4,
PROXY_IPV6 = 6
} ProxyAddrType;
typedef struct {
ProxyAddrType type; /* Specifies whether IPV4 or IPV6 */
gpointer addr; /* Either in_addr * or in6_addr * */
gpointer mask; /* Either in_addr * or in6_addr * */
} ProxyHostAddr;
/* Signals. */
enum {
CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
/* Forward declarations. */
static void ipv6_network_addr (const struct in6_addr *addr,
const struct in6_addr *mask,
struct in6_addr *res);
static void
ep_free_proxy_host_addr (ProxyHostAddr *host)
{
if (host) {
if (host->addr) {
g_free (host->addr);
host->addr = NULL;
}
if (host->mask) {
g_free (host->mask);
host->mask = NULL;
}
g_free (host);
}
}
static gboolean
ep_read_key_boolean (EProxy *proxy,
EProxyKey key)
{
gboolean res = FALSE;
g_return_val_if_fail (E_IS_PROXY (proxy), FALSE);
switch (key) {
case E_PROXY_KEY_USE_HTTP_PROXY:
if (proxy->priv->type == PROXY_TYPE_SYSTEM)
/* it's not used in the UI, thus behave like always set to TRUE */
res = TRUE; /* g_settings_get_boolean (proxy->priv->proxy_http_settings, "enabled"); */
else
res = g_settings_get_boolean (proxy->priv->evolution_proxy_settings, "use-http-proxy");
break;
case E_PROXY_KEY_HTTP_USE_AUTH:
if (proxy->priv->type == PROXY_TYPE_SYSTEM)
res = g_settings_get_boolean (proxy->priv->proxy_http_settings, "use-authentication");
else
res = g_settings_get_boolean (proxy->priv->evolution_proxy_settings, "use-authentication");
break;
default:
g_warn_if_reached ();
break;
}
return res;
}
static gint
ep_read_key_int (EProxy *proxy,
EProxyKey key)
{
gint res = 0;
g_return_val_if_fail (E_IS_PROXY (proxy), 0);
switch (key) {
case E_PROXY_KEY_HTTP_PORT:
if (proxy->priv->type == PROXY_TYPE_SYSTEM)
res = g_settings_get_int (proxy->priv->proxy_http_settings, "port");
else
res = g_settings_get_int (proxy->priv->evolution_proxy_settings, "http-port");
break;
case E_PROXY_KEY_HTTPS_PORT:
if (proxy->priv->type == PROXY_TYPE_SYSTEM)
res = g_settings_get_int (proxy->priv->proxy_https_settings, "port");
else
res = g_settings_get_int (proxy->priv->evolution_proxy_settings, "secure-port");
break;
case E_PROXY_KEY_SOCKS_PORT:
if (proxy->priv->type == PROXY_TYPE_SYSTEM)
res = g_settings_get_int (proxy->priv->proxy_socks_settings, "port");
else
res = g_settings_get_int (proxy->priv->evolution_proxy_settings, "socks-port");
break;
default:
g_warn_if_reached ();
break;
}
return res;
}
/* free returned pointer with g_free() */
static gchar *
ep_read_key_string (EProxy *proxy,
EProxyKey key)
{
gchar *res = NULL;
g_return_val_if_fail (E_IS_PROXY (proxy), NULL);
switch (key) {
case E_PROXY_KEY_MODE:
if (proxy->priv->type == PROXY_TYPE_SYSTEM)
res = g_settings_get_string (proxy->priv->proxy_settings, "mode");
else
g_warn_if_reached ();
break;
case E_PROXY_KEY_HTTP_HOST:
if (proxy->priv->type == PROXY_TYPE_SYSTEM)
res = g_settings_get_string (proxy->priv->proxy_http_settings, "host");
else
res = g_settings_get_string (proxy->priv->evolution_proxy_settings, "http-host");
break;
case E_PROXY_KEY_HTTPS_HOST:
if (proxy->priv->type == PROXY_TYPE_SYSTEM)
res = g_settings_get_string (proxy->priv->proxy_https_settings, "host");
else
res = g_settings_get_string (proxy->priv->evolution_proxy_settings, "secure-host");
break;
case E_PROXY_KEY_SOCKS_HOST:
if (proxy->priv->type == PROXY_TYPE_SYSTEM)
res = g_settings_get_string (proxy->priv->proxy_socks_settings, "host");
else
res = g_settings_get_string (proxy->priv->evolution_proxy_settings, "socks-host");
break;
case E_PROXY_KEY_HTTP_AUTH_USER:
if (proxy->priv->type == PROXY_TYPE_SYSTEM)
res = g_settings_get_string (proxy->priv->proxy_http_settings, "authentication-user");
else
res = g_settings_get_string (proxy->priv->evolution_proxy_settings, "authentication-user");
break;
case E_PROXY_KEY_HTTP_AUTH_PWD:
if (proxy->priv->type == PROXY_TYPE_SYSTEM)
res = g_settings_get_string (proxy->priv->proxy_http_settings, "authentication-password");
else
res = g_settings_get_string (proxy->priv->evolution_proxy_settings, "authentication-password");
break;
case E_PROXY_KEY_AUTOCONFIG_URL:
if (proxy->priv->type == PROXY_TYPE_SYSTEM)
res = g_settings_get_string (proxy->priv->proxy_settings, "autoconfig-url");
else
res = g_settings_get_string (proxy->priv->evolution_proxy_settings, "autoconfig-url");
break;
default:
g_warn_if_reached ();
break;
}
return res;
}
/* list of newly allocated strings, use g_free() for each member and free list itself too */
static GSList *
ep_read_key_list (EProxy *proxy,
EProxyKey key)
{
GSList *res = NULL;
gchar **strv = NULL;
g_return_val_if_fail (E_IS_PROXY (proxy), NULL);
switch (key) {
case E_PROXY_KEY_HTTP_IGNORE_HOSTS:
if (proxy->priv->type == PROXY_TYPE_SYSTEM)
strv = g_settings_get_strv (proxy->priv->proxy_settings, "ignore-hosts");
else
strv = g_settings_get_strv (proxy->priv->evolution_proxy_settings, "ignore-hosts");
break;
default:
g_warn_if_reached ();
break;
}
if (strv) {
gint ii;
for (ii = 0; strv && strv[ii]; ii++) {
res = g_slist_prepend (res, g_strdup (strv[ii]));
}
g_strfreev (strv);
res = g_slist_reverse (res);
}
return res;
}
static gboolean
ep_is_in_ignored (EProxy *proxy,
const gchar *host)
{
EProxyPrivate *priv;
GSList * l;
gchar *hn;
g_return_val_if_fail (proxy != NULL, FALSE);
g_return_val_if_fail (host != NULL, FALSE);
priv = proxy->priv;
if (!priv->ign_hosts)
return FALSE;
hn = g_ascii_strdown (host, -1);
for (l = priv->ign_hosts; l; l = l->next) {
if (*((gchar *) l->data) == '*') {
if (g_str_has_suffix (hn, ((gchar *) l->data) + 1)) {
g_free (hn);
return TRUE;
}
} else if (strcmp (hn, l->data) == 0) {
g_free (hn);
return TRUE;
}
}
g_free (hn);
return FALSE;
}
static gboolean
ep_need_proxy_http (EProxy *proxy,
const gchar *host)
{
SoupAddress *addr = NULL;
EProxyPrivate *priv = proxy->priv;
ProxyHostAddr *p_addr = NULL;
GSList *l;
guint status;
/* check for ignored first */
if (ep_is_in_ignored (proxy, host))
return FALSE;
addr = soup_address_new (host, 0);
status = soup_address_resolve_sync (addr, NULL);
if (status == SOUP_STATUS_OK) {
gint addr_len;
struct sockaddr * so_addr = NULL;
so_addr = soup_address_get_sockaddr (addr, &addr_len);
/* This will never happen, since we have already called
* soup_address_resolve_sync ().
*/
if (!so_addr) {
g_object_unref (addr);
return TRUE;
}
if (so_addr->sa_family == AF_INET) {
struct in_addr in, *mask, *addr_in;
in = ((struct sockaddr_in *) so_addr)->sin_addr;
for (l = priv->ign_addrs; l; l = l->next) {
p_addr = (ProxyHostAddr *) l->data;
if (p_addr->type == PROXY_IPV4) {
addr_in = ((struct in_addr *) p_addr->addr);
mask = ((struct in_addr *) p_addr->mask);
if ((in.s_addr & mask->s_addr) == addr_in->s_addr) {
d (g_print ("Host [%s] doesn't require proxy\n", host));
g_object_unref (addr);
return FALSE;
}
}
}
} else {
struct in6_addr in6, net6;
struct in_addr *addr_in, *mask;
in6 = ((struct sockaddr_in6 *) so_addr)->sin6_addr;
for (l = priv->ign_addrs; l; l = l->next) {
p_addr = (ProxyHostAddr *) l->data;
ipv6_network_addr (&in6, (struct in6_addr *) p_addr->mask, &net6);
if (p_addr->type == PROXY_IPV6) {
if (IN6_ARE_ADDR_EQUAL (&net6, (struct in6_addr *) p_addr->addr)) {
d (g_print ("Host [%s] doesn't require proxy\n", host));
g_object_unref (addr);
return FALSE;
}
} else if (p_addr->type == PROXY_IPV6 &&
IN6_IS_ADDR_V4MAPPED (&net6)) {
guint32 v4addr;
addr_in = ((struct in_addr *) p_addr->addr);
mask = ((struct in_addr *) p_addr->mask);
v4addr = net6.s6_addr[12] << 24
| net6.s6_addr[13] << 16
| net6.s6_addr[14] << 8
| net6.s6_addr[15];
if ((v4addr & mask->s_addr) != addr_in->s_addr) {
d (g_print ("Host [%s] doesn't require proxy\n", host));
g_object_unref (addr);
return FALSE;
}
}
}
}
}
d (g_print ("%s needs a proxy to connect to internet\n", host));
g_object_unref (addr);
return TRUE;
}
static gboolean
ep_need_proxy_https (EProxy *proxy,
const gchar *host)
{
/* Can we share ignore list from HTTP at all? */
return !ep_is_in_ignored (proxy, host);
}
static gboolean
ep_need_proxy_socks (EProxy *proxy,
const gchar *host)
{
/* Can we share ignore list from HTTP at all? */
return !ep_is_in_ignored (proxy, host);
}
/* Apply a prefix-notation @netmask to the given @addr_in, as described in
* http://tools.ietf.org/html/rfc4632#section-3.1 */
static gboolean
ep_manipulate_ipv4 (ProxyHostAddr *host_addr,
struct in_addr *addr_in,
gchar *netmask)
{
gboolean has_error = FALSE;
struct in_addr *addr, *mask;
if (!addr_in)
return has_error;
host_addr->type = PROXY_IPV4;
addr = g_new0 (struct in_addr, 1);
memcpy (addr, addr_in, sizeof (struct in_addr));
mask = g_new0 (struct in_addr, 1);
if (netmask) {
gchar *endptr;
gint width = strtol (netmask, &endptr, 10);
if (*endptr != '\0' || width < 0 || width > 32) {
has_error = TRUE;
mask->s_addr = 0xFFFFFFFF;
} else if (width == 32) {
mask->s_addr = 0;
addr->s_addr = 0;
} else {
mask->s_addr = htonl (~0 << width);
addr->s_addr &= mask->s_addr;
}
} else {
mask->s_addr = 0xFFFFFFFF;
}
host_addr->addr = addr;
host_addr->mask = mask;
return has_error;
}
static void
ipv6_network_addr (const struct in6_addr *addr,
const struct in6_addr *mask,
struct in6_addr *res)
{
gint i;
for (i = 0; i < 16; ++i) {
res->s6_addr[i] = addr->s6_addr[i] & mask->s6_addr[i];
}
}
static gboolean
ep_manipulate_ipv6 (ProxyHostAddr *host_addr,
struct in6_addr *addr_in6,
gchar *netmask)
{
gboolean has_error = FALSE;
struct in6_addr *addr, *mask;
gint i;
if (!addr_in6)
return has_error;
host_addr->type = PROXY_IPV6;
addr = g_new0 (struct in6_addr, 1);
mask = g_new0 (struct in6_addr, 1);
for (i = 0; i < 16; ++i) {
addr->s6_addr[i] = addr_in6->s6_addr[i];
}
if (netmask) {
gchar *endptr;
gint width = strtol (netmask, &endptr, 10);
if (*endptr != '\0' || width < 0 || width > 128) {
has_error = TRUE;
}
for (i = 0; i < 16; ++i) {
mask->s6_addr[i] = 0;
}
for (i = 0; i < width / 8; i++) {
mask->s6_addr[i] = 0xff;
}
mask->s6_addr[i] = (0xff << (8 - width % 8)) & 0xff;
ipv6_network_addr (addr, mask, addr);
} else {
for (i = 0; i < 16; ++i) {
mask->s6_addr[i] = 0xff;
}
}
host_addr->addr = addr;
host_addr->mask = mask;
return has_error;
}
static void
ep_parse_ignore_host (gpointer data,
gpointer user_data)
{
EProxy * proxy = (EProxy *) user_data;
EProxyPrivate * priv = NULL;
SoupAddress *addr;
guint status;
gchar *input, *netmask, *hostname;
ProxyHostAddr *host_addr;
gboolean has_error = FALSE;
if (!proxy || !proxy->priv)
return;
priv = proxy->priv;
input = (gchar *) data;
if ((netmask = strrchr (input, '/')) != NULL) {
hostname = g_strndup (input, netmask - input);
++netmask;
} else {
hostname = g_ascii_strdown (input, -1);
}
addr = soup_address_new (hostname, 0);
status = soup_address_resolve_sync (addr, NULL);
if (status == SOUP_STATUS_OK) {
gint addr_len;
struct sockaddr * so_addr = NULL;
host_addr = g_new0 (ProxyHostAddr, 1);
so_addr = soup_address_get_sockaddr (addr, &addr_len);
/* This will never happen, since we have already called
* soup_address_resolve_sync ().
*/
if (!so_addr)
goto error;
if (so_addr->sa_family == AF_INET)
has_error = ep_manipulate_ipv4 (
host_addr,
&((struct sockaddr_in *) so_addr)->sin_addr,
netmask);
else
has_error = ep_manipulate_ipv6 (
host_addr,
&((struct sockaddr_in6 *) so_addr)->sin6_addr,
netmask);
if (!has_error) {
priv->ign_addrs = g_slist_append (
priv->ign_addrs, host_addr);
priv->ign_hosts = g_slist_append (
priv->ign_hosts, hostname);
} else {
g_free (hostname);
}
} else {
d (g_print ("Unable to resolve %s\n", hostname));
priv->ign_hosts = g_slist_append (priv->ign_hosts, hostname);
}
error:
g_object_unref (addr);
}
static gboolean
ep_change_uri (SoupURI **soup_uri,
const gchar *uri)
{
gboolean changed = FALSE;
g_return_val_if_fail (soup_uri != NULL, FALSE);
if (!uri || !*uri) {
if (*soup_uri) {
soup_uri_free (*soup_uri);
*soup_uri = NULL;
changed = TRUE;
}
} else if (*soup_uri) {
gchar *old = soup_uri_to_string (*soup_uri, FALSE);
if (old && *old) {
gint len = strlen (old);
/* remove ending slash, if there */
if (old[len - 1] == '/')
old[len - 1] = 0;
}
changed = old && uri && g_ascii_strcasecmp (old, uri) != 0;
if (changed) {
soup_uri_free (*soup_uri);
*soup_uri = soup_uri_new (uri);
}
g_free (old);
} else {
*soup_uri = soup_uri_new (uri);
changed = TRUE;
}
return changed;
}
static gchar *
update_proxy_uri (const gchar *uri,
const gchar *proxy_user,
const gchar *proxy_pw)
{
gchar *res, *user = NULL, *pw = NULL;
gboolean is_https;
g_return_val_if_fail (uri != NULL, NULL);
if (proxy_user && *proxy_user) {
user = soup_uri_encode (proxy_user, ":/;#@?\\");
if (proxy_pw)
pw = soup_uri_encode (proxy_pw, ":/;#@?\\");
}
if (!user)
return g_strdup (uri);
/* here can be only http or https and nothing else */
is_https = g_str_has_prefix (uri, "https://");
res = g_strdup_printf (
"%s://%s%s%s@%s",
is_https ? "https" : "http",
user,
pw ? ":" : "",
pw ? pw : "",
uri + strlen ("http://") + (is_https ? 1 : 0));
g_free (user);
g_free (pw);
return res;
}
static void
ep_set_proxy (EProxy *proxy,
gboolean regen_ign_host_list)
{
gchar *proxy_server, *uri_http = NULL, *uri_https = NULL, *uri_socks = NULL;
gint proxy_port, old_type;
EProxyPrivate * priv = proxy->priv;
GSList *ignore;
gboolean changed = FALSE, sys_manual = TRUE;
old_type = priv->type;
priv->type = g_settings_get_int (priv->evolution_proxy_settings, "proxy-type");
if (priv->type > PROXY_TYPE_AUTO_URL)
priv->type = PROXY_TYPE_SYSTEM;
changed = priv->type != old_type;
if (priv->type == PROXY_TYPE_SYSTEM) {
gchar *mode = ep_read_key_string (proxy, E_PROXY_KEY_MODE);
/* supporting only manual system proxy setting */
sys_manual = mode && g_str_equal (mode, "manual");
g_free (mode);
}
priv->use_proxy = ep_read_key_boolean (proxy, E_PROXY_KEY_USE_HTTP_PROXY);
if (!priv->use_proxy || priv->type == PROXY_TYPE_NO_PROXY || !sys_manual) {
changed = ep_change_uri (&priv->uri_http, NULL) || changed;
changed = ep_change_uri (&priv->uri_https, NULL) || changed;
changed = ep_change_uri (&priv->uri_socks, NULL) || changed;
goto emit_signal;
}
proxy_server = ep_read_key_string (proxy, E_PROXY_KEY_HTTP_HOST);
proxy_port = ep_read_key_int (proxy, E_PROXY_KEY_HTTP_PORT);
if (proxy_server != NULL && *proxy_server && !g_ascii_isspace (*proxy_server)) {
if (proxy_port > 0)
uri_http = g_strdup_printf ("http://%s:%d", proxy_server, proxy_port);
else
uri_http = g_strdup_printf ("http://%s", proxy_server);
} else
uri_http = NULL;
g_free (proxy_server);
d (g_print ("ep_set_proxy: uri_http: %s\n", uri_http));
proxy_server = ep_read_key_string (proxy, E_PROXY_KEY_HTTPS_HOST);
proxy_port = ep_read_key_int (proxy, E_PROXY_KEY_HTTPS_PORT);
if (proxy_server != NULL && *proxy_server && !g_ascii_isspace (*proxy_server)) {
if (proxy_port > 0)
uri_https = g_strdup_printf ("https://%s:%d", proxy_server, proxy_port);
else
uri_https = g_strdup_printf ("https://%s", proxy_server);
} else
uri_https = NULL;
g_free (proxy_server);
d (g_print ("ep_set_proxy: uri_https: %s\n", uri_https));
proxy_server = ep_read_key_string (proxy, E_PROXY_KEY_SOCKS_HOST);
proxy_port = ep_read_key_int (proxy, E_PROXY_KEY_SOCKS_PORT);
if (proxy_server != NULL && *proxy_server && !g_ascii_isspace (*proxy_server)) {
if (proxy_port > 0)
uri_socks = g_strdup_printf ("socks://%s:%d", proxy_server, proxy_port);
else
uri_socks = g_strdup_printf ("socks://%s", proxy_server);
} else
uri_socks = NULL;
g_free (proxy_server);
d (g_print ("ep_set_proxy: uri_socks: %s\n", uri_socks));
if (regen_ign_host_list) {
if (priv->ign_hosts) {
g_slist_foreach (priv->ign_hosts, (GFunc) g_free, NULL);
g_slist_free (priv->ign_hosts);
priv->ign_hosts = NULL;
}
if (priv->ign_addrs) {
g_slist_foreach (priv->ign_addrs, (GFunc) ep_free_proxy_host_addr, NULL);
g_slist_free (priv->ign_addrs);
priv->ign_addrs = NULL;
}
ignore = ep_read_key_list (proxy, E_PROXY_KEY_HTTP_IGNORE_HOSTS);
if (ignore) {
g_slist_foreach (ignore, (GFunc) ep_parse_ignore_host, proxy);
g_slist_foreach (ignore, (GFunc) g_free, NULL);
g_slist_free (ignore);
}
}
if (ep_read_key_boolean (proxy, E_PROXY_KEY_HTTP_USE_AUTH)) {
gchar *proxy_user, *proxy_pw, *tmp = NULL, *tmps = NULL;
proxy_user = ep_read_key_string (proxy, E_PROXY_KEY_HTTP_AUTH_USER);
proxy_pw = ep_read_key_string (proxy, E_PROXY_KEY_HTTP_AUTH_PWD);
if (uri_http && proxy_user && *proxy_user) {
tmp = uri_http;
uri_http = update_proxy_uri (uri_http, proxy_user, proxy_pw);
}
if (uri_https && proxy_user && *proxy_user) {
tmps = uri_https;
uri_https = update_proxy_uri (uri_https, proxy_user, proxy_pw);
}
g_free (proxy_user);
g_free (proxy_pw);
g_free (tmp);
g_free (tmps);
}
changed = ep_change_uri (&priv->uri_http, uri_http) || changed;
changed = ep_change_uri (&priv->uri_https, uri_https) || changed;
changed = ep_change_uri (&priv->uri_socks, uri_socks) || changed;
emit_signal:
d (g_print (
"%s: changed:%d "
"uri_http: %s; "
"uri_https: %s; "
"uri_socks: %s\n",
G_STRFUNC, changed ? 1 : 0,
uri_http ? uri_http : "[null]",
uri_https ? uri_https : "[null]",
uri_socks ? uri_socks : "[null]"));
if (changed)
g_signal_emit (proxy, signals[CHANGED], 0);
g_free (uri_http);
g_free (uri_https);
g_free (uri_socks);
}
static void
ep_evo_proxy_changed_cb (GSettings *settings,
const gchar *key,
EProxy *proxy)
{
EProxyPrivate *priv;
g_return_if_fail (E_IS_PROXY (proxy));
priv = proxy->priv;
d (g_print ("%s: proxy settings changed, key '%s'\n", G_STRFUNC, key ? key : "NULL"));
if (g_strcmp0 (key, "proxy-type") == 0) {
ep_set_proxy (proxy, TRUE);
} else if (priv->type == PROXY_TYPE_SYSTEM) {
return;
}
ep_set_proxy (proxy, g_strcmp0 (key, "ignore-hosts") == 0);
}
static void
ep_sys_proxy_changed_cb (GSettings *settings,
const gchar *key,
EProxy *proxy)
{
g_return_if_fail (proxy != NULL);
if (proxy->priv->type != PROXY_TYPE_SYSTEM)
return;
ep_set_proxy (proxy, g_strcmp0 (key, "ignore-hosts") == 0);
}
static void
ep_sys_proxy_http_changed_cb (GSettings *settings,
const gchar *key,
EProxy *proxy)
{
g_return_if_fail (proxy != NULL);
if (proxy->priv->type != PROXY_TYPE_SYSTEM)
return;
ep_set_proxy (proxy, FALSE);
}
static void
ep_sys_proxy_https_changed_cb (GSettings *settings,
const gchar *key,
EProxy *proxy)
{
g_return_if_fail (proxy != NULL);
if (proxy->priv->type != PROXY_TYPE_SYSTEM)
return;
ep_set_proxy (proxy, FALSE);
}
static void
ep_sys_proxy_socks_changed_cb (GSettings *settings,
const gchar *key,
EProxy *proxy)
{
g_return_if_fail (proxy != NULL);
if (proxy->priv->type != PROXY_TYPE_SYSTEM)
return;
ep_set_proxy (proxy, FALSE);
}
static void
e_proxy_dispose (GObject *object)
{
EProxy *proxy;
EProxyPrivate *priv;
proxy = E_PROXY (object);
priv = proxy->priv;
if (priv->evolution_proxy_settings) {
g_signal_handlers_disconnect_by_func (priv->evolution_proxy_settings, ep_evo_proxy_changed_cb, proxy);
g_object_unref (priv->evolution_proxy_settings);
priv->evolution_proxy_settings = NULL;
}
if (priv->proxy_settings) {
g_signal_handlers_disconnect_by_func (priv->proxy_settings, ep_sys_proxy_changed_cb, proxy);
g_object_unref (priv->proxy_settings);
priv->proxy_settings = NULL;
}
if (priv->proxy_http_settings) {
g_signal_handlers_disconnect_by_func (priv->proxy_http_settings, ep_sys_proxy_http_changed_cb, proxy);
g_object_unref (priv->proxy_http_settings);
priv->proxy_http_settings = NULL;
}
if (priv->proxy_https_settings) {
g_signal_handlers_disconnect_by_func (priv->proxy_https_settings, ep_sys_proxy_https_changed_cb, proxy);
g_object_unref (priv->proxy_https_settings);
priv->proxy_https_settings = NULL;
}
if (priv->proxy_socks_settings) {
g_signal_handlers_disconnect_by_func (priv->proxy_socks_settings, ep_sys_proxy_socks_changed_cb, proxy);
g_object_unref (priv->proxy_socks_settings);
priv->proxy_socks_settings = NULL;
}
if (priv->uri_http)
soup_uri_free (priv->uri_http);
if (priv->uri_https)
soup_uri_free (priv->uri_https);
if (priv->uri_socks)
soup_uri_free (priv->uri_socks);
g_slist_foreach (priv->ign_hosts, (GFunc) g_free, NULL);
g_slist_free (priv->ign_hosts);
g_slist_foreach (priv->ign_addrs, (GFunc) ep_free_proxy_host_addr, NULL);
g_slist_free (priv->ign_addrs);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_proxy_parent_class)->dispose (object);
}
static void
e_proxy_class_init (EProxyClass *class)
{
GObjectClass *object_class;
g_type_class_add_private (class, sizeof (EProxyPrivate));
object_class = G_OBJECT_CLASS (class);
object_class->dispose = e_proxy_dispose;
/**
* EProxy::changed:
* @proxy: the #EProxy which emitted the signal
*
* Emitted when proxy settings changes.
**/
signals[CHANGED] = g_signal_new (
"changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (EProxyClass, changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void
e_proxy_init (EProxy *proxy)
{
proxy->priv = E_PROXY_GET_PRIVATE (proxy);
proxy->priv->type = PROXY_TYPE_SYSTEM;
proxy->priv->evolution_proxy_settings = g_settings_new ("org.gnome.evolution.shell.network-config");
proxy->priv->proxy_settings = g_settings_new ("org.gnome.system.proxy");
proxy->priv->proxy_http_settings = g_settings_get_child (proxy->priv->proxy_settings, "http");
proxy->priv->proxy_https_settings = g_settings_get_child (proxy->priv->proxy_settings, "https");
proxy->priv->proxy_socks_settings = g_settings_get_child (proxy->priv->proxy_settings, "socks");
g_signal_connect (proxy->priv->evolution_proxy_settings, "changed", G_CALLBACK (ep_evo_proxy_changed_cb), proxy);
g_signal_connect (proxy->priv->proxy_settings, "changed", G_CALLBACK (ep_sys_proxy_changed_cb), proxy);
g_signal_connect (proxy->priv->proxy_http_settings, "changed", G_CALLBACK (ep_sys_proxy_http_changed_cb), proxy);
g_signal_connect (proxy->priv->proxy_https_settings, "changed", G_CALLBACK (ep_sys_proxy_https_changed_cb), proxy);
g_signal_connect (proxy->priv->proxy_socks_settings, "changed", G_CALLBACK (ep_sys_proxy_socks_changed_cb), proxy);
}
/**
* e_proxy_new:
*
* Since: 2.24
**/
EProxy *
e_proxy_new (void)
{
return g_object_new (E_TYPE_PROXY, NULL);
}
/**
* e_proxy_setup_proxy:
*
* Since: 2.24
**/
void
e_proxy_setup_proxy (EProxy *proxy)
{
g_return_if_fail (E_IS_PROXY (proxy));
/* We get the evolution-shell proxy keys here
* set soup up to use the proxy,
* and listen to any changes */
/* XXX Why can't we do this automatically in constructed() ? */
ep_set_proxy (proxy, TRUE);
}
/**
* e_proxy_peek_uri_for:
*
* Since: 2.26
**/
SoupURI *
e_proxy_peek_uri_for (EProxy *proxy,
const gchar *uri)
{
SoupURI *res = NULL;
SoupURI *soup_uri;
g_return_val_if_fail (E_IS_PROXY (proxy), NULL);
g_return_val_if_fail (uri != NULL, NULL);
soup_uri = soup_uri_new (uri);
if (soup_uri == NULL)
return NULL;
if (soup_uri->scheme == SOUP_URI_SCHEME_HTTP)
res = proxy->priv->uri_http;
else if (soup_uri->scheme == SOUP_URI_SCHEME_HTTPS)
res = proxy->priv->uri_https;
else if (soup_uri->scheme && g_ascii_strcasecmp (soup_uri->scheme, "socks") == 0)
res = proxy->priv->uri_socks;
soup_uri_free (soup_uri);
return res;
}
/**
* e_proxy_require_proxy_for_uri:
*
* Since: 2.24
**/
gboolean
e_proxy_require_proxy_for_uri (EProxy *proxy,
const gchar *uri)
{
SoupURI *soup_uri = NULL;
gboolean need_proxy = FALSE;
g_return_val_if_fail (E_IS_PROXY (proxy), FALSE);
g_return_val_if_fail (uri != NULL, FALSE);
if (!proxy->priv->use_proxy || proxy->priv->type == PROXY_TYPE_NO_PROXY) {
d (g_print ("[%s] don't need a proxy to connect to internet\n", uri));
return FALSE;
}
soup_uri = soup_uri_new (uri);
if (soup_uri == NULL)
return FALSE;
if (soup_uri->scheme == SOUP_URI_SCHEME_HTTP)
need_proxy = ep_need_proxy_http (proxy, soup_uri->host);
else if (soup_uri->scheme == SOUP_URI_SCHEME_HTTPS)
need_proxy = ep_need_proxy_https (proxy, soup_uri->host);
else if (soup_uri->scheme && g_ascii_strcasecmp (soup_uri->scheme, "socks") == 0)
need_proxy = ep_need_proxy_socks (proxy, soup_uri->host);
soup_uri_free (soup_uri);
return need_proxy;
}