Split user list from Channel into ChannelUserList
authorclinton <clinton@unknownlamer.org>
Mon, 23 Feb 2009 23:47:48 +0000 (23:47 +0000)
committerclinton <clinton@unknownlamer.org>
Mon, 23 Feb 2009 23:47:48 +0000 (23:47 +0000)
This patch is *huge* and potentially introduces a few bug, but it
*seems* ok so far. The ChannelUserList ought to be threadsafe; it was
necessary to do this as soon I will be added a bot:channel-users
function to the Scheme interface.

Doing this, naturally, exposed a number of horrid design issues that
I, as always, chose to ignore for now and instead merely cleaned up
one aspect as best as it could be given the surrounding muck. (ok,
Bobot++ isn't *terrible* but everything touches the internals of
everything so now they all have the Clap because one class caught it).

16 files changed:
source/Bot.C
source/BotThreading.C
source/Channel.C
source/Channel.H
source/ChannelUserList.C [new file with mode: 0644]
source/ChannelUserList.H [new file with mode: 0644]
source/Commands.C
source/Commands.H
source/Makefile.am
source/Parser.C
source/User.C
source/User.H
source/UserCommands.C
source/UserCommands.H
source/UserListItem.H
source/Utils.C

index cc860b9..679750e 100644 (file)
@@ -507,8 +507,8 @@ Bot::canChangeServer()
        it != channelList->end(); ++it) {
     channel = (*it).first;
     c = channelList->getChannel(channel);
-    if (c->countOp == 1 &&
-        c->count > 1 && this->iAmOp(channel))
+    if (c->operator_count () == 1 &&
+        c->user_count () > 1 && this->iAmOp(channel))
       return false;
   }
   return true;
@@ -625,7 +625,7 @@ Bot::getUserhost(String channel, String nick)
 
 
   if (c && c->hasNick(nick))
-    return c->getUser(nick)->userhost;
+    return c->getUser(nick).userhost;
 
   unsigned long num = sentUserhostID++;
 
@@ -647,8 +647,7 @@ Bot::getUserhost(String channel, String nick)
 bool
 Bot::iAmOp(String channel)
 {
-  User * me = channelList->getChannel(channel)->getUser(nickName);
-  return (me->mode & User::OP_MODE);
+  return channelList->getChannel(channel)->getUser(nickName).mode & User::OP_MODE;
 }
 
 void
index 75812b3..af31195 100644 (file)
@@ -52,21 +52,21 @@ BotMutex::~BotMutex ()
 
 void BotMutex::lock ()
 {
-  pthread_t self = pthread_self ();
-  std::cerr << "< Mutex Lock..."
-           << " Mutex: " << &mutex
-           << " Thread: " << &self
-           << std::endl;
+//   pthread_t self = pthread_self ();
+//   std::cerr << "< Mutex Lock..."
+//         << " Mutex: " << &mutex
+//         << " Thread: " << &self
+//         << std::endl;
   pthread_mutex_lock (&mutex);
 }
 
 void BotMutex::unlock ()
 {
-  pthread_t self = pthread_self ();
-  std::cerr << "> Mutex Unlock..."
-           << " Mutex: " << &mutex
-           << " Thread: " << &self
-           << std::endl;
+//   pthread_t self = pthread_self ();
+//   std::cerr << "> Mutex Unlock..."
+//         << " Mutex: " << &mutex
+//         << " Thread: " << &self
+//         << std::endl;
   pthread_mutex_unlock (&mutex);
 }
 
@@ -89,22 +89,22 @@ void BotMutex::unlock ()
 BotLock::BotLock (BotMutex & m)
   : mutex(m)
 {
-  pthread_t self = pthread_self ();
-  std::cerr << "Lock Init..."
-           << " Lock: " << this
-           << " Mutex: " << &mutex
-           << " Thread: " << &self
-           << std::endl;
+//   pthread_t self = pthread_self ();
+//   std::cerr << "Lock Init..."
+//         << " Lock: " << this
+//         << " Mutex: " << &mutex
+//         << " Thread: " << &self
+//         << std::endl;
   mutex.lock ();
 }
 
 BotLock::~BotLock ()
 {
-  pthread_t self = pthread_self ();
-  std::cerr << "Lock Destroy..."
-           << " Lock: " << this
-           << " Mutex: " << &mutex
-           << " Thread: " << &self
-           << std::endl;
+//   pthread_t self = pthread_self ();
+//   std::cerr << "Lock Destroy..."
+//         << " Lock: " << this
+//         << " Mutex: " << &mutex
+//         << " Thread: " << &self
+//         << std::endl;
   mutex.unlock ();
 }
index c0ab590..f2c54e4 100644 (file)
@@ -1,6 +1,6 @@
 // Channel.C  -*- C++ -*-
 // Copyright (c) 1997, 1998 Etienne BERNARD
-// Copyright (C) 2002,2005,2008 Clinton Ebadi
+// Copyright (C) 2002,2005,2008,2009 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
 #endif
 
 Channel::Channel(ServerConnection *c,
-                 String name, String wanted = "")
-  : channelName(name.toLower()), channelTopic(""),
+                 std::string name, std::string wanted = "")
+  : channelName(Utils::to_lower(name)), channelTopic(""),
     lockedTopic(false), channelMode(0), channelLimit(0),
