Conform with Loudmouth coding style
authorMikael Hallendal <micke@imendio.com>
Sat, 24 Feb 2007 02:50:25 +0100
changeset 227 b8fa5635fb30
parent 226 5a31f474b9fd
child 230 8acc59cf04ea
Conform with Loudmouth coding style
loudmouth/lm-sasl.c
--- a/loudmouth/lm-sasl.c	Sat Feb 24 02:23:46 2007 +0100
+++ b/loudmouth/lm-sasl.c	Sat Feb 24 02:50:25 2007 +0100
@@ -45,137 +45,62 @@
 } AuthType;
 
 typedef enum {
-  SASL_AUTH_STATE_NO_MECH = 0,
-  SASL_AUTH_STATE_PLAIN_STARTED,
-  SASL_AUTH_STATE_DIGEST_MD5_STARTED,
-  SASL_AUTH_STATE_DIGEST_MD5_SENT_AUTH_RESPONSE,
-  SASL_AUTH_STATE_DIGEST_MD5_SENT_FINAL_RESPONSE,
+	SASL_AUTH_STATE_NO_MECH,
+	SASL_AUTH_STATE_PLAIN_STARTED,
+	SASL_AUTH_STATE_DIGEST_MD5_STARTED,
+	SASL_AUTH_STATE_DIGEST_MD5_SENT_AUTH_RESPONSE,
+	SASL_AUTH_STATE_DIGEST_MD5_SENT_FINAL_RESPONSE,
 } SaslAuthState;
 
 struct _LmSASL {
-	LmConnection *connection;
-	AuthType auth_type;
-	SaslAuthState state;
-	gchar *username;
-	gchar *password;
-	gchar *server;
-	gchar *digest_md5_rspauth;
-	LmMessageHandler *features_cb;
-	LmMessageHandler *challenge_cb;
-	LmMessageHandler *success_cb;
-	LmMessageHandler *failure_cb;
+	LmConnection        *connection;
+	AuthType             auth_type;
+	SaslAuthState        state;
+	gchar               *username;
+	gchar               *password;
+	gchar               *server;
+	gchar               *digest_md5_rspauth;
+	LmMessageHandler    *features_cb;
+	LmMessageHandler    *challenge_cb;
+	LmMessageHandler    *success_cb;
+	LmMessageHandler    *failure_cb;
 
-	LmSASLResultHandler handler;
+	LmSASLResultHandler  handler;
 };
 
 #define XMPP_NS_SASL_AUTH "urn:ietf:params:xml:ns:xmpp-sasl"
 
-static LmHandlerResult
-features_cb (LmMessageHandler *handler,
-	     LmConnection *connection,
-	     LmMessage *message,
-	     gpointer user_data);
-
-static LmHandlerResult
-challenge_cb (LmMessageHandler *handler,
-	      LmConnection *connection,
-	      LmMessage *message,
-	      gpointer user_data);
-
-static LmHandlerResult
-success_cb (LmMessageHandler *handler,
-	    LmConnection *connection,
-	    LmMessage *message,
-	    gpointer user_data);
-
-static LmHandlerResult
-failure_cb (LmMessageHandler *handler,
-	    LmConnection *connection,
-	    LmMessage *message,
-	    gpointer user_data);
+static LmHandlerResult     sasl_features_cb  (LmMessageHandler *handler,
+					      LmConnection     *connection,
+					      LmMessage        *message,
+					      gpointer          user_data);
 
