*p++ = '\0';
return umodes;
}
+int match_list(struct client_data *cl, struct trie_node **list)
+{
+ struct trie_find *f = NULL;
+ if (trie_findfirst(&f, list) == 1)
+ do {
+ if (irc_glob(cl->nuh, f->key)) {
+ free(f);
+ return 1;
+ }
+ } while (trie_findnext(&f) == 1);
+ return 0;
+}
int parsePacket(struct client_data *client) {
char *source = NULL;
char *command = NULL;
struct channel *chan = findChannel(args[0]+is_modmsg);
if (!chan)
return err_nosuchchannel(client, args[0]), sendbuf(client), 0;
- // TODO: check bans
+ if (match_list(client, &chan->listq))
+ return err_cannotsendtochan(client, chan->name), sendbuf(client), 0;
+ if (match_list(client, &chan->listb) && !match_list(client, &chan->liste))
+ return err_cannotsendtochan(client, chan->name), sendbuf(client), 0;
+ // TODO: actual invites
+ if (chan->dmode & DMODE_INVITEONLY && !match_list(client, &chan->listI))
+ return err_cannotsendtochan(client, chan->name), sendbuf(client), 0;
if (chan->dmode & DMODE_NOEXTERNAL && !trie_get(&chan->members, client->key))
return err_cannotsendtochan(client, chan->name), sendbuf(client), 0;
if (chan->dmode & DMODE_MODERATED && !trie_get(&chan->v, client->key) && !trie_get(&chan->o, client->key))
if (!trie_get(&chan->o, client->key))
return 0; // TODO: error
if (argc == 2) { // Type A channel modes
+ struct trie_find *f = NULL;
if (!strcmp(args[1], "+b")) {
- copy_strf(&databuf, ":%s 368 %s %s :End of channel ban list\n", hostname, client->nick, args[1]);
+ if (trie_findfirst(&f, &chan->listb) == 1)
+ do {
+ copy_strf(&databuf, ":%s 367 %s %s %s\n", hostname, client->nick, chan->name, f->key);
+ sendbuf(client);
+ } while(trie_findnext(&f) == 1);
+ copy_strf(&databuf, ":%s 368 %s %s :End of channel ban list\n", hostname, client->nick, chan->name);
sendbuf(client);
return 0;
}
if (!strcmp(args[1], "+e")) {
- copy_strf(&databuf, ":%s 349 %s %s :End of channel exception list\n", hostname, client->nick, args[1]);
+ if (trie_findfirst(&f, &chan->liste) == 1)
+ do {
+ copy_strf(&databuf, ":%s 348 %s %s %s\n", hostname, client->nick, chan->name, f->key);
+ sendbuf(client);
+ } while(trie_findnext(&f) == 1);
+ copy_strf(&databuf, ":%s 349 %s %s :End of channel exception list\n", hostname, client->nick, chan->name);
sendbuf(client);
return 0;
}
if (!strcmp(args[1], "+I")) {
- copy_strf(&databuf, ":%s 347 %s %s :End of Channel Invite Exception List\n", hostname, client->nick, args[1]);
+ if (trie_findfirst(&f, &chan->listI) == 1)
+ do {
+ copy_strf(&databuf, ":%s 346 %s %s %s\n", hostname, client->nick, chan->name, f->key);
+ sendbuf(client);
+ } while(trie_findnext(&f) == 1);
+ copy_strf(&databuf, ":%s 347 %s %s :End of Channel Invite Exception List\n", hostname, client->nick, chan->name);
+ sendbuf(client);
+ return 0;
+ }
+ if (!strcmp(args[1], "+q")) {
+ if (trie_findfirst(&f, &chan->listq) == 1)
+ do {
+ copy_strf(&databuf, ":%s 728 %s %s q %s\n", hostname, client->nick, chan->name, f->key);
+ sendbuf(client);
+ } while(trie_findnext(&f) == 1);
+ copy_strf(&databuf, ":%s 729 %s %s q :End of channel quiet list\n", hostname, client->nick, chan->name);
sendbuf(client);
return 0;
}
case '-': is_plus = 0; break;
default: goto unknown;
}
+ struct trie_node **list;
char **argp = &args[2];
while (*p) {
switch (*p) {
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;
+ set_list: {
+ if(!*argp)
+ break;
+ char *mask = *argp++;
+ if (strchr(mask, ' '))
+ break; // TODO: error msg
+ stringlower(mask);
+ trie_set(list, mask, is_plus ? mask /* dummy */ : NULL, NULL);
+ 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':
+ case 'o': {
if(!*argp)
break;
const char *nick = *argp++;
chan->name, is_plus?"+":"-", which, cl->nick);
sendbuf_chan(chan);
break;
+ }
default:
goto unknown;
}
client->nick = mystrdup(nickname);
if (!client->nick)
abort();
+ client->nuh = malloc(strlen(client->nick) + strlen(client->username) + strlen(client->hostname) + 3);
+ if (!client->nuh)
+ abort();
+ sprintf(client->nuh, "%s!%s@%s", client->nick, client->username, client->hostname);
+ stringlower(client->nuh);
client->key = mystrdup(key);
if (!client->key)
abort();
return; // error 475
if (chan->member_limit != -1 && chan->member_count >= chan->member_limit)
return; // error 471
- // TODO: check ban
- // TODO: check ban exemption
- // TODO: check invite
- // TODO: check invite exemption
+ if (match_list(client, &chan->listb) && !match_list(client, &chan->liste))
+ return; // error 474
+ // TODO: actual invites
+ if (chan->dmode & DMODE_INVITEONLY && !match_list(client, &chan->listI))
+ return; // error 474
}
}
if (trie_set(&chan->members, client->key, client, NULL) == -1)
trie_free(&chan->members);
trie_free(&chan->o);
trie_free(&chan->v);
+ trie_free(&chan->listb);
+ trie_free(&chan->liste);
+ trie_free(&chan->listI);
+ trie_free(&chan->listq);
free(chan->chankey);
free(chan);
}