#include "IRCMemberEntry.h" #include "IRCBase.h" #include <algorithm> IRCMemberEntry::IRCMemberEntry(std::shared_ptr<IRCMember> member, IRCBase& owner) : m_member(member) , m_owner(&owner) {} std::shared_ptr<IRCMember> IRCMemberEntry::member() const { return m_member; } const std::string& IRCMemberEntry::modes() const { return m_modes; } void IRCMemberEntry::addMode(char m) { // Note: "PREFIX" is always present. // Value example: (ohv)@%+ // Value is ordered with most significant first. const std::string& prefix = m_owner->isupport().find("PREFIX")->second; // Just interested in the mode letters (ie. ohv) const std::string validModes(prefix.begin() + 1, std::find(prefix.begin(), prefix.end(), ')')); auto order = [validModes](const char m) -> int { auto ret = validModes.find(m); return ret != std::string::npos ? static_cast<int>(ret) : -1; }; auto mOrd = order(m); if (mOrd < 0) return; auto it = m_modes.begin(); for (auto& mode : m_modes) { if (mode == m) return; else if (order(mode) >= mOrd) break; else ++it; } m_modes.insert(it, m); } void IRCMemberEntry::delMode(char m) { auto pos = m_modes.find_first_of(m); /* * Out-of-bounds can happen due to an IRC protocol bug. For example, where you join a channel which has * members that got both op (@) and voice (+) but only one of the symbols is visible from NAMES message * meaning that the client only picks up the "most significant" mode. * IRCv3 implements a fix for this which this client support, but not all servers do. * When a member then removes the unknown mode, we get this situation below; */ if (pos != std::string::npos) m_modes.erase(pos, 1); }