[evolution-ews] Clean up Negotiate auth implementation to be a SoupAuth subclass



commit fe826a4271e8860ae83dd2c7f11a4010b7c0d897
Author: Daniel Sands <dnsands sandia gov>
Date:   Wed Jul 23 12:14:09 2014 +0100

    Clean up Negotiate auth implementation to be a SoupAuth subclass
    
    It would still be better if libsoup did this for us (cf. bug 587145) but
    this is at least slightly cleaner than what we had before. And hopefully
    leaves us in a better position to migrate to a 'real' solution provided
    by libsoup... if that ever actually materialises.

 src/server/Makefile.am              |    2 +
 src/server/e-ews-connection-utils.c |  160 -----------------
 src/server/e-ews-connection-utils.h |    4 -
 src/server/e-ews-connection.c       |   16 +-
 src/server/e-ews-notification.c     |   21 +--
 src/server/e-soup-auth-negotiate.c  |  337 +++++++++++++++++++++++++++++++++++
 src/server/e-soup-auth-negotiate.h  |   26 +++
 7 files changed, 377 insertions(+), 189 deletions(-)
---
diff --git a/src/server/Makefile.am b/src/server/Makefile.am
index 6b90322..d0f559d 100644
--- a/src/server/Makefile.am
+++ b/src/server/Makefile.am
@@ -60,6 +60,8 @@ libeews_1_2_la_SOURCES = \
        e-soap-response.h \
        e-source-ews-folder.c \
        e-source-ews-folder.h \
+       e-soup-auth-negotiate.c \
+       e-soup-auth-negotiate.h \
        $(NULL)
 
 libeews_1_2_la_LIBADD = \
diff --git a/src/server/e-ews-connection-utils.c b/src/server/e-ews-connection-utils.c
index d59975c..7bff7b7 100644
--- a/src/server/e-ews-connection-utils.c
+++ b/src/server/e-ews-connection-utils.c
@@ -28,166 +28,6 @@
 #include "e-ews-connection-utils.h"
 #include "camel-ews-settings.h"
 
