changeset 21829:cc0809ec0c85

This is the second part of the fix to support having multiple presence records in Bonjour (and also supporting multiple presences using the same IP). Incoming conversations are no longer immediately attached to a buddy - we use an algorithm to match a conversation to a buddy based on the IP and, if possible the "from" attribute of the stream or the first tag in the stream. Thanks to Sjoerd Simons from Telepahy Salut for noticing and suggesting the algorithm. Fixes #4187. It'd be good if a few people test this.
author Daniel Atallah <daniel.atallah@gmail.com>
date Fri, 14 Dec 2007 21:44:34 +0000
parents 85fcbd3b9d32
children f2cf1d61a676 2be2eec7d273
files libpurple/protocols/bonjour/bonjour.c libpurple/protocols/bonjour/bonjour.h libpurple/protocols/bonjour/bonjour_ft.c libpurple/protocols/bonjour/jabber.c libpurple/protocols/bonjour/jabber.h libpurple/protocols/bonjour/parser.c libpurple/protocols/bonjour/parser.h
diffstat 7 files changed, 395 insertions(+), 237 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/bonjour/bonjour.c	Fri Dec 14 00:41:28 2007 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c	Fri Dec 14 21:44:34 2007 +0000
@@ -109,7 +109,7 @@
 	gc->proto_data = bd = g_new0(BonjourData, 1);
 
 	/* Start waiting for jabber connections (iChat style) */
-	bd->jabber_data = g_new(BonjourJabber, 1);
+	bd->jabber_data = g_new0(BonjourJabber, 1);
 	bd->jabber_data->port = BONJOUR_DEFAULT_PORT_INT;
 	bd->jabber_data->account = account;
 
--- a/libpurple/protocols/bonjour/bonjour.h	Fri Dec 14 00:41:28 2007 +0000
+++ b/libpurple/protocols/bonjour/bonjour.h	Fri Dec 14 21:44:34 2007 +0000
@@ -44,7 +44,7 @@
 {
 	BonjourDnsSd *dns_sd_data;
 	BonjourJabber *jabber_data;
-	GList *xfer_lists;
+	GSList *xfer_lists;
 } BonjourData;
 
 #endif /* _BONJOUR_H_ */
--- a/libpurple/protocols/bonjour/bonjour_ft.c	Fri Dec 14 00:41:28 2007 +0000
+++ b/libpurple/protocols/bonjour/bonjour_ft.c	Fri Dec 14 21:44:34 2007 +0000
@@ -149,7 +149,7 @@
 static PurpleXfer*
 bonjour_si_xfer_find(BonjourData *bd, const char *sid, const char *from)
 {
-	GList *xfers = NULL;
+	GSList *xfers = NULL;
 	PurpleXfer *xfer = NULL;
 	XepXfer *xf = NULL;
 
@@ -309,7 +309,7 @@
 	if(xf != NULL) {
 		bd = (BonjourData*)xf->data;
 		if(bd != NULL) {
-			bd->xfer_lists = g_list_remove(bd->xfer_lists, xfer);
+			bd->xfer_lists = g_slist_remove(bd->xfer_lists, xfer);
 			purple_debug_info("bonjour", "B free xfer from lists(%p).\n", bd->xfer_lists);
 		}
 		if (xf->proxy_connection != NULL)
@@ -359,7 +359,7 @@
 	purple_xfer_set_cancel_send_fnc(xfer, bonjour_xfer_cancel_send);
 	purple_xfer_set_end_fnc(xfer, bonjour_xfer_end);
 
-	bd->xfer_lists = g_list_append(bd->xfer_lists, xfer);
+	bd->xfer_lists = g_slist_append(bd->xfer_lists, xfer);
 
 	return xfer;
 }
@@ -605,7 +605,7 @@
 	purple_xfer_set_cancel_recv_fnc(xfer, bonjour_xfer_cancel_recv);
 	purple_xfer_set_end_fnc(xfer, bonjour_xfer_end);
 
-	bd->xfer_lists = g_list_append(bd->xfer_lists, xfer);
+	bd->xfer_lists = g_slist_append(bd->xfer_lists, xfer);
 
 	purple_xfer_request(xfer);
 }
--- a/libpurple/protocols/bonjour/jabber.c	Fri Dec 14 00:41:28 2007 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Fri Dec 14 21:44:34 2007 +0000
@@ -78,7 +78,7 @@
 xep_iq_parse(xmlnode *packet, PurpleConnection *connection, PurpleBuddy *pb);
 
 static BonjourJabberConversation *
