# HG changeset patch
# Node ID 28a3d2a6f51fcc8f7d3633c62939603aa56c40d4
# Parent  365eaa9d46f8561bfb353cffa16662e6852d5208
diff --git a/protocols/ircv3/purpleircv3connection.c b/protocols/ircv3/purpleircv3connection.c
--- a/protocols/ircv3/purpleircv3connection.c
+++ b/protocols/ircv3/purpleircv3connection.c
@@ -86,6 +86,13 @@
 	                        G_CALLBACK(purple_ircv3_message_handler_privmsg),
 	                        connection, G_CONNECT_DEFAULT);
 
+	g_signal_connect_object(client, "message::" IBIS_MSG_JOIN,
+	                        G_CALLBACK(purple_ircv3_message_handler_join),
+	                        connection, G_CONNECT_DEFAULT);
+	g_signal_connect_object(client, "message::" IBIS_MSG_PART,
+	                        G_CALLBACK(purple_ircv3_message_handler_part),
+	                        connection, G_CONNECT_DEFAULT);
+
 	g_signal_connect_object(client, "message",
 	                        G_CALLBACK(purple_ircv3_connection_unknown_message_cb),
 	                        connection, G_CONNECT_AFTER);
diff --git a/protocols/ircv3/purpleircv3messagehandlers.h b/protocols/ircv3/purpleircv3messagehandlers.h
--- a/protocols/ircv3/purpleircv3messagehandlers.h
+++ b/protocols/ircv3/purpleircv3messagehandlers.h
@@ -38,6 +38,8 @@
 
 G_BEGIN_DECLS
 
+G_GNUC_INTERNAL gboolean purple_ircv3_message_handler_join(IbisClient *client, const char *command, IbisMessage *message, gpointer data);
+G_GNUC_INTERNAL gboolean purple_ircv3_message_handler_part(IbisClient *client, const char *command, IbisMessage *message, gpointer data);
 G_GNUC_INTERNAL gboolean purple_ircv3_message_handler_privmsg(IbisClient *client, const char *command, IbisMessage *message, gpointer data);
 G_GNUC_INTERNAL gboolean purple_ircv3_message_handler_topic(IbisClient *client, const char *command, IbisMessage *message, gpointer data);
 
diff --git a/protocols/ircv3/purpleircv3messagehandlers.c b/protocols/ircv3/purpleircv3messagehandlers.c
--- a/protocols/ircv3/purpleircv3messagehandlers.c
+++ b/protocols/ircv3/purpleircv3messagehandlers.c
@@ -28,9 +28,156 @@
 #include "purpleircv3core.h"
 
 /******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+purple_ircv3_add_contact_to_conversation(PurpleContact *contact,
+                                         PurpleConversation *conversation)
+{
+	PurpleConversationMember *member = NULL;
+
+	member = purple_conversation_find_member(conversation,
+	                                         PURPLE_CONTACT_INFO(contact));
+
+	if(!PURPLE_IS_CONVERSATION_MEMBER(member)) {
+		purple_conversation_add_member(conversation,
+		                               PURPLE_CONTACT_INFO(contact),
+		                               TRUE, NULL);
+	}
+}
+
+/******************************************************************************
  * General Commands
  *****************************************************************************/
 gboolean
