diff options
-rw-r--r-- | include/channels.h | 6 | ||||
-rw-r--r-- | src/channels.cpp | 73 | ||||
-rw-r--r-- | src/coremods/core_channel/cmd_names.cpp | 69 | ||||
-rw-r--r-- | src/coremods/core_channel/cmd_topic.cpp | 9 | ||||
-rw-r--r-- | src/coremods/core_channel/core_channel.cpp | 19 | ||||
-rw-r--r-- | src/coremods/core_channel/core_channel.h | 14 |
6 files changed, 106 insertions, 84 deletions
diff --git a/include/channels.h b/include/channels.h index 2b7c5d025..4d1d14c13 100644 --- a/include/channels.h +++ b/include/channels.h @@ -305,12 +305,6 @@ class CoreExport Channel : public Extensible, public InviteBase<Channel> */ const char* ChanModes(bool showkey); - /** Spool the NAMES list for this channel to the given user - * @param user The user to spool the NAMES list to - * @param isinside If true, the user is inside the channel, if not then false - */ - void UserList(User* user, bool isinside = true); - /** Get the value of a users prefix on this channel. * @param user The user to look up * @return The module or core-defined value of the users prefix. diff --git a/src/channels.cpp b/src/channels.cpp index e06e4c6fc..f79b5b89f 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -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) @@ -344,16 +341,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; } @@ -586,66 +573,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() - user->nick.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. diff --git a/src/coremods/core_channel/cmd_names.cpp b/src/coremods/core_channel/cmd_names.cpp index 20faae774..3af99ed2b 100644 --- a/src/coremods/core_channel/cmd_names.cpp +++ b/src/coremods/core_channel/cmd_names.cpp @@ -24,6 +24,8 @@ CommandNames::CommandNames(Module* parent) : Command(parent, "NAMES", 0, 0) , secretmode(parent, "secret") + , privatemode(parent, "private") + , invisiblemode(parent, "invisible") { syntax = "{<channel>{,<channel>}}"; } @@ -51,10 +53,11 @@ CmdResult CommandNames::Handle (const std::vector<std::string>& parameters, User // - the user doing the /NAMES is inside the channel // - the user doing the /NAMES has the channels/auspex privilege - bool has_user = c->HasUser(user); - if ((!c->IsModeSet(secretmode)) || (has_user) || (user->HasPrivPermission("channels/auspex"))) + // If the user is inside the channel or has privs, instruct SendNames() to show invisible (+i) members + bool show_invisible = ((c->HasUser(user)) || (user->HasPrivPermission("channels/auspex"))); + if ((show_invisible) || (!c->IsModeSet(secretmode))) { - c->UserList(user, has_user); + SendNames(user, c, show_invisible); return CMD_SUCCESS; } } @@ -62,3 +65,63 @@ CmdResult CommandNames::Handle (const std::vector<std::string>& parameters, User user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str()); return CMD_FAILURE; } + +void CommandNames::SendNames(User* user, Channel* chan, bool show_invisible) +{ + std::string list; + if (chan->IsModeSet(secretmode)) + list.push_back('@'); + else if (chan->IsModeSet(privatemode)) + list.push_back('*'); + else + list.push_back('='); + + list.push_back(' '); + list.append(chan->name).append(" :"); + std::string::size_type pos = list.size(); + + const size_t maxlen = ServerInstance->Config->Limits.MaxLine - 10 - ServerInstance->Config->ServerName.size() - user->nick.size(); + std::string prefixlist; + std::string nick; + const Channel::MemberMap& members = chan->GetUsers(); + for (Channel::MemberMap::const_iterator i = members.begin(); i != members.end(); ++i) + { + if ((!show_invisible) && (i->first->IsModeSet(invisiblemode))) + { + // Member is invisible and we are not supposed to show them + continue; + } + + Membership* const 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.", chan->name.c_str()); +} diff --git a/src/coremods/core_channel/cmd_topic.cpp b/src/coremods/core_channel/cmd_topic.cpp index ea723c024..8d65d764a 100644 --- a/src/coremods/core_channel/cmd_topic.cpp +++ b/src/coremods/core_channel/cmd_topic.cpp @@ -51,8 +51,7 @@ CmdResult CommandTopic::HandleLocal(const std::vector<std::string>& parameters, if (c->topic.length()) { - user->WriteNumeric(RPL_TOPIC, "%s :%s", c->name.c_str(), c->topic.c_str()); - user->WriteNumeric(RPL_TOPICTIME, "%s %s %lu", c->name.c_str(), c->setby.c_str(), (unsigned long)c->topicset); + Topic::ShowTopic(user, c); } else { @@ -84,3 +83,9 @@ CmdResult CommandTopic::HandleLocal(const std::vector<std::string>& parameters, c->SetTopic(user, t); return CMD_SUCCESS; } + +void Topic::ShowTopic(LocalUser* user, Channel* chan) +{ + user->WriteNumeric(RPL_TOPIC, "%s :%s", chan->name.c_str(), chan->topic.c_str()); + user->WriteNumeric(RPL_TOPICTIME, "%s %s %lu", chan->name.c_str(), chan->setby.c_str(), (unsigned long)chan->topicset); +} diff --git a/src/coremods/core_channel/core_channel.cpp b/src/coremods/core_channel/core_channel.cpp index 47f722e1e..99ad74d3d 100644 --- a/src/coremods/core_channel/core_channel.cpp +++ b/src/coremods/core_channel/core_channel.cpp @@ -34,6 +34,25 @@ class CoreModChannel : public Module { } + void OnPostJoin(Membership* memb) CXX11_OVERRIDE + { + Channel* const chan = memb->chan; + LocalUser* const localuser = IS_LOCAL(memb->user); + if (localuser) + { + if (chan->topicset) + Topic::ShowTopic(localuser, chan); + + // Show all members of the channel, including invisible (+i) users + cmdnames.SendNames(localuser, chan, true); + } + } + + void Prioritize() CXX11_OVERRIDE + { + ServerInstance->Modules.SetPriority(this, I_OnPostJoin, PRIORITY_FIRST); + } + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the INVITE, JOIN, KICK, NAMES, and TOPIC commands", VF_VENDOR|VF_CORE); diff --git a/src/coremods/core_channel/core_channel.h b/src/coremods/core_channel/core_channel.h index d3adbc9c9..755f876f6 100644 --- a/src/coremods/core_channel/core_channel.h +++ b/src/coremods/core_channel/core_channel.h @@ -21,6 +21,11 @@ #include "inspircd.h" +namespace Topic +{ + void ShowTopic(LocalUser* user, Channel* chan); +} + /** Handle /INVITE. */ class CommandInvite : public Command @@ -81,6 +86,8 @@ class CommandTopic : public SplitCommand class CommandNames : public Command { ChanModeReference secretmode; + ChanModeReference privatemode; + UserModeReference invisiblemode; public: /** Constructor for names. @@ -93,6 +100,13 @@ class CommandNames : public Command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(const std::vector<std::string>& parameters, User *user); + + /** Spool the NAMES list for a given channel to the given user + * @param user User to spool the NAMES list to + * @param chan Channel whose nicklist to send + * @param show_invisible True to show invisible (+i) members to the user, false to omit them from the list + */ + void SendNames(User* user, Channel* chan, bool show_invisible); }; /** Handle /KICK. |