]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/channels.cpp
Rewrite invite system
[user/henk/code/inspircd.git] / src / channels.cpp
index 13595c4c323901709e42c1717a40d9bcfcac7655..6e3bc5e04e4cbe6f21dcbb4104ed9af9e581c588 100644 (file)
@@ -32,9 +32,6 @@ namespace
        ChanModeReference inviteonlymode(NULL, "inviteonly");
        ChanModeReference keymode(NULL, "key");
        ChanModeReference limitmode(NULL, "limit");
-       ChanModeReference secretmode(NULL, "secret");
-       ChanModeReference privatemode(NULL, "private");
-       UserModeReference invisiblemode(NULL, "invisible");
 }
 
 Channel::Channel(const std::string &cname, time_t ts)
@@ -61,11 +58,11 @@ void Channel::SetTopic(User* u, const std::string& ntopic)
 
 Membership* Channel::AddUser(User* user)
 {
-       Membership*& memb = userlist[user];
-       if (memb)
+       std::pair<MemberMap::iterator, bool> ret = userlist.insert(std::make_pair(user, insp::aligned_storage<Membership>()));
+       if (!ret.second)
                return NULL;
 
-       memb = new Membership(user, this);
+       Membership* memb = new(ret.first->second) Membership(user, this);
        return memb;
 }
 
@@ -86,15 +83,13 @@ void Channel::CheckDestroy()
        if (res == MOD_RES_DENY)
                return;
 
+       // If the channel isn't in chanlist then it is already in the cull list, don't add it again
        chan_hash::iterator iter = ServerInstance->chanlist.find(this->name);
-       /* kill the record */
-       if (iter != ServerInstance->chanlist.end())
-       {
-               FOREACH_MOD(OnChannelDelete, (this));
-               ServerInstance->chanlist.erase(iter);
-       }
+       if ((iter == ServerInstance->chanlist.end()) || (iter->second != this))
+               return;
 
-       ClearInvites();
+       FOREACH_MOD(OnChannelDelete, (this));
+       ServerInstance->chanlist.erase(iter);
        ServerInstance->GlobalCulls.AddItem(this);
 }
 
@@ -102,7 +97,7 @@ void Channel::DelUser(const MemberMap::iterator& membiter)
 {
        Membership* memb = membiter->second;
        memb->cull();
-       delete memb;
+       memb->~Membership();
        userlist.erase(membiter);
 
        // If this channel became empty then it should be removed
@@ -136,10 +131,18 @@ void Channel::SetDefaultModes()
                                continue;
 
                        if (mode->GetNumParams(true))
+                       {
                                list.GetToken(parameter);
+                               // If the parameter begins with a ':' then it's invalid
+                               if (parameter.c_str()[0] == ':')
+                                       continue;
+                       }
                        else
                                parameter.clear();
 
+                       if ((mode->GetNumParams(true)) && (parameter.empty()))
+                               continue;
+
                        mode->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, this, parameter, true);
                }
        }
