void sendbuf_list_sans_self(struct client_data *client, map_t *ls, int cookie) {
sendbuf_list_sans_self_caps(client, ls, cookie, 0, 0);
}
+void sendbuf_monitor(const char *nick, int cookie, int positive, int negative)
+{
+ struct client_data *cl;
+ map_foreach(&client_map, 0, &cl)
+ if (map_get(&cl->monitor, nick)) {
+ if (cookie) {
+ if (cookie != cl->cookie)
+ cl->cookie = cookie;
+ else
+ continue;
+ }
+ if (!(~cl->caps & positive) && !(cl->caps & negative))
+ sendbuf(cl);
+ }
+}
int get_cookie() {
static int cookie = 0;
if (++cookie == 0) {
}
return cookie;
}
-void sendbuf_visible_caps(struct client_data *client, int positive, int negative) {
+int sendbuf_visible_caps(struct client_data *client, int positive, int negative) {
int cookie = get_cookie();
struct channel *chan;
map_foreach(&client->channels, 0, &chan)
sendbuf_list_sans_self_caps(client, &chan->members, cookie, positive, negative);
+ return cookie;
}
void sendbuf_visible(struct client_data *client) {
sendbuf_visible_caps(client, 0, 0);
{ "extended-join", CAP_EXTENDEDJOIN },
{ "away-notify", CAP_AWAYNOTIFY },
{ "invite-notify", CAP_INVITENOTIFY },
+ { "extended-monitor", CAP_EXTENDEDMONITOR },
{ 0, 0 }
};
rpl_unaway(client), sendbuf(client);
}
msg_away(client);
- sendbuf_visible_caps(client, CAP_AWAYNOTIFY, 0);
+ int cookie = sendbuf_visible_caps(client, CAP_AWAYNOTIFY, 0);
+ sendbuf_monitor(client->key, cookie, CAP_AWAYNOTIFY|CAP_EXTENDEDMONITOR, 0);
+ } else if(strcmp(command, "MONITOR") == 0) {
+ if (!is_registered(client))
+ return err_notregistered(client), sendbuf(client), 0;
+ if (argc == 0)
+ return err_needmoreparams(client, command), sendbuf(client), 0;
+ if (!args[0][0] || args[0][1])
+ return err_needmoreparams(client, command), sendbuf(client), 0; /* FIXME: wrong error */
+ switch (args[0][0]) {
+ case '+': {
+ if (argc < 2)
+ return err_needmoreparams(client, command), sendbuf(client), 0;
+ if (strchr(args[1], ' '))
+ return err_needmoreparams(client, command), sendbuf(client), 0; /* FIXME: wrong error */
+ stringlower(args[1]);
+ char *p = args[1];
+ do {
+ char *nick = p;
+ if ((p = strchr(nick, ',')))
+ *p++ = '\0';
+ /* TODO: rpl_monlistfull */
+ if (map_set(&client->monitor, nick, /* dummy */ nick, 0) == -1)
+ abort();
+ struct client_data *cl = map_get(&client_map, nick);
+ if (cl)
+ rpl_mononline(client, cl), sendbuf(client);
+ else
+ rpl_monoffline(client, nick), sendbuf(client);
+ } while (p);
+ break;
+ }
+ case '-': {
+ if (argc < 2)
+ return err_needmoreparams(client, command), sendbuf(client), 0;
+ if (strchr(args[1], ' '))
+ return err_needmoreparams(client, command), sendbuf(client), 0; /* FIXME: wrong error */
+ stringlower(args[1]);
+ char *p = args[1];
+ do {
+ char *nick = p;
+ if ((p = strchr(nick, ',')))
+ *p++ = '\0';
+ map_unset(&client->monitor, nick, 0);
+ } while (p);
+ break;
+ }
+ case 'C':
+ map_free(&client->monitor);
+ break;
+ case 'L': {
+ const char *key;
+ map_foreach(&client->monitor, &key, 0)
+ rpl_monlist(client, key), sendbuf(client);
+ rpl_endofmonlist(client), sendbuf(client);
+ break;
+ }
+ case 'S': {
+ const char *key;
+ map_foreach(&client->monitor, &key, 0) {
+ struct client_data *cl = map_get(&client_map, key);
+ if (cl)
+ rpl_mononline(client, cl), sendbuf(client);
+ else
+ rpl_monoffline(client, key), sendbuf(client);
+ }
+ break;
+ }
+ default:
+ return err_needmoreparams(client, command), sendbuf(client), 0; /* FIXME: wrong error */
+ }
#ifdef HAS_LUA
} else if(strcmp(command, "LUA") == 0) {
if (argc < 1)
msg_nick(client, nickname);
sendbuf(client);
sendbuf_visible(client);
+ rpl_monoffline(0, client->key), sendbuf_monitor(client->key, 0, 0, 0);
map_unset(&client_map, client->key, NULL);
struct channel *chan;
map_foreach(&client->channels, 0, &chan) {
abort();
if (map_set(&client_map, client->key, client, 0) == -1)
abort();
+ rpl_mononline(0, client), sendbuf_monitor(client->key, 0, 0, 0);
return;
}
}
void rpl_isupport(struct client_data *client) // 005
{
- copy_strf(&databuf, ":%s 005 %s NETWORK=PatchyIRC CASEMAPPING=ascii NICKLEN=%u EXCEPTS=e INVEX=I MAXTARGETS=1 CHANMODES=beIqw,k,l,Pimnst CHANTYPES=#& PREFIX=(ov)@+ STATUSMSG=@+ BOT=B WHOX :are supported by this server\r\n", hostname, client->nick, MAX_NICKLEN-1);
+ copy_strf(&databuf, ":%s 005 %s NETWORK=PatchyIRC CASEMAPPING=ascii NICKLEN=%u EXCEPTS=e INVEX=I MAXTARGETS=1 CHANMODES=beIqw,k,l,Pimnst CHANTYPES=#& PREFIX=(ov)@+ STATUSMSG=@+ BOT=B WHOX MONITOR :are supported by this server\r\n", hostname, client->nick, MAX_NICKLEN-1);
}
#if 0
{
copy_strf(&databuf, ":%s 729 %s %s q :End of channel quiet list\r\n", hostname, client->nick, chan->name);
}
+void rpl_mononline(struct client_data *client, struct client_data *cl) // 730
+{
+ copy_strf(&databuf, ":%s 730 %s :%s!%s@%s\r\n", hostname, client ? client->nick : "*", cl->nick, cl->username, cl->hostname);
+}
+void rpl_monoffline(struct client_data *client, const char *nick) // 731
+{
+ copy_strf(&databuf, ":%s 731 %s :%s\r\n", hostname, client ? client->nick : "*", nick);
+}
+void rpl_monlist(struct client_data *client, const char *nick) // 732
+{
+ copy_strf(&databuf, ":%s 732 %s :%s\r\n", hostname, client->nick, nick);
+}
+void rpl_endofmonlist(struct client_data *client) // 733
+{
+ copy_strf(&databuf, ":%s 733 %s :End of MONITOR list\r\n", hostname, client->nick);
+}
+#if 0
+void rpl_monlistfull(struct client_data *client, int limit, const char *targets) // 734
+{
+ copy_strf(&databuf, ":%s 734 %s %d %s :Monitor list is full.\r\n", hostname, client->nick, limit, targets);
+}
+#endif
// 900 RPL_LOGGEDIN
// 901 RPL_LOGGEDOUT
// 902 ERR_NICKLOCKED