-    channelKey(""), keepModes(DEFAULT_KEEPMODES), wantedModes(wanted), count(0),
-    countOp(0), joined(false), doMode(true), gotWho(false), cnx(c)
+    channelKey(""), keepModes(DEFAULT_KEEPMODES), wantedModes(wanted), 
+    channelUserlist (name),
+    joined(false), doMode(true), gotWho(false), cnx(c)
 {
-#ifdef HAVE_STL_CLEAR
-  channelMemory.clear();
-#endif
   if (c->bot->wantedChannels[channelName])
     {
       if (c->bot->wantedChannels[channelName]->keep != "")
@@ -62,104 +60,55 @@ Channel::Channel(ServerConnection *c,
 }
 
 Channel::~Channel()
-{
-  User *u;
-  std::map<String, User *, std::less<String> >::iterator it;
-
-  while (channelMemory.size() != 0) {
-    it = channelMemory.begin();
-    u = (*it).second;
-    if (u && u->userListItem && u->userListItem->identified > 0)
-      u->userListItem->identified--;
-    channelMemory.erase(it);
-    delete u;
- }
-}
+{ }
 
 void
-Channel::addNick(String n, String uh, int mode, UserList *ul,
+Channel::addNick(std::string n, std::string uh, int mode, UserList *ul,
                  bool names)
 {
-  if (User * u = getUser(n.toLower())) {
-    count--;
-    if (u->mode & User::OP_MODE)
-      countOp--;
-    channelMemory.erase(n.toLower());
-    delete u;
-  }
-
-  User *u;
-
-  if (names)
-    u = new User(n, mode);
-  else
-    u = new User(n, uh, channelName, mode, ul);
-
-  channelMemory[n.toLower()] = u;
-
-  if (u->userListItem) {
-    if (u->userListItem->identified)
-      u->userListItem->identified++;
-    else {
-      if (u->userListItem->passwd == "")
-        u->userListItem->identified = 1;
-    }
-  }
-
-  count++;
-  if (u->mode & User::OP_MODE)
-    countOp++;
+  channelUserlist.add (n, uh, mode, ul, names);
 }
 
 void
-Channel::delNick(String n)
+Channel::delNick(std::string n)
 {
-  n = n.toLower();
-  User *u = getUser(n);
-
-  if (!u)
-    return;
-
-  if (channelMemory[n]!=0) {
-    channelMemory.erase(n);
-  }
-
-  count--;
-  if (u->mode & User::OP_MODE)
-    countOp--;
-  if (u->userListItem && u->userListItem->identified > 0)
-    u->userListItem->identified--;
-  delete u;  
+  channelUserlist.del (n);
 }
 
 void
-Channel::changeNick(String on, String nn)
+Channel::changeNick(std::string on, std::string nn)
 {
-  on = on.toLower();
-  User *u = getUser(on);
-  channelMemory.erase(on);
-  channelMemory[nn.toLower()] = u;
+  channelUserlist.change_nickname (on, nn);
 }
 
 bool
-Channel::hasNick(String n)
+Channel::hasNick(const std::string &n) const
 {
-  return getUser(n.toLower()) != 0;
+  return channelUserlist.in_channel_p (n);
 }
 
-User *
-Channel::getUser(String n)
+const User
+Channel::getUser(const std::string &n) const
 {
-  User *u;
+  return channelUserlist.get (n);
+}
 
-  n = n.toLower();
+void 
+Channel::change_user_key (std::string name, std::string key)
+{
+  channelUserlist.change_user_key (name, key);
+}
 
-  if ((u = channelMemory[n]) == 0) {
-    channelMemory.erase(n);
-    return 0;
-  }
+unsigned int 
+Channel::user_count () const throw ()
+{
+  return channelUserlist.user_count ();
+}
 
-  return u;
+unsigned int 
+Channel::operator_count () const throw ()
+{
+  return channelUserlist.operator_count ();
 }
 
 void
@@ -196,21 +145,25 @@ void Channel::purge_expired_bans ()
 void
 Channel::resynchModes()
 {
-  cnx->queue->sendChannelMode(String("MODE ") + channelName +
+  cnx->queue->sendChannelMode(std::string("MODE ") + channelName +
                               " +" + cnx->bot->wantedChannels[channelName]->mode);
 }
 
 void
-Channel::parseMode(Person *from, String mode)
+Channel::parseMode(Person *from, std::string mode)
 {
   char sign = '-';
   StringTokenizer st(mode);
-  String m = st.next_token(), n;
-  User *u = 0;
+  std::string m = st.next_token(), n;
+  bool doNotObey = true; // disobey mode if server or target is protected
   if (from)
-    u = getUser(from->getNick());
-  // u == 0 if it's a server mode
-  bool doNotObey = !u || (u->getProt() <= User::NO_PROT);
+    try
+      {
+       doNotObey = getUser(from->getNick()).getProt () <= User::NO_PROT;
+      }
+    catch (ChannelUserList::user_not_found&)
+      { }
+
   if (!gotWho)
     doNotObey = false;
 
@@ -278,7 +231,7 @@ Channel::parseMode(Person *from, String mode)
       if (keepModes.find('l') != -1 && doNotObey) {
         if (sign == '-' && wantedModes.find('l') != -1)
           cnx->queue->sendChannelMode(channelName, "+l",
-                                 String((long)channelLimit));
+                                     Utils::long2str(channelLimit));
         else
           cnx->queue->sendChannelMode(channelName, "-l", "");
       }
@@ -294,51 +247,60 @@ Channel::parseMode(Person *from, String mode)
           cnx->queue->sendChannelMode(channelName, "-k", channelKey);
       }
       cnx->bot->wantedChannels[channelName]->key = (sign == '+' ? channelKey :
-                                               String(""));
+                                               std::string(""));
       break;
     case 'o':
-      n = st.next_token();
-      u = getUser(n);
-      if (joined)
-        sign == '+' ? countOp++ : countOp--;
-      if (!u)
-        break;
-      sign == '+' ? (u->mode |= User::OP_MODE) :
-        (u->mode &= ~User::OP_MODE);
-      if (sign == '-' && u->getProt() >= User::NO_DEOP) {
-        String fromNick = from->getNick();
-        User * v = getUser(fromNick);
-       if (u == v)
-          return;
-        if (v->getProt() < User::NO_DEOP)
-          cnx->queue->sendChannelMode(channelName, "-o", fromNick);
-        cnx->queue->sendChannelMode(channelName, "+o", n);
-      }
-      if (sign == '+') {
-        if (doNotObey && !from &&
-            u->getProt() < User::NO_DEOP && !u->getAop())
-          cnx->queue->sendChannelMode(channelName, "-o", n);
-        ShitEntry * se =
-          cnx->bot->shitList->getShit(n+"!"+cnx->bot->getUserhost(channelName, n),
-                                      channelName);
-        if (se && se->isStillValid() &&
-            se->getShitLevel() >= ShitEntry::SHIT_NOOP)
-          cnx->queue->sendChannelMode(channelName, "-o", n);
-        if (n.toLower() == cnx->bot->nickName.toLower() && doMode) {
-          doMode = false;
-          resynchModes();
-        }
-      }
-      break;
+      try
+       {
+         n = st.next_token();
+         User u = getUser(n);
+         // if (joined)
+         //   sign == '+' ? countOp++ : countOp--;
+         channelUserlist.change_user_mode (n, User::OP_MODE, sign != '+');
+
+         if (sign == '-' && u.getProt() >= User::NO_DEOP) {
+           std::string fromNick = from->getNick();
+           User v = getUser(fromNick);
+
+           if (n == fromNick)
+             return;
+
+           if (v.getProt() < User::NO_DEOP)
+             cnx->queue->sendChannelMode(channelName, "-o", fromNick);
+
+           cnx->queue->sendChannelMode(channelName, "+o", n);
+         }
+
+         if (sign == '+') {
+           if (doNotObey && !from &&
+               u.getProt() < User::NO_DEOP && !u.getAop())
+             cnx->queue->sendChannelMode(channelName, "-o", n);
+           ShitEntry * se =
+             cnx->bot->shitList->getShit(n+"!"+cnx->bot->getUserhost(channelName, n),
+                                         channelName);
+           if (se && se->isStillValid() &&
+               se->getShitLevel() >= ShitEntry::SHIT_NOOP)
+             cnx->queue->sendChannelMode(channelName, "-o", n);
+           if (Utils::to_lower (n) == cnx->bot->nickName.toLower() && doMode) {
+             doMode = false;
+             resynchModes();
+           }
+         }
+         break;
+       }
+      catch (ChannelUserList::user_not_found &)
+       {
+         break;
+       }
     case 'v':
-      u = getUser(st.next_token());
-      u->mode = (sign == '+' ? u->mode |= User::VOICE_MODE :
-                 u->mode &= ~User::VOICE_MODE);
+      channelUserlist.change_user_mode (st.next_token (),
+                                       User::VOICE_MODE,
+                                       sign != '+');
       break;
     case  'b':
-      String m = st.next_token();
+      std::string m = st.next_token();
       if (sign == '+')
-       channelBanlist.add (m);
+       channelBanlist.add (Mask(m));
       if (sign == '-') 
        {
         ShitEntry * se = cnx->bot->shitList->getShit(m, channelName);
@@ -347,7 +309,7 @@ Channel::parseMode(Person *from, String mode)
            se->getShitLevel() >= ShitEntry::SHIT_NODEBAN)
           cnx->queue->sendChannelMode(channelName, "+b", m);
        else
-         channelBanlist.del (m);
+         channelBanlist.del (Mask(m));
          
        }
     }
