# HG changeset patch
# Node ID 189d53b309f2e62f977e902317b085b2917792e5
# Parent  fac24c225f6ea4b6192ffcc6131e6868fb7c3a45
diff --git a/libpurple/purpleprotocolconversation.c b/libpurple/purpleprotocolconversation.c
--- a/libpurple/purpleprotocolconversation.c
+++ b/libpurple/purpleprotocolconversation.c
@@ -499,3 +499,36 @@
 		          G_OBJECT_TYPE_NAME(protocol));
 	}
 }
+
+gboolean
+purple_protocol_conversation_implements_refresh(PurpleProtocolConversation *protocol)
+{
+	PurpleProtocolConversationInterface *iface = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_PROTOCOL_CONVERSATION(protocol), FALSE);
+
+	iface = PURPLE_PROTOCOL_CONVERSATION_GET_IFACE(protocol);
+	if(iface->refresh != NULL) {
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+void
+purple_protocol_conversation_refresh(PurpleProtocolConversation *protocol,
+                                     PurpleConversation *conversation)
+{
+	PurpleProtocolConversationInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_CONVERSATION(protocol));
+	g_return_if_fail(PURPLE_IS_CONVERSATION(conversation));
+
+	iface = PURPLE_PROTOCOL_CONVERSATION_GET_IFACE(protocol);
+	if(iface->refresh != NULL) {
+		iface->refresh(protocol, conversation);
+	} else {
+		g_warning("%s does not implement refresh",
+		          G_OBJECT_TYPE_NAME(protocol));
+	}
+}
diff --git a/libpurple/purpleprotocolconversation.h b/libpurple/purpleprotocolconversation.h
--- a/libpurple/purpleprotocolconversation.h
+++ b/libpurple/purpleprotocolconversation.h
@@ -95,6 +95,8 @@
 
 	void (*send_typing)(PurpleProtocolConversation *protocol, PurpleConversation *conversation, PurpleTypingState state);
 
+	void (*refresh)(PurpleProtocolConversation *protocol, PurpleConversation *conversation);
+
 	/*< private >*/
 	gpointer reserved[8];
 };
@@ -446,6 +448,36 @@
 PURPLE_AVAILABLE_IN_3_0
 void purple_protocol_conversation_send_typing(PurpleProtocolConversation *protocol, PurpleConversation *conversation, PurpleTypingState state);
 
+/**
+ * purple_protocol_conversation_implements_refresh:
+ *
+ * Checks if @protocol implements [vfunc@ProtocolConversation.refresh].
+ *
+ * Returns: true if everything is implemented, otherwise false.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+gboolean purple_protocol_conversation_implements_refresh(PurpleProtocolConversation *protocol);
+
+/**
+ * purple_protocol_conversation_refresh:
+ * @conversation: the conversation
+ *
+ * Asks the protocol to refresh a conversation.
+ *
+ * A conversation could need to be refreshed for any number of reasons, but the
+ * primary case is to help restore conversations when user interfaces restart.
+ *
+ * This allows the user interface to recreate a conversation and then have the
+ * protocol do whatever is necessary to bring the conversation back up to date
+ * and online.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+void purple_protocol_conversation_refresh(PurpleProtocolConversation *protocol, PurpleConversation *conversation);
+
 G_END_DECLS
 
 #endif /* PURPLE_PROTOCOL_CONVERSATION_H */
diff --git a/libpurple/tests/test_protocol_conversation.c b/libpurple/tests/test_protocol_conversation.c
--- a/libpurple/tests/test_protocol_conversation.c
+++ b/libpurple/tests/test_protocol_conversation.c
@@ -458,6 +458,45 @@
 	g_test_trap_assert_stderr("*Purple-WARNING*TestPurpleProtocolConversationEmpty*send_typing*");
 }
 
+static void
+test_purple_protocol_conversation_empty_implements_refresh(void) {
+	PurpleProtocolConversation *protocol = NULL;
+
+	protocol = g_object_new(test_purple_protocol_conversation_empty_get_type(),
+	                        NULL);
+
+	g_assert_false(purple_protocol_conversation_implements_refresh(protocol));
+
+	g_assert_finalize_object(protocol);
+}
+
+static void
+test_purple_protocol_conversation_empty_refresh(void) {
+	if(g_test_subprocess()) {
+		PurpleAccount *account = NULL;
+		PurpleConversation *conversation = NULL;
+		PurpleProtocolConversation *protocol = NULL;
+
+		protocol = g_object_new(test_purple_protocol_conversation_empty_get_type(),
+		                        NULL);
+		account = purple_account_new("test", "test");
+		conversation = g_object_new(
+			PURPLE_TYPE_CONVERSATION,
+			"account", account,
+			"type", PURPLE_CONVERSATION_TYPE_DM,
+			NULL);
+
+		purple_protocol_conversation_refresh(protocol, conversation);
+
+		g_clear_object(&account);
+		g_clear_object(&conversation);
+		g_clear_object(&protocol);
+	}
+
+	g_test_trap_subprocess(NULL, 0, 0);
+	g_test_trap_assert_stderr("*Purple-WARNING*TestPurpleProtocolConversationEmpty*refresh*");
+}
+
 /******************************************************************************
  * TestProtocolConversation Implementation
  *****************************************************************************/
@@ -491,6 +530,7 @@
 	guint set_avatar_finish;
 
 	guint send_typing;
