From 883e777bacc85b92f460524098ae27b6a8d4d221 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch <p.janouch@gmail.com>
Date: Tue, 21 Apr 2015 21:36:16 +0200
Subject: degesch: implement PART and KICK handlers

---
 degesch.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 65 insertions(+), 15 deletions(-)

diff --git a/degesch.c b/degesch.c
index ac44a71..c4e2385 100644
--- a/degesch.c
+++ b/degesch.c
@@ -1309,6 +1309,25 @@ irc_make_channel (struct app_context *ctx, char *name)
 	return channel;
 }
 
+static void
+irc_unlink_user_from_channel
+	(struct app_context *ctx, struct user *user, struct channel *channel)
+{
+	// The order is important here as the channel can hold the last reference
+	LIST_FOR_EACH (struct user_channel, iter, user->channels)
+		if (iter->channel == channel)
+		{
+			LIST_UNLINK (user->channels, iter);
+			user_channel_destroy (iter);
+		}
+	LIST_FOR_EACH (struct channel_user, iter, channel->users)
+		if (iter->user == user)
+		{
+			LIST_UNLINK (channel->users, iter);
+			channel_user_destroy (iter);
+		}
+}
+
 // --- Supporting code ---------------------------------------------------------
 
 static char *
@@ -1896,15 +1915,41 @@ irc_handle_join (struct app_context *ctx, const struct irc_message *msg)
 	if (buffer)
 	{
 		buffer_send (ctx, buffer, BUFFER_LINE_JOIN, 0,
-			msg->prefix, NULL, "%s", target);
+			msg->prefix, NULL, "%s", channel_name);
 	}
 }
 
 static void
 irc_handle_kick (struct app_context *ctx, const struct irc_message *msg)
 {
-	// TODO: remove user from the channel
-	// TODO: log a message
+	if (!msg->prefix || msg->params.len < 2)
+		return;
+
+	const char *channel_name = msg->params.vector[0];
+	const char *target = msg->params.vector[1];
+	if (!irc_is_channel (ctx, channel_name)
+	 || irc_is_channel (ctx, target))
+		return;
+
+	const char *message = NULL;
+	if (msg->params.len > 2)
+		message = msg->params.vector[2];
+
+	struct user *user = str_map_find (&ctx->irc_users, target);
+	struct channel *channel = str_map_find (&ctx->irc_channels, channel_name);
+	struct buffer *buffer = str_map_find (&ctx->irc_buffer_map, channel_name);
+	hard_assert ((channel && buffer) ||
+		(channel && !buffer) || (!channel && !buffer));
+
+	// It would be is weird for this to be false
+	if (user && channel)
+		irc_unlink_user_from_channel (ctx, user, channel);
+
+	if (buffer)
+	{
+		buffer_send (ctx, buffer, BUFFER_LINE_KICK, 0,
+			msg->prefix, message, "%s", target);
+	}
 }
 
 static void
@@ -2000,27 +2045,32 @@ irc_handle_part (struct app_context *ctx, const struct irc_message *msg)
 	if (!msg->prefix || msg->params.len < 1)
 		return;
 
-	char *nickname = irc_cut_nickname (msg->prefix);
-	struct user *user = str_map_find (&ctx->irc_users, nickname);
-	free (nickname);
-	if (!user)
-		return;
-
-	const char *target = msg->params.vector[0];
-	if (!irc_is_channel (ctx, target))
+	const char *channel_name = msg->params.vector[0];
+	if (!irc_is_channel (ctx, channel_name))
 		return;
 
 	const char *message = NULL;
 	if (msg->params.len > 1)
 		message = msg->params.vector[1];
 
-	struct channel *channel = str_map_find (&ctx->irc_channels, target);
-	struct buffer *buffer = str_map_find (&ctx->irc_buffer_map, target);
+	char *nickname = irc_cut_nickname (msg->prefix);
+	struct user *user = str_map_find (&ctx->irc_users, nickname);
+	free (nickname);
+
+	struct channel *channel = str_map_find (&ctx->irc_channels, channel_name);
+	struct buffer *buffer = str_map_find (&ctx->irc_buffer_map, channel_name);
 	hard_assert ((channel && buffer) ||
 		(channel && !buffer) || (!channel && !buffer));
 
-	// TODO: remove user from the channel
-	// TODO: log a message
+	// It would be is weird for this to be false
+	if (user && channel)
+		irc_unlink_user_from_channel (ctx, user, channel);
+
+	if (buffer)
+	{
+		buffer_send (ctx, buffer, BUFFER_LINE_PART, 0,
+			msg->prefix, message, "%s", channel_name);
+	}
 }
 
 static void
-- 
cgit v1.2.3-70-g09d2