summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/channels.h2
-rw-r--r--include/membership.h25
-rw-r--r--include/typedefs.h4
-rw-r--r--include/users.h13
-rw-r--r--src/channels.cpp88
-rw-r--r--src/commands/cmd_invite.cpp6
-rw-r--r--src/inspircd.cpp1
-rw-r--r--src/modules/m_spanningtree/fjoin.cpp1
-rw-r--r--src/users.cpp79
9 files changed, 151 insertions, 68 deletions
diff --git a/include/channels.h b/include/channels.h
index 89ac6b86c..7e70fd6c5 100644
--- a/include/channels.h
+++ b/include/channels.h
@@ -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
*/
diff --git a/include/membership.h b/include/membership.h
index 281d04f70..340f92a12 100644
--- a/include/membership.h
+++ b/include/membership.h
@@ -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
diff --git a/include/typedefs.h b/include/typedefs.h
index 615af6c9c..7659628d2 100644
--- a/include/typedefs.h
+++ b/include/typedefs.h
@@ -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)
*/
diff --git a/include/users.h b/include/users.h
index cdc0d8078..66e867ad0 100644
--- a/include/users.h
+++ b/include/users.h
@@ -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.
diff --git a/src/channels.cpp b/src/channels.cpp
index 4a927cedb..f1dba5315 100644
--- a/src/channels.cpp
+++ b/src/channels.cpp
@@ -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;
+ }
+}
diff --git a/src/commands/cmd_invite.cpp b/src/commands/cmd_invite.cpp
index 3baa9cb03..200cce4a3 100644
--- a/src/commands/cmd_invite.cpp
+++ b/src/commands/cmd_invite.cpp
@@ -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());
}
diff --git a/src/inspircd.cpp b/src/inspircd.cpp
index 005a11dd7..cf8c22633 100644
--- a/src/inspircd.cpp
+++ b/src/inspircd.cpp
@@ -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();
}
}
diff --git a/src/modules/m_spanningtree/fjoin.cpp b/src/modules/m_spanningtree/fjoin.cpp
index 50775be1d..929ace474 100644
--- a/src/modules/m_spanningtree/fjoin.cpp
+++ b/src/modules/m_spanningtree/fjoin.cpp
@@ -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);
}
diff --git a/src/users.cpp b/src/users.cpp
index 39be81272..020c1a9bf 100644
--- a/src/users.cpp
+++ b/src/users.cpp
@@ -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();
}