diff --git a/Chan.cpp b/Chan.cpp index 307d0840..64eb8f2d 100644 --- a/Chan.cpp +++ b/Chan.cpp @@ -2,6 +2,7 @@ #include "znc.h" #include "User.h" #include "Utils.h" +#include "IRCSock.h" CChan::CChan(const CString& sName, CUser* pUser) { m_sName = sName.Token(0); @@ -12,6 +13,7 @@ CChan::CChan(const CString& sName, CUser* pUser) { } m_pUser = pUser; + m_Nick.SetUser(pUser); m_bAutoCycle = true; m_bDetached = false; m_uBufferCount = m_pUser->GetBufferCount(); @@ -25,11 +27,8 @@ CChan::~CChan() { void CChan::Reset() { m_bWhoDone = false; m_bIsOn = false; - m_bIsOp = false; - m_bIsVoice = false; - m_uOpCount = 0; - m_uVoiceCount = 0; - m_uModes = 0; + m_suUserPerms.clear(); + m_musModes.clear(); m_uLimit = 0; m_uClientRequests = 0; m_sTopic = ""; @@ -63,10 +62,9 @@ void CChan::JoinUser(bool bForce) { CString sLine = sPre; for (map::iterator a = m_msNicks.begin(); a != m_msNicks.end(); a++) { - if (a->second->IsOp()) { - sLine += "@"; - } else if (a->second->IsVoice()) { - sLine += "+"; + char c = a->second->GetPermChar(); + if (c != '\0') { + sLine += c; } sLine += a->first; @@ -110,23 +108,21 @@ void CChan::DetachUser() { m_bDetached = true; } -CString CChan::GetModeCString() const { - CString sRet; +CString CChan::GetModeString() const { + CString sModes, sArgs; - if (m_uModes & Secret) { sRet += "s"; } - if (m_uModes & Private) { sRet += "p"; } - if (m_uModes & OpTopic) { sRet += "t"; } - if (m_uModes & InviteOnly) { sRet += "i"; } - if (m_uModes & NoMessages) { sRet += "n"; } - if (m_uModes & Moderated) { sRet += "m"; } - if (m_uLimit) { sRet += "l"; } - if (m_uModes & Key) { sRet += "k"; } + for (map::const_iterator it = m_musModes.begin(); it != m_musModes.end(); it++) { + sModes += it->first; + if (it->second.size()) { + sArgs += " " + it->second; + } + } - return (sRet.empty()) ? sRet : ("+" + sRet); + return (sModes.empty()) ? sModes : ("+" + sModes + sArgs); } void CChan::SetModes(const CString& sModes) { - m_uModes = 0; + m_musModes.clear(); m_uLimit = 0; m_sKey = ""; ModeChange(sModes); @@ -176,26 +172,96 @@ void CChan::ModeChange(const CString& sModes, const CString& sOpNick) { #endif for (unsigned int a = 0; a < sModeArg.size(); a++) { - switch (sModeArg[a]) { - case '+': bAdd = true; break; - case '-': bAdd = false; break; - case 's': if (bAdd) { m_uModes |= Secret; } else { m_uModes &= ~Secret; } break; - case 'p': if (bAdd) { m_uModes |= Private; } else { m_uModes &= ~Private; } break; - case 'm': if (bAdd) { m_uModes |= Moderated; } else { m_uModes &= ~Moderated; } break; - case 'i': if (bAdd) { m_uModes |= InviteOnly; } else { m_uModes &= ~InviteOnly; } break; - case 'n': if (bAdd) { m_uModes |= NoMessages; } else { m_uModes &= ~NoMessages; } break; - case 't': if (bAdd) { m_uModes |= OpTopic; } else { m_uModes &= ~OpTopic; } break; - case 'l': if (bAdd) { m_uLimit = strtoul(GetModeArg(sArgs).c_str(), NULL, 10); } else { m_uLimit = 0; } break; - case 'k': if (bAdd) { m_uModes |= Key; SetKey(GetModeArg(sArgs)); } else { m_uModes &= ~Key; GetModeArg(sArgs); } break; - case 'o': OnOp(sOpNick, GetModeArg(sArgs), bAdd); break; - case 'v': OnVoice(sOpNick, GetModeArg(sArgs), bAdd); break; - case 'b': // Don't do anything with bans yet - case 'e': // Don't do anything with excepts yet - default: GetModeArg(sArgs); // Pop off an arg, assume new modes will have an argument + const unsigned char& uMode = sModeArg[a]; + CString sArg; + + if (uMode == '+') { + bAdd = true; + } else if (uMode == '-') { + bAdd = false; + } else if (m_pUser->GetIRCSock()->IsPermMode(uMode)) { + sArg = GetModeArg(sArgs); + CNick* pNick = FindNick(sArg); + if (pNick) { + unsigned char uPerm = m_pUser->GetIRCSock()->GetPermFromMode(uMode); + + if (uPerm) { + if (bAdd) { + if (pNick->AddPerm(uPerm)) { + IncPermCount(uPerm); + } + + if (pNick->GetNick().CaseCmp(m_pUser->GetCurNick()) == 0) { + AddPerm(uPerm); + } + } else { + if (pNick->RemPerm(uPerm)) { + DecPermCount(uPerm); + } + + if (pNick->GetNick().CaseCmp(m_pUser->GetCurNick()) == 0) { + RemPerm(uPerm); + } + } + } + } + } else { + switch (m_pUser->GetIRCSock()->GetModeType(uMode)) { + case CIRCSock::ListArg: + sArg = GetModeArg(sArgs); + break; + case CIRCSock::HasArg: + sArg = GetModeArg(sArgs); + break; + case CIRCSock::NoArg: + break; + case CIRCSock::ArgWhenSet: + if (bAdd) { + sArg = GetModeArg(sArgs); + } + + break; + } + + (bAdd) ? AddMode(uMode, sArg) : RemMode(uMode, sArg); } } } +CString CChan::GetModeArg(unsigned char uMode) const { + if (uMode) { + map::const_iterator it = m_musModes.find(uMode); + + if (it != m_musModes.end()) { + return it->second; + } + } + + return ""; +} + +bool CChan::HasMode(unsigned char uMode) const { + return (uMode && m_musModes.find(uMode) != m_musModes.end()); +} + +bool CChan::AddMode(unsigned char uMode, const CString& sArg) { + if (HasMode(uMode)) { + return false; + } + + m_musModes[uMode] = sArg; + return true; +} + +bool CChan::RemMode(unsigned char uMode, const CString& sArg) { + if (!HasMode(uMode)) { + return false; + } + + m_musModes.erase(uMode); + return true; +} + CString CChan::GetModeArg(CString& sArgs) const { CString sRet = sArgs.substr(0, sArgs.find(' ')); sArgs = (sRet.size() < sArgs.size()) ? sArgs.substr(sRet.size() +1) : ""; @@ -245,53 +311,28 @@ int CChan::AddNicks(const CString& sNicks) { bool CChan::AddNick(const CString& sNick) { const char* p = sNick.c_str(); - bool bIsOp = false; - bool bIsVoice = false; - bool bNoMode = false; + char cPrefix = '\0'; - switch (*p) { - case '\0': + if (m_pUser->GetIRCSock()->IsPermChar(*p)) { + cPrefix = *p; + + if (!*++p) { return false; - case '@': - bIsOp = true; - break; - case '+': - bIsVoice = true; - break; - case '%': - break; - case '*': - break; - case '!': - break; - default: - bNoMode = true; - break; - } - - if (!bNoMode && !*++p) { - return false; + } } CNick* pNick = FindNick(p); if (!pNick) { pNick = new CNick(p); + pNick->SetUser(m_pUser); } - if ((bIsOp) && (!pNick->IsOp())) { - IncOpCount(); - pNick->SetOp(true); + if (pNick->AddPerm(cPrefix)) { + IncPermCount(cPrefix); + } - if (pNick->GetNick().CaseCmp(m_pUser->GetCurNick()) == 0) { - SetOpped(true); - } - } else if ((bIsVoice) && (!pNick->IsVoice())) { - IncVoiceCount(); - pNick->SetVoice(true); - - if (pNick->GetNick().CaseCmp(m_pUser->GetCurNick()) == 0) { - SetVoiced(true); - } + if (pNick->GetNick().CaseCmp(m_pUser->GetCurNick()) == 0) { + AddPerm(cPrefix); } m_msNicks[pNick->GetNick()] = pNick; @@ -299,25 +340,50 @@ bool CChan::AddNick(const CString& sNick) { return true; } +unsigned int CChan::GetPermCount(unsigned char uPerm) { + map::iterator it = m_muuPermCount.find(uPerm); + return (it == m_muuPermCount.end()) ? 0 : it->second; +} + +void CChan::DecPermCount(unsigned char uPerm) { + map::iterator it = m_muuPermCount.find(uPerm); + + if (it == m_muuPermCount.end()) { + m_muuPermCount[uPerm] = 0; + } else { + if (it->second) { + m_muuPermCount[uPerm]--; + } + } +} + +void CChan::IncPermCount(unsigned char uPerm) { + map::iterator it = m_muuPermCount.find(uPerm); + + if (it == m_muuPermCount.end()) { + m_muuPermCount[uPerm] = 1; + } else { + m_muuPermCount[uPerm]++; + } +} + bool CChan::RemNick(const CString& sNick) { map::iterator it = m_msNicks.find(sNick); if (it == m_msNicks.end()) { return false; } - if (it->second->IsOp()) { - DecOpCount(); - } + const set& suPerms = it->second->GetChanPerms(); - if (it->second->IsVoice()) { - DecVoiceCount(); + for (set::iterator it = suPerms.begin(); it != suPerms.end(); it++) { + DecPermCount(*it); } delete it->second; m_msNicks.erase(it); CNick* pNick = m_msNicks.begin()->second; - if ((m_msNicks.size() == 1) && (!pNick->IsOp()) && (pNick->GetNick().CaseCmp(m_pUser->GetCurNick()) == 0)) { + if ((m_msNicks.size() == 1) && (!pNick->HasPerm(Op)) && (pNick->GetNick().CaseCmp(m_pUser->GetCurNick()) == 0)) { if (AutoCycle()) { Cycle(); } @@ -336,7 +402,7 @@ bool CChan::ChangeNick(const CString& sOldNick, const CString& sNewNick) { // Rename this nick it->second->SetNick(sNewNick); - // Insert a new element into the map then erase the old one, do this to change the key + // Insert a new element into the map then erase the old one, do this to change the key to the new nick m_msNicks[sNewNick] = it->second; m_msNicks.erase(it); @@ -347,7 +413,7 @@ void CChan::OnOp(const CString& sOpNick, const CString& sNick, bool bOpped) { CNick* pNick = FindNick(sNick); if (pNick) { - bool bNoChange = (pNick->IsOp() == bOpped); + bool bNoChange = (pNick->HasPerm(Op) == bOpped); #ifdef _MODULES CNick* pOpNick = FindNick(sOpNick); @@ -361,7 +427,7 @@ void CChan::OnOp(const CString& sOpNick, const CString& sNick, bool bOpped) { #endif if (sNick.CaseCmp(m_pUser->GetCurNick()) == 0) { - SetOpped(bOpped); + (bOpped) ? AddPerm(Op) : RemPerm(Op); } if (bNoChange) { @@ -369,8 +435,11 @@ void CChan::OnOp(const CString& sOpNick, const CString& sNick, bool bOpped) { return; } - pNick->SetOp(bOpped); - (bOpped) ? IncOpCount() : DecOpCount(); + bool bChange = (bOpped) ? pNick->AddPerm(Op) : pNick->RemPerm(Op); + + if (bChange) { + (bOpped) ? IncPermCount(Op) : DecPermCount(Op); + } } } @@ -378,7 +447,7 @@ void CChan::OnVoice(const CString& sOpNick, const CString& sNick, bool bVoiced) CNick* pNick = FindNick(sNick); if (pNick) { - bool bNoChange = (pNick->IsVoice() == bVoiced); + bool bNoChange = (pNick->HasPerm(Voice) == bVoiced); #ifdef _MODULES CNick* pOpNick = FindNick(sOpNick); @@ -393,7 +462,7 @@ void CChan::OnVoice(const CString& sOpNick, const CString& sNick, bool bVoiced) #endif if (sNick.CaseCmp(m_pUser->GetCurNick()) == 0) { - SetVoiced(bVoiced); + (bVoiced) ? AddPerm(Voice) : RemPerm(Voice); } if (bNoChange) { @@ -401,8 +470,11 @@ void CChan::OnVoice(const CString& sOpNick, const CString& sNick, bool bVoiced) return; } - pNick->SetVoice(bVoiced); - (bVoiced) ? IncVoiceCount() : DecVoiceCount(); + bool bChange = (bVoiced) ? pNick->AddPerm(Voice) : pNick->RemPerm(Voice); + + if (bChange) { + (bVoiced) ? IncPermCount(Voice) : DecPermCount(Voice); + } } } diff --git a/Chan.h b/Chan.h index 762e7f58..fb207f54 100644 --- a/Chan.h +++ b/Chan.h @@ -2,10 +2,13 @@ #define _CHAN_H #include "Nick.h" +#include "String.h" #include #include +#include using std::vector; using std::map; +using std::set; // Forward Declarations class CUser; @@ -14,14 +17,27 @@ class CUser; class CChan { public: typedef enum { - Private = 1 << 0, - Secret = 1 << 1, - NoMessages = 1 << 2, - Moderated = 1 << 3, - OpTopic = 1 << 4, - InviteOnly = 1 << 5, - Key = 1 << 6 - } EMode; + Voice = '+', + HalfOp = '%', + Op = '@', + Admin = '!', + Owner = '*' + } EUserPerms; + + typedef enum { + M_Private = 'p', + M_Secret = 's', + M_Moderated = 'm', + M_InviteOnly = 'i', + M_NoMessages = 'n', + M_OpTopic = 't', + M_Limit = 'l', + M_Key = 'k', + M_Op = 'o', + M_Voice = 'v', + M_Ban = 'b', + M_Except = 'e', + } EModes; CChan(const CString& sName, CUser* pUser); virtual ~CChan(); @@ -42,9 +58,11 @@ public: // Modes void SetModes(const CString& s); void ModeChange(const CString& sModes, const CString& sNick = ""); + bool AddMode(unsigned char uMode, const CString& sArg); + bool RemMode(unsigned char uMode, const CString& sArg); void OnOp(const CString& sOpNick, const CString& sNick, bool bOpped); void OnVoice(const CString& sOpNick, const CString& sNick, bool bVoiced); - CString GetModeCString() const; + CString GetModeString() const; CString GetModeArg(CString& sArgs) const; // !Modes @@ -62,19 +80,22 @@ public: void ClearBuffer(); // !Buffer + // m_Nick wrappers + CString GetPermStr() const { return m_Nick.GetPermStr(); } + bool HasPerm(unsigned char uPerm) const { return m_Nick.HasPerm(uPerm); } + bool AddPerm(unsigned char uPerm) { return m_Nick.AddPerm(uPerm); } + bool RemPerm(unsigned char uPerm) { return m_Nick.RemPerm(uPerm); } + // !wrappers + // Setters + void IncPermCount(unsigned char uPerm); + void DecPermCount(unsigned char uPerm); void SetIsOn(bool b) { m_bIsOn = b; if (!b) { Reset(); } else { Joined(); } } - void SetOpped(bool b) { m_bIsOp = b; } - void SetVoiced(bool b) { m_bIsVoice = b; } void SetKey(const CString& s) { m_sKey = s; } void SetTopic(const CString& s) { m_sTopic = s; } void SetTopicOwner(const CString& s) { m_sTopicOwner = s; } void SetTopicDate(unsigned long u) { m_ulTopicDate = u; } void SetDefaultModes(const CString& s) { m_sDefaultModes = s; } - void IncOpCount() { m_uOpCount++; } - void DecOpCount() { m_uOpCount -= (m_uOpCount > 0); } - void IncVoiceCount() { m_uVoiceCount++; } - void DecVoiceCount() { m_uVoiceCount -= (m_uVoiceCount > 0); } void SetBufferCount(unsigned int u) { m_uBufferCount = u; } void SetKeepBuffer(bool b) { m_bKeepBuffer = b; } void SetAutoCycle(bool b) { m_bAutoCycle = b; } @@ -83,11 +104,12 @@ public: // !Setters // Getters + bool HasMode(unsigned char uMode) const; + CString GetModeArg(unsigned char uMode) const; + unsigned int GetPermCount(unsigned char uPerm); const bool IsOn() const { return m_bIsOn; } - const bool IsOp() const { return m_bIsOp; } - const bool IsVoice() const { return m_bIsVoice; } const CString& GetName() const { return m_sName; } - unsigned int GetModes() const { return m_uModes; } + const map& GetModes() const { return m_musModes; } const CString& GetKey() const { return m_sKey; } unsigned int GetLimit() const { return m_uLimit; } const CString& GetTopic() const { return m_sTopic; } @@ -98,10 +120,7 @@ public: const vector& GetBuffer() const { return m_vsBuffer; } const map& GetNicks() const { return m_msNicks; } unsigned int GetNickCount() const { return m_msNicks.size(); } - unsigned int GetOpCount() const { return m_uOpCount; } - unsigned int GetVoiceCount() const { return m_uVoiceCount; } unsigned int GetBufferCount() const { return m_uBufferCount; } - bool HasMode(EMode eMode) const { return (m_uModes & eMode); } bool KeepBuffer() const { return m_bKeepBuffer; } bool AutoCycle() const { return m_bAutoCycle; } bool IsDetached() const { return m_bDetached; } @@ -110,8 +129,6 @@ private: protected: bool m_bDetached; bool m_bIsOn; - bool m_bIsOp; - bool m_bIsVoice; bool m_bWhoDone; bool m_bKeepBuffer; bool m_bAutoCycle; @@ -121,16 +138,18 @@ protected: CString m_sTopicOwner; unsigned long m_ulTopicDate; CUser* m_pUser; + CNick m_Nick; unsigned int m_uLimit; - unsigned int m_uModes; CString m_sDefaultModes; vector m_vsBans; map m_msNicks; // Todo: make this caseless (irc style) + set m_suUserPerms; unsigned int m_uBufferCount; - unsigned int m_uOpCount; - unsigned int m_uVoiceCount; unsigned int m_uClientRequests; // Used to tell how many times a client tried to join this chan vector m_vsBuffer; + + map m_musModes; + map m_muuPermCount; }; #endif // !_CHAN_H diff --git a/IRCSock.cpp b/IRCSock.cpp index dc25984d..adfeb430 100644 --- a/IRCSock.cpp +++ b/IRCSock.cpp @@ -17,7 +17,17 @@ CIRCSock::CIRCSock(CZNC* pZNC, CUser* pUser) : Csock() { m_MotdBuffer.SetLineCount(200); // This should be more than enough motd lines m_Nick.SetIdent(pUser->GetIdent()); m_Nick.SetHost(pUser->GetVHost()); - m_sNickPrefixes = "+@"; + m_sPerms = "@+"; + m_sPermModes = "ov"; + m_mueChanModes['p'] = NoArg; + m_mueChanModes['s'] = NoArg; + m_mueChanModes['t'] = NoArg; + m_mueChanModes['i'] = NoArg; + m_mueChanModes['n'] = NoArg; + m_mueChanModes['b'] = HasArg; + m_mueChanModes['e'] = HasArg; + m_mueChanModes['k'] = HasArg; + m_mueChanModes['l'] = ArgWhenSet; } CIRCSock::~CIRCSock() { @@ -873,12 +883,50 @@ void CIRCSock::ParseISupport(const CString& sLine) { if (sName.CaseCmp("PREFIX") == 0) { CString sPrefixes = sValue.Token(1, false, ')'); + CString sPermModes = sValue.Token(0, false, ')'); + sPermModes.LeftTrim("("); - if (!sPrefixes.empty()) { - m_sNickPrefixes = sPrefixes; + if (!sPrefixes.empty() && sPermModes.size() == sPrefixes.size()) { + m_sPerms = sPrefixes; + m_sPermModes = sPermModes; + } + } else if (sName.CaseCmp("CHANMODES") == 0) { + if (!sValue.empty()) { + m_mueChanModes.clear(); + + for (unsigned int a = 0; a < 4; a++) { + CString sModes = sValue.Token(a, false, ','); + + for (unsigned int b = 0; b < sModes.size(); b++) { + m_mueChanModes[sModes[b]] = (EChanModeArgs) a; + } + } } } sArg = sLine.Token(i++); } } + +unsigned char CIRCSock::GetPermFromMode(unsigned char uMode) const { + if (m_sPermModes.size() == m_sPerms.size()) { + for (unsigned int a = 0; a < m_sPermModes.size(); a++) { + if (m_sPermModes[a] == uMode) { + return m_sPerms[a]; + } + } + } + + return 0; +} + +CIRCSock::EChanModeArgs CIRCSock::GetModeType(unsigned char uMode) const { + map::const_iterator it = m_mueChanModes.find(uMode); + + if (it == m_mueChanModes.end()) { + return NoArg; + } + + return it->second; +} + diff --git a/IRCSock.h b/IRCSock.h index 264d5d4d..5978bf06 100644 --- a/IRCSock.h +++ b/IRCSock.h @@ -16,6 +16,13 @@ public: CIRCSock(CZNC* pZNC, CUser* pUser); virtual ~CIRCSock(); + typedef enum { + ListArg = 0, // These values must line up with their position in the CHANMODE argument to raw 005 + HasArg = 1, + ArgWhenSet = 2, + NoArg = 3 + } EChanModeArgs; + // Message Handlers bool OnCTCPReply(const CString& sNickMask, CString& sMessage); bool OnPrivCTCP(const CString& sNickMask, CString& sMessage); @@ -47,29 +54,37 @@ public: // !Setters // Getters - CString GetNickMask() const { - return m_Nick.GetNickMask(); - } + + EChanModeArgs GetModeType(unsigned char uMode) const; + unsigned char GetPermFromMode(unsigned char uMode) const; + const map& GetChanModes() const { return m_mueChanModes; } + bool IsPermChar(const char c) const { return (c != '\0' && GetPerms().find(c) != CString::npos); } + bool IsPermMode(const char c) const { return (c != '\0' && GetPermModes().find(c) != CString::npos); } + const CString& GetPerms() const { return m_sPerms; } + const CString& GetPermModes() const { return m_sPermModes; } + CString GetNickMask() const { return m_Nick.GetNickMask(); } const CString& GetNick() const { return m_Nick.GetNick(); } const CString& GetPass() const { return m_sPass; } // !Getters private: void SetNick(const CString& sNick); protected: - bool m_bISpoofReleased; - bool m_bAuthed; - bool m_bKeepNick; - CString m_sNickPrefixes; - CZNC* m_pZNC; - CUser* m_pUser; - CNick m_Nick; - CString m_sPass; - CBuffer m_RawBuffer; - CBuffer m_MotdBuffer; - CUserSock* m_pUserSock; + bool m_bISpoofReleased; + bool m_bAuthed; + bool m_bKeepNick; + CString m_sPerms; + CString m_sPermModes; + map m_mueChanModes; + CZNC* m_pZNC; + CUser* m_pUser; + CNick m_Nick; + CString m_sPass; + CBuffer m_RawBuffer; + CBuffer m_MotdBuffer; + CUserSock* m_pUserSock; map m_msChans; - unsigned int m_uQueryBufferCount; - CBuffer m_QueryBuffer; + unsigned int m_uQueryBufferCount; + CBuffer m_QueryBuffer; }; #endif // !_IRCSOCK_H diff --git a/Nick.cpp b/Nick.cpp index c04bcfda..3094ffd1 100644 --- a/Nick.cpp +++ b/Nick.cpp @@ -1,20 +1,23 @@ -#include "Nick.h" #include "Chan.h" +#include "Nick.h" #include "User.h" +#include "IRCSock.h" CNick::CNick() { - m_bIsOp = false; - m_bIsVoice = false; + Reset(); } CNick::CNick(const CString& sNick) { + Reset(); Parse(sNick); - m_bIsOp = false; - m_bIsVoice = false; } CNick::~CNick() {} +void CNick::Reset() { + m_cPerm = '\0'; +} + void CNick::Parse(const CString& sNickMask) { if (sNickMask.empty()) { return; @@ -56,14 +59,62 @@ unsigned int CNick::GetCommonChans(vector& vRetChans, CUser* pUser) cons return vRetChans.size(); } +void CNick::SetUser(CUser* pUser) { m_pUser = pUser; } +void CNick::SetPermChar(char c) { m_cPerm = c; } void CNick::SetNick(const CString& s) { m_sNick = s; } void CNick::SetIdent(const CString& s) { m_sIdent = s; } void CNick::SetHost(const CString& s) { m_sHost = s; } -void CNick::SetOp(bool b) { m_bIsOp = b; } -void CNick::SetVoice(bool b) { m_bIsVoice = b; } -bool CNick::IsOp() const { return m_bIsOp; } -bool CNick::IsVoice() const { return m_bIsVoice; } +bool CNick::HasPerm(unsigned char uPerm) const { + return (uPerm && m_suChanPerms.find(uPerm) != m_suChanPerms.end()); +} + +bool CNick::AddPerm(unsigned char uPerm) { + if (!uPerm || HasPerm(uPerm)) { + return false; + } + + m_suChanPerms.insert(uPerm); + UpdatePermChar(); + + return true; +} + +bool CNick::RemPerm(unsigned char uPerm) { + if (!HasPerm(uPerm)) { + return false; + } + + m_suChanPerms.erase(uPerm); + UpdatePermChar(); + + return true; +} + +void CNick::UpdatePermChar() { + const CString& sChanPerms = (!m_pUser) ? "@+" : m_pUser->GetIRCSock()->GetPerms(); + m_cPerm = 0; + + for (unsigned int a = 0; a < sChanPerms.size(); a++) { + const unsigned char& c = sChanPerms[a]; + if (HasPerm(c)) { + m_cPerm = c; + break; + } + } +} + +const set& CNick::GetChanPerms() const { return m_suChanPerms; } +const unsigned char CNick::GetPermChar() const { return m_cPerm; } +CString CNick::GetPermStr() const { + CString sRet; + + if (m_cPerm) { + sRet += m_cPerm; + } + + return sRet; +} const CString& CNick::GetNick() const { return m_sNick; } const CString& CNick::GetIdent() const { return m_sIdent; } const CString& CNick::GetHost() const { return m_sHost; } diff --git a/Nick.h b/Nick.h index 7d6ded8d..845ff309 100644 --- a/Nick.h +++ b/Nick.h @@ -1,9 +1,11 @@ #ifndef _NICK_H #define _NICK_H -#include #include "String.h" +#include +#include using std::vector; +using std::set; // Forward Decl class CUser; @@ -17,21 +19,27 @@ public: CNick(const CString& sNick); virtual ~CNick(); + void Reset(); void Parse(const CString& sNickMask); CString GetHostMask() const; unsigned int GetCommonChans(vector& vChans, CUser* pUser) const; // Setters + void SetUser(CUser* pUser); + void UpdatePermChar(); + void SetPermChar(char c); void SetNick(const CString& s); void SetIdent(const CString& s); void SetHost(const CString& s); - void SetOp(bool b); - void SetVoice(bool b); + bool AddPerm(unsigned char uPerm); + bool RemPerm(unsigned char uPerm); // !Setters // Getters - bool IsOp() const; - bool IsVoice() const; + const set& GetChanPerms() const; + CString GetPermStr() const; + const unsigned char GetPermChar() const; + bool HasPerm(unsigned char uPerm) const; const CString& GetNick() const; const CString& GetIdent() const; const CString& GetHost() const; @@ -39,13 +47,12 @@ public: // !Getters private: protected: - CString m_sNick; - CString m_sIdent; - CString m_sHost; - - bool m_bIsOp; - bool m_bIsVoice; + set m_suChanPerms; + unsigned char m_cPerm; + CUser* m_pUser; + CString m_sNick; + CString m_sIdent; + CString m_sHost; }; #endif // !_NICK_H - diff --git a/UserSock.cpp b/UserSock.cpp index 15144cd1..5bf57294 100644 --- a/UserSock.cpp +++ b/UserSock.cpp @@ -408,6 +408,7 @@ void CUserSock::UserCommand(const CString& sLine) { } const map& msNicks = pChan->GetNicks(); + const CString& sPerms = m_pUser->GetIRCSock()->GetPerms(); if (!msNicks.size()) { PutStatus("No nicks on [" + sChan + "]"); @@ -415,16 +416,28 @@ void CUserSock::UserCommand(const CString& sLine) { } CTable Table; - Table.AddColumn("@"); - Table.AddColumn("+"); + + for (unsigned int p = 0; p < sPerms.size(); p++) { + CString sPerm; + sPerm += sPerms[p]; + Table.AddColumn(sPerm); + } + Table.AddColumn("Nick"); Table.AddColumn("Ident"); Table.AddColumn("Host"); for (map::const_iterator a = msNicks.begin(); a != msNicks.end(); a++) { Table.AddRow(); - if (a->second->IsOp()) { Table.SetCell("@", "@"); } - if (a->second->IsVoice()) { Table.SetCell("+", "+"); } + + for (unsigned int b = 0; b < sPerms.size(); b++) { + if (a->second->HasPerm(sPerms[b])) { + CString sPerm; + sPerm += sPerms[b]; + Table.SetCell(sPerm, sPerm); + } + } + Table.SetCell("Nick", a->second->GetNick()); Table.SetCell("Ident", a->second->GetIdent()); Table.SetCell("Host", a->second->GetHost()); @@ -475,6 +488,7 @@ void CUserSock::UserCommand(const CString& sLine) { } else if (sCommand.CaseCmp("LISTCHANS") == 0) { if (m_pUser) { const vector& vChans = m_pUser->GetChans(); + const CString& sPerms = m_pUser->GetIRCSock()->GetPerms(); CTable Table; Table.AddColumn("Name"); @@ -482,17 +496,21 @@ void CUserSock::UserCommand(const CString& sLine) { Table.AddColumn("Buf"); Table.AddColumn("Modes"); Table.AddColumn("Users"); - Table.AddColumn("+o"); - Table.AddColumn("+v"); + + for (unsigned int p = 0; p < sPerms.size(); p++) { + CString sPerm; + sPerm += sPerms[p]; + Table.AddColumn(sPerm); + } for (unsigned int a = 0; a < vChans.size(); a++) { CChan* pChan = vChans[a]; Table.AddRow(); - Table.SetCell("Name", CString((pChan->IsOp()) ? "@" : ((pChan->IsVoice()) ? "+" : "")) + pChan->GetName()); + Table.SetCell("Name", pChan->GetPermStr() + pChan->GetName()); Table.SetCell("Status", ((vChans[a]->IsOn()) ? ((vChans[a]->IsDetached()) ? "Detached" : "Joined") : "Trying")); Table.SetCell("Buf", CString((pChan->KeepBuffer()) ? "*" : "") + CString::ToString(pChan->GetBufferCount())); - CString sModes = pChan->GetModeCString(); + CString sModes = pChan->GetModeString(); unsigned int uLimit = pChan->GetLimit(); const CString& sKey = pChan->GetKey(); @@ -501,8 +519,12 @@ void CUserSock::UserCommand(const CString& sLine) { Table.SetCell("Modes", sModes); Table.SetCell("Users", CString::ToString(pChan->GetNickCount())); - Table.SetCell("+o", CString::ToString(pChan->GetOpCount())); - Table.SetCell("+v", CString::ToString(pChan->GetVoiceCount())); + + for (unsigned int b = 0; b < sPerms.size(); b++) { + CString sPerm; + sPerm += sPerms[b]; + Table.SetCell(sPerm, CString::ToString(pChan->GetPermCount(sPerms[b]))); + } } if (Table.size()) {