# HG changeset patch
# Node ID fc6b7bb79196
# Parent  c4a96b5eecba
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -46,6 +46,7 @@
 	'purplechatuser.c',
 	'purpleconnectionerrorinfo.c',
 	'purplecontact.c',
+	'purplecontactinfo.c',
 	'purplecontactmanager.c',
 	'purpleconversation.c',
 	'purpleconversationmanager.c',
@@ -150,6 +151,7 @@
 	'purplechatuser.h',
 	'purpleconnectionerrorinfo.h',
 	'purplecontact.h',
+	'purplecontactinfo.h',
 	'purplecontactmanager.h',
 	'purpleconversation.h',
 	'purpleconversationmanager.h',
@@ -260,7 +262,7 @@
 	'plugins.h',
 	'purplechatuser.h',
 	'purpleconnectionerrorinfo.h',
-	'purplecontact.h',
+	'purplecontactinfo.h',
 	'purpleconversation.h',
 	'purpleimconversation.h',
 	'purplemessage.h',
diff --git a/libpurple/protocols/ircv3/purpleircv3messagehandlers.c b/libpurple/protocols/ircv3/purpleircv3messagehandlers.c
--- a/libpurple/protocols/ircv3/purpleircv3messagehandlers.c
+++ b/libpurple/protocols/ircv3/purpleircv3messagehandlers.c
@@ -168,7 +168,7 @@
 	                                                    source);
 	if(!PURPLE_IS_CONTACT(contact)) {
 		contact = purple_contact_new(account, NULL);
-		purple_contact_set_username(contact, source);
+		purple_contact_info_set_username(PURPLE_CONTACT_INFO(contact), source);
 		purple_contact_manager_add(contact_manager, contact);
 	}
 
diff --git a/libpurple/purplecontact.h b/libpurple/purplecontact.h
--- a/libpurple/purplecontact.h
+++ b/libpurple/purplecontact.h
@@ -28,62 +28,22 @@
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
-#include <libpurple/purplepresence.h>
-#include <libpurple/purpletags.h>
+#include <libpurple/purplecontactinfo.h>
 
 G_BEGIN_DECLS
 
 #define PURPLE_TYPE_CONTACT (purple_contact_get_type())
-G_DECLARE_DERIVABLE_TYPE(PurpleContact, purple_contact, PURPLE, CONTACT,
-                         GObject)
-
-/**
- * PurpleContactPermission:
- * @PURPLE_CONTACT_PERMISSION_UNSET: The value is unset.
- * @PURPLE_CONTACT_PERMISSION_ALLOW: The contact is allowed to contact the
- *                                   user.
- * @PURPLE_CONTACT_PERMISSION_DENY: The contact is not allowed to contact the
- *                                  user.
- *
- * A representation of whether or not a contact has permission to contact the
- * user.
- *
- * Since: 3.0.0
- */
-typedef enum {
-	PURPLE_CONTACT_PERMISSION_UNSET = 0,
-	PURPLE_CONTACT_PERMISSION_ALLOW,
-	PURPLE_CONTACT_PERMISSION_DENY,
-} PurpleContactPermission;
+G_DECLARE_FINAL_TYPE(PurpleContact, purple_contact, PURPLE, CONTACT,
+                     PurpleContactInfo)
 
 #include <libpurple/account.h>
-#include <libpurple/purpleperson.h>
-
-/**
- * PurpleContactClass:
- * @get_account: A virtual method whose sole purpose is to allow
- *               [class@Purple.Account] to subclass [class@Purple.Contact].
- *
- * The class struct for [class@Purple.Contact].
- *
- * Since: 3.0.0
- */
-struct _PurpleContactClass {
-	/*< private >*/
-	GObjectClass parent;
-
-	/*< public >*/
-	PurpleAccount *(*get_account)(PurpleContact *contact);
-
-	/*< private >*/
-	gpointer reserved[4];
-};
 
 /**
  * PurpleContact:
  *
- * A representation of a user. Contacts are used everywhere you need to refer to
- * a user. Be it a chat, an direct message, a file transfer, etc.
+ * A contact is a concrete representation of a user in that it contains all of
+ * the contact information as well as a [class@Purple.Account] to use that
+ * contact information with.
  */
 
 /**
@@ -114,248 +74,6 @@
  */
 PurpleAccount *purple_contact_get_account(PurpleContact *contact);
 
-/**
- * purple_contact_get_id:
- * @contact: The instance.
- *
- * Gets the id of @contact.
- *
- * If a protocol would like to set this, it should call
- * [ctor@GObject.Object.new] and pass in the id attribute manually.
- *
- * Returns: The id of the contact.
- *
- * Since: 3.0.0
- */
-const gchar *purple_contact_get_id(PurpleContact *contact);
-
-/**
- * purple_contact_set_id:
- * @contact: The instance.
- * @id: The new identifier.
- *
- * Sets the identifier of @contact to @id. Note, this should be used rarely if
- * at all. The main intent of this, is for protocols to update the id of
- * [property@Purple.Account:contact] when an account is connected if it is
- * missing.
- *
- * Since: 3.0.0
- */
-void purple_contact_set_id(PurpleContact *contact, const char *id);
-
-/**
- * purple_contact_get_username:
- * @contact: The instance.
- *
- * Gets the username of @contact.
- *
- * Returns: The username of @contact.
- *
- * Since: 3.0.0
- */
-const gchar *purple_contact_get_username(PurpleContact *contact);
-
-/**
- * purple_contact_set_username:
- * @contact: The instance.
- * @username: The new username.
- *
- * Sets the username of @contact to @username.
- *
- * This is primarily used by protocol plugins like IRC when a user changes
- * their "nick" which is their username.
- *
- * Since: 3.0.0
- */
-void purple_contact_set_username(PurpleContact *contact, const gchar *username);
-
-/**
- * purple_contact_get_display_name:
- * @contact: The instance.
- *
- * Gets the display name for @contact. The display name is typically set by the
- * contact and is handled by the protocol plugin.
- *
- * Returns: (nullable): The display name of @contact if one is set, otherwise
- *          %NULL will be returned.
- *
- * Since: 3.0.0
- */
-const gchar *purple_contact_get_display_name(PurpleContact *contact);
-
-/**
- * purple_contact_set_display_name:
- * @contact: The instance.
- * @display_name: (nullable): The new displayname.
- *
- * Sets the display name of @contact to @display_name.
- *
- * This should primarily only be used by protocol plugins and everyone else
- * should be using [method@Purple.Contact.set_alias].
- *
- * Since: 3.0.0
- */
-void purple_contact_set_display_name(PurpleContact *contact, const gchar *display_name);
-
-/**
- * purple_contact_get_alias:
- * @contact: The instance.
- *
- * Gets the alias for @contact.
- *
- * Returns: (nullable): The alias of @contact if one is set, otherwise %NULL.
- *
- * Since: 3.0.0
- */
-const gchar *purple_contact_get_alias(PurpleContact *contact);
-
-/**
- * purple_contact_set_alias:
- * @contact: The instance.
- * @alias: (nullable): The new alias.
- *
- * Sets the alias of @contact to @alias.
- *
- * Protocol plugins may use this value to synchronize across instances.
- *
- * Since: 3.0.0
- */
-void purple_contact_set_alias(PurpleContact *contact, const gchar *alias);
-
-/**
- * purple_contact_get_avatar:
- * @contact: The instance.
- *
- * Gets the avatar for @contact if one is set.
- *
- * Returns: (transfer none): The avatar if set, otherwise %NULL.
- *
- * Since: 3.0.0
- */
-GdkPixbuf *purple_contact_get_avatar(PurpleContact *contact);
-
-/**
- * purple_contact_set_avatar:
- * @contact: The instance.
- * @avatar: (nullable): The new avatar to set.
- *
- * Sets the avatar for @contact to @avatar. If @avatar is %NULL an existing
- * avatar will be removed.
- *
- * Typically this should only called by the protocol plugin.
- *
- * Since: 3.0.0
- */
-void purple_contact_set_avatar(PurpleContact *contact, GdkPixbuf *avatar);
-
-/**
- * purple_contact_get_presence:
- * @contact: The instance.
- *
- * Gets the [class@Purple.Presence] for @contact.
- *
- * Returns: (transfer none) (nullable): The presence for @contact if one is
- *          set, otherwise %NULL.
- *
- * Since: 3.0.0
- */
-PurplePresence *purple_contact_get_presence(PurpleContact *contact);
-
-/**
- * purple_contact_get_tags:
- * @contact: The instance.
- *
- * Gets the [class@Purple.Tags] instance for @contact.
- *
- * Returns: (transfer none): The tags for @contact.
- *
- * Since: 3.0.0
- */
-PurpleTags *purple_contact_get_tags(PurpleContact *contact);
-
-/**
- * purple_contact_set_person:
- * @contact: The instance.
- * @person: (nullable): The new [class@Purple.Person] or %NULL.
- *
- * Sets the person that @contact belongs to to @person.
- *
- * Since: 3.0.0
- */
-void purple_contact_set_person(PurpleContact *contact, PurplePerson *person);
-
-/**
- * purple_contact_get_person:
- * @contact: The instance.
- *
- * Gets the [class@Purple.Person] that @contact belongs to.
- *
- * Returns: (transfer none) (nullable): The [class@Purple.Person] that @contact
- *          belongs to, or %NULL.
- *
- * Since: 3.0.0
- */
-PurplePerson *purple_contact_get_person(PurpleContact *contact);
-
-/**
- * purple_contact_get_permission:
- * @contact: The instance.
- *
- * Gets the [enum@Purple.ContactPermission] for @contact.
- *
- * Returns: The permission for @contact.
- *
- * Since: 3.0.0
- */
-PurpleContactPermission purple_contact_get_permission(PurpleContact *contact);
-
-/**
- * purple_contact_set_permission:
- * @contact: The instance.
- * @permission: The new permission of the contact.
- *
- * Sets the permission of @contact to @permission.
- *
- * Since: 3.0.0
- */
-void purple_contact_set_permission(PurpleContact *contact, PurpleContactPermission permission);
-
-/**
- * purple_contact_get_name_for_display:
- * @contact: The instance.
- *
- * Gets the name that should be displayed for @contact.
- *
- * If @contact is associated with a [class@Purple.Person], the value of
- * [property@Purple.Person:alias] will be returned if it is set.
- *
- * Otherwise, this will return the first set property from the following list:
- *
- *  * [property@Purple.Contact:alias]
- *  * [property@Purple.Contact:display-name]
- *  * [property@Purple.Contact:username]
- *  * [property@Purple.Contact:id]
- *
- * Returns: (transfer none): The name to display for @contact.
- *
- * Since: 3.0.0
- */
-const char *purple_contact_get_name_for_display(PurpleContact *contact);
-
-/**
- * purple_contact_compare:
- * @a: The first instance.
- * @b: The second instance.
- *
- * Compares contacts @a and @b
- *
- * Returns: less than 0 if @a should be sorted before @b, 0 if they sorted
- *          equally, and greater than 0 if @a should be sorted after @b.
- *
- * Since: 3.0.0
- */
-int purple_contact_compare(PurpleContact *a, PurpleContact *b);
-
 G_END_DECLS
 
 #endif /* PURPLE_CONTACT_H */
diff --git a/libpurple/purplecontact.h b/libpurple/purplecontactinfo.h
copy from libpurple/purplecontact.h
copy to libpurple/purplecontactinfo.h
--- a/libpurple/purplecontact.h
+++ b/libpurple/purplecontactinfo.h
@@ -20,8 +20,8 @@
 # error "only <pidgin.h> may be included directly"
 #endif
 
-#ifndef PURPLE_CONTACT_H
-#define PURPLE_CONTACT_H
+#ifndef PURPLE_CONTACT_INFO_H
+#define PURPLE_CONTACT_INFO_H
 
 #include <glib.h>
 #include <glib-object.h>
@@ -33,16 +33,16 @@
 
 G_BEGIN_DECLS
 
-#define PURPLE_TYPE_CONTACT (purple_contact_get_type())
-G_DECLARE_DERIVABLE_TYPE(PurpleContact, purple_contact, PURPLE, CONTACT,
-                         GObject)
+#define PURPLE_TYPE_CONTACT_INFO (purple_contact_info_get_type())
+G_DECLARE_DERIVABLE_TYPE(PurpleContactInfo, purple_contact_info, PURPLE,
+                         CONTACT_INFO, GObject)
 
 /**
- * PurpleContactPermission:
- * @PURPLE_CONTACT_PERMISSION_UNSET: The value is unset.
- * @PURPLE_CONTACT_PERMISSION_ALLOW: The contact is allowed to contact the
+ * PurpleContactInfoPermission:
+ * @PURPLE_CONTACT_INFO_PERMISSION_UNSET: The value is unset.
+ * @PURPLE_CONTACT_INFO_PERMISSION_ALLOW: The contact is allowed to contact the
  *                                   user.
- * @PURPLE_CONTACT_PERMISSION_DENY: The contact is not allowed to contact the
+ * @PURPLE_CONTACT_INFO_PERMISSION_DENY: The contact is not allowed to contact the
  *                                  user.
  *
  * A representation of whether or not a contact has permission to contact the
@@ -51,47 +51,41 @@
  * Since: 3.0.0
  */
 typedef enum {
-	PURPLE_CONTACT_PERMISSION_UNSET = 0,
-	PURPLE_CONTACT_PERMISSION_ALLOW,
-	PURPLE_CONTACT_PERMISSION_DENY,
-} PurpleContactPermission;
+	PURPLE_CONTACT_INFO_PERMISSION_UNSET = 0,
+	PURPLE_CONTACT_INFO_PERMISSION_ALLOW,
+	PURPLE_CONTACT_INFO_PERMISSION_DENY,
+} PurpleContactInfoPermission;
 
-#include <libpurple/account.h>
 #include <libpurple/purpleperson.h>
 
 /**
- * PurpleContactClass:
- * @get_account: A virtual method whose sole purpose is to allow
- *               [class@Purple.Account] to subclass [class@Purple.Contact].
+ * PurpleContactInfoClass:
  *
- * The class struct for [class@Purple.Contact].
+ * The class struct for [class@Purple.ContactInfo].
  *
  * Since: 3.0.0
  */
