// Parser.C -*- C++ -*- // Copyright (c) 1997, 1998 Etienne BERNARD // Copyright (C) 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "StringTokenizer.H" #include "Parser.H" #include "UserCommands.H" #include "Macros.H" #include "Utils.H" #include "ShitList.H" static struct { char *name; void (*function)(ServerConnection *, Person *, String); } functions[] = { { "001", Parser::parse001 }, /* RPL_WELCOME */ { "302", Parser::parse302 }, /* RPL_USERHOST */ { "311", Parser::parse311 }, /* RPL_WHOISUSER */ { "315", Parser::parse315 }, /* RPL_ENDOFWHO */ { "324", Parser::parse324 }, /* RPL_CHANNELMODEIS */ { "332", Parser::parse332 }, /* RPL_TOPIC */ { "352", Parser::parse352 }, /* RPL_WHOREPLY */ { "353", Parser::parse353 }, /* RPL_NAMESREPLY */ { "366", Parser::parse366 }, /* RPL_ENDOFNAMES */ { "367", Parser::parse367 }, /* RPL_BANLIST */ { "401", Parser::parse401 }, /* ERR_NOSUCHNICK */ { "433", Parser::parse433 }, /* ERR_NICKNAMEINUSE */ { "437", Parser::parse433 }, /* ERR_UNAVAILRESOURCE */ { "471", Parser::parse473 }, /* ERR_CHANNELISFULL */ { "473", Parser::parse473 }, /* ERR_INVITEONLYCHAN */ { "474", Parser::parse473 }, /* ERR_BANNEDFROMCHAN */ { "475", Parser::parse473 }, /* ERR_BADCHANNELKEY */ { "ERROR", Parser::parseError }, { "INVITE", Parser::parseInvite }, { "JOIN", Parser::parseJoin }, { "KICK", Parser::parseKick }, { "MODE", Parser::parseMode }, { "NICK", Parser::parseNick }, { "NOTICE", Parser::parseNotice }, { "PART", Parser::parsePart }, { "PING", Parser::parsePing }, { "PONG", Parser::parsePong }, { "PRIVMSG", Parser::parsePrivmsg }, { "QUIT", Parser::parseQuit }, { "TOPIC", Parser::parseTopic }, { "", Parser::parseError }, { 0, 0 } }; void Parser::parseLine(ServerConnection * cnx, String line) { StringTokenizer st(line); Person * from = 0; #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks(Hook::RAW, line, scm_listify (Utils::string2SCM(line), SCM_UNDEFINED)); #endif if (line[0] == ':') { String fromMask = st.nextToken().subString(1); if (fromMask.find('!') != -1) from = new Person(cnx->bot, fromMask); } String command = st.nextToken(); String rest = st.rest(); for (int i = 0; functions[i].name != 0; i++) if (command == functions[i].name) { functions[i].function(cnx, from, rest); break; } delete from; } void Parser::parse001(ServerConnection * cnx, Person *from, String rest) { String temp = ""; StringTokenizer st(rest); String realNick = st.nextToken(); 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 >::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.nextToken(':'); if (st.rest().length()) { st.nextToken('='); String parameters = st.rest(); parameters = parameters.subString(1); cnx->bot->userhostMap[num] = parameters; } else cnx->bot->userhostMap[num] = ""; } void Parser::parse311(ServerConnection *cnx, Person *from, String rest) { StringTokenizer st(rest); st.nextToken(); String nuh = st.nextToken() + "!"; String uh = st.nextToken() + "@"; uh = uh + st.nextToken(); 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.nextToken(); String channel = st.nextToken(); 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.nextToken(); String channel = st.nextToken(); 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.nextToken(); String channel = st.nextToken(); if (Channel *c = cnx->bot->channelList->getChannel(channel)) if (c) c->channelTopic = st.rest().subString(1); } void Parser::parse352(ServerConnection *cnx, Person *from, String rest) { StringTokenizer st(rest); st.nextToken(); String ch = st.nextToken(); String uh = st.nextToken() + "@"; uh = uh + st.nextToken(); st.nextToken(); String n = st.nextToken(); String m = st.nextToken(); 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.nextToken(); st.nextToken(); Channel * c = cnx->bot->channelList->getChannel(st.nextToken()); if (!c) return; StringTokenizer st2(st.nextToken(':')); while (st2.hasMoreTokens()) { nick = st2.nextToken(); if (nick[0] == '@') { mode = User::OP_MODE; nick = nick.subString(1); } else if (nick[0] == '+') { mode = User::VOICE_MODE; nick = nick.subString(1); } c->addNick(nick, "", mode, 0, true); } } void Parser::parse366(ServerConnection *cnx, Person *from, String rest) { StringTokenizer st(rest); st.nextToken(); String ch = st.nextToken(); if (Channel *c = cnx->bot->channelList->getChannel(ch)) c->joined = true; } void Parser::parse367(ServerConnection *cnx, Person *from, String rest) { StringTokenizer st(rest); st.nextToken(); String ch = st.nextToken(); if (Channel *c = cnx->bot->channelList->getChannel(ch)) c->addBan(st.nextToken(), -1); } void Parser::parse401(ServerConnection *cnx, Person *from, String rest) { StringTokenizer st(rest); st.nextToken(); String nick = st.nextToken(); 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.subString(0, i-1) + "_" + cnx->bot->nickName.subString(i+1); else cnx->bot->nickName = cnx->bot->nickName.subString(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.nextToken(); cnx->bot->logLine(String("Unable to join channel ") + st.nextToken() + "."); } 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.nextToken(':'); String channel = st.rest(); #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks(Hook::INVITE, nick + " " + channel, scm_listify (Utils::string2SCM(nick), Utils::string2SCM(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.nextToken('!'); String uh = st.nextToken(); StringTokenizer st2(rest); String c = st2.nextToken(':'); String mode; bool joinAndMode = false; #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks(Hook::JOIN, n + " " + c, scm_listify (Utils::string2SCM(n), Utils::string2SCM(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.nextToken('\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->getUser(n)->userkey = Utils::getKey(); cnx->queue->sendCTCP(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.nextToken(); String target = st.nextToken(); String reason = st.rest().subString(1); #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks(Hook::KICK, target + " " + from->getNick() + " " + channel + " " + reason, scm_listify (Utils::string2SCM(target), Utils::string2SCM(from->getNick()), Utils::string2SCM(channel), Utils::string2SCM(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; User *u = cnx->bot->channelList->getChannel(channel)->getUser(target); if (u && 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"); } } cnx->bot->channelList->getChannel(channel)->delNick(target); } } void Parser::parseMode(ServerConnection *cnx, Person *from, String rest) { StringTokenizer st(rest); String ch = st.nextToken(); String modes = st.rest(); #ifdef USESCRIPTS if (from) cnx->bot->botInterp->RunHooks(Hook::MODE, from->getNick() + " " + ch + " " + modes, scm_listify (Utils::string2SCM(from->getNick()), Utils::string2SCM(ch), Utils::string2SCM(modes), SCM_UNDEFINED)); #endif if (Utils::isChannel(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.subString(1); String nn_lower = nn.toLower(); #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks(Hook::NICKNAME, on_orig + " " + nn, scm_listify (Utils::string2SCM(on_orig), Utils::string2SCM(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 >::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.nextToken(); rest = st.rest().subString(1); if (rest[0] != '\001') { #ifdef USESCRIPTS if (Utils::isChannel(to)) cnx->bot->botInterp->RunHooks(Hook::PUBLIC_NOTICE, nick + " " + to + " " + rest, scm_listify (Utils::string2SCM(nick), Utils::string2SCM(to), Utils::string2SCM(rest), SCM_UNDEFINED)); else cnx->bot->botInterp->RunHooks(Hook::NOTICE, nick + " " + rest, scm_listify (Utils::string2SCM(nick), Utils::string2SCM(rest), SCM_UNDEFINED)); #endif return; } rest = rest.subString(1, rest.length() - 2); StringTokenizer st2(rest); String command = st2.nextToken(); rest = st2.rest(); #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks(Hook::CTCP_REPLY, nick + " " + command + " " + rest, scm_listify (Utils::string2SCM(nick), Utils::string2SCM(command), Utils::string2SCM(rest), SCM_UNDEFINED)); #endif if (command == "PING") { StringTokenizer st3(rest); rest = st3.nextToken(); String c = st3.rest(); if (cnx->bot->channelList->getChannel(c) && cnx->bot->channelList->getChannel(c)->getUser(nick) && cnx->bot->channelList->getChannel(c)->getUser(nick)->getAop() && !(cnx->bot->channelList->getChannel(c)->getUser(nick)->mode & User::OP_MODE) && cnx->bot->channelList->getChannel(c)->getUser(nick)->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.nextToken(); String fromUserhost = Utils::getUserhost(from->getAddress()); rest = st.rest().subString(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_listify (Utils::string2SCM(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::isChannel(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.subString(1, rest.length() - 2); if (!Utils::isChannel(to)) for (std::map >::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.subString(1, 5).toUpper() != "IDENT") && (rest.length() < 8 || rest.subString(1, 8).toUpper() != "PASSWORD") && !Utils::isChannel(to)) for (std::map >::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.nextToken(); #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks(Hook::LEAVE, n + " " + channel, scm_listify (Utils::string2SCM(n), Utils::string2SCM(channel), SCM_UNDEFINED)); #endif if (n.toLower() == cnx->bot->nickName.toLower()) { cnx->bot->logLine(String("Leaved channel ") + channel + "."); cnx->bot->channelList->delChannel(channel); } else { Channel * c = cnx->bot->channelList->getChannel(channel); if (!c) return; c->delNick(n); if (c->countOp == 0 && c->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_listify (Utils::string2SCM(n), Utils::string2SCM(rest), SCM_UNDEFINED)); #endif if (n == cnx->bot->nickName) cnx->bot->stop = true; for (std::map >::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.nextToken(); String newTopic = st.rest().subString(1); Channel *c = cnx->bot->channelList->getChannel(channel); #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks(Hook::TOPIC, from->getNick() + " " + channel + " " + newTopic, scm_listify (Utils::string2SCM(from->getNick()), Utils::string2SCM(channel), Utils::string2SCM(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 = st.nextToken().toUpper(); String nick = from->getNick(); String rest; if (st.hasMoreTokens()) rest = st.rest(); else rest = ""; #ifdef USESCRIPTS cnx->bot->botInterp->RunHooks(Hook::CTCP, nick + " " + to + " " + command + " " + rest, scm_listify (Utils::string2SCM(nick), Utils::string2SCM(to), Utils::string2SCM(command), Utils::string2SCM(rest), SCM_UNDEFINED)); #endif if (command == "PING") cnx->queue->sendCTCPReply(nick, "PING", rest); else if (command == "VERSION") cnx->queue->sendCTCPReply(nick, "VERSION", cnx->bot->versionString); else if (command == "CLOCK") { time_t diff = time(NULL) - cnx->bot->startTime; cnx->queue->sendCTCPReply(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") cnx->queue->sendCTCPReply(nick, "COMMAND", String(cnx->bot->commandChar)); else if (command == "LAG") cnx->queue->sendCTCPReply(nick, "LAG", String((long)cnx->lag) + " second(s)"); else if (command == "DCC") { StringTokenizer st2(rest); command = st2.nextToken().toUpper(); if (command == "CHAT") { // FIXME: Re-activate and debug DCC // st2.nextToken(); // unsigned long address = // htonl(strtoul((const char *)st2.nextToken(), 0, 0)); // int port = atoi((const char *)st2.rest()); // if (port >= 1024 && Utils::getLevel(cnx->bot, from->getAddress())) // cnx->bot->addDCC(from, address, port); } } #ifdef USESCRIPTS else if (command == "ACTION") { cnx->bot->botInterp->RunHooks(Hook::ACTION, from->getAddress() + " " + to + " " + rest, scm_listify (Utils::string2SCM(from->getAddress()), Utils::string2SCM(to), Utils::string2SCM(rest), SCM_UNDEFINED)); } #endif } struct userFunctionsStruct userFunctionsInit[] = { { "ACTION", UserCommands::Action, User::USER, true }, { "ADDUSER", UserCommands::AddUser, User::FRIEND, false }, { "ADDSERVER", UserCommands::AddServer, User::FRIEND, false }, { "ADDSHIT", UserCommands::AddShit, User::FRIEND, false }, { "ALIAS", UserCommands::Alias, User::MASTER, false }, { "BAN", UserCommands::Ban, User::USER, true }, { "BANLIST", UserCommands::BanList, User::USER, true }, // { "CHANGELEVEL", UserCommands::ChangeLevel, User::FRIEND, false }, { "CHANNELS", UserCommands::Channels, User::FRIEND, false }, { "CYCLE", UserCommands::Cycle, User::FRIEND, true }, { "DCCLIST", UserCommands::DCCList, User::FRIEND, false }, { "DEBAN", UserCommands::Deban, User::USER, true }, { "DELSERVER", UserCommands::DelServer, User::FRIEND, false }, { "DELUSER", UserCommands::DelUser, User::FRIEND, false }, { "DELSHIT", UserCommands::DelShit, User::FRIEND, false }, { "DEOP", UserCommands::Deop, User::TRUSTED_USER, true }, { "DIE", UserCommands::Die, User::MASTER, false }, { "DO", UserCommands::Do, User::MASTER, false }, #ifdef USESCRIPTS { "EXECUTE", UserCommands::Execute, User::MASTER, false }, #endif { "HELP", UserCommands::Help, User::NONE, false }, { "IDENT", UserCommands::Ident, User::NONE, true }, { "INVITE", UserCommands::Invite, User::USER, true }, { "JOIN", UserCommands::Join, User::FRIEND, false }, { "KEEP", UserCommands::Keep, User::FRIEND, true }, { "KICK", UserCommands::Kick, User::USER, true }, { "KICKBAN", UserCommands::KickBan, User::USER, true }, { "LOAD", UserCommands::Load, User::FRIEND, false }, #ifdef USESCRIPTS { "LOADSCRIPT", UserCommands::LoadScript, User::MASTER, false }, #endif { "LOCK", UserCommands::Lock, User::FRIEND, true }, { "MODE", UserCommands::Mode, User::FRIEND, true }, { "MSG", UserCommands::Msg, User::USER, false }, { "NAMES", UserCommands::Names, User::USER, true }, { "NEXTSERVER", UserCommands::NextServer, User::FRIEND, false }, { "NICK", UserCommands::Nick, User::FRIEND, false }, { "NSLOOKUP", UserCommands::NsLookup, User::USER, false }, { "OP", UserCommands::Op, User::TRUSTED_USER, true }, { "PART", UserCommands::Part, User::FRIEND, true }, { "PASSWORD", UserCommands::Password, User::USER, true }, { "RECONNECT", UserCommands::Reconnect, User::FRIEND, false }, { "RSPYMESSAGE", UserCommands::RSpyMessage, User::USER, false }, { "SAVE", UserCommands::Save, User::FRIEND, false }, { "SAY", UserCommands::Say, User::USER, true }, { "SERVER", UserCommands::Server, User::FRIEND, false }, { "SERVERLIST", UserCommands::ServerList, User::FRIEND, false }, { "SETVERSION", UserCommands::SetVersion, User::MASTER, false }, { "SHITLIST", UserCommands::ShitList, User::FRIEND, false }, { "SPYLIST", UserCommands::SpyList, User::USER, false }, { "SPYMESSAGE", UserCommands::SpyMessage, User::USER, false }, { "STATS", UserCommands::Stats, User::FRIEND, true }, { "TBAN", UserCommands::TBan, User::USER, true }, { "TKBAN", UserCommands::TKBan, User::USER, true }, { "TOPIC", UserCommands::Topic, User::USER, true }, { "UNLOCK", UserCommands::Unlock, User::FRIEND, true }, { "USERLIST", UserCommands::UserList, User::FRIEND, false }, { "WHO", UserCommands::Who, User::NONE, true }, { "WHOIS", UserCommands::Whois, User::FRIEND, true }, { "", 0, 0, false } }; void Parser::parseMessage(ServerConnection *cnx, Person *from, String to, String parameters) { #ifdef USESCRIPTS if (Utils::isChannel(to)) cnx->bot->botInterp->RunHooks(Hook::PUBLIC, from->getNick() + " " + to + " " + parameters, scm_listify (Utils::string2SCM(from->getNick()), Utils::string2SCM(to), Utils::string2SCM(parameters), SCM_UNDEFINED)); else cnx->bot->botInterp->RunHooks(Hook::MESSAGE, from->getNick() + " " + parameters, scm_listify (Utils::string2SCM(from->getNick()), Utils::string2SCM(parameters), SCM_UNDEFINED)); #endif if (parameters[0] != cnx->bot->commandChar) return; StringTokenizer st(parameters); String command = st.nextToken().subString(1).toUpper(); String rest = st.rest().trim(); int level; bool identified = false; std::list::iterator it; for (it = cnx->bot->userFunctions.begin(); it != cnx->bot->userFunctions.end(); ++it) if (command == (*it)->name) { if ((*it)->needsChannelName) { if (Utils::isChannel(rest)) { StringTokenizer st2(rest); to = st.nextToken(); rest = st.rest(); } if (!Utils::isChannel(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::getLevel(cnx->bot, from->getAddress(), to); User * u = 0; if (Channel *c = cnx->bot->channelList->getChannel(to)) u = c->getUser(from->getNick()); if (!u || !u->userListItem) identified = true; else identified = u->userListItem->passwd == "" || u->userListItem->identified > 0; } else { level = Utils::getLevel(cnx->bot, from->getAddress()); identified = true; } if (level >= (*it)->minLevel) { cnx->bot->logLine(from->getAddress() + " did " + command + " " + rest); #ifdef USESCRIPTS if ((*it)->argsCount != -1) { Parser::parseScriptFunction(cnx, to, (*it)->needsChannelName, (*it)->scmFunc, (*it)->argsCount, rest); } else { (*it)->function(cnx, from, to, rest); } #else (*it)->function(cnx, from, to, rest); #endif break; } 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_listify (SCM_UNDEFINED); if (needsChannelName) { args_list = gh_append2(args_list, scm_listify (Utils::string2SCM(channel), SCM_UNDEFINED)); argsCount--; } StringTokenizer st(parameters); for (int i = argsCount; i > 0; i--) { if (i == 1) param = st.rest(); else param = st.nextToken(); args_list = gh_append2(args_list, scm_listify (Utils::string2SCM(param), SCM_UNDEFINED)); } struct wrapper_data wd; wd.func = scmFunc; wd.args = args_list; gh_catch(SCM_BOOL_T, (scm_catch_body_t) scm_apply_wrapper, (void *)&wd, (scm_catch_handler_t) Interp::ErrorHandler, 0); } #endif