-bonjour_jabber_conv_new(PurpleBuddy *pb) {
+bonjour_jabber_conv_new(PurpleBuddy *pb, PurpleAccount *account, const char *ip) {
 
 	BonjourJabberConversation *bconv = g_new0(BonjourJabberConversation, 1);
 	bconv->socket = -1;
@@ -86,13 +86,14 @@
 	bconv->tx_handler = 0;
 	bconv->rx_handler = 0;
 	bconv->pb = pb;
+	bconv->account = account;
+	bconv->ip = g_strdup(ip);
 
 	bonjour_parser_setup(bconv);
 
 	return bconv;
 }
 
-
 static const char *
 _font_size_ichat_to_purple(int size)
 {
@@ -204,39 +205,36 @@
 	g_free(body);
 }
 
-struct _check_buddy_by_address_t {
+struct _match_buddies_by_address_t {
 	const char *address;
-	PurpleBuddy **pb;
-	BonjourJabber *bj;
+	GSList *matched_buddies;
+	BonjourJabber *jdata;
 };
 
 static void
-_check_buddy_by_address(gpointer key, gpointer value, gpointer data)
+_match_buddies_by_address(gpointer key, gpointer value, gpointer data)
 {
 	PurpleBuddy *pb = value;
-	BonjourBuddy *bb;
-	struct _check_buddy_by_address_t *cbba = data;
+	struct _match_buddies_by_address_t *mbba = data;
 
 	/*
 	 * If the current PurpleBuddy's data is not null and the PurpleBuddy's account
 	 * is the same as the account requesting the check then continue to determine
 	 * whether one of the buddies IPs matches the target IP.
 	 */
-	if (cbba->bj->account == pb->account)
+	if (mbba->jdata->account == pb->account && pb->proto_data != NULL)
 	{
-		bb = pb->proto_data;
-		if (bb != NULL) {
-			const char *ip;
-			GSList *tmp = bb->ips;
+		const char *ip;
+		BonjourBuddy *bb = pb->proto_data;
+		GSList *tmp = bb->ips;
 
-			while(tmp) {
-				ip = tmp->data;
-				if (ip != NULL && g_ascii_strcasecmp(ip, cbba->address) == 0) {
-					*(cbba->pb) = pb;
-					break;
-				}
-				tmp = tmp->next;
+		while(tmp) {
+			ip = tmp->data;
+			if (ip != NULL && g_ascii_strcasecmp(ip, mbba->address) == 0) {
+				mbba->matched_buddies = g_slist_prepend(mbba->matched_buddies, pb);
+				break;
 			}
+			tmp = tmp->next;
 		}
 	}
 }
@@ -249,8 +247,6 @@
 	BonjourJabberConversation *bconv = bb->conversation;
 	int ret, writelen;
 
-	/* TODO: Make sure that the stream has been established before sending */
-
 	writelen = purple_circ_buffer_get_max_read(bconv->tx_buf);
 
 	if (writelen == 0) {
@@ -338,6 +334,7 @@
 void bonjour_jabber_process_packet(PurpleBuddy *pb, xmlnode *packet) {
 
 	g_return_if_fail(packet != NULL);
+	g_return_if_fail(pb != NULL);
 
 	if (!strcmp(packet->name, "message"))
 		_jabber_parse_and_write_message_to_ui(packet, pb);
@@ -351,31 +348,31 @@
 static void
 _client_socket_handler(gpointer data, gint socket, PurpleInputCondition condition)
 {
-	PurpleBuddy *pb = data;
+	BonjourJabberConversation *bconv = data;
 	gint len, message_length;
 	static char message[4096];
 
-	/*TODO: use a static buffer */
-
 	/* Read the data from the socket */
 	if ((len = recv(socket, message, sizeof(message) - 1, 0)) == -1) {
 		/* There have been an error reading from the socket */
 		if (errno != EAGAIN) {
-			BonjourBuddy *bb = pb->proto_data;
 			const char *err = g_strerror(errno);
 
 			purple_debug_warning("bonjour", "receive error: %s\n", err ? err : "(null)");
 
-			bonjour_jabber_close_conversation(bb->conversation);
-			bb->conversation = NULL;
+			bonjour_jabber_close_conversation(bconv);
+			if (bconv->pb != NULL) {
+				BonjourBuddy *bb = bconv->pb->proto_data;
+				bb->conversation = NULL;
+			}
 
 			/* I guess we really don't need to notify the user.
 			 * If they try to send another message it'll reconnect */
 		}
 		return;
 	} else if (len == 0) { /* The other end has closed the socket */
-		purple_debug_warning("bonjour", "Connection closed (without stream end) by %s.\n", pb->name ? pb->name : "(null)");
-		bonjour_jabber_stream_ended(pb);
+		purple_debug_warning("bonjour", "Connection closed (without stream end) by %s.\n", (bconv->pb && bconv->pb->name) ? bconv->pb->name : "(unknown)");
+		bonjour_jabber_stream_ended(bconv);
 		return;
 	} else {
 		message_length = len;
@@ -389,30 +386,34 @@
 
 	purple_debug_info("bonjour", "Receive: -%s- %d bytes\n", message, len);
 
-	bonjour_parser_process(pb, message, message_length);
+	bonjour_parser_process(bconv, message, message_length);
 }
 
-void bonjour_jabber_stream_ended(PurpleBuddy *pb) {
-	BonjourBuddy *bb = pb->proto_data;
+void bonjour_jabber_stream_ended(BonjourJabberConversation *bconv) {
 
-	purple_debug_info("bonjour", "Recieved conversation close notification from %s.\n", pb->name);
-
-	g_return_if_fail(bb != NULL);
+	purple_debug_info("bonjour", "Recieved conversation close notification from %s.\n", bconv->pb ? bconv->pb->name : "(unknown)");
 
 	/* Inform the user that the conversation has been closed */
-	if (bb->conversation != NULL) {
+	if (bconv != NULL) {
+		BonjourBuddy *bb = NULL;
+
+		if(bconv->pb != NULL)
+			bb = bconv->pb->proto_data;
 #if 0
-		PurpleConversation *conv;
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, pb->name, pb->account);
-		if (conv != NULL) {
-			char *tmp = g_strdup_printf(_("%s has closed the conversation."), pb->name);
-			purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
-			g_free(tmp);
+		if(bconv->pb != NULL) {
+			PurpleConversation *conv;
+			conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bconv->pb->name, bconv->pb->account);
+			if (conv != NULL) {
+				char *tmp = g_strdup_printf(_("%s has closed the conversation."), bconv->pb->name);
+				purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
+				g_free(tmp);
+			}
 		}
 #endif
 		/* Close the socket, clear the watcher and free memory */
-		bonjour_jabber_close_conversation(bb->conversation);
-		bb->conversation = NULL;
+		bonjour_jabber_close_conversation(bconv);
+		if(bb)
+			bb->conversation = NULL;
 	}
 }
 
@@ -425,9 +426,7 @@
 static void
 _start_stream(gpointer data, gint source, PurpleInputCondition condition)
 {
-	PurpleBuddy *pb = data;
-	BonjourBuddy *bb = pb->proto_data;
-	BonjourJabberConversation *bconv = bb->conversation;
+	BonjourJabberConversation *bconv = data;
 	struct _stream_start_data *ss = bconv->stream_data;
 	int len, ret;
 
@@ -441,23 +440,26 @@
 	else if (ret <= 0) {
 		const char *err = g_strerror(errno);
 		PurpleConversation *conv;
-		const char *ip = NULL;
+		const char *bname = bconv->buddy_name;
+		BonjourBuddy *bb = NULL;
 
-		/* For better or worse, use the first IP*/
-		if (bb->ips)
-			ip = bb->ips->data;
+		if(bconv->pb) {
+			bb = bconv->pb->proto_data;
+			bname = purple_buddy_get_name(bconv->pb);
+		}
 
-		purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n",
-				   purple_buddy_get_name(pb), ip ? ip : "(null)", bb->port_p2pj, err ? err : "(null)");
+		purple_debug_error("bonjour", "Error starting stream with buddy %s at %s error: %s\n",
+				   bname ? bname : "(unknown)", bconv->ip, err ? err : "(null)");
 
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account);
+		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bname, bconv->account);
 		if (conv != NULL)
 			purple_conversation_write(conv, NULL,
 				  _("Unable to send the message, the conversation couldn't be started."),
 				  PURPLE_MESSAGE_SYSTEM, time(NULL));
 
 		bonjour_jabber_close_conversation(bconv);
-		bb->conversation = NULL;
+		if(bb != NULL)
+			bb->conversation = NULL;
 
 		return;
 	}
@@ -479,20 +481,27 @@
 	bconv->tx_handler = 0;
 	bconv->sent_stream_start = FULLY_SENT;
 
-	bonjour_jabber_stream_started(pb);
+	bonjour_jabber_stream_started(bconv);
 }
 
-static gboolean bonjour_jabber_send_stream_init(PurpleBuddy *pb, int client_socket)
+static gboolean bonjour_jabber_send_stream_init(BonjourJabberConversation *bconv, int client_socket)
 {
 	int ret, len;
 	char *stream_start;
-	BonjourBuddy *bb = pb->proto_data;
+	const char *bname = bconv->buddy_name;
+
+	if (bconv->pb != NULL)
+		bname = purple_buddy_get_name(bconv->pb);
 
-	stream_start = g_strdup_printf(DOCTYPE, purple_account_get_username(pb->account),
-								   purple_buddy_get_name(pb));
+	/* If we have no idea who "to" is, use an empty string.
+	 * If we don't know now, it is because the other side isn't playing nice, so they can't complain. */
+	if (bname == NULL)
+		bname = "";
+
+	stream_start = g_strdup_printf(DOCTYPE, purple_account_get_username(bconv->account), bname);
 	len = strlen(stream_start);
 
-	bb->conversation->sent_stream_start = PARTIALLY_SENT;
+	bconv->sent_stream_start = PARTIALLY_SENT;
 
 	/* Start the stream */
 	ret = send(client_socket, stream_start, len, 0);
@@ -501,14 +510,18 @@
 		ret = 0;
 	else if (ret <= 0) {
 		const char *err = g_strerror(errno);
-		const char *ip = NULL;
+
+		purple_debug_error("bonjour", "Error starting stream with buddy %s at %s error: %s\n",
+				   (*bname) ? bname : "(unknown)", bconv->ip, err ? err : "(null)");
 
-		/* For better or worse, use the first IP*/
-		if (bb->ips)
-			ip = bb->ips->data;
-
-		purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n",
-				   purple_buddy_get_name(pb), ip ? ip : "(null)", bb->port_p2pj, err ? err : "(null)");
+		if (bconv->pb) {
+			PurpleConversation *conv;
+			conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bname, bconv->account);
+			if (conv != NULL)
+				purple_conversation_write(conv, NULL,
+					  _("Unable to send the message, the conversation couldn't be started."),
+					  PURPLE_MESSAGE_SYSTEM, time(NULL));
+		}
 
 		close(client_socket);
 		g_free(stream_start);
@@ -520,63 +533,61 @@
 	if (ret < len) {
 		struct _stream_start_data *ss = g_new(struct _stream_start_data, 1);
 		ss->msg = g_strdup(stream_start + ret);
-		bb->conversation->stream_data = ss;
+		bconv->stream_data = ss;
 		/* Finish sending the stream start */
-		bb->conversation->tx_handler = purple_input_add(client_socket,
-			PURPLE_INPUT_WRITE, _start_stream, pb);
+		bconv->tx_handler = purple_input_add(client_socket,
+			PURPLE_INPUT_WRITE, _start_stream, bconv);
 	} else
-		bb->conversation->sent_stream_start = FULLY_SENT;
+		bconv->sent_stream_start = FULLY_SENT;
 
 	g_free(stream_start);
 
 	return TRUE;
 }
 
-static gboolean
-_async_bonjour_jabber_close_conversation(gpointer data) {
-	BonjourJabberConversation *bconv = data;
-	bonjour_jabber_close_conversation(bconv);
-	return FALSE;
-}
+/* This gets called when we've successfully sent our <stream:stream />
+ * AND when we've recieved a <stream:stream /> */
+void bonjour_jabber_stream_started(BonjourJabberConversation *bconv) {
 
-void bonjour_jabber_stream_started(PurpleBuddy *pb) {
-	BonjourBuddy *bb = pb->proto_data;
-	BonjourJabberConversation *bconv = bb->conversation;
-
-	if (bconv->sent_stream_start == NOT_SENT && !bonjour_jabber_send_stream_init(pb, bconv->socket)) {
+	if (bconv->sent_stream_start == NOT_SENT && !bonjour_jabber_send_stream_init(bconv, bconv->socket)) {
 		const char *err = g_strerror(errno);
-		PurpleConversation *conv;
-		const char *ip = NULL;
+		const char *bname = bconv->buddy_name;
 
-		/* For better or worse, use the first IP*/
-		if (bb->ips)
-			ip = bb->ips->data;
+		if (bconv->pb)
+			bname = purple_buddy_get_name(bconv->pb);
+
+		purple_debug_error("bonjour", "Error starting stream with buddy %s at %s error: %s\n",
+				   bname ? bname : "(unknown)", bconv->ip, err ? err : "(null)");
 
-		purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n",
-				   purple_buddy_get_name(pb), ip ? ip : "(null)", bb->port_p2pj, err ? err : "(null)");
+		if (bconv->pb) {
+			PurpleConversation *conv;
+			conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bname, bconv->account);
+			if (conv != NULL)
+				purple_conversation_write(conv, NULL,
+					  _("Unable to send the message, the conversation couldn't be started."),
+					  PURPLE_MESSAGE_SYSTEM, time(NULL));
+		}
 
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account);
-		if (conv != NULL)
-			purple_conversation_write(conv, NULL,
-				  _("Unable to send the message, the conversation couldn't be started."),
-				  PURPLE_MESSAGE_SYSTEM, time(NULL));
+		/* We don't want to recieve anything else */
+		close(bconv->socket);
+		bconv->socket = -1;
 
-		close(bconv->socket);
 		/* This must be asynchronous because it destroys the parser and we
 		 * may be in the middle of parsing.
 		 */
-		purple_timeout_add(0, _async_bonjour_jabber_close_conversation, bb->conversation);
-		bb->conversation = NULL;
+		async_bonjour_jabber_close_conversation(bconv);
 		return;
 	}
 
-	/* If the stream has been completely started, we can start doing stuff */
-	if (bconv->sent_stream_start == FULLY_SENT && bconv->recv_stream_start && purple_circ_buffer_get_max_read(bconv->tx_buf) > 0) {
+	/* If the stream has been completely started and we know who we're talking to, we can start doing stuff. */
+	/* I don't think the circ_buffer can actually contain anything without a buddy being associated, but lets be explicit. */
+	if (bconv->sent_stream_start == FULLY_SENT && bconv->recv_stream_start
+			&& bconv->pb && purple_circ_buffer_get_max_read(bconv->tx_buf) > 0) {
 		/* Watch for when we can write the buffered messages */
 		bconv->tx_handler = purple_input_add(bconv->socket, PURPLE_INPUT_WRITE,
-			_send_data_write_cb, pb);
+			_send_data_write_cb, bconv->pb);
 		/* We can probably write the data right now. */
-		_send_data_write_cb(pb, bconv->socket, PURPLE_INPUT_WRITE);
+		_send_data_write_cb(bconv->pb, bconv->socket, PURPLE_INPUT_WRITE);
 	}
 
 }
@@ -584,15 +595,14 @@
 static void
 _server_socket_handler(gpointer data, int server_socket, PurpleInputCondition condition)
 {
-	PurpleBuddy *pb = NULL;
+	BonjourJabber *jdata = data;
 	struct sockaddr_in their_addr; /* connector's address information */
 	socklen_t sin_size = sizeof(struct sockaddr);
 	int client_socket;
 	int flags;
-	BonjourBuddy *bb;
 	char *address_text = NULL;
-	PurpleBuddyList *bl = purple_get_blist();
-	struct _check_buddy_by_address_t *cbba;
+	struct _match_buddies_by_address_t *mbba;
+	BonjourJabberConversation *bconv;
 
 	/* Check that it is a read condition */
 	if (condition != PURPLE_INPUT_READ)
@@ -607,39 +617,35 @@
 	/* Look for the buddy that has opened the conversation and fill information */
 	address_text = inet_ntoa(their_addr.sin_addr);
 	purple_debug_info("bonjour", "Received incoming connection from %s.\n", address_text);
-	cbba = g_new0(struct _check_buddy_by_address_t, 1);
-	cbba->address = address_text;
-	cbba->pb = &pb;
-	cbba->bj = data;
-	g_hash_table_foreach(bl->buddies, _check_buddy_by_address, cbba);
-	g_free(cbba);
-	if (pb == NULL)
-	{
+	mbba = g_new0(struct _match_buddies_by_address_t, 1);
+	mbba->address = address_text;
+	mbba->jdata = jdata;
+	g_hash_table_foreach(purple_get_blist()->buddies, _match_buddies_by_address, mbba);
+
+	if (mbba->matched_buddies == NULL) {
 		purple_debug_info("bonjour", "We don't like invisible buddies, this is not a superheros comic\n");
+		g_slist_free(mbba->matched_buddies);
+		g_free(mbba);
 		close(client_socket);
 		return;
 	}
-	bb = pb->proto_data;
 
-	/* Check if the conversation has been previously started */
-	/* This really shouldn't ever happen unless something weird is going on */
-	if (bb->conversation == NULL)
-	{
-		bb->conversation = bonjour_jabber_conv_new(pb);
+	g_slist_free(mbba->matched_buddies);
+	g_free(mbba);
 
-		/* We wait for the stream start before doing anything else */
-		bb->conversation->socket = client_socket;
-		bb->conversation->rx_handler = purple_input_add(client_socket,
-			PURPLE_INPUT_READ, _client_socket_handler, pb);
+	/* We've established that this *could* be from one of our buddies.
+	 * Wait for the stream open to see if that matches too before assigning it.
+	 */
+	bconv = bonjour_jabber_conv_new(NULL, jdata->account, address_text);
 
-	} else {
-		purple_debug_warning("bonjour", "Ignoring incoming connection because an existing connection exists.\n");
-		close(client_socket);
-	}
+	/* We wait for the stream start before doing anything else */
+	bconv->socket = client_socket;
+	bconv->rx_handler = purple_input_add(client_socket, PURPLE_INPUT_READ, _client_socket_handler, bconv);
+
 }
 
 gint
-bonjour_jabber_start(BonjourJabber *data)
+bonjour_jabber_start(BonjourJabber *jdata)
 {
 	struct sockaddr_in my_addr;
 	int yes = 1;
@@ -647,20 +653,20 @@
 	gboolean bind_successful;
 
 	/* Open a listening socket for incoming conversations */
-	if ((data->socket = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+	if ((jdata->socket = socket(PF_INET, SOCK_STREAM, 0)) < 0)
 	{
 		purple_debug_error("bonjour", "Cannot open socket: %s\n", g_strerror(errno));
-		purple_connection_error_reason (data->account->gc,
+		purple_connection_error_reason (jdata->account->gc,
 			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 			_("Cannot open socket"));
 		return -1;
 	}
 
 	/* Make the socket reusable */
-	if (setsockopt(data->socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
+	if (setsockopt(jdata->socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
 	{
 		purple_debug_error("bonjour", "Error setting socket options: %s\n", g_strerror(errno));
-		purple_connection_error_reason (data->account->gc,
+		purple_connection_error_reason (jdata->account->gc,
 			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 			_("Error setting socket options"));
 		return -1;
@@ -673,30 +679,30 @@
 	bind_successful = FALSE;
 	for (i = 0; i < 10; i++)
 	{
-		my_addr.sin_port = htons(data->port);
-		if (bind(data->socket, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == 0)
+		my_addr.sin_port = htons(jdata->port);
+		if (bind(jdata->socket, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == 0)
 		{
 			bind_successful = TRUE;
 			break;
 		}
-		data->port++;
+		jdata->port++;
 	}
 
 	/* On no!  We tried 10 ports and could not bind to ANY of them */
 	if (!bind_successful)
 	{
 		purple_debug_error("bonjour", "Cannot bind socket: %s\n", g_strerror(errno));
-		purple_connection_error_reason (data->account->gc,
+		purple_connection_error_reason (jdata->account->gc,
 			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 			_("Could not bind socket to port"));
 		return -1;
 	}
 
 	/* Attempt to listen on the bound socket */
-	if (listen(data->socket, 10) != 0)
+	if (listen(jdata->socket, 10) != 0)
 	{
 		purple_debug_error("bonjour", "Cannot listen on socket: %s\n", g_strerror(errno));
-		purple_connection_error_reason (data->account->gc,
+		purple_connection_error_reason (jdata->account->gc,
 			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 			_("Could not listen on socket"));
 		return -1;
@@ -704,18 +710,18 @@
 
 #if 0
 	/* TODO: Why isn't this being used? */
-	data->socket = purple_network_listen(data->port, SOCK_STREAM);
+	data->socket = purple_network_listen(jdata->port, SOCK_STREAM);
 
-	if (data->socket == -1)
+	if (jdata->socket == -1)
 	{
 		purple_debug_error("bonjour", "No se ha podido crear el socket\n");
 	}
 #endif
 
 	/* Open a watcher in the socket we have just opened */
-	data->watcher_id = purple_input_add(data->socket, PURPLE_INPUT_READ, _server_socket_handler, data);
+	jdata->watcher_id = purple_input_add(jdata->socket, PURPLE_INPUT_READ, _server_socket_handler, jdata);
 
-	return data->port;
+	return jdata->port;
 }
 
 static void
@@ -728,14 +734,9 @@
 
 	if (source < 0) {
 		PurpleConversation *conv;
-		const char *ip = NULL;
-
-		/* For better or worse, use the first IP*/
-		if (bb->ips)
-			ip = bb->ips->data;
 
 		purple_debug_error("bonjour", "Error connecting to buddy %s at %s:%d error: %s\n",
-				   purple_buddy_get_name(pb), ip ? ip : "(null)", bb->port_p2pj, error ? error : "(null)");
+				   purple_buddy_get_name(pb), bb->conversation->ip, bb->port_p2pj, error ? error : "(null)");
 
 		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account);
 		if (conv != NULL)
@@ -748,17 +749,12 @@
 		return;
 	}
 
-	if (!bonjour_jabber_send_stream_init(pb, source)) {
+	if (!bonjour_jabber_send_stream_init(bb->conversation, source)) {
 		const char *err = g_strerror(errno);
 		PurpleConversation *conv;
-		const char *ip = NULL;
-
-		/* For better or worse, use the first IP*/
-		if (bb->ips)
-			ip = bb->ips->data;
 
 		purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n",
-				   purple_buddy_get_name(pb), ip ? ip : "(null)", bb->port_p2pj, err ? err : "(null)");
+				   purple_buddy_get_name(pb), bb->conversation->ip, bb->port_p2pj, err ? err : "(null)");
 
 		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account);
 		if (conv != NULL)
@@ -775,19 +771,116 @@
 	/* Start listening for the stream acknowledgement */
 	bb->conversation->socket = source;
 	bb->conversation->rx_handler = purple_input_add(source,
-		PURPLE_INPUT_READ, _client_socket_handler, pb);
+		PURPLE_INPUT_READ, _client_socket_handler, bb->conversation);
+}
+
+void
+bonjour_jabber_conv_match_by_name(BonjourJabberConversation *bconv) {
+	PurpleBuddy *pb;
+
+	g_return_if_fail(bconv->ip != NULL);
+	g_return_if_fail(bconv->pb == NULL);
+
+	pb = purple_find_buddy(bconv->account, bconv->buddy_name);
+	if (pb && pb->proto_data) {
+		BonjourBuddy *bb = pb->proto_data;
+		const char *ip;
+		GSList *tmp = bb->ips;
+
+		purple_debug_info("bonjour", "Found buddy %s for incoming conversation \"from\" attrib.\n",
+			purple_buddy_get_name(pb));
+
+		/* Check that one of the buddy's IPs matches */
+		while(tmp) {
+			ip = tmp->data;
+			if (ip != NULL && g_ascii_strcasecmp(ip, bconv->ip) == 0) {
+				BonjourJabber *jdata = ((BonjourData*) bconv->account->gc->proto_data)->jabber_data;
+
+				purple_debug_info("bonjour", "Matched buddy %s to incoming conversation \"from\" attrib and IP (%s)\n",
+					purple_buddy_get_name(pb), bconv->ip);
+
+				/* Attach conv. to buddy and remove from pending list */
+				jdata->pending_conversations = g_slist_remove(jdata->pending_conversations, bconv);
+
+				/* Check if the buddy already has a conversation and, if so, replace it */
+				if(bb->conversation != NULL && bb->conversation != bconv)
+					bonjour_jabber_close_conversation(bb->conversation);
+
+				bconv->pb = pb;
+				bb->conversation = bconv;
+
+				break;
+			}
+			tmp = tmp->next;
+		}
+	}
+
+	/* We've failed to match a buddy - give up */
+	if (bconv->pb == NULL) {
+		/* This must be asynchronous because it destroys the parser and we
+		 * may be in the middle of parsing.
+		 */
+		async_bonjour_jabber_close_conversation(bconv);
+	}
+}
+
+
+void
+bonjour_jabber_conv_match_by_ip(BonjourJabberConversation *bconv) {
+	BonjourJabber *jdata = ((BonjourData*) bconv->account->gc->proto_data)->jabber_data;
+	struct _match_buddies_by_address_t *mbba;
+
+	mbba = g_new0(struct _match_buddies_by_address_t, 1);
+	mbba->address = bconv->ip;
+	mbba->jdata = jdata;
+	g_hash_table_foreach(purple_get_blist()->buddies, _match_buddies_by_address, mbba);
+
+	/* If there is exactly one match, use it */
+	if(mbba->matched_buddies != NULL) {
+		if(mbba->matched_buddies->next != NULL)
+			purple_debug_error("bonjour", "More than one buddy matched for ip %s.\n", bconv->ip);
+		else {
+			PurpleBuddy *pb = mbba->matched_buddies->data;
+			BonjourBuddy *bb = pb->proto_data;
+
+			purple_debug_info("bonjour", "Matched buddy %s to incoming conversation using IP (%s)\n",
+				purple_buddy_get_name(pb), bconv->ip);
+
+			/* Attach conv. to buddy and remove from pending list */
+			jdata->pending_conversations = g_slist_remove(jdata->pending_conversations, bconv);
+
+			/* Check if the buddy already has a conversation and, if so, replace it */
+			if (bb->conversation != NULL && bb->conversation != bconv)
+				bonjour_jabber_close_conversation(bb->conversation);
+
+			bconv->pb = pb;
+			bb->conversation = bconv;
+		}
+	} else
+		purple_debug_error("bonjour", "No buddies matched for ip %s.\n", bconv->ip);
+
+	/* We've failed to match a buddy - give up */
+	if (bconv->pb == NULL) {
+		/* This must be asynchronous because it destroys the parser and we
+		 * may be in the middle of parsing.
+		 */
+		async_bonjour_jabber_close_conversation(bconv);
+	}
+
+	g_slist_free(mbba->matched_buddies);
+	g_free(mbba);
 }
 
 static PurpleBuddy *
-_find_or_start_conversation(BonjourJabber *data, const gchar *to)
+_find_or_start_conversation(BonjourJabber *jdata, const gchar *to)
 {
 	PurpleBuddy *pb = NULL;
 	BonjourBuddy *bb = NULL;
 
-	g_return_val_if_fail(data != NULL, NULL);
+	g_return_val_if_fail(jdata != NULL, NULL);
 	g_return_val_if_fail(to != NULL, NULL);
 
-	pb = purple_find_buddy(data->account, to);
+	pb = purple_find_buddy(jdata->account, to);
 	if (pb == NULL || pb->proto_data == NULL)
 		/* You can not send a message to an offline buddy */
 		return NULL;
@@ -799,24 +892,21 @@
 	{
 		PurpleProxyConnectData *connect_data;
 		PurpleProxyInfo *proxy_info;
-		const char *ip = NULL;
-
 		/* For better or worse, use the first IP*/
-		if (bb->ips)
-			ip = bb->ips->data;
+		const char *ip = bb->ips->data;
 
 		purple_debug_info("bonjour", "Starting conversation with %s\n", to);
 
 		/* Make sure that the account always has a proxy of "none".
 		 * This is kind of dirty, but proxy_connect_none() isn't exposed. */
-		proxy_info = purple_account_get_proxy_info(data->account);
+		proxy_info = purple_account_get_proxy_info(jdata->account);
 		if (proxy_info == NULL) {
 			proxy_info = purple_proxy_info_new();
-			purple_account_set_proxy_info(data->account, proxy_info);
+			purple_account_set_proxy_info(jdata->account, proxy_info);
 		}
 		purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_NONE);
 
-		connect_data = purple_proxy_connect(NULL, data->account,
+		connect_data = purple_proxy_connect(NULL, jdata->account,
 						    ip, bb->port_p2pj, _connected_to_buddy, pb);
 
 		if (connect_data == NULL) {
@@ -824,7 +914,7 @@
 			return NULL;
 		}
 
-		bb->conversation = bonjour_jabber_conv_new(pb);
+		bb->conversation = bonjour_jabber_conv_new(pb, jdata->account, ip);
 		bb->conversation->connect_data = connect_data;
 		/* We don't want _send_data() to register the tx_handler;
 		 * that neeeds to wait until we're actually connected. */
@@ -834,7 +924,7 @@
 }
 
 int
-bonjour_jabber_send_message(BonjourJabber *data, const gchar *to, const gchar *body)
+bonjour_jabber_send_message(BonjourJabber *jdata, const gchar *to, const gchar *body)
 {
 	xmlnode *message_node, *node, *node2;
 	gchar *message;
@@ -842,7 +932,7 @@
 	BonjourBuddy *bb;
 	int ret;
 
-	pb = _find_or_start_conversation(data, to);
+	pb = _find_or_start_conversation(jdata, to);
 	if (pb == NULL) {
 		purple_debug_info("bonjour", "Can't send a message to an offline buddy (%s).\n", to);
 		/* You can not send a message to an offline buddy */
@@ -853,7 +943,7 @@
 
 	message_node = xmlnode_new("message");
 	xmlnode_set_attrib(message_node, "to", bb->name);
-	xmlnode_set_attrib(message_node, "from", purple_account_get_username(data->account));
+	xmlnode_set_attrib(message_node, "from", purple_account_get_username(jdata->account));
 	xmlnode_set_attrib(message_node, "type", "chat");
 
 	/* Enclose the message from the UI within a "font" node */
@@ -885,26 +975,57 @@
 	return ret;
 }
 
+static gboolean
+_async_bonjour_jabber_close_conversation_cb(gpointer data) {
+	BonjourJabberConversation *bconv = data;
+	bonjour_jabber_close_conversation(bconv);
+	return FALSE;
+}
+
+void
+async_bonjour_jabber_close_conversation(BonjourJabberConversation *bconv) {
+	BonjourJabber *jdata = ((BonjourData*) bconv->account->gc->proto_data)->jabber_data;
+
+	jdata->pending_conversations = g_slist_remove(jdata->pending_conversations, bconv);
+
+	/* Disconnect this conv. from the buddy here so it can't be disposed of twice.*/
+	if(bconv->pb != NULL) {
+		BonjourBuddy *bb = bconv->pb->proto_data;
+		if (bb->conversation == bconv)
+			bb->conversation = NULL;
+	}
+
+	purple_timeout_add(0, _async_bonjour_jabber_close_conversation_cb, bconv);
+}
+
 void
 bonjour_jabber_close_conversation(BonjourJabberConversation *bconv)
 {
 	if (bconv != NULL) {
-		GList *xfers, *tmp_next;
-		BonjourData *bd = bconv->pb->account->gc->proto_data;
+		BonjourData *bd = NULL;
+
+		if(PURPLE_CONNECTION_IS_VALID(bconv->account->gc)) {
+			bd = bconv->account->gc->proto_data;
+			bd->jabber_data->pending_conversations = g_slist_remove(bd->jabber_data->pending_conversations, bconv);
+		}
 
 		/* Cancel any file transfers that are waiting to begin */
-		xfers = bd->xfer_lists;
-		while(xfers != NULL) {
-			PurpleXfer *xfer = xfers->data;
-			tmp_next = xfers->next;
-			/* We only need to cancel this if it hasn't actually started transferring. */
-			/* This will change if we ever support IBB transfers. */
-			if (strcmp(xfer->who, bconv->pb->name) == 0
-					&& (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_NOT_STARTED
-					    || purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_UNKNOWN)) {
-				purple_xfer_cancel_remote(xfer);
+		/* There wont be any transfers if it hasn't been attached to a buddy */
+		if (bconv->pb != NULL && bd != NULL) {
+			GSList *xfers, *tmp_next;
+			xfers = bd->xfer_lists;
+			while(xfers != NULL) {
+				PurpleXfer *xfer = xfers->data;
+				tmp_next = xfers->next;
+				/* We only need to cancel this if it hasn't actually started transferring. */
+				/* This will change if we ever support IBB transfers. */
+				if (strcmp(xfer->who, bconv->pb->name) == 0
+						&& (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_NOT_STARTED
+							|| purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_UNKNOWN)) {
+					purple_xfer_cancel_remote(xfer);
+				}
+				xfers = tmp_next;
 			}
-			xfers = tmp_next;
 		}
 
 		/* Close the socket and remove the watcher */
@@ -933,25 +1054,26 @@
 		if (bconv->context != NULL)
 			bonjour_parser_setup(bconv);
 
+		g_free(bconv->buddy_name);
+		g_free(bconv->ip);
 		g_free(bconv);
 	}
 }
 
 void
-bonjour_jabber_stop(BonjourJabber *data)
+bonjour_jabber_stop(BonjourJabber *jdata)
 {
 	/* Close the server socket and remove the watcher */
-	if (data->socket >= 0)
-		close(data->socket);
-	if (data->watcher_id > 0)
-		purple_input_remove(data->watcher_id);
+	if (jdata->socket >= 0)
+		close(jdata->socket);
+	if (jdata->watcher_id > 0)
+		purple_input_remove(jdata->watcher_id);
 
 	/* Close all the conversation sockets and remove all the watchers after sending end streams */
-	if (data->account->gc != NULL)
-	{
+	if (jdata->account->gc != NULL) {
 		GSList *buddies, *l;
 
-		buddies = purple_find_buddies(data->account, purple_account_get_username(data->account));
+		buddies = purple_find_buddies(jdata->account, NULL);
 		for (l = buddies; l; l = l->next) {
 			BonjourBuddy *bb = ((PurpleBuddy*) l->data)->proto_data;
 			bonjour_jabber_close_conversation(bb->conversation);
@@ -960,6 +1082,11 @@
 
 		g_slist_free(buddies);
 	}
+
+	while (jdata->pending_conversations != NULL) {
+		bonjour_jabber_close_conversation(jdata->pending_conversations->data);
+		jdata->pending_conversations = g_slist_delete_link(jdata->pending_conversations, jdata->pending_conversations);
+	}
 }
 
 XepIq *
@@ -1056,7 +1183,7 @@
 	PurpleBuddy *pb = NULL;
 
 	/* start the talk, reuse the message socket  */
-	pb = _find_or_start_conversation ((BonjourJabber*)iq->data, iq->to);
+	pb = _find_or_start_conversation((BonjourJabber*) iq->data, iq->to);
 	/* Send the message */
 	if (pb != NULL) {
 		/* Convert xml node into stream */
--- a/libpurple/protocols/bonjour/jabber.h	Fri Dec 14 00:41:28 2007 +0000
+++ b/libpurple/protocols/bonjour/jabber.h	Fri Dec 14 21:44:34 2007 +0000
@@ -38,7 +38,8 @@
 	gint port;
 	gint socket;
 	gint watcher_id;
-	PurpleAccount* account;
+	PurpleAccount *account;
+	GSList *pending_conversations;
 } BonjourJabber;
 
 typedef struct _BonjourJabberConversation
@@ -54,6 +55,11 @@
 	xmlParserCtxt *context;
 	xmlnode *current;
 	PurpleBuddy *pb;
+	PurpleAccount *account;
+
+	/* The following are only needed before attaching to a PurpleBuddy */
+	gchar *buddy_name;
+	gchar *ip;
 } BonjourJabberConversation;
 
 /**
@@ -68,14 +74,20 @@
 
 void bonjour_jabber_close_conversation(BonjourJabberConversation *bconv);
 
-void bonjour_jabber_stream_started(PurpleBuddy *pb);
+void async_bonjour_jabber_close_conversation(BonjourJabberConversation *bconv);
 
-void bonjour_jabber_stream_ended(PurpleBuddy *pb);
+void bonjour_jabber_stream_started(BonjourJabberConversation *bconv);
+
+void bonjour_jabber_stream_ended(BonjourJabberConversation *bconv);
 
 void bonjour_jabber_process_packet(PurpleBuddy *pb, xmlnode *packet);
 
 void bonjour_jabber_stop(BonjourJabber *data);
 
+void bonjour_jabber_conv_match_by_ip(BonjourJabberConversation *bconv);
+
+void bonjour_jabber_conv_match_by_name(BonjourJabberConversation *bconv);
+
 typedef enum {
 	XEP_IQ_SET,
 	XEP_IQ_GET,
--- a/libpurple/protocols/bonjour/parser.c	Fri Dec 14 00:41:28 2007 +0000
+++ b/libpurple/protocols/bonjour/parser.c	Fri Dec 14 21:44:34 2007 +0000
@@ -31,26 +31,59 @@
 #include "util.h"
 #include "xmlnode.h"
 
+static gboolean
+parse_from_attrib_and_find_buddy(BonjourJabberConversation *bconv, int nb_attributes, const xmlChar **attributes) {
+	int i;
+
+	/* If the "from" attribute is specified, attach it to the conversation. */
+	for(i=0; i < nb_attributes * 5; i+=5) {
+		if(!xmlStrcmp(attributes[i], (xmlChar*) "from")) {
+			int len = attributes[i+4] - attributes[i+3];
+			bconv->buddy_name = g_strndup(attributes[i+3], len);
+			bonjour_jabber_conv_match_by_name(bconv);
+
+			return (bconv->pb != NULL);
+		}
+	}
+
+	return FALSE;
+}
+
 static void
 bonjour_parser_element_start_libxml(void *user_data,
 				   const xmlChar *element_name, const xmlChar *prefix, const xmlChar *namespace,
 				   int nb_namespaces, const xmlChar **namespaces,
 				   int nb_attributes, int nb_defaulted, const xmlChar **attributes)
 {
-	PurpleBuddy *pb = user_data;
-	BonjourBuddy *bb = pb->proto_data;
-	BonjourJabberConversation *bconv = bb->conversation;
+	BonjourJabberConversation *bconv = user_data;
 
 	xmlnode *node;
 	int i;
 
-	if(!element_name) {
-		return;
-	} else if(!xmlStrcmp(element_name, (xmlChar*) "stream")) {
-		bconv->recv_stream_start = TRUE;
-		bonjour_jabber_stream_started(pb);
+	g_return_if_fail(element_name != NULL);
+
+	if(!xmlStrcmp(element_name, (xmlChar*) "stream")) {
+		if(!bconv->recv_stream_start) {
+			bconv->recv_stream_start = TRUE;
+
+			if (bconv->pb == NULL)
+				parse_from_attrib_and_find_buddy(bconv, nb_attributes, attributes);
+
+			bonjour_jabber_stream_started(bconv);
+		}
 	} else {
 
+		/* If we haven't yet attached a buddy and this isn't "<stream:features />",
+		 * try to get a "from" attribute as a last resort to match our buddy. */
+		if(bconv->pb == NULL
+				&& !(prefix && !xmlStrcmp(prefix, (xmlChar*) "stream")
+					&& !xmlStrcmp(element_name, (xmlChar*) "features"))
+				&& !parse_from_attrib_and_find_buddy(bconv, nb_attributes, attributes))
+			/* We've run out of options for finding who the conversation is from
+			   using explicitly specified stuff; see if we can make a good match
+			   by using the IP */
+			bonjour_jabber_conv_match_by_ip(bconv);
+
 		if(bconv->current)
 			node = xmlnode_new_child(bconv->current, (const char*) element_name);
 		else
@@ -82,27 +115,19 @@
 	}
 }
 
-static gboolean _async_bonjour_jabber_stream_ended_cb(gpointer data) {
-	bonjour_jabber_stream_ended((PurpleBuddy *) data);
-	return FALSE;
-}
-
 static void
 bonjour_parser_element_end_libxml(void *user_data, const xmlChar *element_name,
 				 const xmlChar *prefix, const xmlChar *namespace)
 {
-	PurpleBuddy *pb = user_data;
-	BonjourBuddy *bb = pb->proto_data;
-	BonjourJabberConversation *bconv = bb->conversation;
+	BonjourJabberConversation *bconv = user_data;
 
 	if(!bconv->current) {
 		/* We don't keep a reference to the start stream xmlnode,
 		 * so we have to check for it here to close the conversation */
-		if(!xmlStrcmp(element_name, (xmlChar*) "stream")) {
+		if(!xmlStrcmp(element_name, (xmlChar*) "stream"))
 			/* Asynchronously close the conversation to prevent bonjour_parser_setup()
 			 * being called from within this context */
-			purple_timeout_add(0, _async_bonjour_jabber_stream_ended_cb, pb);
-		}
+			async_bonjour_jabber_close_conversation(bconv);
 		return;
 	}
 
@@ -112,7 +137,7 @@
 	} else {
 		xmlnode *packet = bconv->current;
 		bconv->current = NULL;
-		bonjour_jabber_process_packet(pb, packet);
+		bonjour_jabber_process_packet(bconv->pb, packet);
 		xmlnode_free(packet);
 	}
 }
@@ -120,9 +145,7 @@
 static void
 bonjour_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len)
 {
-	PurpleBuddy *pb = user_data;
-	BonjourBuddy *bb = pb->proto_data;
-	BonjourJabberConversation *bconv = bb->conversation;
+	BonjourJabberConversation *bconv = user_data;
 
 	if(!bconv->current)
 		return;
@@ -184,21 +207,17 @@
 }
 
 
-void bonjour_parser_process(PurpleBuddy *pb, const char *buf, int len)
+void bonjour_parser_process(BonjourJabberConversation *bconv, const char *buf, int len)
 {
-	BonjourBuddy *bb = pb->proto_data;
 
-	g_return_if_fail(bb != NULL);
-	g_return_if_fail(bb->conversation != NULL);
-
-	if (bb->conversation->context ==  NULL) {
+	if (bconv->context == NULL) {
 		/* libxml inconsistently starts parsing on creating the
 		 * parser, so do a ParseChunk right afterwards to force it. */
-		bb->conversation->context = xmlCreatePushParserCtxt(&bonjour_parser_libxml, pb, buf, len, NULL);
-		xmlParseChunk(bb->conversation->context, "", 0, 0);
-	} else if (xmlParseChunk(bb->conversation->context, buf, len, 0) < 0) {
+		bconv->context = xmlCreatePushParserCtxt(&bonjour_parser_libxml, bconv, buf, len, NULL);
+		xmlParseChunk(bconv->context, "", 0, 0);
+	} else if (xmlParseChunk(bconv->context, buf, len, 0) < 0)
 		/* TODO: What should we do here - I assume we should display an error or something (maybe just print something to the conv?) */
 		purple_debug_error("bonjour", "Error parsing xml.\n");
-	}
+
 }
 
--- a/libpurple/protocols/bonjour/parser.h	Fri Dec 14 00:41:28 2007 +0000
+++ b/libpurple/protocols/bonjour/parser.h	Fri Dec 14 21:44:34 2007 +0000
@@ -28,6 +28,6 @@
 #include "jabber.h"
 
 void bonjour_parser_setup(BonjourJabberConversation *bconv);
-void bonjour_parser_process(PurpleBuddy *pb, const char *buf, int len);
+void bonjour_parser_process(BonjourJabberConversation *bconv, const char *buf, int len);
 
 #endif /* _PURPLE_BONJOUR_PARSER_H_ */