-struct _PurpleContactClass {
+struct _PurpleContactInfoClass {
 	/*< private >*/
 	GObjectClass parent;
 
-	/*< public >*/
-	PurpleAccount *(*get_account)(PurpleContact *contact);
-
 	/*< private >*/
 	gpointer reserved[4];
 };
 
 /**
- * PurpleContact:
+ * PurpleContactInfo:
  *
- * A representation of a user. Contacts are used everywhere you need to refer to
- * a user. Be it a chat, an direct message, a file transfer, etc.
+ * The information about a contact. This information is used everywhere you
+ * need to refer to a user. Be it a chat, an direct message, a file transfer,
+ * etc.
  */
 
 /**
- * purple_contact_new:
- * @account: The [class@Purple.Account] this contact is from.
+ * purple_contact_info_new:
  * @id: (nullable): The id of the contact.
  *
- * Creates a new [class@Purple.Contact].
+ * Creates a new [class@Purple.ContactInfo].
  *
  * If @id is %NULL, an ID will be randomly generated.
  *
@@ -99,26 +93,13 @@
  *
  * Since: 3.0.0
  */
-PurpleContact *purple_contact_new(PurpleAccount *account, const gchar *id);
+PurpleContactInfo *purple_contact_info_new(const gchar *id);
 
 /**
- * purple_contact_get_account:
- * @contact: The instance.
- *
- * Gets the [class@Purple.Account] that @contact belongs to.
- *
- * Returns: (transfer none): The [class@Purple.Account] that @contact belongs
- *          to.
+ * purple_contact_info_get_id:
+ * @info: The instance.
  *
- * Since: 3.0.0
- */
-PurpleAccount *purple_contact_get_account(PurpleContact *contact);
-
-/**
- * purple_contact_get_id:
- * @contact: The instance.
- *
- * Gets the id of @contact.
+ * Gets the id of @info.
  *
  * If a protocol would like to set this, it should call
  * [ctor@GObject.Object.new] and pass in the id attribute manually.
@@ -127,223 +108,223 @@
  *
  * Since: 3.0.0
  */
-const gchar *purple_contact_get_id(PurpleContact *contact);
+const gchar *purple_contact_info_get_id(PurpleContactInfo *info);
 
 /**
- * purple_contact_set_id:
- * @contact: The instance.
+ * purple_contact_info_set_id:
+ * @info: The instance.
  * @id: The new identifier.
  *
- * Sets the identifier of @contact to @id. Note, this should be used rarely if
+ * Sets the identifier of @info to @id. Note, this should be used rarely if
  * at all. The main intent of this, is for protocols to update the id of
  * [property@Purple.Account:contact] when an account is connected if it is
  * missing.
  *
  * Since: 3.0.0
  */
-void purple_contact_set_id(PurpleContact *contact, const char *id);
+void purple_contact_info_set_id(PurpleContactInfo *info, const char *id);
 
 /**
- * purple_contact_get_username:
- * @contact: The instance.
+ * purple_contact_info_get_username:
+ * @info: The instance.
  *
- * Gets the username of @contact.
+ * Gets the username of @info.
  *
- * Returns: The username of @contact.
+ * Returns: The username of @info.
  *
  * Since: 3.0.0
  */
-const gchar *purple_contact_get_username(PurpleContact *contact);
+const gchar *purple_contact_info_get_username(PurpleContactInfo *info);
 
 /**
- * purple_contact_set_username:
- * @contact: The instance.
+ * purple_contact_info_set_username:
+ * @info: The instance.
  * @username: The new username.
  *
- * Sets the username of @contact to @username.
+ * Sets the username of @info to @username.
  *
  * This is primarily used by protocol plugins like IRC when a user changes
  * their "nick" which is their username.
  *
  * Since: 3.0.0
  */
-void purple_contact_set_username(PurpleContact *contact, const gchar *username);
+void purple_contact_info_set_username(PurpleContactInfo *info, const gchar *username);
 
 /**
- * purple_contact_get_display_name:
- * @contact: The instance.
+ * purple_contact_info_get_display_name:
+ * @info: The instance.
  *
- * Gets the display name for @contact. The display name is typically set by the
+ * Gets the display name for @info. The display name is typically set by the
  * contact and is handled by the protocol plugin.
  *
- * Returns: (nullable): The display name of @contact if one is set, otherwise
+ * Returns: (nullable): The display name of @info if one is set, otherwise
  *          %NULL will be returned.
  *
  * Since: 3.0.0
  */
-const gchar *purple_contact_get_display_name(PurpleContact *contact);
+const gchar *purple_contact_info_get_display_name(PurpleContactInfo *info);
 
 /**
- * purple_contact_set_display_name:
- * @contact: The instance.
+ * purple_contact_info_set_display_name:
+ * @info: The instance.
  * @display_name: (nullable): The new displayname.
  *
- * Sets the display name of @contact to @display_name.
+ * Sets the display name of @info to @display_name.
  *
  * This should primarily only be used by protocol plugins and everyone else
- * should be using [method@Purple.Contact.set_alias].
+ * should be using [method@Purple.ContactInfo.set_alias].
  *
  * Since: 3.0.0
  */
-void purple_contact_set_display_name(PurpleContact *contact, const gchar *display_name);
+void purple_contact_info_set_display_name(PurpleContactInfo *info, const gchar *display_name);
 
 /**
- * purple_contact_get_alias:
- * @contact: The instance.
+ * purple_contact_info_get_alias:
+ * @info: The instance.
  *
- * Gets the alias for @contact.
+ * Gets the alias for @info.
  *
- * Returns: (nullable): The alias of @contact if one is set, otherwise %NULL.
+ * Returns: (nullable): The alias of @info if one is set, otherwise %NULL.
  *
  * Since: 3.0.0
  */
-const gchar *purple_contact_get_alias(PurpleContact *contact);
+const gchar *purple_contact_info_get_alias(PurpleContactInfo *info);
 
 /**
- * purple_contact_set_alias:
- * @contact: The instance.
+ * purple_contact_info_set_alias:
+ * @info: The instance.
  * @alias: (nullable): The new alias.
  *
- * Sets the alias of @contact to @alias.
+ * Sets the alias of @info to @alias.
  *
  * Protocol plugins may use this value to synchronize across instances.
  *
  * Since: 3.0.0
  */
-void purple_contact_set_alias(PurpleContact *contact, const gchar *alias);
+void purple_contact_info_set_alias(PurpleContactInfo *info, const gchar *alias);
 
 /**
- * purple_contact_get_avatar:
- * @contact: The instance.
+ * purple_contact_info_get_avatar:
+ * @info: The instance.
  *
- * Gets the avatar for @contact if one is set.
+ * Gets the avatar for @info if one is set.
  *
  * Returns: (transfer none): The avatar if set, otherwise %NULL.
  *
  * Since: 3.0.0
  */
-GdkPixbuf *purple_contact_get_avatar(PurpleContact *contact);
+GdkPixbuf *purple_contact_info_get_avatar(PurpleContactInfo *info);
 
 /**
- * purple_contact_set_avatar:
- * @contact: The instance.
+ * purple_contact_info_set_avatar:
+ * @info: The instance.
  * @avatar: (nullable): The new avatar to set.
  *
- * Sets the avatar for @contact to @avatar. If @avatar is %NULL an existing
+ * Sets the avatar for @info to @avatar. If @avatar is %NULL an existing
  * avatar will be removed.
  *
  * Typically this should only called by the protocol plugin.
  *
  * Since: 3.0.0
  */
-void purple_contact_set_avatar(PurpleContact *contact, GdkPixbuf *avatar);
+void purple_contact_info_set_avatar(PurpleContactInfo *info, GdkPixbuf *avatar);
 
 /**
- * purple_contact_get_presence:
- * @contact: The instance.
+ * purple_contact_info_get_presence:
+ * @info: The instance.
  *
- * Gets the [class@Purple.Presence] for @contact.
+ * Gets the [class@Purple.Presence] for @info.
  *
- * Returns: (transfer none) (nullable): The presence for @contact if one is
+ * Returns: (transfer none) (nullable): The presence for @info if one is
  *          set, otherwise %NULL.
  *
  * Since: 3.0.0
  */
-PurplePresence *purple_contact_get_presence(PurpleContact *contact);
+PurplePresence *purple_contact_info_get_presence(PurpleContactInfo *info);
 
 /**
- * purple_contact_get_tags:
- * @contact: The instance.
+ * purple_contact_info_get_tags:
+ * @info: The instance.
  *
- * Gets the [class@Purple.Tags] instance for @contact.
+ * Gets the [class@Purple.Tags] instance for @info.
  *
- * Returns: (transfer none): The tags for @contact.
+ * Returns: (transfer none): The tags for @info.
  *
  * Since: 3.0.0
  */
-PurpleTags *purple_contact_get_tags(PurpleContact *contact);
+PurpleTags *purple_contact_info_get_tags(PurpleContactInfo *info);
 
 /**
- * purple_contact_set_person:
- * @contact: The instance.
+ * purple_contact_info_set_person:
+ * @info: The instance.
  * @person: (nullable): The new [class@Purple.Person] or %NULL.
  *
- * Sets the person that @contact belongs to to @person.
+ * Sets the person that @info belongs to to @person.
  *
  * Since: 3.0.0
  */
-void purple_contact_set_person(PurpleContact *contact, PurplePerson *person);
+void purple_contact_info_set_person(PurpleContactInfo *info, PurplePerson *person);
 
 /**
- * purple_contact_get_person:
- * @contact: The instance.
+ * purple_contact_info_get_person:
+ * @info: The instance.
  *
- * Gets the [class@Purple.Person] that @contact belongs to.
+ * Gets the [class@Purple.Person] that @info belongs to.
  *
- * Returns: (transfer none) (nullable): The [class@Purple.Person] that @contact
+ * Returns: (transfer none) (nullable): The [class@Purple.Person] that @info
  *          belongs to, or %NULL.
  *
  * Since: 3.0.0
  */
-PurplePerson *purple_contact_get_person(PurpleContact *contact);
+PurplePerson *purple_contact_info_get_person(PurpleContactInfo *info);
 
 /**
- * purple_contact_get_permission:
- * @contact: The instance.
+ * purple_contact_info_get_permission:
+ * @info: The instance.
  *
- * Gets the [enum@Purple.ContactPermission] for @contact.
+ * Gets the [enum@Purple.ContactInfoPermission] for @info.
  *
- * Returns: The permission for @contact.
+ * Returns: The permission for @info.
  *
  * Since: 3.0.0
  */
-PurpleContactPermission purple_contact_get_permission(PurpleContact *contact);
+PurpleContactInfoPermission purple_contact_info_get_permission(PurpleContactInfo *info);
 
 /**
- * purple_contact_set_permission:
- * @contact: The instance.
+ * purple_contact_info_set_permission:
+ * @info: The instance.
  * @permission: The new permission of the contact.
  *
- * Sets the permission of @contact to @permission.
+ * Sets the permission of @info to @permission.
  *
  * Since: 3.0.0
  */
-void purple_contact_set_permission(PurpleContact *contact, PurpleContactPermission permission);
+void purple_contact_info_set_permission(PurpleContactInfo *info, PurpleContactInfoPermission permission);
 
 /**
- * purple_contact_get_name_for_display:
- * @contact: The instance.
+ * purple_contact_info_get_name_for_display:
+ * @info: The instance.
  *
- * Gets the name that should be displayed for @contact.
+ * Gets the name that should be displayed for @info.
  *
- * If @contact is associated with a [class@Purple.Person], the value of
+ * If @info is associated with a [class@Purple.Person], the value of
  * [property@Purple.Person:alias] will be returned if it is set.
  *
  * Otherwise, this will return the first set property from the following list:
  *
- *  * [property@Purple.Contact:alias]
- *  * [property@Purple.Contact:display-name]
- *  * [property@Purple.Contact:username]
- *  * [property@Purple.Contact:id]
+ *  * [property@Purple.ContactInfo:alias]
+ *  * [property@Purple.ContactInfo:display-name]
+ *  * [property@Purple.ContactInfo:username]
+ *  * [property@Purple.ContactInfo:id]
  *
- * Returns: (transfer none): The name to display for @contact.
+ * Returns: (transfer none): The name to display for @info.
  *
  * Since: 3.0.0
  */
-const char *purple_contact_get_name_for_display(PurpleContact *contact);
+const char *purple_contact_info_get_name_for_display(PurpleContactInfo *info);
 
 /**
- * purple_contact_compare:
+ * purple_contact_info_compare:
  * @a: The first instance.
  * @b: The second instance.
  *
@@ -354,8 +335,8 @@
  *
  * Since: 3.0.0
  */
-int purple_contact_compare(PurpleContact *a, PurpleContact *b);
+int purple_contact_info_compare(PurpleContactInfo *a, PurpleContactInfo *b);
 
 G_END_DECLS
 
-#endif /* PURPLE_CONTACT_H */
+#endif /* PURPLE_CONTACT_INFO_H */
diff --git a/libpurple/purplecontact.c b/libpurple/purplecontact.c
--- a/libpurple/purplecontact.c
+++ b/libpurple/purplecontact.c
@@ -21,71 +21,34 @@
 #include "purpleenums.h"
 #include "util.h"
 
-typedef struct  {
-	gchar *id;
-	PurpleAccount *account;
-
-	gchar *username;
-	gchar *display_name;
-	gchar *alias;
+struct _PurpleContact {
+	PurpleContactInfo parent;
 
-	GdkPixbuf *avatar;
-
-	PurplePresence *presence;
-
-	PurpleTags *tags;
-
-	PurplePerson *person;
-
-	PurpleContactPermission permission;
-} PurpleContactPrivate;
+	PurpleAccount *account;
+};
 
 enum {
 	PROP_0,
-	PROP_ID,
 	PROP_ACCOUNT,
-	PROP_USERNAME,
-	PROP_DISPLAY_NAME,
-	PROP_ALIAS,
-	PROP_AVATAR,
-	PROP_PRESENCE,
-	PROP_TAGS,
-	PROP_PERSON,
-	PROP_PERMISSION,
 	N_PROPERTIES
 };
 static GParamSpec *properties[N_PROPERTIES] = {NULL, };
 
-G_DEFINE_TYPE_WITH_PRIVATE(PurpleContact, purple_contact, G_TYPE_OBJECT)
+G_DEFINE_TYPE(PurpleContact, purple_contact, PURPLE_TYPE_CONTACT_INFO)
 
 /******************************************************************************
  * Helpers
  *****************************************************************************/
 static void
 purple_contact_set_account(PurpleContact *contact, PurpleAccount *account) {
-	PurpleContactPrivate *priv = NULL;
-
 	g_return_if_fail(PURPLE_IS_CONTACT(contact));
 	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
 
-	priv = purple_contact_get_instance_private(contact);
-
-	if(g_set_object(&priv->account, account)) {
+	if(g_set_object(&contact->account, account)) {
 		g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_ACCOUNT]);
 	}
 }
 
-static PurpleAccount *
-purple_contact_default_get_account(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
-
-	priv = purple_contact_get_instance_private(contact);
-
-	return priv->account;
-}
-
 /******************************************************************************
  * GObject Implementation
  *****************************************************************************/
