From: Egor Date: Fri, 26 Jan 2024 11:33:56 +0000 (+0200) Subject: move channel MODE setting into a separate func X-Git-Url: https://git.patchysicp.xyz/?a=commitdiff_plain;h=d2337f8621efe1155fccc7871a7291f704a92804;p=patchyircd.git move channel MODE setting into a separate func --- diff --git a/src/irc.c b/src/irc.c index b3f1acc..584a7b4 100644 --- a/src/irc.c +++ b/src/irc.c @@ -903,175 +903,7 @@ saslcleanup: if (any) return 0; } - int is_plus; - char *p = args[1]; - switch (*p++) { - case '+': is_plus = 1; break; - case '-': is_plus = 0; break; - default: goto unknown; - } - map_t *list; - char **argp = &args[2]; - while (*p) { - switch (*p) { - case '+': is_plus = 1; break; - case '-': is_plus = 0; break; -#define MSG_CHANDMODE(m) \ - copy_strf(&databuf, ":%s!%s@%s MODE %s %s"m"\r\n", \ - client->nick, client->username, client->hostname, \ - chan->name, is_plus?"+":"-") - case 'P': - if (!(client->umode & UMODE_OPER)) - break; - SETBIT(chan->dmode, DMODE_PERSIST, is_plus); - MSG_CHANDMODE("P"); - chanlog(), sendbuf_chan(chan); - break; - case 'i': - SETBIT(chan->dmode, DMODE_INVITEONLY, is_plus); - MSG_CHANDMODE("i"); - chanlog(), sendbuf_chan(chan); - break; - case 'm': - SETBIT(chan->dmode, DMODE_MODERATED, is_plus); - MSG_CHANDMODE("m"); - chanlog(), sendbuf_chan(chan); - break; - case 'n': - SETBIT(chan->dmode, DMODE_NOEXTERNAL, is_plus); - MSG_CHANDMODE("n"); - chanlog(), sendbuf_chan(chan); - break; - case 's': - SETBIT(chan->dmode, DMODE_SECRET, is_plus); - MSG_CHANDMODE("s"); - chanlog(), sendbuf_chan(chan); - break; - case 't': - SETBIT(chan->dmode, DMODE_TOPICPROT, is_plus); - MSG_CHANDMODE("t"); - chanlog(), sendbuf_chan(chan); - break; - case 'l': - if (is_plus) { - int x = 0; - if (!*argp) { - // FIXME: not enough args error - } else if (sscanf(*argp, "%u", &x) != 1 || x < 0) { - // FIXME: bad arg error - argp++; - } else { - chan->member_limit = x; - copy_strf(&databuf, ":%s!%s@%s MODE %s +l %u\r\n", - client->nick, client->username, client->hostname, - chan->name, x); - chanlog(), sendbuf_chan(chan); - argp++; - } - } else { - chan->member_limit = -1; - MSG_CHANDMODE("l"); - chanlog(), sendbuf_chan(chan); - } - break; - case 'k': - if (is_plus) { - if (!*argp) { - // FIXME: not enough args error - break; - } else if (strchr(*argp, ',') || strchr(*argp, ' ')) { - err_invalidkey(client, chan), sendbuf(client); - argp++; - break; - } - if (chan->chankey) - free(chan->chankey); - chan->chankey = mystrdup(*argp); - if (!chan->chankey) - abort(); - } else { - free(chan->chankey); - chan->chankey = NULL; - if (*argp) // unused argument - argp++; - } - copy_strf(&databuf, ":%s!%s@%s MODE %s %sk %s\r\n", - client->nick, client->username, client->hostname, - chan->name, is_plus?"+":"-", is_plus?*argp:"*"); - chanlog(), sendbuf_chan(chan); - break; - case 'b': - list = &chan->listb; - goto set_list; - case 'e': - list = &chan->liste; - goto set_list; - case 'I': - list = &chan->listI; - goto set_list; - case 'q': - list = &chan->listq; - goto set_list; - case 'w': - if (!*argp) // TODO: error msg - break; - if (argp[0][0] == 'o') - list = &chan->listwo; - else if (argp[0][0] == 'v') - list = &chan->listwv; - else - break; // TODO: error msg - if (argp[0][1] != ':') - break; // TODO: error msg - argp[0] += 2; - goto set_list; - set_list: { - if(!*argp) // TODO: error msg - break; - char *mask = *argp++; - if (strchr(mask, ' ')) - break; // TODO: error msg - stringlower(mask); - if (map_set(list, mask, is_plus ? mask /* dummy */ : NULL, NULL) == -1) - abort(); - char which[2] = {*p, 0}; - copy_strf(&databuf, ":%s!%s@%s MODE %s %s%s %s\r\n", - client->nick, client->username, client->hostname, - chan->name, is_plus?"+":"-", which, mask); - // TODO: limit to ops - chanlog(), sendbuf_chan(chan); - break; - } - case 'v': - case 'o': { - if(!*argp) - break; - const char *nick = *argp++; - char which[2] = {*p, 0}; - struct client_data *cl = findClient(nick); - if (!cl) { - err_nosuchnick(client, nick), sendbuf(client); - break; - } - if (!map_get(&chan->members, cl->key)) { - err_usernotinchannel(client, cl->nick, chan), sendbuf(client); - break; - } - if (map_set(*p == 'o' ? &chan->o : &chan->v, cl->key, is_plus ? cl : NULL, NULL) == -1) - abort(); - copy_strf(&databuf, ":%s!%s@%s MODE %s %s%s %s\r\n", - client->nick, client->username, client->hostname, - chan->name, is_plus?"+":"-", which, cl->nick); - sendbuf_chan(chan); - break; - } - default: - err_unknownmode(client, *p); - sendbuf(client); - break; - } - p++; - } + channel_mode(client, chan, args+1); } } } else if(strcmp(command, "LIST") == 0) { @@ -1728,6 +1560,179 @@ void channel_kill(struct channel *chan) free(chan->chankey); free(chan); } +void channel_mode(struct client_data *client, struct channel *chan, char *args[]) { + int is_plus; + char *p = args[0]; + switch (*p++) { + case '+': is_plus = 1; break; + case '-': is_plus = 0; break; + default: + err_unknowncommand(client, "MODE"), sendbuf(client); + return; + } + map_t *list; + char **argp = &args[1]; + while (*p) { + switch (*p) { + case '+': is_plus = 1; break; + case '-': is_plus = 0; break; +#define MSG_CHANDMODE(m) \ + copy_strf(&databuf, ":%s!%s@%s MODE %s %s"m"\r\n", \ + client->nick, client->username, client->hostname, \ + chan->name, is_plus?"+":"-") + case 'P': + if (!(client->umode & UMODE_OPER)) + break; + SETBIT(chan->dmode, DMODE_PERSIST, is_plus); + MSG_CHANDMODE("P"); + chanlog(), sendbuf_chan(chan); + break; + case 'i': + SETBIT(chan->dmode, DMODE_INVITEONLY, is_plus); + MSG_CHANDMODE("i"); + chanlog(), sendbuf_chan(chan); + break; + case 'm': + SETBIT(chan->dmode, DMODE_MODERATED, is_plus); + MSG_CHANDMODE("m"); + chanlog(), sendbuf_chan(chan); + break; + case 'n': + SETBIT(chan->dmode, DMODE_NOEXTERNAL, is_plus); + MSG_CHANDMODE("n"); + chanlog(), sendbuf_chan(chan); + break; + case 's': + SETBIT(chan->dmode, DMODE_SECRET, is_plus); + MSG_CHANDMODE("s"); + chanlog(), sendbuf_chan(chan); + break; + case 't': + SETBIT(chan->dmode, DMODE_TOPICPROT, is_plus); + MSG_CHANDMODE("t"); + chanlog(), sendbuf_chan(chan); + break; + case 'l': + if (is_plus) { + int x = 0; + if (!*argp) { + // FIXME: not enough args error + } else if (sscanf(*argp, "%u", &x) != 1 || x < 0) { + // FIXME: bad arg error + argp++; + } else { + chan->member_limit = x; + copy_strf(&databuf, ":%s!%s@%s MODE %s +l %u\r\n", + client->nick, client->username, client->hostname, + chan->name, x); + chanlog(), sendbuf_chan(chan); + argp++; + } + } else { + chan->member_limit = -1; + MSG_CHANDMODE("l"); + chanlog(), sendbuf_chan(chan); + } + break; + case 'k': + if (is_plus) { + if (!*argp) { + // FIXME: not enough args error + break; + } else if (strchr(*argp, ',') || strchr(*argp, ' ')) { + err_invalidkey(client, chan), sendbuf(client); + argp++; + break; + } + if (chan->chankey) + free(chan->chankey); + chan->chankey = mystrdup(*argp); + if (!chan->chankey) + abort(); + } else { + free(chan->chankey); + chan->chankey = NULL; + if (*argp) // unused argument + argp++; + } + copy_strf(&databuf, ":%s!%s@%s MODE %s %sk %s\r\n", + client->nick, client->username, client->hostname, + chan->name, is_plus?"+":"-", is_plus?*argp:"*"); + chanlog(), sendbuf_chan(chan); + break; + case 'b': + list = &chan->listb; + goto set_list; + case 'e': + list = &chan->liste; + goto set_list; + case 'I': + list = &chan->listI; + goto set_list; + case 'q': + list = &chan->listq; + goto set_list; + case 'w': + if (!*argp) // TODO: error msg + break; + if (argp[0][0] == 'o') + list = &chan->listwo; + else if (argp[0][0] == 'v') + list = &chan->listwv; + else + break; // TODO: error msg + if (argp[0][1] != ':') + break; // TODO: error msg + argp[0] += 2; + goto set_list; + set_list: { + if(!*argp) // TODO: error msg + break; + char *mask = *argp++; + if (strchr(mask, ' ')) + break; // TODO: error msg + stringlower(mask); + if (map_set(list, mask, is_plus ? mask /* dummy */ : NULL, NULL) == -1) + abort(); + char which[2] = {*p, 0}; + copy_strf(&databuf, ":%s!%s@%s MODE %s %s%s %s\r\n", + client->nick, client->username, client->hostname, + chan->name, is_plus?"+":"-", which, mask); + // TODO: limit to ops + chanlog(), sendbuf_chan(chan); + break; + } + case 'v': + case 'o': { + if(!*argp) + break; + const char *nick = *argp++; + char which[2] = {*p, 0}; + struct client_data *cl = findClient(nick); + if (!cl) { + err_nosuchnick(client, nick), sendbuf(client); + break; + } + if (!map_get(&chan->members, cl->key)) { + err_usernotinchannel(client, cl->nick, chan), sendbuf(client); + break; + } + if (map_set(*p == 'o' ? &chan->o : &chan->v, cl->key, is_plus ? cl : NULL, NULL) == -1) + abort(); + copy_strf(&databuf, ":%s!%s@%s MODE %s %s%s %s\r\n", + client->nick, client->username, client->hostname, + chan->name, is_plus?"+":"-", which, cl->nick); + sendbuf_chan(chan); + break; + } + default: + err_unknownmode(client, *p); + sendbuf(client); + break; + } + p++; + } +} struct client_data *findClient(const char *nickname) { char key[MAX_NICKLEN]; diff --git a/src/irc.h b/src/irc.h index 0a1f9e4..b9f88dd 100644 --- a/src/irc.h +++ b/src/irc.h @@ -21,5 +21,6 @@ void channel_sendnames(struct client_data *client, struct channel *chan); void channel_join(struct client_data *client, const char *channel, const char *chankey); void channel_part(struct client_data *client, struct channel *chan, const char *reason, struct client_data *kicker); void channel_kill(struct channel *chan); +void channel_mode(struct client_data *client, struct channel *chan, char *args[]); extern struct dynarr databuf; #endif