diff options
| -rw-r--r-- | handle.c | 46 | ||||
| -rw-r--r-- | ircd.h | 15 | ||||
| -rw-r--r-- | loop.c | 2 | ||||
| -rw-r--r-- | main.c | 3 | ||||
| -rw-r--r-- | reply.c | 32 | ||||
| -rw-r--r-- | user.c | 36 |
6 files changed, 123 insertions, 11 deletions
diff --git a/handle.c b/handle.c index 87dfa77..9d705e0 100644 --- a/handle.c +++ b/handle.c @@ -57,11 +57,52 @@ join(struct Message *msg, struct Peer *peer) } static int +mode(struct Message *msg, struct Peer *peer) +{ + int set = 1, m; + + ensure(peer->type, reply(peer, 451), 0); + ensure(msg->params[0] && msg->params[0], reply(peer, 431), 0); + ensure(msg->params[1] && msg->params[1], reply(peer, 221), 0); + + switch (*msg->params[1]) + { + case '-': + set = !set; + case '+': + ++msg->params[1]; + default: + { + for (; *msg->params[1]; ++msg->params[1]) + { + m = user_mode(*msg->params[1]); + if (!m) + { + reply(peer, 501, msg->params[1]); + continue; + } + + if (m & AWAY) + continue; + + if (set && !(m & (OPER | LOCALOPER))) + peer->modes |= m; + else if (!(m & RESTRICTED)) + peer->modes &= ~m; + } + } + } + + return 0; +} + +static int nick(struct Message *msg, struct Peer *peer) { ensure(msg->params[0] && msg->params[0], reply(peer, 431), 0); + ensure(!(peer->modes & RESTRICTED), reply(peer, 484), 0); - user_reg(peer, msg->params[0], NULL, NULL); + user_reg(peer, msg->params[0], NULL, NULL, NULL); return 0; } @@ -205,7 +246,7 @@ user(struct Message *msg, struct Peer *peer) for (i = 0; i < 4; ++i) ensure(msg->params[i] && *msg->params[i], reply(peer, 461), 0); - user_reg(peer, NULL, msg->params[0], msg->params[3]); + user_reg(peer, NULL, msg->params[0], msg->params[3], msg->params[1]); return 0; } @@ -225,6 +266,7 @@ static struct Handler { } handlers[] = { { "join", join }, + { "mode", mode }, { "nick", nick }, { "part", part }, { "privmsg", privmsg }, diff --git a/ircd.h b/ircd.h index 6035b79..2c4b144 100644 --- a/ircd.h +++ b/ircd.h @@ -51,9 +51,17 @@ struct Peer BIT(DELETE), BIT(ANNOUNCE), } flags; + enum PeerMode { + BIT(AWAY), + BIT(INVISIBLE), + BIT(WALLOPS), + BIT(RESTRICTED), + BIT(OPER), + BIT(LOCALOPER), + BIT(SNOTICE), + } modes; char buf[MESSAGE_MAX]; size_t recvd, channels_c; - char modes[52]; }; struct Channel @@ -75,10 +83,11 @@ extern struct Peer peers[PEERS_MAX]; extern size_t channels_c, peers_c; extern const char *hostname; extern const char *host; -extern int port; +extern unsigned long port; const char *getnick(const struct Peer *peer); -void user_reg(struct Peer *peer, const char *nick, const char *user, const char *real); +enum PeerMode user_mode(char m); +void user_reg(struct Peer *peer, const char *nick, const char *user, const char *real, const char *mode); void user_remove(size_t pid); int channel_join(struct Channel *channel, struct Peer *peer); diff --git a/loop.c b/loop.c index aa3f458..cfba4b6 100644 --- a/loop.c +++ b/loop.c @@ -34,7 +34,7 @@ struct Peer peers[PEERS_MAX]; size_t peers_c; const char *host; -int port; +unsigned long port; void ircd(void) diff --git a/main.c b/main.c index c93a84d..26de6e6 100644 --- a/main.c +++ b/main.c @@ -16,6 +16,7 @@ #include "ircd.h" +#include <errno.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> @@ -38,7 +39,7 @@ main(int argc, char **argv) hostname = argv[1]; host = argv[2]; port = strtoul(argv[3], &p, 10); - if (*p || !port || port > 65535) + if (errno || *p || !port || port > 65535) errx(1, "invalid port"); #ifdef __OpenBSD__ diff --git a/reply.c b/reply.c index eaa56f4..2aa0e9b 100644 --- a/reply.c +++ b/reply.c @@ -29,8 +29,11 @@ #define M5(x, ...) ARG(x); M4(__VA_ARGS__) #define M6(x, ...) ARG(x); M5(__VA_ARGS__) #define M7(x, ...) ARG(x); M6(__VA_ARGS__) -#define GET_M(_0,_1,_2,_3,_4,_5,_6,_7,NAME,...) NAME -#define ARGS(_0, ...) GET_M(_0,__VA_ARGS__,M7,M6,M5,M4,M3,M2,M1,M0,)(__VA_ARGS__,) +#define M8(x, ...) ARG(x); M7(__VA_ARGS__) +#define M10(x, ...) ARG(x); M9(__VA_ARGS__) +#define M11(x, ...) ARG(x); M10(__VA_ARGS__) +#define GET_M(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,NAME,...) NAME +#define ARGS(_0, ...) GET_M(_0,__VA_ARGS__,M11,M10,M9,M8,M7,M6,M5,M4,M3,M2,M1,M0,)(__VA_ARGS__,) /* * REPLY macro allows to write less boilerplate for each IRC reply @@ -71,6 +74,18 @@ vreply(const struct Peer *peer, int number, va_list ap) peer->user, peer->host ), _); + REPLY(221, WRITE( + ":%s 221 %s +%s%s%s%s%s%s%s", + hostname, + getnick(peer), + peer->modes & AWAY ? "a" : "", + peer->modes & INVISIBLE ? "i" : "", + peer->modes & WALLOPS ? "w" : "", + peer->modes & RESTRICTED ? "r" : "", + peer->modes & OPER ? "o" : "", + peer->modes & LOCALOPER ? "O" : "", + peer->modes & SNOTICE ? "s" : "" + ), _); REPLY(401, WRITE( ":%s 401 %s %s :No such nick/channel", hostname, @@ -138,7 +153,18 @@ vreply(const struct Peer *peer, int number, va_list ap) getnick(peer), channel ), channel, _); - default: warn("unknown reply: %d", number); WRITE( + REPLY(484, WRITE( + ":%s 484 %s :Your connection is restricted!", + hostname, + getnick(peer) + ), _); + REPLY(501, WRITE( + ":%s 501 %s :Unknown MODE flag (+%c)", + hostname, + getnick(peer), + *m + ), m, _); + default: warn("unknown reply: %d", number); return WRITE( ":%s 421 %s err :Reply %d is not implemented yet", hostname, getnick(peer), diff --git a/user.c b/user.c index f856f6c..8131c84 100644 --- a/user.c +++ b/user.c @@ -16,7 +16,9 @@ #include "ircd.h" +#include <errno.h> #include <stddef.h> +#include <stdlib.h> #include <string.h> #include <err.h> @@ -28,15 +30,47 @@ getnick(const struct Peer *peer) return *peer->nick ? peer->nick : "*"; } +enum PeerMode +user_mode(char m) +{ + switch (m) + { + case 'a': return AWAY; + case 'i': return INVISIBLE; + case 'w': return WALLOPS; + case 'r': return RESTRICTED; + case 'o': return OPER; + case 'O': return LOCALOPER; + case 's': return SNOTICE; + default: return 0; + } +} + void -user_reg(struct Peer *peer, const char *nick, const char *user, const char *real) +user_reg(struct Peer *peer, const char *nick, const char *user, const char *real, const char *mode) { + unsigned long m; + const char *p; + if (nick) strlcpy(peer->nick, nick, sizeof(peer->nick)); if (user) strlcpy(peer->user, user, sizeof(peer->user)); if (real) strlcpy(peer->real, real, sizeof(peer->real)); + if (mode) + { + errno = 0; + m = strtoul(mode, &p, 10); + if (errno || *p) + goto skip; + + if (m & 8) + peer->modes |= INVISIBLE; + if (m & 4) + peer->modes |= WALLOPS; + } +skip: if (*peer->nick && *peer->user && *peer->real) { peer->type = CLIENT; |