diff options
| author | Nakidai <nakidai@disroot.org> | 2026-02-10 03:38:15 +0300 |
|---|---|---|
| committer | Nakidai <nakidai@disroot.org> | 2026-02-10 03:38:15 +0300 |
| commit | db996c22cd51cd46dd9afee1085a8af04cc7b53b (patch) | |
| tree | 3fdc59fc9f7d42a1e8f96d9ca615e2d8b19a60da | |
| parent | 15b0b805fe2e739c9d89b54e1bfb26beb79c3112 (diff) | |
| download | libreircd-db996c22cd51cd46dd9afee1085a8af04cc7b53b.tar.gz libreircd-db996c22cd51cd46dd9afee1085a8af04cc7b53b.zip | |
Add channel mode editing support
Well, an oper should have some way to manage their channel :)
| -rw-r--r-- | channel.c | 54 | ||||
| -rw-r--r-- | handle.c | 52 | ||||
| -rw-r--r-- | ircd.h | 14 | ||||
| -rw-r--r-- | reply.c | 16 |
4 files changed, 134 insertions, 2 deletions
diff --git a/channel.c b/channel.c index 21a777a..d04f3cc 100644 --- a/channel.c +++ b/channel.c @@ -79,6 +79,60 @@ channel_exit(struct Channel *channel, struct Peer *peer) return 0; } +const struct ChannelModeParam * +channel_modes_parse(const struct Message *msg) +{ + static struct ChannelModeParam modes[MESSAGE_MAX]; + size_t i, modes_c, queue_l, queue_r; + char *m, queue[PARAM_MAX]; + int set = 1; + + memset(modes, 0, sizeof(modes)); + for (modes_c = queue_l = queue_r = 0, i = 1; msg->params[i]; ++i, set = 1) switch (*msg->params[i]) + { + case '-': + set = 0; + case '+': + { + for (m = msg->params[i]+1; *m; ++m) switch (*m) + { + break; case 'o': + /* since all flags are ASCII (< 128) bit 7 + * can be and is abused for the set flag */ + if (queue_r == lengthof(queue)) + { + modes[modes_c].mode = *m; + return modes; + } + queue[queue_r++] = (set << 7) | *m; + break; case 's': + modes[modes_c].mode = *m; + modes[modes_c++].set = set; + break; default: + modes[modes_c].mode = *m; + modes[modes_c++].set = set; + return modes; + } + } break; + default: + { + modes[modes_c].param = msg->params[i]; + + if (queue_l == queue_r) + { + return modes; + } + else + { + modes[modes_c].set = !!(queue[queue_l] & (1 << 7)); + modes[modes_c++].mode = queue[queue_l++] & ~(1 << 7); + } + } break; + } + + return modes; +} + void channel_remove(size_t cid) { diff --git a/handle.c b/handle.c index ecbde08..d11b39a 100644 --- a/handle.c +++ b/handle.c @@ -76,8 +76,10 @@ join(struct Message *msg, struct Peer *peer) static int mode_channel(struct Message *msg, struct Peer *peer) { + const struct ChannelModeParam *parsed; enum ChannelPeerMode modes; struct Channel *channel; + char modebuf[2]; size_t i; for (i = 0; i < channels_c; ++i) @@ -96,6 +98,56 @@ mode_channel(struct Message *msg, struct Peer *peer) ensure(modes & CHANNEL_OPER || peer->modes & OPER, reply(peer, 482, channel->name), 0); + parsed = channel_modes_parse(msg); + for (; parsed->param || parsed->mode; ++parsed) switch (parsed->mode) + { + break; case 'o': + 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); + + writechanf( + 0, + channel, + "%s!%s@%s MODE %s %co %s", + getnick(peer), + peer->user, + peer->host, + channel->name, + parsed->set ? '+' : '-', + parsed->param + ); + + if (parsed->set) + channel->peers[i].modes |= CHANNEL_OPER; + else + channel->peers[i].modes &= ~CHANNEL_OPER; + break; case 's': + /* TODO: implement +s. For now it's just a some mode with no param */ + writechanf( + 0, + channel, + "%s!%s@%s MODE %s %cs", + getnick(peer), + peer->user, + peer->host, + channel->name, + parsed->set ? '+' : '-' + ); + if (parsed->set) + channel->modes |= CHANNEL_SECRET; + else + channel->modes &= ~CHANNEL_SECRET; + break; default: + modebuf[0] = parsed->mode; + modebuf[1] = 0; + reply(peer, 472, modebuf, channel->name); + return 0; + } + return 0; } diff --git a/ircd.h b/ircd.h index 29457d8..931948b 100644 --- a/ircd.h +++ b/ircd.h @@ -61,6 +61,13 @@ struct Peer time_t last, ping; }; +struct ChannelModeParam +{ + char *param; + int set; + char mode; +}; + struct Channel { enum { GLOBAL, LOCAL, MODELESS, SAFE } type; @@ -72,7 +79,11 @@ struct Channel BIT(CHANNEL_VOICE), } modes; } peers[CHANNEL_PEERS_MAX]; - size_t modes_c, peers_c; + size_t peers_c; + enum ChannelMode + { + BIT(CHANNEL_SECRET), + } modes; }; struct Oper @@ -101,6 +112,7 @@ void user_remove(size_t pid); int channel_join(struct Channel *channel, struct Peer *peer); int channel_exit(struct Channel *channel, struct Peer *peer); +const struct ChannelModeParam *channel_modes_parse(const struct Message *msg); void channel_remove(size_t cid); int parse_message(char *buf, struct Message *msg); diff --git a/reply.c b/reply.c index adc2557..de1d5c7 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 :", + ":%s 004 %s :%s libreircd-" IRCD_VERSION " aiwroOs os", hostname, getnick(peer), hostname @@ -220,6 +220,13 @@ vreply(const struct Peer *peer, int number, va_list ap) getnick(peer), nick ), nick, _); + REPLY(441, WRITE( + ":%s 441 %s %s %s :They aren't on that channel", + hostname, + getnick(peer), + nick, + channel + ), nick, channel, _); REPLY(442, WRITE( ":%s 442 %s %s :You're not on that channel", hostname, @@ -253,6 +260,13 @@ vreply(const struct Peer *peer, int number, va_list ap) getnick(peer), channel ), channel, _); + REPLY(472, WRITE( + ":%s 472 %s %s :is unknown mode char to me for %s", + hostname, + getnick(peer), + mode, + channel + ), mode, channel, _); REPLY(481, WRITE( ":%s 481 %s :Permission Denied- %s", hostname, |