[libsoup] Use GProxyResolver for all proxy resolving



commit fb09bf930c5e0e79b67fbbd323b46284591b8624
Author: Dan Winship <danw gnome org>
Date:   Sat Feb 16 19:20:18 2013 -0500

    Use GProxyResolver for all proxy resolving
    
    Finish up the GProxyResolver porting started in 2.42 by removing all
    the non-GProxyResolver proxy code from SoupSocket and SoupConnection
    and implementing SoupSession:proxy-uri in terms of
    GSimpleProxyResolver. If the user adds a SoupProxyResolverDefault to
    the session, just use its GProxyResolver directly instead. If the user
    adds any other kind of SoupProxyURIResolver to the session, use the
    new SoupProxyResolverWrapper, which is a GProxyResolver that
    translates from SoupProxyURIResolver.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=680273

 docs/reference/Makefile.am              |    3 +-
 docs/reference/libsoup-2.4-docs.sgml    |    1 -
 docs/reference/libsoup-2.4-sections.txt |   18 ---
 docs/reference/session-porting.xml      |   21 +++-
 libsoup/Makefile.am                     |    4 +-
 libsoup/soup-connection.c               |  146 ++++++--------------------
 libsoup/soup-connection.h               |    3 +-
 libsoup/soup-gnome-features.h           |    2 +-
 libsoup/soup-proxy-resolver-default.c   |   16 ++--
 libsoup/soup-proxy-resolver-gnome.c     |    3 +
 libsoup/soup-proxy-resolver-static.c    |  177 -------------------------------
 libsoup/soup-proxy-resolver-static.h    |   35 ------
 libsoup/soup-proxy-resolver-wrapper.c   |  167 +++++++++++++++++++++++++++++
 libsoup/soup-proxy-resolver-wrapper.h   |   34 ++++++
 libsoup/soup-proxy-resolver.h           |    2 +-
 libsoup/soup-proxy-uri-resolver.c       |   23 ++++-
 libsoup/soup-proxy-uri-resolver.h       |    3 +
 libsoup/soup-session.c                  |  131 ++++++++++++++---------
 18 files changed, 372 insertions(+), 417 deletions(-)
---
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index 29ff97e..36e7700 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -43,7 +43,8 @@ IGNORE_HFILES= soup.h soup-enum-types.h \
        soup-content-sniffer-stream.h soup-io-stream.h \
        soup-cache-input-stream.h soup-filter-input-stream.h \
        soup-cookie-jar-sqlite.h soup-requester.h soup-tld-private.h \
-       soup-misc-private.h
+       soup-misc-private.h soup-proxy-uri-resolver.h \
+       soup-proxy-resolver-wrapper.h
 
 # Images to copy into HTML directory.
 HTML_IMAGES = 
diff --git a/docs/reference/libsoup-2.4-docs.sgml b/docs/reference/libsoup-2.4-docs.sgml
index f28c605..ca92b86 100644
--- a/docs/reference/libsoup-2.4-docs.sgml
+++ b/docs/reference/libsoup-2.4-docs.sgml
@@ -53,7 +53,6 @@
     <xi:include href="xml/soup-cookie-jar-text.xml"/>
     <xi:include href="xml/soup-cookie-jar-db.xml"/>
     <xi:include href="xml/soup-logger.xml"/>
-    <xi:include href="xml/soup-proxy-uri-resolver.xml"/>
     <xi:include href="xml/soup-proxy-resolver-default.xml"/>
   </chapter>
 
diff --git a/docs/reference/libsoup-2.4-sections.txt b/docs/reference/libsoup-2.4-sections.txt
index 2fb9134..6b19310 100644
--- a/docs/reference/libsoup-2.4-sections.txt
+++ b/docs/reference/libsoup-2.4-sections.txt
@@ -1020,24 +1020,6 @@ soup_cookie_jar_db_get_type
 </SECTION>
 
 <SECTION>
-<FILE>soup-proxy-uri-resolver</FILE>
-<TITLE>SoupProxyURIResolver</TITLE>
-SoupProxyURIResolver
-SoupProxyURIResolverCallback
-soup_proxy_uri_resolver_get_proxy_uri_async
-soup_proxy_uri_resolver_get_proxy_uri_sync
-<SUBSECTION Standard>
-SoupProxyURIResolverInterface
-SOUP_IS_PROXY_URI_RESOLVER
-SOUP_IS_PROXY_URI_RESOLVER_CLASS
-SOUP_PROXY_URI_RESOLVER
-SOUP_PROXY_URI_RESOLVER_CLASS
-SOUP_PROXY_URI_RESOLVER_GET_CLASS
-SOUP_TYPE_PROXY_URI_RESOLVER
-soup_proxy_uri_resolver_get_type
-</SECTION>
-
-<SECTION>
 <FILE>soup-content-sniffer</FILE>
 <TITLE>SoupContentSniffer</TITLE>
 SoupContentSniffer
diff --git a/docs/reference/session-porting.xml b/docs/reference/session-porting.xml
index bf1aa41..67a433a 100644
--- a/docs/reference/session-porting.xml
+++ b/docs/reference/session-porting.xml
@@ -92,13 +92,26 @@ linkend="SoupSessionAsync"><type>SoupSessionAsync</type></link> and
   </listitem>
   <listitem>
     <para>
+      The new
+      <link linkend="SoupSession--proxy-resolver"><type>"proxy-resolver"</type></link>
+      property is now initialized to the default
+      <link linkend="GProxyResolver"><type>GProxyResolver</type></link>,
+      meaning that it will automatically use the user's system proxy
+      configuration. This replaces the use of the
+      <link linkend="SoupProxyResolverDefault"><type>SoupProxyResolverDefault</type></link>,
+      session feature in earlier releases. You can set this property to
+      <literal>NULL</literal> if you don't want to use proxies, and the
+      <link linkend="SoupSession--proxy-uri"><type>"proxy-uri"</type></link>
+      property still works if you want to use a single proxy for all requests.
+    </para>
+  </listitem>
+  <listitem>
+    <para>
       Every session gets a