-LmSASL *
-lm_sasl_new (LmConnection *connection,
-	     const gchar *username,
-	     const gchar *password,
-	     const gchar *server,
-	     LmSASLResultHandler handler)
-{
-	LmSASL *sasl = g_new0 (LmSASL, 1);
-
-	sasl->connection = connection;
-	sasl->username = g_strdup (username);
-	sasl->password = g_strdup (password);
-	sasl->server = g_strdup (server);
-	sasl->handler = handler;
-
-	sasl->features_cb  =
-		lm_message_handler_new (features_cb,
-					sasl,
-					NULL);
-	lm_connection_register_message_handler (connection,
-						sasl->features_cb,
-						LM_MESSAGE_TYPE_STREAM_FEATURES,
-						LM_HANDLER_PRIORITY_FIRST);
+static LmHandlerResult     sasl_challenge_cb (LmMessageHandler *handler,
+					      LmConnection     *connection,
+					      LmMessage        *message,
+					      gpointer          user_data);
 
-	sasl->challenge_cb  =
-		lm_message_handler_new (challenge_cb,
-					sasl,
-					NULL);
-	lm_connection_register_message_handler (connection,
-						sasl->challenge_cb,
-						LM_MESSAGE_TYPE_CHALLENGE,
-						LM_HANDLER_PRIORITY_FIRST);
-	sasl->success_cb  =
-		lm_message_handler_new (success_cb,
-					sasl,
-					NULL);
-	lm_connection_register_message_handler (connection,
-						sasl->success_cb,
-						LM_MESSAGE_TYPE_SUCCESS,
-						LM_HANDLER_PRIORITY_FIRST);
+static LmHandlerResult     sasl_success_cb   (LmMessageHandler *handler,
+					      LmConnection     *connection,
+					      LmMessage        *message,
+					      gpointer          user_data);
 
-	sasl->failure_cb  =
-		lm_message_handler_new (failure_cb,
-					sasl,
-					NULL);
-	lm_connection_register_message_handler (connection,
-						sasl->failure_cb,
-						LM_MESSAGE_TYPE_FAILURE,
-						LM_HANDLER_PRIORITY_FIRST);
-	return sasl;
-}
-
-void
-lm_sasl_free (LmSASL *sasl)
-{
-	g_return_if_fail (sasl != NULL);
+static LmHandlerResult     sasl_failure_cb   (LmMessageHandler *handler,
+					      LmConnection     *connection,
+					      LmMessage        *message,
+					      gpointer          user_data);
 
-	if (sasl->username)
-		g_free (sasl->username);
-	if (sasl->password)
-		g_free (sasl->password);
-	if (sasl->server)
-		g_free (sasl->server);
-
-	if (sasl->features_cb)
-		lm_connection_unregister_message_handler (sasl->connection,
-			sasl->features_cb, LM_MESSAGE_TYPE_STREAM_FEATURES);
-	if (sasl->challenge_cb)
-		lm_connection_unregister_message_handler (sasl->connection,
-			sasl->challenge_cb, LM_MESSAGE_TYPE_CHALLENGE);
-
-	g_free (sasl);
-}
 
 /* DIGEST-MD5 mechanism code from libgibber */
 
 static gchar *
