Files
znc/src/ClientCommand.cpp
2018-03-26 08:47:27 +01:00

1842 lines
66 KiB
C++

/*
* Copyright (C) 2004-2018 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <znc/Client.h>
#include <znc/Chan.h>
#include <znc/FileUtils.h>
#include <znc/IRCNetwork.h>
#include <znc/IRCSock.h>
#include <znc/Server.h>
#include <znc/User.h>
#include <znc/Query.h>
using std::vector;
using std::set;
using std::map;
void CClient::UserCommand(CString& sLine) {
if (!m_pUser) {
return;
}
if (sLine.empty()) {
return;
}
bool bReturn = false;
NETWORKMODULECALL(OnStatusCommand(sLine), m_pUser, m_pNetwork, this,
&bReturn);
if (bReturn) return;
const CString sCommand = sLine.Token(0);
if (sCommand.Equals("HELP")) {
HelpUser(sLine.Token(1));
} else if (sCommand.Equals("LISTNICKS")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
CString sChan = sLine.Token(1);
if (sChan.empty()) {
PutStatus(t_s("Usage: ListNicks <#chan>"));
return;
}
CChan* pChan = m_pNetwork->FindChan(sChan);
if (!pChan) {
PutStatus(t_f("You are not on [{1}]")(sChan));
return;
}
if (!pChan->IsOn()) {
PutStatus(t_f("You are not on [{1}] (trying)")(sChan));
return;
}
const map<CString, CNick>& msNicks = pChan->GetNicks();
CIRCSock* pIRCSock = m_pNetwork->GetIRCSock();
const CString& sPerms = (pIRCSock) ? pIRCSock->GetPerms() : "";
if (msNicks.empty()) {
PutStatus(t_f("No nicks on [{1}]")(sChan));
return;
}
CTable Table;
for (unsigned int p = 0; p < sPerms.size(); p++) {
CString sPerm;
sPerm += sPerms[p];
Table.AddColumn(sPerm);
}
Table.AddColumn(t_s("Nick"));
Table.AddColumn(t_s("Ident"));
Table.AddColumn(t_s("Host"));
for (const auto& it : msNicks) {
Table.AddRow();
for (unsigned int b = 0; b < sPerms.size(); b++) {
if (it.second.HasPerm(sPerms[b])) {
CString sPerm;
sPerm += sPerms[b];
Table.SetCell(sPerm, sPerm);
}
}
Table.SetCell(t_s("Nick"), it.second.GetNick());
Table.SetCell(t_s("Ident"), it.second.GetIdent());
Table.SetCell(t_s("Host"), it.second.GetHost());
}
PutStatus(Table);
} else if (sCommand.Equals("ATTACH")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
CString sPatterns = sLine.Token(1, true);
if (sPatterns.empty()) {
PutStatus(t_s("Usage: Attach <#chans>"));
return;
}
set<CChan*> sChans = MatchChans(sPatterns);
unsigned int uAttachedChans = AttachChans(sChans);
PutStatus(t_p("There was {1} channel matching [{2}]",
"There were {1} channels matching [{2}]",
sChans.size())(sChans.size(), sPatterns));
PutStatus(t_p("Attached {1} channel", "Attached {1} channels",
uAttachedChans)(uAttachedChans));
} else if (sCommand.Equals("DETACH")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
CString sPatterns = sLine.Token(1, true);
if (sPatterns.empty()) {
PutStatus(t_s("Usage: Detach <#chans>"));
return;
}
set<CChan*> sChans = MatchChans(sPatterns);
unsigned int uDetached = DetachChans(sChans);
PutStatus(t_p("There was {1} channel matching [{2}]",
"There were {1} channels matching [{2}]",
sChans.size())(sChans.size(), sPatterns));
PutStatus(t_p("Detached {1} channel", "Detached {1} channels",
uDetached)(uDetached));
} else if (sCommand.Equals("VERSION")) {
PutStatus(CZNC::GetTag());
PutStatus(CZNC::GetCompileOptionsString());
} else if (sCommand.Equals("MOTD") || sCommand.Equals("ShowMOTD")) {
if (!SendMotd()) {
PutStatus(t_s("There is no MOTD set."));
}
} else if (m_pUser->IsAdmin() && sCommand.Equals("Rehash")) {
CString sRet;
if (CZNC::Get().RehashConfig(sRet)) {
PutStatus(t_s("Rehashing succeeded!"));
} else {
PutStatus(t_f("Rehashing failed: {1}")(sRet));
}
} else if (m_pUser->IsAdmin() && sCommand.Equals("SaveConfig")) {
if (CZNC::Get().WriteConfig()) {
PutStatus(t_f("Wrote config to {1}")(CZNC::Get().GetConfigFile()));
} else {
PutStatus(t_s("Error while trying to write config."));
}
} else if (sCommand.Equals("LISTCLIENTS")) {
CUser* pUser = m_pUser;
CString sNick = sLine.Token(1);
if (!sNick.empty()) {
if (!m_pUser->IsAdmin()) {
PutStatus("Usage: ListClients");
return;
}
pUser = CZNC::Get().FindUser(sNick);
if (!pUser) {
PutStatus("No such user [" + sNick + "]");
return;
}
}
vector<CClient*> vClients = pUser->GetAllClients();
if (vClients.empty()) {
PutStatus("No clients are connected");
return;
}
CTable Table;
Table.AddColumn("Host");
Table.AddColumn("Network");
Table.AddColumn("Identifier");
for (const CClient* pClient : vClients) {
Table.AddRow();
Table.SetCell("Host", pClient->GetRemoteIP());
if (pClient->GetNetwork()) {
Table.SetCell("Network", pClient->GetNetwork()->GetName());
}
Table.SetCell("Identifier", pClient->GetIdentifier());
}
PutStatus(Table);
} else if (m_pUser->IsAdmin() && sCommand.Equals("LISTUSERS")) {
const map<CString, CUser*>& msUsers = CZNC::Get().GetUserMap();
CTable Table;
Table.AddColumn("Username");
Table.AddColumn("Networks");
Table.AddColumn("Clients");
for (const auto& it : msUsers) {
Table.AddRow();
Table.SetCell("Username", it.first);
Table.SetCell("Networks", CString(it.second->GetNetworks().size()));
Table.SetCell("Clients",
CString(it.second->GetAllClients().size()));
}
PutStatus(Table);
} else if (m_pUser->IsAdmin() && sCommand.Equals("LISTALLUSERNETWORKS")) {
const map<CString, CUser*>& msUsers = CZNC::Get().GetUserMap();
CTable Table;
Table.AddColumn("Username");
Table.AddColumn("Network");
Table.AddColumn("Clients");
Table.AddColumn("OnIRC");
Table.AddColumn("IRC Server");
Table.AddColumn("IRC User");
Table.AddColumn("Channels");
for (const auto& it : msUsers) {
Table.AddRow();
Table.SetCell("Username", it.first);
Table.SetCell("Network", "N/A");
Table.SetCell("Clients",
CString(it.second->GetUserClients().size()));
const vector<CIRCNetwork*>& vNetworks = it.second->GetNetworks();
for (const CIRCNetwork* pNetwork : vNetworks) {
Table.AddRow();
if (pNetwork == vNetworks.back()) {
Table.SetCell("Username", "`-");
} else {
Table.SetCell("Username", "|-");
}
Table.SetCell("Network", pNetwork->GetName());
Table.SetCell("Clients",
CString(pNetwork->GetClients().size()));
if (pNetwork->IsIRCConnected()) {
Table.SetCell("OnIRC", "Yes");
Table.SetCell("IRC Server", pNetwork->GetIRCServer());
Table.SetCell("IRC User",
pNetwork->GetIRCNick().GetNickMask());
Table.SetCell("Channels",
CString(pNetwork->GetChans().size()));
} else {
Table.SetCell("OnIRC", "No");
}
}
}
PutStatus(Table);
} else if (m_pUser->IsAdmin() && sCommand.Equals("SetMOTD")) {
CString sMessage = sLine.Token(1, true);
if (sMessage.empty()) {
PutStatus("Usage: SetMOTD <message>");
} else {
CZNC::Get().SetMotd(sMessage);
PutStatus("MOTD set to [" + sMessage + "]");
}
} else if (m_pUser->IsAdmin() && sCommand.Equals("AddMOTD")) {
CString sMessage = sLine.Token(1, true);
if (sMessage.empty()) {
PutStatus("Usage: AddMOTD <message>");
} else {
CZNC::Get().AddMotd(sMessage);
PutStatus("Added [" + sMessage + "] to MOTD");
}
} else if (m_pUser->IsAdmin() && sCommand.Equals("ClearMOTD")) {
CZNC::Get().ClearMotd();
PutStatus("Cleared MOTD");
} else if (m_pUser->IsAdmin() && sCommand.Equals("BROADCAST")) {
CZNC::Get().Broadcast(sLine.Token(1, true));
} else if (m_pUser->IsAdmin() &&
(sCommand.Equals("SHUTDOWN") || sCommand.Equals("RESTART"))) {
bool bRestart = sCommand.Equals("RESTART");
CString sMessage = sLine.Token(1, true);
bool bForce = false;
if (sMessage.Token(0).Equals("FORCE")) {
bForce = true;
sMessage = sMessage.Token(1, true);
}
if (sMessage.empty()) {
sMessage = (bRestart ? "ZNC is being restarted NOW!"
: "ZNC is being shut down NOW!");
}
if (!CZNC::Get().WriteConfig() && !bForce) {
PutStatus(
"ERROR: Writing config file to disk failed! Aborting. Use " +
sCommand.AsUpper() + " FORCE to ignore.");
} else {
CZNC::Get().Broadcast(sMessage);
throw CException(bRestart ? CException::EX_Restart
: CException::EX_Shutdown);
}
} else if (sCommand.Equals("JUMP") || sCommand.Equals("CONNECT")) {
if (!m_pNetwork) {
PutStatus(
"You must be connected with a network to use this command");
return;
}
if (!m_pNetwork->HasServers()) {
PutStatus("You don't have any servers added.");
return;
}
CString sArgs = sLine.Token(1, true);
sArgs.Trim();
CServer* pServer = nullptr;
if (!sArgs.empty()) {
pServer = m_pNetwork->FindServer(sArgs);
if (!pServer) {
PutStatus("Server [" + sArgs + "] not found");
return;
}
m_pNetwork->SetNextServer(pServer);
// If we are already connecting to some server,
// we have to abort that attempt
Csock* pIRCSock = GetIRCSock();
if (pIRCSock && !pIRCSock->IsConnected()) {
pIRCSock->Close();
}
}
if (!pServer) {
pServer = m_pNetwork->GetNextServer(false);
}
if (GetIRCSock()) {
GetIRCSock()->Quit();
if (pServer)
PutStatus("Connecting to [" + pServer->GetName() + "]...");
else
PutStatus("Jumping to the next server in the list...");
} else {
if (pServer)
PutStatus("Connecting to [" + pServer->GetName() + "]...");
else
PutStatus("Connecting...");
}
m_pNetwork->SetIRCConnectEnabled(true);
return;
} else if (sCommand.Equals("DISCONNECT")) {
if (!m_pNetwork) {
PutStatus(
"You must be connected with a network to use this command");
return;
}
if (GetIRCSock()) {
CString sQuitMsg = sLine.Token(1, true);
GetIRCSock()->Quit(sQuitMsg);
}
m_pNetwork->SetIRCConnectEnabled(false);
PutStatus("Disconnected from IRC. Use 'connect' to reconnect.");
return;
} else if (sCommand.Equals("ENABLECHAN")) {
if (!m_pNetwork) {
PutStatus(
"You must be connected with a network to use this command");
return;
}
CString sPatterns = sLine.Token(1, true);
if (sPatterns.empty()) {
PutStatus("Usage: EnableChan <#chans>");
} else {
set<CChan*> sChans = MatchChans(sPatterns);
unsigned int uEnabled = 0;
for (CChan* pChan : sChans) {
if (!pChan->IsDisabled()) continue;
uEnabled++;
pChan->Enable();
}
PutStatus("There were [" + CString(sChans.size()) +
"] channels matching [" + sPatterns + "]");
PutStatus("Enabled [" + CString(uEnabled) + "] channels");
}
} else if (sCommand.Equals("DISABLECHAN")) {
if (!m_pNetwork) {
PutStatus(
"You must be connected with a network to use this command");
return;
}
CString sPatterns = sLine.Token(1, true);
if (sPatterns.empty()) {
PutStatus("Usage: DisableChan <#chans>");
} else {
set<CChan*> sChans = MatchChans(sPatterns);
unsigned int uDisabled = 0;
for (CChan* pChan : sChans) {
if (pChan->IsDisabled()) continue;
uDisabled++;
pChan->Disable();
}
PutStatus("There were [" + CString(sChans.size()) +
"] channels matching [" + sPatterns + "]");
PutStatus("Disabled [" + CString(uDisabled) + "] channels");
}
} else if (sCommand.Equals("LISTCHANS")) {
if (!m_pNetwork) {
PutStatus(
"You must be connected with a network to use this command");
return;
}
CIRCNetwork* pNetwork = m_pNetwork;
const CString sUser = sLine.Token(1);
const CString sNetwork = sLine.Token(2);
if (!sUser.empty()) {
if (!m_pUser->IsAdmin()) {
PutStatus(t_s("Usage: ListChans"));
return;
}
CUser* pUser = CZNC::Get().FindUser(sUser);
if (!pUser) {
PutStatus(t_f("No such user [{1}]")(sUser));
return;
}
pNetwork = pUser->FindNetwork(sNetwork);
if (!pNetwork) {
PutStatus(t_f("User [{1}] doesn't have network [{2}]")(
sUser, sNetwork));
return;
}
}
const vector<CChan*>& vChans = pNetwork->GetChans();
CIRCSock* pIRCSock = pNetwork->GetIRCSock();
CString sPerms = pIRCSock ? pIRCSock->GetPerms() : "";
if (vChans.empty()) {
PutStatus(t_s("There are no channels defined."));
return;
}
CTable Table;
Table.AddColumn(t_s("Name", "listchans"));
Table.AddColumn(t_s("Status", "listchans"));
Table.AddColumn(t_s("In config", "listchans"));
Table.AddColumn(t_s("Buffer", "listchans"));
Table.AddColumn(t_s("Clear", "listchans"));
Table.AddColumn(t_s("Modes", "listchans"));
Table.AddColumn(t_s("Users", "listchans"));
for (char cPerm : sPerms) {
Table.AddColumn(CString(cPerm));
}
unsigned int uNumDetached = 0, uNumDisabled = 0, uNumJoined = 0;
for (const CChan* pChan : vChans) {
Table.AddRow();
Table.SetCell(t_s("Name", "listchans"),
pChan->GetPermStr() + pChan->GetName());
Table.SetCell(
t_s("Status", "listchans"),
pChan->IsOn()
? (pChan->IsDetached() ? t_s("Detached", "listchans")
: t_s("Joined", "listchans"))
: (pChan->IsDisabled() ? t_s("Disabled", "listchans")
: t_s("Trying", "listchans")));
Table.SetCell(
t_s("In config", "listchans"),
CString(pChan->InConfig() ? t_s("yes", "listchans") : ""));
Table.SetCell(t_s("Buffer", "listchans"),
CString(pChan->HasBufferCountSet() ? "*" : "") +
CString(pChan->GetBufferCount()));
Table.SetCell(
t_s("Clear", "listchans"),
CString(pChan->HasAutoClearChanBufferSet() ? "*" : "") +
CString(pChan->AutoClearChanBuffer()
? t_s("yes", "listchans")
: ""));
Table.SetCell(t_s("Modes", "listchans"), pChan->GetModeString());
Table.SetCell(t_s("Users", "listchans"),
CString(pChan->GetNickCount()));
std::map<char, unsigned int> mPerms = pChan->GetPermCounts();
for (char cPerm : sPerms) {
Table.SetCell(CString(cPerm), CString(mPerms[cPerm]));
}
if (pChan->IsDetached()) uNumDetached++;
if (pChan->IsOn()) uNumJoined++;
if (pChan->IsDisabled()) uNumDisabled++;
}
PutStatus(Table);
PutStatus(t_f("Total: {1}, Joined: {2}, Detached: {3}, Disabled: {4}")(
vChans.size(), uNumJoined, uNumDetached, uNumDisabled));
} else if (sCommand.Equals("ADDNETWORK")) {
if (!m_pUser->IsAdmin() && !m_pUser->HasSpaceForNewNetwork()) {
PutStatus(t_s(
"Network number limit reached. Ask an admin to increase the "
"limit for you, or delete unneeded networks using /znc "
"DelNetwork <name>"));
return;
}
CString sNetwork = sLine.Token(1);
if (sNetwork.empty()) {
PutStatus(t_s("Usage: AddNetwork <name>"));
return;
}
if (!CIRCNetwork::IsValidNetwork(sNetwork)) {
PutStatus(t_s("Network name should be alphanumeric"));
return;
}
CString sNetworkAddError;
if (m_pUser->AddNetwork(sNetwork, sNetworkAddError)) {
PutStatus(
t_f("Network added. Use /znc JumpNetwork {1}, or connect to "
"ZNC with username {2} (instead of just {3}) to connect to "
"it.")(sNetwork, m_pUser->GetUserName() + "/" + sNetwork,
m_pUser->GetUserName()));
} else {
PutStatus(t_s("Unable to add that network"));
PutStatus(sNetworkAddError);
}
} else if (sCommand.Equals("DELNETWORK")) {
CString sNetwork = sLine.Token(1);
if (sNetwork.empty()) {
PutStatus(t_s("Usage: DelNetwork <name>"));
return;
}
if (m_pNetwork && m_pNetwork->GetName().Equals(sNetwork)) {
SetNetwork(nullptr);
}
if (m_pUser->DeleteNetwork(sNetwork)) {
PutStatus(t_s("Network deleted"));
} else {
PutStatus(
t_s("Failed to delete network, perhaps this network doesn't "
"exist"));
}
} else if (sCommand.Equals("LISTNETWORKS")) {
CUser* pUser = m_pUser;
if (m_pUser->IsAdmin() && !sLine.Token(1).empty()) {
pUser = CZNC::Get().FindUser(sLine.Token(1));
if (!pUser) {
PutStatus(t_f("User {1} not found")(sLine.Token(1)));
return;
}
}
const vector<CIRCNetwork*>& vNetworks = pUser->GetNetworks();
CTable Table;
Table.AddColumn(t_s("Network", "listnetworks"));
Table.AddColumn(t_s("On IRC", "listnetworks"));
Table.AddColumn(t_s("IRC Server", "listnetworks"));
Table.AddColumn(t_s("IRC User", "listnetworks"));
Table.AddColumn(t_s("Channels", "listnetworks"));
for (const CIRCNetwork* pNetwork : vNetworks) {
Table.AddRow();
Table.SetCell(t_s("Network", "listnetworks"), pNetwork->GetName());
if (pNetwork->IsIRCConnected()) {
Table.SetCell(t_s("On IRC", "listnetworks"),
t_s("Yes", "listnetworks"));
Table.SetCell(t_s("IRC Server", "listnetworks"),
pNetwork->GetIRCServer());
Table.SetCell(t_s("IRC User", "listnetworks"),
pNetwork->GetIRCNick().GetNickMask());
Table.SetCell(t_s("Channels", "listnetworks"),
CString(pNetwork->GetChans().size()));
} else {
Table.SetCell(t_s("On IRC", "listnetworks"),
t_s("No", "listnetworks"));
}
}
if (PutStatus(Table) == 0) {
PutStatus(t_s("No networks", "listnetworks"));
}
} else if (sCommand.Equals("MOVENETWORK")) {
if (!m_pUser->IsAdmin()) {
PutStatus(t_s("Access denied."));
return;
}
CString sOldUser = sLine.Token(1);
CString sOldNetwork = sLine.Token(2);
CString sNewUser = sLine.Token(3);
CString sNewNetwork = sLine.Token(4);
if (sOldUser.empty() || sOldNetwork.empty() || sNewUser.empty()) {
PutStatus(t_s(
"Usage: MoveNetwork <old user> <old network> <new user> [new "
"network]"));
return;
}
if (sNewNetwork.empty()) {
sNewNetwork = sOldNetwork;
}
CUser* pOldUser = CZNC::Get().FindUser(sOldUser);
if (!pOldUser) {
PutStatus(t_f("Old user {1} not found.")(sOldUser));
return;
}
CIRCNetwork* pOldNetwork = pOldUser->FindNetwork(sOldNetwork);
if (!pOldNetwork) {
PutStatus(t_f("Old network {1} not found.")(sOldNetwork));
return;
}
CUser* pNewUser = CZNC::Get().FindUser(sNewUser);
if (!pNewUser) {
PutStatus(t_f("New user {1} not found.")(sNewUser));
return;
}
if (pNewUser->FindNetwork(sNewNetwork)) {
PutStatus(t_f("User {1} already has network {2}.")(sNewUser,
sNewNetwork));
return;
}
if (!CIRCNetwork::IsValidNetwork(sNewNetwork)) {
PutStatus(t_f("Invalid network name [{1}]")(sNewNetwork));
return;
}
const CModules& vMods = pOldNetwork->GetModules();
for (CModule* pMod : vMods) {
CString sOldModPath = pOldNetwork->GetNetworkPath() + "/moddata/" +
pMod->GetModName();
CString sNewModPath = pNewUser->GetUserPath() + "/networks/" +
sNewNetwork + "/moddata/" +
pMod->GetModName();
CDir oldDir(sOldModPath);
for (CFile* pFile : oldDir) {
if (pFile->GetShortName() != ".registry") {
PutStatus(
t_f("Some files seem to be in {1}. You might want to "
"move them to {2}")(sOldModPath, sNewModPath));
break;
}
}
pMod->MoveRegistry(sNewModPath);
}
CString sNetworkAddError;
CIRCNetwork* pNewNetwork =
pNewUser->AddNetwork(sNewNetwork, sNetworkAddError);
if (!pNewNetwork) {
PutStatus(t_f("Error adding network: {1}")(sNetworkAddError));
return;
}
pNewNetwork->Clone(*pOldNetwork, false);
if (m_pNetwork && m_pNetwork->GetName().Equals(sOldNetwork) &&
m_pUser == pOldUser) {
SetNetwork(nullptr);
}
if (pOldUser->DeleteNetwork(sOldNetwork)) {
PutStatus(t_s("Success."));
} else {
PutStatus(
t_s("Copied the network to new user, but failed to delete old "
"network"));
}
} else if (sCommand.Equals("JUMPNETWORK")) {
CString sNetwork = sLine.Token(1);
if (sNetwork.empty()) {
PutStatus(t_s("No network supplied."));
return;
}
if (m_pNetwork && (m_pNetwork->GetName() == sNetwork)) {
PutStatus(t_s("You are already connected with this network."));
return;
}
CIRCNetwork* pNetwork = m_pUser->FindNetwork(sNetwork);
if (pNetwork) {
PutStatus(t_f("Switched to {1}")(sNetwork));
SetNetwork(pNetwork);
} else {
PutStatus(t_f("You don't have a network named {1}")(sNetwork));
}
} else if (sCommand.Equals("ADDSERVER")) {
CString sServer = sLine.Token(1);
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
if (sServer.empty()) {
PutStatus(t_s("Usage: AddServer <host> [[+]port] [pass]"));
return;
}
if (m_pNetwork->AddServer(sLine.Token(1, true))) {
PutStatus(t_s("Server added"));
} else {
PutStatus(
t_s("Unable to add that server. Perhaps the server is already "
"added or openssl is disabled?"));
}
} else if (sCommand.Equals("REMSERVER") || sCommand.Equals("DELSERVER")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
CString sServer = sLine.Token(1);
unsigned short uPort = sLine.Token(2).ToUShort();
CString sPass = sLine.Token(3);
if (sServer.empty()) {
PutStatus(t_s("Usage: DelServer <host> [port] [pass]"));
return;
}
if (!m_pNetwork->HasServers()) {
PutStatus(t_s("You don't have any servers added."));
return;
}
if (m_pNetwork->DelServer(sServer, uPort, sPass)) {
PutStatus(t_s("Server removed"));
} else {
PutStatus(t_s("No such server"));
}
} else if (sCommand.Equals("LISTSERVERS")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
if (m_pNetwork->HasServers()) {
const vector<CServer*>& vServers = m_pNetwork->GetServers();
CServer* pCurServ = m_pNetwork->GetCurrentServer();
CTable Table;
Table.AddColumn(t_s("Host", "listservers"));
Table.AddColumn(t_s("Port", "listservers"));
Table.AddColumn(t_s("SSL", "listservers"));
Table.AddColumn(t_s("Password", "listservers"));
for (const CServer* pServer : vServers) {
Table.AddRow();
Table.SetCell(t_s("Host", "listservers"), pServer->GetName() +
(pServer == pCurServ ? "*" : ""));
Table.SetCell(t_s("Port", "listservers"),
CString(pServer->GetPort()));
Table.SetCell(
t_s("SSL", "listservers"),
(pServer->IsSSL()) ? t_s("SSL", "listservers|cell") : "");
Table.SetCell(t_s("Password", "listservers"),
pServer->GetPass().empty() ? "" : "******");
}
PutStatus(Table);
} else {
PutStatus(t_s("You don't have any servers added."));
}
} else if (sCommand.Equals("AddTrustedServerFingerprint")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
CString sFP = sLine.Token(1);
if (sFP.empty()) {
PutStatus(t_s("Usage: AddTrustedServerFingerprint <fi:ng:er>"));
return;
}
m_pNetwork->AddTrustedFingerprint(sFP);
PutStatus(t_s("Done."));
} else if (sCommand.Equals("DelTrustedServerFingerprint")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
CString sFP = sLine.Token(1);
if (sFP.empty()) {
PutStatus(t_s("Usage: DelTrustedServerFingerprint <fi:ng:er>"));
return;
}
m_pNetwork->DelTrustedFingerprint(sFP);
PutStatus(t_s("Done."));
} else if (sCommand.Equals("ListTrustedServerFingerprints")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
const SCString& ssFPs = m_pNetwork->GetTrustedFingerprints();
if (ssFPs.empty()) {
PutStatus(t_s("No fingerprints added."));
} else {
int k = 0;
for (const CString& sFP : ssFPs) {
PutStatus(CString(++k) + ". " + sFP);
}
}
} else if (sCommand.Equals("TOPICS")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
const vector<CChan*>& vChans = m_pNetwork->GetChans();
CTable Table;
Table.AddColumn(t_s("Channel", "topicscmd"));
Table.AddColumn(t_s("Set By", "topicscmd"));
Table.AddColumn(t_s("Topic", "topicscmd"));
for (const CChan* pChan : vChans) {
Table.AddRow();
Table.SetCell(t_s("Channel", "topicscmd"), pChan->GetName());
Table.SetCell(t_s("Set By", "topicscmd"), pChan->GetTopicOwner());
Table.SetCell(t_s("Topic", "topicscmd"), pChan->GetTopic());
}
PutStatus(Table);
} else if (sCommand.Equals("LISTMODS") || sCommand.Equals("LISTMODULES")) {
const auto PrintModules = [this](const CModules& Modules) {
CTable Table;
Table.AddColumn(t_s("Name", "listmods"));
Table.AddColumn(t_s("Arguments", "listmods"));
for (const CModule* pMod : Modules) {
Table.AddRow();
Table.SetCell(t_s("Name", "listmods"), pMod->GetModName());
Table.SetCell(t_s("Arguments", "listmods"), pMod->GetArgs());
}
PutStatus(Table);
};
if (m_pUser->IsAdmin()) {
const CModules& GModules = CZNC::Get().GetModules();
if (!GModules.size()) {
PutStatus(t_s("No global modules loaded."));
} else {
PutStatus(t_s("Global modules:"));
PrintModules(GModules);
}
}
const CModules& UModules = m_pUser->GetModules();
if (!UModules.size()) {
PutStatus(t_s("Your user has no modules loaded."));
} else {
PutStatus(t_s("User modules:"));
PrintModules(UModules);
}
if (m_pNetwork) {
const CModules& NetworkModules = m_pNetwork->GetModules();
if (NetworkModules.empty()) {
PutStatus(t_s("This network has no modules loaded."));
} else {
PutStatus(t_s("Network modules:"));
PrintModules(NetworkModules);
}
}
return;
} else if (sCommand.Equals("LISTAVAILMODS") ||
sCommand.Equals("LISTAVAILABLEMODULES")) {
if (m_pUser->DenyLoadMod()) {
PutStatus(t_s("Access denied."));
return;
}
const auto PrintModules = [this](const set<CModInfo>& ssModules) {
CTable Table;
Table.AddColumn(t_s("Name", "listavailmods"));
Table.AddColumn(t_s("Description", "listavailmods"));
for (const CModInfo& Info : ssModules) {
Table.AddRow();
Table.SetCell(
t_s("Name", "listavailmods"),
(CZNC::Get().GetModules().FindModule(Info.GetName())
? "*"
: " ") +
Info.GetName());
Table.SetCell(t_s("Description", "listavailmods"),
Info.GetDescription().Ellipsize(128));
}
PutStatus(Table);
};
if (m_pUser->IsAdmin()) {
set<CModInfo> ssGlobalMods;
CZNC::Get().GetModules().GetAvailableMods(ssGlobalMods,
CModInfo::GlobalModule);
if (ssGlobalMods.empty()) {
PutStatus(t_s("No global modules available."));
} else {
PutStatus(t_s("Global modules:"));
PrintModules(ssGlobalMods);
}
}
set<CModInfo> ssUserMods;
CZNC::Get().GetModules().GetAvailableMods(ssUserMods);
if (ssUserMods.empty()) {
PutStatus(t_s("No user modules available."));
} else {
PutStatus(t_s("User modules:"));
PrintModules(ssUserMods);
}
set<CModInfo> ssNetworkMods;
CZNC::Get().GetModules().GetAvailableMods(ssNetworkMods,
CModInfo::NetworkModule);
if (ssNetworkMods.empty()) {
PutStatus(t_s("No network modules available."));
} else {
PutStatus(t_s("Network modules:"));
PrintModules(ssNetworkMods);
}
return;
} else if (sCommand.Equals("LOADMOD") || sCommand.Equals("LOADMODULE")) {
CModInfo::EModuleType eType;
CString sType = sLine.Token(1);
CString sMod = sLine.Token(2);
CString sArgs = sLine.Token(3, true);
// TODO use proper library for parsing arguments
if (sType.Equals("--type=global")) {
eType = CModInfo::GlobalModule;
} else if (sType.Equals("--type=user")) {
eType = CModInfo::UserModule;
} else if (sType.Equals("--type=network")) {
eType = CModInfo::NetworkModule;
} else {
sMod = sType;
sArgs = sLine.Token(2, true);
sType = "default";
// Will be set correctly later
eType = CModInfo::UserModule;
}
if (m_pUser->DenyLoadMod()) {
PutStatus(t_f("Unable to load {1}: Access denied.")(sMod));
return;
}
if (sMod.empty()) {
PutStatus(t_s(
"Usage: LoadMod [--type=global|user|network] <module> [args]"));
return;
}
CModInfo ModInfo;
CString sRetMsg;
if (!CZNC::Get().GetModules().GetModInfo(ModInfo, sMod, sRetMsg)) {
PutStatus(t_f("Unable to load {1}: {2}")(sMod, sRetMsg));
return;
}
if (sType.Equals("default")) {
eType = ModInfo.GetDefaultType();
}
if (eType == CModInfo::GlobalModule && !m_pUser->IsAdmin()) {
PutStatus(
t_f("Unable to load global module {1}: Access denied.")(sMod));
return;
}
if (eType == CModInfo::NetworkModule && !m_pNetwork) {
PutStatus(
t_f("Unable to load network module {1}: Not connected with a "
"network.")(sMod));
return;
}
CString sModRet;
bool bLoaded = false;
switch (eType) {
case CModInfo::GlobalModule:
bLoaded = CZNC::Get().GetModules().LoadModule(
sMod, sArgs, eType, nullptr, nullptr, sModRet);
break;
case CModInfo::UserModule:
bLoaded = m_pUser->GetModules().LoadModule(sMod, sArgs, eType,
m_pUser, nullptr, sModRet);
break;
case CModInfo::NetworkModule:
bLoaded = m_pNetwork->GetModules().LoadModule(
sMod, sArgs, eType, m_pUser, m_pNetwork, sModRet);
break;
default:
sModRet = t_s("Unknown module type");
}
if (bLoaded) {
if (sModRet.empty()) {
PutStatus(t_f("Loaded module {1}")(sMod));
} else {
PutStatus(t_f("Loaded module {1}: {2}")(sMod, sModRet));
}
} else {
PutStatus(t_f("Unable to load module {1}: {2}")(sMod, sModRet));
}
return;
} else if (sCommand.Equals("UNLOADMOD") ||
sCommand.Equals("UNLOADMODULE")) {
CModInfo::EModuleType eType = CModInfo::UserModule;
CString sType = sLine.Token(1);
CString sMod = sLine.Token(2);
// TODO use proper library for parsing arguments
if (sType.Equals("--type=global")) {
eType = CModInfo::GlobalModule;
} else if (sType.Equals("--type=user")) {
eType = CModInfo::UserModule;
} else if (sType.Equals("--type=network")) {
eType = CModInfo::NetworkModule;
} else {
sMod = sType;
sType = "default";
}
if (m_pUser->DenyLoadMod()) {
PutStatus(t_f("Unable to unload {1}: Access denied.")(sMod));
return;
}
if (sMod.empty()) {
PutStatus(
t_s("Usage: UnloadMod [--type=global|user|network] <module>"));
return;
}
if (sType.Equals("default")) {
CModInfo ModInfo;
CString sRetMsg;
if (!CZNC::Get().GetModules().GetModInfo(ModInfo, sMod, sRetMsg)) {
PutStatus(
t_f("Unable to determine type of {1}: {2}")(sMod, sRetMsg));
return;
}
eType = ModInfo.GetDefaultType();
}
if (eType == CModInfo::GlobalModule && !m_pUser->IsAdmin()) {
PutStatus(t_f("Unable to unload global module {1}: Access denied.")(
sMod));
return;
}
if (eType == CModInfo::NetworkModule && !m_pNetwork) {
PutStatus(
t_f("Unable to unload network module {1}: Not connected with a "
"network.")(sMod));
return;
}
CString sModRet;
switch (eType) {
case CModInfo::GlobalModule:
CZNC::Get().GetModules().UnloadModule(sMod, sModRet);
break;
case CModInfo::UserModule:
m_pUser->GetModules().UnloadModule(sMod, sModRet);
break;
case CModInfo::NetworkModule:
m_pNetwork->GetModules().UnloadModule(sMod, sModRet);
break;
default:
sModRet = t_f(
"Unable to unload module {1}: Unknown module type")(sMod);
}
PutStatus(sModRet);
return;
} else if (sCommand.Equals("RELOADMOD") ||
sCommand.Equals("RELOADMODULE")) {
CModInfo::EModuleType eType;
CString sType = sLine.Token(1);
CString sMod = sLine.Token(2);
CString sArgs = sLine.Token(3, true);
if (m_pUser->DenyLoadMod()) {
PutStatus(t_s("Unable to reload modules. Access denied."));
return;
}
// TODO use proper library for parsing arguments
if (sType.Equals("--type=global")) {
eType = CModInfo::GlobalModule;
} else if (sType.Equals("--type=user")) {
eType = CModInfo::UserModule;
} else if (sType.Equals("--type=network")) {
eType = CModInfo::NetworkModule;
} else {
sMod = sType;
sArgs = sLine.Token(2, true);
sType = "default";
// Will be set correctly later
eType = CModInfo::UserModule;
}
if (sMod.empty()) {
PutStatus(
t_s("Usage: ReloadMod [--type=global|user|network] <module> "
"[args]"));
return;
}
if (sType.Equals("default")) {
CModInfo ModInfo;
CString sRetMsg;
if (!CZNC::Get().GetModules().GetModInfo(ModInfo, sMod, sRetMsg)) {
PutStatus(t_f("Unable to reload {1}: {2}")(sMod, sRetMsg));
return;
}
eType = ModInfo.GetDefaultType();
}
if (eType == CModInfo::GlobalModule && !m_pUser->IsAdmin()) {
PutStatus(t_f("Unable to reload global module {1}: Access denied.")(
sMod));
return;
}
if (eType == CModInfo::NetworkModule && !m_pNetwork) {
PutStatus(
t_f("Unable to reload network module {1}: Not connected with a "
"network.")(sMod));
return;
}
CString sModRet;
switch (eType) {
case CModInfo::GlobalModule:
CZNC::Get().GetModules().ReloadModule(sMod, sArgs, nullptr,
nullptr, sModRet);
break;
case CModInfo::UserModule:
m_pUser->GetModules().ReloadModule(sMod, sArgs, m_pUser,
nullptr, sModRet);
break;
case CModInfo::NetworkModule:
m_pNetwork->GetModules().ReloadModule(sMod, sArgs, m_pUser,
m_pNetwork, sModRet);
break;
default:
sModRet = t_f(
"Unable to reload module {1}: Unknown module type")(sMod);
}
PutStatus(sModRet);
return;
} else if ((sCommand.Equals("UPDATEMOD") ||
sCommand.Equals("UPDATEMODULE")) &&
m_pUser->IsAdmin()) {
CString sMod = sLine.Token(1);
if (sMod.empty()) {
PutStatus(t_s("Usage: UpdateMod <module>"));
return;
}
PutStatus(t_f("Reloading {1} everywhere")(sMod));
if (CZNC::Get().UpdateModule(sMod)) {
PutStatus(t_s("Done"));
} else {
PutStatus(
t_f("Done, but there were errors, module {1} could not be "
"reloaded everywhere.")(sMod));
}
} else if ((sCommand.Equals("SETBINDHOST") ||
sCommand.Equals("SETVHOST")) &&
(m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command. Try "
"SetUserBindHost instead"));
return;
}
CString sArg = sLine.Token(1);
if (sArg.empty()) {
PutStatus(t_s("Usage: SetBindHost <host>"));
return;
}
if (sArg.Equals(m_pNetwork->GetBindHost())) {
PutStatus(t_s("You already have this bind host!"));
return;
}
m_pNetwork->SetBindHost(sArg);
PutStatus(t_f("Set bind host for network {1} to {2}")(
m_pNetwork->GetName(), m_pNetwork->GetBindHost()));
} else if (sCommand.Equals("SETUSERBINDHOST") &&
(m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) {
CString sArg = sLine.Token(1);
if (sArg.empty()) {
PutStatus(t_s("Usage: SetUserBindHost <host>"));
return;
}
if (sArg.Equals(m_pUser->GetBindHost())) {
PutStatus(t_s("You already have this bind host!"));
return;
}
m_pUser->SetBindHost(sArg);
PutStatus(t_f("Set default bind host to {1}")(m_pUser->GetBindHost()));
} else if ((sCommand.Equals("CLEARBINDHOST") ||
sCommand.Equals("CLEARVHOST")) &&
(m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command. Try "
"ClearUserBindHost instead"));
return;
}
m_pNetwork->SetBindHost("");
PutStatus(t_s("Bind host cleared for this network."));
} else if (sCommand.Equals("CLEARUSERBINDHOST") &&
(m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) {
m_pUser->SetBindHost("");
PutStatus(t_s("Default bind host cleared for your user."));
} else if (sCommand.Equals("SHOWBINDHOST")) {
if (m_pUser->GetBindHost().empty()) {
PutStatus(t_s("This user's default bind host not set"));
} else {
PutStatus(t_f("This user's default bind host is {1}")(
m_pUser->GetBindHost()));
}
if (m_pNetwork) {
if (m_pNetwork->GetBindHost().empty()) {
PutStatus(t_s("This network's bind host not set"));
} else {
PutStatus(t_f("This network's default bind host is {1}")(
m_pNetwork->GetBindHost()));
}
}
} else if (sCommand.Equals("PLAYBUFFER")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
CString sBuffer = sLine.Token(1);
if (sBuffer.empty()) {
PutStatus(t_s("Usage: PlayBuffer <#chan|query>"));
return;
}
if (m_pNetwork->IsChan(sBuffer)) {
CChan* pChan = m_pNetwork->FindChan(sBuffer);
if (!pChan) {
PutStatus(t_f("You are not on {1}")(sBuffer));
return;
}
if (!pChan->IsOn()) {
PutStatus(t_f("You are not on {1} (trying to join)")(sBuffer));
return;
}
if (pChan->GetBuffer().IsEmpty()) {
PutStatus(t_f("The buffer for channel {1} is empty")(sBuffer));
return;
}
pChan->SendBuffer(this);
} else {
CQuery* pQuery = m_pNetwork->FindQuery(sBuffer);
if (!pQuery) {
PutStatus(t_f("No active query with {1}")(sBuffer));
return;
}
if (pQuery->GetBuffer().IsEmpty()) {
PutStatus(t_f("The buffer for {1} is empty")(sBuffer));
return;
}
pQuery->SendBuffer(this);
}
} else if (sCommand.Equals("CLEARBUFFER")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
CString sBuffer = sLine.Token(1);
if (sBuffer.empty()) {
PutStatus(t_s("Usage: ClearBuffer <#chan|query>"));
return;
}
unsigned int uMatches = 0;
vector<CChan*> vChans = m_pNetwork->FindChans(sBuffer);
for (CChan* pChan : vChans) {
uMatches++;
pChan->ClearBuffer();
}
vector<CQuery*> vQueries = m_pNetwork->FindQueries(sBuffer);
for (CQuery* pQuery : vQueries) {
uMatches++;
m_pNetwork->DelQuery(pQuery->GetName());
}
PutStatus(t_p("{1} buffer matching {2} has been cleared",
"{1} buffers matching {2} have been cleared",
uMatches)(uMatches, sBuffer));
} else if (sCommand.Equals("CLEARALLCHANNELBUFFERS")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
for (CChan* pChan : m_pNetwork->GetChans()) {
pChan->ClearBuffer();
}
PutStatus(t_s("All channel buffers have been cleared"));
} else if (sCommand.Equals("CLEARALLQUERYBUFFERS")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
m_pNetwork->ClearQueryBuffer();
PutStatus(t_s("All query buffers have been cleared"));
} else if (sCommand.Equals("CLEARALLBUFFERS")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
for (CChan* pChan : m_pNetwork->GetChans()) {
pChan->ClearBuffer();
}
m_pNetwork->ClearQueryBuffer();
PutStatus(t_s("All buffers have been cleared"));
} else if (sCommand.Equals("SETBUFFER")) {
if (!m_pNetwork) {
PutStatus(t_s(
"You must be connected with a network to use this command"));
return;
}
CString sBuffer = sLine.Token(1);
if (sBuffer.empty()) {
PutStatus(t_s("Usage: SetBuffer <#chan|query> [linecount]"));
return;
}
unsigned int uLineCount = sLine.Token(2).ToUInt();
unsigned int uMatches = 0, uFail = 0;
vector<CChan*> vChans = m_pNetwork->FindChans(sBuffer);
for (CChan* pChan : vChans) {
uMatches++;
if (!pChan->SetBufferCount(uLineCount)) uFail++;
}
vector<CQuery*> vQueries = m_pNetwork->FindQueries(sBuffer);
for (CQuery* pQuery : vQueries) {
uMatches++;
if (!pQuery->SetBufferCount(uLineCount)) uFail++;
}
if (uFail > 0) {
PutStatus(t_p("Setting buffer size failed for {1} buffer",
"Setting buffer size failed for {1} buffers",
uFail)(uFail));
PutStatus(t_p("Maximum buffer size is {1} line",
"Maximum buffer size is {1} lines",
CZNC::Get().GetMaxBufferSize())(
CZNC::Get().GetMaxBufferSize()));
} else {
PutStatus(t_p("Size of every buffer was set to {1} line",
"Size of every buffer was set to {1} lines",
uLineCount)(uLineCount));
}
} else if (m_pUser->IsAdmin() && sCommand.Equals("TRAFFIC")) {
CZNC::TrafficStatsPair Users, ZNC, Total;
CZNC::TrafficStatsMap traffic =
CZNC::Get().GetTrafficStats(Users, ZNC, Total);
CTable Table;
Table.AddColumn(t_s("Username", "trafficcmd"));
Table.AddColumn(t_s("In", "trafficcmd"));
Table.AddColumn(t_s("Out", "trafficcmd"));
Table.AddColumn(t_s("Total", "trafficcmd"));
for (const auto& it : traffic) {
Table.AddRow();
Table.SetCell(t_s("Username", "trafficcmd"), it.first);
Table.SetCell(t_s("In", "trafficcmd"),
CString::ToByteStr(it.second.first));
Table.SetCell(t_s("Out", "trafficcmd"),
CString::ToByteStr(it.second.second));
Table.SetCell(
t_s("Total", "trafficcmd"),
CString::ToByteStr(it.second.first + it.second.second));
}
Table.AddRow();
Table.SetCell(t_s("Username", "trafficcmd"),
t_s("<Users>", "trafficcmd"));
Table.SetCell(t_s("In", "trafficcmd"), CString::ToByteStr(Users.first));
Table.SetCell(t_s("Out", "trafficcmd"),
CString::ToByteStr(Users.second));
Table.SetCell(t_s("Total", "trafficcmd"),
CString::ToByteStr(Users.first + Users.second));
Table.AddRow();
Table.SetCell(t_s("Username", "trafficcmd"),
t_s("<ZNC>", "trafficcmd"));
Table.SetCell(t_s("In", "trafficcmd"), CString::ToByteStr(ZNC.first));
Table.SetCell(t_s("Out", "trafficcmd"), CString::ToByteStr(ZNC.second));
Table.SetCell(t_s("Total", "trafficcmd"),
CString::ToByteStr(ZNC.first + ZNC.second));
Table.AddRow();
Table.SetCell(t_s("Username", "trafficcmd"),
t_s("<Total>", "trafficcmd"));
Table.SetCell(t_s("In", "trafficcmd"), CString::ToByteStr(Total.first));
Table.SetCell(t_s("Out", "trafficcmd"),
CString::ToByteStr(Total.second));
Table.SetCell(t_s("Total", "trafficcmd"),
CString::ToByteStr(Total.first + Total.second));
PutStatus(Table);
} else if (sCommand.Equals("UPTIME")) {
PutStatus(t_f("Running for {1}")(CZNC::Get().GetUptime()));
} else if (m_pUser->IsAdmin() &&
(sCommand.Equals("LISTPORTS") || sCommand.Equals("ADDPORT") ||
sCommand.Equals("DELPORT"))) {
UserPortCommand(sLine);
} else {
PutStatus(t_s("Unknown command, try 'Help'"));
}
}
void CClient::UserPortCommand(CString& sLine) {
const CString sCommand = sLine.Token(0);
if (sCommand.Equals("LISTPORTS")) {
CTable Table;
Table.AddColumn(t_s("Port", "listports"));
Table.AddColumn(t_s("BindHost", "listports"));
Table.AddColumn(t_s("SSL", "listports"));
Table.AddColumn(t_s("Protocol", "listports"));
Table.AddColumn(t_s("IRC", "listports"));
Table.AddColumn(t_s("Web", "listports"));
const vector<CListener*>& vpListeners = CZNC::Get().GetListeners();
for (const CListener* pListener : vpListeners) {
Table.AddRow();
Table.SetCell(t_s("Port", "listports"), CString(pListener->GetPort()));
Table.SetCell(t_s("BindHost", "listports"), (pListener->GetBindHost().empty()
? CString("*")
: pListener->GetBindHost()));
Table.SetCell(t_s("SSL", "listports"),
pListener->IsSSL() ? t_s("yes", "listports|ssl")
: t_s("no", "listports|ssl"));
EAddrType eAddr = pListener->GetAddrType();
Table.SetCell(t_s("Protocol", "listports"),
eAddr == ADDR_ALL ? t_s("IPv4 and IPv6", "listports")
: (eAddr == ADDR_IPV4ONLY
? t_s("IPv4", "listports")
: t_s("IPv6", "listports")));
CListener::EAcceptType eAccept = pListener->GetAcceptType();
Table.SetCell(t_s("IRC", "listports"),
eAccept == CListener::ACCEPT_ALL ||
eAccept == CListener::ACCEPT_IRC
? t_s("yes", "listports|irc")
: t_s("no", "listports|irc"));
Table.SetCell(t_s("Web", "listports"),
eAccept == CListener::ACCEPT_ALL ||
eAccept == CListener::ACCEPT_HTTP
? t_f("yes, on {1}", "listports|irc")(
pListener->GetURIPrefix() + "/")
: t_s("no", "listports|web"));
}
PutStatus(Table);
return;
}
CString sPort = sLine.Token(1);
CString sAddr = sLine.Token(2);
EAddrType eAddr = ADDR_ALL;
if (sAddr.Equals("IPV4")) {
eAddr = ADDR_IPV4ONLY;
} else if (sAddr.Equals("IPV6")) {
eAddr = ADDR_IPV6ONLY;
} else if (sAddr.Equals("ALL")) {
eAddr = ADDR_ALL;
} else {
sAddr.clear();
}
unsigned short uPort = sPort.ToUShort();
if (sCommand.Equals("ADDPORT")) {
CListener::EAcceptType eAccept = CListener::ACCEPT_ALL;
CString sAccept = sLine.Token(3);
if (sAccept.Equals("WEB")) {
eAccept = CListener::ACCEPT_HTTP;
} else if (sAccept.Equals("IRC")) {
eAccept = CListener::ACCEPT_IRC;
} else if (sAccept.Equals("ALL")) {
eAccept = CListener::ACCEPT_ALL;
} else {
sAccept.clear();
}
if (sPort.empty() || sAddr.empty() || sAccept.empty()) {
PutStatus(
t_s("Usage: AddPort <[+]port> <ipv4|ipv6|all> <web|irc|all> "
"[bindhost [uriprefix]]"));
} else {
bool bSSL = (sPort.StartsWith("+"));
const CString sBindHost = sLine.Token(4);
const CString sURIPrefix = sLine.Token(5);
CListener* pListener = new CListener(uPort, sBindHost, sURIPrefix,
bSSL, eAddr, eAccept);
if (!pListener->Listen()) {
auto e = errno;
delete pListener;
PutStatus(t_f("Unable to bind: {1}")(CString(strerror(e))));
} else {
if (CZNC::Get().AddListener(pListener)) {
PutStatus(t_s("Port added"));
} else {
PutStatus(t_s("Couldn't add port"));
}
}
}
} else if (sCommand.Equals("DELPORT")) {
if (sPort.empty() || sAddr.empty()) {
PutStatus(t_s("Usage: DelPort <port> <ipv4|ipv6|all> [bindhost]"));
} else {
const CString sBindHost = sLine.Token(3);
CListener* pListener =
CZNC::Get().FindListener(uPort, sBindHost, eAddr);
if (pListener) {
CZNC::Get().DelListener(pListener);
PutStatus(t_s("Deleted Port"));
} else {
PutStatus(t_s("Unable to find a matching port"));
}
}
}
}
static void AddCommandHelp(CTable& Table, const CString& sCmd,
const CString& sArgs, const CString& sDesc,
const CString& sFilter = "") {
if (sFilter.empty() || sCmd.StartsWith(sFilter) ||
sCmd.AsLower().WildCmp(sFilter.AsLower())) {
Table.AddRow();
Table.SetCell("Command", sCmd + " " + sArgs);
Table.SetCell("Description", sDesc);
}
}
void CClient::HelpUser(const CString& sFilter) {
CTable Table;
Table.AddColumn("Command");
Table.AddColumn("Description");
if (sFilter.empty()) {
PutStatus(
"In the following list all occurrences of <#chan> support "
"wildcards (* and ?)");
PutStatus("(Except ListNicks)");
}
AddCommandHelp(Table, "Version", "", "Print which version of ZNC this is",
sFilter);
AddCommandHelp(Table, "ListMods", "", "List all loaded modules", sFilter);
AddCommandHelp(Table, "ListAvailMods", "", "List all available modules",
sFilter);
if (!m_pUser->IsAdmin()) {
// If they are an admin we will add this command below with an argument
AddCommandHelp(Table, "ListChans", "", "List all channels", sFilter);
}
AddCommandHelp(Table, "ListNicks", "<#chan>", "List all nicks on a channel",
sFilter);
if (!m_pUser->IsAdmin()) {
AddCommandHelp(Table, "ListClients", "",
"List all clients connected to your ZNC user", sFilter);
}
AddCommandHelp(Table, "ListServers", "",
"List all servers of current IRC network", sFilter);
AddCommandHelp(Table, "AddNetwork", "<name>", "Add a network to your user",
sFilter);
AddCommandHelp(Table, "DelNetwork", "<name>",
"Delete a network from your user", sFilter);
AddCommandHelp(Table, "ListNetworks", "", "List all networks", sFilter);
if (m_pUser->IsAdmin()) {
AddCommandHelp(Table, "MoveNetwork",
"<old user> <old network> <new user> [new network]",
"Move an IRC network from one user to another", sFilter);
}
AddCommandHelp(Table, "JumpNetwork", "<network>",
"Jump to another network (Alternatively, you can connect to "
"ZNC several times, using `user/network` as username)",
sFilter);
AddCommandHelp(Table, "AddServer", "<host> [[+]port] [pass]",
"Add a server to the list of alternate/backup servers of "
"current IRC network.",
sFilter);
AddCommandHelp(Table, "DelServer", "<host> [port] [pass]",
"Remove a server from the list of alternate/backup servers "
"of current IRC network",
sFilter);
AddCommandHelp(Table, "AddTrustedServerFingerprint", "<fi:ng:er>",
"Add a trusted server SSL certificate fingerprint (SHA-256) "
"to current IRC network.",
sFilter);
AddCommandHelp(
Table, "DelTrustedServerFingerprint", "<fi:ng:er>",
"Delete a trusted server SSL certificate from current IRC network.",
sFilter);
AddCommandHelp(
Table, "ListTrustedServerFingerprints", "",
"List all trusted server SSL certificates of current IRC network.",
sFilter);
AddCommandHelp(Table, "EnableChan", "<#chans>", "Enable channels", sFilter);
AddCommandHelp(Table, "DisableChan", "<#chans>", "Disable channels",
sFilter);
AddCommandHelp(Table, "Attach", "<#chans>", "Attach to channels", sFilter);
AddCommandHelp(Table, "Detach", "<#chans>", "Detach from channels",
sFilter);
AddCommandHelp(Table, "Topics", "", "Show topics in all your channels",
sFilter);
AddCommandHelp(Table, "PlayBuffer", "<#chan|query>",
"Play back the specified buffer", sFilter);
AddCommandHelp(Table, "ClearBuffer", "<#chan|query>",
"Clear the specified buffer", sFilter);
AddCommandHelp(Table, "ClearAllBuffers", "",
"Clear all channel and query buffers", sFilter);
AddCommandHelp(Table, "ClearAllChannelBuffers", "",
"Clear the channel buffers", sFilter);
AddCommandHelp(Table, "ClearAllQueryBuffers", "", "Clear the query buffers",
sFilter);
AddCommandHelp(Table, "SetBuffer", "<#chan|query> [linecount]",
"Set the buffer count", sFilter);
if (m_pUser->IsAdmin() || !m_pUser->DenySetBindHost()) {
AddCommandHelp(Table, "SetBindHost", "<host (IP preferred)>",
"Set the bind host for this connection", sFilter);
AddCommandHelp(Table, "SetUserBindHost", "<host (IP preferred)>",
"Set the default bind host for this user", sFilter);
AddCommandHelp(Table, "ClearBindHost", "",
"Clear the bind host for this connection", sFilter);
AddCommandHelp(Table, "ClearUserBindHost", "",
"Clear the default bind host for this user", sFilter);
}
AddCommandHelp(Table, "ShowBindHost", "",
"Show currently selected bind host", sFilter);
AddCommandHelp(Table, "Jump", "[server]",
"Jump to the next or the specified server", sFilter);
AddCommandHelp(Table, "Disconnect", "[message]", "Disconnect from IRC",
sFilter);
AddCommandHelp(Table, "Connect", "", "Reconnect to IRC", sFilter);
AddCommandHelp(Table, "Uptime", "",
"Show for how long ZNC has been running", sFilter);
if (!m_pUser->DenyLoadMod()) {
AddCommandHelp(Table, "LoadMod",
"[--type=global|user|network] <module>", "Load a module",
sFilter);
AddCommandHelp(Table, "UnloadMod",
"[--type=global|user|network] <module>",
"Unload a module", sFilter);
AddCommandHelp(Table, "ReloadMod",
"[--type=global|user|network] <module>",
"Reload a module", sFilter);
if (m_pUser->IsAdmin()) {
AddCommandHelp(Table, "UpdateMod", "<module>",
"Reload a module everywhere", sFilter);
}
}
AddCommandHelp(Table, "ShowMOTD", "", "Show ZNC's message of the day",
sFilter);
if (m_pUser->IsAdmin()) {
AddCommandHelp(Table, "SetMOTD", "<message>",
"Set ZNC's message of the day", sFilter);
AddCommandHelp(Table, "AddMOTD", "<message>",
"Append <message> to ZNC's MOTD", sFilter);
AddCommandHelp(Table, "ClearMOTD", "", "Clear ZNC's MOTD", sFilter);
AddCommandHelp(Table, "ListPorts", "", "Show all active listeners",
sFilter);
AddCommandHelp(
Table, "AddPort",
"<[+]port> <ipv4|ipv6|all> <web|irc|all> [bindhost [uriprefix]]",
"Add another port for ZNC to listen on", sFilter);
AddCommandHelp(Table, "DelPort", "<port> <ipv4|ipv6|all> [bindhost]",
"Remove a port from ZNC", sFilter);
AddCommandHelp(
Table, "Rehash", "",
"Reload global settings, modules, and listeners from znc.conf",
sFilter);
AddCommandHelp(Table, "SaveConfig", "",
"Save the current settings to disk", sFilter);
AddCommandHelp(Table, "ListUsers", "",
"List all ZNC users and their connection status",
sFilter);
AddCommandHelp(Table, "ListAllUserNetworks", "",
"List all ZNC users and their networks", sFilter);
AddCommandHelp(Table, "ListChans", "[user <network>]",
"List all channels", sFilter);
AddCommandHelp(Table, "ListClients", "[user]",
"List all connected clients", sFilter);
AddCommandHelp(Table, "Traffic", "",
"Show basic traffic stats for all ZNC users", sFilter);
AddCommandHelp(Table, "Broadcast", "[message]",
"Broadcast a message to all ZNC users", sFilter);
AddCommandHelp(Table, "Shutdown", "[message]",
"Shut down ZNC completely", sFilter);
AddCommandHelp(Table, "Restart", "[message]", "Restart ZNC", sFilter);
}
if (Table.empty()) {
PutStatus("No matches for '" + sFilter + "'");
} else {
PutStatus(Table);
}
}