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) {
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];