-strndup_unescaped(const gchar *str, gsize len) {
+sasl_strndup_unescaped (const gchar *str, gsize len) 
+{
 	const gchar *s;
-	gchar *d, *ret;
+	gchar       *d;
+	gchar       *ret;
 
-	ret = g_malloc0(len + 1);
+	ret = g_malloc0 (len + 1);
 	for (s = str, d = ret ; s < (str + len) ; s++, d++) {
 		if (*s == '\\') s++;
 		*d = *s;
@@ -185,12 +110,15 @@
 }
 
 static GHashTable *
-digest_md5_challenge_to_hash(const gchar * challenge) {
+sasl_digest_md5_challenge_to_hash (const gchar * challenge)
+{
 	const gchar *keystart, *keyend, *valstart;
 	const gchar *c = challenge;
-	gchar *key, *val;
-	GHashTable *result = g_hash_table_new_full(g_str_hash, 
-		g_str_equal, g_free, g_free);
+	gchar       *key, *val;
+	GHashTable  *result;
+	
+	result = g_hash_table_new_full (g_str_hash, g_str_equal, 
+					g_free, g_free);
 
 	do { 
 		keystart = c;
@@ -206,18 +134,18 @@
 			valstart = c;
 			for (; *c != '\0' && *c != '"'; c++);
 			if (*c == '\0' || c == valstart) goto error;
-			val = strndup_unescaped(valstart, c - valstart);
+			val = sasl_strndup_unescaped (valstart, c - valstart);
 			c++;
 		} else {
 			valstart = c;
 			for (; *c !=  '\0' && *c != ','; c++);
 			if (c == valstart) goto error;
-			val = g_strndup(valstart, c - valstart);
+			val = g_strndup (valstart, c - valstart);
 		}
 
-		key = g_strndup(keystart, keyend - keystart);
+		key = g_strndup (keystart, keyend - keystart);
 
-		g_hash_table_insert(result, key, val);
+		g_hash_table_insert (result, key, val);
 
 		if (*c == ',') c++;
 	} while (*c != '\0');
@@ -225,53 +153,66 @@
 	return result;
 error:
 	g_debug ("Failed to parse challenge: %s", challenge);
-	g_hash_table_destroy(result);
+	g_hash_table_destroy (result);
 	return NULL;
 }
 
 static gchar *
-md5_hex_hash(gchar *value, gsize len) {
-	md5_byte_t digest_md5[16];
-	md5_state_t md5_calc;
-	GString *str = g_string_sized_new(32);
-	int i;
+sasl_md5_hex_hash (gchar *value, gsize len) 
+{
+	md5_byte_t   digest_md5[16];
+	md5_state_t  md5_calc;
+	GString     *str;
+	int          i;
+
+	str = g_string_sized_new (32);
 
-	md5_init(&md5_calc);
-	md5_append(&md5_calc, (const md5_byte_t *)value, len);
-	md5_finish(&md5_calc, digest_md5);
+	md5_init (&md5_calc);
+	md5_append (&md5_calc, (const md5_byte_t *)value, len);
+	md5_finish (&md5_calc, digest_md5);
+
 	for (i = 0 ; i < 16 ; i++) {
-		g_string_append_printf(str, "%02x", digest_md5[i]);
+		g_string_append_printf (str, "%02x", digest_md5[i]);
 	}
-	return g_string_free(str, FALSE);
+
+	return g_string_free (str, FALSE);
 }
 
 static gchar *
-digest_md5_generate_cnonce(void) {
+sasl_digest_md5_generate_cnonce(void)
+{
 	/* RFC 2831 recommends the the nonce to be either hexadecimal or base64 with
 	 * at least 64 bits of entropy */
 #define NR 8
 	guint32 n[NR]; 
 	int i;
-	for (i = 0; i < NR; i++)
+
+	for (i = 0; i < NR; i++) {
 		n[i] = g_random_int();
-	return base64_encode((gchar *)n, sizeof(n));
+	}
+
+	return base64_encode ((gchar *)n, sizeof(n));
 }
 
 static gchar *
-md5_prepare_response(LmSASL *sasl, GHashTable *challenge) {
-	GString *response = g_string_new("");
+sasl_md5_prepare_response (LmSASL *sasl, GHashTable *challenge)
+{
+	GString     *response;
 	const gchar *realm, *nonce;
-	gchar *a1, *a1h, *a2, *a2h, *kd, *kdh;
-	gchar *cnonce = NULL;
-	gchar *tmp;
-	md5_byte_t digest_md5[16];
-	md5_state_t md5_calc;
-	gsize len;
+	gchar       *a1, *a1h, *a2, *a2h, *kd, *kdh;
+	gchar       *cnonce = NULL;
+	gchar       *tmp;
+	md5_byte_t   digest_md5[16];
+	md5_state_t  md5_calc;
+	gsize        len;
+
+	response = g_string_new ("");
 
 	if (sasl->username == NULL || sasl->password == NULL) {
 		g_debug ("%s: no username or password provided", G_STRFUNC);
 		if (sasl->handler) {
-			sasl->handler (sasl, sasl->connection, FALSE, "no username/password provided");
+			sasl->handler (sasl, sasl->connection, 
+				       FALSE, "no username/password provided");
 		}
 		goto error;
 	}
@@ -280,12 +221,13 @@
 	if (nonce == NULL || nonce == '\0') {
 		g_debug ("%s: server didn't provide a nonce in the challenge", G_STRFUNC);
 		if (sasl->handler) {
-			sasl->handler (sasl, sasl->connection, FALSE, "server error");
+			sasl->handler (sasl, sasl->connection,
+				       FALSE, "server error");
 		}
 		goto error;
 	}
 
-	cnonce = digest_md5_generate_cnonce();
+	cnonce = sasl_digest_md5_generate_cnonce ();
 
 	/* FIXME challenge can contain multiple realms */
 	realm = g_hash_table_lookup (challenge, "realm");
@@ -294,74 +236,81 @@
 	}
 
 	/* FIXME properly escape values */
-	g_string_append_printf(response, "username=\"%s\"", sasl->username);
-	g_string_append_printf(response, ",realm=\"%s\"", realm);
-	g_string_append_printf(response, ",digest-uri=\"xmpp/%s\"", realm);
-	g_string_append_printf(response, ",nonce=\"%s\",nc=00000001", nonce);
-	g_string_append_printf(response, ",cnonce=\"%s\"", cnonce);
+	g_string_append_printf (response, "username=\"%s\"", sasl->username);
+	g_string_append_printf (response, ",realm=\"%s\"", realm);
+	g_string_append_printf (response, ",digest-uri=\"xmpp/%s\"", realm);
+	g_string_append_printf (response, ",nonce=\"%s\",nc=00000001", nonce);
+	g_string_append_printf (response, ",cnonce=\"%s\"", cnonce);
 	/* FIXME should check if auth is in the cop challenge val */
-	g_string_append_printf(response, ",qop=auth,charset=utf-8");
+	g_string_append_printf (response, ",qop=auth,charset=utf-8");
 
-	tmp = g_strdup_printf("%s:%s:%s", sasl->username, realm, sasl->password);
-	md5_init(&md5_calc);
-	md5_append(&md5_calc, (const md5_byte_t *)tmp, strlen(tmp));
-	md5_finish(&md5_calc, digest_md5);
-	g_free(tmp);
+	tmp = g_strdup_printf ("%s:%s:%s", 
+			       sasl->username, realm, sasl->password);
+	md5_init (&md5_calc);
+	md5_append (&md5_calc, (const md5_byte_t *)tmp, strlen(tmp));
+	md5_finish (&md5_calc, digest_md5);
+	g_free (tmp);
 
-	a1 = g_strdup_printf("0123456789012345:%s:%s", nonce, cnonce);
-	len = strlen(a1);
-	memcpy(a1, digest_md5, 16);
-	a1h = md5_hex_hash(a1, len);
+	a1 = g_strdup_printf ("0123456789012345:%s:%s", nonce, cnonce);
+	len = strlen (a1);
+	memcpy (a1, digest_md5, 16);
+	a1h = sasl_md5_hex_hash (a1, len);
 
-	a2 = g_strdup_printf("AUTHENTICATE:xmpp/%s", realm);
-	a2h = md5_hex_hash(a2, strlen(a2));
+	a2 = g_strdup_printf ("AUTHENTICATE:xmpp/%s", realm);
+	a2h = sasl_md5_hex_hash (a2, strlen(a2));
 
-	kd = g_strdup_printf("%s:%s:00000001:%s:auth:%s", a1h, nonce, cnonce, a2h);
-	kdh = md5_hex_hash(kd, strlen(kd));
-	g_string_append_printf(response, ",response=%s", kdh);
+	kd = g_strdup_printf ("%s:%s:00000001:%s:auth:%s",
+			      a1h, nonce, cnonce, a2h);
+	kdh = sasl_md5_hex_hash (kd, strlen(kd));
+	g_string_append_printf (response, ",response=%s", kdh);
 
-	g_free(kd);
-	g_free(kdh);
-	g_free(a2);
-	g_free(a2h);
+	g_free (kd);
+	g_free (kdh);
+	g_free (a2);
+	g_free (a2h);
 
 	/* Calculate the response we expect from the server */
-	a2 = g_strdup_printf(":xmpp/%s", realm);
-	a2h = md5_hex_hash(a2, strlen(a2));
+	a2 = g_strdup_printf (":xmpp/%s", realm);
+	a2h = sasl_md5_hex_hash (a2, strlen(a2));
 
-	kd = g_strdup_printf("%s:%s:00000001:%s:auth:%s", a1h, nonce, cnonce, a2h);
+	kd = g_strdup_printf ("%s:%s:00000001:%s:auth:%s", a1h, nonce, cnonce, a2h);
 	g_free (sasl->digest_md5_rspauth);
-	sasl->digest_md5_rspauth = md5_hex_hash(kd, strlen(kd));
+	sasl->digest_md5_rspauth = sasl_md5_hex_hash (kd, strlen(kd));
 
-	g_free(a1);
-	g_free(a1h);
-	g_free(a2);
-	g_free(a2h);
-	g_free(kd);
+	g_free (a1);
+	g_free (a1h);
+	g_free (a2);
+	g_free (a2h);
+	g_free (kd);
 
 out:
-	g_free(cnonce);
-
-	return response != NULL ? g_string_free(response, FALSE) : NULL;
+	g_free (cnonce);
+	if (response) {
+		return g_string_free (response, FALSE);
+	} else {
+		return NULL;
+	}
 
 error:
-	g_string_free(response, TRUE);
+	g_string_free (response, TRUE);
 	response = NULL;
 	goto out;
 }
 
 static gboolean
-digest_md5_send_initial_response(LmSASL *sasl, GHashTable *challenge) {
+sasl_digest_md5_send_initial_response (LmSASL *sasl, GHashTable *challenge)
+{
 	LmMessage *msg;
-	gchar *response, *response64;
-	int result;
+	gchar     *response;
+	gchar     *response64;
+	int        result;
 
-	response = md5_prepare_response(sasl, challenge);
+	response = sasl_md5_prepare_response(sasl, challenge);
 	if (response == NULL) {
 		return FALSE;
 	}
 
-	response64 = base64_encode((gchar *)response, strlen(response));
+	response64 = base64_encode ((gchar *)response, strlen(response));
 
 	msg = lm_message_new (NULL, LM_MESSAGE_TYPE_RESPONSE);
 	lm_message_node_set_attributes (msg->node,
@@ -371,12 +320,13 @@
 
 	result = lm_connection_send (sasl->connection, msg, NULL);
 
-	g_free(response);
-	g_free(response64);
+	g_free (response);
+	g_free (response64);
 	lm_message_unref (msg);
 
-	if (!result)
+	if (!result) {
 		return FALSE;
+	}
 
 	sasl->state = SASL_AUTH_STATE_DIGEST_MD5_SENT_AUTH_RESPONSE;
 
@@ -384,10 +334,11 @@
 }
 
 static gboolean
-digest_md5_check_server_response(LmSASL *sasl, GHashTable *challenge) {
-	LmMessage *msg;
+sasl_digest_md5_check_server_response(LmSASL *sasl, GHashTable *challenge)
+{
+	LmMessage   *msg;
 	const gchar *rspauth;
-	int result;
+	int          result;
 
 	rspauth = g_hash_table_lookup (challenge, "rspauth");
 	if (rspauth == NULL) {
@@ -396,18 +347,20 @@
 		       G_STRFUNC);
 
 		if (sasl->handler) {
-			sasl->handler (sasl, sasl->connection, TRUE, "server error");
+			sasl->handler (sasl, sasl->connection, 
+				       TRUE, "server error");
 		}
 		return FALSE;
 	}
 
-	if (strcmp(sasl->digest_md5_rspauth, rspauth)) {
+	if (strcmp (sasl->digest_md5_rspauth, rspauth) != 0) {
 		g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
 		       "%s: server sent an invalid reply (rspauth not matching)\n", 
 		       G_STRFUNC);
 
 		if (sasl->handler) {
-			sasl->handler (sasl, sasl->connection, TRUE, "server error");
+			sasl->handler (sasl, sasl->connection,
+				       TRUE, "server error");
 		}
 		return FALSE;
 	}
@@ -431,12 +384,12 @@
 }
 
 static gboolean
-digest_md5_handle_challenge (LmSASL *sasl, LmMessageNode *node)
+sasl_digest_md5_handle_challenge (LmSASL *sasl, LmMessageNode *node)
 {
 	const gchar *encoded;
-	gchar *challenge;
-	gsize len;
-	GHashTable *h;
+	gchar       *challenge;
+	gsize        len;
+	GHashTable  *h;
 
 	encoded = lm_message_node_get_value (node);
 	if (!encoded) {
@@ -445,47 +398,53 @@
 	}
 
 	challenge = (gchar *) base64_decode (encoded, &len);
-	h = digest_md5_challenge_to_hash (challenge);
+	h = sasl_digest_md5_challenge_to_hash (challenge);
 	g_free(challenge);
 
 	if (!h) {
 		g_debug ("%s: server sent an invalid challenge", G_STRFUNC);
 		if (sasl->handler) {
-			sasl->handler (sasl, sasl->connection, FALSE, "server error");
+			sasl->handler (sasl, sasl->connection, 
+				       FALSE, "server error");
 		}
 		return FALSE;
 	}
 
 	switch (sasl->state) {
 	case SASL_AUTH_STATE_DIGEST_MD5_STARTED:
-		digest_md5_send_initial_response(sasl, h); 
+		sasl_digest_md5_send_initial_response (sasl, h); 
 		break;
 	case SASL_AUTH_STATE_DIGEST_MD5_SENT_AUTH_RESPONSE:
-		digest_md5_check_server_response(sasl, h); 
+		sasl_digest_md5_check_server_response (sasl, h); 
 		break;
 	default:
 		g_debug ("%s: server sent a challenge at the wrong time", G_STRFUNC);
 		if (sasl->handler) {
-			sasl->handler (sasl, sasl->connection, FALSE, "server error");
+			sasl->handler (sasl, sasl->connection,
+				       FALSE, "server error");
 		}
+
 		return FALSE;
 	} 
+
 	g_hash_table_destroy(h);
+
 	return TRUE;
 }
 
 static LmHandlerResult
-challenge_cb (LmMessageHandler *handler,
-	      LmConnection *connection,
-	      LmMessage *message,
-	      gpointer user_data)
+sasl_challenge_cb (LmMessageHandler *handler,
+		   LmConnection     *connection,
+		   LmMessage        *message,
+		   gpointer          user_data)
 {
-	LmSASL *sasl;
+	LmSASL      *sasl;
 	const gchar *ns;
 
 	ns = lm_message_node_get_attribute (message->node, "xmlns");
-	if (!ns || strcmp (ns, XMPP_NS_SASL_AUTH))
+	if (!ns || strcmp (ns, XMPP_NS_SASL_AUTH) != 0) {
 		return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+	}
 
 	sasl = (LmSASL *) user_data;
 
@@ -496,31 +455,34 @@
 		       G_STRFUNC);
 
 		if (sasl->handler) {
-			sasl->handler (sasl, sasl->connection, FALSE, "server error");
+			sasl->handler (sasl, sasl->connection, 
+				       FALSE, "server error");
 		}
 		break;
 	case AUTH_TYPE_DIGEST:
-		digest_md5_handle_challenge (sasl, message->node);
+		sasl_digest_md5_handle_challenge (sasl, message->node);
 		break;
 	default:
-		g_assert_not_reached ();
+		g_warning ("Wrong auth type");
+		break;
 	}
 
 	return LM_HANDLER_RESULT_REMOVE_MESSAGE;
 }
 
 static LmHandlerResult
-success_cb (LmMessageHandler *handler,
-	    LmConnection *connection,
-	    LmMessage *message,
-	    gpointer user_data)
+sasl_success_cb (LmMessageHandler *handler,
+		 LmConnection     *connection,
+		 LmMessage        *message,
+		 gpointer          user_data)
 {
-	LmSASL *sasl;
+	LmSASL      *sasl;
 	const gchar *ns;
 	
 	ns = lm_message_node_get_attribute (message->node, "xmlns");
-	if (!ns || strcmp (ns, XMPP_NS_SASL_AUTH))
+	if (!ns || strcmp (ns, XMPP_NS_SASL_AUTH) != 0) {
 		return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+	}
 
 	sasl = (LmSASL *) user_data;
 
@@ -529,7 +491,8 @@
 		if (sasl->state != SASL_AUTH_STATE_PLAIN_STARTED) {
 			g_debug ("%s: server sent success before finishing auth", G_STRFUNC);
 			if (sasl->handler) {
-				sasl->handler (sasl, sasl->connection, FALSE, "server error");
+				sasl->handler (sasl, sasl->connection, 
+					       FALSE, "server error");
 			}
 		}
 		break;
@@ -538,15 +501,18 @@
 		    sasl->state != SASL_AUTH_STATE_DIGEST_MD5_SENT_FINAL_RESPONSE) {
 			g_debug ("%s: server sent success before finishing auth", G_STRFUNC);
 			if (sasl->handler) {
-				sasl->handler (sasl, sasl->connection, FALSE, "server error");
+				sasl->handler (sasl, sasl->connection, 
+					       FALSE, "server error");
 			}
 		}
 		break;
 	default:
-		g_assert_not_reached ();
+		g_warning ("Wrong auth type");
+		break;
 	}
 
 	g_debug ("%s: SASL authentication successful", G_STRFUNC);
+
 	if (sasl->handler) {
 		sasl->handler (sasl, sasl->connection, TRUE, NULL);
 	}
@@ -556,26 +522,33 @@
 }
 
 static LmHandlerResult
-failure_cb (LmMessageHandler *handler,
-	    LmConnection *connection,
-	    LmMessage *message,
-	    gpointer user_data)
+sasl_failure_cb (LmMessageHandler *handler,
+		 LmConnection     *connection,
+		 LmMessage        *message,
+		 gpointer          user_data)
 {
-	LmSASL *sasl;
+	LmSASL      *sasl;
 	const gchar *ns;
 	const gchar *reason = "unknown reason";
 	
 	ns = lm_message_node_get_attribute (message->node, "xmlns");
-	if (!ns || strcmp (ns, XMPP_NS_SASL_AUTH))
+	if (!ns || strcmp (ns, XMPP_NS_SASL_AUTH) != 0) {
 		return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+	}
 
 	sasl = (LmSASL *) user_data;
 
 	if (message->node->children) {
-		const gchar *r = lm_message_node_get_value (message->node->children);
-		if (r) reason = r;
+		const gchar *r;
+		
+		r = lm_message_node_get_value (message->node->children);
+		if (r) {
+			reason = r;
+		}
 	}
+	
 	g_debug ("%s: SASL authentication failed: %s", G_STRFUNC, reason);
+
 	if (sasl->handler) {
 		sasl->handler (sasl, sasl->connection, FALSE, reason);
 	}
@@ -585,17 +558,19 @@
 
 
 static gboolean
-lm_sasl_start (LmSASL *sasl)
+sasl_start (LmSASL *sasl)
 {
-	LmMessage *auth_msg;
-	gboolean result;
+	LmMessage  *auth_msg;
+	gboolean    result;
 	const char *mech = NULL;
 
 	auth_msg = lm_message_new (NULL, LM_MESSAGE_TYPE_AUTH);
 
 	if (sasl->auth_type == AUTH_TYPE_PLAIN) {
-      		GString *str = g_string_new("");
-		gchar *cstr;
+      		GString *str;
+		gchar   *cstr;
+
+		str = g_string_new ("");
 
 		mech = "PLAIN";
 		sasl->state = SASL_AUTH_STATE_PLAIN_STARTED;
@@ -605,19 +580,20 @@
 			if (sasl->handler) {
 				sasl->handler (sasl, sasl->connection, FALSE, "no username/password provided");
 			}
+
 			return FALSE;
 		}
 
-		g_string_append_c(str, '\0');
-		g_string_append(str, sasl->username);
-		g_string_append_c(str, '\0');
-		g_string_append(str, sasl->password);
-		cstr = base64_encode((gchar *)str->str, str->len);
+		g_string_append_c (str, '\0');
+		g_string_append (str, sasl->username);
+		g_string_append_c (str, '\0');
+		g_string_append (str, sasl->password);
+		cstr = base64_encode ((gchar *)str->str, str->len);
 
 		lm_message_node_set_value (auth_msg->node, cstr);
 
-		g_string_free(str, TRUE);
-		g_free(cstr);
+		g_string_free (str, TRUE);
+		g_free (cstr);
 
 		/* Here we say the Google magic word. Bad Google. */
 		lm_message_node_set_attributes (auth_msg->node,
@@ -625,7 +601,8 @@
 						"ga:client-uses-full-bind-result", "true",
 						NULL);
 
-	} else if (sasl->auth_type == AUTH_TYPE_DIGEST) {
+	} 
+	else if (sasl->auth_type == AUTH_TYPE_DIGEST) {
 		mech = "DIGEST-MD5";
 		sasl->state = SASL_AUTH_STATE_DIGEST_MD5_STARTED;
 	}
@@ -637,8 +614,10 @@
 
 	result = lm_connection_send (sasl->connection, auth_msg, NULL);
 	lm_message_unref (auth_msg);
-	if (!result)
+
+	if (!result) {
 		return FALSE;
+	}
 
 	return TRUE;
 }
@@ -647,22 +626,27 @@
 lm_sasl_authenticate (LmSASL *sasl, LmMessageNode *mechanisms)
 {
 	LmMessageNode *m;
-	AuthType auth_type = 0;
-	const gchar *ns;
+	AuthType       auth_type = 0;
+	const gchar   *ns;
 
 	ns = lm_message_node_get_attribute (mechanisms, "xmlns");
-	if (!ns || strcmp (ns, XMPP_NS_SASL_AUTH))
+	if (!ns || strcmp (ns, XMPP_NS_SASL_AUTH) != 0) {
 		return FALSE;
+	}
 
 	for (m = mechanisms->children; m; m = m->next) {
-		const gchar *name = lm_message_node_get_value (m);
-		if (!name)
+		const gchar *name;
+		
+		name = lm_message_node_get_value (m);
+
+		if (!name) {
 			continue;
-		if (!strcmp (name, "PLAIN")) {
+		}
+		if (strcmp (name, "PLAIN") == 0) {
 			auth_type |= AUTH_TYPE_PLAIN;
 			continue;
 		}
-		if (!strcmp (name, "DIGEST-MD5")) {
+		if (strcmp (name, "DIGEST-MD5") == 0) {
 			auth_type |= AUTH_TYPE_DIGEST;
 			continue;
 		}
@@ -675,28 +659,29 @@
 	/* Prefer DIGEST */
 	if (auth_type & AUTH_TYPE_DIGEST) {
 		sasl->auth_type = AUTH_TYPE_DIGEST;
-		return lm_sasl_start (sasl);
-	} else if (auth_type & AUTH_TYPE_PLAIN) {
+		return sasl_start (sasl);
+	}
+	else if (auth_type & AUTH_TYPE_PLAIN) {
 		sasl->auth_type = AUTH_TYPE_PLAIN;
-		return lm_sasl_start (sasl);
+		return sasl_start (sasl);
 	} 
 
-	g_assert_not_reached ();
 	return FALSE;
 }
 
 static LmHandlerResult
-features_cb (LmMessageHandler *handler,
-	     LmConnection *connection,
-	     LmMessage *message,
-	     gpointer user_data)
+sasl_features_cb (LmMessageHandler *handler,
+		  LmConnection     *connection,
+		  LmMessage        *message,
+		  gpointer          user_data)
 {
     	LmMessageNode *mechanisms;
-	LmSASL *sasl;
+	LmSASL        *sasl;
 
 	mechanisms = lm_message_node_find_child (message->node, "mechanisms");
-	if (!mechanisms)
+	if (!mechanisms) {
 		return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+	}
 
 	sasl = (LmSASL *) user_data;
 
@@ -705,4 +690,89 @@
 	return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
 }
 
+LmSASL *
+lm_sasl_new (LmConnection        *connection,
+	     const gchar         *username,
+	     const gchar         *password,
+	     const gchar         *server,
+	     LmSASLResultHandler  handler)
+{
+	LmSASL *sasl = g_new0 (LmSASL, 1);
 
+	sasl->connection = connection;
+	sasl->username   = g_strdup (username);
+	sasl->password   = g_strdup (password);
+	sasl->server     = g_strdup (server);
+	sasl->handler    = handler;
+
+	sasl->features_cb = lm_message_handler_new (sasl_features_cb,
+						    sasl,
+						    NULL);
+	lm_connection_register_message_handler (connection,
+						sasl->features_cb,
+						LM_MESSAGE_TYPE_STREAM_FEATURES,
+						LM_HANDLER_PRIORITY_FIRST);
+
+	sasl->challenge_cb = lm_message_handler_new (sasl_challenge_cb,
+						     sasl,
+						     NULL);
+	lm_connection_register_message_handler (connection,
+						sasl->challenge_cb,
+						LM_MESSAGE_TYPE_CHALLENGE,
+						LM_HANDLER_PRIORITY_FIRST);
+	
+	sasl->success_cb = lm_message_handler_new (sasl_success_cb,
+						   sasl,
+						   NULL);
+	lm_connection_register_message_handler (connection,
+						sasl->success_cb,
+						LM_MESSAGE_TYPE_SUCCESS,
+						LM_HANDLER_PRIORITY_FIRST);
+
+	sasl->failure_cb = lm_message_handler_new (sasl_failure_cb,
+						   sasl,
+						   NULL);
+	lm_connection_register_message_handler (connection,
+						sasl->failure_cb,
+						LM_MESSAGE_TYPE_FAILURE,
+						LM_HANDLER_PRIORITY_FIRST);
+	return sasl;
+}
+
+void
+lm_sasl_free (LmSASL *sasl)
+{
+	g_return_if_fail (sasl != NULL);
+
+	g_free (sasl->username);
+	g_free (sasl->password);
+	g_free (sasl->server);
+
+	if (sasl->features_cb) {
+		lm_connection_unregister_message_handler (sasl->connection,
+							  sasl->features_cb, 
+							  LM_MESSAGE_TYPE_STREAM_FEATURES);
+	}
+
+	if (sasl->challenge_cb) {
+		lm_connection_unregister_message_handler (sasl->connection,
+							  sasl->challenge_cb,
+							  LM_MESSAGE_TYPE_CHALLENGE);
+	}
+
+	if (sasl->success_cb) {
+		lm_connection_unregister_message_handler (sasl->connection,
+							  sasl->success_cb,
+							  LM_MESSAGE_TYPE_SUCCESS);
+	}
+
+	if (sasl->failure_cb) {
+		lm_connection_unregister_message_handler (sasl->connection,
+							  sasl->failure_cb,
+							  LM_MESSAGE_TYPE_FAILURE);
+	}
+
+	g_free (sasl);
+}
+
+