diff --git a/exec/ircd.js b/exec/ircd.js index e2222423cebf5b9ace9500b48020e9ba508a8b76..7bda1a7dda8542b299d7a879f32c5786d7078441 100644 --- a/exec/ircd.js +++ b/exec/ircd.js @@ -195,13 +195,16 @@ var WHO_CHANNEL =(1<<1); // c var WHO_REALNAME =(1<<2); // g var WHO_HOST =(1<<3); // h var WHO_IP =(1<<4); // i -var WHO_UMODE =(1<<5); // m -var WHO_NICK =(1<<6); // n -var WHO_OPER =(1<<7); // o -var WHO_SERVER =(1<<8); // s -var WHO_USER =(1<<9); // u -var WHO_FIRST_CHANNEL =(1<<10); // C -var WHO_MEMBER_CHANNEL =(1<<11); // M +var WHO_CLASS =(1<<5); // l +var WHO_UMODE =(1<<6); // m +var WHO_NICK =(1<<7); // n +var WHO_OPER =(1<<8); // o +var WHO_SERVER =(1<<9); // s +var WHO_TIME =(1<<10); // t +var WHO_USER =(1<<11); // u +var WHO_FIRST_CHANNEL =(1<<12); // C +var WHO_MEMBER_CHANNEL =(1<<13); // M +var WHO_SHOW_IPS_ONLY =(1<<14); // I ////////// Functions not linked to an object ////////// function ip_to_int(ip) { @@ -1023,7 +1026,7 @@ while (!server.terminated) { } } if(poll_clients.length && this.socket_select!=undefined) { - readme=socket_select(poll_clients, 1 /* seconds */); + var readme=socket_select(poll_clients, 1 /* seconds */); for(thisPolled in readme) { Clients[poll_client_map[readme[thisPolled]]].work(); } @@ -1524,9 +1527,10 @@ function IRCClient_numeric351() { this.numeric(351, VERSION + " " + servername + " :" + VERSION_STR); } -function IRCClient_numeric352(user,chan) { +function IRCClient_numeric352(user,show_ips_only,chan) { var who_mode=""; var disp; + var disphost; if (!chan) disp = "*"; @@ -1545,7 +1549,13 @@ function IRCClient_numeric352(user,chan) { } if (user.mode&USERMODE_OPER) who_mode += "*"; - this.numeric(352, disp + " " + user.uprefix + " " + user.hostname + " " + user.servername + " " + user.nick + " " + who_mode + " :" + user.hops + " " + user.realname); + + if (show_ips_only) + disphost = user.ip; + else + disphost = user.hostname; + + this.numeric(352, disp + " " + user.uprefix + " " + disphost + " " + user.servername + " " + user.nick + " " + who_mode + " :" + user.hops + " " + user.realname); } function IRCClient_numeric353(chan, str) { @@ -2385,6 +2395,12 @@ function IRCClient_do_complex_who(cmd) { who.IP = cmd[arg]; } break; + case "l": + arg++; + if (cmd[arg]) { + who.tweak_mode(WHO_CLASS,add); + who.Class = parseInt(cmd[arg]); + } case "m": // we never set -m arg++; if (cmd[arg]) { @@ -2419,6 +2435,13 @@ function IRCClient_do_complex_who(cmd) { who.tweak_mode(WHO_SERVER,add); } break; + case "t": + arg++; + if (cmd[arg]) { + who.Time = parseInt(cmd[arg]); + who.tweak_mode(WHO_TIME,add); + } + break; case "u": arg++; if (cmd[arg]) { @@ -2432,6 +2455,9 @@ function IRCClient_do_complex_who(cmd) { case "M": who.tweak_mode(WHO_MEMBER_CHANNEL,add); break; + case "I": + who.tweak_mode(WHO_SHOW_IPS_ONLY,add); + break; default: break; } @@ -2446,6 +2472,30 @@ function IRCClient_do_complex_who(cmd) { if (!who.Channel && ((whomask[0] == "#") || (whomask[0] == "&"))) who.Channel = whomask; + // Strip off any @ or + in front of a channel and set the flags. + var sf_op = false; + var sf_voice = false; + var sf_done = false; + var tmp_wc = who.Channel; + for (cc in tmp_wc) { + switch(tmp_wc[cc]) { + case "@": + sf_op = true; + who.Channel = who.Channel.slice(1); + break; + case "+": + sf_voice = true; + who.Channel = who.Channel.slice(1); + break; + default: // assume we're done + sf_done = true; + break; + } + if (sf_done) + break; + } + delete tmp_wc; // don't need this anymore. + // Now we traverse everything and apply the criteria the user passed. var who_count = 0; for (who_client in Clients) { @@ -2467,12 +2517,29 @@ function IRCClient_do_complex_who(cmd) { continue; else if ((who.del_flags&WHO_AWAY) && wc.away) continue; - if ((who.add_flags&WHO_CHANNEL) && - !wc.onchannel(who.Channel.toUpperCase())) - continue; - else if ((who.del_flags&WHO_CHANNEL) && - wc.onchannel(who.Channel.toUpperCase())) - continue; + if (who.add_flags&WHO_CHANNEL) { + if (!wc.onchannel(who.Channel.toUpperCase())) + continue; + if (sf_op && Channels[who.Channel.toUpperCase()]&& + !Channels[who.Channel.toUpperCase()].ismode( + wc.id,CHANLIST_OP)) + continue; + if(sf_voice&&Channels[who.Channel.toUpperCase()]&& + !Channels[who.Channel.toUpperCase()].ismode( + wc.id,CHANLIST_VOICE)) + continue; + } else if (who.del_flags&WHO_CHANNEL) { + if (wc.onchannel(who.Channel.toUpperCase())) + continue; + if (sf_op && Channels[who.Channel.toUpperCase()]&& + Channels[who.Channel.toUpperCase()].ismode( + wc.id,CHANLIST_OP)) + continue; + if(sf_voice&&Channels[who.Channel.toUpperCase()]&& + Channels[who.Channel.toUpperCase()].ismode( + wc.id,CHANLIST_VOICE)) + continue; + } if ((who.add_flags&WHO_REALNAME) && !match_irc_mask(wc.realname,who.RealName)) continue; @@ -2559,6 +2626,18 @@ function IRCClient_do_complex_who(cmd) { continue; else if ((who.del_flags&WHO_MEMBER_CHANNEL) && flag_M) continue; + if ((who.add_flags&WHO_TIME) && + ((time() - wc.connecttime) < who.Time) ) + continue; + else if ((who.del_flags&WHO_TIME) && + ((time() - wc.connecttime) > who.Time) ) + continue; + if ((who.add_flags&WHO_CLASS) && + (wc.ircclass != who.Class)) + continue; + else if ((who.del_flags&WHO_CLASS) && + (wc.ircclass == who.Class)) + continue; if (whomask && !wc.match_who_mask(whomask)) continue; @@ -2584,11 +2663,17 @@ function IRCClient_do_complex_who(cmd) { if (who.Channel) chan = who.Channel; + var show_ips_only; + if (who.add_flags&WHO_SHOW_IPS_ONLY) + show_ips_only = true; + else + show_ips_only = false; + // If we made it this far, we're good. if (chan && Channels[chan.toUpperCase()]) - this.numeric352(wc,Channels[chan.toUpperCase()]); + this.numeric352(wc,show_ips_only,Channels[chan.toUpperCase()]); else - this.numeric352(wc); + this.numeric352(wc,show_ips_only); who_count++; } if (!(this.mode&USERMODE_OPER) && (who_count >= max_who)) @@ -2616,6 +2701,8 @@ function Who() { this.Nick = ""; this.Server = ""; this.User = ""; + this.Time = 0; + this.Class = 0; } function Who_tweak_mode(bit,add) { @@ -2663,16 +2750,19 @@ function IRCClient_do_who_usage() { this.numeric(334,":i.e. '/WHO +a *.ca' would match all away users from *.ca"); this.numeric(334,":No args/mask matches to everything by default."); this.numeric(334,":a : User is away."); - this.numeric(334,":c <chan>: User is on <channel>, no wildcards."); + this.numeric(334,":c <chan>: User is on <@+><#channel>, no wildcards. Can check +o/+v."); this.numeric(334,":g <rnam>: Check against realname field, wildcards allowed."); this.numeric(334,":h <host>: Check user's hostname, wildcards allowed."); this.numeric(334,":i <ip> : Check against IP address, wildcards allowed."); + this.numeric(334,":l <clas>: User is a member of <clas> irc class as defined on a Y:Line."); this.numeric(334,":m <umde>: User has <umodes> set, -+ allowed."); this.numeric(334,":n <nick>: User's nickname matches <nick>, wildcards allowed."); this.numeric(334,":o : User is an IRC Operator."); this.numeric(334,":s <srvr>: User is on <server>, wildcards allowed."); + this.numeric(334,":t <time>: User has been on for more than (+) or less than (-) <time> secs."); this.numeric(334,":u <user>: User's username field matches, wildcards allowed."); this.numeric(334,":C : Only display first channel that the user matches."); + this.numeric(334,":I : Only return IP addresses (as opposed to hostnames.)"); this.numeric(334,":M : Only check against channels you're a member of."); this.numeric(315,"? :End of /WHO list. (Usage)"); }