diff --git a/libpurple/protocols/ircv3/purpleircv3connection.h b/libpurple/protocols/ircv3/purpleircv3connection.h
--- a/libpurple/protocols/ircv3/purpleircv3connection.h
+++ b/libpurple/protocols/ircv3/purpleircv3connection.h
@@ -122,6 +122,38 @@
 PURPLE_IRCV3_AVAILABLE_IN_ALL
 void purple_ircv3_connection_add_status_message(PurpleIRCv3Connection *connection, PurpleIRCv3Message *message);
 
+/**
+ * purple_ircv3_connection_is_channel:
+ * @connection: The instance.
+ * @id: The id to check.
+ *
+ * Checks if @id is a channel.
+ *
+ * Right now this just checks if @id starts with a `#` but in the future this
+ * will be updated to check all channel prefixes that the connection supports.
+ *
+ * Returns: %TRUE if @id is a channel otherwise %FALSE.
+ *
+ * Since: 3.0.0
+ */
+PURPLE_IRCV3_AVAILABLE_IN_ALL
+gboolean purple_ircv3_connection_is_channel(PurpleIRCv3Connection *connection, const char *id);
+
+/**
+ * purple_ircv3_connection_find_or_create_conversation:
+ * @connection: The instance.
+ * @id: The id of the conversation.
+ *
+ * Looks for an existing conversation belonging to @connection and returns it
+ * if found. If not found a new instance conversation will be created.
+ *
+ * Returns: (transfer none): The conversation.
+ *
+ * Since: 3.0.0
+ */
+PURPLE_IRCV3_AVAILABLE_IN_ALL
+PurpleConversation *purple_ircv3_connection_find_or_create_conversation(PurpleIRCv3Connection *connection, const char *id);
+
 G_END_DECLS
 
 #endif /* PURPLE_IRCV3_CONNECTION_H */
# HG changeset patch
# Node ID 3128e40269a0
# Parent  329359569c5c
diff --git a/libpurple/protocols/ircv3/purpleircv3connection.c b/libpurple/protocols/ircv3/purpleircv3connection.c
--- a/libpurple/protocols/ircv3/purpleircv3connection.c
+++ b/libpurple/protocols/ircv3/purpleircv3connection.c
@@ -697,3 +697,55 @@
 
 	g_clear_object(&message);
 }
+
+gboolean
+purple_ircv3_connection_is_channel(PurpleIRCv3Connection *connection,
+                                   const char *id)
+{
+	g_return_val_if_fail(PURPLE_IRCV3_IS_CONNECTION(connection), FALSE);
+	g_return_val_if_fail(id != NULL, FALSE);
+
+	return (id[0] == '#');
+}
+
+PurpleConversation *
+purple_ircv3_connection_find_or_create_conversation(PurpleIRCv3Connection *connection,
+                                                    const char *id)
+{
+	PurpleAccount *account = NULL;
+	PurpleConversation *conversation = NULL;
+	PurpleConversationManager *manager = NULL;
+
+	g_return_val_if_fail(PURPLE_IRCV3_IS_CONNECTION(connection), NULL);
+	g_return_val_if_fail(id != NULL, NULL);
+
+	account = purple_connection_get_account(PURPLE_CONNECTION(connection));
+	manager = purple_conversation_manager_get_default();
+	conversation = purple_conversation_manager_find_with_id(manager, account,
+	                                                        id);
+
+	if(!PURPLE_IS_CONVERSATION(conversation)) {
+		PurpleConversationType type = PurpleConversationTypeDM;
+
+		if(purple_ircv3_connection_is_channel(connection, id)) {
+			type = PurpleConversationTypeChannel;
+		}
+
+		conversation = g_object_new(
+			PURPLE_TYPE_CONVERSATION,
+			"account", account,
+			"id", id,
+			"name", id,
+			"type", type,
+			NULL);
+
+		purple_conversation_manager_register(manager, conversation);
+
+		/* The manager creates its own reference on our new conversation, so we
+		 * borrow it like we do above if it already exists.
+		 */
+		g_object_unref(conversation);
+	}
+
+	return conversation;
+}
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
@@ -125,7 +125,6 @@
 	PurpleContact *contact = NULL;
 	PurpleContactManager *contact_manager = NULL;
 	PurpleConversation *conversation = NULL;
-	PurpleConversationManager *conversation_manager = NULL;
 	PurpleMessage *message = NULL;
 	PurpleMessageFlags flags = PURPLE_MESSAGE_RECV;
 	GDateTime *dt = NULL;
@@ -174,44 +173,12 @@
 	}
 	g_clear_object(&contact);
 
-	conversation_manager = purple_conversation_manager_get_default();
-
 	target = params[0];
-	if(target[0] == '#') {
-		conversation = purple_conversation_manager_find(conversation_manager,
-		                                                account, target);
-	} else {
-		conversation = purple_conversation_manager_find(conversation_manager,
-		                                                account, nick);
+	if(!purple_ircv3_connection_is_channel(connection, target)) {
+		target = nick;
 	}
-
-	if(!PURPLE_IS_CONVERSATION(conversation)) {
-		if(target[0] == '#') {
-			conversation = g_object_new(
-				PURPLE_TYPE_CONVERSATION,
-				"account", account,
-				"name", target,
-				"type", PurpleConversationTypeChannel,
-				"id", target,
-				NULL);
-		} else {
-			conversation = g_object_new(
-				PURPLE_TYPE_CONVERSATION,
-				"account", account,
-				"name", nick,
-				"type", PurpleConversationTypeDM,
-				"id", nick,
-				NULL);
-		}
-
-		purple_conversation_manager_register(conversation_manager,
-		                                     conversation);
-
-		/* The manager creates its own reference on our new conversation, so we
-		 * borrow it like we do above if it already exists.
-		 */
-		g_object_unref(conversation);
-	}
+	conversation = purple_ircv3_connection_find_or_create_conversation(connection,
+	                                                                   target);
 
 	/* Grab the msgid if one was provided. */
 	if(g_hash_table_lookup_extended(tags, "msgid", NULL, &raw_id)) {
