Add query functions for versions string and release revision
[clinton/bobotpp.git] / source / Commands.C
index 55cdb44..6632dc9 100644 (file)
 
 // 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 "Commands.H"
+
+#include <functional>
+
+#include "BanEntry.H"
+#include "Bot.H"
+#include "ChannelList.H"
 #include "Macros.H"
 #include "Message.H"
-#include "Commands.H"
+#include "Server.H"
+#include "ServerConnection.H"
+#include "ServerList.H"
+#include "ServerQueueItem.H"
+#include "ShitEntry.H"
+#include "ShitList.H"
+#include "StringTokenizer.H"
+#include "User.H"
+#include "UserList.H"
 #include "Utils.H"
 
+#ifdef USESCRIPTS
+#include "BotInterp.H"
+#endif
+
 
 #define CHECK_CONNECTION if (!bot->serverConnection) return NotConnected
 
@@ -35,7 +55,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;
 }
@@ -155,17 +175,91 @@ Commands::Ban(Bot *bot, String channel, String who)
         (*it)->channelMask.matches(channel) &&
         (*it)->prot >= User::NO_BAN)
       return UserProtected(who, channel);
-
-  for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
-       it != c->channelBanlist.end(); ++it)
-    if (m.matches((*it)->banMask) && (*it)->banMask.getMask() != m.getMask())
-      QUEUE->sendChannelMode(channel, "-b", (*it)->banMask.getMask());
   
-  QUEUE->sendChannelMode(channel, "+b", dest);
+  c->delBan (m);
+  c->addBan (m, -1);
+  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)
 {
@@ -205,16 +299,20 @@ Commands::Deban(Bot *bot, String channel, String who)
 
   dest = Utils::make_wildcard(dest);
   Mask m(dest);
+
+  BanList::MatchList matches = c->channelBanlist.find_matches (m);
   
-  for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
-       it != c->channelBanlist.end(); ++it)
-    if (m.matches((*it)->getMask())) {
-      // Let's see if the ban is in the shitlist
-      ShitEntry *se = bot->shitList->getShit((*it)->getMask(), channel);
-      if (!se || !se->isStillValid() ||
-          se->getShitLevel() < ShitEntry::SHIT_NODEBAN)
-        QUEUE->sendChannelMode(channel, "-b", (*it)->getMask());
-    }
+  for (BanList::MatchList::iterator it = matches.begin ();
+       it != matches.end(); 
+       ++it)
+    if (m.matches(*it))
+      {
+       // Let's see if the ban is in the shitlist
+       ShitEntry *se = bot->shitList->getShit(it->getMask(), channel);
+       if (!se || !se->isStillValid() ||
+           se->getShitLevel() < ShitEntry::SHIT_NODEBAN)
+         c->delBan (m);
+      }
 
   return Ok;
 }
@@ -277,6 +375,20 @@ Commands::DelShit(Bot *bot, String who, String maskChannel)
   return Ok;
 }
 
+Commands::deop_wildcard::deop_wildcard 
+(Bot *b, Mask &m, String &c)
+  : bot (b), mask (m), channel (c)
+{ }
+
+void
+Commands::deop_wildcard::operator() (const User &user)
+{
+  if (mask.matches(user.nick + "!" + user.userhost) 
+      && user.getProt() < User::NO_DEOP 
+      && (user.mode & User::OP_MODE))
+    QUEUE->sendChannelMode(channel, "-o", user.nick);
+} 
+
 Message
 Commands::Deop(Bot *bot, String channel, String who)
 {
@@ -291,27 +403,25 @@ Commands::Deop(Bot *bot, String channel, String who)
     return NotChannelOp(channel);
 
   if (!Utils::wildcard_p(who)) {
-    User *u = c->getUser(who);
-    if (!u)
-      return UserNotFound(who, channel);
-    if (!(u->mode & User::OP_MODE))
-      return UserNotOp(who, channel);
-    if (u->getProt() >= User::NO_DEOP)
-      return UserProtected(who, channel);
-    QUEUE->sendChannelMode(channel, "-o", who);
+    try
+      {
+       User u = c->getUser(who);
+
+       if (!(u.mode & User::OP_MODE))
+         return UserNotOp(who, channel);
+       if (u.getProt() >= User::NO_DEOP)
+         return UserProtected(who, channel);
+       QUEUE->sendChannelMode(channel, "-o", who);
+      }
+    catch (const ChannelUserList::user_not_found &e)
+      {
+       return UserNotFound(e.name, channel);
+      }
   } else {
-    Mask m(who);
-    for (std::map<String, User *, std::less<String> >::iterator
-           it = c->channelMemory.begin();
-         it != c->channelMemory.end(); ++it) {
-      if (m.matches((*it).second->nick + "!" +
-                    (*it).second->userhost) &&
-          (*it).second->getProt() < User::NO_DEOP &&
-          ((*it).second->mode & User::OP_MODE))
-        QUEUE->sendChannelMode(channel, "-o", (*it).second->nick);
-    }
+    Mask m (who);
+    deop_wildcard f (bot, m, channel);
+    c->for_each_channel_users (f);
   }
-
   return Ok;
 }
 
