about summary refs log tree commit diff
path: root/handle.c
diff options
context:
space:
mode:
authorNakidai <nakidai@disroot.org>2026-01-06 04:01:24 +0300
committerNakidai <nakidai@disroot.org>2026-01-06 04:01:24 +0300
commit833c53b1ad3338677056445c32c490cac0a08875 (patch)
tree24e60715c46ff89c26c5efc254e036b84aebcb13 /handle.c
parent78426afe18d9ce730a4d92033ca261f9b2f173a0 (diff)
downloadlibreircd-833c53b1ad3338677056445c32c490cac0a08875.tar.gz
libreircd-833c53b1ad3338677056445c32c490cac0a08875.zip
Add basic channels
Though they don't have modes, and JOIN/PART must be able to parse
comma separated list of channels
Diffstat (limited to 'handle.c')
-rw-r--r--handle.c150
1 files changed, 106 insertions, 44 deletions
diff --git a/handle.c b/handle.c
index 79a3b9a..61b34f7 100644
--- a/handle.c
+++ b/handle.c
@@ -20,18 +20,46 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <err.h>
 
-#define ensure(cond, iffalse, doexit) if (!(cond)) { iffalse; if (doexit >= 0) return doexit; }
+
+static int
+join(struct Message *msg, struct Peer *peer)
+{
+	size_t i, j;
+
+	/* TODO: support comma separated list of channels, keys */
+	ensure(peer->type, reply(peer, 451), 0);
+	ensure(msg->params[0] && *msg->params[0], reply(peer, 461), 0);
+	ensure(peer->channels_c != lengthof(peer->channels), reply(peer, 405, msg->params[0]), 0)
+	ensure(*msg->params[0] == '#', reply(peer, 403, msg->params[0]), 0);
+
+	for (i = 0; i < channels_c; ++i)
+	{
+		if (strcmp(channels[i].name, msg->params[0]))
+			continue;
+
+		for (j = 0; j < channels[i].users_c; ++j)
+			ensure(
+				strcmp(channels[i].users[j]->nick, peer->nick),
+				(void)0,
+				0
+			);
+
+		ensure(!channel_join(&channels[i], peer), reply(peer, 471), 0);
+		return 0;
+	}
+
+	channels[channels_c] = (struct Channel){0};
+	strlcpy(channels[channels_c].name, msg->params[0], sizeof(channels->name));
+	channel_join(&channels[channels_c++], peer);
+	return 0;
+}
 
 static int
 nick(struct Message *msg, struct Peer *peer)
 {
-	ensure(msg->params[0] && msg->params[0], writef(
-		peer->fd,
-		":%s 431 %s :No nickname given",
-		hostname,
-		getnick(peer)
-	), 0);
+	ensure(msg->params[0] && msg->params[0], reply(peer, 431), 0);
 
 	user_reg(peer, msg->params[0], NULL, NULL);
 
@@ -39,31 +67,43 @@ nick(struct Message *msg, struct Peer *peer)
 }
 
 static int
