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