-// 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 <sys/types.h>
-#include <netinet/in.h>
-
-#include "StringTokenizer.H"
-#include "Parser.H"
-#include "UserCommands.H"
-#include "Macros.H"
-#include "Utils.H"
-#include "ShitList.H"
-
-typedef void (*fptr)(ServerConnection *, Person *, String);
-std::map<std::string, fptr, std::less<std::string> > Parser::functions;
-
-void Parser::init ()
-{
- 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_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;
- }
- */
- if (fptr temp_func = functions[command])
- temp_func (cnx, from, rest);
-
- 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) {
- // 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.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<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.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<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.subString(1, 5).toUpper() != "IDENT") &&
- (rest.length() < 8 ||
- rest.subString(1, 8).toUpper() != "PASSWORD") &&
- !Utils::isChannel(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.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<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.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 =
- ntohl (strtoul((const char *)st2.nextToken(), 0, 0));
- int port = atoi((const char *)st2.nextToken ());
- 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<userFunction *>::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_t_catch_body) scm_apply_wrapper,
- (void *)&wd, (scm_t_catch_handler) Interp::ErrorHandler,
- 0);
-}
-#endif
+// 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 <sys/types.h>
+#include <netinet/in.h>
+
+#include "StringTokenizer.H"
+#include "Parser.H"
+#include "UserCommands.H"
+#include "Macros.H"
+#include "Utils.H"
+#include "ShitList.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_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;
+ }
+ */
+ if (fptr temp_func = functions[command])
+ temp_func (cnx, from, rest);
+ 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)
+ {
+ // 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.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 < 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.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 < 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.subString (1, 5).toUpper () != "IDENT") &&
+ (rest.length () < 8 ||
+ rest.subString (1, 8).toUpper () != "PASSWORD") &&
+ !Utils::isChannel (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.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 < 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.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 =
+ ntohl (strtoul ((const char *) st2.nextToken (), 0, 0));
+ int port = atoi ((const char *) st2.nextToken ());
+ 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;
+ userFunction * f = cnx->bot->userFunctions[command];
+ if (f)
+ {
+ if (f->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 >= 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_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_t_catch_body) scm_apply_wrapper,
+ (void *) &wd, (scm_t_catch_handler) Interp::ErrorHandler, 0);
+}
+#endif