summary refs log tree commit diff
diff options
context:
space:
mode:
authorNakidai <nakidai@disroot.org>2026-02-13 00:52:30 +0300
committerNakidai <nakidai@disroot.org>2026-02-13 00:52:30 +0300
commitd493c4a9b9bb1db0da7418a0a2797c5f2b3d34ff (patch)
treea6b9ce9905864ae4696e3fa0431d8a02096d1877
parent3f2bbeda9cae1e3d3f50d984549c82a5a29d2f6f (diff)
downloadlibreircd-d493c4a9b9bb1db0da7418a0a2797c5f2b3d34ff.tar.gz
libreircd-d493c4a9b9bb1db0da7418a0a2797c5f2b3d34ff.zip
Add TOPIC and t channel flag support
Yay, now there're topic!!
-rw-r--r--channel.c2
-rw-r--r--handle.c59
-rw-r--r--ircd.h4
-rw-r--r--reply.c15
4 files changed, 77 insertions, 3 deletions
diff --git a/channel.c b/channel.c
index 2717e5e..f2da302 100644
--- a/channel.c
+++ b/channel.c
@@ -105,7 +105,7 @@ channel_modes_parse(const struct Message *msg)
 				return modes;
 			}
 			queue[queue_r++] = (set << 7) | *m;
-		break; case 'n': case 's':
+		break; case 'n': case 's': case 't':
 			modes[modes_c].mode = *m;
 			modes[modes_c++].set = set;
 		break; default:
diff --git a/handle.c b/handle.c
index 25c6875..0be87a3 100644
--- a/handle.c
+++ b/handle.c
@@ -201,6 +201,12 @@ mode_channel(struct Message *msg, struct Peer *peer)
 			channel->modes |= CHANNEL_SECRET;
 		else
 			channel->modes &= ~CHANNEL_SECRET;
+	break; case 't':
+		announce_change(1);
+		if (parsed->set)
+			channel->modes |= CHANNEL_TOPIC;
+		else
+			channel->modes &= ~CHANNEL_TOPIC;
 	break; default:
 		modebuf[0] = parsed->mode;
 		modebuf[1] = 0;
@@ -572,6 +578,58 @@ setoper(struct Message *msg, struct Peer *peer)
 }
 
 static int
+topic(struct Message *msg, struct Peer *peer)
+{
+	struct Channel *ch;
+	size_t i;
+
+	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);
+
+	for (i = 0; i < channels_c; ++i)
+		if (!strcmp(channels[i].name, msg->params[0]))
+			break;
+	ensure(i != channels_c, reply(peer, 442, msg->params[0]), 0);
+	ch = &channels[i];
+
+	if (msg->params[1])
+	{
+		for (i = 0; i < ch->peers_c; ++i)
+			if (ch->peers[i].p->fd == peer->fd)
+				break;
+		ensure(i != ch->peers_c, reply(peer, 442, ch->name), 0);
+		ensure(
+			!(ch->modes & CHANNEL_TOPIC)
+			|| ch->peers[i].modes & CHANNEL_OPER
+			|| peer->modes & OPER,
+			reply(peer, 482, ch->name),
+			0
+		);
+
+		strlcpy(ch->topic, msg->params[1], sizeof(ch->topic));
+		writechanf(
+			0,
+			ch,
+			":%s!%s@%s TOPIC %s :%s",
+			getnick(peer),
+			peer->user,
+			peer->host,
+			ch->name,
+			ch->topic
+		);
+	} else
+	{
+		if (*ch->topic)
+			reply(peer, 332, ch->name, ch->topic);
+		else
+			reply(peer, 331, ch->name);
+	}
+
+	return 0;
+}
+
+static int
 user(struct Message *msg, struct Peer *peer)
 {
 	size_t i;
@@ -663,6 +721,7 @@ static struct Handler {
 	{ "sethostname", sethostname },
 	{ "setinfo", setinfo },
 	{ "setoper", setoper },
+	{ "topic", topic },
 	{ "user", user },
 	{ "whois", whois },
 };
diff --git a/ircd.h b/ircd.h
index 7b59330..3012783 100644
--- a/ircd.h
+++ b/ircd.h
@@ -72,6 +72,7 @@ struct Channel
 {
 	enum { GLOBAL, LOCAL, MODELESS, SAFE } type;
 	char name[CHANNEL_NAME_MAX];
+	char topic[MESSAGE_MAX];
 	struct ChannelPeer {
 		struct Peer *p;
 		enum ChannelPeerMode {
@@ -82,8 +83,9 @@ struct Channel
 	size_t peers_c;
 	enum ChannelMode
 	{
-		BIT(CHANNEL_SECRET),
 		BIT(CHANNEL_NOFROMOUT),
+		BIT(CHANNEL_SECRET),
+		BIT(CHANNEL_TOPIC),
 	} modes;
 };
 
diff --git a/reply.c b/reply.c
index 268e912..41fcb4a 100644
--- a/reply.c
+++ b/reply.c
@@ -87,7 +87,7 @@ vreply(const struct Peer *peer, int number, va_list ap)
 		creation
 	), _);
 	REPLY(4, WRITE(
-		":%s 004 %s :%s libreircd-" IRCD_VERSION " aiwroOs os",
+		":%s 004 %s :%s libreircd-" IRCD_VERSION " aiwroOs nost",
 		hostname,
 		getnick(peer),
 		hostname
@@ -153,6 +153,19 @@ vreply(const struct Peer *peer, int number, va_list ap)
 		channel,
 		modes
 	), channel, modes, _);
+	REPLY(331, WRITE(
+		":%s 331 %s %s :No topic is set",
+		hostname,
+		getnick(peer),
+		channel
+	), channel, _);
+	REPLY(332, WRITE(
+		":%s 332 %s %s :%s",
+		hostname,
+		getnick(peer),
+		channel,
+		topic
+	), channel, topic, _);
 	REPLY(353, WRITE(
 		":%s 353 %s = %s :%s",
 		hostname,