]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
Fix pending invites not being removed when a channel was deleted or had its TS lowered
authorattilamolnar <attilamolnar@hush.com>
Sun, 17 Jun 2012 15:53:39 +0000 (17:53 +0200)
committerattilamolnar <attilamolnar@hush.com>
Sun, 17 Jun 2012 15:54:49 +0000 (17:54 +0200)
include/channels.h
include/membership.h
include/typedefs.h
include/users.h
src/channels.cpp
src/commands/cmd_invite.cpp
src/inspircd.cpp
src/modules/m_spanningtree/fjoin.cpp
src/users.cpp

index 89ac6b86ca0327b6a43e9b3da741dc7bb44d802a..7e70fd6c530dafa8d88a2052b6fe2ded05f4f297 100644 (file)
@@ -56,7 +56,7 @@ class BanItem : public HostItem
  * This class represents a channel, and contains its name, modes, topic, topic set time,
  * etc, and an instance of the BanList type.
  */
-class CoreExport Channel : public Extensible
+class CoreExport Channel : public Extensible, public InviteBase
 {
        /** Connect a Channel to a User
         */
index 281d04f70ba1818366416b77d2aee32ad1e99d3d..340f92a12728692ac4c22102af8307b488b36604 100644 (file)
@@ -35,4 +35,29 @@ class CoreExport Membership : public Extensible
        unsigned int getRank();
 };
 
+class InviteBase
+{
+ protected:
+       InviteList invites;
+
+ public:
+       void ClearInvites();
+
+       friend class Invitation;
+};
+
+class Invitation : public classbase
+{
+       Invitation(Channel* c, LocalUser* u, time_t timeout) : user(u), chan(c), expiry(timeout) {}
+
+ public:
+       LocalUser* const user;
+       Channel* const chan;
+       time_t expiry;
+
+       ~Invitation();
+       static void Create(Channel* c, LocalUser* u, time_t timeout);
+       static Invitation* Find(Channel* c, LocalUser* u, bool check_expired = true);
+};
+
 #endif
index 615af6c9ce05182191e197e248f97e3d6e900263..7659628d22c900dffca052e384a76d42a5d3cbd4 100644 (file)
@@ -34,6 +34,8 @@ class DNSRequest;
 class Extensible;
 class FakeUser;
 class InspIRCd;
+class Invitation;
+class InviteBase;
 class LocalUser;
 class Membership;
 class Module;
@@ -72,7 +74,7 @@ typedef std::vector<std::pair<std::string, std::string> > FailedPortList;
 
 /** Holds a complete list of all channels to which a user has been invited and has not yet joined, and the time at which they'll expire.
  */
-typedef std::vector< std::pair<irc::string, time_t> > InvitedList;
+typedef std::vector<Invitation*> InviteList;
 
 /** Holds a complete list of all allow and deny tags from the configuration file (connection classes)
  */
index cdc0d80783265a085bcfeb6b5e04ef15c91d8be3..66e867ad0f52c536d4a39e4cad01285c9bc7367b 100644 (file)
@@ -29,6 +29,7 @@
 #include "inspsocket.h"
 #include "dns.h"
 #include "mode.h"
+#include "membership.h"
 
 /** connect class types
  */
@@ -740,14 +741,8 @@ class CoreExport UserIOHandler : public StreamSocket
 
 typedef unsigned int already_sent_t;
 