+	guint refresh;
 };
 
 static PurpleCreateConversationDetails *
@@ -796,6 +836,18 @@
 }
 
 static void
+test_purple_protocol_conversation_refresh(PurpleProtocolConversation *protocol,
+                                          PurpleConversation *conversation)
+{
+	TestPurpleProtocolConversation *test_protocol = NULL;
+
+	test_protocol = TEST_PURPLE_PROTOCOL_CONVERSATION(protocol);
+	test_protocol->refresh += 1;
+
+	g_assert_true(PURPLE_IS_CONVERSATION(conversation));
+}
+
+static void
 test_purple_protocol_conversation_iface_init(PurpleProtocolConversationInterface *iface) {
 	iface->get_create_conversation_details = test_purple_protocol_conversation_get_create_conversation_details;
 	iface->create_conversation_async = test_purple_protocol_conversation_create_conversation_async;
@@ -818,6 +870,7 @@
 	iface->set_avatar_finish = test_purple_protocol_conversation_set_avatar_finish;
 
 	iface->send_typing = test_purple_protocol_conversation_send_typing;
+	iface->refresh = test_purple_protocol_conversation_refresh;
 }
 
 G_DEFINE_FINAL_TYPE_WITH_CODE(TestPurpleProtocolConversation,
@@ -850,6 +903,7 @@
 	protocol->set_avatar_finish = 0;
 
 	protocol->send_typing = 0;
+	protocol->refresh = 0;
 }
 
 static void
@@ -1094,7 +1148,6 @@
 	conversation = g_object_new(
 		PURPLE_TYPE_CONVERSATION,
 		"account", account,
-		"name", "this is required at the moment",
 		"type", PURPLE_CONVERSATION_TYPE_DM,
 		NULL);
 
@@ -1158,7 +1211,6 @@
 	conversation = g_object_new(
 		PURPLE_TYPE_CONVERSATION,
 		"account", account,
-		"name", "this is required at the moment",
 		"type", PURPLE_CONVERSATION_TYPE_DM,
 		NULL);
 
@@ -1302,7 +1354,6 @@
 	conversation = g_object_new(
 		PURPLE_TYPE_CONVERSATION,
 		"account", account,
-		"name", "this is required at the moment",
 		"type", PURPLE_CONVERSATION_TYPE_DM,
 		NULL);
 
@@ -1352,7 +1403,6 @@
 	conversation = g_object_new(
 		PURPLE_TYPE_CONVERSATION,
 		"account", account,
-		"name", "this is required at the moment",
 		"type", PURPLE_CONVERSATION_TYPE_DM,
 		NULL);
 
@@ -1367,6 +1417,49 @@
 }
 
 /******************************************************************************
+ * TestProtocolConversation Refresh Tests
+ ****************************************************************************/
+static void
+test_purple_protocol_conversation_implements_refresh(void) {
+	PurpleProtocolConversation *protocol = NULL;
+
+	protocol = g_object_new(test_purple_protocol_conversation_get_type(),
+	                        NULL);
+
+	g_assert_true(purple_protocol_conversation_implements_refresh(protocol));
+
+	g_assert_finalize_object(protocol);
+}
+
+static void
+test_purple_protocol_conversation_refresh_normal(void) {
+	TestPurpleProtocolConversation *test_protocol = NULL;
+	PurpleAccount *account = NULL;
+	PurpleConversation *conversation = NULL;
+	PurpleProtocolConversation *protocol = NULL;
+
+	protocol = g_object_new(test_purple_protocol_conversation_get_type(),
+	                        NULL);
+	test_protocol = TEST_PURPLE_PROTOCOL_CONVERSATION(protocol);
+
+	account = purple_account_new("test", "test");
+
+	conversation = g_object_new(
+		PURPLE_TYPE_CONVERSATION,
+		"account", account,
+		"type", PURPLE_CONVERSATION_TYPE_DM,
+		NULL);
+
+	test_purple_protocol_conversation_refresh(protocol, conversation);
+
+	g_assert_cmpuint(test_protocol->refresh, ==, 1);
+
+	g_clear_object(&conversation);
+	g_clear_object(&account);
+	g_clear_object(&protocol);
+}
+
+/******************************************************************************
  * Main
  *****************************************************************************/
 gint
@@ -1412,6 +1505,12 @@
 	g_test_add_func("/protocol-conversation/empty/send-typing",
 	                test_purple_protocol_conversation_empty_send_typing);
 
+	/* Empty refresh tests. */
+	g_test_add_func("/protocol-conversation/empty/implements-refresh",
+	                test_purple_protocol_conversation_empty_implements_refresh);
+	g_test_add_func("/protocol-conversation/empty/refresh",
+	                test_purple_protocol_conversation_empty_refresh);
+
 	/* Normal create conversation tests. */
 	g_test_add_func("/protocol-conversation/normal/implements-create-conversation",
 	                test_purple_protocol_conversation_implements_create_conversation);
@@ -1476,5 +1575,11 @@
 	g_test_add_func("/protocol-conversation/normal/send-typing",
 	                test_purple_protocol_conversation_send_typing_normal);
 
+	/* Normal refresh tests. */
+	g_test_add_func("/protocol-conversation/normal/implements-refresh",
+	                test_purple_protocol_conversation_implements_refresh);
+	g_test_add_func("/protocol-conversation/normal/refresh",
+	                test_purple_protocol_conversation_refresh_normal);
+
 	return g_test_run();
 }
