From 633c2258111100746a93fd2e085b48675ef823ca Mon Sep 17 00:00:00 2001 From: darthgandalf Date: Mon, 13 Sep 2010 17:00:50 +0000 Subject: [PATCH] Rearrange CAP requests between ZNC and server in a way that each next REQ is sent only after receiving ACK/NAK of previous REQ. Also now you can call CIRCSock::PauseCap() and CIRCSock::ResumeCap() if you need to pause CAP negotiation and process of logging in for a while. git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@2137 726aef4b-f618-498e-8847-2d620e286838 --- IRCSock.cpp | 35 +++++++++++++++++++++++++---------- IRCSock.h | 12 ++++++++++++ 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/IRCSock.cpp b/IRCSock.cpp index 8ca6e02c..c71fcc37 100644 --- a/IRCSock.cpp +++ b/IRCSock.cpp @@ -24,6 +24,7 @@ CIRCSock::CIRCSock(CUser* pUser) : CZNCSock() { m_Nick.SetHost(pUser->GetBindHost()); m_uMaxNickLen = 9; + m_uCapPaused = 0; m_sPerms = "*!@%+"; m_sPermModes = "qaohv"; m_mueChanModes['b'] = ListArg; @@ -679,15 +680,11 @@ void CIRCSock::ReadLine(const CString& sData) { for (it = vsTokens.begin(); it != vsTokens.end(); ++it) { if (OnServerCapAvailable(*it) || *it == "multi-prefix" || *it == "userhost-in-names") { - // For real support of ack (~) modifier need also - // to queue these cap requests. - PutIRC("CAP REQ :" + *it); m_ssPendingCaps.insert(*it); } } } else if (sSubCmd == "ACK") { sArgs.Trim(); - m_ssPendingCaps.erase(sArgs); MODULECALL(OnServerCapResult(sArgs, true), m_pUser, NULL, ); if ("multi-prefix" == sArgs) { m_bNamesx = true; @@ -699,14 +696,10 @@ void CIRCSock::ReadLine(const CString& sData) { // This should work because there's no [known] // capability with length of name more than 100 characters. sArgs.Trim(); - m_ssPendingCaps.erase(sArgs); MODULECALL(OnServerCapResult(sArgs, false), m_pUser, NULL, ); } - - if (m_ssPendingCaps.empty()) { - // We already got all needed ACK/NAK replies. - PutIRC("CAP END"); - } + + SendNextCap(); } // Don't forward any CAP stuff to the client return; @@ -716,6 +709,28 @@ void CIRCSock::ReadLine(const CString& sData) { m_pUser->PutUser(sLine); } +void CIRCSock::SendNextCap() { + if (!m_uCapPaused) { + if (m_ssPendingCaps.empty()) { + // We already got all needed ACK/NAK replies. + PutIRC("CAP END"); + } else { + CString sCap = *m_ssPendingCaps.begin(); + m_ssPendingCaps.erase(m_ssPendingCaps.begin()); + PutIRC("CAP REQ :" + sCap); + } + } +} + +void CIRCSock::PauseCap() { + ++m_uCapPaused; +} + +void CIRCSock::ResumeCap() { + --m_uCapPaused; + SendNextCap(); +} + bool CIRCSock::OnServerCapAvailable(const CString& sCap) { MODULECALL(OnServerCapAvailable(sCap), m_pUser, NULL, return true); return false; diff --git a/IRCSock.h b/IRCSock.h index 2301de56..ea832d89 100644 --- a/IRCSock.h +++ b/IRCSock.h @@ -55,6 +55,16 @@ public: void ResetChans(); void Quit(const CString& sQuitMsg = ""); + /** You can call this from CModule::OnServerCapResult to suspend + * sending other CAP requests and CAP END for a while. Each + * call to PauseCap should be balanced with a call to ResumeCap. + */ + void PauseCap(); + /** If you used PauseCap, call this when CAP negotiation and logging in + * should be resumed again. + */ + void ResumeCap(); + // Setters void SetPass(const CString& s) { m_sPass = s; } // !Setters @@ -88,6 +98,7 @@ private: void ParseISupport(const CString& sLine); // This is called when we connect and the nick we want is already taken void SendAltNick(const CString& sBadNick); + void SendNextCap(); protected: bool m_bISpoofReleased; bool m_bAuthed; @@ -102,6 +113,7 @@ protected: CString m_sPass; map m_msChans; unsigned int m_uMaxNickLen; + unsigned int m_uCapPaused; SCString m_ssAcceptedCaps; SCString m_ssPendingCaps; };