sendbuf(cl);
} while (trie_findnext(&f) == 1);
}
-void sendbuf_chan_sans_self(struct client_data *client, struct channel *chan) {
+void sendbuf_list_sans_self(struct client_data *client, struct trie_node **ls, int cookie) {
struct trie_find *f = NULL;
- if (trie_findfirst(&f, &chan->members) == 1)
+ if (trie_findfirst(&f, ls) == 1)
do {
struct client_data *cl = f->n->value;
- if (client != cl)
+ if (client != cl) {
+ if (cookie) {
+ if (cookie != cl->cookie)
+ cl->cookie = cookie;
+ else
+ continue;
+ }
sendbuf(cl);
+ }
} while (trie_findnext(&f) == 1);
}
-void sendbuf_visible(struct client_data *client) {
+int get_cookie() {
static int cookie = 0;
if (++cookie == 0) {
// handle overflow
} while (trie_findnext(&f) == 1);
cookie++;
}
+ return cookie;
+}
+void sendbuf_visible(struct client_data *client) {
+ int cookie = get_cookie();
struct trie_find *f1 = NULL, *f2 = NULL;
if (trie_findfirst(&f1, &client->channels) == 1)
do {
if (argc < 2) // FIXME: error message
return 0;
(command[0] == 'P' ? msg_privmsg : msg_notice)(client, args[0], args[1]);
- if (args[0][0] == '#' || args[0][0] == '&') {
- struct channel *chan = findChannel(args[0]);
+ // TODO: extra target forms such as nick@server #hostmask $servermask
+ int is_modmsg = !!strchr("@+", args[0][0]);
+ if (strchr("#&", args[0][is_modmsg])) {
+ struct channel *chan = findChannel(args[0]+is_modmsg);
if (!chan)
return err_nosuchchannel(client, args[0]), sendbuf(client), 0;
- sendbuf_chan_sans_self(client, chan);
+ // TODO: check bans
+ 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))
+ return err_cannotsendtochan(client, chan->name), sendbuf(client), 0;
+ switch (args[0][0]) {
+ default:
+ sendbuf_list_sans_self(client, &chan->members, 0);
+ break;
+ case '+': {
+ int cookie = get_cookie();
+ sendbuf_list_sans_self(client, &chan->v, cookie);
+ sendbuf_list_sans_self(client, &chan->o, cookie);
+ break;
+ }
+ case '@':
+ sendbuf_list_sans_self(client, &chan->o, 0);
+ break;
+ }
} else {
struct client_data *cl = findClient(args[0]);
if (!cl) {
struct channel *chan = findChannel(nick);
if (!chan)
return err_nosuchchannel(client, nick), sendbuf(client), 0;
- if (!trie_get(&chan->o, client->key)
+ if (!trie_get(&chan->o, client->key))
return 0; // TODO: error
if (argc == 2) { // Type A channel modes
if (!strcmp(args[1], "+b")) {
{
copy_strf(&databuf, ":%s 403 %s %s :No such channel\r\n", hostname, client->nick, channel);
}
-#if 0
void err_cannotsendtochan(struct client_data *client, const char *channel) // 404
{
copy_strf(&databuf, ":%s 404 %s %s :Cannot send to channel\r\n", hostname, client->nick, channel);
}
+#if 0
void err_toomanychannels(struct client_data *client, const char *channel) // 405
{
copy_strf(&databuf, ":%s 405 %s %s :You have joined too many channels\r\n", hostname, client->nick, channel);