// Parser.C -*- C++ -*- // Copyright (c) 1997, 1998 Etienne BERNARD // Copyright (C) 2002,2003,2005,2008 Clinton Ebadi // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301, USA. #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "Parser.H" #include #include #include #ifdef USESCRIPTS #include #include "BotInterp.H" #include "Interp.H" #endif #include "Bot.H" #include "Channel.H" #include "ChannelList.H" #include "Commands.H" #include "Macros.H" #include "Message.H" #include "Person.H" #include "Server.H" #include "ServerConnection.H" #include "ServerList.H" #include "ShitEntry.H" #include "ShitList.H" #include "StringTokenizer.H" #include "UserCommands.H" #include "User.H" #include "UserList.H" #include "Utils.H" typedef void (*fptr) (ServerConnection *, Person *, String); std::map < std::string, fptr, std::less < std::string > > Parser::functions; void Parser::init () { // Parser functions Parser::functions["001"] = Parser::parse001; /* RPL_WELCOME */ Parser::functions["302"] = Parser::parse302; /* RPL_USERHOST */ Parser::functions["311"] = Parser::parse311; /* RPL_WHOISUSER */ Parser::functions["315"] = Parser::parse315; /* RPL_ENDOFWHO */ Parser::functions["324"] = Parser::parse324; /* RPL_CHANNELMODEIS */ Parser::functions["332"] = Parser::parse332; /* RPL_TOPIC */ Parser::functions["352"] = Parser::parse352; /* RPL_WHOREPLY */ Parser::functions["353"] = Parser::parse353; /* RPL_NAMESREPLY */ Parser::functions["366"] = Parser::parse366; /* RPL_ENDOFNAMES */ Parser::functions["367"] = Parser::parse367; /* RPL_BANLIST */ Parser::functions["401"] = Parser::parse401; /* ERR_NOSUCHNICK */ Parser::functions["433"] = Parser::parse433; /* ERR_NICKNAMEINUSE */ Parser::functions["437"] = Parser::parse433; /* ERR_UNAVAILRESOURCE */ Parser::functions["471"] = Parser::parse473; /* ERR_CHANNELISFULL */ Parser::functions["473"] = Parser::parse473; /* ERR_INVITEONLYCHAN */ Parser::functions["474"] = Parser::parse473; /* ERR_BANNEDFROMCHAN */ Parser::functions["475"] = Parser::parse473; /* ERR_BADCHANNELKEY */ Parser::functions["ERROR"] = Parser::parseError; Parser::functions["INVITE"] = Parser::parseInvite; Parser::functions["JOIN"] = Parser::parseJoin; Parser::functions["KICK"] = Parser::parseKick; Parser::functions["MODE"] = Parser::parseMode; Parser::functions["NICK"] = Parser::parseNick; Parser::functions["NOTICE"] = Parser::parseNotice; Parser::functions["PART"] = Parser::parsePart; Parser::functions["PING"] = Parser::parsePing; Parser::functions["PONG"] = Parser::parsePong; Parser::functions["PRIVMSG"] = Parser::parsePrivmsg; Parser::functions["QUIT"] = Parser::parseQuit; Parser::functions["TOPIC"] = Parser::parseTopic; Parser::functions[""] = Parser::parseError; } void Parser::parseLine (ServerConnection * cnx, String line) { StringTokenizer st (line); Person *from = 0; #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks (Hook::RAW, line, scm_list_n (Utils:: str2scm (line), SCM_UNDEFINED)); #endif if (line[0] == ':') { String fromMask = st.next_token ().substr (1); if (fromMask.find ('!') != -1) from = new Person (cnx->bot, fromMask); } String command = st.next_token (); String rest = st.rest (); // We must use map<>::find or else a new entry will be created in // the map which will cause another lookup of the same invalid // command to segfault the bot std::map >::const_iterator cit = functions.find (command); if (cit != functions.end ()) { fptr temp_func = cit->second; temp_func (cnx, from, rest); } delete from; } void Parser::parse001 (ServerConnection * cnx, Person * from, String rest) { String temp = ""; StringTokenizer st (rest); String realNick = st.next_token (); if ((cnx->bot->nickName).toLower () != realNick.toLower ()) { // Yes, this can happen, and it was a very subtle bug cnx->bot->nickName = realNick; cnx->bot->userList->removeFirst (); cnx->bot->userList->addUserFirst (realNick + "!" + cnx->bot->userHost, "*", 0, 3, true, -1, ""); cnx->bot->lastNickNameChange = time (0); cnx->bot->rehash (); } cnx->bot->connected = true; cnx->queue->sendUserMode (cnx->bot->nickName, "+i"); cnx->queue->sendWhois (cnx->bot->nickName); for (std::map < String, wantedChannel *, std::less < String > >::iterator it = cnx->bot->wantedChannels.begin (); it != cnx->bot->wantedChannels.end (); ++it) cnx->queue->sendJoin ((*it).first, (*it).second->key); cnx->bot->logLine (String ("Connected to server ") + cnx->bot->serverList->currentServer ()-> getHostName () + " (" + String ((long) cnx->bot->serverList-> currentServer ()->getPort ()) + ")."); } void Parser::parse302 (ServerConnection * cnx, Person * from, String rest) { unsigned long num = cnx->bot->receivedUserhostID++; StringTokenizer st (rest); st.next_token (':'); if (st.rest ().length ()) { st.next_token ('='); cnx->bot->userhostMap[num] = Utils::trim_str (st.rest().substr(1)); } else cnx->bot->userhostMap[num] = ""; } void Parser::parse311 (ServerConnection * cnx, Person * from, String rest) { StringTokenizer st (rest); st.next_token (); String nuh = st.next_token () + "!"; String uh = st.next_token () + "@"; uh = uh + st.next_token (); nuh = nuh + uh; cnx->bot->userList->addUserFirst (nuh, "*", 0, 3, true, -1, ""); cnx->bot->userHost = uh; } void Parser::parse315 (ServerConnection * cnx, Person * from, String rest) { StringTokenizer st (rest); st.next_token (); String channel = st.next_token (); Channel *c = cnx->bot->channelList->getChannel (channel); if (!c) return; c->gotWho = true; } void Parser::parse324 (ServerConnection * cnx, Person * from, String rest) { StringTokenizer st (rest); st.next_token (); String channel = st.next_token (); if (Channel * c = cnx->bot->channelList->getChannel (channel)) if (c) c->parseMode (from, st.rest ()); } void Parser::parse332 (ServerConnection * cnx, Person * from, String rest) { StringTokenizer st (rest); st.next_token (); String channel = st.next_token (); if (Channel * c = cnx->bot->channelList->getChannel (channel)) if (c) c->channelTopic = st.rest ().substr (1); } void Parser::parse352 (ServerConnection * cnx, Person * from, String rest) { StringTokenizer st (rest); st.next_token (); String ch = st.next_token (); String uh = st.next_token () + "@"; uh = uh + st.next_token (); st.next_token (); String n = st.next_token (); String m = st.next_token (); int mode = 0; for (int i = 0; i < m.length (); i++) switch (m[i]) { case 'H': break; case 'G': mode |= User::AWAY_MODE; break; case '*': mode |= User::IRCOP_MODE; break; case '@': mode |= User::OP_MODE; break; case '+': mode |= User::VOICE_MODE; break; } if (Channel * c = cnx->bot->channelList->getChannel (ch)) if (c) c->addNick (n, uh, mode, cnx->bot->userList); } void Parser::parse353 (ServerConnection * cnx, Person * from, String rest) { int mode = 0; String nick; StringTokenizer st (rest); st.next_token (); st.next_token (); Channel *c = cnx->bot->channelList->getChannel (st.next_token ()); if (!c) return; StringTokenizer st2 (st.next_token (':')); while (st2.more_tokens_p ()) { nick = st2.next_token (); if (nick[0] == '@') { mode = User::OP_MODE; nick = nick.substr (1); } else if (nick[0] == '+') { mode = User::VOICE_MODE; nick = nick.substr (1); } c->addNick (nick, "", mode, 0, true); } } void Parser::parse366 (ServerConnection * cnx, Person * from, String rest) { StringTokenizer st (rest); st.next_token (); String ch = st.next_token (); if (Channel * c = cnx->bot->channelList->getChannel (ch)) c->joined = true; } void Parser::parse367 (ServerConnection * cnx, Person * from, String rest) { StringTokenizer st (rest); st.next_token (); String ch = st.next_token (); if (Channel * c = cnx->bot->channelList->getChannel (ch)) c->addBan (Mask(st.next_token ()), -1); } void Parser::parse401 (ServerConnection * cnx, Person * from, String rest) { StringTokenizer st (rest); st.next_token (); String nick = st.next_token (); if (cnx->bot->spyList.find (nick) != cnx->bot->spyList.end ()) { delete cnx->bot->spyList[nick]; cnx->bot->spyList.erase (nick); } } void Parser::parse433 (ServerConnection * cnx, Person * from, String rest) { if (cnx->bot->connected) return; if (cnx->bot->nickName.length () == 9) { int i; for (i = 0; i < cnx->bot->nickName.length () && cnx->bot->nickName[i] == '_'; i++); if (i < cnx->bot->nickName.length ()) cnx->bot->nickName = cnx->bot->nickName.substr (0, i - 1) + "_" + cnx->bot->nickName.substr (i + 1); else cnx->bot->nickName = cnx->bot->nickName.substr (0, 4) + String ((long) (rand () % 10000)); } else cnx->bot->nickName = cnx->bot->nickName + "_"; cnx->queue->sendNick (cnx->bot->nickName); } void Parser::parse473 (ServerConnection * cnx, Person * from, String rest) { StringTokenizer st (rest); st.next_token (); cnx->bot->logLine (String ("Unable to join channel ") + st.next_token () + "."); } void Parser::parseError (ServerConnection * cnx, Person * from, String rest) { cnx->bot->logLine (String ("Error from server ") + cnx->bot->serverList->currentServer ()-> getHostName () + " (" + String ((long) cnx->bot->serverList-> currentServer ()->getPort ()) + ")."); cnx->bot->nextServer (); } void Parser::parseInvite (ServerConnection * cnx, Person * from, String rest) { String nick = from->getNick (); StringTokenizer st (rest); st.next_token (':'); String channel = st.rest (); #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks (Hook::INVITE, nick + " " + channel, scm_list_n (Utils:: str2scm (nick), Utils:: str2scm (channel), SCM_UNDEFINED)); #endif if (cnx->bot->wantedChannels.find (channel) != cnx->bot->wantedChannels.end ()) cnx->queue->sendJoin (channel, cnx->bot->wantedChannels[channel]->key); } void Parser::parseJoin (ServerConnection * cnx, Person * from, String rest) { StringTokenizer st (from->getAddress ()); String n = st.next_token ('!'); String uh = st.next_token (); StringTokenizer st2 (rest); String c = st2.next_token (':'); String mode; bool joinAndMode = false; #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks (Hook::JOIN, n + " " + c, scm_list_n (Utils:: str2scm (n), Utils:: str2scm (c), SCM_UNDEFINED)); #endif // This part of code is for the combined JOIN & MODE of ircd 2.9 if (c.find ('\007') >= 0) { joinAndMode = true; StringTokenizer st3 (c); c = st3.next_token ('\007'); String m = st3.rest (); mode = c + " +" + m; for (int i = 0; i < m.length (); i++) mode = mode + " " + n; } if (n == cnx->bot->nickName) { cnx->bot->logLine (String ("Joined channel ") + c + "."); if (cnx->bot->wantedChannels.find (c) != cnx->bot->wantedChannels.end ()) cnx->bot->channelList-> addChannel (cnx, c, cnx->bot->wantedChannels[c]->keep); else cnx->bot->channelList->addChannel (cnx, c); cnx->queue->sendWho (c); cnx->queue->sendChannelMode (String ("MODE ") + c + " b"); cnx->queue->sendChannelMode (String ("MODE ") + c); } else { Channel *ch = cnx->bot->channelList->getChannel (c); if (!ch) return; ShitEntry *se = cnx->bot->shitList->getShit (n + "!" + uh, c); if (se && se->isStillValid () && se->getShitLevel () >= ShitEntry::SHIT_NOJOIN) { cnx->queue->sendChannelMode (c, "+b", se->getMask ()); cnx->queue->sendKick (c, n, se->getShitReason ()); return; } ch->addNick (n, uh, 0, cnx->bot->userList); if (ch->getUser (n).getAop () && !(ch->getUser (n).mode & User::OP_MODE) && cnx->bot->iAmOp (c)) { // This is a part of the antispoof code ch->change_user_key (n, Utils::get_key ()); Commands::CTCP (cnx->bot, n, "PING", ch->getUser(n).userkey + " " + c); } } if (joinAndMode) parseMode (cnx, 0, mode); } void Parser::parseKick (ServerConnection * cnx, Person * from, String rest) { StringTokenizer st (rest); String channel = st.next_token (); String target = st.next_token (); String reason = st.rest ().substr (1); #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks (Hook::KICK, target + " " + from->getNick () + " " + channel + " " + reason, scm_list_n (Utils:: str2scm (target), Utils:: str2scm (from-> getNick ()), Utils:: str2scm (channel), Utils:: str2scm (reason), SCM_UNDEFINED)); #endif if (target == cnx->bot->nickName) { cnx->bot->logLine (from->getAddress () + " kicked me out of channel " + channel + " (" + reason + ")."); cnx->queue->sendJoin (channel, cnx->bot->channelList-> getChannel (channel)->channelKey); cnx->bot->channelList->delChannel (channel); } else { if (!cnx->bot->channelList->getChannel (channel)) return; try { User u = cnx->bot->channelList->getChannel (channel)->getUser (target); if (u.getProt () >= User::NO_KICK) { String fromNick = from->getNick (); User v = cnx->bot->channelList->getChannel (channel)->getUser (fromNick); if (v.getProt () < User::NO_KICK) { cnx->bot->logLine (from->getAddress () + " kicked " + target + " (protected) out of channel " + channel + " (" + reason + ")."); cnx->queue->sendKick (channel, fromNick, target + " \002is protected !\002"); } } } catch (const ChannelUserList::user_not_found &e) { } cnx->bot->channelList->getChannel (channel)->delNick (target); } } void Parser::parseMode (ServerConnection * cnx, Person * from, String rest) { StringTokenizer st (rest); String ch = st.next_token (); String modes = st.rest (); #ifdef USESCRIPTS if (from) cnx->bot->botInterp->RunHooks (Hook::MODE, from->getNick () + " " + ch + " " + modes, scm_list_n (Utils:: str2scm (from-> getNick ()), Utils:: str2scm (ch), Utils:: str2scm (modes), SCM_UNDEFINED)); #endif if (Utils::channel_p (ch)) { Channel *c = cnx->bot->channelList->getChannel (ch); if (!c) return; if (from) c->parseMode (from, modes); else c->parseMode (0, modes); } } void Parser::parseNick (ServerConnection * cnx, Person * from, String rest) { String on_orig = from->getNick (); String on = on_orig.toLower (); String nn = rest.substr (1); String nn_lower = nn.toLower (); #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks (Hook::NICKNAME, on_orig + " " + nn, scm_list_n (Utils:: str2scm (on_orig), Utils:: str2scm (nn), SCM_UNDEFINED)); #endif if ((cnx->bot->nickName).toLower () == on) { cnx->bot->userList->removeFirst (); cnx->bot->userList->addUserFirst (nn + "!" + cnx->bot->userHost, "*", 0, 3, true, -1, ""); cnx->bot->lastNickNameChange = time (0); cnx->bot->nickName = nn; cnx->bot->rehash (); } if (cnx->bot->spyList.find (on) != cnx->bot->spyList.end ()) { cnx->bot->spyList[nn_lower] = cnx->bot->spyList[on]; cnx->bot->spyList.erase (on); } for (std::map < String, Channel *, std::less < String > >::iterator it = cnx->bot->channelList->begin (); it != cnx->bot->channelList->end (); ++it) if ((*it).second->hasNick (on)) (*it).second->changeNick (on, nn_lower); } void Parser::parseNotice (ServerConnection * cnx, Person * from, String rest) { String nick = ""; if (from) nick = from->getNick (); StringTokenizer st (rest); String to = st.next_token (); rest = st.rest ().substr (1); if (rest[0] != '\001') { #ifdef USESCRIPTS if (Utils::channel_p (to)) cnx->bot->botInterp->RunHooks (Hook::PUBLIC_NOTICE, nick + " " + to + " " + rest, scm_list_n (Utils:: str2scm (nick), Utils:: str2scm (to), Utils:: str2scm (rest), SCM_UNDEFINED)); else cnx->bot->botInterp->RunHooks (Hook::NOTICE, nick + " " + rest, scm_list_n (Utils:: str2scm (nick), Utils:: str2scm (rest), SCM_UNDEFINED)); #endif return; } rest = rest.substr (1, rest.length () - 2); StringTokenizer st2 (rest); String command = st2.next_token (); rest = st2.rest (); #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks (Hook::CTCP_REPLY, nick + " " + command + " " + rest, scm_list_n (Utils:: str2scm (nick), Utils:: str2scm (command), Utils:: str2scm (rest), SCM_UNDEFINED)); #endif if (command == "PING") { StringTokenizer st3 (rest); rest = st3.next_token (); String c = st3.rest (); Channel *channel = cnx->bot->channelList->getChannel (c); if (channel && channel->hasNick (nick)) { User u = cnx->bot->channelList->getChannel(c)->getUser(nick); if (u.getAop () && !(u.mode & User::OP_MODE) && u.userkey == rest) cnx->queue->sendChannelMode (c, "+o", nick); } } } void Parser::parsePrivmsg (ServerConnection * cnx, Person * from, String rest) { String nick = from->getNick (); StringTokenizer st (rest); String to = st.next_token (); String fromUserhost = Utils::get_userhost (from->getAddress ()); rest = st.rest ().substr (1); if (++(cnx->bot->ignoredUserhosts[fromUserhost]) > Bot::MAX_MESSAGES) { if (cnx->bot->ignoredUserhosts[fromUserhost] == Bot::MAX_MESSAGES + 1) { #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks (Hook::FLOOD, nick, scm_list_n (Utils:: str2scm (nick), SCM_UNDEFINED)); #endif cnx->bot->ignoredUserhosts[fromUserhost] += Bot::IGNORE_DELAY; cnx->bot->logLine (from->getAddress () + " is flooding me. We will ignore him/her/it."); if (!Utils::channel_p (to)) from-> sendNotice (String ("\002You are now being ignored for ") + String ((long) Bot::IGNORE_DELAY) + " seconds.\002"); } // The following lines reset the counter if you use the // command "!sorry" (if '!' is your command char). // This is not documented, I know. But one probably does // not want that every users can bypass the flood control // Of course, if you want this feature to remain 'secret', // do not use it in public. if (rest.toUpper () == String (cnx->bot->commandChar) + "SORRY") { cnx->bot->ignoredUserhosts[fromUserhost] = 0; from->sendNotice ("\002Don't do it again!\002"); } return; } if (rest[0] == '\001') { rest = rest.substr (1, rest.length () - 2); if (!Utils::channel_p (to)) for (std::map < String, Person *, std::less < String > >::iterator it = cnx->bot->spyList.begin (); it != cnx->bot->spyList.end (); ++it) (*it).second->sendNotice (String ("CTCP From ") + nick + ": " + rest); Parser::parseCTCP (cnx, from, to, rest); } else { if ((rest.length () < 5 || rest.substr (1, 5).toUpper () != "IDENT") && (rest.length () < 8 || rest.substr (1, 8).toUpper () != "PASSWORD") && !Utils::channel_p (to)) for (std::map < String, Person *, std::less < String > >::iterator it = cnx->bot->spyList.begin (); it != cnx->bot->spyList.end (); ++it) (*it).second->sendNotice (String ("*") + nick + "* " + rest); Parser::parseMessage (cnx, from, to, rest); } } void Parser::parsePart (ServerConnection * cnx, Person * from, String rest) { String n = from->getNick (); StringTokenizer st (rest); String channel = st.next_token (); #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks (Hook::PART, n + " " + channel, scm_list_n (Utils:: str2scm (n), Utils:: str2scm (channel), SCM_UNDEFINED)); #endif if (n.toLower () == cnx->bot->nickName.toLower ()) { cnx->bot->logLine (String ("Left channel ") + channel + "."); cnx->bot->channelList->delChannel (channel); } else { Channel *c = cnx->bot->channelList->getChannel (channel); if (!c) return; c->delNick (n); if (c->operator_count () == 0 && c->user_count () == 1) { cnx->queue->sendPart (channel); cnx->queue->sendJoin (channel, cnx->bot->wantedChannels[channel]->key); } } } void Parser::parsePing (ServerConnection * cnx, Person * from, String rest) { cnx->queue->sendPong (rest); } void Parser::parsePong (ServerConnection * cnx, Person * from, String rest) { cnx->lag = (cnx->lag + 2 * (time (NULL) - cnx->pingTime)) / 3; cnx->bot->sentPing = false; } void Parser::parseQuit (ServerConnection * cnx, Person * from, String rest) { String n = from->getNick (); #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks (Hook::SIGNOFF, n + " " + rest, scm_list_n (Utils:: str2scm (n), Utils:: str2scm (rest), SCM_UNDEFINED)); #endif if (n == cnx->bot->nickName) cnx->bot->stop = true; for (std::map < String, Channel *, std::less < String > >::iterator it = cnx->bot->channelList->begin (); it != cnx->bot->channelList->end (); ++it) (*it).second->delNick (n); } void Parser::parseTopic (ServerConnection * cnx, Person * from, String rest) { StringTokenizer st (rest); String channel = st.next_token (); String newTopic = st.rest ().substr (1); Channel *c = cnx->bot->channelList->getChannel (channel); #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks (Hook::TOPIC, from->getNick () + " " + channel + " " + newTopic, scm_list_n (Utils:: str2scm (from-> getNick ()), Utils:: str2scm (channel), Utils:: str2scm (newTopic), SCM_UNDEFINED)); #endif if (!c) return; if (c->lockedTopic && from->getNick () != cnx->bot->nickName) cnx->queue->sendTopic (channel, c->channelTopic); c->channelTopic = newTopic; } void Parser::parseCTCP (ServerConnection * cnx, Person * from, String to, String parameters) { StringTokenizer st (parameters); String command = Utils::to_upper (st.next_token ()); String nick = from->getNick (); String rest; if (st.more_tokens_p ()) rest = st.rest (); else rest = ""; #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks (Hook::CTCP, nick + " " + to + " " + command + " " + rest, scm_list_n (Utils:: str2scm (nick), Utils:: str2scm (to), Utils:: str2scm (command), Utils:: str2scm (rest), SCM_UNDEFINED)); #endif if (command == "PING") { Commands::CTCPReply (cnx->bot, nick, "PING", rest); } else if (command == "VERSION") { Commands::CTCPReply (cnx->bot, nick, "VERSION", cnx->bot->versionString); } else if (command == "CLOCK") { time_t diff = time (NULL) - cnx->bot->startTime; Commands::CTCPReply (cnx->bot, nick, "CLOCK", String ("elapsed time: ") + String ((long) (diff / 86400)) + "d" + String ((long) (diff % 86400) / 3600) + "h" + String ((long) (diff % 3600) / 60) + "m" + String ((long) (diff % 60)) + "s"); } else if (command == "COMMAND") { Commands::CTCPReply (cnx->bot, nick, "COMMAND", String (cnx->bot->commandChar)); } else if (command == "LAG") { Commands::CTCPReply (cnx->bot, nick, "LAG", String ((long) cnx->lag) + " second(s)"); } else if (command == "DCC") { StringTokenizer st2 (rest); command = Utils::to_upper (st2.next_token ()); if (command == "CHAT") { // FIXME: debug DCC st2.next_token (); unsigned long address = std::strtoul (st2.next_token ().c_str(), 0, 0); int port = std::atoi (st2.next_token().c_str()); if (port >= 1024 && Utils::get_level (cnx->bot, from->getAddress ())) cnx->bot->addDCC (from, address, port, Bot::CHAT); else cnx->bot->logLine ("DCC Chat Failed in Parser"); } } #ifdef USESCRIPTS else if (command == "ACTION") { cnx->bot->botInterp->RunHooks (Hook::ACTION, from->getNick () + " " + to + " " + rest, scm_list_n (Utils:: str2scm (from-> getNick ()), Utils:: str2scm (to), Utils:: str2scm (rest), SCM_UNDEFINED)); } #endif } void Parser::parseMessage (ServerConnection * cnx, Person * from, String to, String parameters) { #ifdef USESCRIPTS if (Utils::channel_p (to)) cnx->bot->botInterp->RunHooks (Hook::PUBLIC, from->getNick () + " " + to + " " + parameters, scm_list_n (Utils:: str2scm (from-> getNick ()), Utils:: str2scm (to), Utils:: str2scm (parameters), SCM_UNDEFINED)); else cnx->bot->botInterp->RunHooks (Hook::MESSAGE, from->getNick () + " " + parameters, scm_list_n (Utils:: str2scm (from-> getNick ()), Utils:: str2scm (parameters), SCM_UNDEFINED)); #endif if (parameters[0] != cnx->bot->commandChar) return; StringTokenizer st (parameters); String command = Utils::to_upper (st.next_token ().substr (1)); String rest = Utils::trim_str (st.rest ()); int level; bool identified = false; std::map >::const_iterator uf_iter = cnx->bot->userFunctions.find (command); userFunction * f = 0; if (uf_iter != cnx->bot->userFunctions.end ()) f = uf_iter->second; else return; if (f) { if (f->needsChannelName) { if (Utils::channel_p (rest)) { StringTokenizer st2 (rest); to = st.next_token (); rest = st.rest (); } if (!Utils::channel_p (to)) { from->sendNotice ("\002You need to supply a channel name" " for this command\002"); return; } if (!cnx->bot->channelList->getChannel (to)) { from->sendNotice (String ("\002I am not on channel\002 ") + to); return; } level = Utils::get_level (cnx->bot, from->getAddress (), to); Channel * c = cnx->bot->channelList->getChannel (to); if (c && c->hasNick (from->getNick ())) { User u = c->getUser (from->getNick ()); if (!u.userListItem) identified = true; else identified = u.userListItem->passwd == "" || u.userListItem->identified > 0; } else { identified = true; } } else { level = Utils::get_level (cnx->bot, from->getAddress ()); identified = true; } if (level >= f->minLevel) { cnx->bot->logLine (from->getAddress () + " did " + command + " " + rest); #ifdef USESCRIPTS if (f->argsCount != -1) { Parser::parseScriptFunction (cnx, to, f->needsChannelName, f->scmFunc, f->argsCount, rest); } else { f->function (cnx, from, to, rest); } #else f->function (cnx, from, to, rest); #endif } else { if (!identified) from-> sendNotice (String ("\002You are not identified on channel\002 ") + to); } } } #ifdef USESCRIPTS void Parser::parseScriptFunction (ServerConnection * cnx, String channel, bool needsChannelName, SCM scmFunc, int argsCount, String parameters) { String param; SCM args_list = scm_list_n (SCM_UNDEFINED); if (needsChannelName) { args_list = scm_append (scm_list_2 (args_list, scm_list_n (Utils:: str2scm (channel), SCM_UNDEFINED))); argsCount--; } StringTokenizer st (parameters); for (int i = argsCount; i > 0; i--) { if (i == 1) param = st.rest (); else param = st.next_token (); args_list = scm_append (scm_list_2 (args_list, scm_list_n (Utils::str2scm (param), SCM_UNDEFINED))); } struct wrapper_data wd; wd.func = scmFunc; wd.args = args_list; scm_internal_catch (SCM_BOOL_T, (scm_t_catch_body) Interp::LazyApplyWrapper, (void *) &wd, (scm_t_catch_handler) Interp::EmptyHandler, 0); } #endif