+/* 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, CUList *ulist)
+{
+ char list[MAXBUF];
+ size_t dlen, curlen;
+ int MOD_RESULT = 0;
+ bool call_modules = true;
+
+ if (!IS_LOCAL(user))
+ return;
+
+ FOREACH_RESULT(I_OnUserList,OnUserList(user, this, ulist));
+ if (MOD_RESULT == 1)
+ call_modules = false;
+
+ if (MOD_RESULT != -1)
+ {
+ if ((this->IsModeSet('s')) && (!this->HasUser(user)))
+ {
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), this->name.c_str());
+ return;
+ }
+ }
+
+ dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=', this->name.c_str());
+
+ int numusers = 0;
+ char* ptr = list + dlen;
+
+ if (!ulist)
+ ulist = this->GetUsers();
+
+ /* Improvement by Brain - this doesnt change in value, so why was it inside
+ * the loop?
+ */
+ bool has_user = this->HasUser(user);
+
+ for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+ {
+ if ((!has_user) && (i->first->IsModeSet('i')))
+ {
+ /*
+ * user is +i, and source not on the channel, does not show
+ * nick in NAMES list
+ */
+ continue;
+ }
+
+ if (i->first->Visibility && !i->first->Visibility->VisibleTo(user))
+ continue;
+
+ std::string prefixlist = this->GetPrefixChar(i->first);
+ std::string nick = i->first->nick;
+
+ if (call_modules)
+ {
+ FOREACH_MOD(I_OnNamesListItem, OnNamesListItem(user, i->first, this, prefixlist, nick));
+
+ /* Nick was nuked, a module wants us to skip it */
+ if (nick.empty())
+ continue;
+ }
+
+ size_t ptrlen = 0;
+
+ if (curlen + prefixlist.length() + nick.length() + 1 > 480)
+ {
+ /* list overflowed into multiple numerics */
+ user->WriteServ(std::string(list));
+
+ /* reset our lengths */
+ dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=', this->name.c_str());
+ ptr = list + dlen;
+
+ ptrlen = 0;
+ numusers = 0;
+ }
+
+ ptrlen = snprintf(ptr, MAXBUF, "%s%s ", prefixlist.c_str(), nick.c_str());
+
+ curlen += ptrlen;
+ ptr += ptrlen;
+
+ numusers++;
+ }
+
+ /* if whats left in the list isnt empty, send it */
+ if (numusers)
+ {
+ user->WriteNumeric(RPL_NAMREPLY, std::string(list));
+ }
+
+ user->WriteNumeric(RPL_ENDOFNAMES, "%s %s :End of /NAMES list.", user->nick.c_str(), this->name.c_str());
+}
+
+long Channel::GetMaxBans()
+{
+ /* Return the cached value if there is one */
+ if (this->maxbans)
+ return this->maxbans;
+
+ /* If there isnt one, we have to do some O(n) hax to find it the first time. (ick) */
+ for (std::map<std::string,int>::iterator n = ServerInstance->Config->maxbans.begin(); n != ServerInstance->Config->maxbans.end(); n++)
+ {
+ if (match(this->name,n->first))
+ {
+ this->maxbans = n->second;
+ return n->second;
+ }
+ }
+
+ /* Screw it, just return the default of 64 */
+ this->maxbans = 64;
+ return this->maxbans;
+}
+
+void Channel::ResetMaxBans()
+{
+ this->maxbans = 0;
+}
+
+/* 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.
+ */
+const char* Channel::GetPrefixChar(User *user)
+{
+ static char pf[2] = {0, 0};
+
+ prefixlist::iterator n = prefixes.find(user);
+ if (n != prefixes.end())
+ {
+ if (n->second.size())
+ {
+ /* If the user has any prefixes, their highest prefix
+ * will always be at the head of the list, as the list is
+ * sorted in rank order highest first (see SetPrefix()
+ * for reasons why)
+ */
+ *pf = n->second.begin()->first;
+ return pf;
+ }
+ }
+
+ *pf = 0;
+ return pf;
+}
+
+
+const char* Channel::GetAllPrefixChars(User* user)
+{
+ static char prefix[MAXBUF];
+ int ctr = 0;
+ *prefix = 0;
+
+ prefixlist::iterator n = prefixes.find(user);
+ if (n != prefixes.end())
+ {
+ for (std::vector<prefixtype>::iterator x = n->second.begin(); x != n->second.end(); x++)
+ {
+ prefix[ctr++] = x->first;
+ }
+ }
+
+ prefix[ctr] = 0;
+
+ return prefix;
+}
+
+unsigned int Channel::GetPrefixValue(User* user)
+{
+ prefixlist::iterator n = prefixes.find(user);
+ if (n != prefixes.end())
+ {
+ if (n->second.size())
+ return n->second.begin()->second;
+ }
+ return 0;
+}
+
+int Channel::GetStatusFlags(User *user)
+{
+ UCListIter i = user->chans.find(this);
+ if (i != user->chans.end())
+ {
+ return i->second;
+ }
+ return 0;
+}
+
+int Channel::GetStatus(User *user)
+{
+ if (ServerInstance->ULine(user->server))
+ return STATUS_OP;
+
+ UCListIter i = user->chans.find(this);
+ if (i != user->chans.end())
+ {
+ if ((i->second & UCMODE_OP) > 0)
+ {
+ return STATUS_OP;
+ }
+ if ((i->second & UCMODE_HOP) > 0)
+ {
+ return STATUS_HOP;
+ }
+ if ((i->second & UCMODE_VOICE) > 0)
+ {
+ return STATUS_VOICE;
+ }
+ return STATUS_NORMAL;
+ }
+ return STATUS_NORMAL;
+}
+
+void Channel::SetPrefix(User* user, char prefix, unsigned int prefix_value, bool adding)
+{
+ prefixlist::iterator n = prefixes.find(user);
+ prefixtype pfx = std::make_pair(prefix,prefix_value);
+ if (adding)
+ {
+ if (n != prefixes.end())
+ {
+ if (std::find(n->second.begin(), n->second.end(), pfx) == n->second.end())
+ {
+ n->second.push_back(pfx);
+ /* We must keep prefixes in rank order, largest first.
+ * This is for two reasons, firstly because x-chat *ass-u-me's* this
+ * state, and secondly it turns out to be a benefit to us later.
+ * See above in GetPrefix().
+ */
+ std::sort(n->second.begin(), n->second.end(), ModeParser::PrefixComparison);
+ }
+ }
+ else
+ {
+ pfxcontainer one;
+ one.push_back(pfx);
+ prefixes.insert(std::make_pair<User*,pfxcontainer>(user, one));
+ }
+ }
+ else
+ {
+ if (n != prefixes.end())
+ {
+ pfxcontainer::iterator x = std::find(n->second.begin(), n->second.end(), pfx);
+ if (x != n->second.end())
+ n->second.erase(x);
+ }
+ }
+}
+
+void Channel::RemoveAllPrefixes(User* user)
+{
+ prefixlist::iterator n = prefixes.find(user);
+ if (n != prefixes.end())
+ {
+ prefixes.erase(n);
+ }
+}