void jabber_gmail_init(JabberStream *js) {
	JabberIq *iq;
	PurpleXmlNode *usersetting, *mailnotifications;

	if (!purple_account_get_check_mail(purple_connection_get_account(js->gc)))
		return;

	/*
	 * Quoting https://developers.google.com/talk/jep_extensions/usersettings:
	 * To ensure better compatibility with other clients, rather than
	 * setting this value to "false" to turn off notifications, it is
	 * recommended that a client set this to "true" and filter incoming
	 * email notifications itself.
	 */
	iq = jabber_iq_new(js, JABBER_IQ_SET);
	usersetting = purple_xmlnode_new_child(iq->node, "usersetting");
	purple_xmlnode_set_namespace(usersetting, "google:setting");
	mailnotifications = purple_xmlnode_new_child(usersetting, "mailnotifications");
	purple_xmlnode_set_attrib(mailnotifications, "value", "true");
	jabber_iq_send(iq);

	iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY);
	jabber_iq_set_callback(iq, jabber_gmail_parse, NULL);
	jabber_iq_send(iq);
}
Exemple #2
0
void jabber_chat_request_room_configure(JabberChat *chat) {
	JabberIq *iq;
	char *room_jid;

	if(!chat)
		return;

	chat->config_dialog_handle = NULL;

	if(!chat->muc) {
		purple_notify_error(chat->js->gc, _("Room Configuration Error"), _("Room Configuration Error"),
				_("This room is not capable of being configured"));
		return;
	}

	iq = jabber_iq_new_query(chat->js, JABBER_IQ_GET,
			"http://jabber.org/protocol/muc#owner");
	room_jid = g_strdup_printf("%s@%s", chat->room, chat->server);

	xmlnode_set_attrib(iq->node, "to", room_jid);

	jabber_iq_set_callback(iq, jabber_chat_room_configure_cb, NULL);

	jabber_iq_send(iq);

	g_free(room_jid);
}
Exemple #3
0
void jabber_auth_start_old(JabberStream *js)
{
	PurpleAccount *account;
	JabberIq *iq;
	PurpleXmlNode *query, *username;

	account = purple_connection_get_account(js->gc);

	/*
	 * We can end up here without encryption if the server doesn't support
	 * <stream:features/> and we're not using old-style SSL.  If the user
	 * is requiring SSL/TLS, we need to enforce it.
	 */
	if (!jabber_stream_is_ssl(js) &&
			g_str_equal("require_tls",
				purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS))) {
		purple_connection_error(js->gc,
			PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
			_("You require encryption, but it is not available on this server."));
		return;
	}

	if (js->registration) {
		jabber_register_start(js);
		return;
	}

	/*
	 * IQ Auth doesn't have support for resource binding, so we need to pick a
	 * default resource so it will work properly.  jabberd14 throws an error and
	 * iChat server just fails silently.
	 */
	if (!js->user->resource || *js->user->resource == '\0') {
		g_free(js->user->resource);
		js->user->resource = g_strdup("Home");
	}

#ifdef HAVE_CYRUS_SASL
	/* If we have Cyrus SASL, then passwords will have been set
	 * to OPTIONAL for this protocol. So, we need to do our own
	 * password prompting here
	 */

	if (!purple_connection_get_password(js->gc)) {
		purple_account_request_password(account, G_CALLBACK(auth_old_pass_cb), G_CALLBACK(auth_no_pass_cb), js->gc);
		return;
	}