index 40caad9..838200d 100644 (file)
@@ -1,6 +1,6 @@
 // Channel.H  -*- C++ -*-
 // Copyright (c) 1997, 1998 Etienne BERNARD
-// Copyright (C) 2002,2008 Clinton Ebadi
+// Copyright (C) 2002,2008,2009 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
 
 #include <algorithm>
 #include <functional>
-#include <map>
+#include <list>
+#include <string>
 #include <vector>
 
 #include <ctime>
 
 #include "BanList.H"
-#include "String.H"
+#include "ChannelUserList.H"
+#include "Utils.H"
 
 class BanEntry;
 class Bot;
@@ -49,30 +51,28 @@ class UserList;
 // want to set/keep on these channels, and the
 // channel keys
 struct wantedChannel {
-  String mode;
-  String keep;
-  String key;
+  std::string mode;
+  std::string keep;
+  std::string key;
 
-  wantedChannel(String m, String kp, String ky)
+  wantedChannel(std::string m, std::string kp, std::string ky)
     : mode(m), keep(kp), key(ky) { }
 };
 
 class Channel {
-  String channelName;
-  String channelTopic;
+  std::string channelName;
+  std::string channelTopic;
   bool lockedTopic;
   int channelMode;
   int channelLimit;
-  String channelKey;
-  String keepModes;
-  String wantedModes;
+  std::string channelKey;
+  std::string keepModes;
+  std::string wantedModes;
   
-  int count;
-  int countOp;
   bool joined;
   bool doMode;
   bool gotWho;
-  std::map<String, User *, std::less<String> > channelMemory;
+  ChannelUserList channelUserlist;
   BanList channelBanlist;
   ServerConnection * cnx;
 
@@ -89,14 +89,19 @@ public:
     IS_LIMITED = 128        // +l <limit>
   };
   
-  Channel(ServerConnection *, String, String);
+  Channel(ServerConnection *, std::string, std::string);
   ~Channel();
 
-  void addNick(String, String, int, UserList *, bool = false);
-  void delNick(String);
-  void changeNick(String, String);
-  bool hasNick(String);
-  User * getUser(String);
+  void addNick(std::string, std::string, int, UserList *, bool = false);
+  void delNick(std::string);
+  void changeNick(std::string, std::string);
+  void change_user_key (std::string, std::string);
+  bool hasNick(const std::string &) const;
+  const User getUser(const std::string &) const;
+  unsigned int user_count () const throw ();
+  unsigned int operator_count () const throw ();
+  template<typename T> void for_each_channel_users (const T & fun)
+  { channelUserlist.foreach (fun); }
   
   void addBan(const Mask&, std::time_t = -1);
   void delBan(const Mask&);
@@ -104,7 +109,7 @@ public:
   template<typename T>  void for_each_ban_entry (const T & fun)
   { channelBanlist.foreach (fun); }
   
-  void parseMode(Person *, String);
+  void parseMode(Person *, std::string);
   void resynchModes();
 
   friend class Bot;