@@ -360,7 +470,7 @@ Commands::Join(Bot *bot, String channel, String key)
   // We don't trust the user...
   if (!CHANNEL(channel)) {
     if (bot->wantedChannels[channel])
-      bot->wantedChannels[channel]->key = key;
+      bot->wantedChannels[channel]->key = static_cast<std::string> (key);
     else {
       bot->wantedChannels[channel] = new wantedChannel("", "", key);
     }
@@ -385,6 +495,19 @@ Commands::Keep(Bot *bot, String channel, String modes)
   return Ok;  
 }
 
+Commands::kick_wildcard::kick_wildcard 
+(Bot *b, Mask &m, String &c, String &r)
+  : bot (b), mask (m), channel (c), reason (r)
+{ }
+
+void
+Commands::kick_wildcard::operator() (const User &user)
+{
+  if (mask.matches(user.nick + "!" + user.userhost) &&
+      user.getProt() < User::NO_KICK)
+    QUEUE->sendKick(channel, user.nick, reason);
+} 
+
 Message
 Commands::Kick(Bot *bot, String channel, String who, String reason)
 {
@@ -400,22 +523,22 @@ Commands::Kick(Bot *bot, String channel, String who, String reason)
 
   if (Utils::wildcard_p(who)) {
     Mask m(who);
-    for (std::map<String, User *, std::less<String> >::iterator it =
-           c->channelMemory.begin();
-         it != c->channelMemory.end();
-         ++it)
-      if (m.matches((*it).second->nick + "!" +
-                    (*it).second->userhost) &&
-          (*it).second->getProt() < User::NO_KICK)
-        QUEUE->sendKick(channel, (*it).second->nick, reason);
+    kick_wildcard f (bot, m, channel, reason);
+    c->for_each_channel_users (f);
   } else {
-    User * u = c->getUser(who);
-    if (!u)
-      return UserNotFound(who, channel);
-    if (u->getProt() < User::NO_KICK)
-      QUEUE->sendKick(channel, who, reason);
-    else
-      return UserProtected(who, channel);
+    try
+      {
+       User u = c->getUser(who);
+
+       if (u.getProt() < User::NO_KICK)
+         QUEUE->sendKick(channel, who, reason);
+       else
+         return UserProtected(who, channel);
+      }
+    catch (const ChannelUserList::user_not_found &e)
+      {
+       return UserNotFound(e.name, channel);
+      }
   }
 
   return Ok;
@@ -488,7 +611,13 @@ Commands::Msg(Bot *bot, String who, String message)
       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;
 }
@@ -503,6 +632,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();
@@ -515,7 +654,7 @@ Commands::Nick(Bot *bot, String nick)
 {
   CHECK_CONNECTION;
 
-  if (nick == "" || !Utils::valid_nickname_p(nick))
+  if (nick == "" || !Utils::valid_nickname_p(bot, nick))
     return InvalidNick(nick);
   
   bot->wantedNickName = nick;
@@ -538,7 +677,13 @@ Commands::Notice(Bot *bot, String who, String message)
   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;
 }
@@ -558,16 +703,21 @@ Commands::Op(Bot *bot, String channel, String who)
 
   if (Utils::wildcard_p(who))
     return MassOpNotAllowed;
+  
+  try
+    {
+      User u = c->getUser(who);
 
-  User *u = c->getUser(who);
-  if (!u)
-    return UserNotFound(who, channel);
-
-  ShitEntry *se = bot->shitList->getShit(who, channel);
-  if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP)
-    return UserOnShitList(who);
-
-  QUEUE->sendChannelMode(channel, "+o", who);
+      ShitEntry *se = bot->shitList->getShit(who, channel);
+      if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP)
+       return UserOnShitList(who);
+      
+      QUEUE->sendChannelMode(channel, "+o", who);
+    }
+  catch (const ChannelUserList::user_not_found &e)
+    {
+      return UserNotFound(e.name, channel);
+    }
 
   return Ok;
 }
@@ -645,7 +795,7 @@ Commands::SetVersion(Bot *bot, String str)
   if (str.length() == 0)
     return InvalidParameters;
 
-  bot->versionString = str;
+  bot->set_version (str);
   return Ok;
 }
 
@@ -659,35 +809,20 @@ Commands::TBan(Bot *bot, String channel, String who, int seconds)
 
   // 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);
-    }
-
+    return InvalidTime(seconds);
+  
   // Look for user
   if (!Utils::wildcard_p(who))
-    {
-      dest = bot->getUserhost(channel, 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::make_wildcard(dest);
   Mask m(dest);
@@ -705,20 +840,9 @@ Commands::TBan(Bot *bot, String channel, String who, int seconds)
        }
     }
 
-  // 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());
-       }
-    }
 
-  // Ban them
-  CHANNEL(channel)->addBan(dest, seconds);
-  QUEUE->sendChannelMode(channel, "+b", dest);
-  bot->todoList->addDeban(channel, dest, seconds);
+  //  c->delBan (dest);
+  c->addBan(dest, seconds);
 
   return Ok;
 }
@@ -774,3 +898,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;
+    }
+}
+
+