/* * e-source-proxy.c * * 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 . * */ /** * SECTION: e-source-proxy * @include: libedataserver/libedataserver.h * @short_description: #ESource extension for network proxy settings * * The #ESourceProxy extension defines a network proxy profile. * * An #ESource instance with this extension can serve as a #GProxyResolver. * * Access the extension as follows: * * |[ * #include * * ESourceProxy *extension; * * extension = e_source_get_extension (source, E_SOURCE_EXTENSION_PROXY); * ]| **/ #include "evolution-data-server-config.h" #include #include #include #include "e-source-proxy.h" typedef struct _AsyncContext AsyncContext; struct _ESourceProxyPrivate { EProxyMethod method; gchar *autoconfig_url; gchar **ignore_hosts; gchar *ftp_host; guint16 ftp_port; gchar *http_host; guint16 http_port; gboolean http_use_auth; gchar *http_auth_user; gchar *http_auth_password; gchar *https_host; guint16 https_port; gchar *socks_host; guint16 socks_port; }; struct _AsyncContext { gchar *uri; gchar **proxies; }; enum { PROP_0, PROP_AUTOCONFIG_URL, PROP_FTP_HOST, PROP_FTP_PORT, PROP_HTTP_AUTH_PASSWORD, PROP_HTTP_AUTH_USER, PROP_HTTP_HOST, PROP_HTTP_PORT, PROP_HTTP_USE_AUTH, PROP_HTTPS_HOST, PROP_HTTPS_PORT, PROP_IGNORE_HOSTS, PROP_METHOD, PROP_SOCKS_HOST, PROP_SOCKS_PORT }; G_DEFINE_TYPE_WITH_PRIVATE ( ESourceProxy, e_source_proxy, E_TYPE_SOURCE_EXTENSION) static void async_context_free (AsyncContext *async_context) { g_free (async_context->uri); g_strfreev (async_context->proxies); g_slice_free (AsyncContext, async_context); } static gchar ** source_proxy_direct (void) { gchar **proxies; proxies = g_new (gchar *, 2); proxies[0] = g_strdup ("direct://"); proxies[1] = NULL; return proxies; } static gchar * source_proxy_dup_http_proxy (ESourceProxy *extension, const gchar *http_host, guint16 http_port) { GString *http_proxy = g_string_new ("http://"); if (e_source_proxy_get_http_use_auth (extension)) { gchar *http_user; gchar *http_pass; gchar *enc_http_user; gchar *enc_http_pass; http_user = e_source_proxy_dup_http_auth_user (extension); http_pass = e_source_proxy_dup_http_auth_password (extension); enc_http_user = g_uri_escape_string (http_user, NULL, TRUE); enc_http_pass = g_uri_escape_string (http_pass, NULL, TRUE); g_string_append (http_proxy, enc_http_user); g_string_append_c (http_proxy, ':'); g_string_append (http_proxy, enc_http_pass); g_string_append_c (http_proxy, '@'); g_free (enc_http_user); g_free (enc_http_pass); g_free (http_user); g_free (http_pass); } g_string_append_printf (http_proxy, "%s:%u", http_host, http_port); return g_string_free (http_proxy, FALSE); } static gchar ** source_proxy_lookup_pacrunner (ESource *source, const gchar *uri, GCancellable *cancellable, GError **error) { GDBusProxy *pacrunner; ESourceProxy *extension; const gchar *extension_name; gchar *autoconfig_url; gchar **proxies = NULL; extension_name = E_SOURCE_EXTENSION_PROXY; extension = e_source_get_extension (source, extension_name); autoconfig_url = e_source_proxy_dup_autoconfig_url (extension); if (autoconfig_url == NULL) { proxies = source_proxy_direct (); goto exit; } pacrunner = g_dbus_proxy_new_for_bus_sync ( G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, NULL, "org.gtk.GLib.PACRunner", "/org/gtk/GLib/PACRunner", "org.gtk.GLib.PACRunner", cancellable, error); if (pacrunner != NULL) { GVariant *variant_proxies; variant_proxies = g_dbus_proxy_call_sync ( pacrunner, "Lookup", g_variant_new ("(ss)", autoconfig_url, uri), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, error); if (variant_proxies != NULL) { g_variant_get (variant_proxies, "(^as)", &proxies); g_variant_unref (variant_proxies); } g_object_unref (pacrunner); } exit: g_free (autoconfig_url); return proxies; } static void source_proxy_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { switch (property_id) { case PROP_AUTOCONFIG_URL: e_source_proxy_set_autoconfig_url ( E_SOURCE_PROXY (object), g_value_get_string (value)); return; case PROP_FTP_HOST: e_source_proxy_set_ftp_host ( E_SOURCE_PROXY (object), g_value_get_string (value)); return; case PROP_FTP_PORT: e_source_proxy_set_ftp_port ( E_SOURCE_PROXY (object), g_value_get_uint (value)); return; case PROP_HTTP_AUTH_PASSWORD: e_source_proxy_set_http_auth_password ( E_SOURCE_PROXY (object), g_value_get_string (value)); return; case PROP_HTTP_AUTH_USER: e_source_proxy_set_http_auth_user ( E_SOURCE_PROXY (object), g_value_get_string (value)); return; case PROP_HTTP_HOST: e_source_proxy_set_http_host ( E_SOURCE_PROXY (object), g_value_get_string (value)); return; case PROP_HTTP_PORT: e_source_proxy_set_http_port ( E_SOURCE_PROXY (object), g_value_get_uint (value)); return; case PROP_HTTP_USE_AUTH: e_source_proxy_set_http_use_auth ( E_SOURCE_PROXY (object), g_value_get_boolean (value)); return; case PROP_HTTPS_HOST: e_source_proxy_set_https_host ( E_SOURCE_PROXY (object), g_value_get_string (value)); return; case PROP_HTTPS_PORT: e_source_proxy_set_https_port ( E_SOURCE_PROXY (object), g_value_get_uint (value)); return; case PROP_IGNORE_HOSTS: e_source_proxy_set_ignore_hosts ( E_SOURCE_PROXY (object), g_value_get_boxed (value)); return; case PROP_METHOD: e_source_proxy_set_method ( E_SOURCE_PROXY (object), g_value_get_enum (value)); return; case PROP_SOCKS_HOST: e_source_proxy_set_socks_host ( E_SOURCE_PROXY (object), g_value_get_string (value)); return; case PROP_SOCKS_PORT: e_source_proxy_set_socks_port ( E_SOURCE_PROXY (object), g_value_get_uint (value)); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void source_proxy_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { switch (property_id) { case PROP_AUTOCONFIG_URL: g_value_take_string ( value, e_source_proxy_dup_autoconfig_url ( E_SOURCE_PROXY (object))); return; case PROP_FTP_HOST: g_value_take_string ( value, e_source_proxy_dup_ftp_host ( E_SOURCE_PROXY (object))); return; case PROP_FTP_PORT: g_value_set_uint ( value, e_source_proxy_get_ftp_port ( E_SOURCE_PROXY (object))); return; case PROP_HTTP_AUTH_PASSWORD: g_value_take_string ( value, e_source_proxy_dup_http_auth_password ( E_SOURCE_PROXY (object))); return; case PROP_HTTP_AUTH_USER: g_value_take_string ( value, e_source_proxy_dup_http_auth_user ( E_SOURCE_PROXY (object))); return; case PROP_HTTP_HOST: g_value_take_string ( value, e_source_proxy_dup_http_host ( E_SOURCE_PROXY (object))); return; case PROP_HTTP_PORT: g_value_set_uint ( value, e_source_proxy_get_http_port ( E_SOURCE_PROXY (object))); return; case PROP_HTTP_USE_AUTH: g_value_set_boolean ( value, e_source_proxy_get_http_use_auth ( E_SOURCE_PROXY (object))); return; case PROP_HTTPS_HOST: g_value_take_string ( value, e_source_proxy_dup_https_host ( E_SOURCE_PROXY (object))); return; case PROP_HTTPS_PORT: g_value_set_uint ( value, e_source_proxy_get_https_port ( E_SOURCE_PROXY (object))); return; case PROP_IGNORE_HOSTS: g_value_take_boxed ( value, e_source_proxy_dup_ignore_hosts ( E_SOURCE_PROXY (object))); return; case PROP_METHOD: g_value_set_enum ( value, e_source_proxy_get_method ( E_SOURCE_PROXY (object))); return; case PROP_SOCKS_HOST: g_value_take_string ( value, e_source_proxy_dup_socks_host ( E_SOURCE_PROXY (object))); return; case PROP_SOCKS_PORT: g_value_set_uint ( value, e_source_proxy_get_socks_port ( E_SOURCE_PROXY (object))); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void source_proxy_finalize (GObject *object) { ESourceProxyPrivate *priv; priv = E_SOURCE_PROXY (object)->priv; g_free (priv->autoconfig_url); g_strfreev (priv->ignore_hosts); g_free (priv->ftp_host); g_free (priv->http_host); g_free (priv->http_auth_user); g_free (priv->http_auth_password); g_free (priv->https_host); g_free (priv->socks_host); /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (e_source_proxy_parent_class)->finalize (object); } static void e_source_proxy_class_init (ESourceProxyClass *class) { GObjectClass *object_class; ESourceExtensionClass *extension_class; object_class = G_OBJECT_CLASS (class); object_class->set_property = source_proxy_set_property; object_class->get_property = source_proxy_get_property; object_class->finalize = source_proxy_finalize; extension_class = E_SOURCE_EXTENSION_CLASS (class); extension_class->name = E_SOURCE_EXTENSION_PROXY; g_object_class_install_property ( object_class, PROP_AUTOCONFIG_URL, g_param_spec_string ( "autoconfig-url", "Autoconfig URL", "Proxy autoconfiguration URL", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); g_object_class_install_property ( object_class, PROP_FTP_HOST, g_param_spec_string ( "ftp-host", "FTP Host", "FTP proxy host name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); g_object_class_install_property ( object_class, PROP_FTP_PORT, g_param_spec_uint ( "ftp-port", "FTP Port", "FTP proxy port", 0, G_MAXUINT16, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); g_object_class_install_property ( object_class, PROP_HTTP_AUTH_PASSWORD, g_param_spec_string ( "http-auth-password", "HTTP Auth Password", "HTTP proxy password", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); g_object_class_install_property ( object_class, PROP_HTTP_AUTH_USER, g_param_spec_string ( "http-auth-user", "HTTP Auth User", "HTTP proxy username", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); g_object_class_install_property ( object_class, PROP_HTTP_HOST, g_param_spec_string ( "http-host", "HTTP Host", "HTTP proxy host name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); g_object_class_install_property ( object_class, PROP_HTTP_PORT, g_param_spec_uint ( "http-port", "HTTP Port", "HTTP proxy port", 0, G_MAXUINT16, 8080, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); g_object_class_install_property ( object_class, PROP_HTTP_USE_AUTH, g_param_spec_boolean ( "http-use-auth", "HTTP Use Auth", "Whether HTTP proxy server " "connections require authentication", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); g_object_class_install_property ( object_class, PROP_HTTPS_HOST, g_param_spec_string ( "https-host", "HTTPS Host", "Secure HTTP proxy host name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); g_object_class_install_property ( object_class, PROP_HTTPS_PORT, g_param_spec_uint ( "https-port", "HTTPS Port", "Secure HTTP proxy port", 0, G_MAXUINT16, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); g_object_class_install_property ( object_class, PROP_IGNORE_HOSTS, g_param_spec_boxed ( "ignore-hosts", "Ignore Hosts", "Hosts to connect directly", G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); g_object_class_install_property ( object_class, PROP_METHOD, g_param_spec_enum ( "method", "Method", "Proxy configuration method", E_TYPE_PROXY_METHOD, E_PROXY_METHOD_DEFAULT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); g_object_class_install_property ( object_class, PROP_SOCKS_HOST, g_param_spec_string ( "socks-host", "SOCKS Host", "SOCKS proxy host name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); g_object_class_install_property ( object_class, PROP_SOCKS_PORT, g_param_spec_uint ( "socks-port", "SOCKS Port", "SOCKS proxy port", 0, G_MAXUINT16, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); } static void e_source_proxy_init (ESourceProxy *extension) { extension->priv = e_source_proxy_get_instance_private (extension); } /** * e_source_proxy_get_method: * @extension: an #ESourceProxy * * Returns the proxy configuration method for @extension. * * The proxy configuration method determines the behavior of * e_source_proxy_lookup(). * * Returns: the proxy configuration method * * Since: 3.12 **/ EProxyMethod e_source_proxy_get_method (ESourceProxy *extension) { g_return_val_if_fail ( E_IS_SOURCE_PROXY (extension), E_PROXY_METHOD_DEFAULT); return extension->priv->method; } /** * e_source_proxy_set_method: * @extension: an #ESourceProxy * @method: the proxy configuration method * * Sets the proxy configuration method for @extension. * * The proxy configuration method determines the behavior of * e_source_proxy_lookup(). * * Since: 3.12 **/ void e_source_proxy_set_method (ESourceProxy *extension, EProxyMethod method) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); if (method == extension->priv->method) return; extension->priv->method = method; g_object_notify (G_OBJECT (extension), "method"); } /** * e_source_proxy_get_autoconfig_url: * @extension: an #ESourceProxy * * Returns the URL that provides proxy configuration values. When the * @extension's #ESourceProxy:method is @E_PROXY_METHOD_AUTO, this URL * is used to look up proxy information for all protocols. * * Returns: the autoconfiguration URL * * Since: 3.12 **/ const gchar * e_source_proxy_get_autoconfig_url (ESourceProxy *extension) { g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); return extension->priv->autoconfig_url; } /** * e_source_proxy_dup_autoconfig_url: * @extension: an #ESourceProxy * * Thread-safe variation of e_source_proxy_get_autoconfig_url(). * Use this function when accessing @extension from multiple threads. * * The returned string should be freed with g_free() when no longer needed. * * Returns: a newly-allocated copy of #ESourceProxy:autoconfig-url * * Since: 3.12 **/ gchar * e_source_proxy_dup_autoconfig_url (ESourceProxy *extension) { const gchar *protected; gchar *duplicate; g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); protected = e_source_proxy_get_autoconfig_url (extension); duplicate = g_strdup (protected); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return duplicate; } /** * e_source_proxy_set_autoconfig_url: * @extension: an #ESourceProxy * @autoconfig_url: an autoconfiguration URL * * Sets the URL that provides proxy configuration values. When the * @extension's #ESourceProxy:method is @E_PROXY_METHOD_AUTO, this URL * is used to look up proxy information for all protocols. * * Since: 3.12 **/ void e_source_proxy_set_autoconfig_url (ESourceProxy *extension, const gchar *autoconfig_url) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); if (e_util_strcmp0 (autoconfig_url, extension->priv->autoconfig_url) == 0) { e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return; } g_free (extension->priv->autoconfig_url); extension->priv->autoconfig_url = e_util_strdup_strip (autoconfig_url); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); g_object_notify (G_OBJECT (extension), "autoconfig-url"); } /** * e_source_proxy_get_ignore_hosts: * @extension: an #ESourceProxy * * Returns a %NULL-terminated string array of hosts which are connected to * directly, rather than via the proxy (if it is active). The array elements * can be hostnames, domains (using an initial wildcard like *.foo.com), IP * host addresses (both IPv4 and IPv6) and network addresses with a netmask * (something like 192.168.0.0/24). * * The returned array is owned by @extension and should not be modified or * freed. * * Returns: (transfer none): a %NULL-terminated string array of hosts * * Since: 3.12 **/ const gchar * const * e_source_proxy_get_ignore_hosts (ESourceProxy *extension) { g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); return (const gchar * const *) extension->priv->ignore_hosts; } /** * e_source_proxy_dup_ignore_hosts: * @extension: an #ESourceProxy * * Thread-safe variation of e_source_proxy_get_ignore_hosts(). * Use this function when accessing @extension from multiple threads. * * The returned string array should be freed with g_strfreev() when no * longer needed. * * Returns: (transfer full): a newly-allocated copy of * #ESourceProxy:ignore-hosts * * Since: 3.12 **/ gchar ** e_source_proxy_dup_ignore_hosts (ESourceProxy *extension) { const gchar * const *protected; gchar **duplicate; g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); protected = e_source_proxy_get_ignore_hosts (extension); duplicate = g_strdupv ((gchar **) protected); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return duplicate; } /** * e_source_proxy_set_ignore_hosts: * @extension: an #ESourceProxy * @ignore_hosts: a %NULL-terminated string array of hosts * * Sets the hosts which are connected to directly, rather than via the proxy * (if it is active). The array elements can be hostnames, domains (using an * initial wildcard like *.foo.com), IP host addresses (both IPv4 and IPv6) * and network addresses with a netmask (something like 192.168.0.0/24). * * Since: 3.12 **/ void e_source_proxy_set_ignore_hosts (ESourceProxy *extension, const gchar * const *ignore_hosts) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); if (e_util_strv_equal (ignore_hosts, extension->priv->ignore_hosts)) { e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return; } g_strfreev (extension->priv->ignore_hosts); extension->priv->ignore_hosts = g_strdupv ((gchar **) ignore_hosts); /* Strip leading and trailing whitespace from each element. */ if (extension->priv->ignore_hosts != NULL) { guint length, ii; length = g_strv_length (extension->priv->ignore_hosts); for (ii = 0; ii < length; ii++) g_strstrip (extension->priv->ignore_hosts[ii]); } e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); g_object_notify (G_OBJECT (extension), "ignore-hosts"); } /** * e_source_proxy_get_ftp_host: * @extension: an #ESourceProxy * * Returns the machine name to proxy FTP through when @extension's * #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Returns: FTP proxy host name * * Since: 3.12 **/ const gchar * e_source_proxy_get_ftp_host (ESourceProxy *extension) { g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); return extension->priv->ftp_host; } /** * e_source_proxy_dup_ftp_host: * @extension: an #ESourceProxy * * Thread-safe variation of e_source_proxy_get_ftp_host(). * Use this function when accessing @extension from multiple threads. * * The returned string should be freed with g_free() when no longer needed. * * Returns: a newly-allocated copy of #ESourceProxy:ftp-host * * Since: 3.12 **/ gchar * e_source_proxy_dup_ftp_host (ESourceProxy *extension) { const gchar *protected; gchar *duplicate; g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); protected = e_source_proxy_get_ftp_host (extension); duplicate = g_strdup (protected); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return duplicate; } /** * e_source_proxy_set_ftp_host: * @extension: an #ESourceProxy * @ftp_host: FTP proxy host name * * Sets the machine name to proxy FTP through when @extension's * #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Since: 3.12 **/ void e_source_proxy_set_ftp_host (ESourceProxy *extension, const gchar *ftp_host) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); if (e_util_strcmp0 (ftp_host, extension->priv->ftp_host) == 0) { e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return; } g_free (extension->priv->ftp_host); extension->priv->ftp_host = e_util_strdup_strip (ftp_host); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); g_object_notify (G_OBJECT (extension), "ftp-host"); } /** * e_source_proxy_get_ftp_port: * @extension: an #ESourceProxy * * Returns the port on the machine defined by #ESourceProxy:ftp-host to proxy * through when @extension's #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Returns: FTP proxy port * * Since: 3.12 **/ guint16 e_source_proxy_get_ftp_port (ESourceProxy *extension) { g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), 0); return extension->priv->ftp_port; } /** * e_source_proxy_set_ftp_port: * @extension: an #ESourceProxy * @ftp_port: FTP proxy port * * Sets the port on the machine defined by #ESourceProxy:ftp-host to proxy * through when @extension's #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Since: 3.12 **/ void e_source_proxy_set_ftp_port (ESourceProxy *extension, guint16 ftp_port) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); if (ftp_port == extension->priv->ftp_port) return; extension->priv->ftp_port = ftp_port; g_object_notify (G_OBJECT (extension), "ftp-port"); } /** * e_source_proxy_get_http_host: * @extension: an #ESourceProxy * * Returns the machine name to proxy HTTP through when @extension's * #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Returns: HTTP proxy host name * * Since: 3.12 **/ const gchar * e_source_proxy_get_http_host (ESourceProxy *extension) { g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); return extension->priv->http_host; } /** * e_source_proxy_dup_http_host: * @extension: an #ESourceProxy * * Thread-safe variation of e_source_proxy_get_http_host(). * Use this function when accessing @extension from multiple threads. * * The returned string should be freed with g_free() when no longer needed. * * Returns: a newly-allocated copy of #ESourceProxy:http-host * * Since: 3.12 **/ gchar * e_source_proxy_dup_http_host (ESourceProxy *extension) { const gchar *protected; gchar *duplicate; g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); protected = e_source_proxy_get_http_host (extension); duplicate = g_strdup (protected); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return duplicate; } /** * e_source_proxy_set_http_host: * @extension: an #ESourceProxy * @http_host: HTTP proxy host name * * Sets the machine name to proxy HTTP through when @extension's * #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Since: 3.12 **/ void e_source_proxy_set_http_host (ESourceProxy *extension, const gchar *http_host) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); if (e_util_strcmp0 (http_host, extension->priv->http_host) == 0) { e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return; } g_free (extension->priv->http_host); extension->priv->http_host = e_util_strdup_strip (http_host); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); g_object_notify (G_OBJECT (extension), "http-host"); } /** * e_source_proxy_get_http_port: * @extension: an #ESourceProxy * * Returns the port on the machine defined by #ESourceProxy:http-host to proxy * through when @extension's #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Returns: HTTP proxy port * * Since: 3.12 **/ guint16 e_source_proxy_get_http_port (ESourceProxy *extension) { g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), 0); return extension->priv->http_port; } /** * e_source_proxy_set_http_port: * @extension: an #ESourceProxy * @http_port: HTTP proxy port * * Sets the port on the machine defined by #ESourceProxy:http-host to proxy * through when @extension's #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Since: 3.12 **/ void e_source_proxy_set_http_port (ESourceProxy *extension, guint16 http_port) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); if (http_port == extension->priv->http_port) return; extension->priv->http_port = http_port; g_object_notify (G_OBJECT (extension), "http-port"); } /** * e_source_proxy_get_http_use_auth: * @extension: an #ESourceProxy * * Returns whether the HTTP proxy server at #ESourceProxy:http-host and * #ESourceProxy:http-port requires authentication. * * The username/password combo is defined by #ESourceProxy:http-auth-user * and #ESourceProxy:http-auth-password, but only applies when @extension's * #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Returns: whether to authenticate HTTP proxy connections * * Since: 3.12 **/ gboolean e_source_proxy_get_http_use_auth (ESourceProxy *extension) { g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), FALSE); return extension->priv->http_use_auth; } /** * e_source_proxy_set_http_use_auth: * @extension: an #ESourceProxy * @http_use_auth: whether to authenticate HTTP proxy connections * * Sets whether the HTTP proxy server at #ESourceProxy:http-host and * #ESourceProxy:http-port requires authentication. * * The username/password combo is defined by #ESourceProxy:http-auth-user * and #ESourceProxy:http-auth-password, but only applies when @extension's * #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Since: 3.12 **/ void e_source_proxy_set_http_use_auth (ESourceProxy *extension, gboolean http_use_auth) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); if (http_use_auth == extension->priv->http_use_auth) return; extension->priv->http_use_auth = http_use_auth; g_object_notify (G_OBJECT (extension), "http-use-auth"); } /** * e_source_proxy_get_http_auth_user: * @extension: an #ESourceProxy * * Returns the user name to pass as authentication when doing HTTP proxying * and #ESourceProxy:http-use-auth is %TRUE. * * Returns: HTTP proxy username * * Since: 3.12 **/ const gchar * e_source_proxy_get_http_auth_user (ESourceProxy *extension) { g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); return extension->priv->http_auth_user; } /** * e_source_proxy_dup_http_auth_user: * @extension: an #ESourceProxy * * Thread-safe variation of e_source_proxy_get_http_auth_user(). * Use this function when accessing @extension from multiple threads. * * The returned string should be freed with g_free() when no longer needed. * * Returns: a newly-allocated copy of #ESourceProxy:http-auth-user * * Since: 3.12 **/ gchar * e_source_proxy_dup_http_auth_user (ESourceProxy *extension) { const gchar *protected; gchar *duplicate; g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); protected = e_source_proxy_get_http_auth_user (extension); duplicate = g_strdup (protected); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return duplicate; } /** * e_source_proxy_set_http_auth_user: * @extension: an #ESourceProxy * @http_auth_user: HTTP proxy username * * Sets the user name to pass as authentication when doing HTTP proxying * and #ESourceProxy:http-use-auth is %TRUE. * * Since: 3.12 **/ void e_source_proxy_set_http_auth_user (ESourceProxy *extension, const gchar *http_auth_user) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); if (e_util_strcmp0 (http_auth_user, extension->priv->http_auth_user) == 0) { e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return; } g_free (extension->priv->http_auth_user); extension->priv->http_auth_user = e_util_strdup_strip (http_auth_user); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); g_object_notify (G_OBJECT (extension), "http-auth-user"); } /** * e_source_proxy_get_http_auth_password: * @extension: an #ESourceProxy * * Returns the password to pass as authentication when doing HTTP proxying * and #ESourceProxy:http-use-auth is %TRUE. * * Returns: HTTP proxy password * * Since: 3.12 **/ const gchar * e_source_proxy_get_http_auth_password (ESourceProxy *extension) { g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); return extension->priv->http_auth_password; } /** * e_source_proxy_dup_http_auth_password: * @extension: an #ESourceProxy * * Thread-safe variation of e_source_proxy_get_http_auth_password(). * Use this function when accessing @extension from multiple threads. * * The returned string should be freed with g_free() when no longer needed. * * Returns: a newly-allocated copy of #ESourceProxy:http-auth-password * * Since: 3.12 **/ gchar * e_source_proxy_dup_http_auth_password (ESourceProxy *extension) { const gchar *protected; gchar *duplicate; g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); protected = e_source_proxy_get_http_auth_password (extension); duplicate = g_strdup (protected); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return duplicate; } /** * e_source_proxy_set_http_auth_password: * @extension: an #ESourceProxy * @http_auth_password: HTTP proxy password * * Sets the password to pass as authentication when doing HTTP proxying * and #ESourceProxy:http-use-auth is %TRUE. * * Since: 3.12 **/ void e_source_proxy_set_http_auth_password (ESourceProxy *extension, const gchar *http_auth_password) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); if (e_util_strcmp0 (http_auth_password, extension->priv->http_auth_password) == 0) { e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return; } g_free (extension->priv->http_auth_password); extension->priv->http_auth_password = e_util_strdup_strip (http_auth_password); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); g_object_notify (G_OBJECT (extension), "http-auth-password"); } /** * e_source_proxy_get_https_host: * @extension: an #ESourceProxy * * Returns the machine name to proxy secure HTTP through when @extension's * #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Returns: secure HTTP proxy host name * * Since: 3.12 **/ const gchar * e_source_proxy_get_https_host (ESourceProxy *extension) { g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); return extension->priv->https_host; } /** * e_source_proxy_dup_https_host: * @extension: an #ESourceProxy * * Threads-safe variation of e_source_proxy_get_https_host(). * Use this function when accessing @extension from multiple threads. * * The returned string should be freed with g_free() when no longer needed. * * Returns: a newly-allocated copy of #ESourceProxy:https-host * * Since: 3.12 **/ gchar * e_source_proxy_dup_https_host (ESourceProxy *extension) { const gchar *protected; gchar *duplicate; g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); protected = e_source_proxy_get_https_host (extension); duplicate = g_strdup (protected); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return duplicate; } /** * e_source_proxy_set_https_host: * @extension: an #ESourceProxy * @https_host: secure HTTP proxy host name * * Sets the machine name to proxy secure HTTP through when @extension's * #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Since: 3.12 **/ void e_source_proxy_set_https_host (ESourceProxy *extension, const gchar *https_host) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); if (e_util_strcmp0 (https_host, extension->priv->https_host) == 0) { e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return; } g_free (extension->priv->https_host); extension->priv->https_host = e_util_strdup_strip (https_host); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); g_object_notify (G_OBJECT (extension), "https-host"); } /** * e_source_proxy_get_https_port: * @extension: an #ESourceProxy * * Returns the port on the machine defined by #ESourceProxy:https-host to proxy * through when @extension's #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Returns: secure HTTP proxy port * * Since: 3.12 **/ guint16 e_source_proxy_get_https_port (ESourceProxy *extension) { g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), 0); return extension->priv->https_port; } /** * e_source_proxy_set_https_port: * @extension: an #ESourceProxy * @https_port: secure HTTP proxy port * * Sets the port on the machine defined by #ESourceProxy:https-host to proxy * through when @extension's #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Since: 3.12 **/ void e_source_proxy_set_https_port (ESourceProxy *extension, guint16 https_port) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); if (https_port == extension->priv->https_port) return; extension->priv->https_port = https_port; g_object_notify (G_OBJECT (extension), "https-port"); } /** * e_source_proxy_get_socks_host: * @extension: an #ESourceProxy * * Returns the machine name to use as a SOCKS proxy when @extension's * #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Returns: SOCKS proxy host name * * Since: 3.12 **/ const gchar * e_source_proxy_get_socks_host (ESourceProxy *extension) { g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); return extension->priv->socks_host; } /** * e_source_proxy_dup_socks_host: * @extension: an #ESourceProxy * * Thread-safe variation of e_source_proxy_get_socks_host(). * Use this function when accessing @extension from multiple threads. * * The returned string should be freed with g_free() when no longer needed. * * Returns: a newly-allocated copy of #ESourceProxy:socks-host * * Since: 3.12 **/ gchar * e_source_proxy_dup_socks_host (ESourceProxy *extension) { const gchar *protected; gchar *duplicate; g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), NULL); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); protected = e_source_proxy_get_socks_host (extension); duplicate = g_strdup (protected); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return duplicate; } /** * e_source_proxy_set_socks_host: * @extension: an #ESourceProxy * @socks_host: SOCKS proxy host name * * Sets the machine name to use as a SOCKS proxy when @extension's * #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Since: 3.12 **/ void e_source_proxy_set_socks_host (ESourceProxy *extension, const gchar *socks_host) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); e_source_extension_property_lock (E_SOURCE_EXTENSION (extension)); if (e_util_strcmp0 (socks_host, extension->priv->socks_host) == 0) { e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); return; } g_free (extension->priv->socks_host); extension->priv->socks_host = e_util_strdup_strip (socks_host); e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension)); g_object_notify (G_OBJECT (extension), "socks-host"); } /** * e_source_proxy_get_socks_port: * @extension: an #ESourceProxy * * Returns the port on the machine defined by #ESourceProxy:socks-host to proxy * through when @extension's #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Returns: SOCKS proxy port * * Since: 3.12 **/ guint16 e_source_proxy_get_socks_port (ESourceProxy *extension) { g_return_val_if_fail (E_IS_SOURCE_PROXY (extension), 0); return extension->priv->socks_port; } /** * e_source_proxy_set_socks_port: * @extension: an #ESourceProxy * @socks_port: SOCKS proxy port * * Sets the port on the machine defined by #ESourceProxy:socks-host to proxy * through when @extension's #ESourceProxy:method is @E_PROXY_METHOD_MANUAL. * * Since: 3.12 **/ void e_source_proxy_set_socks_port (ESourceProxy *extension, guint16 socks_port) { g_return_if_fail (E_IS_SOURCE_PROXY (extension)); if (socks_port == extension->priv->socks_port) return; extension->priv->socks_port = socks_port; g_object_notify (G_OBJECT (extension), "socks-port"); } /** * e_source_proxy_lookup_sync: * @source: an #ESource * @uri: a URI representing the destination to connect to * @cancellable: optional #GCancellable object, or %NULL * @error: return location for a #GError, or %NULL * * Looks into @source's #ESourceProxy extension to determine what proxy, * if any, to use to connect to @uri. The returned proxy URIs are of the * same form described by g_proxy_resolver_lookup(). * * The proxy extension's #ESourceProxy:method controls how proxy URIs are * determined: * * When using @E_PROXY_METHOD_DEFAULT, the function will defer to the * #GProxyResolver returned by g_proxy_resolver_get_default(). * * When using @E_PROXY_METHOD_MANUAL, the function will configure a * #GSimpleProxyResolver from the HTTP, HTTPS, FTP and SOCKS properties, * as well as #ESourceProxy:ignore-hosts. * * When using @E_PROXY_METHOD_AUTO, the function will execute a proxy * auto-config (PAC) file at #ESourceProxy:autoconfig-url. * * When using @E_PROXY_METHOD_NONE, the function will only return * direct://. * * If @source does not have an #ESourceProxy extension, the function sets * @error to @G_IO_ERROR_NOT_SUPPORTED and returns %NULL. * * Free the returned proxy URIs with g_strfreev() when finished with them. * * Returns: (transfer full) (nullable): a %NULL-terminated array of proxy URIs, * or %NULL * * Since: 3.12 **/ gchar ** e_source_proxy_lookup_sync (ESource *source, const gchar *uri, GCancellable *cancellable, GError **error) { GProxyResolver *resolver = NULL; ESourceProxy *extension; EProxyMethod method; const gchar *extension_name; gchar **proxies; g_return_val_if_fail (E_IS_SOURCE (source), NULL); g_return_val_if_fail (uri != NULL, NULL); extension_name = E_SOURCE_EXTENSION_PROXY; if (!e_source_has_extension (source, extension_name)) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Source ā€œ%sā€ does not support proxy lookups"), e_source_get_display_name (source)); return NULL; } extension = e_source_get_extension (source, extension_name); method = e_source_proxy_get_method (extension); if (method == E_PROXY_METHOD_DEFAULT) { resolver = g_proxy_resolver_get_default (); if (resolver != NULL) g_object_ref (resolver); } if (method == E_PROXY_METHOD_MANUAL) { gchar *ftp_proxy = NULL; gchar *http_proxy = NULL; gchar *https_proxy = NULL; gchar *socks_proxy = NULL; gchar **ignore_hosts; gchar *host; guint16 port; host = e_source_proxy_dup_ftp_host (extension); port = e_source_proxy_get_ftp_port (extension); if (host != NULL && port > 0) { ftp_proxy = g_strdup_printf ( "ftp://%s:%u", host, port); } g_free (host); host = e_source_proxy_dup_http_host (extension); port = e_source_proxy_get_http_port (extension); if (host != NULL && port > 0) { /* This one is a little more complicated. */ http_proxy = source_proxy_dup_http_proxy ( extension, host, port); } g_free (host); host = e_source_proxy_dup_https_host (extension); port = e_source_proxy_get_https_port (extension); if (host != NULL && port > 0) { https_proxy = g_strdup_printf ( "http://%s:%u", host, port); } g_free (host); host = e_source_proxy_dup_socks_host (extension); port = e_source_proxy_get_socks_port (extension); if (host != NULL && port > 0) { socks_proxy = g_strdup_printf ( "socks://%s:%u", host, port); } g_free (host); ignore_hosts = e_source_proxy_dup_ignore_hosts (extension); resolver = g_simple_proxy_resolver_new (NULL, ignore_hosts); g_strfreev (ignore_hosts); if (ftp_proxy != NULL) { g_simple_proxy_resolver_set_uri_proxy ( G_SIMPLE_PROXY_RESOLVER (resolver), "ftp", ftp_proxy); g_free (ftp_proxy); } if (https_proxy != NULL) { g_simple_proxy_resolver_set_uri_proxy ( G_SIMPLE_PROXY_RESOLVER (resolver), "https", https_proxy); g_free (https_proxy); } else if (http_proxy != NULL) { g_simple_proxy_resolver_set_uri_proxy ( G_SIMPLE_PROXY_RESOLVER (resolver), "https", http_proxy); } if (http_proxy != NULL) { g_simple_proxy_resolver_set_uri_proxy ( G_SIMPLE_PROXY_RESOLVER (resolver), "http", http_proxy); g_free (http_proxy); } if (socks_proxy != NULL) { g_simple_proxy_resolver_set_uri_proxy ( G_SIMPLE_PROXY_RESOLVER (resolver), "socks", socks_proxy); g_simple_proxy_resolver_set_default_proxy ( G_SIMPLE_PROXY_RESOLVER (resolver), socks_proxy); g_free (socks_proxy); } } if (method == E_PROXY_METHOD_AUTO) { proxies = source_proxy_lookup_pacrunner ( source, uri, cancellable, error); } else if (resolver != NULL) { proxies = g_proxy_resolver_lookup ( resolver, uri, cancellable, error); } else { proxies = source_proxy_direct (); } g_clear_object (&resolver); return proxies; } /* Helper for e_source_proxy_lookup() */ static void source_proxy_lookup_thread (GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable) { AsyncContext *async_context; GError *local_error = NULL; async_context = g_simple_async_result_get_op_res_gpointer (simple); async_context->proxies = e_source_proxy_lookup_sync ( E_SOURCE (object), async_context->uri, cancellable, &local_error); if (local_error != NULL) g_simple_async_result_take_error (simple, local_error); } /** * e_source_proxy_lookup: * @source: an #ESource * @uri: a URI representing the destination to connect to * @cancellable: optional #GCancellable object, or %NULL * @callback: a #GAsyncReadyCallback to call when the request is satisfied * @user_data: data to pass to the callback function * * Asynchronously determines what proxy, if any, to use to connect to @uri. * See e_source_proxy_lookup_sync() for more details. * * When the operation is finished, @callback will be called. You can then * call e_source_proxy_lookup_finish() to get the result of the operation. * * Since: 3.12 **/ void e_source_proxy_lookup (ESource *source, const gchar *uri, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *simple; AsyncContext *async_context; g_return_if_fail (E_IS_SOURCE (source)); g_return_if_fail (uri != NULL); async_context = g_slice_new0 (AsyncContext); async_context->uri = g_strdup (uri); simple = g_simple_async_result_new ( G_OBJECT (source), callback, user_data, e_source_proxy_lookup); g_simple_async_result_set_check_cancellable (simple, cancellable); g_simple_async_result_set_op_res_gpointer ( simple, async_context, (GDestroyNotify) async_context_free); g_simple_async_result_run_in_thread ( simple, source_proxy_lookup_thread, G_PRIORITY_DEFAULT, cancellable); g_object_unref (simple); } /** * e_source_proxy_lookup_finish: * @source: an #ESource * @result: a #GAsyncResult * @error: return location for a #GError, or %NULL * * Finishes the operation started with e_source_proxy_lookup(). * * Free the returned proxy URIs with g_strfreev() when finished with them. * * Returns: (transfer full) (nullable): a %NULL-terminated array of proxy * URIs, or %NULL * * Since: 3.12 **/ gchar ** e_source_proxy_lookup_finish (ESource *source, GAsyncResult *result, GError **error) { GSimpleAsyncResult *simple; AsyncContext *async_context; gchar **proxies; g_return_val_if_fail ( g_simple_async_result_is_valid ( result, G_OBJECT (source), e_source_proxy_lookup), NULL); simple = G_SIMPLE_ASYNC_RESULT (result); async_context = g_simple_async_result_get_op_res_gpointer (simple); if (g_simple_async_result_propagate_error (simple, error)) return NULL; g_return_val_if_fail (async_context->proxies != NULL, NULL); proxies = async_context->proxies; async_context->proxies = NULL; return proxies; }