-      <link linkend="SoupProxyResolverDefault"><type>SoupProxyResolverDefault</type></link>
-      and a
       <link linkend="SoupContentDecoder"><type>SoupContentDecoder</type></link>
       attached to it by default, meaning that it will automatically
-      use the user's system proxy configuration, and will handle (and
-      request) "gzip"- and "deflate"-encoded response bodies.
+      handle (and request) "gzip"- and "deflate"-encoded response
+      bodies.
     </para>
   </listitem>
 </itemizedlist>
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
index be35fc7..60920bd 100644
--- a/libsoup/Makefile.am
+++ b/libsoup/Makefile.am
@@ -161,8 +161,8 @@ libsoup_2_4_la_SOURCES =            \
        soup-path-map.c                 \
        soup-proxy-resolver.c           \
        soup-proxy-resolver-default.c   \
-       soup-proxy-resolver-static.h    \
-       soup-proxy-resolver-static.c    \
+       soup-proxy-resolver-wrapper.h   \
+       soup-proxy-resolver-wrapper.c   \
        soup-proxy-uri-resolver.c       \
        soup-request.c                  \
        soup-request-data.c             \
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index 7657fc9..c118410 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -19,8 +19,7 @@ typedef struct {
 
        SoupAddress *local_addr;
        SoupURI *remote_uri, *proxy_uri;
-       SoupProxyURIResolver *soup_proxy_resolver;
-       GProxyResolver *g_proxy_resolver;
+       GProxyResolver *proxy_resolver;
        GTlsDatabase *tlsdb;
        gboolean ssl, ssl_strict, ssl_fallback;
 
@@ -51,8 +50,7 @@ enum {
 
        PROP_LOCAL_ADDRESS,
        PROP_REMOTE_URI,
-       PROP_SOUP_PROXY_RESOLVER,
-       PROP_G_PROXY_RESOLVER,
+       PROP_PROXY_RESOLVER,
        PROP_SSL,
        PROP_SSL_CREDS,
        PROP_SSL_STRICT,
@@ -86,8 +84,7 @@ soup_connection_finalize (GObject *object)
        g_clear_pointer (&priv->remote_uri, soup_uri_free);
        g_clear_pointer (&priv->proxy_uri, soup_uri_free);
        g_clear_object (&priv->tlsdb);
-       g_clear_object (&priv->soup_proxy_resolver);
-       g_clear_object (&priv->g_proxy_resolver);
+       g_clear_object (&priv->proxy_resolver);
        g_clear_object (&priv->local_addr);
        g_clear_pointer (&priv->async_context, g_main_context_unref);
 
@@ -115,7 +112,6 @@ soup_connection_set_property (GObject *object, guint prop_id,
                              const GValue *value, GParamSpec *pspec)
 {
        SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
-       SoupProxyURIResolver *proxy_resolver;
 
        switch (prop_id) {
        case PROP_LOCAL_ADDRESS:
@@ -124,16 +120,8 @@ soup_connection_set_property (GObject *object, guint prop_id,
        case PROP_REMOTE_URI:
                priv->remote_uri = g_value_dup_boxed (value);
                break;
-       case PROP_SOUP_PROXY_RESOLVER:
-               proxy_resolver = g_value_get_object (value);
-               if (proxy_resolver && SOUP_IS_PROXY_RESOLVER_DEFAULT (proxy_resolver))
-                       priv->g_proxy_resolver = g_object_ref (g_proxy_resolver_get_default ());
-               else if (proxy_resolver)
-                       priv->soup_proxy_resolver = g_object_ref (proxy_resolver);
-               break;
-       case PROP_G_PROXY_RESOLVER:
-               if (g_value_get_object (value))
-                       priv->g_proxy_resolver = g_value_dup_object (value);
+       case PROP_PROXY_RESOLVER:
+               priv->proxy_resolver = g_value_dup_object (value);
                break;
        case PROP_SSL:
                priv->ssl = g_value_get_boolean (value);
@@ -267,15 +255,8 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
                                    SOUP_TYPE_URI,
                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
        g_object_class_install_property (
-               object_class, PROP_SOUP_PROXY_RESOLVER,
-               g_param_spec_object (SOUP_CONNECTION_SOUP_PROXY_RESOLVER,
-                                    "Proxy resolver",
-                                    "SoupProxyResolver to use",
-                                    SOUP_TYPE_PROXY_URI_RESOLVER,
-                                    G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
-       g_object_class_install_property (
-               object_class, PROP_G_PROXY_RESOLVER,
-               g_param_spec_object (SOUP_CONNECTION_G_PROXY_RESOLVER,
+               object_class, PROP_PROXY_RESOLVER,
+               g_param_spec_object (SOUP_CONNECTION_PROXY_RESOLVER,
                                     "Proxy resolver",
                                     "GProxyResolver to use",
                                     G_TYPE_PROXY_RESOLVER,
@@ -519,8 +500,7 @@ socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
                return;
        }
 
-       if (priv->g_proxy_resolver)
-               priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
+       priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
 
        if (priv->ssl && !priv->proxy_uri) {
                if (soup_socket_start_ssl (sock, data->cancellable)) {
@@ -538,55 +518,6 @@ socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
        socket_connect_finished (sock, status, data);
 }
 
-static void
-connect_async_to_uri (SoupConnectionAsyncConnectData *data, SoupURI *uri)
-{
-       SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
-       SoupAddress *remote_addr;
-
-       remote_addr = soup_address_new (uri->host, uri->port);
-       priv->socket =
-               soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, remote_addr,
-                                SOUP_SOCKET_SSL_CREDENTIALS, priv->tlsdb,
-                                SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
-                                SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
-                                SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
-                                SOUP_SOCKET_USE_THREAD_CONTEXT, priv->use_thread_context,
-                                SOUP_SOCKET_PROXY_RESOLVER, priv->g_proxy_resolver,
-                                SOUP_SOCKET_TIMEOUT, priv->io_timeout,
-                                SOUP_SOCKET_CLEAN_DISPOSE, TRUE,
-                                SOUP_SOCKET_LOCAL_ADDRESS, priv->local_addr,
-                                NULL);
-       g_object_unref (remote_addr);
-
-       data->event_id = g_signal_connect (priv->socket, "event",
-                                          G_CALLBACK (re_emit_socket_event),
-                                          data->conn);
-
-       soup_socket_connect_async (priv->socket, data->cancellable,
-                                  socket_connect_result, data);
-}
-
-static void
-proxy_resolver_result (SoupProxyURIResolver *resolver,
-                      guint status, SoupURI *proxy_uri,
-                      gpointer user_data)
-{
-       SoupConnectionAsyncConnectData *data = user_data;
-       SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
-
-       if (status != SOUP_STATUS_OK) {
-               socket_connect_finished (NULL, status, data);
-               return;
-       }
-
-       if (proxy_uri) {
-               priv->proxy_uri = soup_uri_copy (proxy_uri);
-               connect_async_to_uri (data, proxy_uri);
-       } else 
-               connect_async_to_uri (data, priv->remote_uri);
-}
-
 void
 soup_connection_connect_async (SoupConnection *conn,
                               GCancellable *cancellable,
@@ -595,7 +526,7 @@ soup_connection_connect_async (SoupConnection *conn,
 {
        SoupConnectionAsyncConnectData *data;
        SoupConnectionPrivate *priv;
-       GMainContext *async_context;
+       SoupAddress *remote_addr;
 
        g_return_if_fail (SOUP_IS_CONNECTION (conn));
        priv = SOUP_CONNECTION_GET_PRIVATE (conn);
@@ -609,22 +540,28 @@ soup_connection_connect_async (SoupConnection *conn,
        data->callback_data = user_data;
        data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
 
-       if (!priv->soup_proxy_resolver) {
-               connect_async_to_uri (data, priv->remote_uri);
-               return;
-       }
+       remote_addr = soup_address_new (priv->remote_uri->host,
+                                       priv->remote_uri->port);
+       priv->socket =
+               soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, remote_addr,
+                                SOUP_SOCKET_SSL_CREDENTIALS, priv->tlsdb,
+                                SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
+                                SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
+                                SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
+                                SOUP_SOCKET_USE_THREAD_CONTEXT, priv->use_thread_context,
+                                SOUP_SOCKET_PROXY_RESOLVER, priv->proxy_resolver,
+                                SOUP_SOCKET_TIMEOUT, priv->io_timeout,
+                                SOUP_SOCKET_CLEAN_DISPOSE, TRUE,
+                                SOUP_SOCKET_LOCAL_ADDRESS, priv->local_addr,
+                                NULL);
+       g_object_unref (remote_addr);
 
-       if (priv->use_thread_context)
-               async_context = g_main_context_get_thread_default ();
-       else
-               async_context = priv->async_context;
+       data->event_id = g_signal_connect (priv->socket, "event",
+                                          G_CALLBACK (re_emit_socket_event),
+                                          data->conn);
 
-       soup_proxy_uri_resolver_get_proxy_uri_async (priv->soup_proxy_resolver,
-                                                    priv->remote_uri,
-                                                    async_context,
-                                                    cancellable,
-                                                    proxy_resolver_result,
-                                                    data);
+       soup_socket_connect_async (priv->socket, data->cancellable,
+                                  socket_connect_result, data);
 }
 
 guint
@@ -632,7 +569,6 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
 {
        SoupConnectionPrivate *priv;
        guint status, event_id = 0;
-       SoupURI *connect_uri;
        SoupAddress *remote_addr;
 
        g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_STATUS_MALFORMED);
@@ -641,25 +577,10 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
 
        soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
 
-       if (priv->soup_proxy_resolver) {
-               status = soup_proxy_uri_resolver_get_proxy_uri_sync (priv->soup_proxy_resolver,
-                                                                    priv->remote_uri,
-                                                                    cancellable,
-                                                                    &priv->proxy_uri);
-               if (status != SOUP_STATUS_OK)
-                       goto fail;
-
-               if (priv->proxy_uri)
-                       connect_uri = priv->proxy_uri;
-               else
-                       connect_uri = priv->remote_uri;
-       } else
-               connect_uri = priv->remote_uri;
-
-       remote_addr = soup_address_new (connect_uri->host, connect_uri->port);
+       remote_addr = soup_address_new (priv->remote_uri->host, priv->remote_uri->port);
        priv->socket =
                soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, remote_addr,
-                                SOUP_SOCKET_PROXY_RESOLVER, priv->g_proxy_resolver,
+                                SOUP_SOCKET_PROXY_RESOLVER, priv->proxy_resolver,
                                 SOUP_SOCKET_SSL_CREDENTIALS, priv->tlsdb,
                                 SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
                                 SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
@@ -677,8 +598,7 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
        if (!SOUP_STATUS_IS_SUCCESSFUL (status))
                goto fail;
 
-       if (priv->g_proxy_resolver)
-               priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
+       priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
 
        if (priv->ssl && !priv->proxy_uri) {
                if (!soup_socket_start_ssl (priv->socket, cancellable))
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index dcfb56a..50fb701 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -41,8 +41,7 @@ typedef void  (*SoupConnectionCallback)        (SoupConnection   *conn,
 
 #define SOUP_CONNECTION_LOCAL_ADDRESS   "local-address"
 #define SOUP_CONNECTION_REMOTE_URI      "remote-uri"
-#define SOUP_CONNECTION_SOUP_PROXY_RESOLVER  "soup-proxy-resolver"
-#define SOUP_CONNECTION_G_PROXY_RESOLVER  "g-proxy-resolver"
+#define SOUP_CONNECTION_PROXY_RESOLVER  "proxy-resolver"
 #define SOUP_CONNECTION_SSL             "ssl"
 #define SOUP_CONNECTION_SSL_CREDENTIALS "ssl-creds"
 #define SOUP_CONNECTION_SSL_STRICT      "ssl-strict"
diff --git a/libsoup/soup-gnome-features.h b/libsoup/soup-gnome-features.h
index 648d504..18f37de 100644
--- a/libsoup/soup-gnome-features.h
+++ b/libsoup/soup-gnome-features.h
@@ -11,7 +11,7 @@
 G_BEGIN_DECLS
 
 SOUP_AVAILABLE_IN_2_26
-SOUP_DEPRECATED_IN_2_42_FOR(SOUP_TYPE_PROXY_RESOLVER_DEFAULT)
+SOUP_DEPRECATED_IN_2_42_FOR(SoupSession:proxy-resolver)
 GType soup_proxy_resolver_gnome_get_type (void);
 #define SOUP_TYPE_PROXY_RESOLVER_GNOME (soup_proxy_resolver_gnome_get_type ())
 
diff --git a/libsoup/soup-proxy-resolver-default.c b/libsoup/soup-proxy-resolver-default.c
index ee3b102..9149fee 100644
--- a/libsoup/soup-proxy-resolver-default.c
+++ b/libsoup/soup-proxy-resolver-default.c
@@ -9,6 +9,9 @@
 #include <config.h>
 #endif
 
+#undef SOUP_VERSION_MIN_REQUIRED
+#define SOUP_VERSION_MIN_REQUIRED SOUP_VERSION_2_42
+
 #include "soup-proxy-resolver-default.h"
 #include "soup.h"
 
@@ -19,14 +22,11 @@
  * #SoupProxyResolverDefault is a #SoupProxyURIResolver implementation
  * that uses the default gio GProxyResolver to resolve proxies.
  *
- * If you are using a plain #SoupSession (ie, not #SoupSessionAsync or
- * #SoupSessionSync), then a #SoupProxyResolverDefault will
- * automatically be added to the session. (You can use
- * %SOUP_SESSION_REMOVE_FEATURE_BY_TYPE at construct time if you don't
- * want this.) If you are using one of the deprecated #SoupSession
- * subclasses, you can add a #SoupProxyResolverDefault to your session
- * with soup_session_add_feature() or
- * soup_session_add_feature_by_type().
+ * Deprecated: In libsoup 2.44 and later, you can set the
+ * #SoupSession:proxy-resolver property to the resolver returned by
+ * g_proxy_resolver_get_default() to get the same effect. Note that
+ * for "plain" #SoupSessions (ie, not #SoupSessionAsync or
+ * #SoupSessionSync), this is done for you automatically.
  *
  * Since: 2.34
  */
diff --git a/libsoup/soup-proxy-resolver-gnome.c b/libsoup/soup-proxy-resolver-gnome.c
index bc42337..16a3468 100644
--- a/libsoup/soup-proxy-resolver-gnome.c
+++ b/libsoup/soup-proxy-resolver-gnome.c
@@ -9,6 +9,9 @@
 #include <config.h>
 #endif
 
+#undef SOUP_VERSION_MIN_REQUIRED
+#define SOUP_VERSION_MIN_REQUIRED SOUP_VERSION_2_40
+
 #include <string.h>
 
 #include "soup-proxy-resolver-gnome.h"
diff --git a/libsoup/soup-proxy-resolver-wrapper.c b/libsoup/soup-proxy-resolver-wrapper.c
new file mode 100644
index 0000000..e07664c
--- /dev/null
+++ b/libsoup/soup-proxy-resolver-wrapper.c
@@ -0,0 +1,167 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-proxy-resolver-wrapper.c: SoupProxyURIResolver -> GProxyResolver wrapper
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-proxy-resolver-wrapper.h"
+#include "soup.h"
+
+static void soup_proxy_resolver_wrapper_interface_init (GProxyResolverInterface *proxy_resolver_interface);
+
+G_DEFINE_TYPE_WITH_CODE (SoupProxyResolverWrapper, soup_proxy_resolver_wrapper, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER, 
soup_proxy_resolver_wrapper_interface_init);
+                        )
+
+static void
+soup_proxy_resolver_wrapper_init (SoupProxyResolverWrapper *resolver_wrapper)
+{
+}
+
+static void
+soup_proxy_resolver_wrapper_finalize (GObject *object)
+{
+       SoupProxyResolverWrapper *wrapper =
+               SOUP_PROXY_RESOLVER_WRAPPER (object);
+
+       g_clear_object (&wrapper->soup_resolver);
+
+       G_OBJECT_CLASS (soup_proxy_resolver_wrapper_parent_class)->finalize (object);
+}
+
+static char **
+convert_response (SoupURI *source_uri, guint status,
+                 SoupURI *proxy_uri, GError **error)
+{
+       char **proxies = NULL;
+
+       if (status == SOUP_STATUS_CANT_RESOLVE_PROXY) {
+               g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
+                            "%s (%s)", soup_status_get_phrase (status),
+                            source_uri->host);
+       } else if (status == SOUP_STATUS_CANT_CONNECT_PROXY) {
+               g_set_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_REFUSED,
+                            "%s (%s)", soup_status_get_phrase (status),
+                            source_uri->host);
+       } else {
+               g_return_val_if_fail (status == SOUP_STATUS_OK, NULL);
+
+               proxies = g_new (char *, 2);
+               proxies[0] = soup_uri_to_string (proxy_uri, FALSE);
+               proxies[1] = NULL;
+
+               soup_uri_free (proxy_uri);
+       }
+
+       return proxies;
+}
+
+static void
+wrapper_lookup_async_complete (SoupProxyURIResolver *resolver,
+                              guint status, SoupURI *proxy_uri,
+                              gpointer user_data)
+{
+       GTask *task = user_data;
+       SoupURI *source_uri = g_task_get_task_data (task);
+       char **proxies;
+       GError *error = NULL;
+
+       proxies = convert_response (source_uri, status, proxy_uri, &error);
+       if (error)
+               g_task_return_error (task, error);
+       else
+               g_task_return_pointer (task, proxies, (GDestroyNotify) g_strfreev);
+       g_object_unref (task);
+}
+
+static void
+soup_proxy_resolver_wrapper_lookup_async (GProxyResolver       *resolver,
+                                         const gchar          *uri,
+                                         GCancellable         *cancellable,
+                                         GAsyncReadyCallback   callback,
+                                         gpointer              user_data)
+{
+       SoupProxyResolverWrapper *wrapper =
+               SOUP_PROXY_RESOLVER_WRAPPER (resolver);
+       GTask *task;
+       SoupURI *source_uri;
+
+       task = g_task_new (resolver, cancellable, callback, user_data);
+       source_uri = soup_uri_new (uri);
+       g_task_set_task_data (task, source_uri, (GDestroyNotify) soup_uri_free);
+
+       G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+       soup_proxy_uri_resolver_get_proxy_uri_async (wrapper->soup_resolver,
+                                                    source_uri,
+                                                    g_main_context_get_thread_default (),
+                                                    cancellable,
+                                                    wrapper_lookup_async_complete,
+                                                    task);
+       G_GNUC_END_IGNORE_DEPRECATIONS;
+}
+
+static char **
+soup_proxy_resolver_wrapper_lookup_finish (GProxyResolver       *resolver,
+                                          GAsyncResult         *result,
+                                          GError              **error)
+{
+       return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+static gchar **
+soup_proxy_resolver_wrapper_lookup (GProxyResolver  *resolver,
+                                   const gchar     *uri,
+                                   GCancellable    *cancellable,
+                                   GError         **error)
+{
+       SoupProxyResolverWrapper *wrapper =
+               SOUP_PROXY_RESOLVER_WRAPPER (resolver);
+       SoupURI *source_uri, *proxy_uri;
+       guint status;
+       gchar **proxies;
+
+       source_uri = soup_uri_new (uri);
+       G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+       status = soup_proxy_uri_resolver_get_proxy_uri_sync (wrapper->soup_resolver,
+                                                            source_uri,
+                                                            cancellable,
+                                                            &proxy_uri);
+       G_GNUC_END_IGNORE_DEPRECATIONS;
+       proxies = convert_response (source_uri, status, proxy_uri, error);
+       soup_uri_free (source_uri);
+       return proxies;
+}
+
+static void
+soup_proxy_resolver_wrapper_class_init (SoupProxyResolverWrapperClass *static_class)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (static_class);
+
+       object_class->finalize = soup_proxy_resolver_wrapper_finalize;
+}
+
+static void
+soup_proxy_resolver_wrapper_interface_init (GProxyResolverInterface *proxy_resolver_interface)
+{
+       proxy_resolver_interface->lookup =
+               soup_proxy_resolver_wrapper_lookup;
+       proxy_resolver_interface->lookup_async =
+               soup_proxy_resolver_wrapper_lookup_async;
+       proxy_resolver_interface->lookup_finish =
+               soup_proxy_resolver_wrapper_lookup_finish;
+}
+
+GProxyResolver *
+soup_proxy_resolver_wrapper_new (SoupProxyURIResolver *soup_resolver)
+{
+       SoupProxyResolverWrapper *wrapper;
+
+       wrapper = g_object_new (SOUP_TYPE_PROXY_RESOLVER_WRAPPER, NULL);
+       wrapper->soup_resolver = g_object_ref (soup_resolver);
+       return (GProxyResolver *)wrapper;
+}
diff --git a/libsoup/soup-proxy-resolver-wrapper.h b/libsoup/soup-proxy-resolver-wrapper.h
new file mode 100644
index 0000000..d16b57c
--- /dev/null
+++ b/libsoup/soup-proxy-resolver-wrapper.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#ifndef SOUP_PROXY_RESOLVER_WRAPPER_H
+#define SOUP_PROXY_RESOLVER_WRAPPER_H 1
+
+#include "soup-proxy-uri-resolver.h"
+#include "soup-uri.h"
+
+#define SOUP_TYPE_PROXY_RESOLVER_WRAPPER            (soup_proxy_resolver_wrapper_get_type ())
+#define SOUP_PROXY_RESOLVER_WRAPPER(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), 
SOUP_TYPE_PROXY_RESOLVER_WRAPPER, SoupProxyResolverWrapper))
+#define SOUP_PROXY_RESOLVER_WRAPPER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), 
SOUP_TYPE_PROXY_RESOLVER_WRAPPER, SoupProxyResolverWrapperClass))
+#define SOUP_IS_PROXY_RESOLVER_WRAPPER(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), 
SOUP_TYPE_PROXY_RESOLVER_WRAPPER))
+#define SOUP_IS_PROXY_RESOLVER_WRAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), 
SOUP_TYPE_PROXY_RESOLVER_WRAPPER))
+#define SOUP_PROXY_RESOLVER_WRAPPER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), 
SOUP_TYPE_PROXY_RESOLVER_WRAPPER, SoupProxyResolverWrapperClass))
+
+typedef struct {
+       GObject parent;
+
+       SoupProxyURIResolver *soup_resolver;
+} SoupProxyResolverWrapper;
+
+typedef struct {
+       GObjectClass parent_class;
+
+} SoupProxyResolverWrapperClass;
+
+GType soup_proxy_resolver_wrapper_get_type (void);
+
+GProxyResolver *soup_proxy_resolver_wrapper_new (SoupProxyURIResolver *soup_resolver);
+
+#endif /* SOUP_PROXY_RESOLVER_WRAPPER_H */
diff --git a/libsoup/soup-proxy-resolver.h b/libsoup/soup-proxy-resolver.h
index 8798956..72e4885 100644
--- a/libsoup/soup-proxy-resolver.h
+++ b/libsoup/soup-proxy-resolver.h
@@ -39,7 +39,7 @@ typedef struct {
 
 } SoupProxyResolverInterface;
 