@@ -96,36 +59,9 @@
 	PurpleContact *contact = PURPLE_CONTACT(obj);
 
 	switch(param_id) {
-		case PROP_ID:
-			g_value_set_string(value, purple_contact_get_id(contact));
-			break;
 		case PROP_ACCOUNT:
 			g_value_set_object(value, purple_contact_get_account(contact));
 			break;
-		case PROP_USERNAME:
-			g_value_set_string(value, purple_contact_get_username(contact));
-			break;
-		case PROP_DISPLAY_NAME:
-			g_value_set_string(value, purple_contact_get_display_name(contact));
-			break;
-		case PROP_ALIAS:
-			g_value_set_string(value, purple_contact_get_alias(contact));
-			break;
-		case PROP_AVATAR:
-			g_value_set_object(value, purple_contact_get_avatar(contact));
-			break;
-		case PROP_PRESENCE:
-			g_value_set_object(value, purple_contact_get_presence(contact));
-			break;
-		case PROP_TAGS:
-			g_value_set_object(value, purple_contact_get_tags(contact));
-			break;
-		case PROP_PERSON:
-			g_value_set_object(value, purple_contact_get_person(contact));
-			break;
-		case PROP_PERMISSION:
-			g_value_set_enum(value, purple_contact_get_permission(contact));
-			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
 			break;
@@ -139,30 +75,9 @@
 	PurpleContact *contact = PURPLE_CONTACT(obj);
 
 	switch(param_id) {
-		case PROP_ID:
-			purple_contact_set_id(contact, g_value_get_string(value));
-			break;
 		case PROP_ACCOUNT:
 			purple_contact_set_account(contact, g_value_get_object(value));
 			break;
-		case PROP_USERNAME:
-			purple_contact_set_username(contact, g_value_get_string(value));
-			break;
-		case PROP_DISPLAY_NAME:
-			purple_contact_set_display_name(contact, g_value_get_string(value));
-			break;
-		case PROP_ALIAS:
-			purple_contact_set_alias(contact, g_value_get_string(value));
-			break;
-		case PROP_AVATAR:
-			purple_contact_set_avatar(contact, g_value_get_object(value));
-			break;
-		case PROP_PERSON:
-			purple_contact_set_person(contact, g_value_get_object(value));
-			break;
-		case PROP_PERMISSION:
-			purple_contact_set_permission(contact, g_value_get_enum(value));
-			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
 			break;
@@ -172,79 +87,25 @@
 static void
 purple_contact_dispose(GObject *obj) {
 	PurpleContact *contact = PURPLE_CONTACT(obj);
-	PurpleContactPrivate *priv = purple_contact_get_instance_private(contact);
 
-	g_clear_object(&priv->account);
-	g_clear_object(&priv->avatar);
-	g_clear_object(&priv->presence);
-	g_clear_object(&priv->tags);
-	g_clear_object(&priv->person);
+	g_clear_object(&contact->account);
 
 	G_OBJECT_CLASS(purple_contact_parent_class)->dispose(obj);
 }
 
 static void
-purple_contact_finalize(GObject *obj) {
-	PurpleContact *contact = PURPLE_CONTACT(obj);
-	PurpleContactPrivate *priv = purple_contact_get_instance_private(contact);
-
-	g_clear_pointer(&priv->id, g_free);
-	g_clear_pointer(&priv->username, g_free);
-	g_clear_pointer(&priv->display_name, g_free);
-	g_clear_pointer(&priv->alias, g_free);
-
-	G_OBJECT_CLASS(purple_contact_parent_class)->finalize(obj);
-}
-
-static void
-purple_contact_constructed(GObject *obj) {
-	PurpleContact *contact = NULL;
-	PurpleContactPrivate *priv = NULL;
-
-	G_OBJECT_CLASS(purple_contact_parent_class)->constructed(obj);
-
-	contact = PURPLE_CONTACT(obj);
-	priv = purple_contact_get_instance_private(contact);
-
-	if(priv->id == NULL) {
-		purple_contact_set_id(contact, NULL);
-	}
-}
-
-static void
 purple_contact_init(PurpleContact *contact) {
-	PurpleContactPrivate *priv = purple_contact_get_instance_private(contact);
-
-	priv->tags = purple_tags_new();
-	priv->presence = g_object_new(PURPLE_TYPE_PRESENCE, NULL);
 }
 
 static void
 purple_contact_class_init(PurpleContactClass *klass) {
 	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
 
-	klass->get_account = purple_contact_default_get_account;
-
-	obj_class->constructed = purple_contact_constructed;
 	obj_class->dispose = purple_contact_dispose;
-	obj_class->finalize = purple_contact_finalize;
 	obj_class->get_property = purple_contact_get_property;
 	obj_class->set_property = purple_contact_set_property;
 
 	/**
-	 * PurpleContact:id:
-	 *
-	 * The protocol specific id for the contact.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_ID] = g_param_spec_string(
-		"id", "id",
-		"The id of the contact",
-		NULL,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
 	 * PurpleContact:account:
 	 *
 	 * The account that this contact belongs to.
@@ -257,116 +118,6 @@
 		PURPLE_TYPE_ACCOUNT,
 		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
 
-	/**
-	 * PurpleContact:username:
-	 *
-	 * The username for this contact. In rare cases this can change, like when
-	 * a user changes their "nick" on IRC which is their user name.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_USERNAME] = g_param_spec_string(
-		"username", "username",
-		"The username of the contact",
-		NULL,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleContact:display-name:
-	 *
-	 * The display name for this contact. This is generally set by the person
-	 * the contact is representing and controlled via the protocol plugin.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_DISPLAY_NAME] = g_param_spec_string(
-		"display-name", "display-name",
-		"The display name of the contact",
-		NULL,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleContact:alias:
-	 *
-	 * The alias for this contact. This is controlled by the libpurple user and
-	 * may be used by the protocol if it allows for aliasing.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_ALIAS] = g_param_spec_string(
-		"alias", "alias",
-		"The alias of the contact.",
-		NULL,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleContact:avatar:
-	 *
-	 * The avatar for this contact. This is typically controlled by the protocol
-	 * and should only be read by others.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_AVATAR] = g_param_spec_object(
-		"avatar", "avatar",
-		"The avatar of the contact",
-		GDK_TYPE_PIXBUF,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleContact:presence:
-	 *
-	 * The [class@Purple.Presence] for this contact. This is typically
-	 * controlled by the protocol and should only be read by others.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_PRESENCE] = g_param_spec_object(
-		"presence", "presence",
-		"The presence of the contact",
-		PURPLE_TYPE_PRESENCE,
-		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleContact:tags:
-	 *
-	 * The [class@Purple.Tags] for this contact.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_TAGS] = g_param_spec_object(
-		"tags", "tags",
-		"The tags for the contact",
-		PURPLE_TYPE_TAGS,
-		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleContact:person:
-	 *
-	 * The [class@Purple.Person] that this contact belongs to.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_PERSON] = g_param_spec_object(
-		"person", "person",
-		"The person this contact belongs to.",
-		PURPLE_TYPE_PERSON,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleContact:permission:
-	 *
-	 * The permission level for the contact.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_PERMISSION] = g_param_spec_enum(
-		"permission", "permission",
-		"The permission level of the contact",
-		PURPLE_TYPE_CONTACT_PERMISSION,
-		PURPLE_CONTACT_PERMISSION_UNSET,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
 	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
 }
 
@@ -386,285 +137,7 @@
 
 PurpleAccount *
 purple_contact_get_account(PurpleContact *contact) {
-	PurpleContactClass *klass = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
-
-	klass = PURPLE_CONTACT_GET_CLASS(contact);
-	if(klass != NULL && klass->get_account != NULL) {
-		return klass->get_account(contact);
-	}
-
-	return NULL;
-}
-
-const gchar *
-purple_contact_get_id(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
-
-	priv = purple_contact_get_instance_private(contact);
-
-	return priv->id;
-}
-
-void
-purple_contact_set_id(PurpleContact *contact, const gchar *id) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
-
-	priv = purple_contact_get_instance_private(contact);
-
-	g_free(priv->id);
-	priv->id = g_strdup(id);
-
-	g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_ID]);
-}
-
-const gchar *
-purple_contact_get_username(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
-
-	priv = purple_contact_get_instance_private(contact);
-
-	return priv->username;
-}
-
-void
-purple_contact_set_username(PurpleContact *contact, const gchar *username) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
-	g_return_if_fail(username != NULL);
-
-	priv = purple_contact_get_instance_private(contact);
-
-	g_free(priv->username);
-	priv->username = g_strdup(username);
-
-	g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_USERNAME]);
-}
-
-const gchar *
-purple_contact_get_display_name(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
-
-	priv = purple_contact_get_instance_private(contact);
-
-	return priv->display_name;
-}
-
-void
-purple_contact_set_display_name(PurpleContact *contact,
-                                const gchar *display_name)
-{
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
-
-	priv = purple_contact_get_instance_private(contact);
-
-	g_free(priv->display_name);
-	priv->display_name = g_strdup(display_name);
-
-	g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_DISPLAY_NAME]);
-}
-
-const gchar *
-purple_contact_get_alias(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
-
-	priv = purple_contact_get_instance_private(contact);
-
-	return priv->alias;
-}
-
-void
-purple_contact_set_alias(PurpleContact *contact, const gchar *alias) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
-
-	priv = purple_contact_get_instance_private(contact);
-
-	g_free(priv->alias);
-	priv->alias = g_strdup(alias);
-
-	g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_ALIAS]);
-}
-
-GdkPixbuf *
-purple_contact_get_avatar(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
-
 	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
 
-	priv = purple_contact_get_instance_private(contact);
-
-	return priv->avatar;
-}
-
-void
-purple_contact_set_avatar(PurpleContact *contact, GdkPixbuf *avatar) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
-
-	priv = purple_contact_get_instance_private(contact);
-
-	if(g_set_object(&priv->avatar, avatar)) {
-		g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_AVATAR]);
-	}
-}
-
-PurplePresence *
-purple_contact_get_presence(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
-
-	priv = purple_contact_get_instance_private(contact);
-
-	return priv->presence;
-}
-
-PurpleTags *
-purple_contact_get_tags(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
-
-	priv = purple_contact_get_instance_private(contact);
-
-	return priv->tags;
-}
-
-void
-purple_contact_set_person(PurpleContact *contact, PurplePerson *person) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
-
-	priv = purple_contact_get_instance_private(contact);
-
-	if(g_set_object(&priv->person, person)) {
-		g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_PERSON]);
-	}
-}
-
-PurplePerson *
-purple_contact_get_person(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
-
-	priv = purple_contact_get_instance_private(contact);
-
-	return priv->person;
-}
-
-PurpleContactPermission
-purple_contact_get_permission(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact),
-	                     PURPLE_CONTACT_PERMISSION_UNSET);
-
-	priv = purple_contact_get_instance_private(contact);
-
-	return priv->permission;
+	return contact->account;
 }
-
-void
-purple_contact_set_permission(PurpleContact *contact,
-                              PurpleContactPermission permission)
-{
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
-
-	priv = purple_contact_get_instance_private(contact);
-
-	priv->permission = permission;
-
-	g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_PERMISSION]);
-}
-
-const char *
-purple_contact_get_name_for_display(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
-
-	priv = purple_contact_get_instance_private(contact);
-
-	/* If contact is associated with a PurplePerson that has an alias set,
-	 * return the alias of that PurplePerson.
-	 */
-	if(priv->person != NULL) {
-		const char *alias = purple_person_get_alias(priv->person);
-
-		if(alias != NULL && alias[0] != '\0') {
-			return alias;
-		}
-	}
-
-	/* If the purple user set an alias for the contact, return that. */
-	if(priv->alias != NULL && priv->alias[0] != '\0') {
-		return priv->alias;
-	}
-
-	/* If the contact has a display name set, return that. */
-	if(priv->display_name != NULL && priv->display_name[0] != '\0') {
-		return priv->display_name;
-	}
-
-	/* Fallback to the username if that is set. */
-	if(priv->username != NULL && priv->username[0] != '\0') {
-		return priv->username;
-	}
-
-	/* Finally, in a last ditch effort, return the id of the contact. */
-	return priv->id;
-}
-
-int
-purple_contact_compare(PurpleContact *a, PurpleContact *b) {
-	PurplePerson *person_a = NULL;
-	PurplePerson *person_b = NULL;
-	const char *name_a = NULL;
-	const char *name_b = NULL;
-
-	/* Check for NULL values. */
-	if(a != NULL && b == NULL) {
-		return -1;
-	} else if(a == NULL && b != NULL) {
-		return 1;
-	} else if(a == NULL && b == NULL) {
-		return 0;
-	}
-
-	/* Check if the contacts have persons associated with them. */
-	person_a = purple_contact_get_person(a);
-	person_b = purple_contact_get_person(b);
-
-	if(person_a != NULL && person_b == NULL) {
-		return -1;
-	} else if(person_a == NULL && person_b != NULL) {
-		return 1;
-	}
-
-	/* Finally get the names for the displaying and compare those. */
-	name_a = purple_contact_get_name_for_display(a);
-	name_b = purple_contact_get_name_for_display(b);
-
-	return purple_utf8_strcasecmp(name_a, name_b);
-}
diff --git a/libpurple/purplecontact.c b/libpurple/purplecontactinfo.c
copy from libpurple/purplecontact.c
copy to libpurple/purplecontactinfo.c
--- a/libpurple/purplecontact.c
+++ b/libpurple/purplecontactinfo.c
@@ -16,14 +16,13 @@
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
-#include "purplecontact.h"
+#include "purplecontactinfo.h"
 
 #include "purpleenums.h"
 #include "util.h"
 
 typedef struct  {
 	gchar *id;
-	PurpleAccount *account;
 
 	gchar *username;
 	gchar *display_name;
@@ -37,13 +36,12 @@
 
 	PurplePerson *person;
 
-	PurpleContactPermission permission;
-} PurpleContactPrivate;
+	PurpleContactInfoPermission permission;
+} PurpleContactInfoPrivate;
 
 enum {
 	PROP_0,
 	PROP_ID,
-	PROP_ACCOUNT,
 	PROP_USERNAME,
 	PROP_DISPLAY_NAME,
 	PROP_ALIAS,
@@ -56,75 +54,49 @@
 };
 static GParamSpec *properties[N_PROPERTIES] = {NULL, };
 
-G_DEFINE_TYPE_WITH_PRIVATE(PurpleContact, purple_contact, G_TYPE_OBJECT)
-
-/******************************************************************************
- * Helpers
- *****************************************************************************/
-static void
-purple_contact_set_account(PurpleContact *contact, PurpleAccount *account) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
-	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
-
-	priv = purple_contact_get_instance_private(contact);
-
-	if(g_set_object(&priv->account, account)) {
-		g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_ACCOUNT]);
-	}
-}
-
-static PurpleAccount *
-purple_contact_default_get_account(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
-
-	priv = purple_contact_get_instance_private(contact);
-
-	return priv->account;
-}
+G_DEFINE_TYPE_WITH_PRIVATE(PurpleContactInfo, purple_contact_info,
+                           G_TYPE_OBJECT)
 
 /******************************************************************************
  * GObject Implementation
  *****************************************************************************/
 static void
