Basic multithreading support
[clinton/bobotpp.git] / source / Commands.C
index 8d289a9..5d7e3be 100644 (file)
@@ -1,6 +1,6 @@
 // Commands.C  -*- C++ -*-
 // Copyright (c) 1998 Etienne BERNARD
-// Copyright (C) 2002 Clinton Ebadi
+// Copyright (C) 2002,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
 
 // 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.
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
 
 #include "Macros.H"
 #include "Message.H"
 #include "Commands.H"
 #include "Utils.H"
+#include "StringTokenizer.H"
 
-#define Ok (Message(0, ""))
-#define NotOnChannel(c) (Message(-1, String("I am not on channel ") + (c)))
-#define NotChannelOp(c) (Message(-2, String("I am not channel op on ") + (c)))
-#define UserNotFound(w, c) (Message(-3, (w) + " is not on channel " + (c)))
-#define UserNotOp(w, c) (Message(-4, (w) + " is not channel op on " + (c)))
-#define UserProtected(w, c) (Message(-5, (w) + " is protected on " + (c)))
-#define InvalidNick(n) (Message(-6, (n) + " is not a valid nickname"))
-#define InvalidChannel(c) (Message(-7, (c) + " is not a valid channel name"))
-#define MassOpNotAllowed (Message(-8, "Mass op is not allowed."))
-#define UserOnShitList(w) (Message(-9, String("User ") + w + " is on my shitlist"))
-#define CanNotChangeTopic(c) (Message(-10, String("I can not change topic on ") + (c)))
-#define TopicLocked(c) (Message(-11, String("Topic is locked on ") + (c)))
-#define InvalidPort(p) (Message(-12, String((long)(p)) + " is an invalid port number"))
-#define InvalidTime(t) (Message(-13, String((long)(t)) + " is an invalid time"))
-#define CanNotChangeServer (Message(-14, "I cannot change server without loosing op on one of my channels"))
-#define EmptyServerList (Message(-15, "Server list is empty"))
-#define InvalidServerNumber(n) (Message(-16, String((long)(n)) + " is an invalid server number"))
-#define InvalidParameters (Message(-17, "Invalid parameters"))
-#define NotFound(w) (Message(-18, String("I can not find ") + (w)));
-#define NotInUserlist(w) (Message(-19, (w) + " is not in my userlist"))
-#define NotInShitlist(w) (Message(-20, (w) + " is not in my shitlist"))
-#define AlreadyInUserlist(m, mc) (Message(-21, (m) + " is already in userlist on channel(s) " + (mc)))
-#define AlreadyInShitlist(m, mc) (Message(-22, (m) + " is already in shitlist on channel(s) " + (mc)))
-#define EmptyMessage (Message(-23, "Can not send an empty message"))
-#define EmptyAddressee (Message(-24, "Can not send to nobody"))
-#define NotToChannel (Message(-25, "Can not send to a channel. Use \"say\" instead."))
-#define NotConnected (Message(-26, "Not connected."))
 
 #define CHECK_CONNECTION if (!bot->serverConnection) return NotConnected
 
@@ -62,7 +37,7 @@ Commands::Action(Bot *bot, String channel, String message)
   if (message.length() == 0)
     return InvalidParameters;
 
-  QUEUE->sendCTCP (channel, "ACTION", message);
+  Commands::CTCP (bot, channel, "ACTION", message);
 
   return Ok;
 }
@@ -82,17 +57,21 @@ Commands::AddUser(Bot *bot, String who, String maskChannel, int level,
 
   String mask;
 
-  if (!Utils::isWildcard(who)) 
+  if (!Utils::wildcard_p(who)) 
     {
-    mask = bot->getUserhost("", who);
-    if (mask.length() == 0)
-      return NotFound(who);
-  }
+      mask = bot->getUserhost("", who);
+      if (mask.length() == 0)
+       {
+         return NotFound(who);
+       }
+    }
   // Aha! This was before the brace...segfault gone
-  mask = Utils::makeWildcard(mask);
+  mask = Utils::make_wildcard(mask);
 
   if (bot->userList->isInUserList(mask, maskChannel))