@@ -231,13 +234,10 @@ Channel* Channel::JoinUser(LocalUser* user, std::string cname, bool override, co
                        if (MOD_RESULT == MOD_RES_PASSTHRU)
                        {
                                std::string ckey = chan->GetModeParameter(keymode);
-                               bool invited = user->IsInvited(chan);
-                               bool can_bypass = ServerInstance->Config->InvBypassModes && invited;
-
                                if (!ckey.empty())
                                {
                                        FIRST_MOD_RESULT(OnCheckKey, MOD_RESULT, (user, chan, key));
-                                       if (!MOD_RESULT.check((ckey == key) || can_bypass))
+                                       if (!MOD_RESULT.check(InspIRCd::TimingSafeCompare(ckey, key)))
                                        {
                                                // If no key provided, or key is not the right one, and can't bypass +k (not invited or option not enabled)
                                                user->WriteNumeric(ERR_BADCHANNELKEY, "%s :Cannot join channel (Incorrect channel key)", chan->name.c_str());
@@ -248,7 +248,7 @@ Channel* Channel::JoinUser(LocalUser* user, std::string cname, bool override, co
                                if (chan->IsModeSet(inviteonlymode))
                                {
                                        FIRST_MOD_RESULT(OnCheckInvite, MOD_RESULT, (user, chan));
-                                       if (!MOD_RESULT.check(invited))
+                                       if (MOD_RESULT != MOD_RES_ALLOW)
                                        {
                                                user->WriteNumeric(ERR_INVITEONLYCHAN, "%s :Cannot join channel (Invite only)", chan->name.c_str());
                                                return NULL;
@@ -259,27 +259,18 @@ Channel* Channel::JoinUser(LocalUser* user, std::string cname, bool override, co
                                if (!limit.empty())
                                {
                                        FIRST_MOD_RESULT(OnCheckLimit, MOD_RESULT, (user, chan));
-                                       if (!MOD_RESULT.check((chan->GetUserCounter() < atol(limit.c_str()) || can_bypass)))
+                                       if (!MOD_RESULT.check((chan->GetUserCounter() < atol(limit.c_str()))))
                                        {
                                                user->WriteNumeric(ERR_CHANNELISFULL, "%s :Cannot join channel (Channel is full)", chan->name.c_str());
                                                return NULL;
                                        }
                                }
 
-                               if (chan->IsBanned(user) && !can_bypass)
+                               if (chan->IsBanned(user))
                                {
                                        user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s :Cannot join channel (You're banned)", chan->name.c_str());
                                        return NULL;
                                }
-
-                               /*
-                                * If the user has invites for this channel, remove them now
-                                * after a successful join so they don't build up.
-                                */
-                               if (invited)
-                               {
-                                       user->RemoveInvite(chan);
-                               }
                        }
                }
        }
@@ -337,16 +328,6 @@ Membership* Channel::ForceJoin(User* user, const std::string* privs, bool bursti
                this->WriteAllExcept(user, !ServerInstance->Config->CycleHostsFromUser, 0, except_list, "MODE %s +%s", this->name.c_str(), ms.c_str());
        }
 
-       if (IS_LOCAL(user))
-       {
-               if (this->topicset)
-               {
-                       user->WriteNumeric(RPL_TOPIC, "%s :%s", this->name.c_str(), this->topic.c_str());
-                       user->WriteNumeric(RPL_TOPICTIME, "%s %s %lu", this->name.c_str(), this->setby.c_str(), (unsigned long)this->topicset);
-               }
-               this->UserList(user);
-       }
-
        FOREACH_MOD(OnPostJoin, (memb));
        return memb;
 }
@@ -388,10 +369,10 @@ bool Channel::CheckBan(User* user, const std::string& mask)
                return false;
 
        const std::string nickIdent = user->nick + "!" + user->ident;
-       std::string prefix = mask.substr(0, at);
+       std::string prefix(mask, 0, at);
        if (InspIRCd::Match(nickIdent, prefix, NULL))
        {
-               std::string suffix = mask.substr(at + 1);
+               std::string suffix(mask, at + 1);
                if (InspIRCd::Match(user->host, suffix, NULL) ||
                        InspIRCd::Match(user->dhost, suffix, NULL) ||
                        InspIRCd::MatchCIDR(user->GetIPString(), suffix, NULL))
@@ -579,66 +560,6 @@ const char* Channel::ChanModes(bool showkey)
        return scratch.c_str();
 }
 
-/* compile a userlist of a channel into a string, each nick seperated by
- * spaces and op, voice etc status shown as @ and +, and send it to 'user'
- */
-void Channel::UserList(User* user, bool has_user)
-{
-       bool has_privs = user->HasPrivPermission("channels/auspex");
-       std::string list;
-       list.push_back(this->IsModeSet(secretmode) ? '@' : this->IsModeSet(privatemode) ? '*' : '=');
-       list.push_back(' ');
-       list.append(this->name).append(" :");
-       std::string::size_type pos = list.size();
-
-       const size_t maxlen = ServerInstance->Config->Limits.MaxLine - 10 - ServerInstance->Config->ServerName.size();
-       std::string prefixlist;
-       std::string nick;
-       for (MemberMap::iterator i = userlist.begin(); i != userlist.end(); ++i)
-       {
-               if ((!has_user) && (i->first->IsModeSet(invisiblemode)) && (!has_privs))
-               {
-                       /*
-                        * user is +i, and source not on the channel, does not show
-                        * nick in NAMES list
-                        */
-                       continue;
-               }
-
-               Membership* memb = i->second;
-
-               prefixlist.clear();
-               char prefix = memb->GetPrefixChar();
-               if (prefix)
-                       prefixlist.push_back(prefix);
-               nick = i->first->nick;
-
-               ModResult res;
-               FIRST_MOD_RESULT(OnNamesListItem, res, (user, memb, prefixlist, nick));
-
-               // See if a module wants us to exclude this user from NAMES
-               if (res == MOD_RES_DENY)
-                       continue;
-
-               if (list.size() + prefixlist.length() + nick.length() + 1 > maxlen)
-               {
-                       /* list overflowed into multiple numerics */
-                       user->WriteNumeric(RPL_NAMREPLY, list);
-
-                       // Erase all nicks, keep the constant part
-                       list.erase(pos);
-               }
-
-               list.append(prefixlist).append(nick).push_back(' ');
-       }
-
-       // Only send the user list numeric if there is at least one user in it
-       if (list.size() != pos)
-               user->WriteNumeric(RPL_NAMREPLY, list);
-
-       user->WriteNumeric(RPL_ENDOFNAMES, "%s :End of /NAMES list.", this->name.c_str());
-}
-
 /* returns the status character for a given user on a channel, e.g. @ for op,
  * % for halfop etc. If the user has several modes set, the highest mode
  * the user has must be returned.
@@ -716,68 +637,3 @@ bool Membership::SetPrefix(PrefixMode* delta_mh, bool adding)
                modes.push_back(prefix);
        return adding;
 }
-
-void Invitation::Create(Channel* c, LocalUser* u, time_t timeout)
-{
-       if ((timeout != 0) && (ServerInstance->Time() >= timeout))
-               // Expired, don't bother
-               return;
-
-       ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Create chan=%s user=%s", c->name.c_str(), u->uuid.c_str());
-
-       Invitation* inv = Invitation::Find(c, u, false);
-       if (inv)
-       {
-                if ((inv->expiry == 0) || (inv->expiry > timeout))
-                       return;
-               inv->expiry = timeout;
-               ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Create changed expiry in existing invitation %p", (void*) inv);
-       }
-       else
-       {
-               inv = new Invitation(c, u, timeout);
-               c->invites.push_front(inv);
-               u->invites.push_front(inv);
-               ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Create created new invitation %p", (void*) inv);
-       }
-}
-
-Invitation* Invitation::Find(Channel* c, LocalUser* u, bool check_expired)
-{
-       ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Find chan=%s user=%s check_expired=%d", c ? c->name.c_str() : "NULL", u ? u->uuid.c_str() : "NULL", check_expired);
-
-       Invitation* result = NULL;
-       for (InviteList::iterator i = u->invites.begin(); i != u->invites.end(); )
-       {
-               Invitation* inv = *i;
-               ++i;
-
-               if ((check_expired) && (inv->expiry != 0) && (inv->expiry <= ServerInstance->Time()))
-               {
-                       /* Expired invite, remove it. */
-                       std::string expiration = InspIRCd::TimeString(inv->expiry);
-                       ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Find ecountered expired entry: %p expired %s", (void*) inv, expiration.c_str());
-                       delete inv;
-               }
-               else
-               {
-                       /* Is it what we're searching for? */
-                       if (inv->chan == c)
-                       {
-                               result = inv;
-                               break;
-                       }
-               }
-       }
-
-       ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Find result=%p", (void*) result);
-       return result;
-}
-
-Invitation::~Invitation()
-{
-       // Remove this entry from both lists
-       chan->invites.erase(this);
-       user->invites.erase(this);
-       ServerInstance->Logs->Log("INVITEBASE", LOG_DEBUG, "Invitation::~ %p", (void*) this);
-}