diff --git a/ClientCommand.cpp b/ClientCommand.cpp index 3374a789..063103be 100644 --- a/ClientCommand.cpp +++ b/ClientCommand.cpp @@ -97,14 +97,22 @@ void CClient::UserCommand(CString& sLine) { return; } - CChan* pChan = m_pUser->FindChan(sChan); - if (!pChan) { - PutStatus("You are not on [" + sChan + "]"); - return; + const vector& vChans = m_pUser->GetChans(); + vector::const_iterator it; + unsigned int uMatches = 0, uDetached = 0; + for (it = vChans.begin(); it != vChans.end(); ++it) { + if (!(*it)->GetName().WildCmp(sChan)) + continue; + uMatches++; + + if ((*it)->IsDetached()) + continue; + uDetached++; + (*it)->DetachUser(); } - PutStatus("Detaching you from [" + sChan + "]"); - pChan->DetachUser(); + PutStatus("There were [" + CString(uMatches) + "] channels matching [" + sChan + "]"); + PutStatus("Detached [" + CString(uDetached) + "] channels"); } else if (sCommand.Equals("VERSION")) { const char *features = "IPv6: " #ifdef HAVE_IPV6 @@ -306,14 +314,22 @@ void CClient::UserCommand(CString& sLine) { if (sChan.empty()) { PutStatus("Usage: EnableChan "); } else { - CChan* pChan = m_pUser->FindChan(sChan); - if (!pChan) { - PutStatus("Channel [" + sChan + "] not found."); - return; + const vector& vChans = m_pUser->GetChans(); + vector::const_iterator it; + unsigned int uMatches = 0, uEnabled = 0; + for (it = vChans.begin(); it != vChans.end(); ++it) { + if (!(*it)->GetName().WildCmp(sChan)) + continue; + uMatches++; + + if (!(*it)->IsDisabled()) + continue; + uEnabled++; + (*it)->Enable(); } - pChan->Enable(); - PutStatus("Channel [" + sChan + "] enabled."); + PutStatus("There were [" + CString(uMatches) + "] channels matching [" + sChan + "]"); + PutStatus("Enabled [" + CString(uEnabled) + "] channels"); } } else if (sCommand.Equals("LISTCHANS")) { CUser* pUser = m_pUser; @@ -931,13 +947,17 @@ void CClient::UserCommand(CString& sLine) { return; } - if (!pChan->IsOn()) { - PutStatus("You are not on [" + sChan + "] [trying]"); - return; - } + const vector& vChans = m_pUser->GetChans(); + vector::const_iterator it; + unsigned int uMatches = 0; + for (it = vChans.begin(); it != vChans.end(); ++it) { + if (!(*it)->GetName().WildCmp(sChan)) + continue; + uMatches++; - pChan->ClearBuffer(); - PutStatus("The buffer for [" + sChan + "] has been cleared"); + (*it)->ClearBuffer(); + } + PutStatus("The buffer for [" + CString(uMatches) + "] channels matching [" + sChan + "] has been cleared"); } else if (sCommand.Equals("CLEARALLCHANNELBUFFERS")) { vector::const_iterator it; const vector& vChans = m_pUser->GetChans(); @@ -954,21 +974,25 @@ void CClient::UserCommand(CString& sLine) { return; } - CChan* pChan = m_pUser->FindChan(sChan); - - if (!pChan) { - PutStatus("You are not on [" + sChan + "]"); - return; - } - - unsigned int uLineCount = sLine.Token(2).ToUInt(); - if (pChan->SetBufferCount(uLineCount)) { - PutStatus("BufferCount for [" + sChan + "] set to [" + CString(pChan->GetBufferCount()) + "]"); - } else { - PutStatus("Setting the buffer count failed, max buffer count is " - + CString(CZNC::Get().GetMaxBufferSize())); + const vector& vChans = m_pUser->GetChans(); + vector::const_iterator it; + unsigned int uMatches = 0, uFail = 0; + for (it = vChans.begin(); it != vChans.end(); ++it) { + if (!(*it)->GetName().WildCmp(sChan)) + continue; + uMatches++; + + if (!(*it)->SetBufferCount(uLineCount)) + uFail++; + } + + PutStatus("BufferCount for [" + CString(uMatches - uFail) + + "] channels was set to [" + CString(uLineCount) + "]"); + if (uFail > 0) { + PutStatus("Setting BufferCount failed for [" + CString(uFail) + "] channels, " + "max buffer count is " + CString(CZNC::Get().GetMaxBufferSize())); } } else if (m_pUser->IsAdmin() && sCommand.Equals("TRAFFIC")) { CZNC::TrafficStatsPair Users, ZNC, Total; @@ -1122,6 +1146,9 @@ void CClient::HelpUser() { Table.AddColumn("Arguments"); Table.AddColumn("Description"); + PutStatus("In the following list all occurences of <#chan> support wildcards (* and ?)"); + PutStatus("(Except ListNicks)"); + Table.AddRow(); Table.SetCell("Command", "Version"); Table.SetCell("Description", "Print which version of ZNC this is"); diff --git a/configure.ac b/configure.ac index 7e8bcc51..d2ff1a15 100644 --- a/configure.ac +++ b/configure.ac @@ -139,6 +139,7 @@ AC_ARG_ENABLE( [poll], [POLL="yes"]) if test "$DEBUG" != "no"; then + appendCXX -ggdb AC_DEFINE([_DEBUG], [1], [Define for debugging]) # These enable some debug options in g++'s STL, e.g. invalid use of iterators AC_DEFINE([_GLIBCXX_DEBUG], [1], [Enable extra debugging checks in libstdc++]) diff --git a/modules/admin.cpp b/modules/admin.cpp index 9c16b9a0..5a47bede 100644 --- a/modules/admin.cpp +++ b/modules/admin.cpp @@ -13,6 +13,7 @@ #include "User.h" #include "Modules.h" #include "Chan.h" +#include "IRCSock.h" template struct array_size_helper { @@ -44,6 +45,8 @@ class CAdminMod : public CModule { {"DelUser", "username", "Deletes a user"}, {"CloneUser", "oldusername newusername", "Clones a user"}, {"AddServer", "[username] server", "Adds a new IRC server for the given or current user"}, + {"Reconnect", "username", "Cycles the user's IRC server connection"}, + {"Disconnect", "username", "Disconnects the user from their IRC server"}, {"LoadModule", "username modulename", "Loads a Module for a user"}, {"UnLoadModule", "username modulename", "Removes a Module of a user"}, {"ListMods", "username", "Get the list of modules for a user"} @@ -286,7 +289,7 @@ class CAdminMod : public CModule { else if (sVar == "buffercount") { unsigned int i = sValue.ToUInt(); // Admins don't have to honour the buffer limit - if (pUser->SetBufferCount(i), m_pUser->IsAdmin()) { + if (pUser->SetBufferCount(i, m_pUser->IsAdmin())) { PutModule("BufferCount = " + sValue); } else { PutModule("Setting failed, limit is " + @@ -432,7 +435,7 @@ class CAdminMod : public CModule { } else if (sVar == "buffer") { unsigned int i = sValue.ToUInt(); // Admins don't have to honour the buffer limit - if (pChan->SetBufferCount(i), m_pUser->IsAdmin()) { + if (pChan->SetBufferCount(i, m_pUser->IsAdmin())) { PutModule("Buffer = " + sValue); } else { PutModule("Setting failed, limit is " + @@ -625,6 +628,52 @@ class CAdminMod : public CModule { PutModule("Could not add IRC server"); } + void ReconnectUser(const CString& sLine) { + const CString sUsername = sLine.Token(1); + + CUser* pUser = GetUser(sUsername); + if (!pUser) { + PutModule("User not found."); + return; + } + + CIRCSock *pIRCSock = pUser->GetIRCSock(); + // cancel connection attempt: + if (pIRCSock && !pIRCSock->IsConnected()) { + pIRCSock->Close(); + } + // or close existing connection: + else if(pIRCSock) { + pIRCSock->Quit(); + } + + // then reconnect + pUser->SetIRCConnectEnabled(true); + pUser->CheckIRCConnect(); + + PutModule("Queued user for a reconnect."); + } + + void DisconnectUser(const CString& sLine) { + const CString sUsername = sLine.Token(1); + + CUser* pUser = GetUser(sUsername); + if (!pUser) { + PutModule("User not found."); + return; + } + + CIRCSock *pIRCSock = pUser->GetIRCSock(); + if (pIRCSock && !pIRCSock->IsConnected()) + pIRCSock->Close(); + else if(pIRCSock) + pIRCSock->Quit(); + + pUser->SetIRCConnectEnabled(false); + + PutModule("Closed user's IRC connection."); + } + void LoadModuleForUser(const CString& sLine) { CString sUsername = sLine.Token(1); CString sModName = sLine.Token(2); @@ -736,6 +785,8 @@ public: fnmap_["deluser"] = &CAdminMod::DelUser; fnmap_["cloneuser"] = &CAdminMod::CloneUser; fnmap_["addserver"] = &CAdminMod::AddServer; + fnmap_["reconnect"] = &CAdminMod::ReconnectUser; + fnmap_["disconnect"] = &CAdminMod::DisconnectUser; fnmap_["loadmodule"] = &CAdminMod::LoadModuleForUser; fnmap_["unloadmodule"] = &CAdminMod::UnLoadModuleForUser; fnmap_["listmods"] = &CAdminMod::ListModuleForUser; @@ -756,4 +807,4 @@ public: } }; -MODULEDEFS(CAdminMod, "Dynamic configuration of users/settings through irc") +MODULEDEFS(CAdminMod, "Dynamic configuration of users/settings through IRC")