-SOUP_DEPRECATED_IN_2_28_FOR(SoupProxyURIResolver)
+SOUP_DEPRECATED_IN_2_28
 GType soup_proxy_resolver_get_type (void);
 
 SOUP_DEPRECATED_IN_2_28
diff --git a/libsoup/soup-proxy-uri-resolver.c b/libsoup/soup-proxy-uri-resolver.c
index ca49b90..f075a0f 100644
--- a/libsoup/soup-proxy-uri-resolver.c
+++ b/libsoup/soup-proxy-uri-resolver.c
@@ -9,6 +9,9 @@
 #include <config.h>
 #endif
 
+#undef SOUP_VERSION_MIN_REQUIRED
+#define SOUP_VERSION_MIN_REQUIRED SOUP_VERSION_2_42
+
 #include "soup-proxy-uri-resolver.h"
 #include "soup.h"
 
@@ -19,12 +22,18 @@
  * #SoupProxyURIResolver is an interface for finding appropriate HTTP
  * proxies to use.
  *
- * You are not likely to have to implement this interface on your own;
- * instead, you should usually just be able to use
- * #SoupProxyResolverDefault.
+ * Deprecated: #SoupSession now has a #SoupSession:proxy-resolver
+ * property that takes a #GProxyResolver (which is semantically
+ * identical to #SoupProxyURIResolver).
+ *
+ * Even in older releases of libsoup, you are not likely to have to
+ * implement this interface on your own; instead, you should usually
+ * just be able to use #SoupProxyResolverDefault.
  */
 
