* 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
*/
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
class Extensible;
class FakeUser;
class InspIRCd;
+class Invitation;
+class InviteBase;
class LocalUser;
class Membership;
class Module;
/** 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)
*/
#include "inspsocket.h"
#include "dns.h"
#include "mode.h"
+#include "membership.h"
/** connect class types
*/
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();
/** 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
*/
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.
FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
ServerInstance->chanlist->erase(iter);
}
+
+ ClearInvites();
ServerInstance->GlobalCulls.AddItem(this);
}
}
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;
+ }
+}
{
// 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());
}
for (std::vector<LocalUser*>::const_iterator i = Users->local_users.begin(); i != Users->local_users.end(); i++)
{
(**i).already_sent = 0;
+ (**i).RemoveExpiredInvites();
}
}
// 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);
}
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;
ServerInstance->Users->QuitUser(this, "Culled without QuitUser");
PurgeEmptyChannels();
- this->InvalidateCache();
-
if (client_sa.sa.sa_family != AF_UNSPEC)
ServerInstance->Users->RemoveCloneCounts(this);
else
ServerInstance->Logs->Log("USERS", DEBUG, "Failed to remove user from vector");
+ ClearInvites();
eh.cull();
return User::cull();
}