#endif
	iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:auth");

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

	jabber_iq_set_callback(iq, auth_old_cb, NULL);

	jabber_iq_send(iq);
}
Exemple #4
0
void
jabber_google_send_jingle_info(JabberStream *js)
{
	JabberIq *jingle_info =
		jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_JINGLE_INFO);

	jabber_iq_set_callback(jingle_info, jabber_google_jingle_info_cb,
		NULL);
	purple_debug_info("jabber", "sending google:jingleinfo query\n");
	jabber_iq_send(jingle_info);
}
Exemple #5
0
Fichier : si.c Projet : VoxOx/VoxOx
static void jabber_si_xfer_send_request(GaimXfer *xfer)
{
	JabberSIXfer *jsx = xfer->data;
	JabberIq *iq;
	xmlnode *si, *file, *feature, *x, *field, *option, *value;
	char buf[32];

	xfer->filename = g_path_get_basename(xfer->local_filename);

	iq = jabber_iq_new(jsx->js, JABBER_IQ_SET);
	xmlnode_set_attrib(iq->node, "to", xfer->who);
	si = xmlnode_new_child(iq->node, "si");
	xmlnode_set_namespace(si, "http://jabber.org/protocol/si");
	jsx->stream_id = jabber_get_next_id(jsx->js);
	xmlnode_set_attrib(si, "id", jsx->stream_id);
	xmlnode_set_attrib(si, "profile",
			"http://jabber.org/protocol/si/profile/file-transfer");

	file = xmlnode_new_child(si, "file");
	xmlnode_set_namespace(file,
			"http://jabber.org/protocol/si/profile/file-transfer");
	xmlnode_set_attrib(file, "name", xfer->filename);
	g_snprintf(buf, sizeof(buf), "%" G_GSIZE_FORMAT, xfer->size);
	xmlnode_set_attrib(file, "size", buf);
	/* maybe later we'll do hash and date attribs */

	feature = xmlnode_new_child(si, "feature");
	xmlnode_set_namespace(feature,
			"http://jabber.org/protocol/feature-neg");
	x = xmlnode_new_child(feature, "x");
	xmlnode_set_namespace(x, "jabber:x:data");
	xmlnode_set_attrib(x, "type", "form");
	field = xmlnode_new_child(x, "field");
	xmlnode_set_attrib(field, "var", "stream-method");
	xmlnode_set_attrib(field, "type", "list-single");
	option = xmlnode_new_child(field, "option");
	value = xmlnode_new_child(option, "value");
	xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams",
			-1);
	/*
	option = xmlnode_new_child(field, "option");
	value = xmlnode_new_child(option, "value");
	xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1);
	*/

	jabber_iq_set_callback(iq, jabber_si_xfer_send_method_cb, xfer);

	jabber_iq_send(iq);
}
Exemple #6
0
void jabber_roster_request(JabberStream *js)
{
	JabberIq *iq;
	xmlnode *query;

	iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:roster");
	query = xmlnode_get_child(iq->node, "query");

	if (js->server_caps & JABBER_CAP_GOOGLE_ROSTER) {
		xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
		xmlnode_set_attrib(query, "gr:ext", "2");
	}

	jabber_iq_set_callback(iq, roster_request_cb, NULL);
	jabber_iq_send(iq);
}
Exemple #7
0
static void finish_plaintext_authentication(JabberStream *js)
{
	JabberIq *iq;
	PurpleXmlNode *query, *x;

	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, "password");
	purple_xmlnode_insert_data(x, purple_connection_get_password(js->gc), -1);
	jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
	jabber_iq_send(iq);
}
Exemple #8
0
void jabber_chat_register(JabberChat *chat)
{
	JabberIq *iq;
	char *room_jid;

	if(!chat)
		return;

	room_jid = g_strdup_printf("%s@%s", chat->room, chat->server);

	iq = jabber_iq_new_query(chat->js, JABBER_IQ_GET, "jabber:iq:register");
	xmlnode_set_attrib(iq->node, "to", room_jid);
	g_free(room_jid);

	jabber_iq_set_callback(iq, jabber_chat_register_cb, NULL);

	jabber_iq_send(iq);
}
Exemple #9
0
void
jabber_ibb_session_send_data(JabberIBBSession *sess, gconstpointer data,
                             gsize size)
{
	JabberIBBSessionState state = jabber_ibb_session_get_state(sess);

	purple_debug_info("jabber", "sending data block of %" G_GSIZE_FORMAT " bytes on IBB stream\n",
		size);

	if (state != JABBER_IBB_SESSION_OPENED) {
		purple_debug_error("jabber",
			"trying to send data on a non-open IBB session\n");
	} else if (size > jabber_ibb_session_get_max_data_size(sess)) {
		purple_debug_error("jabber",
			"trying to send a too large packet in the IBB session\n");
	} else {
		JabberIq *set = jabber_iq_new(jabber_ibb_session_get_js(sess),
			JABBER_IQ_SET);
		PurpleXmlNode *data_element = purple_xmlnode_new("data");
		char *base64 = purple_base64_encode(data, size);
		char seq[10];
		g_snprintf(seq, sizeof(seq), "%u", jabber_ibb_session_get_send_seq(sess));

		purple_xmlnode_set_attrib(set->node, "to", jabber_ibb_session_get_who(sess));
		purple_xmlnode_set_namespace(data_element, NS_IBB);
		purple_xmlnode_set_attrib(data_element, "sid", jabber_ibb_session_get_sid(sess));
		purple_xmlnode_set_attrib(data_element, "seq", seq);
		purple_xmlnode_insert_data(data_element, base64, -1);

		purple_xmlnode_insert_child(set->node, data_element);

		purple_debug_info("jabber",
			"IBB: setting send <iq/> callback for session %p %s\n", sess,
			sess->sid);
		jabber_iq_set_callback(set, jabber_ibb_session_send_acknowledge_cb, sess);
		sess->last_iq_id = g_strdup(purple_xmlnode_get_attrib(set->node, "id"));
		purple_debug_info("jabber", "IBB: set sess->last_iq_id: %s\n",
			sess->last_iq_id);
		jabber_iq_send(set);

		g_free(base64);
		(sess->send_seq)++;
	}
}
Exemple #10
0
static void jabber_chat_register_x_data_cb(JabberStream *js, xmlnode *result, gpointer data)
{
	JabberChat *chat = data;
	xmlnode *query;
	JabberIq *iq;
	char *to = g_strdup_printf("%s@%s", chat->room, chat->server);

	iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:register");
	xmlnode_set_attrib(iq->node, "to", to);
	g_free(to);

	query = xmlnode_get_child(iq->node, "query");

	xmlnode_insert_child(query, result);

	jabber_iq_set_callback(iq, jabber_chat_register_x_data_result_cb, NULL);

	jabber_iq_send(iq);
}
Exemple #11
0
void jabber_pep_request_item(JabberStream *js, const char *to, const char *node, const char *id, JabberPEPHandler cb) {
	JabberIq *iq = jabber_iq_new(js, JABBER_IQ_GET);
	xmlnode *pubsub, *items, *item;
	
	xmlnode_set_attrib(iq->node,"to",to);
	pubsub = xmlnode_new_child(iq->node,"pubsub");
	
	xmlnode_set_namespace(pubsub,"http://jabber.org/protocol/pubsub");
	
	items = xmlnode_new_child(pubsub, "items");
	xmlnode_set_attrib(items,"node",node);
	
	item = xmlnode_new_child(items, "item");
	if(id)
		xmlnode_set_attrib(item, "id", id);
	
	jabber_iq_set_callback(iq,do_pep_iq_request_item_callback,(gpointer)cb);
	
	jabber_iq_send(iq);
}
Exemple #12
0
gboolean jabber_chat_role_list(JabberChat *chat, const char *role)
{
	JabberIq *iq;
	char *room_jid;
	xmlnode *query, *item;

	iq = jabber_iq_new_query(chat->js, JABBER_IQ_GET,
			"http://jabber.org/protocol/muc#admin");

	room_jid = g_strdup_printf("%s@%s", chat->room, chat->server);
	xmlnode_set_attrib(iq->node, "to", room_jid);

	query = xmlnode_get_child(iq->node, "query");
	item = xmlnode_new_child(query, "item");
	xmlnode_set_attrib(item, "role", role);

	jabber_iq_set_callback(iq, jabber_chat_role_list_cb, GINT_TO_POINTER(chat->id));
	jabber_iq_send(iq);

	return TRUE;
}
Exemple #13
0
static void roomlist_ok_cb(JabberStream *js, const char *server)
{
	JabberIq *iq;

	if(!js->roomlist)
		return;

	if(!server || !*server) {
		purple_notify_error(js->gc, _("Invalid Server"), _("Invalid Server"), NULL);
		return;
	}

	purple_roomlist_set_in_progress(js->roomlist, TRUE);

	iq = jabber_iq_new_query(js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#items");

	xmlnode_set_attrib(iq->node, "to", server);

	jabber_iq_set_callback(iq, roomlist_disco_result_cb, NULL);

	jabber_iq_send(iq);
}
Exemple #14
0
void jabber_chat_disco_traffic(JabberChat *chat)
{
	JabberIq *iq;
	xmlnode *query;
	char *room_jid;

	room_jid = g_strdup_printf("%s@%s", chat->room, chat->server);

	iq = jabber_iq_new_query(chat->js, JABBER_IQ_GET, NS_DISCO_INFO);

	xmlnode_set_attrib(iq->node, "to", room_jid);

	query = xmlnode_get_child(iq->node, "query");

	xmlnode_set_attrib(query, "node", "http://jabber.org/protocol/muc#traffic");

	jabber_iq_set_callback(iq, jabber_chat_disco_traffic_cb, GINT_TO_POINTER(chat->id));

	jabber_iq_send(iq);

	g_free(room_jid);
}
Exemple #15
0
void
jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type,
                  const char *id, PurpleXmlNode *new_mail)
{
	PurpleXmlNode *query;
	JabberIq *iq;

	/* bail if the user isn't interested */
	if (!purple_account_get_check_mail(purple_connection_get_account(js->gc)))
		return;

	/* Is this an initial incoming mail notification? If so, send a request for more info */
	if (type != JABBER_IQ_SET)
		return;

	/* Acknowledge the notification */
	iq = jabber_iq_new(js, JABBER_IQ_RESULT);
	if (from)
		purple_xmlnode_set_attrib(iq->node, "to", from);
	purple_xmlnode_set_attrib(iq->node, "id", id);
	jabber_iq_send(iq);

	purple_debug_misc("jabber",
		   "Got new mail notification. Sending request for more info\n");

	iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY);
	jabber_iq_set_callback(iq, jabber_gmail_parse, NULL);
	query = purple_xmlnode_get_child(iq->node, "query");

	if (js->gmail_last_time)
		purple_xmlnode_set_attrib(query, "newer-than-time", js->gmail_last_time);
	if (js->gmail_last_tid)
		purple_xmlnode_set_attrib(query, "newer-than-tid", js->gmail_last_tid);

	jabber_iq_send(iq);
	return;
}
Exemple #16
0
void
jabber_ibb_session_open(JabberIBBSession *sess)
{
	if (jabber_ibb_session_get_state(sess) != JABBER_IBB_SESSION_NOT_OPENED) {
		purple_debug_error("jabber",
			"jabber_ibb_session called on an already open stream\n");
	} else {
		JabberIq *set = jabber_iq_new(sess->js, JABBER_IQ_SET);
		PurpleXmlNode *open = purple_xmlnode_new("open");
		gchar block_size[10];

		purple_xmlnode_set_attrib(set->node, "to", jabber_ibb_session_get_who(sess));
		purple_xmlnode_set_namespace(open, NS_IBB);
		purple_xmlnode_set_attrib(open, "sid", jabber_ibb_session_get_sid(sess));
		g_snprintf(block_size, sizeof(block_size), "%" G_GSIZE_FORMAT,
			jabber_ibb_session_get_block_size(sess));
		purple_xmlnode_set_attrib(open, "block-size", block_size);
		purple_xmlnode_insert_child(set->node, open);

		jabber_iq_set_callback(set, jabber_ibb_session_opened_cb, sess);

		jabber_iq_send(set);
	}
}
Exemple #17
0
static gboolean
handle_presence_contact(JabberStream *js, JabberPresence *presence)
{
	JabberBuddyResource *jbr;
	PurpleAccount *account;
	PurpleBuddy *b;
	char *buddy_name;
	PurpleConversation *conv;

	buddy_name = jabber_id_get_bare_jid(presence->jid_from);

	account = purple_connection_get_account(js->gc);
	b = purple_find_buddy(account, buddy_name);

	/*
	 * Unbind/unlock from sending messages to a specific resource on
	 * presence changes.  This is locked to a specific resource when
	 * receiving a message (in message.c).
	 */
	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
			buddy_name, account);
	if (conv) {
		purple_debug_info("jabber", "Changed conversation binding from %s to %s\n",
				purple_conversation_get_name(conv), buddy_name);
		purple_conversation_set_name(conv, buddy_name);
	}

	if (b == NULL) {
		if (presence->jb != js->user_jb) {
			purple_debug_warning("jabber", "Got presence for unknown buddy %s on account %s (%p)\n",
					buddy_name, purple_account_get_username(account), account);
			g_free(buddy_name);
			return FALSE;
		} else {
			/* this is a different resource of our own account. Resume even when this account isn't on our blist */
		}
	}

	if (b && presence->vcard_avatar_hash) {
		const char *ah = presence->vcard_avatar_hash[0] != '\0' ?
				presence->vcard_avatar_hash : NULL;
		const char *ah2 = purple_buddy_icons_get_checksum_for_user(b);
		if (!purple_strequal(ah, ah2)) {
			/* XXX this is a crappy way of trying to prevent
			 * someone from spamming us with presence packets
			 * and causing us to DoS ourselves...what we really
			 * need is a queue system that can throttle itself,
			 * but i'm too tired to write that right now */
			if(!g_slist_find(js->pending_avatar_requests, presence->jb)) {
				JabberIq *iq;
				xmlnode *vcard;

				js->pending_avatar_requests =
					g_slist_prepend(js->pending_avatar_requests, presence->jb);

				iq = jabber_iq_new(js, JABBER_IQ_GET);
				xmlnode_set_attrib(iq->node, "to", buddy_name);
				vcard = xmlnode_new_child(iq->node, "vCard");
				xmlnode_set_namespace(vcard, "vcard-temp");

				jabber_iq_set_callback(iq, jabber_vcard_parse_avatar, NULL);
				jabber_iq_send(iq);
			}
		}
	}

	if (presence->state == JABBER_BUDDY_STATE_ERROR ||
			presence->type == JABBER_PRESENCE_UNAVAILABLE ||
			presence->type == JABBER_PRESENCE_UNSUBSCRIBED) {
		jabber_buddy_remove_resource(presence->jb, presence->jid_from->resource);
	} else {
		jbr = jabber_buddy_track_resource(presence->jb,
				presence->jid_from->resource, presence->priority,
				presence->state, presence->status);
		jbr->idle = presence->idle ? time(NULL) - presence->idle : 0;
	}

	jbr = jabber_buddy_find_resource(presence->jb, NULL);
	if (jbr) {
		jabber_google_presence_incoming(js, buddy_name, jbr);
		purple_prpl_got_user_status(account, buddy_name,
				jabber_buddy_state_get_status_id(jbr->state),
				"priority", jbr->priority,
				"message", jbr->status,
				NULL);
		purple_prpl_got_user_idle(account, buddy_name,
				jbr->idle, jbr->idle);
		if (presence->nickname)
			serv_got_alias(js->gc, buddy_name, presence->nickname);
	} else {
		purple_prpl_got_user_status(account, buddy_name,
				jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_UNAVAILABLE),
				presence->status ? "message" : NULL, presence->status,
				NULL);
	}
	g_free(buddy_name);

	return TRUE;
}
Exemple #18
0
static void
jabber_presence_set_capabilities(JabberCapsClientInfo *info, GList *exts,
                                 JabberPresenceCapabilities *userdata)
{
	JabberBuddyResource *jbr;
	char *resource = strchr(userdata->from, '/');

	if (resource)
		resource += 1;

	jbr = jabber_buddy_find_resource(userdata->jb, resource);
	if (!jbr) {
		g_free(userdata->from);
		g_free(userdata);
		if (exts) {
			g_list_foreach(exts, (GFunc)g_free, NULL);
			g_list_free(exts);
		}
		return;
	}

	/* Any old jbr->caps.info is owned by the caps code */
	if (jbr->caps.exts) {
		g_list_foreach(jbr->caps.exts, (GFunc)g_free, NULL);
		g_list_free(jbr->caps.exts);
	}

	jbr->caps.info = info;
	jbr->caps.exts = exts;

	purple_prpl_got_media_caps(
			purple_connection_get_account(userdata->js->gc),
			userdata->from);
	if (info == NULL)
		goto out;

	if (!jbr->commands_fetched && jabber_resource_has_capability(jbr, "http://jabber.org/protocol/commands")) {
		JabberIq *iq = jabber_iq_new_query(userdata->js, JABBER_IQ_GET, NS_DISCO_ITEMS);
		xmlnode *query = xmlnode_get_child_with_namespace(iq->node, "query", NS_DISCO_ITEMS);
		xmlnode_set_attrib(iq->node, "to", userdata->from);
		xmlnode_set_attrib(query, "node", "http://jabber.org/protocol/commands");
		jabber_iq_set_callback(iq, jabber_adhoc_disco_result_cb, NULL);
		jabber_iq_send(iq);

		jbr->commands_fetched = TRUE;
	}

#if 0
	/*
	 * Versions of libpurple before 2.6.0 didn't advertise this capability, so
	 * we can't yet use Entity Capabilities to determine whether or not the
	 * other client supports Chat States.
	 */
	if (jabber_resource_has_capability(jbr, "http://jabber.org/protocol/chatstates"))
		jbr->chat_states = JABBER_CHAT_STATES_SUPPORTED;
	else
		jbr->chat_states = JABBER_CHAT_STATES_UNSUPPORTED;
#endif

out:
	g_free(userdata->from);
	g_free(userdata);
}
Exemple #19
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;
		}
	}
}