+part(struct Message *msg, struct Peer *peer)
+{
+	size_t i;
+
+	ensure(peer->type, reply(peer, 451), 0);
+	ensure(msg->params[0] && *msg->params[0], reply(peer, 461), 0);
+
+	for (i = 0; i < peer->channels_c; ++i)
+		if (!strcmp(peer->channels[i]->name, msg->params[0]))
+			break;
+	ensure(i != peer->channels_c, reply(peer, 442, msg->params[0]), 0)
+
+	writechanf(
+		0,
+		peer->channels[i],
+		":%s!%s@%s PART %s :%s",
+		getnick(peer),
+		peer->user,
+		peer->host,
+		msg->params[0],
+		msg->params[1] ? msg->params[1] : getnick(peer)
+	);
+	channel_exit(peer->channels[i], peer);
+	return 0;
+}
+
+static int
 privmsg(struct Message *msg, struct Peer *peer)
 {
 	size_t i;
 
-	ensure(peer->type, writef(
-		peer->fd,
-		":%s 451 %s :You have not registered",
-		hostname,
-		getnick(peer)
-	), 0);
-	ensure(msg->params[0] && *msg->params[0], writef(
-		peer->fd,
-		":%s 411 %s :No recipient given (PRIVMSG)",
-		hostname,
-		getnick(peer)
-	), 0);
-	ensure(msg->params[1] && *msg->params[1], writef(
-		peer->fd,
-		":%s 412 %s :No text to send",
-		hostname,
-		getnick(peer)
-	), 0);
+	ensure(peer->type, reply(peer, 451), 0);
+	ensure(msg->params[0] && *msg->params[0], reply(peer, 411), 0);
+	ensure(msg->params[1] && *msg->params[1], reply(peer, 412), 0);
 
 	/* TODO: implement channels */
-	ensure(!strchr("!+#&", *msg->params[0]), writef(
+	ensure(!strchr("!+&", *msg->params[0]), writef(
 		peer->fd,
 		":%s 421 %s :Channels are not supported yet",
 		hostname,
@@ -71,17 +111,48 @@ privmsg(struct Message *msg, struct Peer *peer)
 	), 0);
 
 	/* TODO: implement server-to-server communication */
-	for (i = 0; i < PEERS_MAX; ++i)
-		if (peers[i].type == CLIENT && !strcmp(peers[i].nick, msg->params[0]))
+	switch (*msg->params[0])
+	{
+	case '#':
+	{
+		for (i = 0; i < channels_c; ++i)
+			if (!strcmp(channels[i].name, msg->params[0]))
+			{
+				writechanf(
+					peer,
+					&channels[i],
+					":%s!%s@%s PRIVMSG %s :%s",
+					peer->nick,
+					peer->user,
+					peer->host,
+					msg->params[0],
+					msg->params[1]
+				);
+				break;
+			}
+		ensure(i != channels_c, reply(peer, 401, msg->params[0]), 0);
+	} break;
+	default:
+	{
+		for (i = 0; i < peers_c; ++i)
+		{
+			if (peers[i].type != CLIENT || strcmp(peers[i].nick, msg->params[0]))
+				continue;
+
 			writef(
 				peers[i].fd,
 				":%s!%s@%s PRIVMSG %s :%s",
 				peer->nick,
 				peer->user,
 				peer->host,
-				peer->nick,
+				msg->params[0],
 				msg->params[1]
 			);
+			break;
+		}
+		ensure(i != peers_c, reply(peer, 401, msg->params[0]), 0);
+	} break;
+	}
 	return 0;
 }
 
@@ -96,20 +167,9 @@ user(struct Message *msg, struct Peer *peer)
 {
 	size_t i;
 
-	ensure(!peer->type, writef(
-		peer->fd,
-		":%s 462 %s :Unauthorized command (already registered)",
-		hostname,
-		getnick(peer)
-	), 0);
+	ensure(!peer->type, reply(peer, 462), 0);
 	for (i = 0; i < 4; ++i)
-		ensure(msg->params[i] && *msg->params[i], writef(
-			peer->fd,
-			":%s 461 %s %s :Not enough parameters",
-			hostname,
-			getnick(peer),
-			msg->command
-		), 0);
+		ensure(msg->params[i] && *msg->params[i], reply(peer, 461), 0);
 
 	user_reg(peer, NULL, msg->params[0], msg->params[3]);
 
@@ -119,9 +179,9 @@ user(struct Message *msg, struct Peer *peer)
 static int
 default_handler(struct Message *msg, struct Peer *peer)
 {
-	ensure(peer->type, 0, 0);
+	ensure(peer->type, (void)0, 0);
 
-	writef(peer->fd, ":%s 421 %s %s :Unknown command", hostname, getnick(peer), msg->command);
+	reply(peer, 421, msg->command);
 	return 0;
 }
 
@@ -130,7 +190,9 @@ static struct Handler {
 	Handler *handler;
 } handlers[] =
 {
+	{ "join", join },
 	{ "nick", nick },
+	{ "part", part },
 	{ "privmsg", privmsg },
 	{ "quit", quit },
 	{ "user", user },