I#27 - [IMAPx] Ignore DavMail's CR/LF in BODYSTRUCTURE response
[evolution-data-server.git] / src / libedataserver / e-proxy.c
blob883379a60b28884baa0ec853717fda25fd00ba11
1 /*
2 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4 * This library is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 * Authors: Jeffrey Stedfast <fejj@ximian.com>
17 * Veerapuram Varadhan <vvaradhan@novell.com>
20 #include "evolution-data-server-config.h"
22 #include <string.h>
23 #include <stdlib.h>
25 #ifdef _WIN32
26 #include <winsock2.h>
27 #include <ws2tcpip.h>
28 #ifndef IN6_ARE_ADDR_EQUAL
29 #define IN6_ARE_ADDR_EQUAL(a, b) \
30 (memcmp ((gpointer)(a), (gpointer)(b), sizeof (struct in6_addr)) == 0)
31 #endif
32 #else
33 #include <netinet/in.h>
34 #include <sys/socket.h>
35 #endif
37 #include <libsoup/soup-address.h>
38 #include <libsoup/soup-uri.h>
39 #include "e-proxy.h"
41 #define E_PROXY_GET_PRIVATE(obj) \
42 (G_TYPE_INSTANCE_GET_PRIVATE \
43 ((obj), E_TYPE_PROXY, EProxyPrivate))
45 G_DEFINE_TYPE (EProxy, e_proxy, G_TYPE_OBJECT)
47 /* Debug */
48 #define d(x)
50 enum ProxyType {
51 PROXY_TYPE_SYSTEM = 0,
52 PROXY_TYPE_NO_PROXY,
53 PROXY_TYPE_MANUAL,
54 PROXY_TYPE_AUTO_URL /* no auto-proxy at the moment */
57 typedef enum {
58 E_PROXY_KEY_MODE,
59 E_PROXY_KEY_USE_HTTP_PROXY,
60 E_PROXY_KEY_HTTP_HOST,
61 E_PROXY_KEY_HTTP_PORT,
62 E_PROXY_KEY_HTTP_USE_AUTH,
63 E_PROXY_KEY_HTTP_AUTH_USER,
64 E_PROXY_KEY_HTTP_AUTH_PWD,
65 E_PROXY_KEY_HTTP_IGNORE_HOSTS,
66 E_PROXY_KEY_HTTPS_HOST,
67 E_PROXY_KEY_HTTPS_PORT,
68 E_PROXY_KEY_SOCKS_HOST,
69 E_PROXY_KEY_SOCKS_PORT,
70 E_PROXY_KEY_AUTOCONFIG_URL
71 } EProxyKey;
73 struct _EProxyPrivate {
74 SoupURI *uri_http, *uri_https, *uri_socks;
75 GSList * ign_hosts; /* List of hostnames. (Strings) */
76 GSList * ign_addrs; /* List of hostaddrs. (ProxyHostAddrs) */
77 gboolean use_proxy; /* Is our-proxy enabled? */
78 enum ProxyType type;
79 GSettings *evolution_proxy_settings;
80 GSettings *proxy_settings;
81 GSettings *proxy_http_settings;
82 GSettings *proxy_https_settings;
83 GSettings *proxy_socks_settings;
86 /* Enum definition is copied from gnome-vfs/modules/http-proxy.c */
87 typedef enum {
88 PROXY_IPV4 = 4,
89 PROXY_IPV6 = 6
90 } ProxyAddrType;
92 typedef struct {
93 ProxyAddrType type; /* Specifies whether IPV4 or IPV6 */
94 gpointer addr; /* Either in_addr * or in6_addr * */
95 gpointer mask; /* Either in_addr * or in6_addr * */
96 } ProxyHostAddr;
98 /* Signals. */
99 enum {
100 CHANGED,
101 LAST_SIGNAL
104 static guint signals[LAST_SIGNAL] = { 0 };
106 /* Forward declarations. */
108 static void ipv6_network_addr (const struct in6_addr *addr,
109 const struct in6_addr *mask,
110 struct in6_addr *res);
112 static void
113 ep_free_proxy_host_addr (ProxyHostAddr *host)
115 if (host) {
116 if (host->addr) {
117 g_free (host->addr);
118 host->addr = NULL;
120 if (host->mask) {
121 g_free (host->mask);
122 host->mask = NULL;
124 g_free (host);
128 static gboolean
129 ep_read_key_boolean (EProxy *proxy,
130 EProxyKey key)
132 gboolean res = FALSE;
134 g_return_val_if_fail (E_IS_PROXY (proxy), FALSE);
136 switch (key) {
137 case E_PROXY_KEY_USE_HTTP_PROXY:
138 if (proxy->priv->type == PROXY_TYPE_SYSTEM)
139 /* it's not used in the UI, thus behave like always set to TRUE */
140 res = TRUE; /* g_settings_get_boolean (proxy->priv->proxy_http_settings, "enabled"); */
141 else
142 res = g_settings_get_boolean (proxy->priv->evolution_proxy_settings, "use-http-proxy");
143 break;
144 case E_PROXY_KEY_HTTP_USE_AUTH:
145 if (proxy->priv->type == PROXY_TYPE_SYSTEM)
146 res = g_settings_get_boolean (proxy->priv->proxy_http_settings, "use-authentication");
147 else
148 res = g_settings_get_boolean (proxy->priv->evolution_proxy_settings, "use-authentication");
149 break;
150 default:
151 g_warn_if_reached ();
152 break;
155 return res;
158 static gint
159 ep_read_key_int (EProxy *proxy,
160 EProxyKey key)
162 gint res = 0;
164 g_return_val_if_fail (E_IS_PROXY (proxy), 0);
166 switch (key) {
167 case E_PROXY_KEY_HTTP_PORT:
168 if (proxy->priv->type == PROXY_TYPE_SYSTEM)
169 res = g_settings_get_int (proxy->priv->proxy_http_settings, "port");
170 else
171 res = g_settings_get_int (proxy->priv->evolution_proxy_settings, "http-port");
172 break;
173 case E_PROXY_KEY_HTTPS_PORT:
174 if (proxy->priv->type == PROXY_TYPE_SYSTEM)
175 res = g_settings_get_int (proxy->priv->proxy_https_settings, "port");
176 else
177 res = g_settings_get_int (proxy->priv->evolution_proxy_settings, "secure-port");
178 break;
179 case E_PROXY_KEY_SOCKS_PORT:
180 if (proxy->priv->type == PROXY_TYPE_SYSTEM)
181 res = g_settings_get_int (proxy->priv->proxy_socks_settings, "port");
182 else
183 res = g_settings_get_int (proxy->priv->evolution_proxy_settings, "socks-port");
184 break;
185 default:
186 g_warn_if_reached ();
187 break;
190 return res;
193 /* free returned pointer with g_free() */
194 static gchar *
195 ep_read_key_string (EProxy *proxy,
196 EProxyKey key)
198 gchar *res = NULL;
200 g_return_val_if_fail (E_IS_PROXY (proxy), NULL);
202 switch (key) {
203 case E_PROXY_KEY_MODE:
204 if (proxy->priv->type == PROXY_TYPE_SYSTEM)
205 res = g_settings_get_string (proxy->priv->proxy_settings, "mode");
206 else
207 g_warn_if_reached ();
208 break;
209 case E_PROXY_KEY_HTTP_HOST:
210 if (proxy->priv->type == PROXY_TYPE_SYSTEM)
211 res = g_settings_get_string (proxy->priv->proxy_http_settings, "host");
212 else
213 res = g_settings_get_string (proxy->priv->evolution_proxy_settings, "http-host");
214 break;
215 case E_PROXY_KEY_HTTPS_HOST:
216 if (proxy->priv->type == PROXY_TYPE_SYSTEM)
217 res = g_settings_get_string (proxy->priv->proxy_https_settings, "host");
218 else
219 res = g_settings_get_string (proxy->priv->evolution_proxy_settings, "secure-host");
220 break;
221 case E_PROXY_KEY_SOCKS_HOST:
222 if (proxy->priv->type == PROXY_TYPE_SYSTEM)
223 res = g_settings_get_string (proxy->priv->proxy_socks_settings, "host");
224 else
225 res = g_settings_get_string (proxy->priv->evolution_proxy_settings, "socks-host");
226 break;
227 case E_PROXY_KEY_HTTP_AUTH_USER:
228 if (proxy->priv->type == PROXY_TYPE_SYSTEM)
229 res = g_settings_get_string (proxy->priv->proxy_http_settings, "authentication-user");
230 else
231 res = g_settings_get_string (proxy->priv->evolution_proxy_settings, "authentication-user");
232 break;
233 case E_PROXY_KEY_HTTP_AUTH_PWD:
234 if (proxy->priv->type == PROXY_TYPE_SYSTEM)
235 res = g_settings_get_string (proxy->priv->proxy_http_settings, "authentication-password");
236 else
237 res = g_settings_get_string (proxy->priv->evolution_proxy_settings, "authentication-password");
238 break;
239 case E_PROXY_KEY_AUTOCONFIG_URL:
240 if (proxy->priv->type == PROXY_TYPE_SYSTEM)
241 res = g_settings_get_string (proxy->priv->proxy_settings, "autoconfig-url");
242 else
243 res = g_settings_get_string (proxy->priv->evolution_proxy_settings, "autoconfig-url");
244 break;
245 default:
246 g_warn_if_reached ();
247 break;
250 return res;
253 /* list of newly allocated strings, use g_free() for each member and free list itself too */
254 static GSList *
255 ep_read_key_list (EProxy *proxy,
256 EProxyKey key)
258 GSList *res = NULL;
259 gchar **strv = NULL;
261 g_return_val_if_fail (E_IS_PROXY (proxy), NULL);
263 switch (key) {
264 case E_PROXY_KEY_HTTP_IGNORE_HOSTS:
265 if (proxy->priv->type == PROXY_TYPE_SYSTEM)
266 strv = g_settings_get_strv (proxy->priv->proxy_settings, "ignore-hosts");
267 else
268 strv = g_settings_get_strv (proxy->priv->evolution_proxy_settings, "ignore-hosts");
269 break;
270 default:
271 g_warn_if_reached ();
272 break;
275 if (strv) {
276 gint ii;
278 for (ii = 0; strv && strv[ii]; ii++) {
279 res = g_slist_prepend (res, g_strdup (strv[ii]));
282 g_strfreev (strv);
284 res = g_slist_reverse (res);
287 return res;
290 static gboolean
291 ep_is_in_ignored (EProxy *proxy,
292 const gchar *host)
294 EProxyPrivate *priv;
295 GSList * l;
296 gchar *hn;
298 g_return_val_if_fail (proxy != NULL, FALSE);
299 g_return_val_if_fail (host != NULL, FALSE);
301 priv = proxy->priv;
302 if (!priv->ign_hosts)
303 return FALSE;
305 hn = g_ascii_strdown (host, -1);
307 for (l = priv->ign_hosts; l; l = l->next) {
308 if (*((gchar *) l->data) == '*') {
309 if (g_str_has_suffix (hn, ((gchar *) l->data) + 1)) {
310 g_free (hn);
311 return TRUE;
313 } else if (strcmp (hn, l->data) == 0) {
314 g_free (hn);
315 return TRUE;
318 g_free (hn);
320 return FALSE;
323 static gboolean
324 ep_need_proxy_http (EProxy *proxy,
325 const gchar *host)
327 SoupAddress *addr = NULL;
328 EProxyPrivate *priv = proxy->priv;
329 ProxyHostAddr *p_addr = NULL;
330 GSList *l;
331 guint status;
333 /* check for ignored first */
334 if (ep_is_in_ignored (proxy, host))
335 return FALSE;
337 addr = soup_address_new (host, 0);
338 status = soup_address_resolve_sync (addr, NULL);
339 if (status == SOUP_STATUS_OK) {
340 gint addr_len;
341 struct sockaddr * so_addr = NULL;
343 so_addr = soup_address_get_sockaddr (addr, &addr_len);
345 /* This will never happen, since we have already called
346 * soup_address_resolve_sync ().
348 if (!so_addr) {
349 g_object_unref (addr);
350 return TRUE;
353 if (so_addr->sa_family == AF_INET) {
354 struct in_addr in, *mask, *addr_in;
356 in = ((struct sockaddr_in *) so_addr)->sin_addr;
357 for (l = priv->ign_addrs; l; l = l->next) {
358 p_addr = (ProxyHostAddr *) l->data;
359 if (p_addr->type == PROXY_IPV4) {
360 addr_in = ((struct in_addr *) p_addr->addr);
361 mask = ((struct in_addr *) p_addr->mask);
362 if ((in.s_addr & mask->s_addr) == addr_in->s_addr) {
363 d (g_print ("Host [%s] doesn't require proxy\n", host));
364 g_object_unref (addr);
365 return FALSE;
369 } else {
370 struct in6_addr in6, net6;
371 struct in_addr *addr_in, *mask;
373 in6 = ((struct sockaddr_in6 *) so_addr)->sin6_addr;
374 for (l = priv->ign_addrs; l; l = l->next) {
375 p_addr = (ProxyHostAddr *) l->data;
376 ipv6_network_addr (&in6, (struct in6_addr *) p_addr->mask, &net6);
377 if (p_addr->type == PROXY_IPV6) {
378 if (IN6_ARE_ADDR_EQUAL (&net6, (struct in6_addr *) p_addr->addr)) {
379 d (g_print ("Host [%s] doesn't require proxy\n", host));
380 g_object_unref (addr);
381 return FALSE;
383 } else if (p_addr->type == PROXY_IPV6 &&
384 IN6_IS_ADDR_V4MAPPED (&net6)) {
385 guint32 v4addr;
387 addr_in = ((struct in_addr *) p_addr->addr);
388 mask = ((struct in_addr *) p_addr->mask);
390 v4addr = net6.s6_addr[12] << 24
391 | net6.s6_addr[13] << 16
392 | net6.s6_addr[14] << 8
393 | net6.s6_addr[15];
394 if ((v4addr & mask->s_addr) != addr_in->s_addr) {
395 d (g_print ("Host [%s] doesn't require proxy\n", host));
396 g_object_unref (addr);
397 return FALSE;
404 d (g_print ("%s needs a proxy to connect to internet\n", host));
405 g_object_unref (addr);
407 return TRUE;
410 static gboolean
411 ep_need_proxy_https (EProxy *proxy,
412 const gchar *host)
414 /* Can we share ignore list from HTTP at all? */
415 return !ep_is_in_ignored (proxy, host);
418 static gboolean
419 ep_need_proxy_socks (EProxy *proxy,
420 const gchar *host)
422 /* Can we share ignore list from HTTP at all? */
423 return !ep_is_in_ignored (proxy, host);
426 /* Apply a prefix-notation @netmask to the given @addr_in, as described in
427 * http://tools.ietf.org/html/rfc4632#section-3.1 */
428 static gboolean
429 ep_manipulate_ipv4 (ProxyHostAddr *host_addr,
430 struct in_addr *addr_in,
431 gchar *netmask)
433 gboolean has_error = FALSE;
434 struct in_addr *addr, *mask;
436 if (!addr_in)
437 return has_error;
439 host_addr->type = PROXY_IPV4;
440 addr = g_new0 (struct in_addr, 1);
441 memcpy (addr, addr_in, sizeof (struct in_addr));
442 mask = g_new0 (struct in_addr, 1);
444 if (netmask) {
445 gchar *endptr;
446 gint width = strtol (netmask, &endptr, 10);
448 if (*endptr != '\0' || width < 0 || width > 32) {
449 has_error = TRUE;
450 mask->s_addr = 0xFFFFFFFF;
451 } else if (width == 32) {
452 mask->s_addr = 0;
453 addr->s_addr = 0;
454 } else {
455 mask->s_addr = htonl (~0U << width);
456 addr->s_addr &= mask->s_addr;
458 } else {
459 mask->s_addr = 0xFFFFFFFF;
462 host_addr->addr = addr;
463 host_addr->mask = mask;
465 return has_error;
468 static void
469 ipv6_network_addr (const struct in6_addr *addr,
470 const struct in6_addr *mask,
471 struct in6_addr *res)
473 gint i;
475 for (i = 0; i < 16; ++i) {
476 res->s6_addr[i] = addr->s6_addr[i] & mask->s6_addr[i];
480 static gboolean
481 ep_manipulate_ipv6 (ProxyHostAddr *host_addr,
482 struct in6_addr *addr_in6,
483 gchar *netmask)
485 gboolean has_error = FALSE;
486 struct in6_addr *addr, *mask;
487 gint i;
489 if (!addr_in6)
490 return has_error;
492 host_addr->type = PROXY_IPV6;
494 addr = g_new0 (struct in6_addr, 1);
495 mask = g_new0 (struct in6_addr, 1);
497 for (i = 0; i < 16; ++i) {
498 addr->s6_addr[i] = addr_in6->s6_addr[i];
500 if (netmask) {
501 gchar *endptr;
502 gint width = strtol (netmask, &endptr, 10);
504 if (*endptr != '\0' || width < 0 || width > 128) {
505 has_error = TRUE;
507 for (i = 0; i < 16; ++i) {
508 mask->s6_addr[i] = 0;
510 for (i = 0; i < width / 8; i++) {
511 mask->s6_addr[i] = 0xff;
513 mask->s6_addr[i] = (0xff << (8 - width % 8)) & 0xff;
514 ipv6_network_addr (addr, mask, addr);
515 } else {
516 for (i = 0; i < 16; ++i) {
517 mask->s6_addr[i] = 0xff;
521 host_addr->addr = addr;
522 host_addr->mask = mask;
524 return has_error;
527 static void
528 ep_parse_ignore_host (gpointer data,
529 gpointer user_data)
531 EProxy * proxy = (EProxy *) user_data;
532 EProxyPrivate * priv = NULL;
533 SoupAddress *addr;
534 guint status;
535 gchar *input, *netmask, *hostname;
536 gboolean has_error = FALSE;
538 if (!proxy || !proxy->priv)
539 return;
541 priv = proxy->priv;
542 input = (gchar *) data;
544 if ((netmask = strrchr (input, '/')) != NULL) {
545 hostname = g_strndup (input, netmask - input);
546 ++netmask;
547 } else {
548 hostname = g_ascii_strdown (input, -1);
551 addr = soup_address_new (hostname, 0);
552 status = soup_address_resolve_sync (addr, NULL);
553 if (status == SOUP_STATUS_OK) {
554 ProxyHostAddr *host_addr;
555 gint addr_len;
556 struct sockaddr * so_addr = NULL;
558 host_addr = g_new0 (ProxyHostAddr, 1);
560 so_addr = soup_address_get_sockaddr (addr, &addr_len);
562 /* This will never happen, since we have already called
563 * soup_address_resolve_sync ().
565 if (!so_addr) {
566 ep_free_proxy_host_addr (host_addr);
567 goto error;
570 if (so_addr->sa_family == AF_INET)
571 has_error = ep_manipulate_ipv4 (
572 host_addr,
573 &((struct sockaddr_in *) so_addr)->sin_addr,
574 netmask);
575 else
576 has_error = ep_manipulate_ipv6 (
577 host_addr,
578 &((struct sockaddr_in6 *) so_addr)->sin6_addr,
579 netmask);
581 if (!has_error) {
582 priv->ign_addrs = g_slist_append (
583 priv->ign_addrs, host_addr);
584 priv->ign_hosts = g_slist_append (
585 priv->ign_hosts, hostname);
586 } else {
587 ep_free_proxy_host_addr (host_addr);
588 g_free (hostname);
590 } else {
591 d (g_print ("Unable to resolve %s\n", hostname));
592 priv->ign_hosts = g_slist_append (priv->ign_hosts, hostname);
594 error:
595 g_object_unref (addr);
598 static gboolean
599 ep_change_uri (SoupURI **soup_uri,
600 const gchar *uri)
602 gboolean changed = FALSE;
604 g_return_val_if_fail (soup_uri != NULL, FALSE);
606 if (!uri || !*uri) {
607 if (*soup_uri) {
608 soup_uri_free (*soup_uri);
609 *soup_uri = NULL;
610 changed = TRUE;
612 } else if (*soup_uri) {
613 gchar *old = soup_uri_to_string (*soup_uri, FALSE);
615 if (old && *old) {
616 gint len = strlen (old);
618 /* remove ending slash, if there */
619 if (old[len - 1] == '/')
620 old[len - 1] = 0;
623 changed = old && uri && g_ascii_strcasecmp (old, uri) != 0;
624 if (changed) {
625 soup_uri_free (*soup_uri);
626 *soup_uri = soup_uri_new (uri);
629 g_free (old);
630 } else {
631 *soup_uri = soup_uri_new (uri);
632 changed = TRUE;
635 return changed;
638 static gchar *
639 update_proxy_uri (const gchar *uri,
640 const gchar *proxy_user,
641 const gchar *proxy_pw)
643 gchar *res, *user = NULL, *pw = NULL;
644 gboolean is_https;
646 g_return_val_if_fail (uri != NULL, NULL);
648 if (proxy_user && *proxy_user) {
649 user = soup_uri_encode (proxy_user, ":/;#@?\\");
650 if (proxy_pw)
651 pw = soup_uri_encode (proxy_pw, ":/;#@?\\");
654 if (!user)
655 return g_strdup (uri);
657 /* here can be only http or https and nothing else */
658 is_https = g_str_has_prefix (uri, "https://");
660 res = g_strdup_printf (
661 "%s://%s%s%s@%s",
662 is_https ? "https" : "http",
663 user,
664 pw ? ":" : "",
665 pw ? pw : "",
666 uri + strlen ("http://") + (is_https ? 1 : 0));
668 g_free (user);
669 g_free (pw);
671 return res;
674 static void
675 ep_set_proxy (EProxy *proxy,
676 gboolean regen_ign_host_list)
678 gchar *proxy_server, *uri_http = NULL, *uri_https = NULL, *uri_socks = NULL;
679 gint proxy_port, old_type;
680 EProxyPrivate * priv = proxy->priv;
681 GSList *ignore;
682 gboolean changed = FALSE, sys_manual = TRUE;
684 old_type = priv->type;
685 priv->type = g_settings_get_int (priv->evolution_proxy_settings, "proxy-type");
686 if (priv->type > PROXY_TYPE_AUTO_URL)
687 priv->type = PROXY_TYPE_SYSTEM;
688 changed = priv->type != old_type;
690 if (priv->type == PROXY_TYPE_SYSTEM) {
691 gchar *mode = ep_read_key_string (proxy, E_PROXY_KEY_MODE);
693 /* supporting only manual system proxy setting */
694 sys_manual = mode && g_str_equal (mode, "manual");
696 g_free (mode);
699 priv->use_proxy = ep_read_key_boolean (proxy, E_PROXY_KEY_USE_HTTP_PROXY);
700 if (!priv->use_proxy || priv->type == PROXY_TYPE_NO_PROXY || !sys_manual) {
701 changed = ep_change_uri (&priv->uri_http, NULL) || changed;
702 changed = ep_change_uri (&priv->uri_https, NULL) || changed;
703 changed = ep_change_uri (&priv->uri_socks, NULL) || changed;
704 goto emit_signal;
707 proxy_server = ep_read_key_string (proxy, E_PROXY_KEY_HTTP_HOST);
708 proxy_port = ep_read_key_int (proxy, E_PROXY_KEY_HTTP_PORT);
709 if (proxy_server != NULL && *proxy_server && !g_ascii_isspace (*proxy_server)) {
710 if (proxy_port > 0)
711 uri_http = g_strdup_printf ("http://%s:%d", proxy_server, proxy_port);
712 else
713 uri_http = g_strdup_printf ("http://%s", proxy_server);
714 } else
715 uri_http = NULL;
716 g_free (proxy_server);
717 d (g_print ("ep_set_proxy: uri_http: %s\n", uri_http));
719 proxy_server = ep_read_key_string (proxy, E_PROXY_KEY_HTTPS_HOST);
720 proxy_port = ep_read_key_int (proxy, E_PROXY_KEY_HTTPS_PORT);
721 if (proxy_server != NULL && *proxy_server && !g_ascii_isspace (*proxy_server)) {
722 if (proxy_port > 0)
723 uri_https = g_strdup_printf ("https://%s:%d", proxy_server, proxy_port);
724 else
725 uri_https = g_strdup_printf ("https://%s", proxy_server);
726 } else
727 uri_https = NULL;
728 g_free (proxy_server);
729 d (g_print ("ep_set_proxy: uri_https: %s\n", uri_https));
731 proxy_server = ep_read_key_string (proxy, E_PROXY_KEY_SOCKS_HOST);
732 proxy_port = ep_read_key_int (proxy, E_PROXY_KEY_SOCKS_PORT);
733 if (proxy_server != NULL && *proxy_server && !g_ascii_isspace (*proxy_server)) {
734 if (proxy_port > 0)
735 uri_socks = g_strdup_printf ("socks://%s:%d", proxy_server, proxy_port);
736 else
737 uri_socks = g_strdup_printf ("socks://%s", proxy_server);
738 } else
739 uri_socks = NULL;
740 g_free (proxy_server);
741 d (g_print ("ep_set_proxy: uri_socks: %s\n", uri_socks));
743 if (regen_ign_host_list) {
744 if (priv->ign_hosts) {
745 g_slist_foreach (priv->ign_hosts, (GFunc) g_free, NULL);
746 g_slist_free (priv->ign_hosts);
747 priv->ign_hosts = NULL;
750 if (priv->ign_addrs) {
751 g_slist_foreach (priv->ign_addrs, (GFunc) ep_free_proxy_host_addr, NULL);
752 g_slist_free (priv->ign_addrs);
753 priv->ign_addrs = NULL;
756 ignore = ep_read_key_list (proxy, E_PROXY_KEY_HTTP_IGNORE_HOSTS);
757 if (ignore) {
758 g_slist_foreach (ignore, (GFunc) ep_parse_ignore_host, proxy);
759 g_slist_foreach (ignore, (GFunc) g_free, NULL);
760 g_slist_free (ignore);
764 if (ep_read_key_boolean (proxy, E_PROXY_KEY_HTTP_USE_AUTH)) {
765 gchar *proxy_user, *proxy_pw, *tmp = NULL, *tmps = NULL;
767 proxy_user = ep_read_key_string (proxy, E_PROXY_KEY_HTTP_AUTH_USER);
768 proxy_pw = ep_read_key_string (proxy, E_PROXY_KEY_HTTP_AUTH_PWD);
770 if (uri_http && proxy_user && *proxy_user) {
771 tmp = uri_http;
772 uri_http = update_proxy_uri (uri_http, proxy_user, proxy_pw);
775 if (uri_https && proxy_user && *proxy_user) {
776 tmps = uri_https;
777 uri_https = update_proxy_uri (uri_https, proxy_user, proxy_pw);
780 g_free (proxy_user);
781 g_free (proxy_pw);
782 g_free (tmp);
783 g_free (tmps);
786 changed = ep_change_uri (&priv->uri_http, uri_http) || changed;
787 changed = ep_change_uri (&priv->uri_https, uri_https) || changed;
788 changed = ep_change_uri (&priv->uri_socks, uri_socks) || changed;
790 emit_signal:
791 d (g_print (
792 "%s: changed:%d "
793 "uri_http: %s; "
794 "uri_https: %s; "
795 "uri_socks: %s\n",
796 G_STRFUNC, changed ? 1 : 0,
797 uri_http ? uri_http : "[null]",
798 uri_https ? uri_https : "[null]",
799 uri_socks ? uri_socks : "[null]"));
800 if (changed)
801 g_signal_emit (proxy, signals[CHANGED], 0);
803 g_free (uri_http);
804 g_free (uri_https);
805 g_free (uri_socks);
808 static void
809 ep_evo_proxy_changed_cb (GSettings *settings,
810 const gchar *key,
811 EProxy *proxy)
813 EProxyPrivate *priv;
815 g_return_if_fail (E_IS_PROXY (proxy));
817 priv = proxy->priv;
819 d (g_print ("%s: proxy settings changed, key '%s'\n", G_STRFUNC, key ? key : "NULL"));
820 if (g_strcmp0 (key, "proxy-type") == 0) {
821 ep_set_proxy (proxy, TRUE);
822 } else if (priv->type == PROXY_TYPE_SYSTEM) {
823 return;
826 ep_set_proxy (proxy, g_strcmp0 (key, "ignore-hosts") == 0);
829 static void
830 ep_sys_proxy_changed_cb (GSettings *settings,
831 const gchar *key,
832 EProxy *proxy)
834 g_return_if_fail (proxy != NULL);
836 if (proxy->priv->type != PROXY_TYPE_SYSTEM)
837 return;
839 ep_set_proxy (proxy, g_strcmp0 (key, "ignore-hosts") == 0);
842 static void
843 ep_sys_proxy_http_changed_cb (GSettings *settings,
844 const gchar *key,
845 EProxy *proxy)
847 g_return_if_fail (proxy != NULL);
849 if (proxy->priv->type != PROXY_TYPE_SYSTEM)
850 return;
852 ep_set_proxy (proxy, FALSE);
855 static void
856 ep_sys_proxy_https_changed_cb (GSettings *settings,
857 const gchar *key,
858 EProxy *proxy)
860 g_return_if_fail (proxy != NULL);
862 if (proxy->priv->type != PROXY_TYPE_SYSTEM)
863 return;
865 ep_set_proxy (proxy, FALSE);
868 static void
869 ep_sys_proxy_socks_changed_cb (GSettings *settings,
870 const gchar *key,
871 EProxy *proxy)
873 g_return_if_fail (proxy != NULL);
875 if (proxy->priv->type != PROXY_TYPE_SYSTEM)
876 return;
878 ep_set_proxy (proxy, FALSE);
881 static void
882 e_proxy_dispose (GObject *object)
884 EProxy *proxy;
885 EProxyPrivate *priv;
887 proxy = E_PROXY (object);
888 priv = proxy->priv;
890 if (priv->evolution_proxy_settings) {
891 g_signal_handlers_disconnect_by_func (priv->evolution_proxy_settings, ep_evo_proxy_changed_cb, proxy);
892 g_object_unref (priv->evolution_proxy_settings);
893 priv->evolution_proxy_settings = NULL;
896 if (priv->proxy_settings) {
897 g_signal_handlers_disconnect_by_func (priv->proxy_settings, ep_sys_proxy_changed_cb, proxy);
898 g_object_unref (priv->proxy_settings);
899 priv->proxy_settings = NULL;
902 if (priv->proxy_http_settings) {
903 g_signal_handlers_disconnect_by_func (priv->proxy_http_settings, ep_sys_proxy_http_changed_cb, proxy);
904 g_object_unref (priv->proxy_http_settings);
905 priv->proxy_http_settings = NULL;
908 if (priv->proxy_https_settings) {
909 g_signal_handlers_disconnect_by_func (priv->proxy_https_settings, ep_sys_proxy_https_changed_cb, proxy);
910 g_object_unref (priv->proxy_https_settings);
911 priv->proxy_https_settings = NULL;
914 if (priv->proxy_socks_settings) {
915 g_signal_handlers_disconnect_by_func (priv->proxy_socks_settings, ep_sys_proxy_socks_changed_cb, proxy);
916 g_object_unref (priv->proxy_socks_settings);
917 priv->proxy_socks_settings = NULL;
920 if (priv->uri_http)
921 soup_uri_free (priv->uri_http);
923 if (priv->uri_https)
924 soup_uri_free (priv->uri_https);
926 if (priv->uri_socks)
927 soup_uri_free (priv->uri_socks);
929 g_slist_foreach (priv->ign_hosts, (GFunc) g_free, NULL);
930 g_slist_free (priv->ign_hosts);
932 g_slist_foreach (priv->ign_addrs, (GFunc) ep_free_proxy_host_addr, NULL);
933 g_slist_free (priv->ign_addrs);
935 /* Chain up to parent's dispose() method. */
936 G_OBJECT_CLASS (e_proxy_parent_class)->dispose (object);
939 static void
940 e_proxy_class_init (EProxyClass *class)
942 GObjectClass *object_class;
944 g_type_class_add_private (class, sizeof (EProxyPrivate));
946 object_class = G_OBJECT_CLASS (class);
947 object_class->dispose = e_proxy_dispose;
950 * EProxy::changed:
951 * @proxy: the #EProxy which emitted the signal
953 * Emitted when proxy settings changes.
955 signals[CHANGED] = g_signal_new (
956 "changed",
957 G_OBJECT_CLASS_TYPE (object_class),
958 G_SIGNAL_RUN_FIRST,
959 G_STRUCT_OFFSET (EProxyClass, changed),
960 NULL, NULL, NULL,
961 G_TYPE_NONE, 0);
965 static void
966 e_proxy_init (EProxy *proxy)
968 proxy->priv = E_PROXY_GET_PRIVATE (proxy);
970 proxy->priv->type = PROXY_TYPE_SYSTEM;
972 proxy->priv->evolution_proxy_settings = g_settings_new ("org.gnome.evolution.shell.network-config");
973 proxy->priv->proxy_settings = g_settings_new ("org.gnome.system.proxy");
974 proxy->priv->proxy_http_settings = g_settings_get_child (proxy->priv->proxy_settings, "http");
975 proxy->priv->proxy_https_settings = g_settings_get_child (proxy->priv->proxy_settings, "https");
976 proxy->priv->proxy_socks_settings = g_settings_get_child (proxy->priv->proxy_settings, "socks");
978 g_signal_connect (proxy->priv->evolution_proxy_settings, "changed", G_CALLBACK (ep_evo_proxy_changed_cb), proxy);
979 g_signal_connect (proxy->priv->proxy_settings, "changed", G_CALLBACK (ep_sys_proxy_changed_cb), proxy);
980 g_signal_connect (proxy->priv->proxy_http_settings, "changed", G_CALLBACK (ep_sys_proxy_http_changed_cb), proxy);
981 g_signal_connect (proxy->priv->proxy_https_settings, "changed", G_CALLBACK (ep_sys_proxy_https_changed_cb), proxy);
982 g_signal_connect (proxy->priv->proxy_socks_settings, "changed", G_CALLBACK (ep_sys_proxy_socks_changed_cb), proxy);
986 * e_proxy_new:
988 * Returns: (transfer full): a new instance of an #EProxy
990 * Since: 2.24
992 EProxy *
993 e_proxy_new (void)
995 return g_object_new (E_TYPE_PROXY, NULL);
999 * e_proxy_setup_proxy:
1000 * @proxy: an #EProxy
1002 * Sets up internal structure members and reads the proxy settings.
1004 * Since: 2.24
1006 void
1007 e_proxy_setup_proxy (EProxy *proxy)
1009 g_return_if_fail (E_IS_PROXY (proxy));
1011 /* We get the evolution-shell proxy keys here
1012 * set soup up to use the proxy,
1013 * and listen to any changes */
1015 /* XXX Why can't we do this automatically in constructed() ? */
1017 ep_set_proxy (proxy, TRUE);
1021 * e_proxy_peek_uri_for:
1022 * @proxy: an #EProxy
1023 * @uri: a URI
1025 * Returns: (transfer none): A proxy URI (as a #SoupURI) which the given @uri
1026 * may use, based on its scheme
1028 * Since: 2.26
1030 SoupURI *
1031 e_proxy_peek_uri_for (EProxy *proxy,
1032 const gchar *uri)
1034 SoupURI *res = NULL;
1035 SoupURI *soup_uri;
1037 g_return_val_if_fail (E_IS_PROXY (proxy), NULL);
1038 g_return_val_if_fail (uri != NULL, NULL);
1040 soup_uri = soup_uri_new (uri);
1041 if (soup_uri == NULL)
1042 return NULL;
1044 if (soup_uri->scheme == SOUP_URI_SCHEME_HTTP)
1045 res = proxy->priv->uri_http;
1046 else if (soup_uri->scheme == SOUP_URI_SCHEME_HTTPS)
1047 res = proxy->priv->uri_https;
1048 else if (soup_uri->scheme && g_ascii_strcasecmp (soup_uri->scheme, "socks") == 0)
1049 res = proxy->priv->uri_socks;
1051 soup_uri_free (soup_uri);
1053 return res;
1057 * e_proxy_require_proxy_for_uri:
1058 * @proxy: an #EProxy
1059 * @uri: a URI
1061 * Returns: Whether the @uri requires proxy to connect to it
1063 * Since: 2.24
1065 gboolean
1066 e_proxy_require_proxy_for_uri (EProxy *proxy,
1067 const gchar *uri)
1069 SoupURI *soup_uri = NULL;
1070 gboolean need_proxy = FALSE;
1072 g_return_val_if_fail (E_IS_PROXY (proxy), FALSE);
1073 g_return_val_if_fail (uri != NULL, FALSE);
1075 if (!proxy->priv->use_proxy || proxy->priv->type == PROXY_TYPE_NO_PROXY) {
1076 d (g_print ("[%s] don't need a proxy to connect to internet\n", uri));
1077 return FALSE;
1080 soup_uri = soup_uri_new (uri);
1081 if (soup_uri == NULL)
1082 return FALSE;
1084 if (soup_uri->scheme == SOUP_URI_SCHEME_HTTP)
1085 need_proxy = ep_need_proxy_http (proxy, soup_uri->host);
1086 else if (soup_uri->scheme == SOUP_URI_SCHEME_HTTPS)
1087 need_proxy = ep_need_proxy_https (proxy, soup_uri->host);
1088 else if (soup_uri->scheme && g_ascii_strcasecmp (soup_uri->scheme, "socks") == 0)
1089 need_proxy = ep_need_proxy_socks (proxy, soup_uri->host);
1091 soup_uri_free (soup_uri);
1093 return need_proxy;