diff --git a/libpurple/purplecontact.h b/libpurple/purplecontact.h
--- a/libpurple/purplecontact.h
+++ b/libpurple/purplecontact.h
@@ -299,6 +299,42 @@
  */
 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: -1 if @a should be sorted before @b, 0 if they sorted equally, and
+ *          1 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 */
# HG changeset patch
# Node ID 8567a1b6f55a
# Parent  6182863475ee
diff --git a/libpurple/purplecontact.c b/libpurple/purplecontact.c
--- a/libpurple/purplecontact.c
+++ b/libpurple/purplecontact.c
@@ -19,6 +19,7 @@
 #include "purplecontact.h"
 
 #include "purpleenums.h"
+#include "util.h"
 
 struct _PurpleContact {
 	GObject parent;
@@ -502,3 +503,70 @@
 
 	g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_PERMISSION]);
 }
+
+const char *
+purple_contact_get_name_for_display(PurpleContact *contact) {
+	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+
+	/* If contact is associated with a PurplePerson that has an alias set,
+	 * return the alias of that PurplePerson.
+	 */
+	if(contact->person != NULL) {
+		const char *alias = purple_person_get_alias(contact->person);
+
+		if(alias != NULL && alias[0] != '\0') {
+			return alias;
+		}
+	}
+
+	/* If the purple user set an alias for the contact, return that. */
+	if(contact->alias != NULL && contact->alias[0] != '\0') {
+		return contact->alias;
+	}
+
+	/* If the contact has a display name set, return that. */
+	if(contact->display_name != NULL && contact->display_name[0] != '\0') {
+		return contact->display_name;
+	}
+
+	/* Fallback to the username if that is set. */
+	if(contact->username != NULL && contact->username[0] != '\0') {
+		return contact->username;
+	}
+
+	/* Finally, in a last ditch effort, return the id of the contact. */
+	return contact->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/tests/test_contact.c b/libpurple/tests/test_contact.c
--- a/libpurple/tests/test_contact.c
+++ b/libpurple/tests/test_contact.c
@@ -121,6 +121,228 @@
 }
 
 /******************************************************************************
+ * 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), ==, -1);
+
+	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), ==, 1);
+
+	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), ==, -1);
+
+	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), ==, 1);
+
+	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), ==, -1);
+	g_assert_cmpint(purple_contact_compare(contact_b, contact_a), ==, 1);
+
+	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
@@ -134,5 +356,29 @@
 	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();
 }