-class CoreExport LocalUser : public User
+class CoreExport LocalUser : public User, public InviteBase
 {
-       /** A list of channels the user has a pending invite to.
-        * Upon INVITE channels are added, and upon JOIN, the
-        * channels are removed from this list.
-        */
-       InvitedList invites;
-
  public:
        LocalUser(int fd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server);
        CullResult cull();
@@ -835,7 +830,7 @@ class CoreExport LocalUser : public User
        /** Returns the list of channels this user has been invited to but has not yet joined.
         * @return A list of channels the user is invited to
         */
-       InvitedList* GetInviteList();
+       InviteList& GetInviteList();
 
        /** Returns true if a user is invited to a channel.
         * @param channel A channel name to look up
@@ -856,6 +851,8 @@ class CoreExport LocalUser : public User
         */
        void RemoveInvite(const irc::string &channel);
 
+       void RemoveExpiredInvites();
+
        /** Returns true or false for if a user can execute a privilaged oper command.
         * This is done by looking up their oper type from User::oper, then referencing
         * this to their oper classes and checking the commands they can execute.
index 4a927cedb86afe8a6b5d728d363093493f6d5b2b..f1dba53155eaf0c5238f403a303f9ac25897904f 100644 (file)
@@ -172,6 +172,8 @@ void Channel::DelUser(User* user)
                        FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
                        ServerInstance->chanlist->erase(iter);
                }
+
+               ClearInvites();
                ServerInstance->GlobalCulls.AddItem(this);
        }
 }
@@ -969,3 +971,89 @@ void Channel::RemoveAllPrefixes(User* user)
                m->second->modes.clear();
        }
 }
+
+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", 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", DEBUG, "Invitation::Create changed expiry in existing invitation %p", (void*) inv);
+       }
+       else
+       {
+               inv = new Invitation(c, u, timeout);
+               c->invites.push_back(inv);
+               u->invites.push_back(inv);
+               ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Create created new invitation %p", (void*) inv);
+       }
+}
+
+Invitation* Invitation::Find(Channel* c, LocalUser* u, bool check_expired)
+{
+       ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find chan=%s user=%s check_expired=%d", c ? c->name.c_str() : "NULL", u ? u->uuid.c_str() : "NULL", check_expired);
+       if (!u || u->invites.empty())
+               return NULL;
+
+       InviteList locallist;
+       locallist.swap(u->invites);
+
+       Invitation* result = NULL;
+       for (InviteList::iterator i = locallist.begin(); i != locallist.end(); )
+       {
+               Invitation* inv = *i;
+               if ((check_expired) && (inv->expiry != 0) && (inv->expiry <= ServerInstance->Time()))
+               {
+                       /* Expired invite, remove it. */
+                       ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find ecountered expired entry: %p timed out at %lu", (void*) inv, inv->expiry);
+                       i = locallist.erase(i);
+                       inv->cull();
+                       delete inv;
+               }
+               else
+               {
+                       /* Is it what we're searching for? */
+                       if (inv->chan == c)
+                       {
+                               result = inv;
+                               break;
+                       }
+                       ++i;
+               }
+       }
+
+       locallist.swap(u->invites);
+       ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find result=%p", (void*) result);
+       return result;
+}
+
+Invitation::~Invitation()
+{
+       // Remove this entry from both lists
+       InviteList::iterator it = std::find(chan->invites.begin(), chan->invites.end(), this);
+       if (it != chan->invites.end())
+               chan->invites.erase(it);
+       it = std::find(user->invites.begin(), user->invites.end(), this);
+       if (it != user->invites.end())
+               user->invites.erase(it);
+}
+
+void InviteBase::ClearInvites()
+{
+       ServerInstance->Logs->Log("INVITEBASE", DEBUG, "InviteBase::ClearInvites %p", (void*) this);
+       InviteList locallist;
+       locallist.swap(invites);
+       for (InviteList::const_iterator i = locallist.begin(); i != locallist.end(); ++i)
+       {
+               (*i)->cull();
+               delete *i;
+       }
+}
index 3baa9cb038c8e7b77a16d507ad628a776ae3e0a9..200cce4a3e7ffc511168e89778e91386c64a0551 100644 (file)
@@ -132,10 +132,10 @@ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, Use
        {
                // pinched from ircu - invite with not enough parameters shows channels
                // youve been invited to but haven't joined yet.
-               InvitedList* il = IS_LOCAL(user)->GetInviteList();
-               for (InvitedList::iterator i = il->begin(); i != il->end(); i++)
+               InviteList& il = IS_LOCAL(user)->GetInviteList();
+               for (InviteList::const_iterator i = il.begin(); i != il.end(); ++i)
                {
-                       user->WriteNumeric(RPL_INVITELIST, "%s :%s",user->nick.c_str(),i->first.c_str());
+                       user->WriteNumeric(RPL_INVITELIST, "%s :%s",user->nick.c_str(), (*i)->chan->name.c_str());
                }
                user->WriteNumeric(RPL_ENDOFINVITELIST, "%s :End of INVITE list",user->nick.c_str());
        }
index 005a11dd7c239e502932e956905defbfa7fc059c..cf8c22633315e3538c25a7d50da04bf732ea6c8b 100644 (file)
@@ -220,6 +220,7 @@ void InspIRCd::RehashUsersAndChans()
        for (std::vector<LocalUser*>::const_iterator i = Users->local_users.begin(); i != Users->local_users.end(); i++)
        {
                (**i).already_sent = 0;
+               (**i).RemoveExpiredInvites();
        }
 }
 
