// 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"
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<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 =
// 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<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_catch_body_t) scm_apply_wrapper,
(void *)&wd, (scm_catch_handler_t) Interp::ErrorHandler,
0);
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1