-    return AlreadyInUserlist(mask, maskChannel);
+    {
+      return AlreadyInUserlist(mask, maskChannel);
+    }
 
   bot->userList->addUser(mask, maskChannel, level, prot, aop, 
                         expire, password);
@@ -127,11 +106,11 @@ Commands::AddShit(Bot *bot, String mask, String maskChannel,
 
   String who = mask;
 
-  if (!Utils::isWildcard(mask)) {
+  if (!Utils::wildcard_p(mask)) {
     mask = bot->getUserhost("", who);
     if (mask.length() == 0)
       return NotFound(who);
-    mask = Utils::makeWildcard(mask);
+    mask = Utils::make_wildcard(mask);
     if (bot->shitList->getShit(mask, maskChannel))
       return AlreadyInShitlist(mask, maskChannel);
   }
@@ -160,7 +139,7 @@ Commands::Ban(Bot *bot, String channel, String who)
 
   String dest;
 
-  if (!Utils::isWildcard(who))
+  if (!Utils::wildcard_p(who))
     dest = bot->getUserhost(channel, who);
   else
     dest = who;
@@ -168,7 +147,7 @@ Commands::Ban(Bot *bot, String channel, String who)
   if (dest.length() == 0)
     return NotFound(who);
 
-  dest = Utils::makeWildcard(dest);
+  dest = Utils::make_wildcard(dest);
   Mask m(dest);
 
   for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
@@ -189,6 +168,84 @@ Commands::Ban(Bot *bot, String channel, String who)
   return Ok;
 }
 
+Message
+Commands::CTCP (Bot *bot, std::string target, std::string command,
+               std::string message)
+{
+  CHECK_CONNECTION;
+
+  if (target == "")
+    {
+      return EmptyAddressee;
+    }
+
+  if (command == "")
+    {
+      return InvalidParameters;
+    }
+
+  if (message == "")
+    {
+      return EmptyMessage;
+    }
+
+  if (Utils::channel_p (target) && !CHANNEL (target))
+    {
+      return NotOnChannel (target);
+    }
+
+
+  // Send multi-line messages as seperate privmsgs
+  StringTokenizer st_message (message);
+
+  while (st_message.more_tokens_p ('\n'))
+    {
+      QUEUE->sendCTCP (target, command, st_message.next_token ('\n'));
+    }
+
+  return Ok;
+}
+
+Message
+Commands::CTCPReply (Bot *bot, std::string target, std::string command,
+                    std::string message)
+{
+  CHECK_CONNECTION;
+
+  if (target == "")
+    {
+      return EmptyAddressee;
+    }
+
+  if (command == "")
+    {
+      return InvalidParameters;
+    }
+
+  if (message == "")
+    {
+      return EmptyMessage;
+    }
+
+  // CTCP-REPLY cannot go to a channel
+  if (Utils::channel_p (target))
+    {
+      return NotToChannel;
+    }
+
+
+  // Send multi-line messages as seperate privmsgs
+  StringTokenizer st_message (message);
+
+  while (st_message.more_tokens_p ('\n'))
+    {
+      QUEUE->sendCTCPReply (target, command, st_message.next_token ('\n'));
+    }
+
+  return Ok;
+}
+
+
 Message
 Commands::Cycle(Bot *bot, String channel)
 {
@@ -218,7 +275,7 @@ Commands::Deban(Bot *bot, String channel, String who)
 
   String dest;
 
-  if (!Utils::isWildcard(who))
+  if (!Utils::wildcard_p(who))
     dest = bot->getUserhost(channel, who);
   else
     dest = who;
@@ -226,7 +283,7 @@ Commands::Deban(Bot *bot, String channel, String who)
   if (dest.length() == 0)
     return UserNotFound(who, channel);
 
-  dest = Utils::makeWildcard(dest);
+  dest = Utils::make_wildcard(dest);
   Mask m(dest);
   
   for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
@@ -261,11 +318,11 @@ Commands::DelUser(Bot *bot, String who, String maskChannel)
 
   String dest;
 
-  if (!Utils::isWildcard(who)) {
+  if (!Utils::wildcard_p(who)) {
     dest = bot->getUserhost("", who);
     if (dest.length() == 0)
       return NotFound(who);
-    dest = Utils::makeWildcard(who);
+    dest = Utils::make_wildcard(who);
   }
 
   if (!bot->userList->isInUserList(dest, maskChannel))
@@ -285,11 +342,11 @@ Commands::DelShit(Bot *bot, String who, String maskChannel)
 
   String dest;
 
-  if (!Utils::isWildcard(who)) {
+  if (!Utils::wildcard_p(who)) {
     dest = bot->getUserhost("", who);
     if (dest.length() == 0)
       return NotFound(who);
-    dest = Utils::makeWildcard(who);
+    dest = Utils::make_wildcard(who);
   }
 
   if (!bot->shitList->getShit(dest, maskChannel))
@@ -313,7 +370,7 @@ Commands::Deop(Bot *bot, String channel, String who)
   if (!bot->iAmOp(channel))
     return NotChannelOp(channel);
 
-  if (!Utils::isWildcard(who)) {
+  if (!Utils::wildcard_p(who)) {
     User *u = c->getUser(who);
     if (!u)
       return UserNotFound(who, channel);
@@ -376,7 +433,7 @@ Commands::Join(Bot *bot, String channel, String key)
 {
   CHECK_CONNECTION;
 
-  if (!Utils::isValidChannelName(channel))
+  if (!Utils::valid_channel_name_p(channel))
     return InvalidChannel(channel);
 
   // We change the key only if we are not on the channel.
@@ -421,7 +478,7 @@ Commands::Kick(Bot *bot, String channel, String who, String reason)
   if (!bot->iAmOp(channel))
     return NotChannelOp(channel);
 
-  if (Utils::isWildcard(who)) {
+  if (Utils::wildcard_p(who)) {
     Mask m(who);
     for (std::map<String, User *, std::less<String> >::iterator it =
            c->channelMemory.begin();
@@ -494,15 +551,30 @@ Commands::Msg(Bot *bot, String who, String message)
   CHECK_CONNECTION;
 
   if (who == "")
-    return EmptyAddressee;
+    {
+      return EmptyAddressee;
+    }
 
-  if (Utils::isChannel(who))
-    return NotToChannel;
+  if (Utils::channel_p(who))
+    {
+      if (!CHANNEL(who))
+       {
+         return NotOnChannel (who);
+       }
+    }
 
   if (message == "")
-    return EmptyMessage;
+    {
+      return EmptyMessage;
+    }
 
-  QUEUE->sendPrivmsg(who, message);
+  // Send multi-line messages as seperate privmsgs
+  StringTokenizer st_message (message);
+
+  while (st_message.more_tokens_p ('\n'))
+    {
+      QUEUE->sendPrivmsg(who, st_message.next_token ('\n'));
+    }
 
   return Ok;
 }
@@ -517,6 +589,16 @@ Commands::NextServer(Bot *bot)
 
   if (!bot->canChangeServer())
     return CanNotChangeServer;
+
+#ifdef USESCRIPTS
+  // Run hooks/disconnect
+  bot->botInterp->RunHooks 
+    (Hook::DISCONNECT, 
+     bot->serverConnection->server->getHostName (),
+     scm_list_n 
+     (Utils::str2scm  (bot->serverConnection->server->getHostName ()),
+      SCM_BOOL_T));
+#endif
   
   QUEUE->sendQuit("Changing server");
   bot->nextServer();
@@ -529,7 +611,7 @@ Commands::Nick(Bot *bot, String nick)
 {
   CHECK_CONNECTION;
 
-  if (nick == "" || !Utils::isValidNickName(nick))
+  if (nick == "" || !Utils::valid_nickname_p(bot, nick))
     return InvalidNick(nick);
   
   bot->wantedNickName = nick;
@@ -546,13 +628,19 @@ Commands::Notice(Bot *bot, String who, String message)
   if (who == "")
     return EmptyAddressee;
 
-  if (Utils::isChannel(who))
-    return NotToChannel;
+  //  if (Utils::channel_p(who))
+  //    return NotToChannel;
 
   if (message == "")
     return EmptyMessage;
 
-  QUEUE->sendNotice(who, message);
+  // Send multiple lines as multiple notices
+  StringTokenizer st_message (message);
+
+  while (st_message.more_tokens_p ('\n'))
+    {
+      QUEUE->sendNotice(who, st_message.next_token ('\n'));
+    }
 
   return Ok;
 }
@@ -570,7 +658,7 @@ Commands::Op(Bot *bot, String channel, String who)
   if (!bot->iAmOp(channel))
     return NotChannelOp(channel);
 
-  if (Utils::isWildcard(who))
+  if (Utils::wildcard_p(who))
     return MassOpNotAllowed;
 
   User *u = c->getUser(who);
@@ -620,14 +708,7 @@ Commands::Reconnect(Bot *bot)
 Message
 Commands::Say(Bot *bot, String channel, String message)
 {
-  CHECK_CONNECTION;
-
-//   if (!CHANNEL(channel))
-//     return NotOnChannel(channel);
-
-  QUEUE->sendPrivmsg(channel, message);
-
-  return Ok;
+  return Commands::Msg (bot, channel, message);
 }
 
 
@@ -676,45 +757,72 @@ Commands::TBan(Bot *bot, String channel, String who, int seconds)
   CHECK_CONNECTION;
 
   Channel *c = CHANNEL(channel);
+  String dest;
 
+  // Make sure all of the inputs are valid
   if (!c)
-    return NotOnChannel(channel);
+    {
+      return NotOnChannel(channel);
+    }
 
   if (!bot->iAmOp(channel))
-    return NotChannelOp(channel);
+    {
+      return NotChannelOp(channel);
+    }
 
   if (seconds <= 0)
-    return InvalidTime(seconds);
-
-  String dest;
+    {
+      return InvalidTime(seconds);
+    }
 
-  if (!Utils::isWildcard(who))
-    dest = bot->getUserhost(channel, who);
+  // Look for user
+  if (!Utils::wildcard_p(who))
+    {
+      dest = bot->getUserhost(channel, who);
+    }
   else
-    dest = who;
+    {
+      dest = who;
+    }
 
   if (dest.length() == 0)
-    return UserNotFound(who, channel);
+    {
+      return UserNotFound(who, channel);
+    }
+
 
-  dest = Utils::makeWildcard(dest);
+  dest = Utils::make_wildcard(dest);
   Mask m(dest);
 
+  // Make sure the user isn't protected from bans
   for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
        it != bot->userList->l.end();
        it++)
-    if (m.matches((*it)->mask) &&
-        (*it)->channelMask.matches(channel) &&
-        (*it)->prot >= User::NO_BAN)
-      return UserProtected(who, channel);
+    {
+      if (m.matches((*it)->mask) &&
+         (*it)->channelMask.matches(channel) &&
+         (*it)->prot >= User::NO_BAN)
+       {
+         return UserProtected(who, channel);
+       }
+    }
 
+  // Clear existing bans on the user
   for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
        it != c->channelBanlist.end(); ++it)
-    if (m.matches((*it)->banMask))
-      QUEUE->sendChannelMode(channel, "-b", (*it)->banMask.getMask());
+    {
+      if (m.matches((*it)->banMask))
+       {
+         QUEUE->sendChannelMode(channel, "-b", (*it)->banMask.getMask());
+       }
+    }
 
+  // Ban them
   CHANNEL(channel)->addBan(dest, seconds);
   QUEUE->sendChannelMode(channel, "+b", dest);
   bot->todoList->addDeban(channel, dest, seconds);
+
+  return Ok;
 }
 
 
@@ -768,3 +876,31 @@ Commands::Unlock(Bot *bot, String channel)
 
   return Ok;
 }
+
+Message
+Commands::Who (Bot *bot, String target)
+{
+  CHECK_CONNECTION;
+
+  QUEUE->sendWho (target);
+
+  return Ok;
+}
+
+Message
+Commands::Whois (Bot *bot, String nick)
+{
+  CHECK_CONNECTION;
+
+  if (!Utils::valid_nickname_p (bot, nick))
+    {
+      return InvalidNick (nick);
+    }
+  else
+    {
+      QUEUE->sendWhois (nick);
+      return Ok;
+    }
+}
+
+