Exemple #1
0
static void roomlist_disco_result_cb(JabberStream *js, const char *from,
                                     JabberIqType type, const char *id,
                                     xmlnode *packet, gpointer data)
{
	xmlnode *query;
	xmlnode *item;

	if(!js->roomlist)
		return;

	if (type == JABBER_IQ_ERROR) {
		char *err = jabber_parse_error(js, packet, NULL);
		purple_notify_error(js->gc, _("Error"),
				_("Error retrieving room list"), err);
		purple_roomlist_set_in_progress(js->roomlist, FALSE);
		purple_roomlist_unref(js->roomlist);
		js->roomlist = NULL;
		g_free(err);
		return;
	}

	if(!(query = xmlnode_get_child(packet, "query"))) {
		char *err = jabber_parse_error(js, packet, NULL);
		purple_notify_error(js->gc, _("Error"),
				_("Error retrieving room list"), err);
		purple_roomlist_set_in_progress(js->roomlist, FALSE);
		purple_roomlist_unref(js->roomlist);
		js->roomlist = NULL;
		g_free(err);
		return;
	}

	for(item = xmlnode_get_child(query, "item"); item;
			item = xmlnode_get_next_twin(item)) {
		const char *name;
		PurpleRoomlistRoom *room;
		JabberID *jid;

		if(!(jid = jabber_id_new(xmlnode_get_attrib(item, "jid"))))
			continue;
		name = xmlnode_get_attrib(item, "name");


		room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, jid->node, NULL);
		purple_roomlist_room_add_field(js->roomlist, room, jid->node);
		purple_roomlist_room_add_field(js->roomlist, room, jid->domain);
		purple_roomlist_room_add_field(js->roomlist, room, name ? name : "");
		purple_roomlist_room_add(js->roomlist, room);

		jabber_id_free(jid);
	}
	purple_roomlist_set_in_progress(js->roomlist, FALSE);
	purple_roomlist_unref(js->roomlist);
	js->roomlist = NULL;
}
Exemple #2
0
static void roomlist_disco_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
{
	xmlnode *query;
	xmlnode *item;
	const char *type;

	if(!js->roomlist)
		return;

	if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) {
		char *err = jabber_parse_error(js,packet);
		gaim_notify_error(js->gc, _("Error"),
				_("Error retrieving room list"), err);
		gaim_roomlist_set_in_progress(js->roomlist, FALSE);
		gaim_roomlist_unref(js->roomlist);
		js->roomlist = NULL;
		g_free(err);
		return;
	}

	if(!(query = xmlnode_get_child(packet, "query"))) {
		char *err = jabber_parse_error(js, packet);
		gaim_notify_error(js->gc, _("Error"),
				_("Error retrieving room list"), err);
		gaim_roomlist_set_in_progress(js->roomlist, FALSE);
		gaim_roomlist_unref(js->roomlist);
		js->roomlist = NULL;
		g_free(err);
		return;
	}

	for(item = xmlnode_get_child(query, "item"); item;
			item = xmlnode_get_next_twin(item)) {
		const char *name;
		GaimRoomlistRoom *room;
		JabberID *jid;

		if(!(jid = jabber_id_new(xmlnode_get_attrib(item, "jid"))))
			continue;
		name = xmlnode_get_attrib(item, "name");


		room = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_ROOM, jid->node, NULL);
		gaim_roomlist_room_add_field(js->roomlist, room, jid->node);
		gaim_roomlist_room_add_field(js->roomlist, room, jid->domain);
		gaim_roomlist_room_add_field(js->roomlist, room, name ? name : "");
		gaim_roomlist_room_add(js->roomlist, room);

		jabber_id_free(jid);
	}
	gaim_roomlist_set_in_progress(js->roomlist, FALSE);
	gaim_roomlist_unref(js->roomlist);
	js->roomlist = NULL;
}
Exemple #3
0
void jabber_auth_handle_failure(JabberStream *js, PurpleXmlNode *packet)
{
	PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
	char *msg = NULL;

	if (js->auth_mech && js->auth_mech->handle_failure) {
		PurpleXmlNode *stanza = NULL;
		JabberSaslState state = js->auth_mech->handle_failure(js, packet, &stanza, &msg);

		if (state != JABBER_SASL_STATE_FAIL) {
			if (stanza) {
				jabber_send(js, stanza);
				purple_xmlnode_free(stanza);
			}

			return;
		}
	}

	if (!msg)
		msg = jabber_parse_error(js, packet, &reason);

	if (!msg) {
		purple_connection_error(js->gc,
			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
			_("Invalid response from server"));
	} else {
		purple_connection_error(js->gc, reason, msg);
		g_free(msg);
	}
}
Exemple #4
0
static void auth_old_result_cb(JabberStream *js, const char *from,
                               JabberIqType type, const char *id,
                               PurpleXmlNode *packet, gpointer data)
{
	if (type == JABBER_IQ_RESULT) {
		jabber_stream_set_state(js, JABBER_STREAM_POST_AUTH);
		jabber_disco_items_server(js);
	} else {
		PurpleAccount *account;
		PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
		char *msg = jabber_parse_error(js, packet, &reason);
		PurpleXmlNode *error;
		const char *err_code;

		account = purple_connection_get_account(js->gc);

		/* FIXME: Why is this not in jabber_parse_error? */
		if((error = purple_xmlnode_get_child(packet, "error")) &&
					(err_code = purple_xmlnode_get_attrib(error, "code")) &&
					g_str_equal(err_code, "401")) {
			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
			/* Clear the pasword if it isn't being saved */
			if (!purple_account_get_remember_password(account))
				purple_account_set_password(account, NULL, NULL, NULL);
		}

		purple_connection_error(js->gc, reason, msg);
		g_free(msg);
	}
}
Exemple #5
0
static void jabber_chat_room_configure_cb(JabberStream *js, xmlnode *packet, gpointer data)
{
	xmlnode *query, *x;
	const char *type = xmlnode_get_attrib(packet, "type");
	const char *from = xmlnode_get_attrib(packet, "from");
	char *msg;
	JabberChat *chat;
	JabberID *jid;

	if(!type || !from)
		return;



	if(!strcmp(type, "result")) {
		jid = jabber_id_new(from);

		if(!jid)
			return;

		chat = jabber_chat_find(js, jid->node, jid->domain);
		jabber_id_free(jid);

		if(!chat)
			return;

		if(!(query = xmlnode_get_child(packet, "query")))
			return;

		for(x = xmlnode_get_child(query, "x"); x; x = xmlnode_get_next_twin(x)) {
			const char *xmlns;
			if(!(xmlns = xmlnode_get_namespace(x)))
				continue;

			if(!strcmp(xmlns, "jabber:x:data")) {
				chat->config_dialog_type = PURPLE_REQUEST_FIELDS;
				chat->config_dialog_handle = jabber_x_data_request(js, x, jabber_chat_room_configure_x_data_cb, chat);
				return;
			}
		}
	} else if(!strcmp(type, "error")) {
		char *msg = jabber_parse_error(js, packet);

		purple_notify_error(js->gc, _("Configuration error"), _("Configuration error"), msg);

		if(msg)
			g_free(msg);
		return;
	}

	msg = g_strdup_printf("Unable to configure room %s", from);

	purple_notify_info(js->gc, _("Unable to configure"), _("Unable to configure"), msg);
	g_free(msg);

}
Exemple #6
0
static void jabber_chat_register_cb(JabberStream *js, const char *from,
                                    JabberIqType type, const char *id,
                                    xmlnode *packet, gpointer data)
{
	xmlnode *query, *x;
	char *msg;
	JabberChat *chat;
	JabberID *jid;

	if (!from)
		return;

	if (type == JABBER_IQ_RESULT) {
		jid = jabber_id_new(from);

		if(!jid)
			return;

		chat = jabber_chat_find(js, jid->node, jid->domain);
		jabber_id_free(jid);

		if(!chat)
			return;

		if(!(query = xmlnode_get_child(packet, "query")))
			return;

		for(x = xmlnode_get_child(query, "x"); x; x = xmlnode_get_next_twin(x)) {
			const char *xmlns;

			if(!(xmlns = xmlnode_get_namespace(x)))
				continue;

			if(!strcmp(xmlns, "jabber:x:data")) {
				jabber_x_data_request(js, x, jabber_chat_register_x_data_cb, chat);
				return;
			}
		}
	} else if (type == JABBER_IQ_ERROR) {
		char *msg = jabber_parse_error(js, packet, NULL);

		purple_notify_error(js->gc, _("Registration error"), _("Registration error"), msg);

		if(msg)
			g_free(msg);
		return;
	}

	msg = g_strdup_printf("Unable to configure room %s", from);

	purple_notify_info(js->gc, _("Unable to configure"), _("Unable to configure"), msg);
	g_free(msg);

}
Exemple #7
0
static void jabber_chat_register_x_data_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
{
	const char *type = xmlnode_get_attrib(packet, "type");

	if(type && !strcmp(type, "error")) {
		char *msg = jabber_parse_error(js, packet);

		purple_notify_error(js->gc, _("Registration error"), _("Registration error"), msg);

		if(msg)
			g_free(msg);
		return;
	}
}
Exemple #8
0
static void
jabber_chat_register_x_data_result_cb(JabberStream *js, const char *from,
                                      JabberIqType type, const char *id,
                                      xmlnode *packet, gpointer data)
{
	if (type == JABBER_IQ_ERROR) {
		char *msg = jabber_parse_error(js, packet, NULL);

		purple_notify_error(js->gc, _("Registration error"), _("Registration error"), msg);

		if(msg)
			g_free(msg);
		return;
	}
}
Exemple #9
0
void jabber_presence_parse(JabberStream *js, xmlnode *packet)
{
	const char *type;
	JabberBuddyResource *jbr = NULL;
	gboolean signal_return, ret;
	JabberPresence presence;
	xmlnode *child;

	memset(&presence, 0, sizeof(presence));
	/* defaults */
	presence.state = JABBER_BUDDY_STATE_UNKNOWN;
	presence.sent = time(NULL);
	/* interesting values */
	presence.from = xmlnode_get_attrib(packet, "from");
	presence.to   = xmlnode_get_attrib(packet, "to");
	type = xmlnode_get_attrib(packet, "type");
	presence.type = str_to_presence_type(type);

	presence.jb = jabber_buddy_find(js, presence.from, TRUE);
	g_return_if_fail(presence.jb != NULL);

	presence.jid_from = jabber_id_new(presence.from);
	if (presence.jid_from == NULL) {
		purple_debug_error("jabber", "Ignoring presence with malformed 'from' "
		                   "JID: %s\n", presence.from);
		return;
	}

	signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_connection_get_prpl(js->gc),
			"jabber-receiving-presence", js->gc, type, presence.from, packet));
	if (signal_return) {
		goto out;
	}

	if (presence.jid_from->node)
		presence.chat = jabber_chat_find(js, presence.jid_from->node,
		                                 presence.jid_from->domain);
	if(presence.jb->error_msg) {
		g_free(presence.jb->error_msg);
		presence.jb->error_msg = NULL;
	}

	if (presence.type == JABBER_PRESENCE_AVAILABLE) {
		presence.state = JABBER_BUDDY_STATE_ONLINE;
	} else if (presence.type == JABBER_PRESENCE_ERROR) {
		/* TODO: Is this handled properly?  Should it be treated as per-jbr? */
		char *msg = jabber_parse_error(js, packet, NULL);
		presence.state = JABBER_BUDDY_STATE_ERROR;
		presence.jb->error_msg = msg ? msg : g_strdup(_("Unknown Error in presence"));
	} else if (presence.type == JABBER_PRESENCE_SUBSCRIBE) {
		/* TODO: Move to handle_subscribe() (so nick is extracted by the
		 * PresenceHandler */
		struct _jabber_add_permit *jap = g_new0(struct _jabber_add_permit, 1);
		gboolean onlist = FALSE;
		PurpleAccount *account;
		PurpleBuddy *buddy;
		xmlnode *nick;

		account = purple_connection_get_account(js->gc);
		buddy = purple_find_buddy(account, presence.from);
		nick = xmlnode_get_child_with_namespace(packet, "nick", "http://jabber.org/protocol/nick");
		if (nick)
			presence.nickname = xmlnode_get_data(nick);

		if (buddy) {
			if ((presence.jb->subscription & (JABBER_SUB_TO | JABBER_SUB_PENDING)))
				onlist = TRUE;
		}

		jap->gc = js->gc;
		jap->who = g_strdup(presence.from);
		jap->js = js;

		purple_account_request_authorization(account, presence.from, NULL, presence.nickname,
				NULL, onlist, authorize_add_cb, deny_add_cb, jap);

		goto out;
	} else if (presence.type == JABBER_PRESENCE_SUBSCRIBED) {
Exemple #10
0
static gboolean
handle_presence_chat(JabberStream *js, JabberPresence *presence, xmlnode *packet)
{
	static int i = 1;
	PurpleConvChatBuddyFlags flags = PURPLE_CBFLAGS_NONE;
	JabberChat *chat = presence->chat;

	if (presence->state == JABBER_BUDDY_STATE_ERROR) {
		char *title, *msg = jabber_parse_error(js, packet, NULL);

		if (!chat->conv) {
			title = g_strdup_printf(_("Error joining chat %s"), presence->from);
			purple_serv_got_join_chat_failed(js->gc, chat->components);
		} else {
			title = g_strdup_printf(_("Error in chat %s"), presence->from);
			if (g_hash_table_size(chat->members) == 0)
				serv_got_chat_left(js->gc, chat->id);
		}
		purple_notify_error(js->gc, title, title, msg);
		g_free(title);
		g_free(msg);

		if (g_hash_table_size(chat->members) == 0)
			/* Only destroy the chat if the error happened while joining */
			jabber_chat_destroy(chat);
		return FALSE;
	}

	if (presence->type == JABBER_PRESENCE_AVAILABLE) {
		const char *jid = NULL;
		const char *affiliation = NULL;
		const char *role = NULL;
		gboolean is_our_resource = FALSE; /* Is the presence about us? */
		JabberBuddyResource *jbr;

		/*
		 * XEP-0045 mandates the presence to include a resource (which is
		 * treated as the chat nick). Some non-compliant servers allow
		 * joining without a nick.
		 */
		if (!presence->jid_from->resource)
			return FALSE;

		if (presence->chat_info.item) {
			jid = xmlnode_get_attrib(presence->chat_info.item, "jid");
			affiliation = xmlnode_get_attrib(presence->chat_info.item, "affiliation");
			role = xmlnode_get_attrib(presence->chat_info.item, "role");
		}

		if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(110)) ||
				g_str_equal(presence->jid_from->resource, chat->handle) ||
				purple_strequal(presence->to, jid))
			is_our_resource = TRUE;

		if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(201))) {
			chat->config_dialog_type = PURPLE_REQUEST_ACTION;
			chat->config_dialog_handle =
				purple_request_action(js->gc,
						_("Create New Room"),
						_("Create New Room"),
						_("You are creating a new room.  Would"
							" you like to configure it, or"
							" accept the default settings?"),
						/* Default Action */ 1,
						purple_connection_get_account(js->gc), NULL, chat->conv,
						chat, 2,
						_("_Configure Room"), G_CALLBACK(jabber_chat_request_room_configure),
						_("_Accept Defaults"), G_CALLBACK(jabber_chat_create_instant_room));
		}

		if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(210))) {
			/* server rewrote room-nick */
			g_free(chat->handle);
			chat->handle = g_strdup(presence->jid_from->resource);
		}

		if (purple_strequal(affiliation, "owner"))
			flags |= PURPLE_CBFLAGS_FOUNDER;
		if (role) {
			if (g_str_equal(role, "moderator"))
				flags |= PURPLE_CBFLAGS_OP;
			else if (g_str_equal(role, "participant"))
				flags |= PURPLE_CBFLAGS_VOICE;
		}

		if(!chat->conv) {
			char *room_jid = g_strdup_printf("%s@%s", presence->jid_from->node, presence->jid_from->domain);
			chat->id = i++;
			chat->conv = serv_got_joined_chat(js->gc, chat->id, room_jid);
			purple_conv_chat_set_nick(PURPLE_CONV_CHAT(chat->conv), chat->handle);

			jabber_chat_disco_traffic(chat);
			g_free(room_jid);
		}

		jbr = jabber_buddy_track_resource(presence->jb, presence->jid_from->resource, presence->priority, presence->state, presence->status);
		jbr->commands_fetched = TRUE;

		jabber_chat_track_handle(chat, presence->jid_from->resource, jid, affiliation, role);

		if(!jabber_chat_find_buddy(chat->conv, presence->jid_from->resource))
			purple_conv_chat_add_user(PURPLE_CONV_CHAT(chat->conv), presence->jid_from->resource,
					jid, flags, chat->joined > 0 && ((!presence->delayed) || (presence->sent > chat->joined)));
		else
			purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(chat->conv), presence->jid_from->resource,
					flags);

		if (is_our_resource && chat->joined == 0)
			chat->joined = time(NULL);

	} else if (presence->type == JABBER_PRESENCE_UNAVAILABLE) {
		gboolean nick_change = FALSE;
		gboolean kick = FALSE;
		gboolean is_our_resource = FALSE; /* Is the presence about us? */

		const char *jid = NULL;

		/* If the chat nick is invalid, we haven't yet joined, or we've
		 * already left (it was probably us leaving after we closed the
		 * chat), we don't care.
		 */
		if (!presence->jid_from->resource || !chat->conv || chat->left) {
			if (chat->left &&
					presence->jid_from->resource && chat->handle && !strcmp(presence->jid_from->resource, chat->handle))
				jabber_chat_destroy(chat);
			return FALSE;
		}

		is_our_resource = g_str_equal(presence->jid_from->resource, chat->handle);

		jabber_buddy_remove_resource(presence->jb, presence->jid_from->resource);

		if (presence->chat_info.item)
			jid = xmlnode_get_attrib(presence->chat_info.item, "jid");

		if (chat->muc) {
			if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(110))) {
				is_our_resource = TRUE;
				chat->joined = 0;
			}

			if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(301))) {
				/* XXX: We got banned.  YAY! (No GIR, that's bad) */
			}


			if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(303))) {
				const char *nick = NULL;
				if (presence->chat_info.item)
					nick = xmlnode_get_attrib(presence->chat_info.item, "nick");

				/* nick change */
				if (!nick) {
					purple_debug_warning("jabber", "Chat presence indicating a nick change, but no new nickname!\n");
				} else {
					nick_change = TRUE;

					if (g_str_equal(presence->jid_from->resource, chat->handle)) {
						/* Changing our own nickname */
						g_free(chat->handle);
						/* TODO: This should be resourceprep'd */
						chat->handle = g_strdup(nick);
					}

					purple_conv_chat_rename_user(PURPLE_CONV_CHAT(chat->conv),
					                             presence->jid_from->resource,
					                             nick);
					jabber_chat_remove_handle(chat,
					                          presence->jid_from->resource);
				}
			}

			if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(307))) {
				/* Someone was kicked from the room */
				const char *actor = NULL;
				char *reason = NULL;
				char *tmp;

				kick = TRUE;

				if (presence->chat_info.item) {
					xmlnode *node;

					node = xmlnode_get_child(presence->chat_info.item, "actor");
					if (node)
						actor = xmlnode_get_attrib(node, "jid");
					node = xmlnode_get_child(presence->chat_info.item, "reason");
					if (node)
						reason = xmlnode_get_data(node);
				}

				if (reason == NULL)
					reason = g_strdup(_("No reason"));

				if (is_our_resource) {
					if (actor)
						tmp = g_strdup_printf(_("You have been kicked by %s: (%s)"),
								actor, reason);
					else
						tmp = g_strdup_printf(_("You have been kicked: (%s)"),
								reason);
				} else {
					if (actor)
						tmp = g_strdup_printf(_("Kicked by %s (%s)"),
								actor, reason);
					else
						tmp = g_strdup_printf(_("Kicked (%s)"),
								reason);
				}

				g_free(presence->status);
				presence->status = tmp;

				g_free(reason);
			}

			if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(321))) {
				/* XXX: removed due to an affiliation change */
			}

			if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(322))) {
				/* XXX: removed because room is now members-only */
			}

			if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(332))) {
				/* XXX: removed due to system shutdown */
			}
		}

		/*
		 * Possibly another connected resource of our JID (see XEP-0045
		 * v1.24 section 7.1.10) being disconnected. Should be
		 * distinguished by the item_jid.
		 * Also possibly works around bits of an Openfire bug. See
		 * #8319.
		 */
		if (is_our_resource && jid && !purple_strequal(presence->to, jid)) {
			/* TODO: When the above is a loop, this needs to still act
			 * sanely for all cases (this code is a little fragile). */
			if (!kick && !nick_change)
				/* Presumably, kicks and nick changes also affect us. */
				is_our_resource = FALSE;
		}

		if(!nick_change) {
			if (is_our_resource) {
				if (kick)
					purple_conv_chat_write(PURPLE_CONV_CHAT(chat->conv), presence->jid_from->resource,
							presence->status, PURPLE_MESSAGE_SYSTEM, time(NULL));

				serv_got_chat_left(js->gc, chat->id);
				jabber_chat_destroy(chat);
			} else {
				purple_conv_chat_remove_user(PURPLE_CONV_CHAT(chat->conv), presence->jid_from->resource,
						presence->status);
				jabber_chat_remove_handle(chat, presence->jid_from->resource);
			}
		}
	}

	return TRUE;
}
Exemple #11
0
static void auth_old_cb(JabberStream *js, const char *from,
                        JabberIqType type, const char *id,
                        PurpleXmlNode *packet, gpointer data)
{
	JabberIq *iq;
	PurpleXmlNode *query, *x;
	const char *pw = purple_connection_get_password(js->gc);

	if (type == JABBER_IQ_ERROR) {
		PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
		char *msg = jabber_parse_error(js, packet, &reason);
		purple_connection_error(js->gc, reason, msg);
		g_free(msg);
	} else if (type == JABBER_IQ_RESULT) {
		query = purple_xmlnode_get_child(packet, "query");
		if (js->stream_id && *js->stream_id &&
				purple_xmlnode_get_child(query, "digest")) {
			char *s, *hash;

			iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
			query = purple_xmlnode_get_child(iq->node, "query");
			x = purple_xmlnode_new_child(query, "username");
			purple_xmlnode_insert_data(x, js->user->node, -1);
			x = purple_xmlnode_new_child(query, "resource");
			purple_xmlnode_insert_data(x, js->user->resource, -1);

			x = purple_xmlnode_new_child(query, "digest");
			s = g_strdup_printf("%s%s", js->stream_id, pw);
			hash = jabber_calculate_data_hash(s, strlen(s), "sha1");
			purple_xmlnode_insert_data(x, hash, -1);
			g_free(hash);
			g_free(s);
			jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
			jabber_iq_send(iq);
		} else if ((x = purple_xmlnode_get_child(query, "crammd5"))) {
			/* For future reference, this appears to be a custom OS X extension
			 * to non-SASL authentication.
			 */
			const char *challenge;
			gchar digest[33];
			PurpleCipher *hmac;
			PurpleHash *md5;
			gssize diglen;

			/* Calculate the MHAC-MD5 digest */
			md5 = purple_md5_hash_new();
			hmac = purple_hmac_cipher_new(md5);
			challenge = purple_xmlnode_get_attrib(x, "challenge");
			purple_cipher_set_key(hmac, (guchar *)pw, strlen(pw));
			purple_cipher_append(hmac, (guchar *)challenge, strlen(challenge));
			diglen = purple_cipher_digest_to_str(hmac, digest, 33);
			g_object_unref(hmac);
			g_object_unref(md5);

			g_return_if_fail(diglen > 0);

			/* Create the response query */
			iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
			query = purple_xmlnode_get_child(iq->node, "query");

			x = purple_xmlnode_new_child(query, "username");
			purple_xmlnode_insert_data(x, js->user->node, -1);
			x = purple_xmlnode_new_child(query, "resource");
			purple_xmlnode_insert_data(x, js->user->resource, -1);

			x = purple_xmlnode_new_child(query, "crammd5");

			purple_xmlnode_insert_data(x, digest, 32);

			jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
			jabber_iq_send(iq);

		} else if(purple_xmlnode_get_child(query, "password")) {
			PurpleAccount *account = purple_connection_get_account(js->gc);
			if(!jabber_stream_is_ssl(js) && !purple_account_get_bool(account,
						"auth_plain_in_clear", FALSE)) {
				char *msg = g_strdup_printf(_("%s requires plaintext authentication over an unencrypted connection.  Allow this and continue authentication?"),
											purple_account_get_username(account));
				purple_request_yes_no(js->gc, _("Plaintext Authentication"),
						_("Plaintext Authentication"),
						msg,
						1,
						purple_request_cpar_from_account(account),
						account, allow_plaintext_auth,
						disallow_plaintext_auth);
				g_free(msg);
				return;
			}
			finish_plaintext_authentication(js);
		} else {
			purple_connection_error(js->gc,
				PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
				_("Server does not use any supported authentication method"));
			return;
		}
	}
}