diff --git a/source/ChannelUserList.C b/source/ChannelUserList.C
new file mode 100644 (file)
index 0000000..877e554
--- /dev/null
@@ -0,0 +1,193 @@
+// ChannelUserList.C  -*- C++ -*-
+// Copyright (c) 1997, 1998 Etienne BERNARD
+// Copyright (C) 2002,2005,2008,2009 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.
+
+#include "ChannelUserList.H"
+#include "User.H"
+#include "UserList.H"
+#include "UserListItem.H"
+#include "Utils.H"
+
+#include <algorithm>
+#include <functional>
+
+ChannelUserList::ChannelUserList (const std::string & cn) throw ()
+  : users_mutex (true), channel_name (cn)
+{ }
+
+ChannelUserList::~ChannelUserList () throw ()
+{
+  BotLock destructor_lock (users_mutex);
+
+  while (users.begin () != users.end ())
+    {
+      del (users.begin()->nick);
+    }
+}
+
+std::list<User>::iterator 
+ChannelUserList::get_user_i_ (const std::string &name)
+{
+  BotLock get_lock (users_mutex);
+
+  return std::find_if (users.begin (), users.end (),
+                      std::bind1st (user_equal_p, User(name, 0)));
+}
+
+void
+ChannelUserList::add_ (std::string name, std::string host, int mode,
+                      UserListItem* user_list_item, bool names) throw ()
+{
+  BotLock add_lock (users_mutex);
+
+  del (name);
+
+  if (user_list_item) 
+    {
+      if (user_list_item->identified)
+       {
+         user_list_item->identified++;
+       }
+      else if (user_list_item->passwd == "")
+       {
+         user_list_item->identified = 1;
+       }
+    }
+
+  Utils::push_sorted (users,
+                     names ? User (name, mode) 
+                     : User (name, host, channel_name, mode, user_list_item),
+                     user_less_p);
+}
+
+void
+ChannelUserList::add (std::string name, std::string host, int mode,
+                     UserList* user_list, bool names) throw ()
+{
+  BotLock add_lock (users_mutex);
+  name = Utils::to_lower (name);
+
+  UserListItem *uli = names ? 0 : user_list->getUserListItem (name + "!" + host,
+                                                             channel_name);
+
+  add_ (name, host, mode, uli, names);
+}
+
+void
+ChannelUserList::del (const std::string &name) throw ()
+{
+  BotLock del_lock (users_mutex);
+
+  std::list<User>::iterator found = get_user_i_ (name);
+
+  if (found != users.end ())
+    {
+      if (found->userListItem && found->userListItem->identified > 0)
+         found->userListItem->identified--;
+
+      users.erase (found);
+    }
+}
+
+User
+ChannelUserList::get (const std::string & name) const throw (user_not_found)
+{
+  BotLock get_lock (users_mutex);
+
+  std::list<User>::const_iterator pos = 
+    std::find_if (users.begin (), users.end (),
+                 std::bind1st (user_equal_p, User(name, 0)));
+
+  if (pos != users.end ())
+    return *pos;
+  else
+    throw user_not_found (name);
+}
+
+void 
+ChannelUserList::change_nickname (const std::string & old_name, 
+                                 std::string new_name) 
+  throw (user_not_found)
+{
+  BotLock change_lock (users_mutex);
+  
+  User user = get (old_name);
+  del (old_name);
+  add_ (new_name, user.userhost, user.mode, user.userListItem, false);
+}
+
+void
+ChannelUserList::change_user_mode (const std::string &name, int flag, bool remove)
+  throw ()
+{
+  BotLock change_lock (users_mutex);
+
+  std::list<User>::iterator user = get_user_i_ (name);
+
+  if (user != users.end ())
+    {
+      remove ? user->mode &= ~flag : user->mode |= flag;
+    }
+}
+
+bool 
+ChannelUserList::in_channel_p (const std::string &name) const throw ()
+{
+  try
+    {
+      get (name);
+    }
+  catch (user_not_found &)
+    {
+      return false;
+    }
+
+  return true;
+}
+
+void
+ChannelUserList::change_user_key (const std::string &name, const std::string &key)
+  throw ()
+{
+  std::list<User>::iterator user = get_user_i_ (name);
+  
+  if (user != users.end ())
+    user->userkey = key;
+}
+
+unsigned int 
+ChannelUserList::user_count () const throw ()
+{
+  return users.size ();
+}
+
+unsigned int 
+ChannelUserList::operator_count () const throw ()
+{
+  unsigned int count = 0;
+  
+  for (std::list<User>::const_iterator user = users.begin ();
+       user != users.end ();
+       ++user)
+    {
+      if (user->mode & User::OP_MODE)
+       count++;
+    }
+
+  return count;
+}
diff --git a/source/ChannelUserList.H b/source/ChannelUserList.H
new file mode 100644 (file)
index 0000000..4a96417
--- /dev/null
@@ -0,0 +1,81 @@
+// ChannelUserList.H  -*- C++ -*-
+// Copyright (c) 1997, 1998 Etienne BERNARD
+// Copyright (C) 2002,2005,2008,2009 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.
+
+#ifndef CHANNEL_USER_LIST_H
+#define CHANNEL_USER_LIST_H
+
+#include <algorithm>
+#include <list>
+#include <string>
+
+#include "BotThreading.H"
+
+class User;
+class UserList;
+class UserListItem;
+
+class ChannelUserList
+{
+  std::list<User> users;
+  mutable BotMutex users_mutex;
+  std::string channel_name;
+
+  std::equal_to<User> user_equal_p;
+  std::less<User> user_less_p;
+
+  std::list<User>::iterator get_user_i_ (const std::string &);
+  void add_ (std::string, std::string, int, UserListItem*, bool) throw ();
+
+public:
+  struct user_not_found 
+  { 
+    std::string name;
+    user_not_found (const std::string &n)
+      : name (n)
+    { }
+  };
+
+  enum
+    {
+      MODE_ADD = 0,
+      MODE_REMOVE = 1
+    };
+
+  ChannelUserList (const std::string &) throw ();
+  ~ChannelUserList () throw ();
+
+  void add (std::string, std::string, int, UserList*, bool = false) throw ();
+  void del (const std::string &) throw ();
+  User get (const std::string &) const throw (user_not_found);
+  void change_nickname (const std::string &, std::string) throw (user_not_found);
+  void change_user_mode (const std::string &, int, bool) throw ();
+  void change_user_key (const std::string &, const std::string &) throw ();
+  bool in_channel_p (const std::string &) const throw ();
+  unsigned int user_count () const throw ();
+  unsigned int operator_count () const throw ();
+
+  template<typename T>
+  void foreach (const T & fun)
+  {
+    BotLock foreach_lock (users_mutex);
+    std::for_each (users.begin (), users.end (), fun);
+  }
+};
+
+#endif
index 93b7676..b1e4f5f 100644 (file)
@@ -19,6 +19,8 @@
 
 #include "Commands.H"
 