+purple_ircv3_message_handler_join(G_GNUC_UNUSED IbisClient *client,
+                                  G_GNUC_UNUSED const char *command,
+                                  IbisMessage *message,
+                                  gpointer data)
+{
+	PurpleIRCv3Connection *connection = data;
+	PurpleContact *contact = NULL;
+	PurpleConversation *conversation = NULL;
+	GStrv params = NULL;
+	guint n_params = 0;
+	char *nick = NULL;
+	const char *source = NULL;
+	const char *conversation_name = NULL;
+
+	source = ibis_message_get_source(message);
+	ibis_source_parse(source, &nick, NULL, NULL);
+	if(purple_strempty(nick)) {
+		/* We _shouldn't_ be able to get an empty nick, but just in case... */
+		g_clear_pointer(&nick, g_free);
+
+		/* TODO: write message about being unable to parse source to status
+		 * window.
+		 */
+
+		return TRUE;
+	}
+
+	contact = purple_ircv3_connection_find_or_create_contact(connection, nick);
+	purple_contact_info_set_sid(PURPLE_CONTACT_INFO(contact), source);
+
+	g_free(nick);
+
+	params = ibis_message_get_params(message);
+	n_params = g_strv_length(params);
+
+	/* A normal join command has the channel as the only parameter. */
+	if(n_params == 1) {
+		conversation_name = params[0];
+	} else {
+		/* TODO: write this to join to the status window saying we didn't know
+		 * how to parse it.
+		 */
+
+		return TRUE;
+	}
+
+	conversation = purple_ircv3_connection_find_or_create_conversation(connection,
+	                                                                   conversation_name);
+	purple_ircv3_add_contact_to_conversation(contact, conversation);
+
+	return TRUE;
+}
+
+gboolean
+purple_ircv3_message_handler_part(G_GNUC_UNUSED IbisClient *client,
+                                  G_GNUC_UNUSED const char *command,
+                                  IbisMessage *message,
+                                  gpointer data)
+{
+	PurpleIRCv3Connection *connection = data;
+	PurpleAccount *account = NULL;
+	PurpleContact *contact = NULL;
+	PurpleConversation *conversation = NULL;
+	PurpleConversationManager *manager = NULL;
+	GStrv params = NULL;
+	guint n_params = 0;
+	char *reason = NULL;
+	char *nick = NULL;
+	const char *conversation_name = NULL;
+	const char *source = NULL;
+
+	params = ibis_message_get_params(message);
+	if(g_strv_length(params) == 0) {
+		/* TODO: mention unparsable message in the status window. */
+		return TRUE;
+	}
+
+	/* TODO: The spec says servers _SHOULD NOT_ send a comma separated list of
+	 * channels, but we should support that at some point just in case.
+	 */
+	conversation_name = params[0];
+
+	account = purple_connection_get_account(PURPLE_CONNECTION(connection));
+	manager = purple_conversation_manager_get_default();
+	conversation = purple_conversation_manager_find_with_id(manager, account,
+	                                                        conversation_name);
+
+	if(!PURPLE_IS_CONVERSATION(conversation)) {
+		/* TODO: write status message unknown channel. */
+
+		return TRUE;
+	}
+
+	source = ibis_message_get_source(message);
+	ibis_source_parse(source, &nick, NULL, NULL);
+	if(purple_strempty(nick)) {
+		/* We _shouldn't_ be able to get an empty nick, but just in case... */
+		g_clear_pointer(&nick, g_free);
+
+		/* TODO: write message about being unable to parse source to status
+		 * window.
+		 */
+
+		return TRUE;
+	}
+
+	/* We do want to find or create the contact, even on a part, because we
+	 * could have connected to a BNC and we weren't told about the contact yet.
+	 */
+	contact = purple_ircv3_connection_find_or_create_contact(connection, nick);
+	g_free(nick);
+
+	/* If a part message was given, join the remaining parameters with a space.
+	 */
+	if(n_params > 1) {
+		reason = g_strjoinv(" ", params + 1);
+	}
+
+	purple_conversation_remove_member(conversation,
+	                                  PURPLE_CONTACT_INFO(contact), TRUE,
+	                                  reason);
+
+	g_clear_pointer(&reason, g_free);
+
+	return TRUE;
+}
+
+gboolean
 purple_ircv3_message_handler_privmsg(G_GNUC_UNUSED IbisClient *client,
                                      const char *command,
                                      IbisMessage *ibis_message, gpointer data)
@@ -79,21 +226,9 @@
 	                                                                   target);
 	/* Find or create the contact. */
 	contact = purple_ircv3_connection_find_or_create_contact(connection, nick);
-	if(PURPLE_IS_CONTACT(contact)) {
-		PurpleConversationMember *member = NULL;
-
-		/* Update the contact's sid as it may have changed. */
-		purple_contact_info_set_sid(PURPLE_CONTACT_INFO(contact), source);
+	purple_contact_info_set_sid(PURPLE_CONTACT_INFO(contact), source);
 
-		/* Make sure the contact is in the conversation. */
-		member = purple_conversation_find_member(conversation,
-		                                         PURPLE_CONTACT_INFO(contact));
-		if(!PURPLE_IS_CONVERSATION_MEMBER(member)) {
-			purple_conversation_add_member(conversation,
-			                               PURPLE_CONTACT_INFO(contact),
-			                               FALSE, NULL);
-		}
-	}
+	purple_ircv3_add_contact_to_conversation(contact, conversation);
 
 	if(purple_strequal(command, IBIS_MSG_NOTICE)) {
 		flags |= PURPLE_MESSAGE_NOTIFY;
