# HG changeset patch
# Node ID 53062ff9b7ff
# Parent  9cb78e799a79
diff --git a/libpurple/protocols/bonjour/bonjour.c b/libpurple/protocols/bonjour/bonjour.c
--- a/libpurple/protocols/bonjour/bonjour.c
+++ b/libpurple/protocols/bonjour/bonjour.c
@@ -363,10 +363,17 @@
 bonjour_convo_closed(G_GNUC_UNUSED PurpleProtocolClient *client,
                      PurpleConnection *connection, const char *who)
 {
-	PurpleBuddy *buddy = purple_blist_find_buddy(purple_connection_get_account(connection), who);
+	PurpleAccount *account = NULL;
+	PurpleContact *contact = NULL;
+	PurpleContactManager *manager = NULL;
 	BonjourBuddy *bb;
 
-	if (buddy == NULL || (bb = purple_buddy_get_protocol_data(buddy)) == NULL)
+	account = purple_connection_get_account(connection);
+	manager = purple_contact_manager_get_default();
+	contact = purple_contact_manager_find_with_username(manager, account, who);
+
+	if(!PURPLE_IS_CONTACT(contact) ||
+	   (bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy")) == NULL)
 	{
 		/*
 		 * This buddy is not in our buddy list, and therefore does not really
@@ -430,9 +437,21 @@
 bonjour_can_receive_file(G_GNUC_UNUSED PurpleProtocolXfer *prplxfer,
                          PurpleConnection *connection, const char *who)
 {
-	PurpleBuddy *buddy = purple_blist_find_buddy(purple_connection_get_account(connection), who);
+	PurpleAccount *account = NULL;
+	PurpleContact *contact = NULL;
+	PurpleContactManager *manager = NULL;
+
+	account = purple_connection_get_account(connection);
+	manager = purple_contact_manager_get_default();
+	contact = purple_contact_manager_find_with_username(manager, account, who);
 
-	return (buddy != NULL && purple_buddy_get_protocol_data(buddy) != NULL);
+	if(PURPLE_IS_CONTACT(contact)) {
+		BonjourBuddy *bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
+
+		return (bb != NULL);
+	}
+
+	return FALSE;
 }
 
 static gssize
diff --git a/libpurple/protocols/bonjour/bonjour_ft.h b/libpurple/protocols/bonjour/bonjour_ft.h
--- a/libpurple/protocols/bonjour/bonjour_ft.h
+++ b/libpurple/protocols/bonjour/bonjour_ft.h
@@ -52,8 +52,8 @@
  */
 void bonjour_send_file(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who, const char *file);
 
-void xep_si_parse(PurpleConnection *pc, PurpleXmlNode *packet, PurpleBuddy *pb);
-void xep_bytestreams_parse(PurpleConnection *pc, PurpleXmlNode *packet, PurpleBuddy *pb);
+void xep_si_parse(PurpleConnection *pc, PurpleXmlNode *packet, PurpleContact *contact);
+void xep_bytestreams_parse(PurpleConnection *pc, PurpleXmlNode *packet, PurpleContact *contact);
 
 void xep_xfer_register(GTypeModule *module);
 
diff --git a/libpurple/protocols/bonjour/bonjour_ft.c b/libpurple/protocols/bonjour/bonjour_ft.c
--- a/libpurple/protocols/bonjour/bonjour_ft.c
+++ b/libpurple/protocols/bonjour/bonjour_ft.c
@@ -64,7 +64,7 @@
 	char *proxy_host;
 	int proxy_port;
 	PurpleXmlNode *streamhost;
-	PurpleBuddy *pb;
+	PurpleContact *contact;
 };
 
 G_DEFINE_DYNAMIC_TYPE(XepXfer, xep_xfer, PURPLE_TYPE_XFER);
@@ -360,7 +360,8 @@
 static void
 bonjour_xfer_init(PurpleXfer *xfer)
 {
-	PurpleBuddy *buddy;
+	PurpleContact *contact = NULL;
+	PurpleContactManager *manager = NULL;
 	BonjourBuddy *bb;
 	XepXfer *xf;
 
@@ -368,10 +369,17 @@
 
 	purple_debug_info("bonjour", "Bonjour-xfer-init.\n");
 
-	buddy = purple_blist_find_buddy(purple_xfer_get_account(xfer), purple_xfer_get_remote_user(xfer));
+	manager = purple_contact_manager_get_default();
+	contact = purple_contact_manager_find_with_username(manager,
+	                                                    purple_xfer_get_account(xfer),
+	                                                    purple_xfer_get_remote_user(xfer));
+
 	/* this buddy is offline. */
-	if (buddy == NULL || (bb = purple_buddy_get_protocol_data(buddy)) == NULL)
+	if(!PURPLE_IS_CONTACT(contact) ||
+	   (bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy")) == NULL)
+	{
 		return;
+	}
 
 	/* Assume it is the first IP. We could do something like keep track of which one is in use or something. */
 	if (bb->ips)
@@ -388,7 +396,8 @@
 }
 
 void
-xep_si_parse(PurpleConnection *pc, PurpleXmlNode *packet, PurpleBuddy *pb)
+xep_si_parse(PurpleConnection *pc, PurpleXmlNode *packet,
+             PurpleContact *contact)
 {
 	const char *type, *id;
 	BonjourData *bd;
@@ -397,15 +406,16 @@
 
 	g_return_if_fail(pc != NULL);
 	g_return_if_fail(packet != NULL);
-	g_return_if_fail(pb != NULL);
+	g_return_if_fail(PURPLE_IS_CONTACT(contact));
 
-	bd = purple_connection_get_protocol_data(pc);
-	if(bd == NULL)
+	bd = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
+	if(bd == NULL) {
 		return;
+	}
 
 	purple_debug_info("bonjour", "xep-si-parse.\n");
 
-	name = purple_buddy_get_name(pb);
+	name = purple_contact_info_get_username(PURPLE_CONTACT_INFO(contact));
 
 	type = purple_xmlnode_get_attrib(packet, "type");
 	id = purple_xmlnode_get_attrib(packet, "id");
@@ -574,7 +584,7 @@
  */
 static gboolean
 add_ipv6_link_local_ifaces(PurpleXmlNode *cur_streamhost, const char *host,
-			   PurpleBuddy *pb)
+                           PurpleContact *contact)
 {
 	PurpleXmlNode *new_streamhost = NULL;
 	GInetAddress *addr;
@@ -592,7 +602,7 @@
 	}
 	g_clear_object(&addr);
 
-	bb = purple_buddy_get_protocol_data(pb);
+	bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
 
 	for (ip_elem = bb->ips;
 	     (ip_elem = g_slist_find_custom(ip_elem, host, (GCompareFunc)&xep_addr_differ));
@@ -611,8 +621,8 @@
 }
 
 static gboolean
-__xep_bytestreams_parse(PurpleBuddy *pb, PurpleXfer *xfer, PurpleXmlNode *streamhost,
-			const char *iq_id)
+__xep_bytestreams_parse(PurpleContact *contact, PurpleXfer *xfer,
+                        PurpleXmlNode *streamhost, const char *iq_id)
 {
 	char *tmp_iq_id;
 	const char *jid, *host, *port;
@@ -630,7 +640,7 @@
 
 		/* skip IPv6 link local addresses with no interface scope
 		 * (but try to add a new one with an interface scope then) */
-		if(add_ipv6_link_local_ifaces(streamhost, host, pb))
+		if(add_ipv6_link_local_ifaces(streamhost, host, contact))
 			continue;
 
 		tmp_iq_id = g_strdup(iq_id);
@@ -643,7 +653,7 @@
 		xf->proxy_host = g_strdup(host);
 		xf->proxy_port = portnum;
 		xf->streamhost = streamhost;
-		xf->pb = pb;
+		xf->contact = contact;
 		purple_debug_info("bonjour", "bytestream offer parse"
 				  "jid=%s host=%s port=%d.\n", jid, host, portnum);
 		bonjour_bytestreams_connect(xfer);
@@ -654,7 +664,8 @@
 }
 
 void
-xep_bytestreams_parse(PurpleConnection *pc, PurpleXmlNode *packet, PurpleBuddy *pb)
+xep_bytestreams_parse(PurpleConnection *pc, PurpleXmlNode *packet,
+                      PurpleContact *contact)
 {
 	const char *type, *from, *iq_id, *sid;
 	PurpleXmlNode *query, *streamhost;
@@ -663,16 +674,17 @@
 
 	g_return_if_fail(pc != NULL);
 	g_return_if_fail(packet != NULL);
-	g_return_if_fail(pb != NULL);
+	g_return_if_fail(PURPLE_IS_CONTACT(contact));
 
-	bd = purple_connection_get_protocol_data(pc);
-	if(bd == NULL)
+	bd = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
+	if(bd == NULL) {
 		return;
+	}
 
 	purple_debug_info("bonjour", "xep-bytestreams-parse.\n");
 
 	type = purple_xmlnode_get_attrib(packet, "type");
-	from = purple_buddy_get_name(pb);
+	from = purple_contact_info_get_username(PURPLE_CONTACT_INFO(contact));
 	query = purple_xmlnode_get_child(packet,"query");
 	if(!type)
 		return;
@@ -694,7 +706,7 @@
 	xfer = bonjour_si_xfer_find(bd, sid, from);
 	streamhost = purple_xmlnode_get_child(query, "streamhost");
 
-	if(xfer && streamhost && __xep_bytestreams_parse(pb, xfer, streamhost, iq_id))
+	if(xfer && streamhost && __xep_bytestreams_parse(contact, xfer, streamhost, iq_id))
 		return; /* success */
 
 	purple_debug_error("bonjour", "Didn't find an acceptable streamhost.\n");
@@ -966,7 +978,7 @@
 	                   xf->proxy_host, error_message);
 
 	tmp_node = purple_xmlnode_get_next_twin(xf->streamhost);
-	ret = __xep_bytestreams_parse(xf->pb, xfer, tmp_node, xf->iq_id);
+	ret = __xep_bytestreams_parse(xf->contact, xfer, tmp_node, xf->iq_id);
 
 	if (!ret) {
 		xep_ft_si_reject(xf->data, xf->iq_id, purple_xfer_get_remote_user(xfer),
@@ -1046,7 +1058,7 @@
 	GSocketAddress *addr;
 	GInetSocketAddress *inet_addr;
 	GSocketAddress *proxy_addr;
-	PurpleBuddy *pb;
+	PurpleContact *contact = NULL;
 	gchar *hash_input;
 	gchar *dstaddr;
 	GError *error = NULL;
@@ -1089,9 +1101,10 @@
 		return;
 	}
 
-	pb = xf->pb;
-	hash_input = g_strdup_printf("%s%s%s", xf->sid, purple_buddy_get_name(pb),
-	                             bonjour_get_jid(purple_buddy_get_account(pb)));
+	contact = xf->contact;
+	hash_input = g_strdup_printf("%s%s%s", xf->sid,
+	                             purple_contact_info_get_username(PURPLE_CONTACT_INFO(contact)),
+	                             bonjour_get_jid(purple_contact_get_account(contact)));
 	dstaddr = g_compute_checksum_for_string(G_CHECKSUM_SHA1, hash_input, -1);
 	g_free(hash_input);
 
@@ -1128,7 +1141,7 @@
 	purple_debug_info("bonjour", "bonjour-bytestreams-connect.");
 
 	xf = XEP_XFER(xfer);
-	account = purple_buddy_get_account(xf->pb);
+	account = purple_contact_get_account(xf->contact);
 
 	xf->client = purple_gio_socket_client_new(account, &error);
 	if (xf->client == NULL) {
diff --git a/libpurple/protocols/bonjour/buddy.h b/libpurple/protocols/bonjour/buddy.h
--- a/libpurple/protocols/bonjour/buddy.h
+++ b/libpurple/protocols/bonjour/buddy.h
@@ -91,16 +91,15 @@
 gboolean bonjour_buddy_check(BonjourBuddy *buddy);
 
 /**
- * If the buddy doesn't previously exists, it is created. Else, its data is changed (???)
- * purple_buddy is optional; it saves an additional lookup if we already have it
+ * If the buddy doesn't previously exists, it is created.
  */
-void bonjour_buddy_add_to_purple(BonjourBuddy *bonjour_buddy, PurpleBuddy *purple_buddy);
+void bonjour_buddy_add_to_purple(BonjourBuddy *bonjour_buddy);
 
 /**
  * The buddy has signed off Bonjour.
  * If the buddy is being saved, mark as offline, otherwise delete
  */
-void bonjour_buddy_signed_off(PurpleBuddy *purple_buddy);
+void bonjour_buddy_signed_off(PurpleContact *contact);
 
 /**
  * We got the buddy icon data; deal with it
diff --git a/libpurple/protocols/bonjour/buddy.c b/libpurple/protocols/bonjour/buddy.c
--- a/libpurple/protocols/bonjour/buddy.c
+++ b/libpurple/protocols/bonjour/buddy.c
@@ -119,73 +119,102 @@
  * the buddy.
  */
 void
-bonjour_buddy_add_to_purple(BonjourBuddy *bonjour_buddy, PurpleBuddy *buddy)
+bonjour_buddy_add_to_purple(BonjourBuddy *bonjour_buddy)
 {
-	PurpleGroup *group;
 	PurpleAccount *account = bonjour_buddy->account;
-	const char *status_id, *old_hash, *new_hash, *name;
+	PurpleContact *contact = NULL;
+	PurpleContactManager *manager = NULL;
+	PurplePerson *person = NULL;
+	PurplePresence *presence = NULL;
+	PurplePresencePrimitive primitive = PURPLE_PRESENCE_PRIMITIVE_AVAILABLE;
 
 	/* Translate between the Bonjour status and the Purple status */
-	if (bonjour_buddy->status != NULL && g_ascii_strcasecmp("dnd", bonjour_buddy->status) == 0)
-		status_id = BONJOUR_STATUS_ID_AWAY;
-	else
-		status_id = BONJOUR_STATUS_ID_AVAILABLE;
+	if(bonjour_buddy->status != NULL &&
+	   g_ascii_strcasecmp("dnd", bonjour_buddy->status) == 0)
+	{
+		primitive = PURPLE_PRESENCE_PRIMITIVE_AWAY;
+	}
 
 	/*
 	 * TODO: Figure out the idle time by getting the "away"
 	 * field from the DNS SD.
 	 */
 
-	/* Make sure the Bonjour group exists in our buddy list */
-	group = purple_blist_find_group(BONJOUR_GROUP_NAME); /* Use the buddy's domain, instead? */
-	if (group == NULL) {
-		group = purple_group_new(BONJOUR_GROUP_NAME);
-		purple_blist_add_group(group, NULL);
+	/* Determine if we already know about this contact. */
+	manager = purple_contact_manager_get_default();
+	contact = purple_contact_manager_find_with_username(manager, account,
+	                                                    bonjour_buddy->name);
+
+	/* If not, create the contact and add them to the manager. */
+	if(!PURPLE_IS_CONTACT(contact)) {
+		PurpleTags *tags = NULL;
+
+		contact = purple_contact_new(account, NULL);
+		purple_contact_manager_add(manager, contact);
+
+		purple_contact_info_set_username(PURPLE_CONTACT_INFO(contact),
+		                                 bonjour_buddy->name);
+
+		tags = purple_contact_info_get_tags(PURPLE_CONTACT_INFO(contact));
+		purple_tags_add_with_value(tags, "group", BONJOUR_GROUP_NAME);
 	}
 
-	/* Make sure the buddy exists in our buddy list */
-	if (buddy == NULL)
-		buddy = purple_blist_find_buddy(account, bonjour_buddy->name);
-
-	if (buddy == NULL) {
-		buddy = purple_buddy_new(account, bonjour_buddy->name, NULL);
-		purple_blist_node_set_transient(PURPLE_BLIST_NODE(buddy), TRUE);
-		purple_blist_add_buddy(buddy, NULL, group, NULL);
+	/* Make sure we have a person for this contact as we want them to appear in
+	 * the contact list.
+	 */
+	person = purple_contact_info_get_person(PURPLE_CONTACT_INFO(contact));
+	if(!PURPLE_IS_PERSON(person)) {
+		person = g_object_new(PURPLE_TYPE_PERSON, "id", bonjour_buddy->name,
+		                      NULL);
+		purple_contact_info_set_person(PURPLE_CONTACT_INFO(contact), person);
+		purple_person_add_contact_info(person, PURPLE_CONTACT_INFO(contact));
 	}
 
-	name = purple_buddy_get_name(buddy);
-	purple_buddy_set_protocol_data(buddy, bonjour_buddy);
-
-	/* Create the alias for the buddy using the first and the last name */
-	if (bonjour_buddy->nick && *bonjour_buddy->nick)
-		purple_serv_got_alias(purple_account_get_connection(account), name, bonjour_buddy->nick);
-	else {
+	/* Set the alias. */
+	if(!purple_strempty(bonjour_buddy->nick)) {
+		purple_contact_info_set_alias(PURPLE_CONTACT_INFO(contact),
+		                              bonjour_buddy->nick);
+	} else {
+		GStrvBuilder *builder = NULL;
+		GStrv parts = NULL;
 		gchar *alias = NULL;
-		const char *first, *last;
-		first = bonjour_buddy->first;
-		last = bonjour_buddy->last;
-		if ((first && *first) || (last && *last))
-			alias = g_strdup_printf("%s%s%s",
-						(first && *first ? first : ""),
-						(first && *first && last && *last ? " " : ""),
-						(last && *last ? last : ""));
-		purple_serv_got_alias(purple_account_get_connection(account), name, alias);
+
+		builder = g_strv_builder_new();
+
+		if(!purple_strempty(bonjour_buddy->first)) {
+			g_strv_builder_add(builder, bonjour_buddy->first);
+		}
+
+		if(!purple_strempty(bonjour_buddy->last)) {
+			g_strv_builder_add(builder, bonjour_buddy->last);
+		}
+
+		parts = g_strv_builder_end(builder);
+
+		alias = g_strjoinv(" ", parts);
+		g_strfreev(parts);
+
+		if(!purple_strempty(alias)) {
+			purple_contact_info_set_alias(PURPLE_CONTACT_INFO(contact), alias);
+		} else {
+			purple_contact_info_set_alias(PURPLE_CONTACT_INFO(contact), NULL);
+		}
 		g_free(alias);
 	}
 
+	g_object_set_data(G_OBJECT(contact), "bonjour-buddy", bonjour_buddy);
+
 	/* Set the user's status */
-	if (bonjour_buddy->msg != NULL)
-		purple_protocol_got_user_status(account, name, status_id,
-					    "message", bonjour_buddy->msg, NULL);
-	else
-		purple_protocol_got_user_status(account, name, status_id, NULL);
-
-	purple_protocol_got_user_idle(account, name, FALSE, 0);
+	presence = purple_contact_info_get_presence(PURPLE_CONTACT_INFO(contact));
+	purple_presence_set_primitive(presence, primitive);
+	purple_presence_set_message(presence, bonjour_buddy->msg);
+	purple_presence_set_idle(presence, FALSE, NULL);
 
 	/* TODO: Because we don't save Bonjour buddies in blist.xml,
 	 * we will always have to look up the buddy icon at login time.
 	 * I think we should figure out a way to do something about this. */
 
+#if 0
 	/* Deal with the buddy icon */
 	old_hash = purple_buddy_icons_get_checksum_for_user(buddy);
 	new_hash = (bonjour_buddy->phsh && *(bonjour_buddy->phsh)) ? bonjour_buddy->phsh : NULL;
@@ -196,22 +225,25 @@
 		bonjour_dns_sd_retrieve_buddy_icon(bonjour_buddy);
 	} else if (!new_hash)
 		purple_buddy_icons_set_for_user(account, name, NULL, 0, NULL);
+#endif
 }
 
 /**
  * The buddy has signed off Bonjour.
  * If the buddy is being saved, mark as offline, otherwise delete
  */
-void bonjour_buddy_signed_off(PurpleBuddy *pb) {
-	if (purple_blist_node_is_transient(PURPLE_BLIST_NODE(pb))) {
-		purple_account_remove_buddy(purple_buddy_get_account(pb), pb, NULL);
-		purple_blist_remove_buddy(pb);
-	} else {
-		purple_protocol_got_user_status(purple_buddy_get_account(pb),
-					    purple_buddy_get_name(pb), "offline", NULL);
-		bonjour_buddy_delete(purple_buddy_get_protocol_data(pb));
-		purple_buddy_set_protocol_data(pb, NULL);
+void bonjour_buddy_signed_off(PurpleContact *contact) {
+	BonjourBuddy *bb = NULL;
+	PurplePresence *presence = NULL;
+
+	presence = purple_contact_info_get_presence(PURPLE_CONTACT_INFO(contact));
+	purple_presence_set_primitive(presence, PURPLE_PRESENCE_PRIMITIVE_OFFLINE);
+
+	bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
+	if(bb != NULL) {
+		bonjour_buddy_delete(bb);
 	}
+	g_object_set_data(G_OBJECT(contact), "bonjour-buddy", NULL);
 }
 
 /**
diff --git a/libpurple/protocols/bonjour/mdns_avahi.c b/libpurple/protocols/bonjour/mdns_avahi.c
--- a/libpurple/protocols/bonjour/mdns_avahi.c
+++ b/libpurple/protocols/bonjour/mdns_avahi.c
@@ -109,9 +109,10 @@
                    uint16_t port, AvahiStringList *txt,
                    G_GNUC_UNUSED AvahiLookupResultFlags flags, void *userdata)
 {
-	PurpleBuddy *pb;
-	BonjourBuddy *bb;
+	BonjourBuddy *bb = NULL;
 	PurpleAccount *account = userdata;
+	PurpleContactManager *manager = NULL;
+	PurpleContact *contact = NULL;
 	AvahiStringList *l;
 	size_t size;
 	char *key, *value;
@@ -122,8 +123,12 @@
 
 	g_return_if_fail(r != NULL);
 
-	pb = purple_blist_find_buddy(account, name);
-	bb = (pb != NULL) ? purple_buddy_get_protocol_data(pb) : NULL;
+	manager = purple_contact_manager_get_default();
+	contact = purple_contact_manager_find_with_username(manager, account,
+	                                                    name);
+	if(PURPLE_IS_CONTACT(contact)) {
+		bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
+	}
 
 	switch (event) {
 		case AVAHI_RESOLVER_FAILURE:
@@ -143,8 +148,9 @@
 					_cleanup_resolver_data(rd);
 
 					/* If this was the last resolver, remove the buddy */
-					if (b_impl->resolvers == NULL)
-						bonjour_buddy_signed_off(pb);
+					if (b_impl->resolvers == NULL) {
+						bonjour_buddy_signed_off(contact);
+					}
 				}
 			}
 			break;
@@ -219,14 +225,16 @@
 				_cleanup_resolver_data(rd);
 				/* If this was the last resolver, remove the buddy */
 				if (b_impl->resolvers == NULL) {
-					if (pb != NULL)
-						bonjour_buddy_signed_off(pb);
-					else
+					if (PURPLE_IS_CONTACT(contact)) {
+						bonjour_buddy_signed_off(contact);
+					} else {
 						bonjour_buddy_delete(bb);
+					}
 				}
-			} else
+			} else {
 				/* Add or update the buddy in our buddy list */
-				bonjour_buddy_add_to_purple(bb, pb);
+				bonjour_buddy_add_to_purple(bb);
+			}
 
 			break;
 		default:
@@ -242,7 +250,6 @@
                   G_GNUC_UNUSED AvahiLookupResultFlags flags, void *userdata)
 {
 	PurpleAccount *account = userdata;
-	PurpleBuddy *pb = NULL;
 
 	switch (event) {
 		case AVAHI_BROWSER_FAILURE:
@@ -263,15 +270,22 @@
 				}
 			}
 			break;
-		case AVAHI_BROWSER_REMOVE:
+		case AVAHI_BROWSER_REMOVE: {
+			PurpleContact *contact = NULL;
+			PurpleContactManager *manager = NULL;
+
 			purple_debug_info("bonjour", "_browser_callback - Remove service\n");
-			pb = purple_blist_find_buddy(account, name);
-			if (pb != NULL) {
-				BonjourBuddy *bb = purple_buddy_get_protocol_data(pb);
+
+			manager = purple_contact_manager_get_default();
+			contact = purple_contact_manager_find_with_username(manager,
+			                                                    account, name);
+			if (PURPLE_IS_CONTACT(contact)) {
+				BonjourBuddy *bb = NULL;
 				AvahiBuddyImplData *b_impl;
 				GSList *l;
 				AvahiSvcResolverData *rd_search;
 
+				bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
 				g_return_if_fail(bb != NULL);
 
 				b_impl = bb->mdns_impl_data;
@@ -301,11 +315,13 @@
 					_cleanup_resolver_data(rd);
 
 					/* If this was the last resolver, remove the buddy */
-					if (b_impl->resolvers == NULL)
-						bonjour_buddy_signed_off(pb);
+					if (b_impl->resolvers == NULL) {
+						bonjour_buddy_signed_off(contact);
+					}
 				}
 			}
 			break;
+		}
 		case AVAHI_BROWSER_ALL_FOR_NOW:
 		case AVAHI_BROWSER_CACHE_EXHAUSTED:
 			break;
diff --git a/libpurple/protocols/bonjour/mdns_dns_sd.c b/libpurple/protocols/bonjour/mdns_dns_sd.c
--- a/libpurple/protocols/bonjour/mdns_dns_sd.c
+++ b/libpurple/protocols/bonjour/mdns_dns_sd.c
@@ -151,7 +151,7 @@
 			/* New Buddy */
 			BonjourBuddy *bb = (BonjourBuddy*) context;
 			_mdns_parse_text_record(bb, rdata, rdlen);
-			bonjour_buddy_add_to_purple(bb, NULL);
+			bonjour_buddy_add_to_purple(bb);
 		} else if (rrtype == kDNSServiceType_NULL) {
 			/* Buddy Icon response */
 			BonjourBuddy *bb = (BonjourBuddy*) context;
@@ -181,16 +181,21 @@
 {
 	ResolveCallbackArgs *args = (ResolveCallbackArgs*) context;
 	Win32BuddyImplData *idata = args->bb->mdns_impl_data;
+	PurpleContact *contact = NULL;
+	PurpleContactManager *manager = NULL;
 	gboolean delete_buddy = FALSE;
-	PurpleBuddy *pb = NULL;
 
 	g_source_remove(args->resolver_query->input_handler);
 	DNSServiceRefDeallocate(args->resolver_query->sdRef);
 	g_free(args->resolver_query);
 	args->resolver_query = NULL;
 
-	if ((pb = purple_blist_find_buddy(args->account, args->res_data->name))) {
-		if (purple_buddy_get_protocol_data(pb) != args->bb) {
+	manager = purple_contact_manager_get_default();
+	contact = purple_contact_manager_find_with_username(manager, args->account,
+	                                                    args->res_data->name);
+
+	if (PURPLE_IS_CONTACT(contact)) {
+		if (g_object_get_data(G_OBJECT(contact), "bonjour-buddy") != args->bb) {
 			purple_debug_error("bonjour", "Found purple buddy for %s not matching bonjour buddy record.",
 				args->res_data->name);
 			goto cleanup;
@@ -236,7 +241,7 @@
 			args->res_data->txt_query->input_handler = purple_input_add(DNSServiceRefSockFD(txt_query_sr),
 				PURPLE_INPUT_READ, _mdns_handle_event, args->res_data->txt_query);
 
-			bonjour_buddy_add_to_purple(args->bb, NULL);
+			bonjour_buddy_add_to_purple(args->bb);
 		} else {
 			purple_debug_error("bonjour", "Unable to set up record watcher for buddy %s (%d)\n", args->bb->name, errorCode);
 			delete_buddy = TRUE;
@@ -251,10 +256,11 @@
 
 		/* If this was the last resolver, remove the buddy */
 		if (idata->resolvers == NULL) {
-			if (pb)
-				bonjour_buddy_signed_off(pb);
-			else
+			if (PURPLE_IS_CONTACT(contact)) {
+				bonjour_buddy_signed_off(contact);
+			} else {
 				bonjour_buddy_delete(args->bb);
+			}
 
 			/* Remove from the pending list */
 			pending_buddies = g_slist_remove(pending_buddies, args->bb);
@@ -319,11 +325,18 @@
 
 	/* If this was the last resolver, remove the buddy */
 	if (idata->resolvers == NULL) {
-		PurpleBuddy *pb;
+		PurpleContact *contact = NULL;
+		PurpleContactManager *manager = NULL;
+
+		manager = purple_contact_manager_get_default();
+		contact = purple_contact_manager_find_with_username(manager,
+		                                                    args->account,
+		                                                    args->bb->name);
+
 		/* See if this is now attached to a PurpleBuddy */
-		if ((pb = purple_blist_find_buddy(args->account, args->bb->name)))
-			bonjour_buddy_signed_off(pb);
-		else {
+		if(PURPLE_IS_CONTACT(contact)) {
+			bonjour_buddy_signed_off(contact);
+		} else {
 			/* Remove from the pending list */
 			pending_buddies = g_slist_remove(pending_buddies, args->bb);
 			bonjour_buddy_delete(args->bb);
@@ -432,19 +445,23 @@
 			}
 		}
 	} else {
-		PurpleBuddy *pb = NULL;
+		PurpleContact *contact = NULL;
+		PurpleContactManager *manager = NULL;
+
+		manager = purple_contact_manager_get_default();
+		contact = purple_contact_manager_find_with_username(manager, account,
+		                                                    serviceName);
 
 		/* A peer has sent a goodbye packet, remove them from the buddy list */
 		purple_debug_info("bonjour", "Received remove notification for '%s' on iface %u (%s, %s)\n",
 						  serviceName, interfaceIndex, regtype ? regtype : "",
 						  replyDomain ? replyDomain : "");
 
-		pb = purple_blist_find_buddy(account, serviceName);
-		if (pb != NULL) {
+		if(PURPLE_IS_CONTACT(contact)) {
 			GSList *l;
 			/* There may be multiple presences, we should only get rid of this one */
 			Win32SvcResolverData *rd_search;
-			BonjourBuddy *bb = purple_buddy_get_protocol_data(pb);
+			BonjourBuddy *bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
 			Win32BuddyImplData *idata;
 
 			g_return_if_fail(bb != NULL);
@@ -475,11 +492,11 @@
 				if (idata->resolvers == NULL) {
 					purple_debug_info("bonjour", "Removed last presence for buddy '%s'; signing off buddy.\n",
 							  serviceName);
-					bonjour_buddy_signed_off(pb);
+					bonjour_buddy_signed_off(contact);
 				}
 			}
 		} else {
-			purple_debug_warning("bonjour", "Unable to find buddy (%s) to remove\n", serviceName ? serviceName : "(null)");
+			purple_debug_warning("bonjour", "Unable to find contact (%s) to remove\n", serviceName ? serviceName : "(null)");
 			/* TODO: Should we look in the pending buddies list? */
 		}
 	}
diff --git a/libpurple/protocols/bonjour/parser.c b/libpurple/protocols/bonjour/parser.c
--- a/libpurple/protocols/bonjour/parser.c
+++ b/libpurple/protocols/bonjour/parser.c
@@ -38,7 +38,7 @@
 			bconv->buddy_name = g_strndup((char *)attributes[i+3], len);
 			bonjour_xmpp_conv_match_by_name(bconv);
 
-			return (bconv->pb != NULL);
+			return (PURPLE_IS_CONTACT(bconv->contact));
 		}
 	}
 
@@ -67,8 +67,9 @@
 		if(!bconv->recv_stream_start) {
 			bconv->recv_stream_start = TRUE;
 
-			if (bconv->pb == NULL)
+			if(!PURPLE_IS_CONTACT(bconv->contact)) {
 				parse_from_attrib_and_find_buddy(bconv, nb_attributes, attributes);
+			}
 
 			bonjour_xmpp_stream_started(bconv);
 		}
@@ -76,14 +77,16 @@
 
 		/* 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
+		if(!PURPLE_IS_CONTACT(bconv->contact)
 				&& !(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_xmpp_conv_match_by_ip(bconv);
+		}
 
 		if(bconv->current)
 			node = purple_xmlnode_new_child(bconv->current, (const char*) element_name);
@@ -136,7 +139,7 @@
 	} else {
 		PurpleXmlNode *packet = bconv->current;
 		bconv->current = NULL;
-		bonjour_xmpp_process_packet(bconv->pb, packet);
+		bonjour_xmpp_process_packet(bconv->contact, packet);
 		purple_xmlnode_free(packet);
 	}
 }
diff --git a/libpurple/protocols/bonjour/xmpp.h b/libpurple/protocols/bonjour/xmpp.h
--- a/libpurple/protocols/bonjour/xmpp.h
+++ b/libpurple/protocols/bonjour/xmpp.h
@@ -53,7 +53,7 @@
 	gpointer stream_data;
 	xmlParserCtxt *context;
 	PurpleXmlNode *current;
-	PurpleBuddy *pb;
+	PurpleContact *contact;
 	PurpleAccount *account;
 
 	/* The following are only needed before attaching to a PurpleBuddy */
@@ -79,7 +79,7 @@
 
 void bonjour_xmpp_stream_started(BonjourXMPPConversation *bconv);
 
-void bonjour_xmpp_process_packet(PurpleBuddy *pb, PurpleXmlNode *packet);
+void bonjour_xmpp_process_packet(PurpleContact *contact, PurpleXmlNode *packet);
 
 void bonjour_xmpp_stop(BonjourXMPP *data);
 
diff --git a/libpurple/protocols/bonjour/xmpp.c b/libpurple/protocols/bonjour/xmpp.c
--- a/libpurple/protocols/bonjour/xmpp.c
+++ b/libpurple/protocols/bonjour/xmpp.c
@@ -49,17 +49,19 @@
 };
 
 static void
-xep_iq_parse(PurpleXmlNode *packet, PurpleBuddy *pb);
+xep_iq_parse(PurpleXmlNode *packet, PurpleContact *contact);
 
 static BonjourXMPPConversation *
-bonjour_xmpp_conv_new(PurpleBuddy *pb, PurpleAccount *account, const char *ip) {
+bonjour_xmpp_conv_new(PurpleContact *contact, PurpleAccount *account,
+                      const char *ip)
+{
 
 	BonjourXMPPConversation *bconv = g_new0(BonjourXMPPConversation, 1);
 	bconv->cancellable = g_cancellable_new();
 	bconv->tx_buf = purple_circular_buffer_new(512);
 	bconv->tx_handler = 0;
 	bconv->rx_handler = 0;
-	bconv->pb = pb;
+	bconv->contact = contact;
 	bconv->account = account;
 	bconv->ip = g_strdup(ip);
 
@@ -111,11 +113,17 @@
 }
 
 static void
-_xmpp_parse_and_write_message_to_ui(PurpleXmlNode *message_node, PurpleBuddy *pb)
+_xmpp_parse_and_write_message_to_ui(PurpleXmlNode *message_node,
+                                    PurpleContact *contact)
 {
 	PurpleXmlNode *body_node, *html_node, *events_node;
-	PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(pb));
+	PurpleAccount *account = NULL;
+	PurpleConnection *gc = NULL;
 	gchar *body = NULL;
+	const char *username = NULL;
+
+	account = purple_contact_get_account(contact);
+	gc = purple_account_get_connection(account);
 
 	body_node = purple_xmlnode_get_child(message_node, "body");
 	html_node = purple_xmlnode_get_child(message_node, "html");
@@ -196,61 +204,53 @@
 	}
 
 	/* Send the message to the UI */
-	purple_serv_got_im(gc, purple_buddy_get_name(pb), body, 0, time(NULL));
+	username = purple_contact_info_get_username(PURPLE_CONTACT_INFO(contact));
+	purple_serv_got_im(gc, username, body, 0, time(NULL));
 
 	g_free(body);
 }
 
-struct _match_buddies_by_address {
-	const char *address;
-	GSList *matched_buddies;
-};
-
-static void
-_match_buddies_by_address(gpointer value, gpointer data)
-{
-	PurpleBuddy *pb = value;
-	struct _match_buddies_by_address *mbba = data;
-	BonjourBuddy *bb = purple_buddy_get_protocol_data(pb);
-
-	if (!bb) {
-		return;
-	}
-
-	/*
-	 * If the current PurpleBuddy's data is not null, then continue to determine
-	 * whether one of the buddies IPs matches the target IP.
-	 */
-	if (g_slist_find_custom(bb->ips, mbba->address, (GCompareFunc)g_ascii_strcasecmp)) {
-		mbba->matched_buddies = g_slist_prepend(mbba->matched_buddies, pb);
-	}
-}
-
 static GSList *
 _find_match_buddies_by_address(const BonjourXMPP *jdata, const char *address)
 {
-	struct _match_buddies_by_address mbba = {
-		.address = address,
-		.matched_buddies = NULL
-	};
-	GSList *buddies = purple_blist_find_buddies(jdata->account, NULL);
+	PurpleContactManager *manager = NULL;
+	GListModel *contacts = NULL;
+	GSList *ret = NULL;
+
+	manager = purple_contact_manager_get_default();
+	contacts = purple_contact_manager_get_all(manager, jdata->account);
+	for(guint i = 0; i < g_list_model_get_n_items(contacts); i++) {
+		PurpleContact *contact = NULL;
+		BonjourBuddy *bb = NULL;
 
-	g_slist_foreach(buddies, _match_buddies_by_address, &mbba);
-	g_slist_free(buddies);
+		contact = g_list_model_get_item(contacts, i);
+		bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
+		if(bb != NULL) {
+			if(g_slist_find_custom(bb->ips, address,
+			                       (GCompareFunc)g_ascii_strcasecmp))
+			{
+				ret = g_slist_prepend(ret, contact);
+			}
+		}
 
-	return mbba.matched_buddies;
+		g_clear_object(&contact);
+	}
+
+	return ret;
 }
 
 static void
 _send_data_write_cb(GObject *stream, gpointer data)
 {
-	PurpleBuddy *pb = data;
-	BonjourBuddy *bb = purple_buddy_get_protocol_data(pb);
-	BonjourXMPPConversation *bconv = bb->conversation;
+	PurpleContact *contact = data;
+	BonjourBuddy *bb = NULL;
+	BonjourXMPPConversation *bconv = NULL;
 	gsize writelen;
 	gssize ret;
 	GError *error = NULL;
 
+	bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
+	bconv = bb->conversation;
 	writelen = purple_circular_buffer_get_max_read(bconv->tx_buf);
 
 	if (writelen == 0) {
@@ -276,10 +276,10 @@
 		purple_debug_error(
 		        "bonjour",
 		        "Error sending message to buddy %s error: %s",
-		        purple_buddy_get_name(pb),
+		        purple_contact_info_get_username(PURPLE_CONTACT_INFO(contact)),
 		        error ? error->message : "(null)");
 
-		account = purple_buddy_get_account(pb);
+		account = purple_contact_get_account(contact);
 
 		conv = purple_conversation_manager_find_im(manager, account, bb->name);
 		if (conv != NULL) {
@@ -298,9 +298,9 @@
 }
 
 static gint
-_send_data(PurpleBuddy *pb, char *message)
+_send_data(PurpleContact *contact, char *message)
 {
-	BonjourBuddy *bb = purple_buddy_get_protocol_data(pb);
+	BonjourBuddy *bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
 	BonjourXMPPConversation *bconv = bb->conversation;
 	gsize len = strlen(message);
 	gssize ret;
@@ -333,10 +333,10 @@
 		purple_debug_error(
 		        "bonjour",
 		        "Error sending message to buddy %s error: %s",
-		        purple_buddy_get_name(pb),
+		        purple_contact_info_get_username(PURPLE_CONTACT_INFO(contact)),
 		        error ? error->message : "(null)");
 
-		account = purple_buddy_get_account(pb);
+		account = purple_contact_get_account(contact);
 
 		conv = purple_conversation_manager_find_im(manager, account, bb->name);
 		if (conv != NULL) {
@@ -361,7 +361,7 @@
 			                bconv->cancellable);
 			g_source_set_callback(source,
 			                      G_SOURCE_FUNC(_send_data_write_cb),
-			                      pb, NULL);
+			                      contact, NULL);
 			bconv->tx_handler = g_source_attach(source, NULL);
 			g_source_unref(source);
 		}
@@ -371,36 +371,41 @@
 	return ret;
 }
 
-void bonjour_xmpp_process_packet(PurpleBuddy *pb, PurpleXmlNode *packet) {
-
+void
+bonjour_xmpp_process_packet(PurpleContact *contact, PurpleXmlNode *packet) {
+	g_return_if_fail(PURPLE_IS_CONTACT(contact));
 	g_return_if_fail(packet != NULL);
-	g_return_if_fail(pb != NULL);
 
-	if (purple_strequal(packet->name, "message"))
-		_xmpp_parse_and_write_message_to_ui(packet, pb);
-	else if (purple_strequal(packet->name, "iq"))
-		xep_iq_parse(packet, pb);
-	else {
+	if (purple_strequal(packet->name, "message")) {
+		_xmpp_parse_and_write_message_to_ui(packet, contact);
+	} else if (purple_strequal(packet->name, "iq")) {
+		xep_iq_parse(packet, contact);
+	} else {
 		purple_debug_warning("bonjour", "Unknown packet: %s\n",
 			packet->name ? packet->name : "(null)");
 	}
 }
 
-static void bonjour_xmpp_stream_ended(BonjourXMPPConversation *bconv) {
-
+static void
+bonjour_xmpp_stream_ended(BonjourXMPPConversation *bconv) {
 	/* Inform the user that the conversation has been closed */
 	BonjourBuddy *bb = NULL;
-	const gchar *name = bconv->pb ? purple_buddy_get_name(bconv->pb) : "(unknown)";
+	const gchar *name = "(unknown)";
+
+	if(PURPLE_IS_CONTACT(bconv->contact)) {
+		PurpleContactInfo *info = PURPLE_CONTACT_INFO(bconv->contact);
+
+		name = purple_contact_info_get_username(info);
+		bb = g_object_get_data(G_OBJECT(bconv->contact), "bonjour-buddy");
+	}
 
 	purple_debug_info("bonjour", "Received conversation close notification from %s.\n", name);
 
-	if(bconv->pb != NULL)
-		bb = purple_buddy_get_protocol_data(bconv->pb);
-
 	/* Close the socket, clear the watcher and free memory */
 	bonjour_xmpp_close_conversation(bconv);
-	if(bb)
+	if(bb != NULL) {
 		bb->conversation = NULL;
+	}
 }
 
 static gboolean
@@ -425,11 +430,14 @@
 			        len, error ? error->message : "(null)");
 
 			bonjour_xmpp_close_conversation(bconv);
-			if (bconv->pb != NULL) {
-				BonjourBuddy *bb = purple_buddy_get_protocol_data(bconv->pb);
+			if(PURPLE_IS_CONTACT(bconv->contact)) {
+				BonjourBuddy *bb = NULL;
 
-				if(bb != NULL)
+				bb = g_object_get_data(G_OBJECT(bconv->contact),
+				                       "bonjour-buddy");
+				if(bb != NULL) {
 					bb->conversation = NULL;
+				}
 			}
 
 			/* I guess we really don't need to notify the user.
@@ -438,7 +446,8 @@
 		g_clear_error(&error);
 		return FALSE;
 	} else if (len == 0) { /* The other end has closed the socket */
-		const gchar *name = purple_buddy_get_name(bconv->pb);
+		const gchar *name = NULL;
+		name = purple_contact_info_get_username(PURPLE_CONTACT_INFO(bconv->contact));
 		purple_debug_warning("bonjour", "Connection closed (without stream end) by %s.\n", (name) ? name : "(unknown)");
 		bonjour_xmpp_stream_ended(bconv);
 		return FALSE;
@@ -483,9 +492,9 @@
 
 		manager = purple_conversation_manager_get_default();
 
-		if(bconv->pb) {
-			bb = purple_buddy_get_protocol_data(bconv->pb);
-			bname = purple_buddy_get_name(bconv->pb);
+		if(PURPLE_IS_CONTACT(bconv->contact)) {
+			bb = g_object_get_data(G_OBJECT(bconv->contact), "bonjour-buddy");
+			bname = purple_contact_info_get_username(PURPLE_CONTACT_INFO(bconv->contact));
 		}
 
 		purple_debug_error(
@@ -541,8 +550,9 @@
 
 	g_return_val_if_fail(error != NULL, FALSE);
 
-	if (bconv->pb != NULL)
-		bname = purple_buddy_get_name(bconv->pb);
+	if(PURPLE_IS_CONTACT(bconv->contact)) {
+		bname = purple_contact_info_get_username(PURPLE_CONTACT_INFO(bconv->contact));
+	}
 
 	/* 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. */
@@ -568,7 +578,7 @@
 		        (*bname) ? bname : "(unknown)", bconv->ip,
 		        *error ? (*error)->message : "(null)");
 
-		if (bconv->pb) {
+		if(PURPLE_IS_CONTACT(bconv->contact)) {
 			PurpleConversation *conv;
 			PurpleConversationManager *manager;
 
@@ -628,8 +638,9 @@
 	    !bonjour_xmpp_send_stream_init(bconv, &error)) {
 		const char *bname = bconv->buddy_name;
 
-		if (bconv->pb)
-			bname = purple_buddy_get_name(bconv->pb);
+		if(PURPLE_IS_CONTACT(bconv->contact)) {
+			bname = purple_contact_info_get_username(PURPLE_CONTACT_INFO(bconv->contact));
+		}
 
 		purple_debug_error(
 		        "bonjour",
@@ -637,7 +648,7 @@
 		        bname ? bname : "(unknown)", bconv->ip,
 		        error ? error->message : "(null)");
 
-		if (bconv->pb) {
+		if(PURPLE_IS_CONTACT(bconv->contact)) {
 			PurpleConversation *conv;
 			PurpleConversationManager *manager;
 
@@ -670,18 +681,20 @@
 
 	/* 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_circular_buffer_get_max_read(bconv->tx_buf) > 0) {
+	if(bconv->sent_stream_start == FULLY_SENT && bconv->recv_stream_start &&
+	   PURPLE_IS_CONTACT(bconv->contact) &&
+	   purple_circular_buffer_get_max_read(bconv->tx_buf) > 0)
+	{
 		/* Watch for when we can write the buffered messages */
 		GSource *source = g_pollable_output_stream_create_source(
 		        G_POLLABLE_OUTPUT_STREAM(bconv->output),
 		        bconv->cancellable);
 		g_source_set_callback(source, G_SOURCE_FUNC(_send_data_write_cb),
-		                      bconv->pb, NULL);
+		                      bconv->contact, NULL);
 		bconv->tx_handler = g_source_attach(source, NULL);
 		g_source_unref(source);
 		/* We can probably write the data right now. */
-		_send_data_write_cb(G_OBJECT(bconv->output), bconv->pb);
+		_send_data_write_cb(G_OBJECT(bconv->output), bconv->contact);
 	}
 }
 
@@ -699,7 +712,7 @@
 	GInetAddress *their_inet_addr;
 	gchar *address_text;
 	BonjourXMPPConversation *bconv;
-	GSList *buddies;
+	GSList *contacts;
 	GSource *source;
 
 	their_addr = g_socket_connection_get_remote_address(connection, NULL);
@@ -725,14 +738,14 @@
 
 	purple_debug_info("bonjour", "Received incoming connection from %s.\n", address_text);
 
-	buddies = _find_match_buddies_by_address(jdata, address_text);
-	if (buddies == NULL) {
+	contacts = _find_match_buddies_by_address(jdata, address_text);
+	if (contacts == NULL) {
 		purple_debug_info("bonjour", "We don't like invisible buddies, this is not a superheroes comic\n");
 		g_free(address_text);
 		return;
 	}
 
-	g_slist_free(buddies);
+	g_slist_free(contacts);
 
 	/* 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.
@@ -795,14 +808,17 @@
 static void
 _connected_to_buddy(GObject *source, GAsyncResult *res, gpointer user_data)
 {
-	PurpleBuddy *pb = user_data;
-	BonjourBuddy *bb = purple_buddy_get_protocol_data(pb);
+	PurpleContact *contact = user_data;
+	BonjourBuddy *bb = NULL;
 	GSocketConnection *conn;
 	GSource *rx_source;
 	GError *error = NULL;
+	const char *username = NULL;
 
+	bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
 	conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source),
 	                                              res, &error);
+	username = purple_contact_info_get_username(PURPLE_CONTACT_INFO(contact));
 
 	if (conn == NULL) {
 		PurpleAccount *account = NULL;
@@ -819,7 +835,7 @@
 		purple_debug_error("bonjour",
 		                   "Error connecting to buddy %s at %s:%d "
 		                   "(%s); Trying next IP address",
-		                   purple_buddy_get_name(pb),
+		                   username,
 		                   bb->conversation->ip, bb->port_p2pj,
 		                   error ? error->message : "(unknown)");
 		g_clear_error(&error);
@@ -832,7 +848,7 @@
 		if (tmp)
 			tmp = g_slist_next(tmp);
 
-		account = purple_buddy_get_account(pb);
+		account = purple_contact_get_account(contact);
 
 		if (tmp != NULL) {
 			const gchar *ip;
@@ -841,7 +857,7 @@
 			bb->conversation->ip_link = ip = tmp->data;
 
 			purple_debug_info("bonjour", "Starting conversation with %s at %s:%d\n",
-					  purple_buddy_get_name(pb), ip, bb->port_p2pj);
+					  username, ip, bb->port_p2pj);
 
 			/* Make sure to connect without a proxy. */
 			client = g_socket_client_new();
@@ -851,13 +867,15 @@
 				g_socket_client_connect_to_host_async(
 				        client, ip, bb->port_p2pj,
 				        bb->conversation->cancellable,
-				        _connected_to_buddy, pb);
+				        _connected_to_buddy, contact);
 				g_object_unref(client);
 				return;
 			}
 		}
 
-		purple_debug_error("bonjour", "No more addresses for buddy %s. Aborting", purple_buddy_get_name(pb));
+		purple_debug_error("bonjour",
+		                   "No more addresses for buddy %s. Aborting",
+		                   username);
 
 		manager = purple_conversation_manager_get_default();
 
@@ -887,11 +905,11 @@
 		purple_debug_error("bonjour",
 		                   "Error starting stream with buddy %s at "
 		                   "%s:%d error: %s",
-		                   purple_buddy_get_name(pb),
+		                   username,
 		                   bb->conversation->ip, bb->port_p2pj,
 		                   error ? error->message : "(null)");
 
-		account = purple_buddy_get_account(pb);
+		account = purple_contact_get_account(contact);
 
 		manager = purple_conversation_manager_get_default();
 
@@ -920,16 +938,26 @@
 
 void
 bonjour_xmpp_conv_match_by_name(BonjourXMPPConversation *bconv) {
-	PurpleBuddy *pb = NULL;
 	BonjourBuddy *bb = NULL;
+	PurpleContact *contact = NULL;
+	PurpleContactManager *manager = NULL;
 
 	g_return_if_fail(bconv->ip != NULL);
-	g_return_if_fail(bconv->pb == NULL);
+	g_return_if_fail(!PURPLE_IS_CONTACT(bconv->contact));
+
+	manager = purple_contact_manager_get_default();
+	contact = purple_contact_manager_find_with_username(manager,
+	                                                    bconv->account,
+	                                                    bconv->buddy_name);
 
-	pb = purple_blist_find_buddy(bconv->account, bconv->buddy_name);
-	if (pb && (bb = purple_buddy_get_protocol_data(pb))) {
-		purple_debug_info("bonjour", "Found buddy %s for incoming conversation \"from\" attrib.\n",
-			purple_buddy_get_name(pb));
+	if(contact && (bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy"))) {
+		const char *username = NULL;
+
+		username = purple_contact_info_get_username(PURPLE_CONTACT_INFO(contact));
+
+		purple_debug_info("bonjour",
+		                  "Found buddy %s for incoming conversation \"from\" attrib.\n",
+		                  username);
 
 		/* Check that one of the buddy's IPs matches */
 		if (g_slist_find_custom(bb->ips, bconv->ip, (GCompareFunc)g_ascii_strcasecmp)) {
@@ -938,7 +966,7 @@
 			BonjourXMPP *jdata = bd->xmpp_data;
 
 			purple_debug_info("bonjour", "Matched buddy %s to incoming conversation \"from\" attrib and IP (%s)",
-			                  purple_buddy_get_name(pb), bconv->ip);
+			                  username, bconv->ip);
 
 			/* Attach conv. to buddy and remove from pending list */
 			jdata->pending_conversations = g_slist_remove(jdata->pending_conversations, bconv);
@@ -948,13 +976,13 @@
 				bonjour_xmpp_close_conversation(bb->conversation);
 			}
 
-			bconv->pb = pb;
+			bconv->contact = contact;
 			bb->conversation = bconv;
 		}
 	}
 
 	/* We've failed to match a buddy - give up */
-	if (bconv->pb == NULL) {
+	if(!PURPLE_IS_CONTACT(bconv->contact)) {
 		/* This must be asynchronous because it destroys the parser and we
 		 * may be in the middle of parsing.
 		 */
@@ -968,21 +996,22 @@
 	PurpleConnection *pc = purple_account_get_connection(bconv->account);
 	BonjourData *bd = purple_connection_get_protocol_data(pc);
 	BonjourXMPP *jdata = bd->xmpp_data;
-	GSList *buddies;
+	GSList *contacts;
 
-	buddies = _find_match_buddies_by_address(jdata, bconv->ip);
+	contacts = _find_match_buddies_by_address(jdata, bconv->ip);
 
 	/* If there is exactly one match, use it */
-	if (!buddies) {
+	if (!contacts) {
 		purple_debug_error("bonjour", "No buddies matched for ip %s.", bconv->ip);
-	} else if (buddies->next != NULL) {
+	} else if (contacts->next != NULL) {
 		purple_debug_error("bonjour", "More than one buddy matched for ip %s.", bconv->ip);
 	} else {
-		PurpleBuddy *pb = buddies->data;
-		BonjourBuddy *bb = purple_buddy_get_protocol_data(pb);
+		PurpleContact *contact = contacts->data;
+		BonjourBuddy *bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
 
 		purple_debug_info("bonjour", "Matched buddy %s to incoming conversation using IP (%s)",
-		                  purple_buddy_get_name(pb), bconv->ip);
+		                  purple_contact_info_get_username(PURPLE_CONTACT_INFO(contact)),
+		                  bconv->ip);
 
 		/* Attach conv. to buddy and remove from pending list */
 		jdata->pending_conversations = g_slist_remove(jdata->pending_conversations, bconv);
@@ -992,34 +1021,43 @@
 			bonjour_xmpp_close_conversation(bb->conversation);
 		}
 
-		bconv->pb = pb;
+		bconv->contact = contact;
 		bb->conversation = bconv;
 	}
 
 	/* We've failed to match a buddy - give up */
-	if (bconv->pb == NULL) {
+	if(!PURPLE_IS_CONTACT(bconv->contact)) {
 		/* This must be asynchronous because it destroys the parser and we
 		 * may be in the middle of parsing.
 		 */
 		async_bonjour_xmpp_close_conversation(bconv);
 	}
 
-	g_slist_free(buddies);
+	g_slist_free(contacts);
 }
 
-static PurpleBuddy *
+static PurpleContact *
 _find_or_start_conversation(BonjourXMPP *jdata, const gchar *to)
 {
-	PurpleBuddy *pb = NULL;
+	PurpleContact *contact = NULL;
+	PurpleContactManager *manager = NULL;
 	BonjourBuddy *bb = NULL;
 
 	g_return_val_if_fail(jdata != NULL, NULL);
 	g_return_val_if_fail(to != NULL, NULL);
 
-	pb = purple_blist_find_buddy(jdata->account, to);
-	if (pb == NULL || (bb = purple_buddy_get_protocol_data(pb)) == NULL)
-		/* You can not send a message to an offline buddy */
+	manager = purple_contact_manager_get_default();
+	contact = purple_contact_manager_find_with_username(manager,
+	                                                    jdata->account, to);
+
+	if(!PURPLE_IS_CONTACT(contact)) {
 		return NULL;
+	}
+
+	bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy");
+	if(bb == NULL) {
+		return NULL;
+	}
 
 	/* Check if there is a previously open conversation */
 	if (bb->conversation == NULL) {
@@ -1040,15 +1078,15 @@
 			return NULL;
 		}
 
-		bb->conversation = bonjour_xmpp_conv_new(pb, jdata->account, ip);
+		bb->conversation = bonjour_xmpp_conv_new(contact, jdata->account, ip);
 		bb->conversation->ip_link = ip;
 
 		g_socket_client_connect_to_host_async(
 		        client, ip, bb->port_p2pj,
-		        bb->conversation->cancellable, _connected_to_buddy, pb);
+		        bb->conversation->cancellable, _connected_to_buddy, contact);
 		g_object_unref(client);
 	}
-	return pb;
+	return contact;
 }
 
 int
@@ -1056,12 +1094,14 @@
 {
 	PurpleXmlNode *message_node, *node, *node2;
 	gchar *message, *xhtml;
-	PurpleBuddy *pb;
+	PurpleContact *contact = NULL;
 	BonjourBuddy *bb;
 	int ret;
 
-	pb = _find_or_start_conversation(jdata, to);
-	if (pb == NULL || (bb = purple_buddy_get_protocol_data(pb)) == NULL) {
+	contact = _find_or_start_conversation(jdata, to);
+	if(!PURPLE_IS_CONTACT(contact) ||
+	   (bb = g_object_get_data(G_OBJECT(contact), "bonjour-buddy")) == 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 */
 		return -10000;
@@ -1096,7 +1136,7 @@
 	message = purple_xmlnode_to_str(message_node, NULL);
 	purple_xmlnode_free(message_node);
 
-	ret = _send_data(pb, message) >= 0;
+	ret = _send_data(contact, message) >= 0;
 
 	g_free(message);
 
@@ -1119,8 +1159,8 @@
 	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 = purple_buddy_get_protocol_data(bconv->pb);
+	if(PURPLE_IS_CONTACT(bconv->contact)) {
+		BonjourBuddy *bb = g_object_get_data(G_OBJECT(bconv->contact), "bonjour-buddy");
 		if (bb->conversation == bconv)
 			bb->conversation = NULL;
 	}
@@ -1149,17 +1189,23 @@
 
 	/* Cancel any file transfers that are waiting to begin */
 	/* There won't be any transfers if it hasn't been attached to a buddy */
-	if (bconv->pb != NULL && bd != NULL) {
+	if (PURPLE_IS_CONTACT(bconv->contact) && bd != NULL) {
 		GSList *xfers, *tmp_next;
 		xfers = bd->xfer_lists;
 		while (xfers != NULL) {
 			PurpleXfer *xfer = xfers->data;
+			const char *username = NULL;
+
 			tmp_next = xfers->next;
+
+			username = purple_contact_info_get_username(PURPLE_CONTACT_INFO(bconv->contact));
+
 			/* We only need to cancel this if it hasn't actually started transferring. */
 			/* This will change if we ever support IBB transfers. */
-			if (purple_strequal(purple_xfer_get_remote_user(xfer), purple_buddy_get_name(bconv->pb))
+			if (purple_strequal(purple_xfer_get_remote_user(xfer), username)
 					&& (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_NOT_STARTED
-						|| purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_UNKNOWN)) {
+						|| purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_UNKNOWN))
+			{
 				purple_xfer_cancel_remote(xfer);
 			}
 			xfers = tmp_next;
@@ -1229,20 +1275,26 @@
 
 	/* Close all the conversation sockets and remove all the watchers after sending end streams */
 	if (!purple_account_is_disconnected(jdata->account)) {
-		GSList *buddies, *l;
+		PurpleContactManager *manager = NULL;
+		GListModel *model = NULL;
+
+		manager = purple_contact_manager_get_default();
+		model = purple_contact_manager_get_all(manager, jdata->account);
 
-		buddies = purple_blist_find_buddies(jdata->account, NULL);
-		for (l = buddies; l; l = l->next) {
-			BonjourBuddy *bb = purple_buddy_get_protocol_data((PurpleBuddy*) l->data);
-			if (bb && bb->conversation) {
+		for(guint i = 0; g_list_model_get_n_items(model); i++) {
+			PurpleContact *contact = g_list_model_get_item(model, i);
+			BonjourBuddy *bb = g_object_get_data(G_OBJECT(contact),
+			                                     "bonjour-buddy");
+
+			if(bb != NULL && bb->conversation != NULL) {
 				/* Any ongoing connection attempt is cancelled
 				 * when a connection is destroyed */
 				bonjour_xmpp_close_conversation(bb->conversation);
 				bb->conversation = NULL;
 			}
+
+			g_clear_object(&contact);
 		}
-
-		g_slist_free(buddies);
 	}
 
 	g_slist_free_full(jdata->pending_conversations, (GDestroyNotify)bonjour_xmpp_close_conversation);
@@ -1292,33 +1344,35 @@
 }
 
 static void
-xep_iq_parse(PurpleXmlNode *packet, PurpleBuddy *pb)
-{
+xep_iq_parse(PurpleXmlNode *packet, PurpleContact *contact) {
 	PurpleAccount *account;
 	PurpleConnection *gc;
 
-	account = purple_buddy_get_account(pb);
+	account = purple_contact_get_account(contact);
 	gc = purple_account_get_connection(account);
 
-	if (purple_xmlnode_get_child(packet, "si") != NULL || purple_xmlnode_get_child(packet, "error") != NULL)
-		xep_si_parse(gc, packet, pb);
-	else
-		xep_bytestreams_parse(gc, packet, pb);
+	if(purple_xmlnode_get_child(packet, "si") != NULL ||
+	   purple_xmlnode_get_child(packet, "error") != NULL)
+	{
+		xep_si_parse(gc, packet, contact);
+	} else {
+		xep_bytestreams_parse(gc, packet, contact);
+	}
 }
 
 int
 xep_iq_send_and_free(XepIq *iq)
 {
 	int ret = -1;
-	PurpleBuddy *pb = NULL;
+	PurpleContact *contact = NULL;
 
 	/* start the talk, reuse the message socket  */
-	pb = _find_or_start_conversation((BonjourXMPP*) iq->data, iq->to);
+	contact = _find_or_start_conversation((BonjourXMPP*) iq->data, iq->to);
 	/* Send the message */
-	if (pb != NULL) {
+	if(PURPLE_IS_CONTACT(contact)) {
 		/* Convert xml node into stream */
 		gchar *msg = purple_xmlnode_to_str(iq->node, NULL);
-		ret = _send_data(pb, msg);
+		ret = _send_data(contact, msg);
 		g_free(msg);
 	}
 