+#include <functional>
+
 #include "BanEntry.H"
 #include "Bot.H"
 #include "ChannelList.H"
@@ -373,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)
 {
@@ -387,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;
 }
 
@@ -456,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);
     }
@@ -481,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)
 {
@@ -496,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;
@@ -676,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;
 }
index fc3ebd1..1f5e4aa 100644 (file)
 #include "String.H"
 
 class Bot;
+class Channel;
+class Mask;
 class Message;
+class User;
 
 class Commands {
 public:
@@ -71,6 +74,28 @@ public:
   static Message Unlock(Bot *, String);
   static Message Who (Bot *, String);
   static Message Whois (Bot *, String);
+
+private:
+  class deop_wildcard : std::unary_function<User &, void>
+  {
+    Bot *bot;
+    Mask &mask;
+    const String channel;
+  public:
+    deop_wildcard (Bot*, Mask&, String&);
+    void operator ()(const User &);
+  };
+
+  class kick_wildcard : std::unary_function<User &, void>
+  {
+    Bot *bot;
+    Mask &mask;
+    const String channel;
+    const String reason;
+  public:
+    kick_wildcard (Bot*, Mask&, String&, String&);
+    void operator ()(const User &);
+  };
 };
 
 #endif
index a13b420..7defa25 100644 (file)
@@ -8,6 +8,7 @@ bobotpp_SOURCES = BanEntry.C \
        BotThreading.C \
        Channel.C \
        ChannelList.C \
+       ChannelUserList.C \
        Commands.C \
        Connection.C \
        DCCChatConnection.C \
@@ -45,6 +46,7 @@ bobotpp_SOURCES = BanEntry.C \
        BotThreading.H \
        Channel.H \
        ChannelList.H \
+       ChannelUserList.H \
        Commands.H \
        Connection.H \
        DCCChatConnection.H \
index e7e1158..254e6b9 100644 (file)
@@ -444,13 +444,13 @@ Parser::parseJoin (ServerConnection * cnx, Person * from, String rest)
          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))
+      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 ();
+         ch->change_user_key (n, Utils::get_key ());
          Commands::CTCP (cnx->bot, n, "PING", 
-                         ch->getUser(n)->userkey + " " + c);
+                         ch->getUser(n).userkey + " " + c);
        }
     }
 
@@ -498,21 +498,28 @@ Parser::parseKick (ServerConnection * cnx, Person * from, String rest)
     {
       if (!cnx->bot->channelList->getChannel (channel))
        return;
-      User *u = cnx->bot->channelList->getChannel (channel)->getUser (target);
-      if (u && u->getProt () >= User::NO_KICK)
+      try
        {
-         String fromNick = from->getNick ();
-         User *v =
-           cnx->bot->channelList->getChannel (channel)->getUser (fromNick);
-         if (v->getProt () < User::NO_KICK)
+         User u = cnx->bot->channelList->getChannel (channel)->getUser (target);
+         if (u.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");
+             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");
+               }
            }
        }
+      catch (const ChannelUserList::user_not_found &e)
+       {
+
+       }
       cnx->bot->channelList->getChannel (channel)->delNick (target);
     }
 }
@@ -647,15 +654,14 @@ Parser::parseNotice (ServerConnection * cnx, Person * from, String rest)
       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);
+      Channel *channel = cnx->bot->channelList->getChannel (c);
+
+      if (channel && channel->hasNick (nick))
+       {
+         User u = cnx->bot->channelList->getChannel(c)->getUser(nick);
+         if (u.getAop () && !(u.mode & User::OP_MODE) && u.userkey == rest)
+           cnx->queue->sendChannelMode (c, "+o", nick);
+       }
     }
 }
 
@@ -751,7 +757,7 @@ Parser::parsePart (ServerConnection * cnx, Person * from, String rest)
       if (!c)
        return;
       c->delNick (n);
