diff --git a/libpurple/purplecontactinfo.h b/libpurple/purplecontactinfo.h
--- a/libpurple/purplecontactinfo.h
+++ b/libpurple/purplecontactinfo.h
@@ -420,6 +420,29 @@
 void purple_contact_info_set_permission(PurpleContactInfo *info, PurpleContactInfoPermission permission);
 
 /**
+ * purple_contact_info_get_sid:
+ * @info: The instance.
+ *
+ * Gets the sid, or secondary id, of @info.
+ *
+ * Returns: (transfer none) (nullable): The sid if set.
+ *
+ * Since: 3.0.0
+ */
+const char *purple_contact_info_get_sid(PurpleContactInfo *info);
+
+/**
+ * purple_contact_info_set_sid:
+ * @info: The instance.
+ * @sid: (nullable): The sid or secondary id.
+ *
+ * Sets the sid, or secondary id, of @info to @sid.
+ *
+ * Since: 3.0.0
+ */
+void purple_contact_info_set_sid(PurpleContactInfo *info, const char *sid);
+
+/**
  * purple_contact_info_get_name_for_display:
  * @info: The instance.
  *
# HG changeset patch
# Node ID 10deb0c84811
# Parent  8a8e85e9e114
diff --git a/libpurple/purplecontactinfo.c b/libpurple/purplecontactinfo.c
--- a/libpurple/purplecontactinfo.c
+++ b/libpurple/purplecontactinfo.c
@@ -32,6 +32,7 @@
 	char *phone_number;
 	GTimeZone *time_zone;
 	char *note;
+	char *sid;
 
 	char *name_for_display;
 
@@ -62,6 +63,7 @@
 	PROP_TAGS,
 	PROP_PERSON,
 	PROP_PERMISSION,
+	PROP_SID,
 	PROP_NAME_FOR_DISPLAY,
 	N_PROPERTIES
 };
@@ -211,6 +213,9 @@
 			g_value_set_string(value,
 			                   purple_contact_info_get_name_for_display(info));
 			break;
+		case PROP_SID:
+			g_value_set_string(value, purple_contact_info_get_sid(info));
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
 			break;
@@ -262,6 +267,9 @@
 		case PROP_PERMISSION:
 			purple_contact_info_set_permission(info, g_value_get_enum(value));
 			break;
+		case PROP_SID:
+			purple_contact_info_set_sid(info, g_value_get_string(value));
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
 			break;
@@ -299,6 +307,7 @@
 	g_clear_pointer(&priv->phone_number, g_free);
 	g_clear_pointer(&priv->time_zone, g_time_zone_unref);
 	g_clear_pointer(&priv->note, g_free);
+	g_clear_pointer(&priv->sid, g_free);
 	g_clear_pointer(&priv->name_for_display, g_free);
 
 	G_OBJECT_CLASS(purple_contact_info_parent_class)->finalize(obj);
@@ -542,6 +551,23 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
+	 * PurpleContactInfo:sid:
+	 *
+	 * The sid, or secondary id, is an additional identifier field for a
+	 * contact.
+	 *
+	 * This could be used to hold the `ident` for for an IRC contact, the
+	 * `resource` for an XMPP contact, or something similar.
+	 *
+	 * Since: 3.0.0
+	 */
+	properties[PROP_SID] = g_param_spec_string(
+		"sid", "sid",
+		"The secondary id for the contact.",
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	/**
 	 * PurpleContactInfo:name-for-display:
 	 *
 	 * The name that the user interface should display for this contact info.
@@ -1021,6 +1047,33 @@
 }
 
 const char *
+purple_contact_info_get_sid(PurpleContactInfo *info) {
+	PurpleContactInfoPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_CONTACT_INFO(info), NULL);
+
+	priv = purple_contact_info_get_instance_private(info);
+
+	return priv->sid;
+}
+
+void
+purple_contact_info_set_sid(PurpleContactInfo *info, const char *sid) {
+	PurpleContactInfoPrivate *priv = NULL;
+
+	g_return_if_fail(PURPLE_IS_CONTACT_INFO(info));
+
+	priv = purple_contact_info_get_instance_private(info);
+
+	if(!purple_strequal(priv->sid, sid)) {
+		g_free(priv->sid);
+		priv->sid = g_strdup(sid);
+
+		g_object_notify_by_pspec(G_OBJECT(info), properties[PROP_SID]);
+	}
+}
+
+const char *
 purple_contact_info_get_name_for_display(PurpleContactInfo *info) {
 	PurpleContactInfoPrivate *priv = NULL;
 
diff --git a/libpurple/purpleconversation.c b/libpurple/purpleconversation.c
--- a/libpurple/purpleconversation.c
+++ b/libpurple/purpleconversation.c
@@ -83,7 +83,9 @@
 static GParamSpec *properties[N_PROPERTIES] = { NULL, };
 
 enum {
+	SIG_MEMBER_ADDING,
 	SIG_MEMBER_ADDED,
+	SIG_MEMBER_REMOVING,
 	SIG_MEMBER_REMOVED,
 	N_SIGNALS,
 };
diff --git a/libpurple/tests/test_contact_info.c b/libpurple/tests/test_contact_info.c
--- a/libpurple/tests/test_contact_info.c
+++ b/libpurple/tests/test_contact_info.c
@@ -56,6 +56,7 @@
 	char *email = NULL;
 	char *phone_number = NULL;
 	char *note = NULL;
+	char *sid = NULL;
 	char *name_for_display = NULL;
 
 	avatar = g_object_new(PURPLE_TYPE_AVATAR, NULL);
@@ -81,6 +82,7 @@
 		"avatar", avatar,
 		"person", person,
 		"permission", PURPLE_CONTACT_INFO_PERMISSION_ALLOW,
+		"sid", "sid",
 		NULL);
 
 	/* Now use g_object_get to read all of the properties. */
@@ -99,6 +101,7 @@
 		"tags", &tags,
 		"person", &person1,
 		"permission", &permission,
+		"sid", &sid,
 		"name-for-display", &name_for_display,
 		NULL);
 
@@ -119,6 +122,7 @@
 	g_assert_nonnull(tags);
 	g_assert_true(person1 == person);
 	g_assert_true(permission == PURPLE_CONTACT_INFO_PERMISSION_ALLOW);
+	g_assert_cmpstr(sid, ==, "sid");
 
 	/* Free/unref all the things. */
 	g_clear_pointer(&id, g_free);
@@ -131,6 +135,7 @@
 	g_clear_pointer(&time_zone, g_time_zone_unref);
 	g_clear_pointer(&note, g_free);
 	g_clear_pointer(&name_for_display, g_free);
+	g_clear_pointer(&sid, g_free);
 	g_clear_object(&avatar1);
 	g_clear_object(&presence1);
 	g_clear_object(&tags);
