diff options
Diffstat (limited to 'src/coremods')
-rw-r--r-- | src/coremods/core_channel/cmd_names.cpp | 66 | ||||
-rw-r--r-- | src/coremods/core_channel/core_channel.cpp | 4 | ||||
-rw-r--r-- | src/coremods/core_channel/core_channel.h | 9 |
3 files changed, 77 insertions, 2 deletions
diff --git a/src/coremods/core_channel/cmd_names.cpp b/src/coremods/core_channel/cmd_names.cpp index 20faae774..9ae58d6fa 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>}}"; } @@ -54,7 +56,7 @@ CmdResult CommandNames::Handle (const std::vector<std::string>& parameters, User bool has_user = c->HasUser(user); if ((!c->IsModeSet(secretmode)) || (has_user) || (user->HasPrivPermission("channels/auspex"))) { - c->UserList(user, has_user); + SendNames(user, c, has_user); return CMD_SUCCESS; } } @@ -62,3 +64,65 @@ 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 isinside) +{ + bool has_privs = user->HasPrivPermission("channels/auspex"); + + 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 ((!isinside) && (i->first->IsModeSet(invisiblemode)) && (!has_privs)) + { + // 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/core_channel.cpp b/src/coremods/core_channel/core_channel.cpp index ac590ebcc..99ad74d3d 100644 --- a/src/coremods/core_channel/core_channel.cpp +++ b/src/coremods/core_channel/core_channel.cpp @@ -42,7 +42,9 @@ class CoreModChannel : public Module { if (chan->topicset) Topic::ShowTopic(localuser, chan); - chan->UserList(localuser); + + // Show all members of the channel, including invisible (+i) users + cmdnames.SendNames(localuser, chan, true); } } diff --git a/src/coremods/core_channel/core_channel.h b/src/coremods/core_channel/core_channel.h index f3efa3d67..7e213b5a5 100644 --- a/src/coremods/core_channel/core_channel.h +++ b/src/coremods/core_channel/core_channel.h @@ -86,6 +86,8 @@ class CommandTopic : public SplitCommand class CommandNames : public Command { ChanModeReference secretmode; + ChanModeReference privatemode; + UserModeReference invisiblemode; public: /** Constructor for names. @@ -98,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 isinside If true, the user is inside the channel, if not then false + */ + void SendNames(User* user, Channel* chan, bool isinside); }; /** Handle /KICK. |