-G_DEFINE_INTERFACE (SoupProxyURIResolver, soup_proxy_uri_resolver, G_TYPE_OBJECT)
+G_DEFINE_INTERFACE_WITH_CODE (SoupProxyURIResolver, soup_proxy_uri_resolver, G_TYPE_OBJECT,
+                             g_type_interface_add_prerequisite (g_define_type_id, SOUP_TYPE_SESSION_FEATURE);
+                             )
 
 static void
 soup_proxy_uri_resolver_default_init (SoupProxyURIResolverInterface *iface)
@@ -54,6 +63,9 @@ soup_proxy_uri_resolver_default_init (SoupProxyURIResolverInterface *iface)
  * @callback.
  *
  * Since: 2.26.3
+ *
+ * Deprecated: #SoupProxyURIResolver is deprecated in favor of
+ * #GProxyResolver
  **/
 void
 soup_proxy_uri_resolver_get_proxy_uri_async (SoupProxyURIResolver  *proxy_uri_resolver,
@@ -84,6 +96,9 @@ soup_proxy_uri_resolver_get_proxy_uri_async (SoupProxyURIResolver  *proxy_uri_re
  * error.
  *
  * Since: 2.26.3
+ *
+ * Deprecated: #SoupProxyURIResolver is deprecated in favor of
+ * #GProxyResolver
  **/
 guint
 soup_proxy_uri_resolver_get_proxy_uri_sync (SoupProxyURIResolver  *proxy_uri_resolver,
diff --git a/libsoup/soup-proxy-uri-resolver.h b/libsoup/soup-proxy-uri-resolver.h
index 95c118f..e203125 100644
--- a/libsoup/soup-proxy-uri-resolver.h
+++ b/libsoup/soup-proxy-uri-resolver.h
@@ -44,9 +44,11 @@ typedef struct {
 } SoupProxyURIResolverInterface;
 
 SOUP_AVAILABLE_IN_2_28
+SOUP_DEPRECATED_IN_2_44
 GType soup_proxy_uri_resolver_get_type (void);
 
 SOUP_AVAILABLE_IN_2_28
+SOUP_DEPRECATED_IN_2_44
 void  soup_proxy_uri_resolver_get_proxy_uri_async (SoupProxyURIResolver  *proxy_uri_resolver,
                                                   SoupURI               *uri,
                                                   GMainContext          *async_context,
@@ -54,6 +56,7 @@ void  soup_proxy_uri_resolver_get_proxy_uri_async (SoupProxyURIResolver  *proxy_
                                                   SoupProxyURIResolverCallback callback,
                                                   gpointer                user_data);
 SOUP_AVAILABLE_IN_2_28
+SOUP_DEPRECATED_IN_2_44
 guint soup_proxy_uri_resolver_get_proxy_uri_sync  (SoupProxyURIResolver  *proxy_uri_resolver,
                                                   SoupURI               *uri,
                                                   GCancellable          *cancellable,
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 627a684..95436f3 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -19,7 +19,7 @@
 #include "soup-message-private.h"
 #include "soup-misc-private.h"
 #include "soup-message-queue.h"
-#include "soup-proxy-resolver-static.h"
+#include "soup-proxy-resolver-wrapper.h"
 #include "soup-session-private.h"
 
 #define HOST_KEEP_ALIVE 5 * 60 * 1000 /* 5 min in msecs */
@@ -121,7 +121,8 @@ typedef struct {
        GSList *run_queue_sources;
 
        GResolver *resolver;
-       GProxyResolver *g_proxy_resolver;
+       GProxyResolver *proxy_resolver;
+       SoupURI *proxy_uri;
 
        char **http_aliases, **https_aliases;
 
@@ -278,8 +279,9 @@ soup_session_constructor (GType                  type,
 
                priv->http_aliases[0] = NULL;
 
+               priv->proxy_resolver = g_object_ref (g_proxy_resolver_get_default ());
+
                soup_session_add_feature_by_type (session, SOUP_TYPE_CONTENT_DECODER);
-               soup_session_add_feature_by_type (session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
        }
 
        return object;
@@ -336,7 +338,8 @@ soup_session_finalize (GObject *object)
        g_hash_table_destroy (priv->features_cache);
 
        g_object_unref (priv->resolver);
-       g_clear_object (&priv->g_proxy_resolver);
+       g_clear_object (&priv->proxy_resolver);
+       g_clear_pointer (&priv->proxy_uri, soup_uri_free);
 
        g_free (priv->http_aliases);
        g_free (priv->https_aliases);
@@ -548,12 +551,42 @@ set_aliases (char ***variable, char **value)
 }
 
 static void
+set_proxy_resolver (SoupSession *session, SoupURI *uri,
+                   SoupProxyURIResolver *soup_resolver,
+                   GProxyResolver *g_resolver)
+{
+       SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
+
+       G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+       soup_session_remove_feature_by_type (session, SOUP_TYPE_PROXY_URI_RESOLVER);
+       G_GNUC_END_IGNORE_DEPRECATIONS;
+       g_clear_object (&priv->proxy_resolver);
+       g_clear_pointer (&priv->proxy_uri, soup_uri_free);
+
+       if (uri) {
+               char *uri_string;
+
+               priv->proxy_uri = soup_uri_copy (uri);
+               uri_string = soup_uri_to_string (uri, FALSE);
+               priv->proxy_resolver = g_simple_proxy_resolver_new (uri_string, NULL);
+               g_free (uri_string);
+       } else if (soup_resolver) {
+               G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+               if (SOUP_IS_PROXY_RESOLVER_DEFAULT (soup_resolver))
+                       priv->proxy_resolver = g_object_ref (g_proxy_resolver_get_default ());
+               else
+                       priv->proxy_resolver = soup_proxy_resolver_wrapper_new (soup_resolver);
+               G_GNUC_END_IGNORE_DEPRECATIONS;
+       } else if (g_resolver)
+               priv->proxy_resolver = g_object_ref (g_resolver);
+}
+
+static void
 soup_session_set_property (GObject *object, guint prop_id,
                           const GValue *value, GParamSpec *pspec)
 {
        SoupSession *session = SOUP_SESSION (object);
        SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
-       SoupURI *uri;
        const char *user_agent;
        SoupSessionFeature *feature;
        GMainContext *async_context;
@@ -563,26 +596,13 @@ soup_session_set_property (GObject *object, guint prop_id,
                priv->local_addr = g_value_dup_object (value);
                break;
        case PROP_PROXY_URI:
-               uri = g_value_get_boxed (value);
-               if (uri) {
-                       G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
-                       soup_session_remove_feature_by_type (session, SOUP_TYPE_PROXY_RESOLVER);
-                       G_GNUC_END_IGNORE_DEPRECATIONS;
-                       feature = SOUP_SESSION_FEATURE (soup_proxy_resolver_static_new (uri));
-                       soup_session_add_feature (session, feature);
-                       g_object_unref (feature);
-               } else
-                       soup_session_remove_feature_by_type (session, SOUP_TYPE_PROXY_RESOLVER_STATIC);
-               g_clear_object (&priv->g_proxy_resolver);
+               set_proxy_resolver (session, g_value_get_boxed (value),
+                                   NULL, NULL);
                soup_session_abort (session);
                break;
        case PROP_PROXY_RESOLVER:
-               G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
-               soup_session_remove_feature_by_type (session, SOUP_TYPE_PROXY_RESOLVER);
-               G_GNUC_END_IGNORE_DEPRECATIONS;
-               if (priv->g_proxy_resolver)
-                       g_object_unref (priv->g_proxy_resolver);
-               priv->g_proxy_resolver = g_value_dup_object (value);
+               set_proxy_resolver (session, NULL, NULL,
+                                   g_value_get_object (value));
                break;
        case PROP_MAX_CONNS:
                priv->max_conns = g_value_get_int (value);
@@ -705,16 +725,10 @@ soup_session_get_property (GObject *object, guint prop_id,
                g_value_set_object (value, priv->local_addr);
                break;
        case PROP_PROXY_URI:
-               feature = soup_session_get_feature (session, SOUP_TYPE_PROXY_RESOLVER_STATIC);
-               if (feature) {
-                       g_object_get_property (G_OBJECT (feature),
-                                              SOUP_PROXY_RESOLVER_STATIC_PROXY_URI,
-                                              value);
-               } else
-                       g_value_set_boxed (value, NULL);
+               g_value_set_boxed (value, priv->proxy_uri);
                break;
        case PROP_PROXY_RESOLVER:
-               g_value_set_object (value, priv->g_proxy_resolver);
+               g_value_set_object (value, priv->proxy_resolver);
                break;
        case PROP_MAX_CONNS:
                g_value_set_int (value, priv->max_conns);
@@ -1676,8 +1690,7 @@ get_connection_for_host (SoupSession *session,
        conn = g_object_new (
                SOUP_TYPE_CONNECTION,
                SOUP_CONNECTION_REMOTE_URI, host->uri,
-               SOUP_CONNECTION_SOUP_PROXY_RESOLVER, soup_session_get_feature (session, 
SOUP_TYPE_PROXY_URI_RESOLVER),
-               SOUP_CONNECTION_G_PROXY_RESOLVER, priv->g_proxy_resolver,
+               SOUP_CONNECTION_PROXY_RESOLVER, priv->proxy_resolver,
                SOUP_CONNECTION_SSL, uri_is_https (priv, soup_message_get_uri (item->msg)),
                SOUP_CONNECTION_SSL_CREDENTIALS, priv->tlsdb,
                SOUP_CONNECTION_SSL_STRICT, priv->ssl_strict && (priv->tlsdb != NULL || SOUP_IS_PLAIN_SESSION 
(session)),
@@ -2463,9 +2476,8 @@ soup_session_prefetch_dns (SoupSession *session, const char *hostname,
  * feature to the session at construct time by using the
  * %SOUP_SESSION_ADD_FEATURE property.
  *
- * Note that a #SoupProxyResolverDefault and a #SoupContentDecoder are
- * added to the session by default (unless you are using one of the
- * deprecated session subclasses).
+ * Note that a #SoupContentDecoder is added to the session by default
+ * (unless you are using one of the deprecated session subclasses).
  *
  * Since: 2.24
  **/
@@ -2479,8 +2491,13 @@ soup_session_add_feature (SoupSession *session, SoupSessionFeature *feature)
 
        priv = SOUP_SESSION_GET_PRIVATE (session);
 
-       if (SOUP_IS_PROXY_URI_RESOLVER (feature))
-               g_clear_object (&priv->g_proxy_resolver);
+       G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+       if (SOUP_IS_PROXY_URI_RESOLVER (feature)) {
+               set_proxy_resolver (session, NULL,
+                                   SOUP_PROXY_URI_RESOLVER (feature),
+                                   NULL);
+       }
+       G_GNUC_END_IGNORE_DEPRECATIONS;
 
        priv->features = g_slist_prepend (priv->features, g_object_ref (feature));
        g_hash_table_remove_all (priv->features_cache);
@@ -2505,9 +2522,8 @@ soup_session_add_feature (SoupSession *session, SoupSessionFeature *feature)
  * You can also add a feature to the session at construct time by
  * using the %SOUP_SESSION_ADD_FEATURE_BY_TYPE property.
  *
- * Note that a #SoupProxyResolverDefault and a #SoupContentDecoder are
- * added to the session by default (unless you are using one of the
- * deprecated session subclasses).
+ * Note that a #SoupContentDecoder is added to the session by default
+ * (unless you are using one of the deprecated session subclasses).
  *
  * Since: 2.24
  **/
@@ -2568,6 +2584,15 @@ soup_session_remove_feature (SoupSession *session, SoupSessionFeature *feature)
                priv->features = g_slist_remove (priv->features, feature);
                g_hash_table_remove_all (priv->features_cache);
                soup_session_feature_detach (feature, session);
+
+               G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+               if (SOUP_IS_PROXY_URI_RESOLVER (feature)) {
+                       if (SOUP_IS_PROXY_RESOLVER_WRAPPER (priv->proxy_resolver) &&
+                           SOUP_PROXY_RESOLVER_WRAPPER (priv->proxy_resolver)->soup_resolver == 
SOUP_PROXY_URI_RESOLVER (feature))
+                               g_clear_object (&priv->proxy_resolver);
+               }
+               G_GNUC_END_IGNORE_DEPRECATIONS;
+
                g_object_unref (feature);
        }
 }
@@ -2976,16 +3001,23 @@ soup_session_class_init (SoupSessionClass *session_class)
        /**
         * SoupSession:proxy-uri:
         *
-        * An http proxy to use for all http and https requests in
-        * this session. Setting this will remove any
+        * A proxy to use for all http and https requests in this
+        * session. Setting this will clear the
+        * #SoupSession:proxy-resolver property, and remove any
         * #SoupProxyURIResolver features that have been added to the
         * session. Setting this property will also cancel all
         * currently pending messages.
         *
-        * Note that #SoupProxyResolverDefault will handle looking up
-        * the user's proxy settings for you; you should only use
+        * Note that #SoupSession will normally handle looking up the
+        * user's proxy settings for you; you should only use
         * #SoupSession:proxy-uri if you need to override the user's
         * normal proxy settings.
+        *
+        * Also note that this proxy will be used for
+        * <emphasis>all</emphasis> requests; even requests to
+        * <literal>localhost</literal>. If you need more control over
+        * proxies, you can create a #GSimpleProxyResolver and set the
+        * #SoupSession:proxy-resolver property.
         */
        /**
         * SOUP_SESSION_PROXY_URI:
@@ -3007,12 +3039,11 @@ soup_session_class_init (SoupSessionClass *session_class)
         * any #SoupProxyURIResolver features that have been added to
         * the session.
         *
-        * You only need to set this if you want to manually control
-        * proxy resolution (and need to do something more complicated than
-        * #SoupSession:proxy-uri allows). If you just want to use the
-        * system proxy settings, #SoupProxyResolverDefault will do that
-        * for you, and that is automatically part of the session if you
-        * are using a plain #SoupSession.
+        * By default, in a plain #SoupSession, this is set to the
+        * default #GProxyResolver, but you can set it to %NULL if you
+        * don't want to use proxies, or set it to your own
+        * #GProxyResolver if you want to control what proxies get
+        * used.
         *
         * Since: 2.42
         */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]