diff options
-rw-r--r-- | include/channels.h | 2 | ||||
-rw-r--r-- | include/configreader.h | 4 | ||||
-rw-r--r-- | include/membership.h | 83 | ||||
-rw-r--r-- | include/modules/invite.h | 128 | ||||
-rw-r--r-- | include/usermanager.h | 16 | ||||
-rw-r--r-- | include/users.h | 24 | ||||
-rw-r--r-- | src/channels.cpp | 86 | ||||
-rw-r--r-- | src/configreader.cpp | 3 | ||||
-rw-r--r-- | src/coremods/core_channel/cmd_invite.cpp | 13 | ||||
-rw-r--r-- | src/coremods/core_channel/core_channel.cpp | 66 | ||||
-rw-r--r-- | src/coremods/core_channel/core_channel.h | 9 | ||||
-rw-r--r-- | src/coremods/core_channel/invite.cpp | 208 | ||||
-rw-r--r-- | src/coremods/core_channel/invite.h | 127 | ||||
-rw-r--r-- | src/coremods/core_info/cmd_info.cpp | 24 | ||||
-rw-r--r-- | src/inspircd.cpp | 10 | ||||
-rw-r--r-- | src/modules/extra/m_ssl_gnutls.cpp | 93 | ||||
-rw-r--r-- | src/modules/extra/m_ssl_openssl.cpp | 14 | ||||
-rw-r--r-- | src/modules/m_hostcycle.cpp | 4 | ||||
-rw-r--r-- | src/modules/m_override.cpp | 5 | ||||
-rw-r--r-- | src/modules/m_spanningtree/fjoin.cpp | 3 | ||||
-rw-r--r-- | src/modules/m_uninvite.cpp | 8 | ||||
-rw-r--r-- | src/usermanager.cpp | 29 | ||||
-rw-r--r-- | src/users.cpp | 27 |
23 files changed, 688 insertions, 298 deletions
diff --git a/include/channels.h b/include/channels.h index 4d1d14c13..be84ac800 100644 --- a/include/channels.h +++ b/include/channels.h @@ -34,7 +34,7 @@ * 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, public InviteBase<Channel> +class CoreExport Channel : public Extensible { public: /** A map of Memberships on a channel keyed by User pointers diff --git a/include/configreader.h b/include/configreader.h index 57d7ab069..9b73dd3c6 100644 --- a/include/configreader.h +++ b/include/configreader.h @@ -495,10 +495,6 @@ class CoreExport ServerConfig */ static std::string Escape(const std::string& str, bool xml = true); - /** If this value is true, invites will bypass more than just +i - */ - bool InvBypassModes; - /** If this value is true, snotices will not stack when repeats are sent */ bool NoSnoticeStack; diff --git a/include/membership.h b/include/membership.h index 11c142912..05d6b3796 100644 --- a/include/membership.h +++ b/include/membership.h @@ -112,86 +112,3 @@ class CoreExport Membership : public Extensible, public insp::intrusive_list_nod */ const char* GetAllPrefixChars() const; }; - -template <typename T> -class InviteBase -{ - protected: - /** List of pending Invitations - */ - insp::intrusive_list<Invitation, T> invites; - - public: - /** Remove and destruct all pending invitations this user or channel has. - * Must be called before the object is destroyed, also called when the TS of the channel is lowered. - */ - void ClearInvites(); - - friend class Invitation; -}; - -/** - * The Invitation class contains all data about a pending invitation. - * Invitation objects are referenced from the user and the channel they belong to. - */ -class CoreExport Invitation : public insp::intrusive_list_node<Invitation, Channel>, public insp::intrusive_list_node<Invitation, LocalUser> -{ - /** Constructs an Invitation, only called by Create() - * @param c Channel the user is invited to - * @param u User being invited - * @param timeout Expiration time for this Invitation - */ - Invitation(Channel* c, LocalUser* u, time_t timeout) : user(u), chan(c), expiry(timeout) {} - - public: - /** User the invitation is for - */ - LocalUser* const user; - - /** Channel where the user is invited to - */ - Channel* const chan; - - /** Timestamp when this Invitation expires or 0 if it doesn't expire. - * Invitation::Create() can update this field; see that for more info. - */ - time_t expiry; - - /** Destructor - * Removes references to this Invitation from the associated user and channel. - */ - ~Invitation(); - - /** Create or extend an Invitation. - * When a user is invited to join a channel either a new Invitation object is created or - * or the expiration timestamp is updated if there is already a pending Invitation for - * the given (user, channel) pair and the new expiration time is further than the current. - * @param c Target channel - * @param u Target user - * @param timeout Timestamp when the invite should expire, 0 for no expiration - */ - static void Create(Channel* c, LocalUser* u, time_t timeout); - - /** Finds the Invitation object for the given channel/user pair. - * @param c Target channel, can be NULL to remove expired entries - * @param u Target user, cannot be NULL - * @param check_expired Pass true to remove all expired invites found while searching, false - * to return with an Invitation even if it's expired - * @return Invitation object for the given (channel, user) pair if it exists, NULL otherwise - */ - static Invitation* Find(Channel* c, LocalUser* u, bool check_expired = true); -}; - -typedef insp::intrusive_list<Invitation, LocalUser> InviteList; - -template<typename T> -inline void InviteBase<T>::ClearInvites() -{ - for (typename insp::intrusive_list<Invitation, T>::iterator i = invites.begin(); i != invites.end(); ) - { - Invitation* inv = *i; - // Destructing the Invitation invalidates the iterator, so move it now - ++i; - delete inv; - } -} diff --git a/include/modules/invite.h b/include/modules/invite.h new file mode 100644 index 000000000..e53d5202f --- /dev/null +++ b/include/modules/invite.h @@ -0,0 +1,128 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2012, 2015 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +namespace Invite +{ + class APIBase; + class API; + class Invite; + + typedef insp::intrusive_list<Invite, LocalUser> List; +} + +class Invite::APIBase : public DataProvider +{ + public: + APIBase(Module* parent); + + /** Create or extend an Invite. + * When a user is invited to join a channel either a new Invite object is created or + * or the expiration timestamp is updated if there is already a pending Invite for + * the given (user, channel) pair and the new expiration time is further than the current. + * @param user Target user + * @param chan Target channel + * @param timeout Timestamp when the invite should expire, 0 for no expiration + */ + virtual void Create(LocalUser* user, Channel* chan, time_t timeout) = 0; + + /** Retrieves the Invite object for the given (user, channel) pair + * @param user Target user + * @param chan Target channel + * @return Invite object for the given (channel, user) pair if it exists, NULL otherwise + */ + virtual Invite* Find(LocalUser* user, Channel* chan) = 0; + + /** Returns the list of channels a user has been invited to but has not yet joined. + * @param user User whose invite list to retrieve + * @return List of channels the user is invited to or NULL if the list is empty + */ + virtual const List* GetList(LocalUser* user) = 0; + + /** Check if a user is invited to a channel + * @param user User to check + * @param chan Channel to check + * @return True if the user is invited to the channel, false otherwise + */ + bool IsInvited(LocalUser* user, Channel* chan) { return (Find(user, chan) != NULL); } + + /** Removes an Invite if it exists + * @param user User whose invite to remove + * @param chan Channel to remove the invite to + * @return True if the user was invited to the channel and the invite was removed, false if the user wasn't invited + */ + virtual bool Remove(LocalUser* user, Channel* chan) = 0; +}; + +class Invite::API : public dynamic_reference<APIBase> +{ + public: + API(Module* parent) + : dynamic_reference<APIBase>(parent, "core_channel_invite") + { + } +}; + +/** + * The Invite class contains all data about a pending invite. + * Invite objects are referenced from the user and the channel they belong to. + */ +class Invite::Invite : public insp::intrusive_list_node<Invite, LocalUser>, public insp::intrusive_list_node<Invite, Channel> +{ + public: + /** User the invite is for + */ + LocalUser* const user; + + /** Channel where the user is invited to + */ + Channel* const chan; + + /** Check whether the invite will expire or not + * @return True if the invite is timed, false if it doesn't expire + */ + bool IsTimed() const { return (expiretimer != NULL); } + + /** Serialize this object + * @param format Serialization format + * @param show_chans True to include channel in the output, false to include the nick/uuid + * @param out Output will be appended to this string + */ + void Serialize(SerializeFormat format, bool show_chans, std::string& out); + + friend class APIImpl; + + private: + /** Timer handling expiration. If NULL this invite doesn't expire. + */ + Timer* expiretimer; + + /** Constructor, only available to the module providing the invite API (core_channel). + * To create Invites use InviteAPI::Create(). + * @param user User being invited + * @param chan Channel the user is invited to + */ + Invite(LocalUser* user, Channel* chan); + + /** Destructor, only available to the module providing the invite API (core_channel). + * To remove Invites use InviteAPI::Remove(). + */ + ~Invite(); +}; diff --git a/include/usermanager.h b/include/usermanager.h index a67f90224..941569e8c 100644 --- a/include/usermanager.h +++ b/include/usermanager.h @@ -56,6 +56,11 @@ class CoreExport UserManager : public fakederef<UserManager> */ LocalList local_users; + /** Last used already sent id, used when sending messages to neighbors to help determine whether the message has + * been sent to a particular user or not. See User::ForEachNeighbor() for more info. + */ + already_sent_t already_sent_id; + public: /** Constructor, initializes variables */ @@ -83,12 +88,6 @@ class CoreExport UserManager : public fakederef<UserManager> */ unsigned int unregistered_count; - /** - * Reset the already_sent IDs so we don't wrap it around and drop a message - * Also removes all expired invites - */ - void GarbageCollect(); - /** Perform background user events such as PING checks */ void DoBackgroundUserStuff(); @@ -187,4 +186,9 @@ class CoreExport UserManager : public fakederef<UserManager> * @param ... The format arguments */ void ServerNoticeAll(const char* text, ...) CUSTOM_PRINTF(2, 3); + + /** Retrieves the next already sent id, guaranteed to be not equal to any user's already_sent field + * @return Next already_sent id + */ + already_sent_t NextAlreadySentId(); }; diff --git a/include/users.h b/include/users.h index fa8f610bc..fa346a329 100644 --- a/include/users.h +++ b/include/users.h @@ -641,7 +641,7 @@ class CoreExport UserIOHandler : public StreamSocket typedef unsigned int already_sent_t; -class CoreExport LocalUser : public User, public InviteBase<LocalUser>, public insp::intrusive_list_node<LocalUser> +class CoreExport LocalUser : public User, public insp::intrusive_list_node<LocalUser> { public: LocalUser(int fd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server); @@ -720,7 +720,6 @@ class CoreExport LocalUser : public User, public InviteBase<LocalUser>, public i */ unsigned int CommandFloodPenalty; - static already_sent_t already_sent_id; already_sent_t already_sent; /** Check if the user matches a G or K line, and disconnect them if they do. @@ -748,27 +747,6 @@ class CoreExport LocalUser : public User, public InviteBase<LocalUser>, public i void Write(const std::string& text); void Write(const char*, ...) CUSTOM_PRINTF(2, 3); - /** 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 - */ - InviteList& GetInviteList(); - - /** Returns true if a user is invited to a channel. - * @param chan A channel to look up - * @return True if the user is invited to the given channel - */ - bool IsInvited(Channel* chan) { return (Invitation::Find(chan, this) != NULL); } - - /** Removes a channel from a users invite list. - * This member function is called on successfully joining an invite only channel - * to which the user has previously been invited, to clear the invitation. - * @param chan The channel to remove the invite to - * @return True if the user was invited to the channel and the invite was erased, false if the user wasn't invited - */ - bool RemoveInvite(Channel* chan); - - 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 f79b5b89f..6e3bc5e04 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -90,7 +90,6 @@ void Channel::CheckDestroy() FOREACH_MOD(OnChannelDelete, (this)); ServerInstance->chanlist.erase(iter); - ClearInvites(); ServerInstance->GlobalCulls.AddItem(this); } @@ -235,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()); @@ -252,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; @@ -263,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); - } } } } @@ -650,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); -} diff --git a/src/configreader.cpp b/src/configreader.cpp index 974e52abf..a81a1b646 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -56,7 +56,7 @@ ServerConfig::ServerConfig() , NoSnoticeStack(false) { RawLog = HideBans = HideSplits = UndernetMsgPrefix = false; - WildcardIPv6 = InvBypassModes = true; + WildcardIPv6 = true; dns_timeout = 5; MaxTargets = 20; NetBufferSize = 10240; @@ -427,7 +427,6 @@ void ServerConfig::Fill() Paths.Data = ConfValue("path")->getString("datadir", INSPIRCD_DATA_PATH); Paths.Log = ConfValue("path")->getString("logdir", INSPIRCD_LOG_PATH); Paths.Module = ConfValue("path")->getString("moduledir", INSPIRCD_MODULE_PATH); - InvBypassModes = options->getBool("invitebypassmodes", true); NoSnoticeStack = options->getBool("nosnoticestack", false); if (Network.find(' ') != std::string::npos) diff --git a/src/coremods/core_channel/cmd_invite.cpp b/src/coremods/core_channel/cmd_invite.cpp index 7bf669b29..96f560582 100644 --- a/src/coremods/core_channel/cmd_invite.cpp +++ b/src/coremods/core_channel/cmd_invite.cpp @@ -22,9 +22,11 @@ #include "inspircd.h" #include "core_channel.h" +#include "invite.h" -CommandInvite::CommandInvite(Module* parent) +CommandInvite::CommandInvite(Module* parent, Invite::APIImpl& invapiimpl) : Command(parent, "INVITE", 0, 0) + , invapi(invapiimpl) { Penalty = 4; syntax = "[<nick> <channel>]"; @@ -109,7 +111,7 @@ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, Use if (IS_LOCAL(u)) { - Invitation::Create(c, IS_LOCAL(u), timeout); + invapi.Create(IS_LOCAL(u), c, timeout); u->WriteFrom(user,"INVITE %s :%s",u->nick.c_str(),c->name.c_str()); } @@ -150,10 +152,11 @@ 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. - InviteList& il = IS_LOCAL(user)->GetInviteList(); - for (InviteList::const_iterator i = il.begin(); i != il.end(); ++i) + const Invite::List* list = invapi.GetList(IS_LOCAL(user)); + if (list) { - user->WriteNumeric(RPL_INVITELIST, ":%s", (*i)->chan->name.c_str()); + for (Invite::List::const_iterator i = list->begin(); i != list->end(); ++i) + user->WriteNumeric(RPL_INVITELIST, ":%s", (*i)->chan->name.c_str()); } user->WriteNumeric(RPL_ENDOFINVITELIST, ":End of INVITE list"); } diff --git a/src/coremods/core_channel/core_channel.cpp b/src/coremods/core_channel/core_channel.cpp index 99ad74d3d..aba4d9769 100644 --- a/src/coremods/core_channel/core_channel.cpp +++ b/src/coremods/core_channel/core_channel.cpp @@ -1,7 +1,7 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com> + * Copyright (C) 2014-2015 Attila Molnar <attilamolnar@hush.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -19,27 +19,54 @@ #include "inspircd.h" #include "core_channel.h" +#include "invite.h" class CoreModChannel : public Module { + Invite::APIImpl invapi; CommandInvite cmdinvite; CommandJoin cmdjoin; CommandKick cmdkick; CommandNames cmdnames; CommandTopic cmdtopic; + ModResult IsInvited(User* user, Channel* chan) + { + LocalUser* localuser = IS_LOCAL(user); + if ((localuser) && (invapi.IsInvited(localuser, chan))) + return MOD_RES_ALLOW; + return MOD_RES_PASSTHRU; + } + public: CoreModChannel() - : cmdinvite(this), cmdjoin(this), cmdkick(this), cmdnames(this), cmdtopic(this) + : invapi(this) + , cmdinvite(this, invapi), cmdjoin(this), cmdkick(this), cmdnames(this), cmdtopic(this) { } + void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE + { + ConfigTag* optionstag = ServerInstance->Config->ConfValue("options"); + Implementation events[] = { I_OnCheckKey, I_OnCheckLimit, I_OnCheckChannelBan }; + if (optionstag->getBool("invitebypassmodes", true)) + ServerInstance->Modules.Attach(events, this, sizeof(events)/sizeof(Implementation)); + else + { + for (unsigned int i = 0; i < sizeof(events)/sizeof(Implementation); i++) + ServerInstance->Modules.Detach(events[i], this); + } + } + void OnPostJoin(Membership* memb) CXX11_OVERRIDE { Channel* const chan = memb->chan; LocalUser* const localuser = IS_LOCAL(memb->user); if (localuser) { + // Remove existing invite, if any + invapi.Remove(localuser, chan); + if (chan->topicset) Topic::ShowTopic(localuser, chan); @@ -48,6 +75,41 @@ class CoreModChannel : public Module } } + ModResult OnCheckKey(User* user, Channel* chan, const std::string& keygiven) CXX11_OVERRIDE + { + // Hook only runs when being invited bypasses +bkl + return IsInvited(user, chan); + } + + ModResult OnCheckChannelBan(User* user, Channel* chan) CXX11_OVERRIDE + { + // Hook only runs when being invited bypasses +bkl + return IsInvited(user, chan); + } + + ModResult OnCheckLimit(User* user, Channel* chan) CXX11_OVERRIDE + { + // Hook only runs when being invited bypasses +bkl + return IsInvited(user, chan); + } + + ModResult OnCheckInvite(User* user, Channel* chan) CXX11_OVERRIDE + { + // Hook always runs + return IsInvited(user, chan); + } + + void OnUserDisconnect(LocalUser* user) CXX11_OVERRIDE + { + invapi.RemoveAll(user); + } + + void OnChannelDelete(Channel* chan) CXX11_OVERRIDE + { + // Make sure the channel won't appear in invite lists from now on, don't wait for cull to unset the ext + invapi.RemoveAll(chan); + } + void Prioritize() CXX11_OVERRIDE { ServerInstance->Modules.SetPriority(this, I_OnPostJoin, PRIORITY_FIRST); diff --git a/src/coremods/core_channel/core_channel.h b/src/coremods/core_channel/core_channel.h index 755f876f6..2a2800523 100644 --- a/src/coremods/core_channel/core_channel.h +++ b/src/coremods/core_channel/core_channel.h @@ -26,14 +26,21 @@ namespace Topic void ShowTopic(LocalUser* user, Channel* chan); } +namespace Invite +{ + class APIImpl; +} + /** Handle /INVITE. */ class CommandInvite : public Command { + Invite::APIImpl& invapi; + public: /** Constructor for invite. */ - CommandInvite (Module* parent); + CommandInvite(Module* parent, Invite::APIImpl& invapiimpl); /** Handle command. * @param parameters The parameters to the command diff --git a/src/coremods/core_channel/invite.cpp b/src/coremods/core_channel/invite.cpp new file mode 100644 index 000000000..7ac662edc --- /dev/null +++ b/src/coremods/core_channel/invite.cpp @@ -0,0 +1,208 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2012, 2015 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#include "inspircd.h" + +#include "invite.h" + +class InviteExpireTimer : public Timer +{ + Invite::Invite* const inv; + + bool Tick(time_t currtime) CXX11_OVERRIDE; + + public: + InviteExpireTimer(Invite::Invite* invite, time_t timeout); +}; + +static Invite::APIImpl* apiimpl; + +void RemoveInvite(Invite::Invite* inv, bool remove_user, bool remove_chan) +{ + apiimpl->Destruct(inv, remove_user, remove_chan); +} + +void UnserializeInvite(LocalUser* user, const std::string& str) +{ + apiimpl->Unserialize(user, str); +} + +Invite::APIBase::APIBase(Module* parent) + : DataProvider(parent, "core_channel_invite") +{ +} + +Invite::APIImpl::APIImpl(Module* parent) + : APIBase(parent) + , userext(parent, "invite_user") + , chanext(parent, "invite_chan") +{ + apiimpl = this; +} + +void Invite::APIImpl::Destruct(Invite* inv, bool remove_user, bool remove_chan) +{ + Store<LocalUser>* ustore = userext.get(inv->user); + if (ustore) + { + ustore->invites.erase(inv); + if ((remove_user) && (ustore->invites.empty())) + userext.unset(inv->user); + } + + Store<Channel>* cstore = chanext.get(inv->chan); + if (cstore) + { + cstore->invites.erase(inv); + if ((remove_chan) && (cstore->invites.empty())) + chanext.unset(inv->chan); + } + + delete inv; +} + +bool Invite::APIImpl::Remove(LocalUser* user, Channel* chan) +{ + Invite* inv = Find(user, chan); + if (inv) + { + Destruct(inv); + return true; + } + return false; +} + +void Invite::APIImpl::Create(LocalUser* user, Channel* chan, time_t timeout) +{ + if ((timeout != 0) && (ServerInstance->Time() >= timeout)) + // Expired, don't bother + return; + + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Invite::APIImpl::Create(): user=%s chan=%s timeout=%lu", user->uuid.c_str(), chan->name.c_str(), (unsigned long)timeout); + + Invite* inv = Find(user, chan); + if (inv) + { + // We only ever extend invites, so nothing to do if the existing one is not timed + if (!inv->IsTimed()) + return; + + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Invite::APIImpl::Create(): changing expiration in %p", (void*) inv); + if (timeout == 0) + { + // Convert timed invite to non-expiring + delete inv->expiretimer; + inv->expiretimer = NULL; + } + else if (inv->expiretimer->GetTrigger() >= ServerInstance->Time() + timeout) + { + // New expiration time is further than the current, extend the expiration + inv->expiretimer->SetInterval(timeout - ServerInstance->Time()); + } + } + else + { + inv = new Invite(user, chan); + if (timeout) + { + inv->expiretimer = new InviteExpireTimer(inv, timeout - ServerInstance->Time()); + ServerInstance->Timers.AddTimer(inv->expiretimer); + } + + userext.get(user, true)->invites.push_front(inv); + chanext.get(chan, true)->invites.push_front(inv); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Invite::APIImpl::Create(): created new Invite %p", (void*) inv); + } +} + +Invite::Invite* Invite::APIImpl::Find(LocalUser* user, Channel* chan) +{ + const List* list = APIImpl::GetList(user); + if (!list) + return NULL; + + for (List::iterator i = list->begin(); i != list->end(); ++i) + { + Invite* inv = *i; + if (inv->chan == chan) + return inv; + } + + return NULL; +} + +const Invite::List* Invite::APIImpl::GetList(LocalUser* user) +{ + Store<LocalUser>* list = userext.get(user); + if (list) + return &list->invites; + return NULL; +} + +void Invite::APIImpl::Unserialize(LocalUser* user, const std::string& value) +{ + irc::spacesepstream ss(value); + for (std::string channame, exptime; (ss.GetToken(channame) && ss.GetToken(exptime)); ) + { + Channel* chan = ServerInstance->FindChan(channame); + if (chan) + Create(user, chan, ConvToInt(exptime)); + } +} + +Invite::Invite::Invite(LocalUser* u, Channel* c) + : user(u) + , chan(c) + , expiretimer(NULL) +{ +} + +Invite::Invite::~Invite() +{ + delete expiretimer; + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Invite::~ %p", (void*) this); +} + +void Invite::Invite::Serialize(SerializeFormat format, bool show_chans, std::string& out) +{ + if (show_chans) + out.append(this->chan->name); + else + out.append((format == FORMAT_USER) ? user->nick : user->uuid); + out.push_back(' '); + + if (expiretimer) + out.append(ConvToStr(expiretimer->GetTrigger())); + else + out.push_back('0'); + out.push_back(' '); +} + +InviteExpireTimer::InviteExpireTimer(Invite::Invite* invite, time_t timeout) + : Timer(timeout) + , inv(invite) +{ +} + +bool InviteExpireTimer::Tick(time_t currtime) +{ + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "InviteExpireTimer::Tick(): expired %p", (void*) inv); + apiimpl->Destruct(inv); + return false; +} diff --git a/src/coremods/core_channel/invite.h b/src/coremods/core_channel/invite.h new file mode 100644 index 000000000..2a99ec2df --- /dev/null +++ b/src/coremods/core_channel/invite.h @@ -0,0 +1,127 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "modules/invite.h" + +namespace Invite +{ + template<typename T> + struct Store + { + typedef insp::intrusive_list<Invite, T> List; + + /** List of pending Invites + */ + List invites; + }; + + template<typename T, ExtensionItem::ExtensibleType ExtType> + class ExtItem; + + class APIImpl; +} + +extern void RemoveInvite(Invite::Invite* inv, bool remove_user, bool remove_chan); +extern void UnserializeInvite(LocalUser* user, const std::string& value); + +template<typename T, ExtensionItem::ExtensibleType ExtType> +class Invite::ExtItem : public ExtensionItem +{ + public: + ExtItem(Module* owner, const char* extname) + : ExtensionItem(extname, ExtType, owner) + { + } + + Store<T>* get(Extensible* ext, bool create = false) + { + Store<T>* store = static_cast<Store<T>*>(get_raw(ext)); + if ((create) && (!store)) + { + store = new Store<T>; + set_raw(ext, store); + } + return store; + } + + void unset(Extensible* ext) + { + void* store = unset_raw(ext); + if (store) + free(store); + } + + void free(void* item) CXX11_OVERRIDE + { + Store<T>* store = static_cast<Store<T>*>(item); + for (typename Store<T>::List::iterator i = store->invites.begin(); i != store->invites.end(); ) + { + Invite* inv = *i; + // Destructing the Invite invalidates the iterator, so move it now + ++i; + RemoveInvite(inv, (ExtType != ExtensionItem::EXT_USER), (ExtType == ExtensionItem::EXT_USER)); + } + + delete store; + } + + std::string serialize(SerializeFormat format, const Extensible* container, void* item) const CXX11_OVERRIDE + { + if (format == FORMAT_NETWORK) + return std::string(); + + std::string ret; + Store<T>* store = static_cast<Store<T>*>(item); + for (typename insp::intrusive_list<Invite, T>::iterator i = store->invites.begin(); i != store->invites.end(); ++i) + { + Invite* inv = *i; + inv->Serialize(format, (ExtType == ExtensionItem::EXT_USER), ret); + } + if (!ret.empty()) + ret.erase(ret.length()-1); + return ret; + } + + void unserialize(SerializeFormat format, Extensible* container, const std::string& value) CXX11_OVERRIDE + { + if ((ExtType != ExtensionItem::EXT_CHANNEL) && (format != FORMAT_NETWORK)) + UnserializeInvite(static_cast<LocalUser*>(container), value); + } +}; + +class Invite::APIImpl : public APIBase +{ + ExtItem<LocalUser, ExtensionItem::EXT_USER> userext; + ExtItem<Channel, ExtensionItem::EXT_CHANNEL> chanext; + + public: + APIImpl(Module* owner); + + void Create(LocalUser* user, Channel* chan, time_t timeout) CXX11_OVERRIDE; + Invite* Find(LocalUser* user, Channel* chan) CXX11_OVERRIDE; + bool Remove(LocalUser* user, Channel* chan) CXX11_OVERRIDE; + const List* GetList(LocalUser* user) CXX11_OVERRIDE; + + void RemoveAll(LocalUser* user) { userext.unset(user); } + void RemoveAll(Channel* chan) { chanext.unset(chan); } + void Destruct(Invite* inv, bool remove_chan = true, bool remove_user = true); + void Unserialize(LocalUser* user, const std::string& value); +}; diff --git a/src/coremods/core_info/cmd_info.cpp b/src/coremods/core_info/cmd_info.cpp index 0d8c1a45a..8dad99453 100644 --- a/src/coremods/core_info/cmd_info.cpp +++ b/src/coremods/core_info/cmd_info.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2011 Jackmcbarn <jackmcbarn@jackmcbarn.no-ip.org> * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> - * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net> + * Copyright (C) 2007-2015 Robin Burchell <robin+git@viroteck.net> * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can @@ -35,9 +35,10 @@ static const char* const lines[] = { " November 2002 - Present", " ", "\2Core Developers\2:", - " Craig Edwards, Brain, <brain@inspircd.org>", - " Craig McLure, Craig, <craig@inspircd.org>", - " Robin Burchell, w00t, <w00t@inspircd.org>", + " Attila Molnar, Attila, <attilamolnar@hush.com>", + " Peter Powell, SaberUK, <petpow@saberuk.com>", + " ", + "\2Former Developers\2:", " Oliver Lupton, Om, <om@inspircd.org>", " John Brooks, Special, <special@inspircd.org>", " Dennis Friis, peavey, <peavey@inspircd.org>", @@ -45,14 +46,14 @@ static const char* const lines[] = { " Uli Schlachter, psychon, <psychon@inspircd.org>", " Matt Smith, dz, <dz@inspircd.org>", " Daniel De Graaf, danieldg, <danieldg@inspircd.org>", - " jackmcbarn, <jackmcbarn@inspircd.org>", - " Attila Molnar, Attila, <attilamolnar@hush.com>", " ", - "\2Regular Contributors\2:", - " Adam SaberUK", + "\2Founding Developers\2:", + " Craig Edwards, Brain, <brain@inspircd.org>", + " Craig McLure, Craig, <craig@inspircd.org>", + " Robin Burchell, w00t, <w00t@inspircd.org>", " ", - "\2Other Contributors\2:", - " ChrisTX Shawn Shutter", + "\2Active Contributors\2:", + " Adam Shutter", " ", "\2Former Contributors\2:", " dmb Zaba skenmy GreenReaper", @@ -64,9 +65,10 @@ static const char* const lines[] = { " Stskeeps ThaPrince BuildSmart Thunderhacker", " Skip LeaChim Majic MacGyver", " Namegduf Ankit Phoenix Taros", + " jackmcbarn ChrisTX Shawn", " ", "\2Thanks To\2:", - " searchirc.com irc-junkie.org Brik fraggeln", + " Asmo Brik fraggeln", " ", " Best experienced with: \2An IRC client\2", NULL diff --git a/src/inspircd.cpp b/src/inspircd.cpp index fce99f421..69aa2619c 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -367,12 +367,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : } std::cout << con_green << "InspIRCd - Internet Relay Chat Daemon" << con_reset << ", compiled on " __DATE__ " at " __TIME__ << std::endl; - std::cout << con_green << "(C) InspIRCd Development Team." << con_reset << std::endl << std::endl; - std::cout << "Developers:" << std::endl; - std::cout << con_green << "\tBrain, FrostyCoolSlug, w00t, Om, Special, peavey" << std::endl; - std::cout << "\taquanight, psychon, dz, danieldg, jackmcbarn" << std::endl; - std::cout << "\tAttila" << con_reset << std::endl << std::endl; - std::cout << "Others:\t\t\t" << con_green << "See /INFO Output" << con_reset << std::endl; + std::cout << "For contributors & authors: " << con_green << "See /INFO Output" << con_reset << std::endl; #ifndef _WIN32 if (!do_root) @@ -664,10 +659,7 @@ void InspIRCd::Run() OLDTIME = TIME.tv_sec; if ((TIME.tv_sec % 3600) == 0) - { - Users->GarbageCollect(); FOREACH_MOD(OnGarbageCollect, ()); - } Timers.TickTimers(TIME.tv_sec); Users->DoBackgroundUserStuff(); diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index 962e80d28..716a736f8 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -209,14 +209,6 @@ namespace GnuTLS return dh; } - /** Generate */ - static std::auto_ptr<DHParams> Generate(unsigned int bits) - { - std::auto_ptr<DHParams> dh(new DHParams); - ThrowOnError(gnutls_dh_params_generate2(dh->dh_params, bits), "Unable to generate DH params"); - return dh; - } - ~DHParams() { gnutls_dh_params_deinit(dh_params); @@ -353,6 +345,40 @@ namespace GnuTLS { gnutls_priority_set(sess, priority); } + + static const char* GetDefault() + { + return "NORMAL:%SERVER_PRECEDENCE:-VERS-SSL3.0"; + } + + static std::string RemoveUnknownTokens(const std::string& prio) + { + std::string ret; + irc::sepstream ss(prio, ':'); + for (std::string token; ss.GetToken(token); ) + { + // Save current position so we can revert later if needed + const std::string::size_type prevpos = ret.length(); + // Append next token + if (!ret.empty()) + ret.push_back(':'); + ret.append(token); + + gnutls_priority_t test; + if (gnutls_priority_init(&test, ret.c_str(), NULL) < 0) + { + // The new token broke the priority string, revert to the previously working one + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Priority string token not recognized: \"%s\"", token.c_str()); + ret.erase(prevpos); + } + else + { + // Worked + gnutls_priority_deinit(test); + } + } + return ret; + } }; #else /** Dummy class, used when gnutls_priority_set() is not available @@ -362,7 +388,7 @@ namespace GnuTLS public: Priority(const std::string& priorities) { - if (priorities != "NORMAL") + if (priorities != GetDefault()) throw Exception("You've set a non-default priority string, but GnuTLS lacks support for it"); } @@ -371,6 +397,17 @@ namespace GnuTLS // Always set the default priorities gnutls_set_default_priority(sess); } + + static const char* GetDefault() + { + return "NORMAL"; + } + + static std::string RemoveUnknownTokens(const std::string& prio) + { + // We don't do anything here because only NORMAL is accepted + return prio; + } }; #endif @@ -564,24 +601,40 @@ namespace GnuTLS return ret; } + static std::string GetPrioStr(const std::string& profilename, ConfigTag* tag) + { + // Use default priority string if this tag does not specify one + std::string priostr = GnuTLS::Priority::GetDefault(); + bool found = tag->readString("priority", priostr); + // If the prio string isn't set in the config don't be strict about the default one because it doesn't work on all versions of GnuTLS + if (!tag->getBool("strictpriority", found)) + { + std::string stripped = GnuTLS::Priority::RemoveUnknownTokens(priostr); + if (stripped.empty()) + { + // Stripping failed, act as if a prio string wasn't set + stripped = GnuTLS::Priority::RemoveUnknownTokens(GnuTLS::Priority::GetDefault()); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Priority string for profile \"%s\" contains unknown tokens and stripping it didn't yield a working one either, falling back to \"%s\"", profilename.c_str(), stripped.c_str()); + } + else if ((found) && (stripped != priostr)) + { + // Prio string was set in the config and we ended up with something that works but different + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Priority string for profile \"%s\" contains unknown tokens, stripped to \"%s\"", profilename.c_str(), stripped.c_str()); + } + priostr.swap(stripped); + } + return priostr; + } + public: static reference<Profile> Create(const std::string& profilename, ConfigTag* tag) { std::string certstr = ReadFile(tag->getString("certfile", "cert.pem")); std::string keystr = ReadFile(tag->getString("keyfile", "key.pem")); - std::auto_ptr<DHParams> dh; - int gendh = tag->getInt("gendh"); - if (gendh) - { - gendh = (gendh < 1024 ? 1024 : gendh); - dh = DHParams::Generate(gendh); - } - else - dh = DHParams::Import(ReadFile(tag->getString("dhfile", "dhparams.pem"))); + std::auto_ptr<DHParams> dh = DHParams::Import(ReadFile(tag->getString("dhfile", "dhparams.pem"))); - // Use default priority string if this tag does not specify one - std::string priostr = tag->getString("priority", "NORMAL"); + std::string priostr = GetPrioStr(profilename, tag); unsigned int mindh = tag->getInt("mindhbits", 1024); std::string hashstr = tag->getString("hash", "md5"); diff --git a/src/modules/extra/m_ssl_openssl.cpp b/src/modules/extra/m_ssl_openssl.cpp index 7dd834e13..c9ae14e11 100644 --- a/src/modules/extra/m_ssl_openssl.cpp +++ b/src/modules/extra/m_ssl_openssl.cpp @@ -269,10 +269,10 @@ namespace OpenSSL long setoptions = tag->getInt(ctxname + "setoptions"); long clearoptions = tag->getInt(ctxname + "clearoptions"); #ifdef SSL_OP_NO_COMPRESSION - if (!tag->getBool("compression", true)) + if (!tag->getBool("compression", false)) // Disable compression by default setoptions |= SSL_OP_NO_COMPRESSION; #endif - if (!tag->getBool("sslv3", true)) + if (!tag->getBool("sslv3", false)) // Disable SSLv3 by default setoptions |= SSL_OP_NO_SSLv3; if (!tag->getBool("tlsv1", true)) setoptions |= SSL_OP_NO_TLSv1; @@ -363,6 +363,14 @@ namespace OpenSSL return 1; } + static int destroy(BIO* bio) + { + // XXX: Dummy function to avoid a memory leak in OpenSSL. + // The memory leak happens in BIO_free() (bio_lib.c) when the destroy func of the BIO is NULL. + // This is fixed in OpenSSL but some distros still ship the unpatched version hence we provide this workaround. + return 1; + } + static long ctrl(BIO* bio, int cmd, long num, void* ptr) { if (cmd == BIO_CTRL_FLUSH) @@ -385,7 +393,7 @@ static BIO_METHOD biomethods = NULL, // gets OpenSSL::BIOMethod::ctrl, OpenSSL::BIOMethod::create, - NULL, // destroy, NULL causes older OpenSSL to leak memory in BIO_free() (bio_lib.c) + OpenSSL::BIOMethod::destroy, // destroy, does nothing, see function body for more info NULL // callback_ctrl }; diff --git a/src/modules/m_hostcycle.cpp b/src/modules/m_hostcycle.cpp index e8a0abbf1..d4def6473 100644 --- a/src/modules/m_hostcycle.cpp +++ b/src/modules/m_hostcycle.cpp @@ -29,8 +29,8 @@ class ModuleHostCycle : public Module // GetFullHost() returns the original data at the time this function is called const std::string quitline = ":" + user->GetFullHost() + " QUIT :" + quitmsg; - already_sent_t silent_id = ++LocalUser::already_sent_id; - already_sent_t seen_id = ++LocalUser::already_sent_id; + already_sent_t silent_id = ServerInstance->Users.NextAlreadySentId(); + already_sent_t seen_id = ServerInstance->Users.NextAlreadySentId(); IncludeChanList include_chans(user->chans.begin(), user->chans.end()); std::map<User*,bool> exceptions; diff --git a/src/modules/m_override.cpp b/src/modules/m_override.cpp index 69f4b3bca..8bf1d3079 100644 --- a/src/modules/m_override.cpp +++ b/src/modules/m_override.cpp @@ -25,6 +25,7 @@ #include "inspircd.h" +#include "modules/invite.h" class ModuleOverride : public Module { @@ -34,6 +35,7 @@ class ModuleOverride : public Module ChanModeReference inviteonly; ChanModeReference key; ChanModeReference limit; + Invite::API invapi; static bool IsOverride(unsigned int userlevel, const Modes::ChangeList::List& list) { @@ -67,6 +69,7 @@ class ModuleOverride : public Module , inviteonly(this, "inviteonly") , key(this, "key") , limit(this, "limit") + , invapi(this) { } @@ -177,7 +180,7 @@ class ModuleOverride : public Module { if (chan->IsModeSet(inviteonly) && (CanOverride(user,"INVITE"))) { - if (!user->IsInvited(chan)) + if (!invapi->IsInvited(user, chan)) return HandleJoinOverride(user, chan, keygiven, "invite-only", "+i"); return MOD_RES_ALLOW; } diff --git a/src/modules/m_spanningtree/fjoin.cpp b/src/modules/m_spanningtree/fjoin.cpp index 687bf305e..0879e730a 100644 --- a/src/modules/m_spanningtree/fjoin.cpp +++ b/src/modules/m_spanningtree/fjoin.cpp @@ -272,9 +272,6 @@ void CommandFJoin::LowerTS(Channel* chan, time_t TS, const std::string& newname) chan->name = newname; chan->age = TS; - // Remove all pending invites - chan->ClearInvites(); - // Clear all modes CommandFJoin::RemoveStatus(chan); diff --git a/src/modules/m_uninvite.cpp b/src/modules/m_uninvite.cpp index 97ad841f1..e92688d1d 100644 --- a/src/modules/m_uninvite.cpp +++ b/src/modules/m_uninvite.cpp @@ -21,13 +21,17 @@ #include "inspircd.h" +#include "modules/invite.h" /** Handle /UNINVITE */ class CommandUninvite : public Command { + Invite::API invapi; public: - CommandUninvite(Module* Creator) : Command(Creator,"UNINVITE", 2) + CommandUninvite(Module* Creator) + : Command(Creator, "UNINVITE", 2) + , invapi(Creator) { syntax = "<nick> <channel>"; TRANSLATE2(TR_NICK, TR_TEXT); @@ -73,7 +77,7 @@ class CommandUninvite : public Command LocalUser* lu = IS_LOCAL(u); if (lu) { - if (!lu->RemoveInvite(c)) + if (!invapi->Remove(lu, c)) { user->SendText(":%s 505 %s %s %s :Is not invited to channel %s", user->server->GetName().c_str(), user->nick.c_str(), u->nick.c_str(), c->name.c_str(), c->name.c_str()); return CMD_FAILURE; diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 7e92507ca..ba6bbf36b 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -49,7 +49,8 @@ namespace } UserManager::UserManager() - : unregistered_count(0) + : already_sent_id(0) + , unregistered_count(0) { } @@ -278,17 +279,6 @@ void UserManager::ServerNoticeAll(const char* text, ...) } } -void UserManager::GarbageCollect() -{ - // Reset the already_sent IDs so we don't wrap it around and drop a message - LocalUser::already_sent_id = 0; - for (LocalList::const_iterator i = local_users.begin(); i != local_users.end(); ++i) - { - (**i).already_sent = 0; - (**i).RemoveExpiredInvites(); - } -} - /* this returns true when all modules are satisfied that the user should be allowed onto the irc server * (until this returns true, a user will block in the waiting state, waiting to connect up to the * registration timeout maximum seconds) @@ -371,3 +361,18 @@ void UserManager::DoBackgroundUserStuff() } } } + +already_sent_t UserManager::NextAlreadySentId() +{ + if (++already_sent_id == 0) + { + // Wrapped around, reset the already_sent ids of all users + already_sent_id = 1; + for (LocalList::iterator i = local_users.begin(); i != local_users.end(); ++i) + { + LocalUser* user = *i; + user->already_sent = 0; + } + } + return already_sent_id; +} diff --git a/src/users.cpp b/src/users.cpp index d760c713f..93fd8d065 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -26,8 +26,6 @@ #include "inspircd.h" #include "xline.h" -already_sent_t LocalUser::already_sent_id = 0; - bool User::IsNoticeMaskSet(unsigned char sm) { if (!isalpha(sm)) @@ -139,28 +137,6 @@ const std::string& User::GetFullRealHost() return this->cached_fullrealhost; } -InviteList& LocalUser::GetInviteList() -{ - RemoveExpiredInvites(); - return invites; -} - -bool LocalUser::RemoveInvite(Channel* chan) -{ - Invitation* inv = Invitation::Find(chan, this); - if (inv) - { - delete inv; - return true; - } - return false; -} - -void LocalUser::RemoveExpiredInvites() -{ - Invitation::Find(NULL, this); -} - bool User::HasModePermission(unsigned char, ModeType) { return true; @@ -328,7 +304,6 @@ CullResult User::cull() CullResult LocalUser::cull() { - ClearInvites(); eh.cull(); return User::cull(); } @@ -896,7 +871,7 @@ void User::ForEachNeighbor(ForEachNeighborHandler& handler, bool include_self) FOREACH_MOD(OnBuildNeighborList, (this, include_chans, exceptions)); // Get next id, guaranteed to differ from the already_sent field of all users - const already_sent_t newid = ++LocalUser::already_sent_id; + const already_sent_t newid = ServerInstance->Users.NextAlreadySentId(); // Handle exceptions first for (std::map<User*, bool>::const_iterator i = exceptions.begin(); i != exceptions.end(); ++i) |