-purple_contact_get_property(GObject *obj, guint param_id, GValue *value,
-                            GParamSpec *pspec)
+purple_contact_info_get_property(GObject *obj, guint param_id, GValue *value,
+                                 GParamSpec *pspec)
 {
-	PurpleContact *contact = PURPLE_CONTACT(obj);
+	PurpleContactInfo *contact = PURPLE_CONTACT_INFO(obj);
 
 	switch(param_id) {
 		case PROP_ID:
-			g_value_set_string(value, purple_contact_get_id(contact));
-			break;
-		case PROP_ACCOUNT:
-			g_value_set_object(value, purple_contact_get_account(contact));
+			g_value_set_string(value, purple_contact_info_get_id(contact));
 			break;
 		case PROP_USERNAME:
-			g_value_set_string(value, purple_contact_get_username(contact));
+			g_value_set_string(value,
+			                   purple_contact_info_get_username(contact));
 			break;
 		case PROP_DISPLAY_NAME:
-			g_value_set_string(value, purple_contact_get_display_name(contact));
+			g_value_set_string(value,
+			                   purple_contact_info_get_display_name(contact));
 			break;
 		case PROP_ALIAS:
-			g_value_set_string(value, purple_contact_get_alias(contact));
+			g_value_set_string(value, purple_contact_info_get_alias(contact));
 			break;
 		case PROP_AVATAR:
-			g_value_set_object(value, purple_contact_get_avatar(contact));
+			g_value_set_object(value, purple_contact_info_get_avatar(contact));
 			break;
 		case PROP_PRESENCE:
-			g_value_set_object(value, purple_contact_get_presence(contact));
+			g_value_set_object(value,
+			                   purple_contact_info_get_presence(contact));
 			break;
 		case PROP_TAGS:
-			g_value_set_object(value, purple_contact_get_tags(contact));
+			g_value_set_object(value, purple_contact_info_get_tags(contact));
 			break;
 		case PROP_PERSON:
-			g_value_set_object(value, purple_contact_get_person(contact));
+			g_value_set_object(value, purple_contact_info_get_person(contact));
 			break;
 		case PROP_PERMISSION:
-			g_value_set_enum(value, purple_contact_get_permission(contact));
+			g_value_set_enum(value,
+			                 purple_contact_info_get_permission(contact));
 			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
@@ -133,35 +105,35 @@
 }
 
 static void
-purple_contact_set_property(GObject *obj, guint param_id, const GValue *value,
-                            GParamSpec *pspec)
+purple_contact_info_set_property(GObject *obj, guint param_id,
+                                 const GValue *value, GParamSpec *pspec)
 {
-	PurpleContact *contact = PURPLE_CONTACT(obj);
+	PurpleContactInfo *contact = PURPLE_CONTACT_INFO(obj);
 
 	switch(param_id) {
 		case PROP_ID:
-			purple_contact_set_id(contact, g_value_get_string(value));
-			break;
-		case PROP_ACCOUNT:
-			purple_contact_set_account(contact, g_value_get_object(value));
+			purple_contact_info_set_id(contact, g_value_get_string(value));
 			break;
 		case PROP_USERNAME:
-			purple_contact_set_username(contact, g_value_get_string(value));
+			purple_contact_info_set_username(contact,
+			                                 g_value_get_string(value));
 			break;
 		case PROP_DISPLAY_NAME:
-			purple_contact_set_display_name(contact, g_value_get_string(value));
+			purple_contact_info_set_display_name(contact,
+			                                     g_value_get_string(value));
 			break;
 		case PROP_ALIAS:
-			purple_contact_set_alias(contact, g_value_get_string(value));
+			purple_contact_info_set_alias(contact, g_value_get_string(value));
 			break;
 		case PROP_AVATAR:
-			purple_contact_set_avatar(contact, g_value_get_object(value));
+			purple_contact_info_set_avatar(contact, g_value_get_object(value));
 			break;
 		case PROP_PERSON:
-			purple_contact_set_person(contact, g_value_get_object(value));
+			purple_contact_info_set_person(contact, g_value_get_object(value));
 			break;
 		case PROP_PERMISSION:
-			purple_contact_set_permission(contact, g_value_get_enum(value));
+			purple_contact_info_set_permission(contact,
+			                                   g_value_get_enum(value));
 			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
@@ -170,69 +142,72 @@
 }
 
 static void
-purple_contact_dispose(GObject *obj) {
-	PurpleContact *contact = PURPLE_CONTACT(obj);
-	PurpleContactPrivate *priv = purple_contact_get_instance_private(contact);
+purple_contact_info_dispose(GObject *obj) {
+	PurpleContactInfo *contact = PURPLE_CONTACT_INFO(obj);
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_clear_object(&priv->account);
+	priv = purple_contact_info_get_instance_private(contact);
+
 	g_clear_object(&priv->avatar);
 	g_clear_object(&priv->presence);
 	g_clear_object(&priv->tags);
 	g_clear_object(&priv->person);
 
-	G_OBJECT_CLASS(purple_contact_parent_class)->dispose(obj);
+	G_OBJECT_CLASS(purple_contact_info_parent_class)->dispose(obj);
 }
 
 static void
-purple_contact_finalize(GObject *obj) {
-	PurpleContact *contact = PURPLE_CONTACT(obj);
-	PurpleContactPrivate *priv = purple_contact_get_instance_private(contact);
+purple_contact_info_finalize(GObject *obj) {
+	PurpleContactInfo *contact = PURPLE_CONTACT_INFO(obj);
+	PurpleContactInfoPrivate *priv = NULL;
+
+	priv = purple_contact_info_get_instance_private(contact);
 
 	g_clear_pointer(&priv->id, g_free);
 	g_clear_pointer(&priv->username, g_free);
 	g_clear_pointer(&priv->display_name, g_free);
 	g_clear_pointer(&priv->alias, g_free);
 
-	G_OBJECT_CLASS(purple_contact_parent_class)->finalize(obj);
+	G_OBJECT_CLASS(purple_contact_info_parent_class)->finalize(obj);
 }
 
 static void
-purple_contact_constructed(GObject *obj) {
-	PurpleContact *contact = NULL;
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_constructed(GObject *obj) {
+	PurpleContactInfo *contact = NULL;
+	PurpleContactInfoPrivate *priv = NULL;
 
-	G_OBJECT_CLASS(purple_contact_parent_class)->constructed(obj);
+	G_OBJECT_CLASS(purple_contact_info_parent_class)->constructed(obj);
 
-	contact = PURPLE_CONTACT(obj);
-	priv = purple_contact_get_instance_private(contact);
+	contact = PURPLE_CONTACT_INFO(obj);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	if(priv->id == NULL) {
-		purple_contact_set_id(contact, NULL);
+		purple_contact_info_set_id(contact, NULL);
 	}
 }
 
 static void
-purple_contact_init(PurpleContact *contact) {
-	PurpleContactPrivate *priv = purple_contact_get_instance_private(contact);
+purple_contact_info_init(PurpleContactInfo *contact) {
+	PurpleContactInfoPrivate *priv = NULL;
+
+	priv = purple_contact_info_get_instance_private(contact);
 
 	priv->tags = purple_tags_new();
 	priv->presence = g_object_new(PURPLE_TYPE_PRESENCE, NULL);
 }
 
 static void
-purple_contact_class_init(PurpleContactClass *klass) {
+purple_contact_info_class_init(PurpleContactInfoClass *klass) {
 	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
 
-	klass->get_account = purple_contact_default_get_account;
-
-	obj_class->constructed = purple_contact_constructed;
-	obj_class->dispose = purple_contact_dispose;
-	obj_class->finalize = purple_contact_finalize;
-	obj_class->get_property = purple_contact_get_property;
-	obj_class->set_property = purple_contact_set_property;
+	obj_class->constructed = purple_contact_info_constructed;
+	obj_class->dispose = purple_contact_info_dispose;
+	obj_class->finalize = purple_contact_info_finalize;
+	obj_class->get_property = purple_contact_info_get_property;
+	obj_class->set_property = purple_contact_info_set_property;
 
 	/**
-	 * PurpleContact:id:
+	 * PurpleContactInfo:id:
 	 *
 	 * The protocol specific id for the contact.
 	 *
@@ -245,20 +220,7 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleContact:account:
-	 *
-	 * The account that this contact belongs to.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_ACCOUNT] = g_param_spec_object(
-		"account", "account",
-		"The account this contact belongs to",
-		PURPLE_TYPE_ACCOUNT,
-		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleContact:username:
+	 * PurpleContactInfo:username:
 	 *
 	 * The username for this contact. In rare cases this can change, like when
 	 * a user changes their "nick" on IRC which is their user name.
@@ -272,7 +234,7 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleContact:display-name:
+	 * PurpleContactInfo:display-name:
 	 *
 	 * The display name for this contact. This is generally set by the person
 	 * the contact is representing and controlled via the protocol plugin.
@@ -286,7 +248,7 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleContact:alias:
+	 * PurpleContactInfo:alias:
 	 *
 	 * The alias for this contact. This is controlled by the libpurple user and
 	 * may be used by the protocol if it allows for aliasing.
@@ -300,7 +262,7 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleContact:avatar:
+	 * PurpleContactInfo:avatar:
 	 *
 	 * The avatar for this contact. This is typically controlled by the protocol
 	 * and should only be read by others.
@@ -314,7 +276,7 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleContact:presence:
+	 * PurpleContactInfo:presence:
 	 *
 	 * The [class@Purple.Presence] for this contact. This is typically
 	 * controlled by the protocol and should only be read by others.
@@ -328,7 +290,7 @@
 		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleContact:tags:
+	 * PurpleContactInfo:tags:
 	 *
 	 * The [class@Purple.Tags] for this contact.
 	 *
@@ -341,7 +303,7 @@
 		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleContact:person:
+	 * PurpleContactInfo:person:
 	 *
 	 * The [class@Purple.Person] that this contact belongs to.
 	 *
@@ -354,7 +316,7 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleContact:permission:
+	 * PurpleContactInfo:permission:
 	 *
 	 * The permission level for the contact.
 	 *
@@ -363,8 +325,8 @@
 	properties[PROP_PERMISSION] = g_param_spec_enum(
 		"permission", "permission",
 		"The permission level of the contact",
-		PURPLE_TYPE_CONTACT_PERMISSION,
-		PURPLE_CONTACT_PERMISSION_UNSET,
+		PURPLE_TYPE_CONTACT_INFO_PERMISSION,
+		PURPLE_CONTACT_INFO_PERMISSION_UNSET,
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
@@ -373,49 +335,32 @@
 /******************************************************************************
  * Public API
  *****************************************************************************/
-PurpleContact *
-purple_contact_new(PurpleAccount *account, const gchar *id) {
-	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
-
+PurpleContactInfo *
+purple_contact_info_new(const gchar *id) {
 	return g_object_new(
-		PURPLE_TYPE_CONTACT,
-		"account", account,
+		PURPLE_TYPE_CONTACT_INFO,
 		"id", id,
 		NULL);
 }
 
-PurpleAccount *
-purple_contact_get_account(PurpleContact *contact) {
-	PurpleContactClass *klass = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
-
-	klass = PURPLE_CONTACT_GET_CLASS(contact);
-	if(klass != NULL && klass->get_account != NULL) {
-		return klass->get_account(contact);
-	}
+const gchar *
+purple_contact_info_get_id(PurpleContactInfo *contact) {
+	PurpleContactInfoPrivate *priv = NULL;
 
-	return NULL;
-}
+	g_return_val_if_fail(PURPLE_IS_CONTACT_INFO(contact), NULL);
 
-const gchar *
-purple_contact_get_id(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
-
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	return priv->id;
 }
 
 void
-purple_contact_set_id(PurpleContact *contact, const gchar *id) {
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_set_id(PurpleContactInfo *contact, const gchar *id) {
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
+	g_return_if_fail(PURPLE_IS_CONTACT_INFO(contact));
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	g_free(priv->id);
 	priv->id = g_strdup(id);
@@ -424,24 +369,26 @@
 }
 
 const gchar *
-purple_contact_get_username(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_get_username(PurpleContactInfo *contact) {
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+	g_return_val_if_fail(PURPLE_IS_CONTACT_INFO(contact), NULL);
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	return priv->username;
 }
 
 void
-purple_contact_set_username(PurpleContact *contact, const gchar *username) {
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_set_username(PurpleContactInfo *contact,
+                                 const gchar *username)
+{
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
+	g_return_if_fail(PURPLE_IS_CONTACT_INFO(contact));
 	g_return_if_fail(username != NULL);
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	g_free(priv->username);
 	priv->username = g_strdup(username);
@@ -450,25 +397,25 @@
 }
 
 const gchar *
-purple_contact_get_display_name(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_get_display_name(PurpleContactInfo *contact) {
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+	g_return_val_if_fail(PURPLE_IS_CONTACT_INFO(contact), NULL);
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	return priv->display_name;
 }
 
 void
-purple_contact_set_display_name(PurpleContact *contact,
-                                const gchar *display_name)
+purple_contact_info_set_display_name(PurpleContactInfo *contact,
+                                     const gchar *display_name)
 {
-	PurpleContactPrivate *priv = NULL;
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
+	g_return_if_fail(PURPLE_IS_CONTACT_INFO(contact));
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	g_free(priv->display_name);
 	priv->display_name = g_strdup(display_name);
@@ -477,23 +424,23 @@
 }
 
 const gchar *
-purple_contact_get_alias(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_get_alias(PurpleContactInfo *contact) {
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+	g_return_val_if_fail(PURPLE_IS_CONTACT_INFO(contact), NULL);
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	return priv->alias;
 }
 
 void
-purple_contact_set_alias(PurpleContact *contact, const gchar *alias) {
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_set_alias(PurpleContactInfo *contact, const gchar *alias) {
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
+	g_return_if_fail(PURPLE_IS_CONTACT_INFO(contact));
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	g_free(priv->alias);
 	priv->alias = g_strdup(alias);
@@ -502,23 +449,23 @@
 }
 
 GdkPixbuf *
-purple_contact_get_avatar(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_get_avatar(PurpleContactInfo *contact) {
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+	g_return_val_if_fail(PURPLE_IS_CONTACT_INFO(contact), NULL);
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	return priv->avatar;
 }
 
 void
-purple_contact_set_avatar(PurpleContact *contact, GdkPixbuf *avatar) {
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_set_avatar(PurpleContactInfo *contact, GdkPixbuf *avatar) {
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
+	g_return_if_fail(PURPLE_IS_CONTACT_INFO(contact));
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	if(g_set_object(&priv->avatar, avatar)) {
 		g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_AVATAR]);
@@ -526,34 +473,36 @@
 }
 
 PurplePresence *
-purple_contact_get_presence(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_get_presence(PurpleContactInfo *contact) {
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+	g_return_val_if_fail(PURPLE_IS_CONTACT_INFO(contact), NULL);
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	return priv->presence;
 }
 
 PurpleTags *
-purple_contact_get_tags(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_get_tags(PurpleContactInfo *contact) {
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+	g_return_val_if_fail(PURPLE_IS_CONTACT_INFO(contact), NULL);
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	return priv->tags;
 }
 
 void
-purple_contact_set_person(PurpleContact *contact, PurplePerson *person) {
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_set_person(PurpleContactInfo *contact,
+                               PurplePerson *person)
+{
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
+	g_return_if_fail(PURPLE_IS_CONTACT_INFO(contact));
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	if(g_set_object(&priv->person, person)) {
 		g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_PERSON]);
@@ -561,37 +510,37 @@
 }
 
 PurplePerson *
-purple_contact_get_person(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_get_person(PurpleContactInfo *contact) {
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+	g_return_val_if_fail(PURPLE_IS_CONTACT_INFO(contact), NULL);
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	return priv->person;
 }
 
-PurpleContactPermission
-purple_contact_get_permission(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
+PurpleContactInfoPermission
+purple_contact_info_get_permission(PurpleContactInfo *contact) {
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact),
-	                     PURPLE_CONTACT_PERMISSION_UNSET);
+	g_return_val_if_fail(PURPLE_IS_CONTACT_INFO(contact),
+	                     PURPLE_CONTACT_INFO_PERMISSION_UNSET);
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	return priv->permission;
 }
 
 void
-purple_contact_set_permission(PurpleContact *contact,
-                              PurpleContactPermission permission)
+purple_contact_info_set_permission(PurpleContactInfo *contact,
+                                   PurpleContactInfoPermission permission)
 {
-	PurpleContactPrivate *priv = NULL;
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
+	g_return_if_fail(PURPLE_IS_CONTACT_INFO(contact));
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	priv->permission = permission;
 
@@ -599,12 +548,12 @@
 }
 
 const char *
-purple_contact_get_name_for_display(PurpleContact *contact) {
-	PurpleContactPrivate *priv = NULL;
+purple_contact_info_get_name_for_display(PurpleContactInfo *contact) {
+	PurpleContactInfoPrivate *priv = NULL;
 
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+	g_return_val_if_fail(PURPLE_IS_CONTACT_INFO(contact), NULL);
 
-	priv = purple_contact_get_instance_private(contact);
+	priv = purple_contact_info_get_instance_private(contact);
 
 	/* If contact is associated with a PurplePerson that has an alias set,
 	 * return the alias of that PurplePerson.
@@ -637,7 +586,7 @@
 }
 
 int
-purple_contact_compare(PurpleContact *a, PurpleContact *b) {
+purple_contact_info_compare(PurpleContactInfo *a, PurpleContactInfo *b) {
 	PurplePerson *person_a = NULL;
 	PurplePerson *person_b = NULL;
 	const char *name_a = NULL;
@@ -653,8 +602,8 @@
 	}
 
 	/* Check if the contacts have persons associated with them. */
-	person_a = purple_contact_get_person(a);
-	person_b = purple_contact_get_person(b);
+	person_a = purple_contact_info_get_person(a);
+	person_b = purple_contact_info_get_person(b);
 
 	if(person_a != NULL && person_b == NULL) {
 		return -1;
@@ -663,8 +612,8 @@
 	}
 
 	/* Finally get the names for the displaying and compare those. */
-	name_a = purple_contact_get_name_for_display(a);
-	name_b = purple_contact_get_name_for_display(b);
+	name_a = purple_contact_info_get_name_for_display(a);
+	name_b = purple_contact_info_get_name_for_display(b);
 
 	return purple_utf8_strcasecmp(name_a, name_b);
 }
diff --git a/libpurple/purplecontactmanager.c b/libpurple/purplecontactmanager.c
--- a/libpurple/purplecontactmanager.c
+++ b/libpurple/purplecontactmanager.c
@@ -48,11 +48,13 @@
 {
 	PurpleContact *contact_a = (gpointer)a;
 	PurpleContact *contact_b = (gpointer)b;
+	PurpleContactInfo *info_a = PURPLE_CONTACT_INFO(contact_a);
+	PurpleContactInfo *info_b = PURPLE_CONTACT_INFO(contact_b);
 	const gchar *username_a = NULL;
 	const gchar *username_b = NULL;
 
-	username_a = purple_contact_get_username(contact_a);
-	username_b = purple_contact_get_username(contact_b);
+	username_a = purple_contact_info_get_username(info_a);
+	username_b = purple_contact_info_get_username(info_b);
 
 	return purple_strequal(username_a, username_b);
 }
@@ -64,8 +66,8 @@
 	const gchar *id_a = NULL;
 	const gchar *id_b = NULL;
 
-	id_a = purple_contact_get_id(contact_a);
-	id_b = purple_contact_get_id(contact_b);
+	id_a = purple_contact_info_get_id(PURPLE_CONTACT_INFO(contact_a));
+	id_b = purple_contact_info_get_id(PURPLE_CONTACT_INFO(contact_b));
 
 	return purple_strequal(id_a, id_b);
 }
@@ -260,8 +262,9 @@
 		added = TRUE;
 	} else {
 		if(g_list_store_find(contacts, contact, NULL)) {
-			const gchar *username = purple_contact_get_username(contact);
-			const gchar *id = purple_contact_get_id(contact);
+			PurpleContactInfo *info = PURPLE_CONTACT_INFO(contact);
+			const gchar *username = purple_contact_info_get_username(info);
+			const gchar *id = purple_contact_info_get_id(info);
 
 			g_warning("double add detected for contact %s:%s", id, username);
 
@@ -382,7 +385,7 @@
 	}
 
 	needle = purple_contact_new(account, NULL);
-	purple_contact_set_username(needle, username);
+	purple_contact_info_set_username(PURPLE_CONTACT_INFO(needle), username);
 	found = g_list_store_find_with_equal_func(contacts, needle,
 	                                          purple_contact_manager_find_with_username_helper,
 	                                          &position);
@@ -435,6 +438,7 @@
 {
 	PurpleAccount *account = NULL;
 	PurpleContact *contact = NULL;
+	PurpleContactInfo *info = NULL;
 	PurplePresence *buddy_presence = NULL;
 	PurplePresence *contact_presence = NULL;
 	const gchar *id = NULL;
@@ -446,6 +450,7 @@
 	account = purple_buddy_get_account(buddy);
 	id = purple_buddy_get_id(buddy);
 	contact = purple_contact_new(account, id);
+	info = PURPLE_CONTACT_INFO(contact);
 
 	/* Bind all of the properties. */
 	g_object_bind_property(buddy, "name", contact, "username",
@@ -456,7 +461,7 @@
 	                       G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
 
 	buddy_presence = purple_buddy_get_presence(buddy);
-	contact_presence = purple_contact_get_presence(contact);
+	contact_presence = purple_contact_info_get_presence(info);
 
 	g_object_bind_property(buddy_presence, "idle", contact_presence, "idle",
 	                       G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
diff --git a/libpurple/purpleperson.h b/libpurple/purpleperson.h
--- a/libpurple/purpleperson.h
+++ b/libpurple/purpleperson.h
@@ -35,13 +35,13 @@
 #define PURPLE_TYPE_PERSON (purple_person_get_type())
 G_DECLARE_FINAL_TYPE(PurplePerson, purple_person, PURPLE, PERSON, GObject)
 
-#include <libpurple/purplecontact.h>
+#include <libpurple/purplecontactinfo.h>
 
 /**
  * PurplePerson:
  *
- * A collection of [class@Purple.Contact] that contains a user selectable custom
- * avatar and alias.
+ * A collection of [class@Purple.ContactInfo] that contains a user selectable
+ * custom avatar and alias.
  *
  * Since: 3.0.0
  */
@@ -143,43 +143,42 @@
 /**
  * purple_person_add_contact:
  * @person: The instance.
- * @contact: The contact to add.
+ * @info: The [class@Purple.ContactInfo] to add.
  *
- * Adds @contact to @person.
+ * Adds @info to @person.
  *
  * Duplicate contacts are currently allowed, but that may change at a later
  * time.
  *
  * Since: 3.0.0
  */
-void purple_person_add_contact(PurplePerson *person, PurpleContact *contact);
+void purple_person_add_contact_info(PurplePerson *person, PurpleContactInfo *info);
 
 /**
- * purple_person_remove_contact:
+ * purple_person_remove_contact_info:
  * @person: The instance.
- * @contact: The contact to remove.
+ * @info: The [class@Purple.ContactInfo] to remove.
  *
- * Removes @contact from @person.
+ * Removes @info from @person.
  *
- * Returns: %TRUE if @contact was found and removed otherwise %FALSE.
+ * Returns: %TRUE if @info was found and removed otherwise %FALSE.
  *
  * Since: 3.0.0
  */
-gboolean purple_person_remove_contact(PurplePerson *person, PurpleContact *contact);
+gboolean purple_person_remove_contact_info(PurplePerson *person, PurpleContactInfo *info);
 
 /**
- * purple_person_get_priority_contact:
+ * purple_person_get_priority_contact_info:
  * @person: The instance.
  *
- * Gets the priority contact for @person. A priority contact is the one that is
- * the most available.
+ * Gets the contact info for the most available contact info in @person.
  *
  * Returns: (transfer none) (nullable): The priority contact or %NULL if
  *          @person does not have any contacts.
  *
  * Since: 3.0.0
  */
-PurpleContact *purple_person_get_priority_contact(PurplePerson *person);
+PurpleContactInfo *purple_person_get_priority_contact_info(PurplePerson *person);
 
 G_END_DECLS
 
diff --git a/libpurple/purpleperson.c b/libpurple/purpleperson.c
--- a/libpurple/purpleperson.c
+++ b/libpurple/purpleperson.c
@@ -36,7 +36,7 @@
 	PROP_ALIAS,
 	PROP_AVATAR,
 	PROP_TAGS,
-	PROP_PRIORITY_CONTACT,
+	PROP_PRIORITY_CONTACT_INFO,
 	N_PROPERTIES
 };
 static GParamSpec *properties[N_PROPERTIES] = {NULL, };
@@ -61,33 +61,33 @@
 
 static gint
 purple_person_contact_compare(gconstpointer a, gconstpointer b) {
-	PurpleContact *c1 = *(PurpleContact **)a;
-	PurpleContact *c2 = *(PurpleContact **)b;
+	PurpleContactInfo *c1 = *(PurpleContactInfo **)a;
+	PurpleContactInfo *c2 = *(PurpleContactInfo **)b;
 	PurplePresence *p1 = NULL;
 	PurplePresence *p2 = NULL;
 
-	p1 = purple_contact_get_presence(c1);
-	p2 = purple_contact_get_presence(c2);
+	p1 = purple_contact_info_get_presence(c1);
+	p2 = purple_contact_info_get_presence(c2);
 
 	return purple_presence_compare(p1, p2);
 }
 
 static void
 purple_person_sort_contacts(PurplePerson *person) {
-	PurpleContact *original_priority = NULL;
-	PurpleContact *new_priority = NULL;
+	PurpleContactInfo *original_priority = NULL;
+	PurpleContactInfo *new_priority = NULL;
 	guint n_items = person->contacts->len;
 
 	if(n_items <= 1) {
 		g_object_notify_by_pspec(G_OBJECT(person),
-		                         properties[PROP_PRIORITY_CONTACT]);
+		                         properties[PROP_PRIORITY_CONTACT_INFO]);
 
 		g_list_model_items_changed(G_LIST_MODEL(person), 0, n_items, n_items);
 
 		return;
 	}
 
-	original_priority = purple_person_get_priority_contact(person);
+	original_priority = purple_person_get_priority_contact_info(person);
 
 	g_ptr_array_sort(person->contacts, purple_person_contact_compare);
 
@@ -98,7 +98,7 @@
 	new_priority = g_ptr_array_index(person->contacts, 0);
 	if(original_priority != new_priority) {
 		g_object_notify_by_pspec(G_OBJECT(person),
-		                         properties[PROP_PRIORITY_CONTACT]);
+		                         properties[PROP_PRIORITY_CONTACT_INFO]);
 	}
 }
 
@@ -118,7 +118,7 @@
  *****************************************************************************/
 static GType
 purple_person_get_item_type(G_GNUC_UNUSED GListModel *list) {
-	return PURPLE_TYPE_CONTACT;
+	return PURPLE_TYPE_CONTACT_INFO;
 }
 
 static guint
@@ -131,7 +131,7 @@
 static gpointer
 purple_person_get_item(GListModel *list, guint position) {
 	PurplePerson *person = PURPLE_PERSON(list);
-	PurpleContact *contact = NULL;
+	PurpleContactInfo *contact = NULL;
 
 	if(position < person->contacts->len) {
 		contact = g_ptr_array_index(person->contacts, position);
@@ -174,9 +174,9 @@
 		case PROP_TAGS:
 			g_value_set_object(value, purple_person_get_tags(person));
 			break;
-		case PROP_PRIORITY_CONTACT:
+		case PROP_PRIORITY_CONTACT_INFO:
 			g_value_set_object(value,
-			                   purple_person_get_priority_contact(person));
+			                   purple_person_get_priority_contact_info(person));
 			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
@@ -322,10 +322,10 @@
 	 *
 	 * Since: 3.0.0
 	 */
-	properties[PROP_PRIORITY_CONTACT] = g_param_spec_object(
+	properties[PROP_PRIORITY_CONTACT_INFO] = g_param_spec_object(
 		"priority-contact", "priority-contact",
 		"The priority contact for the person",
-		PURPLE_TYPE_CONTACT,
+		PURPLE_TYPE_CONTACT_INFO,
 		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
 	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
@@ -387,30 +387,34 @@
 }
 
 void
-purple_person_add_contact(PurplePerson *person, PurpleContact *contact) {
+purple_person_add_contact_info(PurplePerson *person,
+                               PurpleContactInfo *contact)
+{
 	PurplePresence *presence = NULL;
 
 	g_return_if_fail(PURPLE_IS_PERSON(person));
-	g_return_if_fail(PURPLE_IS_CONTACT(contact));
+	g_return_if_fail(PURPLE_IS_CONTACT_INFO(contact));
 
 	g_ptr_array_add(person->contacts, g_object_ref(contact));
 
-	presence = purple_contact_get_presence(contact);
+	presence = purple_contact_info_get_presence(contact);
 	g_signal_connect_object(presence, "notify",
 	                        G_CALLBACK(purple_person_presence_notify_cb),
 	                        person, 0);
 
-	purple_contact_set_person(contact, person);
+	purple_contact_info_set_person(contact, person);
 
 	purple_person_sort_contacts(person);
 }
 
 gboolean
-purple_person_remove_contact(PurplePerson *person, PurpleContact *contact) {
+purple_person_remove_contact_info(PurplePerson *person,
+                                  PurpleContactInfo *contact)
+{
 	gboolean removed = FALSE;
 
 	g_return_val_if_fail(PURPLE_IS_PERSON(person), FALSE);
-	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), FALSE);
+	g_return_val_if_fail(PURPLE_IS_CONTACT_INFO(contact), FALSE);
 
 	/* Ref the contact to avoid a use-after free. */
 	g_object_ref(contact);
@@ -421,13 +425,13 @@
 	removed = g_ptr_array_remove(person->contacts, contact);
 
 	if(removed) {
-		PurplePresence *presence = purple_contact_get_presence(contact);
+		PurplePresence *presence = purple_contact_info_get_presence(contact);
 
 		g_signal_handlers_disconnect_by_func(presence,
 		                                     purple_person_presence_notify_cb,
 		                                     person);
 
-		purple_contact_set_person(contact, NULL);
+		purple_contact_info_set_person(contact, NULL);
 
 		purple_person_sort_contacts(person);
 	}
@@ -438,8 +442,8 @@
 	return removed;
 }
 
-PurpleContact *
-purple_person_get_priority_contact(PurplePerson *person) {
+PurpleContactInfo *
+purple_person_get_priority_contact_info(PurplePerson *person) {
 	g_return_val_if_fail(PURPLE_IS_PERSON(person), NULL);
 
 	if(person->contacts->len == 0) {
diff --git a/libpurple/tests/meson.build b/libpurple/tests/meson.build
--- a/libpurple/tests/meson.build
+++ b/libpurple/tests/meson.build
@@ -4,6 +4,7 @@
     'authorization_request',
     'circular_buffer',
     'contact',
+    'contact_info',
     'contact_manager',
     'credential_manager',
     'credential_provider',
diff --git a/libpurple/tests/test_contact.c b/libpurple/tests/test_contact.c
--- a/libpurple/tests/test_contact.c
+++ b/libpurple/tests/test_contact.c
@@ -29,12 +29,14 @@
 test_purple_contact_new(void) {
 	PurpleAccount *account = NULL;
 	PurpleContact *contact = NULL;
+	PurpleContactInfo *info = NULL;
 
 	account = purple_account_new("test", "test");
 	contact = purple_contact_new(account, "id");
+	info = PURPLE_CONTACT_INFO(contact);
 
 	g_assert_true(purple_contact_get_account(contact) == account);
-	g_assert_cmpstr(purple_contact_get_id(contact), ==, "id");
+	g_assert_cmpstr(purple_contact_info_get_id(info), ==, "id");
 
 	g_clear_object(&contact);
 	g_clear_object(&account);
@@ -45,21 +47,9 @@
 	PurpleAccount *account = NULL;
 	PurpleAccount *account1 = NULL;
 	PurpleContact *contact = NULL;
-	PurpleContactPermission permission;
-	PurplePerson *person = NULL;
-	PurplePerson *person1 = NULL;
-	PurplePresence *presence1 = NULL;
-	PurpleTags *tags = NULL;
-	GdkPixbuf *avatar = NULL;
-	GdkPixbuf *avatar1 = NULL;
-	gchar *id = NULL;
-	gchar *username = NULL;
-	gchar *display_name = NULL;
-	gchar *alias = NULL;
+	char *id = NULL;
 
 	account = purple_account_new("test", "test");
-	avatar = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, 1, 1);
-	person = purple_person_new();
 
 	/* Use g_object_new so we can test setting properties by name. All of them
 	 * call the setter methods, so by doing it this way we exercise more of the
@@ -69,280 +59,26 @@
 		PURPLE_TYPE_CONTACT,
 		"account", account,
 		"id", "id1",
-		"username", "username",
-		"display-name", "display-name",
-		"alias", "alias",
-		"avatar", avatar,
-		"person", person,
-		"permission", PURPLE_CONTACT_PERMISSION_ALLOW,
 		NULL);
 
 	/* Now use g_object_get to read all of the properties. */
 	g_object_get(contact,
 		"id", &id,
 		"account", &account1,
-		"username", &username,
-		"display-name", &display_name,
-		"alias", &alias,
-		"avatar", &avatar1,
-		"presence", &presence1,
-		"tags", &tags,
-		"person", &person1,
-		"permission", &permission,
 		NULL);
 
 	/* Compare all the things. */
 	g_assert_cmpstr(id, ==, "id1");
 	g_assert_true(account1 == account);
-	g_assert_cmpstr(username, ==, "username");
-	g_assert_cmpstr(display_name, ==, "display-name");
-	g_assert_cmpstr(alias, ==, "alias");
-	g_assert_true(avatar1 == avatar);
-	g_assert_nonnull(presence1);
-	g_assert_nonnull(tags);
-	g_assert_true(person1 == person);
-	g_assert_true(permission == PURPLE_CONTACT_PERMISSION_ALLOW);
 
 	/* Free/unref all the things. */
 	g_clear_pointer(&id, g_free);
 	g_clear_object(&account1);
-	g_clear_pointer(&username, g_free);
-	g_clear_pointer(&display_name, g_free);
-	g_clear_pointer(&alias, g_free);
-	g_clear_object(&avatar1);
-	g_clear_object(&presence1);
-	g_clear_object(&tags);
-	g_clear_object(&person);
-	g_clear_object(&person1);
-
-	g_clear_object(&avatar);
 	g_clear_object(&contact);
 	g_clear_object(&account);
 }
 
 /******************************************************************************
- * get_name_for_display tests
- *****************************************************************************/
-static void
-test_purple_contact_get_name_for_display_person_with_alias(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
-	PurplePerson *person = NULL;
-	const char *alias = NULL;
-
-	account = purple_account_new("test", "test");
-
-	person = purple_person_new();
-	purple_person_set_alias(person, "this is the alias");
-
-	contact = purple_contact_new(account, NULL);
-	purple_contact_set_person(contact, person);
-
-	alias = purple_contact_get_name_for_display(contact);
-	g_assert_cmpstr(alias, ==, "this is the alias");
-
-	g_clear_object(&account);
-	g_clear_object(&contact);
-	g_clear_object(&person);
-}
-
-static void
-test_purple_contact_get_name_for_display_contact_with_alias(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
-	PurplePerson *person = NULL;
-	const char *alias = NULL;
-
-	account = purple_account_new("test", "test");
-	person = purple_person_new();
-
-	contact = purple_contact_new(account, NULL);
-	purple_contact_set_person(contact, person);
-
-	purple_contact_set_alias(contact, "this is the alias");
-
-	alias = purple_contact_get_name_for_display(contact);
-	g_assert_cmpstr(alias, ==, "this is the alias");
-
-	g_clear_object(&account);
-	g_clear_object(&contact);
-	g_clear_object(&person);
-}
-
-static void
-test_purple_contact_get_name_for_display_contact_with_display_name(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
-	PurplePerson *person = NULL;
-	const char *alias = NULL;
-
-	account = purple_account_new("test", "test");
-	person = purple_person_new();
-
-	contact = purple_contact_new(account, NULL);
-	purple_contact_set_person(contact, person);
-
-	purple_contact_set_display_name(contact, "this is the display name");
-
-	alias = purple_contact_get_name_for_display(contact);
-	g_assert_cmpstr(alias, ==, "this is the display name");
-
-	g_clear_object(&account);
-	g_clear_object(&contact);
-	g_clear_object(&person);
-}
-
-static void
-test_purple_contact_get_name_for_display_username_fallback(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
-	PurplePerson *person = NULL;
-	const char *alias = NULL;
-
-	account = purple_account_new("test", "test");
-	person = purple_person_new();
-
-	contact = purple_contact_new(account, NULL);
-	purple_contact_set_username(contact, "username");
-	purple_contact_set_person(contact, person);
-
-	alias = purple_contact_get_name_for_display(contact);
-	g_assert_cmpstr(alias, ==, "username");
-
-	g_clear_object(&account);
-	g_clear_object(&contact);
-	g_clear_object(&person);
-}
-
-static void
-test_purple_contact_get_name_for_display_id_fallback(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
-	PurplePerson *person = NULL;
-	const char *alias = NULL;
-
-	account = purple_account_new("test", "test");
-	person = purple_person_new();
-
-	contact = purple_contact_new(account, "id");
-	purple_contact_set_person(contact, person);
-
-	alias = purple_contact_get_name_for_display(contact);
-	g_assert_cmpstr(alias, ==, "id");
-
-	g_clear_object(&account);
-	g_clear_object(&contact);
-	g_clear_object(&person);
-}
-
-/******************************************************************************
- * purple_contact_compare tests
- *****************************************************************************/
-static void
-test_purple_contact_compare_not_null__null(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
-
-	account = purple_account_new("test", "test");
-	contact = purple_contact_new(account, NULL);
-
-	g_assert_cmpint(purple_contact_compare(contact, NULL), <, 0);
-
-	g_clear_object(&account);
-	g_clear_object(&contact);
-}
-
-static void
-test_purple_contact_compare_null__not_null(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
-
-	account = purple_account_new("test", "test");
-	contact = purple_contact_new(account, NULL);
-
-	g_assert_cmpint(purple_contact_compare(NULL, contact), >, 0);
-
-	g_clear_object(&account);
-	g_clear_object(&contact);
-}
-
-static void
-test_purple_contact_compare_null__null(void) {
-	g_assert_cmpint(purple_contact_compare(NULL, NULL), ==, 0);
-}
-
-static void
-test_purple_contact_compare_person__no_person(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact_a = NULL;
-	PurpleContact *contact_b = NULL;
-	PurplePerson *person = NULL;
-
-	account = purple_account_new("test", "test");
-
-	contact_a = purple_contact_new(account, NULL);
-	person = purple_person_new();
-	purple_contact_set_person(contact_a, person);
-
-	contact_b = purple_contact_new(account, NULL);
-
-	g_assert_cmpint(purple_contact_compare(contact_a, contact_b), <, 0);
-
-	g_clear_object(&account);
-	g_clear_object(&contact_a);
-	g_clear_object(&contact_b);
-	g_clear_object(&person);
-}
-
-static void
-test_purple_contact_compare_no_person__person(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact_a = NULL;
-	PurpleContact *contact_b = NULL;
-	PurplePerson *person = NULL;
-
-	account = purple_account_new("test", "test");
-
-	contact_a = purple_contact_new(account, NULL);
-
-	contact_b = purple_contact_new(account, NULL);
-	person = purple_person_new();
-	purple_contact_set_person(contact_b, person);
-
-	g_assert_cmpint(purple_contact_compare(contact_a, contact_b), >, 0);
-
-	g_clear_object(&account);
-	g_clear_object(&contact_a);
-	g_clear_object(&contact_b);
-	g_clear_object(&person);
-}
-
-static void
-test_purple_contact_compare_name__name(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact_a = NULL;
-	PurpleContact *contact_b = NULL;
-
-	account = purple_account_new("test", "test");
-
-	contact_a = purple_contact_new(account, NULL);
-	purple_contact_set_username(contact_a, "aaa");
-
-	contact_b = purple_contact_new(account, NULL);
-	purple_contact_set_username(contact_b, "zzz");
-
-	g_assert_cmpint(purple_contact_compare(contact_a, contact_b), <, 0);
-	g_assert_cmpint(purple_contact_compare(contact_b, contact_a), >, 0);
-
-	purple_contact_set_username(contact_b, "aaa");
-	g_assert_cmpint(purple_contact_compare(contact_b, contact_a), ==, 0);
-
-	g_clear_object(&account);
-	g_clear_object(&contact_a);
-	g_clear_object(&contact_b);
-}
-
-/******************************************************************************
  * Main
  *****************************************************************************/
 gint
@@ -356,29 +92,5 @@
 	g_test_add_func("/contact/properties",
 	                test_purple_contact_properties);
 
-	g_test_add_func("/contact/get_name_for_display/person_with_alias",
-	                test_purple_contact_get_name_for_display_person_with_alias);
-	g_test_add_func("/contact/get_name_for_display/contact_with_alias",
-	                test_purple_contact_get_name_for_display_contact_with_alias);
-	g_test_add_func("/contact/get_name_for_display/contact_with_display_name",
-	                test_purple_contact_get_name_for_display_contact_with_display_name);
-	g_test_add_func("/contact/get_name_for_display/username_fallback",
-	                test_purple_contact_get_name_for_display_username_fallback);
-	g_test_add_func("/contact/get_name_for_display/id_fallback",
-	                test_purple_contact_get_name_for_display_id_fallback);
-
-	g_test_add_func("/contact/compare/not_null__null",
-	                test_purple_contact_compare_not_null__null);
-	g_test_add_func("/contact/compare/null__not_null",
-	                test_purple_contact_compare_null__not_null);
-	g_test_add_func("/contact/compare/null__null",
-	                test_purple_contact_compare_null__null);
-	g_test_add_func("/contact/compare/person__no_person",
-	                test_purple_contact_compare_person__no_person);
-	g_test_add_func("/contact/compare/no_person__person",
-	                test_purple_contact_compare_no_person__person);
-	g_test_add_func("/contact/compare/name__name",
-	                test_purple_contact_compare_name__name);
-
 	return g_test_run();
 }
diff --git a/libpurple/tests/test_contact.c b/libpurple/tests/test_contact_info.c
copy from libpurple/tests/test_contact.c
copy to libpurple/tests/test_contact_info.c
--- a/libpurple/tests/test_contact.c
+++ b/libpurple/tests/test_contact_info.c
@@ -26,26 +26,20 @@
  * Tests
  *****************************************************************************/
 static void
-test_purple_contact_new(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
+test_purple_contact_info_new(void) {
+	PurpleContactInfo *info = NULL;
 
-	account = purple_account_new("test", "test");
-	contact = purple_contact_new(account, "id");
+	info = purple_contact_info_new("id");
 
-	g_assert_true(purple_contact_get_account(contact) == account);
-	g_assert_cmpstr(purple_contact_get_id(contact), ==, "id");
+	g_assert_cmpstr(purple_contact_info_get_id(info), ==, "id");
 
-	g_clear_object(&contact);
-	g_clear_object(&account);
+	g_clear_object(&info);
 }
 
 static void
-test_purple_contact_properties(void) {
-	PurpleAccount *account = NULL;
-	PurpleAccount *account1 = NULL;
-	PurpleContact *contact = NULL;
-	PurpleContactPermission permission;
+test_purple_contact_info_properties(void) {
+	PurpleContactInfo *info = NULL;
+	PurpleContactInfoPermission permission;
 	PurplePerson *person = NULL;
 	PurplePerson *person1 = NULL;
 	PurplePresence *presence1 = NULL;
@@ -57,7 +51,6 @@
 	gchar *display_name = NULL;
 	gchar *alias = NULL;
 
-	account = purple_account_new("test", "test");
 	avatar = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, 1, 1);
 	person = purple_person_new();
 
@@ -65,22 +58,20 @@
 	 * call the setter methods, so by doing it this way we exercise more of the
 	 * code.
 	 */
-	contact = g_object_new(
-		PURPLE_TYPE_CONTACT,
-		"account", account,
+	info = g_object_new(
+		PURPLE_TYPE_CONTACT_INFO,
 		"id", "id1",
 		"username", "username",
 		"display-name", "display-name",
 		"alias", "alias",
 		"avatar", avatar,
 		"person", person,
-		"permission", PURPLE_CONTACT_PERMISSION_ALLOW,
+		"permission", PURPLE_CONTACT_INFO_PERMISSION_ALLOW,
 		NULL);
 
 	/* Now use g_object_get to read all of the properties. */
-	g_object_get(contact,
+	g_object_get(info,
 		"id", &id,
-		"account", &account1,
 		"username", &username,
 		"display-name", &display_name,
 		"alias", &alias,
@@ -93,7 +84,6 @@
 
 	/* Compare all the things. */
 	g_assert_cmpstr(id, ==, "id1");
-	g_assert_true(account1 == account);
 	g_assert_cmpstr(username, ==, "username");
 	g_assert_cmpstr(display_name, ==, "display-name");
 	g_assert_cmpstr(alias, ==, "alias");
@@ -101,11 +91,10 @@
 	g_assert_nonnull(presence1);
 	g_assert_nonnull(tags);
 	g_assert_true(person1 == person);
-	g_assert_true(permission == PURPLE_CONTACT_PERMISSION_ALLOW);
+	g_assert_true(permission == PURPLE_CONTACT_INFO_PERMISSION_ALLOW);
 
 	/* Free/unref all the things. */
 	g_clear_pointer(&id, g_free);
-	g_clear_object(&account1);
 	g_clear_pointer(&username, g_free);
 	g_clear_pointer(&display_name, g_free);
 	g_clear_pointer(&alias, g_free);
@@ -116,230 +105,195 @@
 	g_clear_object(&person1);
 
 	g_clear_object(&avatar);
-	g_clear_object(&contact);
-	g_clear_object(&account);
+	g_clear_object(&info);
 }
 
 /******************************************************************************
  * get_name_for_display tests
  *****************************************************************************/
 static void
-test_purple_contact_get_name_for_display_person_with_alias(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
+test_purple_contact_info_get_name_for_display_person_with_alias(void) {
+	PurpleContactInfo *info = NULL;
 	PurplePerson *person = NULL;
 	const char *alias = NULL;
 
-	account = purple_account_new("test", "test");
-
 	person = purple_person_new();
 	purple_person_set_alias(person, "this is the alias");
 
-	contact = purple_contact_new(account, NULL);
-	purple_contact_set_person(contact, person);
+	info = purple_contact_info_new(NULL);
+	purple_contact_info_set_person(info, person);
 
-	alias = purple_contact_get_name_for_display(contact);
+	alias = purple_contact_info_get_name_for_display(info);
 	g_assert_cmpstr(alias, ==, "this is the alias");
 
-	g_clear_object(&account);
-	g_clear_object(&contact);
+	g_clear_object(&info);
 	g_clear_object(&person);
 }
 
 static void
-test_purple_contact_get_name_for_display_contact_with_alias(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
+test_purple_contact_info_get_name_for_display_contact_info_with_alias(void) {
+	PurpleContactInfo *info = NULL;
 	PurplePerson *person = NULL;
 	const char *alias = NULL;
 
-	account = purple_account_new("test", "test");
 	person = purple_person_new();
 
-	contact = purple_contact_new(account, NULL);
-	purple_contact_set_person(contact, person);
+	info = purple_contact_info_new(NULL);
+	purple_contact_info_set_person(info, person);
 
-	purple_contact_set_alias(contact, "this is the alias");
+	purple_contact_info_set_alias(info, "this is the alias");
 
-	alias = purple_contact_get_name_for_display(contact);
+	alias = purple_contact_info_get_name_for_display(info);
 	g_assert_cmpstr(alias, ==, "this is the alias");
 
-	g_clear_object(&account);
-	g_clear_object(&contact);
+	g_clear_object(&info);
 	g_clear_object(&person);
 }
 
 static void
-test_purple_contact_get_name_for_display_contact_with_display_name(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
+test_purple_contact_info_get_name_for_display_contact_info_with_display_name(void) {
+	PurpleContactInfo *info = NULL;
 	PurplePerson *person = NULL;
 	const char *alias = NULL;
 
-	account = purple_account_new("test", "test");
 	person = purple_person_new();
 
-	contact = purple_contact_new(account, NULL);
-	purple_contact_set_person(contact, person);
+	info = purple_contact_info_new(NULL);
+	purple_contact_info_set_person(info, person);
 
-	purple_contact_set_display_name(contact, "this is the display name");
+	purple_contact_info_set_display_name(info, "this is the display name");
 
-	alias = purple_contact_get_name_for_display(contact);
+	alias = purple_contact_info_get_name_for_display(info);
 	g_assert_cmpstr(alias, ==, "this is the display name");
 
-	g_clear_object(&account);
-	g_clear_object(&contact);
+	g_clear_object(&info);
 	g_clear_object(&person);
 }
 
 static void
-test_purple_contact_get_name_for_display_username_fallback(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
+test_purple_contact_info_get_name_for_display_username_fallback(void) {
+	PurpleContactInfo *info = NULL;
 	PurplePerson *person = NULL;
 	const char *alias = NULL;
 
-	account = purple_account_new("test", "test");
 	person = purple_person_new();
 
-	contact = purple_contact_new(account, NULL);
-	purple_contact_set_username(contact, "username");
-	purple_contact_set_person(contact, person);
+	info = purple_contact_info_new(NULL);
+	purple_contact_info_set_username(info, "username");
+	purple_contact_info_set_person(info, person);
 
-	alias = purple_contact_get_name_for_display(contact);
+	alias = purple_contact_info_get_name_for_display(info);
 	g_assert_cmpstr(alias, ==, "username");
 
-	g_clear_object(&account);
-	g_clear_object(&contact);
+	g_clear_object(&info);
 	g_clear_object(&person);
 }
 
 static void
-test_purple_contact_get_name_for_display_id_fallback(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
+test_purple_contact_info_get_name_for_display_id_fallback(void) {
+	PurpleContactInfo *info = NULL;
 	PurplePerson *person = NULL;
 	const char *alias = NULL;
 
-	account = purple_account_new("test", "test");
 	person = purple_person_new();
 
-	contact = purple_contact_new(account, "id");
-	purple_contact_set_person(contact, person);
+	info = purple_contact_info_new("id");
+	purple_contact_info_set_person(info, person);
 
-	alias = purple_contact_get_name_for_display(contact);
+	alias = purple_contact_info_get_name_for_display(info);
 	g_assert_cmpstr(alias, ==, "id");
 
-	g_clear_object(&account);
-	g_clear_object(&contact);
+	g_clear_object(&info);
 	g_clear_object(&person);
 }
 
 /******************************************************************************
- * purple_contact_compare tests
+ * purple_contact_info_compare tests
  *****************************************************************************/
 static void
-test_purple_contact_compare_not_null__null(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
+test_purple_contact_info_compare_not_null__null(void) {
+	PurpleContactInfo *info = NULL;
 
-	account = purple_account_new("test", "test");
-	contact = purple_contact_new(account, NULL);
+	info = purple_contact_info_new(NULL);
 
-	g_assert_cmpint(purple_contact_compare(contact, NULL), <, 0);
+	g_assert_cmpint(purple_contact_info_compare(info, NULL), <, 0);
 
-	g_clear_object(&account);
-	g_clear_object(&contact);
+	g_clear_object(&info);
 }
 
 static void
-test_purple_contact_compare_null__not_null(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
+test_purple_contact_info_compare_null__not_null(void) {
+	PurpleContactInfo *info = NULL;
 
-	account = purple_account_new("test", "test");
-	contact = purple_contact_new(account, NULL);
+	info = purple_contact_info_new(NULL);
 
-	g_assert_cmpint(purple_contact_compare(NULL, contact), >, 0);
+	g_assert_cmpint(purple_contact_info_compare(NULL, info), >, 0);
 
-	g_clear_object(&account);
-	g_clear_object(&contact);
+	g_clear_object(&info);
 }
 
 static void
-test_purple_contact_compare_null__null(void) {
-	g_assert_cmpint(purple_contact_compare(NULL, NULL), ==, 0);
+test_purple_contact_info_compare_null__null(void) {
+	g_assert_cmpint(purple_contact_info_compare(NULL, NULL), ==, 0);
 }
 
 static void
-test_purple_contact_compare_person__no_person(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact_a = NULL;
-	PurpleContact *contact_b = NULL;
+test_purple_contact_info_compare_person__no_person(void) {
+	PurpleContactInfo *info_a = NULL;
+	PurpleContactInfo *info_b = NULL;
 	PurplePerson *person = NULL;
 
-	account = purple_account_new("test", "test");
-
-	contact_a = purple_contact_new(account, NULL);
+	info_a = purple_contact_info_new(NULL);
 	person = purple_person_new();
-	purple_contact_set_person(contact_a, person);
+	purple_contact_info_set_person(info_a, person);
 
-	contact_b = purple_contact_new(account, NULL);
-
-	g_assert_cmpint(purple_contact_compare(contact_a, contact_b), <, 0);
+	info_b = purple_contact_info_new(NULL);
 
-	g_clear_object(&account);
-	g_clear_object(&contact_a);
-	g_clear_object(&contact_b);
+	g_assert_cmpint(purple_contact_info_compare(info_a, info_b), <, 0);
+
+	g_clear_object(&info_a);
+	g_clear_object(&info_b);
 	g_clear_object(&person);
 }
 
 static void
-test_purple_contact_compare_no_person__person(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact_a = NULL;
-	PurpleContact *contact_b = NULL;
+test_purple_contact_info_compare_no_person__person(void) {
+	PurpleContactInfo *info_a = NULL;
+	PurpleContactInfo *info_b = NULL;
 	PurplePerson *person = NULL;
 
-	account = purple_account_new("test", "test");
+	info_a = purple_contact_info_new(NULL);
 
-	contact_a = purple_contact_new(account, NULL);
-
-	contact_b = purple_contact_new(account, NULL);
+	info_b = purple_contact_info_new(NULL);
 	person = purple_person_new();
-	purple_contact_set_person(contact_b, person);
-
-	g_assert_cmpint(purple_contact_compare(contact_a, contact_b), >, 0);
+	purple_contact_info_set_person(info_b, person);
 
-	g_clear_object(&account);
-	g_clear_object(&contact_a);
-	g_clear_object(&contact_b);
+	g_assert_cmpint(purple_contact_info_compare(info_a, info_b), >, 0);
+
+	g_clear_object(&info_a);
+	g_clear_object(&info_b);
 	g_clear_object(&person);
 }
 
 static void
-test_purple_contact_compare_name__name(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact_a = NULL;
-	PurpleContact *contact_b = NULL;
+test_purple_contact_info_compare_name__name(void) {
+	PurpleContactInfo *info_a = NULL;
+	PurpleContactInfo *info_b = NULL;
 
-	account = purple_account_new("test", "test");
-
-	contact_a = purple_contact_new(account, NULL);
-	purple_contact_set_username(contact_a, "aaa");
+	info_a = purple_contact_info_new(NULL);
+	purple_contact_info_set_username(info_a, "aaa");
 
-	contact_b = purple_contact_new(account, NULL);
-	purple_contact_set_username(contact_b, "zzz");
+	info_b = purple_contact_info_new(NULL);
+	purple_contact_info_set_username(info_b, "zzz");
 
-	g_assert_cmpint(purple_contact_compare(contact_a, contact_b), <, 0);
-	g_assert_cmpint(purple_contact_compare(contact_b, contact_a), >, 0);
+	g_assert_cmpint(purple_contact_info_compare(info_a, info_b), <, 0);
+	g_assert_cmpint(purple_contact_info_compare(info_b, info_a), >, 0);
 
-	purple_contact_set_username(contact_b, "aaa");
-	g_assert_cmpint(purple_contact_compare(contact_b, contact_a), ==, 0);
+	purple_contact_info_set_username(info_b, "aaa");
+	g_assert_cmpint(purple_contact_info_compare(info_b, info_a), ==, 0);
 
-	g_clear_object(&account);
-	g_clear_object(&contact_a);
-	g_clear_object(&contact_b);
+	g_clear_object(&info_a);
+	g_clear_object(&info_b);
 }
 
 /******************************************************************************
@@ -351,34 +305,34 @@
 
 	test_ui_purple_init();
 
-	g_test_add_func("/contact/new",
-	                test_purple_contact_new);
-	g_test_add_func("/contact/properties",
-	                test_purple_contact_properties);
+	g_test_add_func("/contact-info/new",
+	                test_purple_contact_info_new);
+	g_test_add_func("/contact-info/properties",
+	                test_purple_contact_info_properties);
 
-	g_test_add_func("/contact/get_name_for_display/person_with_alias",
-	                test_purple_contact_get_name_for_display_person_with_alias);
-	g_test_add_func("/contact/get_name_for_display/contact_with_alias",
-	                test_purple_contact_get_name_for_display_contact_with_alias);
-	g_test_add_func("/contact/get_name_for_display/contact_with_display_name",
-	                test_purple_contact_get_name_for_display_contact_with_display_name);
-	g_test_add_func("/contact/get_name_for_display/username_fallback",
-	                test_purple_contact_get_name_for_display_username_fallback);
-	g_test_add_func("/contact/get_name_for_display/id_fallback",
-	                test_purple_contact_get_name_for_display_id_fallback);
+	g_test_add_func("/contact-info/get_name_for_display/person_with_alias",
+	                test_purple_contact_info_get_name_for_display_person_with_alias);
+	g_test_add_func("/contact-info/get_name_for_display/contact_with_alias",
+	                test_purple_contact_info_get_name_for_display_contact_info_with_alias);
+	g_test_add_func("/contact-info/get_name_for_display/contact_with_display_name",
+	                test_purple_contact_info_get_name_for_display_contact_info_with_display_name);
+	g_test_add_func("/contact-info/get_name_for_display/username_fallback",
+	                test_purple_contact_info_get_name_for_display_username_fallback);
+	g_test_add_func("/contact-info/get_name_for_display/id_fallback",
+	                test_purple_contact_info_get_name_for_display_id_fallback);
 
-	g_test_add_func("/contact/compare/not_null__null",
-	                test_purple_contact_compare_not_null__null);
-	g_test_add_func("/contact/compare/null__not_null",
-	                test_purple_contact_compare_null__not_null);
-	g_test_add_func("/contact/compare/null__null",
-	                test_purple_contact_compare_null__null);
-	g_test_add_func("/contact/compare/person__no_person",
-	                test_purple_contact_compare_person__no_person);
-	g_test_add_func("/contact/compare/no_person__person",
-	                test_purple_contact_compare_no_person__person);
-	g_test_add_func("/contact/compare/name__name",
-	                test_purple_contact_compare_name__name);
+	g_test_add_func("/contact-info/compare/not_null__null",
+	                test_purple_contact_info_compare_not_null__null);
+	g_test_add_func("/contact-info/compare/null__not_null",
+	                test_purple_contact_info_compare_null__not_null);
+	g_test_add_func("/contact-info/compare/null__null",
+	                test_purple_contact_info_compare_null__null);
+	g_test_add_func("/contact-info/compare/person__no_person",
+	                test_purple_contact_info_compare_person__no_person);
+	g_test_add_func("/contact-info/compare/no_person__person",
+	                test_purple_contact_info_compare_no_person__person);
+	g_test_add_func("/contact-info/compare/name__name",
+	                test_purple_contact_info_compare_name__name);
 
 	return g_test_run();
 }
diff --git a/libpurple/tests/test_contact_manager.c b/libpurple/tests/test_contact_manager.c
--- a/libpurple/tests/test_contact_manager.c
+++ b/libpurple/tests/test_contact_manager.c
@@ -199,11 +199,11 @@
 	account = purple_account_new("test", "test");
 
 	contact1 = purple_contact_new(account, NULL);
-	purple_contact_set_username(contact1, "user1");
+	purple_contact_info_set_username(PURPLE_CONTACT_INFO(contact1), "user1");
 	purple_contact_manager_add(manager, contact1);
 
 	contact2 = purple_contact_new(account, NULL);
-	purple_contact_set_username(contact2, "user2");
+	purple_contact_info_set_username(PURPLE_CONTACT_INFO(contact2), "user2");
 	purple_contact_manager_add(manager, contact2);
 
 	found = purple_contact_manager_find_with_username(manager, account,
@@ -265,6 +265,7 @@
 	PurpleAccount *account = NULL;
 	PurpleBuddy *buddy = NULL;
 	PurpleContact *contact = NULL;
+	PurpleContactInfo *info = NULL;
 	PurpleContactManager *manager = NULL;
 	PurpleStatusType *type = NULL;
 	GList *statuses = NULL;
@@ -298,15 +299,17 @@
 	g_assert_nonnull(contact);
 	g_assert_true(PURPLE_IS_CONTACT(contact));
 
+	info = PURPLE_CONTACT_INFO(contact);
+
 	/* Now check the alias and display name to make sure they were synced as
 	 * well.
 	 */
 	source = purple_buddy_get_local_alias(buddy);
-	destination = purple_contact_get_alias(contact);
+	destination = purple_contact_info_get_alias(info);
 	g_assert_cmpstr(destination, ==, source);
 
 	source = purple_buddy_get_server_alias(buddy);
-	destination = purple_contact_get_display_name(contact);
+	destination = purple_contact_info_get_display_name(info);
 	g_assert_cmpstr(destination, ==, source);
 
 	/* Now let's change the settings in the buddy and verify they made it to the
@@ -319,16 +322,16 @@
 	*/
 
 	purple_buddy_set_local_alias(buddy, "guy-alias");
-	g_assert_cmpstr(purple_contact_get_alias(contact), ==, "guy-alias");
+	g_assert_cmpstr(purple_contact_info_get_alias(info), ==, "guy-alias");
 
 	purple_buddy_set_server_alias(buddy, "server-guy");
-	g_assert_cmpstr(purple_contact_get_display_name(contact), ==,
+	g_assert_cmpstr(purple_contact_info_get_display_name(info), ==,
 	                "server-guy");
 
-	purple_contact_set_alias(contact, "friend-alias");
+	purple_contact_info_set_alias(info, "friend-alias");
 	g_assert_cmpstr(purple_buddy_get_local_alias(buddy), ==, "friend-alias");
 
-	purple_contact_set_display_name(contact, "server-friend");
+	purple_contact_info_set_display_name(info, "server-friend");
 	g_assert_cmpstr(purple_buddy_get_server_alias(buddy), ==, "server-friend");
 
 	/* We can't verify the presences changes because PurpleBuddy has to be in
diff --git a/libpurple/tests/test_person.c b/libpurple/tests/test_person.c
--- a/libpurple/tests/test_person.c
+++ b/libpurple/tests/test_person.c
@@ -109,63 +109,58 @@
 
 static void
 test_purple_person_contacts_single(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
+	PurpleContactInfo *info = NULL;
 	PurplePerson *person = NULL;
 	PurplePerson *person1 = NULL;
 	guint n_items = 0;
 	gboolean removed = FALSE;
 	gboolean changed = FALSE;
 
-	account = purple_account_new("test", "test");
-	contact = purple_contact_new(account, "username");
+	info = purple_contact_info_new("id");
 	person = purple_person_new();
 	g_signal_connect(person, "items-changed",
 	                 G_CALLBACK(test_purple_person_items_changed_cb), &changed);
 
 	n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
 	g_assert_cmpuint(n_items, ==, 0);
-	purple_person_add_contact(person, contact);
+	purple_person_add_contact_info(person, info);
 	n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
 	g_assert_cmpuint(n_items, ==, 1);
 	g_assert_true(changed);
 
-	person1 = purple_contact_get_person(contact);
+	person1 = purple_contact_info_get_person(info);
 	g_assert_true(person1 == person);
 
 	changed = FALSE;
 
-	removed = purple_person_remove_contact(person, contact);
+	removed = purple_person_remove_contact_info(person, info);
 	g_assert_true(removed);
 	n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
 	g_assert_cmpuint(n_items, ==, 0);
 	g_assert_true(changed);
 
-	person1 = purple_contact_get_person(contact);
+	person1 = purple_contact_info_get_person(info);
 	g_assert_null(person1);
 
 	g_clear_object(&person);
-	g_clear_object(&account);
-	g_clear_object(&contact);
+	g_clear_object(&info);
 }
 
 static void
 test_purple_person_contacts_multiple(void) {
-	PurpleAccount *account = NULL;
 	PurplePerson *person = NULL;
-	GPtrArray *contacts = NULL;
+	GPtrArray *infos = NULL;
 	guint n_items = 0;
-	const gint n_contacts = 5;
+	const gint n_infos = 5;
 	gboolean changed = FALSE;
 
-	account = purple_account_new("test", "test");
 	person = purple_person_new();
 	g_signal_connect(person, "items-changed",
 	                 G_CALLBACK(test_purple_person_items_changed_cb), &changed);
 
-	contacts = g_ptr_array_new_full(n_contacts, g_object_unref);
-	for(gint i = 0; i < n_contacts; i++) {
-		PurpleContact *contact = NULL;
+	infos = g_ptr_array_new_full(n_infos, g_object_unref);
+	for(gint i = 0; i < n_infos; i++) {
+		PurpleContactInfo *info = NULL;
 		gchar *username = NULL;
 
 		changed = FALSE;
@@ -174,35 +169,36 @@
 		g_assert_cmpuint(n_items, ==, i);
 
 		username = g_strdup_printf("username%d", i);
-		contact = purple_contact_new(account, username);
+		info = purple_contact_info_new(NULL);
+		purple_contact_info_set_username(info, username);
 		g_free(username);
 
-		/* Add the contact to the ptr array so we can remove it below. */
-		g_ptr_array_add(contacts, contact);
+		/* Add the contact info to the ptr array so we can remove it below. */
+		g_ptr_array_add(infos, info);
 
-		/* Add the contact to the person and make sure that all the magic
+		/* Add the contact info to the person and make sure that all the magic
 		 * happened.
 		 */
-		purple_person_add_contact(person, contact);
+		purple_person_add_contact_info(person, info);
 		n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
 		g_assert_cmpuint(n_items, ==, i + 1);
 		g_assert_true(changed);
 	}
 
-	for(gint i = 0; i < n_contacts; i++) {
-		PurpleContact *contact = contacts->pdata[i];
+	for(gint i = 0; i < n_infos; i++) {
+		PurpleContactInfo *info = g_ptr_array_index(infos, i);
 		gboolean removed = FALSE;
 
 		changed = FALSE;
 
 		n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
-		g_assert_cmpuint(n_items, ==, n_contacts - i);
+		g_assert_cmpuint(n_items, ==, n_infos - i);
 
-		removed = purple_person_remove_contact(person, contact);
+		removed = purple_person_remove_contact_info(person, info);
 		g_assert_true(removed);
 
 		n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
-		g_assert_cmpuint(n_items, ==, n_contacts - (i + 1));
+		g_assert_cmpuint(n_items, ==, n_infos - (i + 1));
 
 		g_assert_true(changed);
 	}
@@ -211,37 +207,33 @@
 	n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
 	g_assert_cmpuint(n_items, ==, 0);
 
-	g_ptr_array_free(contacts, TRUE);
+	g_ptr_array_free(infos, TRUE);
 
 	g_clear_object(&person);
-	g_clear_object(&account);
 }
 
 static void
 test_purple_person_priority_single(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
-	PurpleContact *priority = NULL;
+	PurpleContactInfo *info = NULL;
+	PurpleContactInfo *priority = NULL;
 	PurplePerson *person = NULL;
 	PurplePresence *presence = NULL;
 	PurpleStatus *status = NULL;
 	PurpleStatusType *status_type = NULL;
 	gboolean called = FALSE;
 
-	account = purple_account_new("test", "test");
-
 	person = purple_person_new();
 	g_signal_connect(person, "notify::priority-contact",
 	                 G_CALLBACK(test_purple_person_notify_cb), &called);
-	priority = purple_person_get_priority_contact(person);
+	priority = purple_person_get_priority_contact_info(person);
 	g_assert_null(priority);
 
 	/* Now create a real contact. */
-	contact = purple_contact_new(account, "username");
-	purple_person_add_contact(person, contact);
+	info = purple_contact_info_new(NULL);
+	purple_person_add_contact_info(person, info);
 
 	/* Set the status of the contact. */
-	presence = purple_contact_get_presence(contact);
+	presence = purple_contact_info_get_presence(info);
 	status_type = purple_status_type_new(PURPLE_STATUS_AVAILABLE, "available",
 	                                     "Available", FALSE);
 	status = purple_status_new(status_type, presence);
@@ -250,40 +242,37 @@
 
 	g_assert_true(called);
 
-	priority = purple_person_get_priority_contact(person);
-	g_assert_true(priority == contact);
+	priority = purple_person_get_priority_contact_info(person);
+	g_assert_true(priority == info);
 
 	purple_status_type_destroy(status_type);
-	g_clear_object(&account);
 	g_clear_object(&person);
-	g_clear_object(&contact);
+	g_clear_object(&info);
 	g_clear_object(&presence);
 }
 
 static void
 test_purple_person_priority_multiple_with_change(void) {
-	PurpleAccount *account = NULL;
-	PurpleContact *priority = NULL;
-	PurpleContact *first = NULL;
-	PurpleContact *sorted_contact = NULL;
+	PurpleContactInfo *priority = NULL;
+	PurpleContactInfo *first = NULL;
+	PurpleContactInfo *sorted_contact = NULL;
 	PurplePerson *person = NULL;
 	PurplePresence *sorted_presence = NULL;
 	PurpleStatus *status = NULL;
 	PurpleStatusType *available = NULL;
 	PurpleStatusType *offline = NULL;
 	gboolean changed = FALSE;
-	gint n_contacts = 5;
+	gint n_infos = 5;
 	guint n_items = 0;
 
-	/* This unit test is a bit complicated, but it adds 5 contacts to a person
-	 * all whose presences are set to offline. After adding all the contacts,
-	 * we verify that the first contact we added is the priority contact. Then
-	 * we flip the active status of the n_contacts - 2 contact to available.
-	 * This should make it the priority contact which we then assert.
+	/* This unit test is a bit complicated, but it adds 5 contact infos to a
+	 * person all whose presences are set to offline. After adding all the
+	 * contact infos, we verify that the first contact info we added is the
+	 * priority contact info. Then we flip the active status of the n_infos - 2
+	 * infos to available. This should make it the priority contact info which
+	 * we then assert.
 	 */
 
-	account = purple_account_new("test", "test");
-
 	/* Create our status types. */
 	available = purple_status_type_new(PURPLE_STATUS_AVAILABLE, "available",
 	                                   "Available", FALSE);
@@ -296,12 +285,12 @@
 	person = purple_person_new();
 	g_signal_connect(person, "notify::priority-contact",
 	                 G_CALLBACK(test_purple_person_notify_cb), &changed);
-	priority = purple_person_get_priority_contact(person);
+	priority = purple_person_get_priority_contact_info(person);
 	g_assert_null(priority);
 
-	/* Create and add all contacts. */
-	for(gint i = 0; i < n_contacts; i++) {
-		PurpleContact *contact = NULL;
+	/* Create and add all contact infos. */
+	for(gint i = 0; i < n_infos; i++) {
+		PurpleContactInfo *info = NULL;
 		PurplePresence *presence = NULL;
 		gchar *username = NULL;
 
@@ -310,48 +299,49 @@
 
 		/* Now create a real contact. */
 		username = g_strdup_printf("username%d", i + 1);
-		contact = purple_contact_new(account, username);
+		info = purple_contact_info_new(NULL);
+		purple_contact_info_set_username(info, username);
 		g_free(username);
 
 		/* Set the status for the contact. */
-		presence = purple_contact_get_presence(contact);
+		presence = purple_contact_info_get_presence(info);
 		status = purple_status_new(offline, presence);
 		g_object_set(G_OBJECT(presence), "active-status", status, NULL);
 		g_clear_object(&status);
 
-		purple_person_add_contact(person, contact);
+		purple_person_add_contact_info(person, info);
 
 		if(i == 0) {
-			first = g_object_ref(contact);
+			first = g_object_ref(info);
 			g_assert_true(changed);
 		} else {
 			g_assert_false(changed);
 
-			if(i == n_contacts - 2) {
-				sorted_contact = g_object_ref(contact);
+			if(i == n_infos - 2) {
+				sorted_contact = g_object_ref(info);
 				sorted_presence = g_object_ref(presence);
 			}
 		}
 
-		g_clear_object(&contact);
+		g_clear_object(&info);
 	}
 
 	n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
-	g_assert_cmpuint(n_items, ==, n_contacts);
+	g_assert_cmpuint(n_items, ==, n_infos);
 
-	priority = purple_person_get_priority_contact(person);
+	priority = purple_person_get_priority_contact_info(person);
 	g_assert_true(priority == first);
 	g_clear_object(&first);
 
-	/* Now set the second from the last contact's status to available, and
-	 * verify that that contact is now the priority contact.
+	/* Now set the second from the last contact info's status to available, and
+	 * verify that that contact info is now the priority contact info.
 	 */
 	changed = FALSE;
 	status = purple_status_new(available, sorted_presence);
 	g_object_set(G_OBJECT(sorted_presence), "active-status", status, NULL);
 	g_clear_object(&status);
 	g_assert_true(changed);
-	priority = purple_person_get_priority_contact(person);
+	priority = purple_person_get_priority_contact_info(person);
 	g_assert_true(priority == sorted_contact);
 
 	/* Cleanup. */
@@ -361,7 +351,6 @@
 	g_clear_object(&sorted_contact);
 	g_clear_object(&sorted_presence);
 
-	g_clear_object(&account);
 	g_clear_object(&person);
 }
 