-#define EWS_GSSAPI_SOUP_SESSION "ews-gssapi-soup-session"
-#define EWS_GSSAPI_SASL                "ews-gssapi-sasl"
-#define EWS_GSSAPI_CONNECTION  "ews-gssapi-connection"
-
-static gchar *
-ews_connection_utils_gssapi_challenge (CamelSasl *sasl,
-                                      const gchar *what,
-                                      gboolean is_base64,
-                                      GError **error)
-{
-       GByteArray *ain, *aout = NULL;
-       gchar *response = NULL;
-       GError *local_error = NULL;
-
-       g_return_val_if_fail (sasl != NULL, NULL);
-
-       ain = g_byte_array_new ();
-
-       if (what && *what) {
-               if (is_base64) {
-                       guchar *bytes;
-                       gsize len = 0;
-
-                       bytes = g_base64_decode (what, &len);
-                       if (bytes) {
-                               g_byte_array_append (ain, bytes, len);
-                               g_free (bytes);
-                       }
-               } else {
-                       g_byte_array_append (ain, (const guchar *) what, strlen (what));
-               }
-       }
-
-       aout = camel_sasl_challenge_sync (sasl, ain, NULL, &local_error);
-
-       if (local_error) {
-               g_propagate_error (error, local_error);
-       } else if (aout && aout->len) {
-               response = g_base64_encode (aout->data, aout->len);
-       } else {
-               response = g_strdup ("");
-       }
-
-       g_byte_array_unref (ain);
-
-       if (aout)
-               g_byte_array_unref (aout);
-
-       return response;
-}
-
-static void
-ews_connection_utils_authenticate_gssapi_cb (SoupMessage *message,
-                                            gpointer user_data)
-{
-       EEwsConnection *connection = g_object_get_data (G_OBJECT (message), EWS_GSSAPI_CONNECTION);
-       SoupSession *session = g_object_get_data (G_OBJECT (message), EWS_GSSAPI_SOUP_SESSION);
-       CamelSasl *sasl = g_object_get_data (G_OBJECT (message), EWS_GSSAPI_SASL);
-       const gchar *auths_lst;
-       gchar **auths;
-       gint ii;
-
-       g_return_if_fail (E_IS_EWS_CONNECTION (connection));
-       g_return_if_fail (SOUP_IS_SESSION (session));
-       g_return_if_fail (CAMEL_IS_SASL (sasl));
-
-       if (SOUP_STATUS_IS_SUCCESSFUL (message->status_code))
-               return;
-
-       auths_lst = soup_message_headers_get_list (message->response_headers, "WWW-Authenticate");
-       if (!auths_lst)
-               return;
-
-       auths = g_strsplit (auths_lst, ",", -1);
-       for (ii = 0; auths && auths[ii]; ii++) {
-               if (g_ascii_strncasecmp (auths[ii], "Negotiate", 9) == 0) {
-                       GError *error = NULL;
-                       const gchar *chlg = auths[ii] + 9;
-                       gchar *response;
-
-                       if (*chlg)
-                               chlg++;
-                       if (!*chlg)
-                               chlg = NULL;
-
-                       response = ews_connection_utils_gssapi_challenge (
-                               sasl, chlg ? chlg : "\r\n", chlg != NULL, &error);
-
-                       if (response && *response) {
-                               gchar *sasl_response = g_strconcat ("Negotiate ", response, NULL);
-
-                               soup_message_headers_remove (message->request_headers, "Authorization");
-                               soup_message_headers_append (message->request_headers, "Authorization", 
sasl_response);
-                               soup_session_requeue_message (session, message);
-
-                               g_free (sasl_response);
-                       } else if (error) {
-                               /* cannot use SOUP_STATUS_UNAUTHORIZED, because it may hide an error message,
-                                  which is a local error of Kerberos/GSSAPI call */
-                               soup_message_set_status_full (message, SOUP_STATUS_BAD_REQUEST, 
error->message);
-                       }
-
-                       g_free (response);
-                       break;
-               }
-       }
-
-       g_strfreev (auths);
-}
-
-void
-e_ews_connection_utils_setup_msg_gssapi_auth (EEwsConnection *connection,
-                                             SoupSession *session,
-                                             SoupMessage *message)
-{
-       CamelSasl *gssapi_sasl;
-       CamelEwsSettings *ews_settings;
-       CamelNetworkSettings *network_settings;
-       SoupURI *soup_uri;
-       const gchar *host, *user;
-
-       if (!camel_sasl_gssapi_is_available ())
-               return;
-
-       g_return_if_fail (E_IS_EWS_CONNECTION (connection));
-       g_return_if_fail (SOUP_IS_MESSAGE (message));
-
-       ews_settings = e_ews_connection_ref_settings (connection);
-       network_settings = CAMEL_NETWORK_SETTINGS (ews_settings);
-       gssapi_sasl = g_object_new (
-               camel_sasl_gssapi_get_type (),
-               "mechanism", "GSSAPI",
-               "service-name", "HTTP",
-               NULL);
-
-       soup_uri = soup_message_get_uri (message);
-       host = soup_uri_get_host (soup_uri);
-       user = soup_uri_get_user (soup_uri);
-       if (!host || !*host)
-               host = camel_network_settings_get_host (network_settings);
-       if (!user || !*user)
-               user = camel_network_settings_get_user (network_settings);
-
-       camel_sasl_gssapi_override_host_and_user (CAMEL_SASL_GSSAPI (gssapi_sasl), host, user);
-
-       /* this might not be a cyclic ref dependency, as long as the message
-          is properly served through the session and freed */
-       g_object_set_data_full (G_OBJECT (message), EWS_GSSAPI_SOUP_SESSION,
-               g_object_ref (session), g_object_unref);
-       g_object_set_data_full (G_OBJECT (message), EWS_GSSAPI_CONNECTION,
-               g_object_ref (connection), e_ews_connection_utils_unref_in_thread);
-       g_object_set_data_full (G_OBJECT (message), EWS_GSSAPI_SASL,
-               gssapi_sasl, g_object_unref);
-
-       soup_message_add_header_handler (message, "got_body", "WWW-Authenticate",
-               G_CALLBACK (ews_connection_utils_authenticate_gssapi_cb), NULL);
-
-       g_object_unref (ews_settings);
-}
-
 static gpointer
 ews_unref_in_thread_func (gpointer data)
 {
diff --git a/src/server/e-ews-connection-utils.h b/src/server/e-ews-connection-utils.h
index a640e6c..3de7d13 100644
--- a/src/server/e-ews-connection-utils.h
+++ b/src/server/e-ews-connection-utils.h
@@ -27,10 +27,6 @@ G_BEGIN_DECLS
 #define E_EWS_CONNECTION_UTILS_CHECK_ELEMENT(element_name, expected_name) \
        (e_ews_connection_utils_check_element (G_STRFUNC, (element_name), (expected_name)))
 
-void           e_ews_connection_utils_setup_msg_gssapi_auth
-                                                       (EEwsConnection *connection,
-                                                        SoupSession *session,
-                                                        SoupMessage *message);
 void           e_ews_connection_utils_unref_in_thread  (gpointer object);
 gboolean       e_ews_connection_utils_check_element    (const gchar *function_name,
                                                         const gchar *element_name,
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index 6b195f4..117f3bb 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -46,6 +46,7 @@
 #include "e-ews-item-change.h"
 #include "e-ews-debug.h"
 #include "e-ews-notification.h"
+#include "e-soup-auth-negotiate.h"
 
 #define d(x) x
 
@@ -653,13 +654,6 @@ ews_next_request (gpointer _cnc)
 
        if (cnc->priv->soup_session) {
                SoupMessage *msg = SOUP_MESSAGE (node->msg);
-               CamelEwsSettings *ews_settings = e_ews_connection_ref_settings (cnc);
-
-               if (camel_ews_settings_get_auth_mechanism (ews_settings) ==
-                   EWS_AUTH_TYPE_GSSAPI)
-                       e_ews_connection_utils_setup_msg_gssapi_auth (cnc, cnc->priv->soup_session, msg);
-
-               g_object_unref (ews_settings);
 
                ews_dump_raw_soup_request (msg);
 
@@ -1660,14 +1654,16 @@ ews_connection_constructor (GType gtype, guint n_properties,
 
        mech = camel_ews_settings_get_auth_mechanism (priv->settings);
 
-       /* We need to disable Basic auth to avoid it getting in the way of
+       /* We used to disable Basic auth to avoid it getting in the way of
         * our GSSAPI hacks. But leave it enabled in the case where NTLM is
         * enabled, which is the default configuration. It's a useful fallback
         * which people may be relying on. */
-       if (mech == EWS_AUTH_TYPE_GSSAPI)
+       if (mech == EWS_AUTH_TYPE_GSSAPI) {
+               soup_session_add_feature_by_type (priv->soup_session,
+                                                 E_SOUP_TYPE_AUTH_NEGOTIATE);
                soup_session_remove_feature_by_type (priv->soup_session,
                                                     SOUP_TYPE_AUTH_BASIC);
-       else if (mech == EWS_AUTH_TYPE_NTLM)
+       } else if (mech == EWS_AUTH_TYPE_NTLM)
                soup_session_add_feature_by_type (priv->soup_session,
                                                  SOUP_TYPE_AUTH_NTLM);
 
diff --git a/src/server/e-ews-notification.c b/src/server/e-ews-notification.c
index b844761..1b5e37f 100644
--- a/src/server/e-ews-notification.c
+++ b/src/server/e-ews-notification.c
@@ -25,6 +25,7 @@
 #include "e-ews-connection-utils.h"
 #include "e-ews-debug.h"
 #include "e-ews-notification.h"
+#include "e-soup-auth-negotiate.h"
 
 #define E_EWS_NOTIFICATION_GET_PRIVATE(obj)\
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -234,14 +235,16 @@ ews_notification_constructor (GType gtype, guint n_properties,
 
        g_object_unref (ews_settings);
 
-       /* We need to disable Basic auth to avoid it getting in the way of
+       /* We used to disable Basic auth to avoid it getting in the way of
         * our GSSAPI hacks. But leave it enabled in the case where NTLM is
         * enabled, which is the default configuration. It's a useful fallback
         * which people may be relying on. */
-       if (mech == EWS_AUTH_TYPE_GSSAPI)
+       if (mech == EWS_AUTH_TYPE_GSSAPI) {
+               soup_session_add_feature_by_type (priv->soup_session,
+                                                 E_SOUP_TYPE_AUTH_NEGOTIATE);
                soup_session_remove_feature_by_type (priv->soup_session,
                                                     SOUP_TYPE_AUTH_BASIC);
-       else if (mech == EWS_AUTH_TYPE_NTLM)
+       } else if (mech == EWS_AUTH_TYPE_NTLM)
                soup_session_add_feature_by_type (priv->soup_session,
                                                  SOUP_TYPE_AUTH_NTLM);
 
@@ -304,7 +307,6 @@ e_ews_notification_subscribe_folder_sync (EEwsNotification *notification,
                                          gchar **subscription_id,
                                          GCancellable *cancellable)
 {
-       CamelEwsSettings *ews_settings;
        ESoapMessage *msg;
        ESoapResponse *response;
        ESoapParameter *param, *subparam;
@@ -361,17 +363,6 @@ e_ews_notification_subscribe_folder_sync (EEwsNotification *notification,
 
        soup_message_body_set_accumulate (SOUP_MESSAGE (msg)->response_body, TRUE);
 
-       ews_settings = e_ews_connection_ref_settings (notification->priv->connection);
-
-       if (camel_ews_settings_get_auth_mechanism (ews_settings) ==
-           EWS_AUTH_TYPE_GSSAPI)
-               e_ews_connection_utils_setup_msg_gssapi_auth (
-                       notification->priv->connection,
-                       notification->priv->soup_session,
-                       SOUP_MESSAGE (msg));
-
-       g_object_unref (ews_settings);
-
        if (g_cancellable_is_cancelled (cancellable)) {
                g_object_unref (msg);
                return FALSE;
diff --git a/src/server/e-soup-auth-negotiate.c b/src/server/e-soup-auth-negotiate.c
new file mode 100644
index 0000000..a0ed8fe
--- /dev/null
+++ b/src/server/e-soup-auth-negotiate.c
@@ -0,0 +1,337 @@
+/*
+ * e-soup-auth-negotiate.c
+ *
+ * This program 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <camel/camel.h>
+#include <libsoup/soup.h>
+#include "e-soup-auth-negotiate.h"
+
+/*
+ * The following set of functions hacks in Negotiate/GSSAPI support for EWS.
+ * Ideally, libsoup should provide the support already.  Unfortunately, it
+ * doesn't: https://bugzilla.gnome.org/show_bug.cgi?id=587145
+ *
+ * Authentication could possibly be configured as connection-based, but it
+ * seems to be message-based by default.  This is fine with us, since it
+ * facilitates attaching a GSSAPI context to the message, and there is no
+ * need to resort to dirty tricks to discover the connection pointer.
+ *
+ * Connection-based auth should also work with this scheme since we only
+ * attempt authentication when told to do so.  If libsoup offered a way to
+ * peek at the connection, though, it would allow use of the "Persistent-Auth"
+ * header to predict that case and avoid an extra round trip.
+ *
+ */
+
+typedef struct {
+       CamelSasl *gssapi_sasl;
+       gchar *token;
+       gchar *challenge;
+       gint  auth_started;
+       gint  challenge_available;
+} SoupMessageState;
+
+static GHashTable *msgs_table;
+
+static gchar *
+e_soup_auth_negotiate_gssapi_challenge (CamelSasl *sasl, const gchar *what,
+                                       gboolean is_base64, GError **error)
+{
+       GByteArray *ain, *aout = NULL;
+       gchar *response = NULL;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (sasl != NULL, NULL);
+
+       ain = g_byte_array_new ();
+
+       if (what && *what) {
+               if (is_base64) {
+                       guchar *bytes;
+                       gsize len = 0;
+
+                       bytes = g_base64_decode (what, &len);
+                       if (bytes) {
+                               g_byte_array_append (ain, bytes, len);
+                               g_free (bytes);
+                       }
+               } else {
+                       g_byte_array_append (ain, (const guchar *) what,
+                                            strlen (what));
+               }
+       }
+
+       aout = camel_sasl_challenge_sync (sasl, ain, NULL, &local_error);
+
+       if (local_error) {
+               g_propagate_error (error, local_error);
+       } else if (aout && aout->len) {
+               response = g_base64_encode (aout->data, aout->len);
+       } else {
+               response = g_strdup ("");
+       }
+
+       g_byte_array_unref (ain);
+
+       if (aout)
+               g_byte_array_unref (aout);
+
+       return response;
+}
+
+static gboolean e_soup_auth_negotiate_update (SoupAuth *auth, SoupMessage *msg,
+                                             GHashTable *auth_params);
+static gboolean e_soup_auth_negotiate_is_ready (SoupAuth *auth,
+                                               SoupMessage *msg);
+static void e_soup_auth_negotiate_message_finished (SoupMessage *msg,
+                                                   gpointer user_data);
+
+static void
+e_soup_auth_negotiate_delete_context (SoupMessage *msg, gpointer user_data)
+{
+       SoupMessageState *state = g_hash_table_lookup (msgs_table, msg);
+
+       g_hash_table_remove (msgs_table, msg);
+       g_signal_handlers_disconnect_by_func (
+               msg, G_CALLBACK (e_soup_auth_negotiate_message_finished),
+               user_data);
+
+       if (state->auth_started)
+               g_object_unref (state->gssapi_sasl);
+       g_free (state->token);
+       g_free (state->challenge);
+       g_slice_free (SoupMessageState, state);
+}
+
+static void
+e_soup_auth_negotiate_message_finished (SoupMessage *msg, gpointer user_data)
+{
+       /*
+        * Feed the remaining GSSAPI data through SASL
+        */
+       SoupAuth *auth = SOUP_AUTH (user_data);
+
+       if (msg->status_code == 200 &&
+           e_soup_auth_negotiate_update (auth, msg, NULL))
+               e_soup_auth_negotiate_is_ready (auth, msg);
+
+       e_soup_auth_negotiate_delete_context (msg, user_data);
+}
+
+static SoupMessageState *
+e_soup_auth_negotiate_get_message_state (SoupMessage *msg, SoupAuth *auth)
+{
+       SoupMessageState *state;
+
+       state = g_hash_table_lookup (msgs_table, msg);
+       if (!state) {
+               state = g_slice_new0 (SoupMessageState);
+               g_hash_table_insert (msgs_table, msg, state);
+               g_signal_connect (
+                       msg, "finished",
+                       G_CALLBACK (e_soup_auth_negotiate_message_finished),
+                       auth);
+       }
+
+       return state;
+}
+
+G_DEFINE_TYPE (ESoupAuthNegotiate, e_soup_auth_negotiate, SOUP_TYPE_AUTH)
+
+static void
+e_soup_auth_negotiate_init (ESoupAuthNegotiate *negotiate)
+{
+}
+
+static void
+e_soup_auth_negotiate_finalize (GObject *object)
+{
+       G_OBJECT_CLASS (e_soup_auth_negotiate_parent_class)->finalize (object);
+}
+
+static gboolean
+e_soup_auth_negotiate_update (SoupAuth *auth, SoupMessage *msg,
+                             GHashTable *auth_params)
+{
+       /*
+        * Basically all we do here is update the challenge
+        */
+       SoupMessageState *state;
+       const gchar *auths_lst;
+       gchar **auths;
+       gint ii;
+
+       /*
+        * The auth_params is supposed to have the challenge.  But the
+        * Negotiate challenge doesn't fit the standard so it must be extracted
+        * from the msg instead.
+        */
+       auths_lst = soup_message_headers_get_list (msg->response_headers,
+                                                  "WWW-Authenticate");
+       if (!auths_lst)
+               return FALSE;
+
+       state = e_soup_auth_negotiate_get_message_state (msg, auth);
+
+       auths = g_strsplit (auths_lst, ",", -1);
+       for (ii = 0; auths && auths[ii]; ii++) {
+               if (g_ascii_strncasecmp (auths[ii], "Negotiate", 9) == 0) {
+                       const gchar *chlg = auths[ii] + 9;
+
+                       if (state->challenge)
+                               g_free (state->challenge);
+                       if (*chlg)
+                               chlg++;
+                       if (!*chlg)
+                               chlg = NULL;
+                       state->challenge = g_strdup (chlg);
+                       state->challenge_available = TRUE;
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+static GSList *
+e_soup_auth_negotiate_get_protection_space (SoupAuth *auth, SoupURI *source_uri)
+{
+       gchar *space, *p;
+
+       space = g_strdup (source_uri->path);
+
+       /* Strip filename component */
+       p = strrchr (space, '/');
+       if (p && p != space && p[1])
+               *p = '\0';
+
+       return g_slist_prepend (NULL, space);
+}
+
+static gboolean
+e_soup_auth_negotiate_is_ready (SoupAuth *auth, SoupMessage *msg)
+{
+       SoupMessageState *state;
+
+       /*
+        * Here we finally update the token and then inform the auth manager
+        * that it's ready.
+        */
+
+       state = e_soup_auth_negotiate_get_message_state (msg, auth);
+
+       if (state->challenge_available) {
+               GError *error = NULL;
+
+               if (!state->auth_started) {
+                       CamelSasl *gssapi_sasl;
+                       SoupURI *soup_uri;
+                       char const *host;
+
+                       gssapi_sasl = g_object_new (
+                               camel_sasl_gssapi_get_type (),
+                               "mechanism", "GSSAPI",
+                               "service-name", "HTTP",
+                               NULL);
+
+                       soup_uri = soup_message_get_uri (msg);
+                       host = soup_uri_get_host (soup_uri);
+
+                       /* We are required to pass a username, but it doesn't
+                          ever get used since we're not actually doing SASL
+                          here. So "" is fine. */
+                       camel_sasl_gssapi_override_host_and_user (
+                               CAMEL_SASL_GSSAPI (gssapi_sasl), host, "");
+
+                       state->gssapi_sasl = gssapi_sasl;
+
+                       state->auth_started = TRUE;
+               }
+
+               g_free (state->token);
+               state->token = e_soup_auth_negotiate_gssapi_challenge (
+                               state->gssapi_sasl,
+                               state->challenge ? state->challenge : "\r\n",
+                               state->challenge != NULL,
+                               &error);
+
+               g_free (state->challenge);
+               state->challenge = NULL;
+               state->challenge_available = FALSE;
+
+               if (error) {
+                       /* cannot use SOUP_STATUS_UNAUTHORIZED, because it may hide an
+                        * error message, which is a local error of Kerberos/GSSAPI
+                        * call
+                        */
+                       soup_message_set_status_full (
+                               msg, SOUP_STATUS_BAD_REQUEST, error->message);
+                       return FALSE;
+               }
+       }
+
+       if (state->token != NULL)
+               return TRUE;
+       return FALSE;
+}
+
+static gboolean
+e_soup_auth_negotiate_is_authenticated (SoupAuth *auth)
+{
+       return TRUE;
+}
+
+static gchar *
+e_soup_auth_negotiate_get_authorization (SoupAuth *auth, SoupMessage *msg)
+{
+       SoupMessageState *state;
+       gchar *token;
+
+       state = e_soup_auth_negotiate_get_message_state (msg, auth);
+       token = g_strdup_printf ("Negotiate %s", state->token);
+
+       g_free (state->token);
+       state->token = NULL;
+
+       return token;
+}
+
+static void
+e_soup_auth_negotiate_class_init (ESoupAuthNegotiateClass *auth_negotiate_class)
+{
+       SoupAuthClass *auth_class = SOUP_AUTH_CLASS (auth_negotiate_class);
+       GObjectClass *object_class = G_OBJECT_CLASS (auth_negotiate_class);
+
+       auth_class->scheme_name = "Negotiate";
+       auth_class->strength = 1;
+
+       auth_class->update = e_soup_auth_negotiate_update;
+       auth_class->get_protection_space = e_soup_auth_negotiate_get_protection_space;
+       auth_class->is_ready = e_soup_auth_negotiate_is_ready;
+       auth_class->is_authenticated = e_soup_auth_negotiate_is_authenticated;
+       auth_class->get_authorization = e_soup_auth_negotiate_get_authorization;
+
+       object_class->finalize = e_soup_auth_negotiate_finalize;
+
+       msgs_table = g_hash_table_new (NULL, NULL);
+}
diff --git a/src/server/e-soup-auth-negotiate.h b/src/server/e-soup-auth-negotiate.h
new file mode 100644
index 0000000..597cf55
--- /dev/null
+++ b/src/server/e-soup-auth-negotiate.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#ifndef E_SOUP_AUTH_NEGOTIATE_H
+#define E_SOUP_AUTH_NEGOTIATE_H
+
+#include "libsoup/soup.h"
+
+#define E_SOUP_TYPE_AUTH_NEGOTIATE \
+       (e_soup_auth_negotiate_get_type ())
+#define E_SOUP_AUTH_NEGOTIATE(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), 
E_SOUP_TYPE_AUTH_NEGOTIATE, ESoupAuthNegotiate))
+#define E_SOUP_AUTH_NEGOTIATE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), E_SOUP_TYPE_AUTH_NEGOTIATE, 
ESoupAuthNegotiate))
+#define E_SOUP_IS_AUTH_NEGOTIATE(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), 
E_SOUP_TYPE_AUTH_NEGOTIATE))
+#define E_SOUP_IS_AUTH_NEGOTIATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_SOUP_TYPE_AUTH_NEGOTIATE))
+#define E_SOUP_AUTH_NEGOTIATE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), E_SOUP_TYPE_AUTH_NEGOTIATE, 
ESoupAuthNegotiateClass))
+
+typedef struct {
+       SoupAuth parent;
+} ESoupAuthNegotiate;
+
+typedef struct {
+       SoupAuthClass parent_class;
+} ESoupAuthNegotiateClass;
+
+GType e_soup_auth_negotiate_get_type (void);
+
+#endif /* E_SOUP_AUTH_NEGOTIATE_H */


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