-      if (c->countOp == 0 && c->count == 1)
+      if (c->operator_count () == 0 && c->user_count () == 1)
        {
          cnx->queue->sendPart (channel);
          cnx->queue->sendJoin (channel,
@@ -988,14 +994,21 @@ Parser::parseMessage (ServerConnection * cnx,
              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;
+
+         Channel * c = cnx->bot->channelList->getChannel (to);
+         if (c && c->hasNick (from->getNick ()))
+           {
+             User u = c->getUser (from->getNick ());
+             if (!u.userListItem)
+               identified = true;
+             else
+               identified = u.userListItem->passwd == ""
+                 || u.userListItem->identified > 0;
+           }
          else
-           identified = u->userListItem->passwd == ""
-             || u->userListItem->identified > 0;
+           {
+             identified = true;
+           }
        }
       else
            {
index bdbf423..e557fef 100644 (file)
@@ -1,5 +1,6 @@
 // User.C  -*- C++ -*-
 // Copyright (c) 1997, 1998 Etienne BERNARD
+// Copyright (C) 2009 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
@@ -21,9 +22,9 @@
 #include "UserListItem.H"
 #include "Utils.H"
 
-User::User(String n, String uh, String channel, int mode, UserList *ul)
+User::User(String n, String uh, String channel, int mode, UserListItem *uli)
   : mode(mode), floodNum(0),
-    userListItem(ul->getUserListItem(n + "!" + uh, channel)),
+    userListItem(uli),
     nick(n), userhost(uh),
     userkey("")
 { }
@@ -34,7 +35,7 @@ User::User(String n, int mode)
 { }
 
 int
-User::getLevel()
+User::getLevel() const
 {
   if (userListItem && userListItem->identified &&
       (userListItem->expirationDate == -1 ||
@@ -44,7 +45,7 @@ User::getLevel()
 }
 
 int
-User::getProt()
+User::getProt() const
 {
   if (userListItem && userListItem->identified &&
       (userListItem->expirationDate == -1 ||
@@ -54,7 +55,7 @@ User::getProt()
 }
 
 bool
-User::getAop()
+User::getAop() const
 {
   if (userListItem && userListItem->identified &&
       (userListItem->expirationDate == -1 ||
@@ -62,3 +63,15 @@ User::getAop()
     return userListItem->aop;
   return false;
 }
+
+bool
+User::operator< (const User &rh) const
+{
+  return Utils::to_lower (nick) < Utils::to_lower (rh.nick);
+}
+
+bool
+User::operator== (const User &rh) const
+{
+  return Utils::to_lower (nick) == Utils::to_lower (rh.nick);
+}
index 2777c5c..9839cf0 100644 (file)
@@ -1,5 +1,6 @@
 // User.H  -*- C++ -*-
 // Copyright (c) 1997, 1998 Etienne BERNARD
+// Copyright (C) 2009 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
@@ -59,16 +60,19 @@ public:
     NO_DEOP = 3
   };
 
-  User(String, String, String, int, UserList *);
+  User(String, String, String, int, UserListItem *);
   User(String, int);
   
-  int getLevel();
-  int getProt();
-  bool getAop();
+  int getLevel() const;
+  int getProt() const;
+  bool getAop() const;
+
+  bool operator< (const User &) const;
+  bool operator== (const User &) const;
 
   friend class Bot;
   friend class Parser;
-  friend class Channel;
+  friend class ChannelUserList;
   friend class Commands;
   friend class UserCommands;
 };
index 40da3a6..0e654e1 100644 (file)
@@ -681,36 +681,41 @@ UserCommands::Ident(ServerConnection *cnx, Person *from,
     return;
   }
 
-  User * u = c->getUser(from->getNick());
-  if (!u) {
-    from->sendNotice(String("\002You can identify yourself on"
-                     " channel\002 ") + channel +
-                     " \002only if you are on the channel.\002");
-    return;
-  }
-
-  if (u->userListItem && u->userListItem->identified) {
-    from->sendNotice(String("\002You are already identified on"
-                     " channel\002 ") + channel);
-    return;
-  }
-
-  if (!u->userListItem) {
-    from->sendNotice("\002You are not in my userlist.\002");
-    return;
-  }
-
-  if (u->userListItem->passwd ==
-      crypt((const char *)rest, (const char *)u->userListItem->passwd)) {
-    // For each channel, we increment identification counter
-    for (std::map<String, Channel *, std::less<String> >::iterator it =
-           cnx->bot->channelList->begin();
-         it != cnx->bot->channelList->end(); ++it)
-      u->userListItem->identified++;
-
-    from->sendNotice("\002You are now identified.\002");
-  } else
-    from->sendNotice("\002This is a wrong password.\002");
+  try
+    {
+      User u = c->getUser(from->getNick());
+      
+      if (u.userListItem && u.userListItem->identified) {
+       from->sendNotice(String("\002You are already identified on"
+                               " channel\002 ") + channel);
+       return;
+      }
+      
+      if (!u.userListItem) {
+       from->sendNotice("\002You are not in my userlist.\002");
+       return;
+      }
+      
+      if (u.userListItem->passwd ==
+         crypt(rest.c_str (), u.userListItem->passwd.c_str ())) {
+       // For each channel, we increment identification counter
+       // fixme: is this logic correct?
+       for (std::map<String, Channel *, std::less<String> >::iterator it =
+              cnx->bot->channelList->begin();
+            it != cnx->bot->channelList->end(); ++it)
+         u.userListItem->identified++;
+       
+       from->sendNotice("\002You are now identified.\002");
+      } else
+       from->sendNotice("\002This is a wrong password.\002");
+    }
+  catch (ChannelUserList::user_not_found &e)
+    {
+      from->sendNotice(String("\002You can identify yourself on"
+                             " channel\002 ") + channel +
+                      " \002only if you are on the channel.\002");
+      return;
+    }
 }
 
 void
@@ -767,13 +772,10 @@ UserCommands::Keep(ServerConnection *cnx, Person *from,
                     channel);
 }
 
-// FIXME: Convert
 void
 UserCommands::Kick(ServerConnection *cnx, Person *from,
                    String channel, String rest)
 {
-  String nick = from->getNick();
-
   Channel * c = cnx->bot->channelList->getChannel(channel);
 
   if (rest.length() == 0) {
@@ -785,46 +787,25 @@ UserCommands::Kick(ServerConnection *cnx, Person *from,
   String who = st.next_token();
 
   if (Utils::wildcard_p(who)) {
-    User * u = c->getUser(nick);
-    if (!u)
-      return;
-    if (u->getLevel() < User::TRUSTED_USER) {
-      from->sendNotice("\002You need an higher level to "
-                       "use wildcards.\002");
-      return;
-    }
-  }
-
-  if (!cnx->bot->iAmOp(channel)) {
-    from->sendNotice(String("\002I am not channel op on\002 ") +
-                     channel);
-    return;
-  }
+    try
+      {
+       User u = c->getUser(from->getNick ());
 
-  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)
-        cnx->queue->sendKick(channel, (*it).second->nick, st.rest());
-  } else {
-    User * u = c->getUser(who);
-    if (!u) {
-      from->sendNotice(String("\002I can not find\002 ") +
-                       who + " \002on\002 " + channel);
-      return;
-    }
-    if (u->getProt() < User::NO_KICK)
-      cnx->queue->sendKick(channel, who, st.rest());
-    else
-      from->sendNotice(String("\002I can not kick\002 ") +
-                        who + " \002on\002 " + channel +
-                        " \002(protected).\002");
+       if (u.getLevel() < User::TRUSTED_USER) {
+         from->sendNotice("\002You need an higher level to "
+                          "use wildcards.\002");
+         return;
+       }
+      }
+    catch (const ChannelUserList::user_not_found &)
+      {
+       return;
+      }
   }
+  
+  Message ret = Commands::Kick (cnx->bot, channel, who, st.rest ());
+  if (ret.getCode () != 0)
+    from->sendNotice (ret.getMessage ());
 }
 
 // FIXME: Convert
@@ -903,31 +884,36 @@ UserCommands::Msg(ServerConnection *cnx, Person *from,
     from->sendNotice(m.getMessage());
 }
 
+UserCommands::map_names::map_names (Person *f, std::string &r)
+  : from (f), result (r), length (0)
+{ }
+
+void
+UserCommands::map_names::operator() (const User &user)
+{
+  result += (user.mode & User::OP_MODE ? "@" :
+            (user.mode & User::VOICE_MODE ? "+" : ""))  +  user.nick + " ";
+  length += user.nick.length() + 1;
+  
+  if (length >= 256) {
+    from->sendNotice(result);
+    result = ""; length = 0;
+  }
+}
+
 void
 UserCommands::Names(ServerConnection *cnx, Person *from,
                      String channel, String rest)
 {
   String nick = from->getNick();
-  String result = "";
-  int length = 0;
   Channel *c = cnx->bot->channelList->getChannel(channel);
-  std::map<String, User *, std::less<String> >::iterator it;
+  std::string result;
 
   from->sendNotice(String("\002Names on ") +
                     channel + ":\002");
 
-  for (it = c->channelMemory.begin();
-       it != c->channelMemory.end(); ++it) {
-    result = result +
-      ((*it).second->mode & User::OP_MODE ? "@" :
-       ((*it).second->mode & User::VOICE_MODE ? "+" : "")) +
-      (*it).second->nick + " ";
-    length += (*it).first.length() + 1;
-    if (length >= 256) {
-      from->sendNotice(result);
-      result = ""; length = 0;
-    }
-  }
+  map_names f (from, result);
+  c->for_each_channel_users (f);
 
   if (result != "")
     from->sendNotice(result);
@@ -1012,7 +998,7 @@ UserCommands::NsLookup(ServerConnection *cnx, Person *from,
   struct in_addr iaddr;
 
   if (isdigit(target[0])) { // An IP ?
-    iaddr.s_addr = inet_addr((const char *)target);
+    iaddr.s_addr = inet_addr(target.c_str ());
     host = gethostbyaddr((char *)(&iaddr),
                          sizeof(struct in_addr),
                          AF_INET);
@@ -1023,7 +1009,7 @@ UserCommands::NsLookup(ServerConnection *cnx, Person *from,
       return;
     }
   } else {
-    host = gethostbyname((const char *)target);
+    host = gethostbyname(target.c_str ());
     if (host) {
       std::memcpy((char *)&iaddr, (char *)host->h_addr,
             host->h_length);
@@ -1037,106 +1023,70 @@ UserCommands::NsLookup(ServerConnection *cnx, Person *from,
                     target);
 }
 
-// FIXME: Convert
 void
 UserCommands::Op(ServerConnection *cnx, Person *from,
                  String channel, String rest)
 {
-  String nick = from->getNick();
-
-  if (!cnx->bot->iAmOp(channel)) {
-    from->sendNotice(String("\002I am not channel op on\002 ") +
-                     channel);
-    return;
-  }
-
-  if (Utils::wildcard_p(rest)) {
-    from->sendNotice("\002Mass op is not allowed.\002");
-    return;
-  }
-
-  String target;
-
-  if (rest.length() == 0)
-    target = nick;
-  else
-    target = rest;
-
-  User *u = cnx->bot->channelList->getChannel(channel)->getUser(target);
-  if (!u) {
-    from->sendNotice(String("\002I cannot find\002 ") + target + " \002on channel\002 " + channel);
-    return;
-  }
-
-  ShitEntry *se = cnx->bot->shitList->getShit(target, channel);
-  if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP) {
-    from->sendNotice(String("\002I can not op\002 ")+target+" \002on channel\002 "+channel+" \002(shitlist).\002");
-    return;
-  }
-
-  if (!(u->mode & User::OP_MODE))
-    cnx->queue->sendChannelMode(channel, "+o", target);
-  else {
-    if (target == nick)
-      from->sendNotice(String("\002You are already channel "
-                              "operator on\002 ") + channel);
-    else
-      from->sendNotice(target + " \002is already channel "
-                       "operator on\002 " + channel);
-  }
+  Message ret = Commands::Op (cnx->bot, channel, 
+                             rest.length () == 0 ? from->getNick () : rest);
+  
+  if (ret.getCode () != 0)
+    from->sendNotice (ret.getMessage ());
 }
 
-// FIXME: Convert
 void
 UserCommands::Part(ServerConnection *cnx, Person *from,
                    String channel, String rest)
 {
-  wantedChannel *w = cnx->bot->wantedChannels[channel];
-  cnx->bot->wantedChannels.erase(channel);
-  delete w;
-  cnx->queue->sendPart(channel);
+  Message ret = Commands::Part (cnx->bot, channel);
+  
+  if (ret.getCode () != 0)
+    from->sendNotice (ret.getMessage ());
 }
 
 void
 UserCommands::Password(ServerConnection *cnx, Person *from,
                        String channel, String rest)
 {
-  Channel *c = cnx->bot->channelList->getChannel(channel);
-
   if (rest.length() == 0) {
     from->sendNotice("\002No password.\002");
     return;
   }
 
-  User * u = c->getUser(from->getNick());
-  if (!u) {
-    from->sendNotice(String("\002To change your password for\002") +
-                     channel + "\002, you need to be on the "
-                     "channel.\002");
-    return;
-  }
-
-  if (!u->userListItem) {
-    from->sendNotice("\002You are not in my userlist.\002");
-    return;
-  }
-
-  if (rest.toLower() == "none") {
-    u->userListItem->passwd = "";
-    from->sendNotice("\002Password cleared.\002");
-    return;
-  }
-  
-  static char saltChars[] = "abcdefghijklmnopqrstuvwxyz"
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
-  char salt[3];
-  srand(time(0));
-  salt[0] = saltChars[rand() % 64];
-  salt[1] = saltChars[rand() % 64];
-  salt[2] = '\0';
-
-  u->userListItem->passwd = crypt((const char *)rest, salt);
-  from->sendNotice("\002Password changed.\002");
+  try
+    {
+      Channel *c = cnx->bot->channelList->getChannel(channel);
+      User u = c->getUser(from->getNick());
+      
+      if (!u.userListItem) {
+       from->sendNotice("\002You are not in my userlist.\002");
+       return;
+      }
+      
+      if (rest.toLower() == "none") {
+       u.userListItem->passwd = "";
+       from->sendNotice("\002Password cleared.\002");
+       return;
+      }
+      
+      static char saltChars[] = "abcdefghijklmnopqrstuvwxyz"
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+      char salt[3];
+      srand(time(0));
+      salt[0] = saltChars[rand() % 64];
+      salt[1] = saltChars[rand() % 64];
+      salt[2] = '\0';
+      
+      u.userListItem->passwd = crypt(rest.c_str (), salt);
+      from->sendNotice("\002Password changed.\002");
+    }
+  catch (const ChannelUserList::user_not_found &e)
+    {
+      from->sendNotice(String("\002To change your password for\002") +
+                      channel + "\002, you need to be on the "
+                      "channel.\002");
+      return;
+    }
 }
 
 void
@@ -1353,8 +1303,8 @@ UserCommands::TBan(ServerConnection *cnx, Person *from,
   }
 
   if (Utils::wildcard_p(who) && from) {
-    User * u = c->getUser(from->getNick());
-    if (u && u->getLevel() < User::TRUSTED_USER) {
+    if (c->hasNick (from->getNick ()) 
+       && c->getUser(from->getNick()).getLevel() < User::TRUSTED_USER) {
       if (from)
         from->sendNotice("\002You need an higher level to use"
                          " wildcards.\002");
@@ -1434,34 +1384,33 @@ UserCommands::Who(ServerConnection *cnx, Person *from,
                  String channel, String rest)
 {
   String nick = from->getNick();
-  User * u = cnx->bot->channelList->getChannel(channel)->getUser(nick);
   UserListItem * uli;
-
-  if (u)
-    uli = u->userListItem;
+  
+  if (cnx->bot->channelList->getChannel(channel)->hasNick(nick))
+    uli = cnx->bot->channelList->getChannel(channel)->getUser(nick).userListItem;
   else
     uli = cnx->bot->userList->getUserListItem(from->getAddress(),
-                                         channel);
-
+                                             channel);
+  
   if (uli) {
     from->sendNotice(String("\002You are\002 ") +
-                      uli->mask.getMask() + " \002on\002 " +
-                      uli->channelMask.getMask());
+                    uli->mask.getMask() + " \002on\002 " +
+                    uli->channelMask.getMask());
     from->sendNotice(String("\002Lvl:\002 ") +
-                     Utils::level2str(uli->level) +
-                     " \002Prot:\002 " +
-                     Utils::prot2str(uli->prot) +
-                     " \002Aop:\002 " +
-                     Utils::bool2str(uli->aop) +
-                     " \002Expired:\002 " +
-                     Utils::bool2str(!uli->isStillValid()) +
-                     " \002Ident:\002 " +
-                     (uli && !uli->identified ? "\026" : "") +
-                     Utils::bool2str(uli && uli->identified) +
-                     (uli && !uli->identified ? "\026" : ""));
+                    Utils::level2str(uli->level) +
+                    " \002Prot:\002 " +
+                    Utils::prot2str(uli->prot) +
+                    " \002Aop:\002 " +
+                    Utils::bool2str(uli->aop) +
+                    " \002Expired:\002 " +
+                    Utils::bool2str(!uli->isStillValid()) +
+                    " \002Ident:\002 " +
+                    (uli && !uli->identified ? "\026" : "") +
+                    Utils::bool2str(uli && uli->identified) +
+                    (uli && !uli->identified ? "\026" : ""));
   } else
     from->sendNotice(String("\002You are not in the userlist for\002 ") +
-                      channel);
+                    channel);
 }
 
 void
@@ -1478,11 +1427,10 @@ UserCommands::Whois(ServerConnection *cnx, Person *from,
   StringTokenizer st(rest);
   String otherNick = st.next_token();
 
-  User * u = cnx->bot->channelList->getChannel(channel)->getUser(otherNick);
   UserListItem * uli;
 
-  if (u)
-    uli = u->userListItem;
+  if (cnx->bot->channelList->getChannel(channel)->hasNick(otherNick))
+    uli = cnx->bot->channelList->getChannel(channel)->getUser(otherNick).userListItem;
   else
     uli = cnx->bot->userList->getUserListItem(otherNick + "!" +
                                          cnx->bot->getUserhost(channel,
index 9b08854..b8d16dd 100644 (file)
 
 #include "String.H"
 
+#include <functional>
+
 class Person;
 class ServerConnection;
+class User;
 
 class UserCommands {
 public:
@@ -87,6 +90,17 @@ public:
   static void UserList(ServerConnection *, Person *, String, String);
   static void Who(ServerConnection *, Person *, String, String);
   static void Whois(ServerConnection *, Person *, String, String);
+
+private:
+  struct map_names : std::unary_function<User &, void>
+  {
+    Person *from;
+    std::string &result;
+    unsigned int length;
+
+    map_names (Person*, std::string&);
+    void operator() (const User &);
+  };
 };
 
 #endif
index 49cf509..f8b1e2c 100644 (file)
@@ -71,7 +71,7 @@ public:
     { return expirationDate == -1 || std::time(NULL) <= expirationDate; }
 
   friend class Parser;
-  friend class Channel;
+  friend class ChannelUserList;
   friend class User;
   friend class UserList;
   friend class Commands;
index dadfff2..c94c388 100644 (file)
@@ -153,15 +153,11 @@ Utils::get_level (Bot * b, std::string nuh, std::string channel)
   if (!channel_p (channel))
     return get_level(b, nuh);
 
-  if (Channel * c =  b->channelList->getChannel(channel))
-    {
-      User * u = c->getUser(get_nick (nuh));
-      if (u)
-       return u->getLevel();
-    } 
-  else {
+  Channel * c =  b->channelList->getChannel(channel);
+  if (c && c->hasNick (get_nick (nuh)))
+    return  c->getUser(get_nick (nuh)).getLevel ();
+  else 
     return -1;
-  }
 
   return b->userList->getLevel(nuh, channel);
 }