evolution-data-server/bnc-174255-honour-system-proxy-settings.patch

990 lines
26 KiB
Diff

--- libedataserver/Makefile.am
+++ libedataserver/Makefile.am
@@ -7,7 +7,8 @@
-DE_DATA_SERVER_EXTENSIONDIR=\"$(extensiondir)\" \
-DE_DATA_SERVER_IMAGESDIR=\"$(imagesdir)\" \
-DE_DATA_SERVER_UI_GLADEDIR=\""$(gladedir)"\" \
- $(E_DATA_SERVER_CFLAGS)
+ $(E_DATA_SERVER_CFLAGS) \
+ $(SOUP_CFLAGS)
# The marshallers
MARSHAL_GENERATED = e-data-server-marshal.c e-data-server-marshal.h
@@ -32,6 +33,7 @@
e-list-iterator.c \
e-memory.c \
e-msgport.c \
+ e-proxy.c \
e-sexp.c \
e-source-group.c \
e-source-list.c \
@@ -50,7 +52,8 @@
$(E_DATA_SERVER_LIBS) \
$(ICONV_LIBS) \
$(DB_LIBS) \
- $(SOCKET_LIBS)
+ $(SOCKET_LIBS) \
+ $(SOUP_LIBS)
libedataserver_1_2_la_LDFLAGS = \
-version-info $(LIBEDATASERVER_CURRENT):$(LIBEDATASERVER_REVISION):$(LIBEDATASERVER_AGE) $(NO_UNDEFINED)
@@ -72,6 +75,7 @@
e-list-iterator.h \
e-memory.h \
e-msgport.h \
+ e-proxy.h \
e-sexp.h \
e-source-group.h \
e-source-list.h \
--- libedataserver/e-proxy.c
+++ libedataserver/e-proxy.c
@@ -0,0 +1,647 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ * Veerapuram Varadhan <vvaradhan@novell.com>
+ *
+ * Copyright 2002 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#include <libsoup/soup-address.h>
+#include <libsoup/soup-uri.h>
+#include "e-proxy.h"
+
+/* Debug */
+#define d(x)
+
+/* GConf paths and keys */
+#define PATH_GCONF_GNOME_VFS "/system/http_proxy"
+#define KEY_GCONF_HTTP_PROXY_PORT (PATH_GCONF_GNOME_VFS "/" "port")
+#define KEY_GCONF_HTTP_PROXY_HOST (PATH_GCONF_GNOME_VFS "/" "host")
+
+#define KEY_GCONF_USE_HTTP_PROXY (PATH_GCONF_GNOME_VFS "/" "use_http_proxy")
+
+#define KEY_GCONF_HTTP_AUTH_USER (PATH_GCONF_GNOME_VFS "/" "authentication_user")
+#define KEY_GCONF_HTTP_AUTH_PW (PATH_GCONF_GNOME_VFS "/" "authentication_password")
+#define KEY_GCONF_HTTP_USE_AUTH (PATH_GCONF_GNOME_VFS "/" "use_authentication")
+
+#define KEY_GCONF_HTTP_PROXY_IGNORE_HOSTS (PATH_GCONF_GNOME_VFS "/" "ignore_hosts")
+
+struct _EProxyPrivate {
+ SoupUri* uri;
+ guint notify_id; /* conxn id of gconf_client_notify_add */
+ GSList* ign_hosts; /* List of hostnames. (Strings) */
+ GSList* ign_addrs; /* List of hostaddrs. (ProxyHostAddrs) */
+ gboolean use_proxy; /* Is system-proxy enabled? */
+};
+
+/* 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 */
+ void* addr; /* Either in_addr* or in6_addr* */
+ void* mask; /* Either in_addr* or in6_addr* */
+} ProxyHostAddr;
+
+/* Signals. */
+enum {
+ CHANGED,
+ LAST_SIGNAL
+};
+
+static GObjectClass *parent_class;
+static unsigned int signals[LAST_SIGNAL] = { 0 };
+
+/* Forward declarations. */
+
+static void ep_setting_changed (GConfClient *client, guint32 cnxn_id,
+ GConfEntry *entry, gpointer user_data);
+static void e_proxy_dispose (GObject* object);
+
+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 void
+e_proxy_class_init (EProxyClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->dispose = e_proxy_dispose;
+
+ /* signals */
+
+ /**
+ * EProxy::changed:
+ * @proxy: the proxy
+ *
+ * Emitted when proxy settings in gconf changes.
+ **/
+ signals[CHANGED] =
+ g_signal_new ("changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EProxyClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+
+}
+
+static void
+e_proxy_init (EProxy *pxy, EProxyClass *klass)
+{
+ EProxyPrivate *priv;
+
+ /* allocate internal structure */
+ priv = g_new0 (EProxyPrivate, 1);
+ pxy->priv = priv;
+ priv->ign_hosts = NULL;
+ priv->ign_addrs = NULL;
+ priv->uri = NULL;
+ priv->notify_id = 0;
+ priv->use_proxy = FALSE;
+}
+
+static void
+e_proxy_dispose (GObject *object)
+{
+ EProxy *proxy = (EProxy *)object;
+
+ if (!E_IS_PROXY (proxy))
+ return;
+
+ EProxyPrivate *priv = proxy->priv;
+
+ if (priv) {
+ GConfClient* client = NULL;
+
+ if ((client = gconf_client_get_default ())) {
+ if (priv->notify_id > 0)
+ gconf_client_notify_remove (client, priv->notify_id);
+ g_object_unref (client);
+ }
+
+ if (priv->uri)
+ soup_uri_free (priv->uri);
+
+ if (priv->ign_hosts) {
+ g_slist_foreach (priv->ign_hosts, (GFunc) ep_free_proxy_host_addr, NULL);
+ g_slist_free (priv->ign_hosts);
+ }
+
+ if (priv->ign_addrs) {
+ g_slist_foreach (priv->ign_addrs, (GFunc) g_free, NULL);
+ g_slist_free (priv->ign_addrs);
+ }
+
+ priv->notify_id = 0;
+
+ g_free (priv);
+ priv = NULL;
+ }
+}
+
+GType
+e_proxy_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static GTypeInfo info = {
+ sizeof (EProxyClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) e_proxy_class_init,
+ NULL, NULL,
+ sizeof (EProxy),
+ 0,
+ (GInstanceInitFunc) e_proxy_init
+ };
+ type = g_type_register_static (G_TYPE_OBJECT, "EProxy", &info, 0);
+ }
+
+ return type;
+}
+
+static gboolean
+ep_need_proxy (EProxy* proxy, const char* host)
+{
+ SoupAddress *addr = NULL;
+ EProxyPrivate *priv = proxy->priv;
+ ProxyHostAddr *p_addr = NULL;
+ GSList *l;
+ guint status;
+
+ addr = soup_address_new (host, 0);
+ status = soup_address_resolve_sync (addr);
+ if (status == SOUP_STATUS_OK) {
+ gint addr_len;
+ struct sockaddr* s_addr = NULL;
+
+ s_addr = soup_address_get_sockaddr (addr, &addr_len);
+
+ /* This will never happen, since we have already called
+ soup_address_resolve_sync().
+ */
+ if (!s_addr)
+ return TRUE;
+
+ if (s_addr->sa_family == AF_INET) {
+ struct in_addr in, *mask, *addr_in;
+
+ in = ((struct sockaddr_in *)s_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);
+ d(g_print ("ep_need_proxy:ipv4: in: %ul\t mask: %ul\t addr: %ul\n",
+ in.s_addr, mask->s_addr, addr_in->s_addr));
+ if ((in.s_addr & mask->s_addr) == addr_in->s_addr) {
+ d(g_print ("Host [%s] doesn't require proxy\n", host));
+ return FALSE;
+ }
+ }
+ }
+ } else {
+ struct in6_addr in6, net6;
+ struct in_addr *addr_in, *mask;
+
+ in6 = ((struct sockaddr_in6 *)s_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));
+ 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));
+ return FALSE;
+ }
+ }
+ }
+ }
+ } else {
+ GSList* l;
+ gchar* 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 FALSE;
+ }
+ } else if (strcmp (hn, l->data) == 0) {
+ g_free (hn);
+ return FALSE;
+ }
+ }
+ g_free (hn);
+ }
+
+ d(g_print ("%s needs a proxy to connect to internet\n", host));
+ return TRUE;
+}
+
+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 = htonl (~0 << width);
+ addr->s_addr &= mask->s_addr;
+ } else {
+ mask->s_addr = 0xFFFFFFFF;
+ }
+
+ d(g_print ("ep_manipulate_ipv4: addr_in: %ul, addr: %ul, mask: %ul\n",
+ addr_in->s_addr, addr->s_addr, mask->s_addr));
+
+ 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;
+ int 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);
+ if (status == SOUP_STATUS_OK) {
+ gint addr_len;
+ struct sockaddr* s_addr = NULL;
+
+ host_addr = g_new0 (ProxyHostAddr, 1);
+
+ s_addr = soup_address_get_sockaddr (addr, &addr_len);
+
+ /* This will never happen, since we have already called
+ soup_address_resolve_sync().
+ */
+ if (!s_addr)
+ goto error;
+
+ if (s_addr->sa_family == AF_INET)
+ has_error = ep_manipulate_ipv4 (host_addr,
+ &((struct sockaddr_in *)s_addr)->sin_addr,
+ netmask);
+ else
+ has_error = ep_manipulate_ipv6 (host_addr,
+ &((struct sockaddr_in6 *)s_addr)->sin6_addr,
+ netmask);
+
+ if (!has_error)
+ priv->ign_addrs = g_slist_append (priv->ign_addrs, host_addr);
+
+ 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 void
+ep_set_proxy (GConfClient *client,
+ gpointer user_data,
+ gboolean regen_ign_host_list,
+ gboolean set_auth)
+{
+ char *proxy_server = NULL, *proxy_user = NULL, *proxy_pw = NULL, *uri = NULL;
+ gboolean use_auth;
+ int proxy_port;
+ EProxy* proxy = (EProxy *)user_data;
+ EProxyPrivate* priv = proxy->priv;
+ GSList *ignore;
+
+ priv->use_proxy = gconf_client_get_bool (client, KEY_GCONF_USE_HTTP_PROXY, NULL);
+ if (priv->use_proxy == FALSE) {
+ if (priv->uri) {
+ soup_uri_free (priv->uri);
+ priv->uri = NULL;
+ }
+ goto emit_signal;
+ }
+
+ proxy_server = gconf_client_get_string (client, KEY_GCONF_HTTP_PROXY_HOST, NULL);
+ proxy_port = gconf_client_get_int (client, KEY_GCONF_HTTP_PROXY_PORT, NULL);
+ uri = g_strdup_printf ("http://%s:%d", proxy_server, proxy_port);
+ d(g_print ("ep_set_proxy: uri: %s\n", uri));
+
+ 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) g_free, NULL);
+ g_slist_free (priv->ign_addrs);
+ priv->ign_addrs = NULL;
+ }
+
+ ignore = gconf_client_get_list (client, KEY_GCONF_HTTP_PROXY_IGNORE_HOSTS,
+ GCONF_VALUE_STRING, NULL);
+ if (ignore) {
+ g_slist_foreach (ignore, (GFunc) ep_parse_ignore_host, proxy);
+ g_slist_foreach (ignore, (GFunc) g_free, NULL);
+ g_slist_free (ignore);
+ }
+ } else if (set_auth) {
+
+ use_auth = gconf_client_get_bool (client, KEY_GCONF_HTTP_USE_AUTH, NULL);
+ if (use_auth == TRUE) {
+ proxy_user = gconf_client_get_string (client, KEY_GCONF_HTTP_AUTH_USER, NULL);
+ proxy_pw = gconf_client_get_string (client, KEY_GCONF_HTTP_AUTH_PW, NULL);
+
+ if (uri)
+ g_free (uri);
+
+ uri = g_strdup_printf ("http://%s:%s@%s:%d", proxy_user, proxy_pw, proxy_server, proxy_port);
+ }
+ }
+
+ if (priv->uri) {
+ soup_uri_free (priv->uri);
+ priv->uri = NULL;
+ }
+
+ if (uri)
+ priv->uri = soup_uri_new (uri);
+ d(g_print ("system-proxy: uri: %s\n", uri));
+
+ emit_signal:
+ g_signal_emit (proxy, signals[CHANGED], 0);
+
+ g_free (uri);
+
+ return;
+}
+
+static void
+ep_setting_changed (GConfClient *client, guint32 cnxn_id,
+ GConfEntry *entry, gpointer user_data)
+{
+ const char *key;
+ EProxy* proxy = (EProxy *)user_data;
+
+ if (!proxy || !proxy->priv)
+ return;
+
+ key = gconf_entry_get_key(entry);
+
+ if (strcmp(key, KEY_GCONF_USE_HTTP_PROXY) == 0
+ || strcmp(key, KEY_GCONF_HTTP_PROXY_IGNORE_HOSTS) == 0
+ || strcmp(key, KEY_GCONF_HTTP_PROXY_HOST) == 0
+ || strcmp(key, KEY_GCONF_HTTP_PROXY_PORT) == 0) {
+ gboolean regen_ign_host_list = FALSE;
+
+ if (strcmp(key, KEY_GCONF_HTTP_PROXY_IGNORE_HOSTS) == 0)
+ regen_ign_host_list = TRUE;
+ ep_set_proxy (client, user_data, regen_ign_host_list, FALSE);
+ d(g_print ("e-proxy.c:ep_settings_changed: proxy settings changed\n"));
+ } else if (strcmp(key, KEY_GCONF_HTTP_AUTH_USER) == 0
+ || strcmp(key, KEY_GCONF_HTTP_AUTH_PW) == 0
+ || strcmp(key, KEY_GCONF_HTTP_USE_AUTH) == 0) {
+ ep_set_proxy (client, user_data, FALSE, TRUE);
+ d(g_print ("e-proxy.c:ep_settings_changed: auth settings changed\n"));
+ }
+}
+
+EProxy*
+e_proxy_new (void)
+{
+ EProxy *proxy = NULL;
+
+ proxy = g_object_new (E_TYPE_PROXY, NULL);
+
+ return proxy;
+}
+
+void
+e_proxy_setup_proxy (EProxy* proxy)
+{
+ GConfClient *client;
+
+ /* We get the gnome-vfs proxy keys here
+ set soup up to use the proxy,
+ and listen to any changes */
+
+ if (!(client = gconf_client_get_default ()))
+ return;
+
+ if (!proxy || !proxy->priv)
+ return;
+
+ /* Listen to the changes in the gnome-vfs path */
+ gconf_client_add_dir (client, PATH_GCONF_GNOME_VFS,
+ GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+
+ if (proxy->priv->notify_id == 0)
+ proxy->priv->notify_id = gconf_client_notify_add (client, PATH_GCONF_GNOME_VFS,
+ ep_setting_changed, (gpointer)proxy,
+ NULL, NULL);
+
+ ep_set_proxy (client, proxy, TRUE, TRUE);
+
+ g_object_unref (client);
+}
+
+SoupUri*
+e_proxy_peek_uri (EProxy* proxy)
+{
+ if (!proxy || !proxy->priv)
+ return NULL;
+
+ return proxy->priv->uri;
+}
+
+gboolean
+e_proxy_require_proxy_for_uri (EProxy* proxy, const char* uri)
+{
+ SoupUri *srv_uri = NULL;
+ gboolean ret = FALSE;
+
+ if (!uri || !proxy || !proxy->priv)
+ return ret;
+
+ if (!proxy->priv->use_proxy) {
+ d(g_print ("[%s] don't need a proxy to connect to internet\n", uri));
+ return ret;
+ }
+
+ srv_uri = soup_uri_new (uri);
+
+ ret = ep_need_proxy (proxy, srv_uri->host);
+
+ soup_uri_free (srv_uri);
+
+ return ret;
+}
--- libedataserver/e-proxy.h
+++ libedataserver/e-proxy.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ * Veerapuram Varadhan <vvaradhan@novell.com>
+ *
+ * Copyright 2002 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef __E_PROXY_H__
+#define __E_PROXY_H__
+
+#include <libsoup/soup-uri.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_PROXY (e_proxy_get_type ())
+#define E_PROXY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_PROXY, EProxy))
+#define E_PROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_PROXY, EProxyClass))
+#define E_IS_PROXY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_PROXY))
+#define E_IS_PROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_PROXY))
+
+typedef struct _EProxy EProxy;
+typedef struct _EProxyClass EProxyClass;
+typedef struct _EProxyPrivate EProxyPrivate;
+
+struct _EProxy {
+ GObject parent;
+ EProxyPrivate *priv;
+};
+
+struct _EProxyClass {
+ GObjectClass parent_class;
+ /* Signals. */
+
+ void (*changed) (EProxy *proxy);
+};
+
+EProxy* e_proxy_new (void);
+SoupUri* e_proxy_peek_uri (EProxy* proxy);
+void e_proxy_setup_proxy (EProxy* proxy);
+GType e_proxy_get_type (void);
+gboolean e_proxy_require_proxy_for_uri (EProxy *proxy,
+ const char* uri);
+
+G_END_DECLS
+
+#endif
--- servers/exchange/lib/e2k-context.c
+++ servers/exchange/lib/e2k-context.c
@@ -49,6 +49,7 @@
#include "e2k-utils.h"
#include "e2k-xml-utils.h"
+#include <libedataserver/e-proxy.h>
#include <libsoup/soup-address.h>
#include <libsoup/soup-message-filter.h>
#include <libsoup/soup-session-async.h>
@@ -104,6 +105,7 @@
/* Forms-based authentication */
char *cookie;
gboolean cookie_verified;
+ EProxy* proxy;
};
/* For operations with progress */
@@ -113,6 +115,9 @@
/* For soup sync session timeout */
#define E2K_SOUP_SESSION_TIMEOUT 30
+/* Soup session proxy-uri property */
+#define SOUP_SESSION_PROXY_URI "proxy-uri"
+
#ifdef E2K_DEBUG
char *e2k_debug;
int e2k_debug_level;
@@ -123,6 +128,31 @@
static gboolean do_notification (GIOChannel *source, GIOCondition condition, gpointer data);
static void setup_message (SoupMessageFilter *filter, SoupMessage *msg);
+static void proxy_settings_changed (EProxy *proxy, gpointer user_data);
+
+
+static void
+proxy_settings_changed (EProxy *proxy, gpointer user_data)
+{
+ SoupUri *proxy_uri = NULL;
+ E2kContext* ctx = (E2kContext *)user_data;
+ if (!ctx || !ctx->priv ||
+ (!ctx->priv->session && !ctx->priv->async_session) ||
+ (!ctx->priv->owa_uri))
+ return;
+
+ if (!e_proxy_require_proxy_for_uri (proxy, ctx->priv->owa_uri))
+ proxy_uri = NULL;
+ else
+ proxy_uri = e_proxy_peek_uri (proxy);
+
+ if (ctx->priv->session)
+ g_object_set (ctx->priv->session, SOUP_SESSION_PROXY_URI,
+ proxy_uri, NULL);
+ if (ctx->priv->async_session)
+ g_object_set (ctx->priv->async_session, SOUP_SESSION_PROXY_URI,
+ proxy_uri, NULL);
+}
static void
init (GObject *object)
@@ -134,6 +164,9 @@
g_hash_table_new (g_str_hash, g_str_equal);
ctx->priv->subscriptions_by_uri =
g_hash_table_new (g_str_hash, g_str_equal);
+ ctx->priv->proxy = e_proxy_new ();
+ e_proxy_setup_proxy (ctx->priv->proxy);
+ g_signal_connect (ctx->priv->proxy, "changed", G_CALLBACK (proxy_settings_changed), ctx);
}
static void
@@ -180,8 +213,13 @@
g_free (ctx->priv->cookie);
+ if (ctx->priv->proxy) {
+ g_object_unref (ctx->priv->proxy);
+ ctx->priv->proxy = NULL;
+ }
g_free (ctx->priv);
ctx->priv = NULL;
+
}
G_OBJECT_CLASS (parent_class)->dispose (object);
@@ -361,6 +399,7 @@
const char *password)
{
guint timeout = E2K_SOUP_SESSION_TIMEOUT;
+ SoupUri* uri = NULL;
g_return_if_fail (E2K_IS_CONTEXT (ctx));
@@ -390,10 +429,15 @@
*/
if (g_getenv ("SOUP_SESSION_TIMEOUT"))
timeout = atoi (g_getenv ("SOUP_SESSION_TIMEOUT"));
-
+
+ /* Check do we need a proxy to contact the server? */
+ if (e_proxy_require_proxy_for_uri (ctx->priv->proxy, ctx->priv->owa_uri))
+ uri = e_proxy_peek_uri (ctx->priv->proxy);
+
ctx->priv->session = soup_session_sync_new_with_options (
SOUP_SESSION_USE_NTLM, !authmech || !strcmp (authmech, "NTLM"),
SOUP_SESSION_TIMEOUT, timeout,
+ SOUP_SESSION_PROXY_URI, uri,
NULL);
g_signal_connect (ctx->priv->session, "authenticate",
G_CALLBACK (session_authenticate), ctx);
@@ -402,7 +446,7 @@
ctx->priv->async_session = soup_session_async_new_with_options (
SOUP_SESSION_USE_NTLM, !authmech || !strcmp (authmech, "NTLM"),
- NULL);
+ SOUP_SESSION_PROXY_URI, uri, NULL);
g_signal_connect (ctx->priv->async_session, "authenticate",
G_CALLBACK (session_authenticate), ctx);
soup_session_add_filter (ctx->priv->async_session,
--- servers/groupwise/Makefile.am
+++ servers/groupwise/Makefile.am
@@ -15,9 +15,10 @@
$(E_DATA_SERVER_LIBS)
soap_test_SOURCES = soap-test.c
-soap_test_LDADD = \
- $(SOUP_LIBS) \
- libegroupwise-1.2.la \
+soap_test_LDADD = \
+ $(top_builddir)/libedataserver/libedataserver-1.2.la \
+ $(SOUP_LIBS) \
+ libegroupwise-1.2.la \
$(E_DATA_SERVER_LIBS)
lib_LTLIBRARIES = libegroupwise-1.2.la
--- servers/groupwise/e-gw-connection.c
+++ servers/groupwise/e-gw-connection.c
@@ -27,6 +27,7 @@
#include <string.h>
#include <ctype.h>
#include <glib/gi18n-lib.h>
+#include <libedataserver/e-proxy.h>
#include <libsoup/soup-session-sync.h>
#include <libsoup/soup-soap-message.h>
#include <libsoup/soup-misc.h>
@@ -37,6 +38,9 @@
/* For soup sync session timeout */
#define GW_SOUP_SESSION_TIMEOUT 30
+/* Soup session proxy-uri property */
+#define SOUP_SESSION_PROXY_URI "proxy-uri"
+
static GObjectClass *parent_class = NULL;
static GHashTable *loaded_connections_permissions = NULL;
@@ -57,8 +61,37 @@
GList *book_list;
EGwSendOptions *opts;
GMutex *reauth_mutex;
+ EProxy *proxy;
};
+static void
+update_soup_session_proxy_settings (EProxy *proxy, SoupSession* session,
+ const char* uri)
+{
+ SoupUri *proxy_uri = NULL;
+
+ if (!session || !uri || !proxy)
+ return;
+
+ if (e_proxy_require_proxy_for_uri (proxy, uri))
+ proxy_uri = e_proxy_peek_uri (proxy);
+
+ g_object_set (session, SOUP_SESSION_PROXY_URI,
+ proxy_uri, NULL);
+}
+
+static void
+proxy_settings_changed (EProxy *proxy, gpointer user_data)
+{
+ EGwConnection* conn = (EGwConnection *)user_data;
+ if (!conn || !conn->priv || !conn->priv->soup_session)
+ return;
+
+ update_soup_session_proxy_settings (proxy,
+ conn->priv->soup_session,
+ conn->priv->uri);
+}
+
static EGwConnectionStatus
reauthenticate (EGwConnection *cnc)
{
@@ -319,6 +352,11 @@
g_free (priv->server_time) ;
priv->server_time = NULL ;
}
+
+ if (priv->proxy) {
+ g_object_unref (priv->proxy);
+ priv->proxy = NULL;
+ }
}
if (parent_class->dispose)
@@ -369,6 +407,11 @@
*/
if (g_getenv ("SOUP_SESSION_TIMEOUT"))
timeout = atoi (g_getenv ("SOUP_SESSION_TIMEOUT"));
+
+ /* Initialize proxy settings */
+ priv->proxy = e_proxy_new ();
+ e_proxy_setup_proxy (priv->proxy);
+ g_signal_connect (priv->proxy, "changed", G_CALLBACK (proxy_settings_changed), cnc);
/* create the SoupSession for this connection */
priv->soup_session = soup_session_sync_new_with_options (SOUP_SESSION_TIMEOUT, timeout, NULL);
@@ -448,11 +491,17 @@
return cnc;
}
}
-
/* not found, so create a new connection */
cnc = g_object_new (E_TYPE_GW_CONNECTION, NULL);
+ /* Set proxy details for the Soup session before any
+ communication.
+ */
+ update_soup_session_proxy_settings (cnc->priv->proxy,
+ cnc->priv->soup_session,
+ uri);
+
msg = form_login_request (uri, username, password);
/* send message to server */