summary refs log tree commit diff
path: root/handle.c
diff options
context:
space:
mode:
authorNakidai <nakidai@disroot.org>2026-02-14 00:05:36 +0300
committerNakidai <nakidai@disroot.org>2026-02-14 00:20:38 +0300
commit834c85d80914007e31657d12d2f22a9cb2cd8624 (patch)
tree283ed0dacb635b97f93c21c8b0b94b6116ca29a3 /handle.c
parent15151c88a7eb381fb5b46daaf521fc609d40539c (diff)
downloadlibreircd-834c85d80914007e31657d12d2f22a9cb2cd8624.tar.gz
libreircd-834c85d80914007e31657d12d2f22a9cb2cd8624.zip
Add support for voice and +m channel mode
So now voices in code are not that useless. Also, code was fixed for
their printing as it is valid for a user to be both an oper and voiced
Diffstat (limited to 'handle.c')
-rw-r--r--handle.c52
1 files changed, 38 insertions, 14 deletions
diff --git a/handle.c b/handle.c
index 684c2ee..1253cdf 100644
--- a/handle.c
+++ b/handle.c
@@ -182,6 +182,18 @@ mode_channel(struct Message *msg, struct Peer *peer)
 	parsed = channel_modes_parse(msg);
 	for (; parsed->param || parsed->mode; ++parsed) switch (parsed->mode)
 	{
+	break; case 'm':
+		announce_change(1);
+		if (parsed->set)
+			channel->modes |= CHANNEL_MODERATED;
+		else
+			channel->modes &= ~CHANNEL_MODERATED;
+	break; case 'n':
+		announce_change(1);
+		if (parsed->set)
+			channel->modes |= CHANNEL_NOFROMOUT;
+		else
+			channel->modes &= ~CHANNEL_NOFROMOUT;
 	break; case 'o':
 		ensure(parsed->param, reply(peer, 461, msg->command), 0);
 
@@ -195,12 +207,6 @@ mode_channel(struct Message *msg, struct Peer *peer)
 			channel->peers[i].modes |= CHANNEL_OPER;
 		else
 			channel->peers[i].modes &= ~CHANNEL_OPER;
-	break; case 'n':
-		announce_change(1);
-		if (parsed->set)
-			channel->modes |= CHANNEL_NOFROMOUT;
-		else
-			channel->modes &= ~CHANNEL_NOFROMOUT;
 	break; case 's':
 		/* TODO: implement +s. For now it's just a some mode with no param */
 		announce_change(1);
@@ -214,6 +220,19 @@ mode_channel(struct Message *msg, struct Peer *peer)
 			channel->modes |= CHANNEL_TOPIC;
 		else
 			channel->modes &= ~CHANNEL_TOPIC;
+	break; case 'v':
+		ensure(parsed->param, reply(peer, 461, msg->command), 0);
+
+		for (i = 0; i < channel->peers_c; ++i)
+			if (!strcmp(channel->peers[i].p->nick, parsed->param))
+				break;
+		ensure(i != channel->peers_c, reply(peer, 441, parsed->param, channel->name), 0);
+
+		announce_change(0);
+		if (parsed->set)
+			channel->peers[i].modes |= CHANNEL_VOICE;
+		else
+			channel->peers[i].modes &= ~CHANNEL_VOICE;
 	break; default:
 		modebuf[0] = parsed->mode;
 		modebuf[1] = 0;
@@ -295,7 +314,7 @@ names(struct Message *msg, struct Peer *peer)
 			chpp = &peer->channels[i]->peers[j];
 			if (chpp->modes & CHANNEL_OPER)
 				strlcat(buf, "@", sizeof(buf));
-			else if (chpp->modes & CHANNEL_VOICE)
+			if (chpp->modes & CHANNEL_VOICE)
 				strlcat(buf, "+", sizeof(buf));
 			strlcat(buf, peer->channels[i]->peers[j].p->nick, sizeof(buf));
 			if (strlen(buf) >= MESSAGE_MAX - 4*PEER_NICK_MAX
@@ -466,13 +485,18 @@ privmsg(struct Message *msg, struct Peer *peer)
 		ensure(i != channels_c, reply(peer, 401, msg->params[0]), 0);
 		ch = &channels[i];
 
-		if (ch->modes & CHANNEL_NOFROMOUT)
-		{
-			for (i = 0; i < ch->peers_c; ++i)
-				if (!strcmp(ch->peers[i].p->nick, peer->nick))
-					break;
-			ensure(i != ch->peers_c, reply(peer, 442, ch->name), 0);
-		}
+		for (i = 0; i < ch->peers_c; ++i)
+			if (ch->peers[i].p == peer)
+				break;
+
+		ensure(
+			(!(ch->modes & CHANNEL_NOFROMOUT) || i != ch->peers_c)
+			&& (!(ch->modes & CHANNEL_MODERATED)
+				|| ch->peers[i].modes & (CHANNEL_OPER | CHANNEL_VOICE)
+			),
+			reply(peer, 404, ch->name),
+			0
+		);
 
 		writechanf(
 			peer,