index 50775be1d30f7f9931cb279f4bb162182b8bf6fd..929ace474f1296271c18c1dd94eb3b098b33402a 100644 (file)
@@ -105,6 +105,7 @@ CmdResult CommandFJoin::Handle(const std::vector<std::string>& params, User *src
                        // while the name is equal in case-insensitive compare, it might differ in case; use the remote version
                        chan->name = channel;
                        chan->age = TS;
+                       chan->ClearInvites();
                        param_list.push_back(channel);
                        this->RemoveStatus(ServerInstance->FakeClient, param_list);
                }
index 39be8127227195af848f68d261db67adb27c1bf8..020c1a9bf17d745761aaa5d393005aef1ccafea4 100644 (file)
@@ -333,75 +333,45 @@ const std::string& User::GetFullRealHost()
 
 bool LocalUser::IsInvited(const irc::string &channel)
 {
-       time_t now = ServerInstance->Time();
-       InvitedList::iterator safei;
-       for (InvitedList::iterator i = invites.begin(); i != invites.end(); ++i)
-       {
-               if (channel == i->first)
-               {
-                       if (i->second != 0 && now > i->second)
-                       {
-                               /* Expired invite, remove it. */
-                               safei = i;
-                               --i;
-                               invites.erase(safei);
-                               continue;
-                       }
-                       return true;
-               }
-       }
-       return false;
+       Channel* chan = ServerInstance->FindChan(channel.c_str());
+       if (!chan)
+               return false;
+
+       return (Invitation::Find(chan, this) != NULL);
 }
 
-InvitedList* LocalUser::GetInviteList()
+InviteList& LocalUser::GetInviteList()
 {
-       time_t now = ServerInstance->Time();
-       /* Weed out expired invites here. */
-       InvitedList::iterator safei;
-       for (InvitedList::iterator i = invites.begin(); i != invites.end(); ++i)
-       {
-               if (i->second != 0 && now > i->second)
-               {
-                       /* Expired invite, remove it. */
-                       safei = i;
-                       --i;
-                       invites.erase(safei);
-               }
-       }
-       return &invites;
+       RemoveExpiredInvites();
+       return invites;
 }
 
 void LocalUser::InviteTo(const irc::string &channel, time_t invtimeout)
 {
-       time_t now = ServerInstance->Time();
-       if (invtimeout != 0 && now > invtimeout) return; /* Don't add invites that are expired from the get-go. */
-       for (InvitedList::iterator i = invites.begin(); i != invites.end(); ++i)
-       {
-               if (channel == i->first)
-               {
-                       if (i->second != 0 && invtimeout > i->second)
-                       {
-                               i->second = invtimeout;
-                       }
-
-                       return;
-               }
-       }
-       invites.push_back(std::make_pair(channel, invtimeout));
+       Channel* chan = ServerInstance->FindChan(channel.c_str());
+       if (chan)
+               Invitation::Create(chan, this, invtimeout);
 }
 
 void LocalUser::RemoveInvite(const irc::string &channel)
 {
-       for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
+       Channel* chan = ServerInstance->FindChan(channel.c_str());
+       if (chan)
        {
-               if (channel == i->first)
+               Invitation* inv = Invitation::Find(chan, this);
+               if (inv)
                {
-                       invites.erase(i);
-                       return;
-               }
+                       inv->cull();
+                       delete inv;
+               }
        }
 }
 
+void LocalUser::RemoveExpiredInvites()
+{
+       Invitation::Find(NULL, this);
+}
+
 bool User::HasModePermission(unsigned char, ModeType)
 {
        return true;
@@ -560,8 +530,6 @@ CullResult User::cull()
                ServerInstance->Users->QuitUser(this, "Culled without QuitUser");
        PurgeEmptyChannels();
 
-       this->InvalidateCache();
-
        if (client_sa.sa.sa_family != AF_UNSPEC)
                ServerInstance->Users->RemoveCloneCounts(this);
 
@@ -576,6 +544,7 @@ CullResult LocalUser::cull()
        else
                ServerInstance->Logs->Log("USERS", DEBUG, "Failed to remove user from vector");
 
+       ClearInvites();
        eh.cull();
        return User::cull();
 }