void CGameContext::OnClientConnected(int ClientID, bool Dummy) { m_apPlayers[ClientID] = new(ClientID) CPlayer(this, ClientID, Dummy); if(Dummy) return; // send active vote if(m_VoteCloseTime) SendVoteSet(VOTE_UNKNOWN, ClientID); // send motd SendMotd(ClientID); // send settings SendSettings(ClientID); }
void WorldSession::HandlePlayerReconnect() { // stop logout timer if need LogoutRequest(0); // set loading flag m_playerLoading = true; // reset all visible objects to be able to resend them _player->m_clientGUIDs.clear(); SetOnline(); WorldPacket data(SMSG_LOGIN_VERIFY_WORLD, 20); data << _player->GetMapId(); data << _player->GetPositionX(); data << _player->GetPositionY(); data << _player->GetPositionZ(); data << _player->GetOrientation(); SendPacket(data); data.Initialize(SMSG_ACCOUNT_DATA_TIMES, 128); for (int i = 0; i < 32; ++i) data << uint32(0); SendPacket(data); // Send Spam records SendExpectedSpamRecords(); SendMotd(_player); if (_player->GetGuildId() != 0) { Guild* guild = sGuildMgr.GetGuildById(_player->GetGuildId()); if (guild) { data.Initialize(SMSG_GUILD_EVENT, (1 + 1 + guild->GetMOTD().size() + 1)); data << uint8(GE_MOTD); data << uint8(1); data << guild->GetMOTD(); SendPacket(data); DEBUG_LOG("WORLD: Sent guild-motd (SMSG_GUILD_EVENT)"); guild->BroadcastEvent(GE_SIGNED_ON, _player->GetObjectGuid(), _player->GetName()); } else { // remove wrong guild data sLog.outError("Player %s (GUID: %u) marked as member of nonexistent guild (id: %u), removing guild membership for player.", _player->GetName(), _player->GetGUIDLow(), _player->GetGuildId()); _player->SetInGuild(0); } } if (!_player->isAlive()) _player->SendCorpseReclaimDelay(true); _player->SendInitialPacketsBeforeAddToMap(); _player->GetMap()->CreatePlayerOnClient(_player); _player->GetSocial()->SendFriendList(); _player->GetSocial()->SendIgnoreList(); _player->SendInitWorldStates(_player->GetZoneId()); _player->CastSpell(_player, 836, TRIGGERED_OLD_TRIGGERED); // LOGINEFFECT _player->SendEnchantmentDurations(); // must be after add to map _player->SendItemDurations(); // must be after add to map // announce group about member online (must be after add to player list to receive announce to self) if (Group* group = _player->GetGroup()) group->UpdatePlayerOnlineStatus(_player); // friend status sSocialMgr.SendFriendStatus(_player, FRIEND_ONLINE, _player->GetObjectGuid(), true); // show time before shutdown if shutdown planned. if (sWorld.IsShutdowning()) sWorld.ShutdownMsg(true, _player); if (sWorld.getConfig(CONFIG_BOOL_ALL_TAXI_PATHS)) _player->SetTaxiCheater(true); if (_player->isGameMaster()) SendNotification(LANG_GM_ON); std::string IP_str = GetRemoteAddress(); sLog.outChar("Account: %d (IP: %s) Login Character:[%s] (guid: %u)", GetAccountId(), IP_str.c_str(), _player->GetName(), _player->GetGUIDLow()); // sync client auras timer _player->UpdateClientAuras(); // sync client control (if taxi flying the client is already sync) if (_player->IsTaxiFlying()) _player->TaxiFlightResume(true); else if (!_player->IsClientControlled(_player)) _player->UpdateClientControl(_player, false); // initialize client pet bar if need _player->SendPetBar(); // send mirror timers _player->SendMirrorTimers(true); m_playerLoading = false; }
void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) { ObjectGuid playerGuid = holder->GetGuid(); Player* pCurrChar = new Player(this); pCurrChar->GetMotionMaster()->Initialize(); SetPlayer(pCurrChar); m_playerLoading = true; SetOnline(); // "GetAccountId()==db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools) if (!pCurrChar->LoadFromDB(playerGuid, holder)) { KickPlayer(); // disconnect client, player no set to session and it will not deleted or saved at kick delete pCurrChar; // delete it manually delete holder; // delete all unprocessed queries m_playerLoading = false; sLog.outError("HandlePlayerLogin> LoadFromDB failed to load %s, AccountId = %u", pCurrChar->GetGuidStr().c_str(), GetAccountId()); WorldPacket data(SMSG_CHARACTER_LOGIN_FAILED, 1); data << (uint8)CHAR_LOGIN_NO_CHARACTER; SendPacket(data, true); return; } WorldPacket data(SMSG_LOGIN_VERIFY_WORLD, 20); data << pCurrChar->GetMapId(); data << pCurrChar->GetPositionX(); data << pCurrChar->GetPositionY(); data << pCurrChar->GetPositionZ(); data << pCurrChar->GetOrientation(); SendPacket(data); data.Initialize(SMSG_ACCOUNT_DATA_TIMES, 128); for (int i = 0; i < 32; ++i) data << uint32(0); SendPacket(data); // Send Spam records SendExpectedSpamRecords(); SendMotd(pCurrChar); // QueryResult *result = CharacterDatabase.PQuery("SELECT guildid,rank FROM guild_member WHERE guid = '%u'",pCurrChar->GetGUIDLow()); QueryResult* resultGuild = holder->GetResult(PLAYER_LOGIN_QUERY_LOADGUILD); if (resultGuild) { Field* fields = resultGuild->Fetch(); pCurrChar->SetInGuild(fields[0].GetUInt32()); pCurrChar->SetRank(fields[1].GetUInt32()); delete resultGuild; } else if (pCurrChar->GetGuildId()) // clear guild related fields in case wrong data about nonexistent membership { pCurrChar->SetInGuild(0); pCurrChar->SetRank(0); } if (pCurrChar->GetGuildId() != 0) { Guild* guild = sGuildMgr.GetGuildById(pCurrChar->GetGuildId()); if (guild) { data.Initialize(SMSG_GUILD_EVENT, (1 + 1 + guild->GetMOTD().size() + 1)); data << uint8(GE_MOTD); data << uint8(1); data << guild->GetMOTD(); SendPacket(data); DEBUG_LOG("WORLD: Sent guild-motd (SMSG_GUILD_EVENT)"); guild->BroadcastEvent(GE_SIGNED_ON, pCurrChar->GetObjectGuid(), pCurrChar->GetName()); } else { // remove wrong guild data sLog.outError("Player %s (GUID: %u) marked as member of nonexistent guild (id: %u), removing guild membership for player.", pCurrChar->GetName(), pCurrChar->GetGUIDLow(), pCurrChar->GetGuildId()); pCurrChar->SetInGuild(0); } } if (!pCurrChar->isAlive()) pCurrChar->SendCorpseReclaimDelay(true); pCurrChar->SendInitialPacketsBeforeAddToMap(); // Show cinematic at the first time that player login if (!pCurrChar->getCinematic()) { pCurrChar->setCinematic(1); if (ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(pCurrChar->getRace())) pCurrChar->SendCinematicStart(rEntry->CinematicSequence); } uint32 miscRequirement = 0; AreaLockStatus lockStatus = AREA_LOCKSTATUS_OK; if (AreaTrigger const* at = sObjectMgr.GetMapEntranceTrigger(pCurrChar->GetMapId())) lockStatus = pCurrChar->GetAreaTriggerLockStatus(at, miscRequirement); else { // Some basic checks in case of a map without areatrigger MapEntry const* mapEntry = sMapStore.LookupEntry(pCurrChar->GetMapId()); if (!mapEntry) lockStatus = AREA_LOCKSTATUS_UNKNOWN_ERROR; } if (lockStatus != AREA_LOCKSTATUS_OK || !pCurrChar->GetMap()->Add(pCurrChar)) { // normal delayed teleport protection not applied (and this correct) for this case (Player object just created) AreaTrigger const* at = sObjectMgr.GetGoBackTrigger(pCurrChar->GetMapId()); if (at) lockStatus = pCurrChar->GetAreaTriggerLockStatus(at, miscRequirement); if (!at || lockStatus != AREA_LOCKSTATUS_OK || !pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation())) pCurrChar->TeleportToHomebind(); } sObjectAccessor.AddObject(pCurrChar); // DEBUG_LOG("Player %s added to Map.",pCurrChar->GetName()); pCurrChar->GetSocial()->SendFriendList(); pCurrChar->GetSocial()->SendIgnoreList(); pCurrChar->SendInitialPacketsAfterAddToMap(); static SqlStatementID updChars; static SqlStatementID updAccount; SqlStatement stmt = CharacterDatabase.CreateStatement(updChars, "UPDATE characters SET online = 1 WHERE guid = ?"); stmt.PExecute(pCurrChar->GetGUIDLow()); stmt = LoginDatabase.CreateStatement(updAccount, "UPDATE account SET active_realm_id = ? WHERE id = ?"); stmt.PExecute(realmID, GetAccountId()); pCurrChar->SetInGameTime(WorldTimer::getMSTime()); // announce group about member online (must be after add to player list to receive announce to self) if (Group* group = pCurrChar->GetGroup()) group->UpdatePlayerOnlineStatus(pCurrChar); // friend status sSocialMgr.SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetObjectGuid(), true); // Place character in world (and load zone) before some object loading pCurrChar->LoadCorpse(); // setting Ghost+speed if dead if (pCurrChar->m_deathState != ALIVE) { // not blizz like, we must correctly save and load player instead... if (pCurrChar->getRace() == RACE_NIGHTELF) pCurrChar->CastSpell(pCurrChar, 20584, TRIGGERED_OLD_TRIGGERED); // auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form) pCurrChar->CastSpell(pCurrChar, 8326, TRIGGERED_OLD_TRIGGERED); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?) pCurrChar->SetWaterWalk(true); } pCurrChar->TaxiFlightResume(); // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned) pCurrChar->LoadPet(); // Set FFA PvP for non GM in non-rest mode if (sWorld.IsFFAPvPRealm() && !pCurrChar->isGameMaster() && !pCurrChar->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING)) pCurrChar->SetPvPFreeForAll(true); if (pCurrChar->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP)) pCurrChar->UpdatePvPContested(true); // Apply at_login requests if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_SPELLS)) { pCurrChar->resetSpells(); SendNotification(LANG_RESET_SPELLS); } if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS)) { pCurrChar->resetTalents(true); SendNotification(LANG_RESET_TALENTS); // we can use SMSG_TALENTS_INVOLUNTARILY_RESET here } if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TAXINODES)) { pCurrChar->InitTaxiNodes(); pCurrChar->RemoveAtLoginFlag(AT_LOGIN_RESET_TAXINODES, true); SendNotification("Your taxi nodes have been reset."); } if (pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST)) pCurrChar->RemoveAtLoginFlag(AT_LOGIN_FIRST); // show time before shutdown if shutdown planned. if (sWorld.IsShutdowning()) sWorld.ShutdownMsg(true, pCurrChar); if (sWorld.getConfig(CONFIG_BOOL_ALL_TAXI_PATHS)) pCurrChar->SetTaxiCheater(true); if (pCurrChar->isGameMaster()) SendNotification(LANG_GM_ON); if (!pCurrChar->isGMVisible()) { SendNotification(LANG_INVISIBLE_INVISIBLE); SpellEntry const* invisibleAuraInfo = sSpellTemplate.LookupEntry<SpellEntry>(sWorld.getConfig(CONFIG_UINT32_GM_INVISIBLE_AURA)); if (invisibleAuraInfo && IsSpellAppliesAura(invisibleAuraInfo)) pCurrChar->CastSpell(pCurrChar, invisibleAuraInfo, TRIGGERED_OLD_TRIGGERED); } std::string IP_str = GetRemoteAddress(); sLog.outChar("Account: %d (IP: %s) Login Character:[%s] (guid: %u)", GetAccountId(), IP_str.c_str(), pCurrChar->GetName(), pCurrChar->GetGUIDLow()); if (!pCurrChar->IsStandState() && !pCurrChar->hasUnitState(UNIT_STAT_STUNNED)) pCurrChar->SetStandState(UNIT_STAND_STATE_STAND); m_playerLoading = false; delete holder; }
void CClient::UserCommand(CString& sLine) { if (!m_pUser) { return; } if (sLine.empty()) { return; } NETWORKMODULECALL(OnStatusCommand(sLine), m_pUser, m_pNetwork, this, return); const CString sCommand = sLine.Token(0); if (sCommand.Equals("HELP")) { HelpUser(); } else if (sCommand.Equals("LISTNICKS")) { if (!m_pNetwork) { PutStatus("You must be connected with a network to use this command"); return; } CString sChan = sLine.Token(1); if (sChan.empty()) { PutStatus("Usage: ListNicks <#chan>"); return; } CChan* pChan = m_pNetwork->FindChan(sChan); if (!pChan) { PutStatus("You are not on [" + sChan + "]"); return; } if (!pChan->IsOn()) { PutStatus("You are not on [" + sChan + "] [trying]"); return; } const map<CString,CNick>& msNicks = pChan->GetNicks(); CIRCSock* pIRCSock = m_pNetwork->GetIRCSock(); const CString& sPerms = (pIRCSock) ? pIRCSock->GetPerms() : ""; if (!msNicks.size()) { PutStatus("No nicks on [" + sChan + "]"); return; } CTable Table; 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<CString,CNick>::const_iterator a = msNicks.begin(); a != msNicks.end(); ++a) { Table.AddRow(); 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()); } PutStatus(Table); } else if (sCommand.Equals("DETACH")) { if (!m_pNetwork) { PutStatus("You must be connected with a network to use this command"); return; } CString sChan = sLine.Token(1); if (sChan.empty()) { PutStatus("Usage: Detach <#chan>"); return; } const vector<CChan*>& vChans = m_pNetwork->GetChans(); vector<CChan*>::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("There were [" + CString(uMatches) + "] channels matching [" + sChan + "]"); PutStatus("Detached [" + CString(uDetached) + "] channels"); } else if (sCommand.Equals("VERSION")) { PutStatus(CZNC::GetTag()); PutStatus(CZNC::GetCompileOptionsString()); } else if (sCommand.Equals("MOTD") || sCommand.Equals("ShowMOTD")) { if (!SendMotd()) { PutStatus("There is no MOTD set."); } } else if (m_pUser->IsAdmin() && sCommand.Equals("Rehash")) { CString sRet; if (CZNC::Get().RehashConfig(sRet)) { PutStatus("Rehashing succeeded!"); } else { PutStatus("Rehashing failed: " + sRet); } } else if (m_pUser->IsAdmin() && sCommand.Equals("SaveConfig")) { if (CZNC::Get().WriteConfig()) { PutStatus("Wrote config to [" + CZNC::Get().GetConfigFile() + "]"); } else { PutStatus("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"); for (unsigned int a = 0; a < vClients.size(); a++) { Table.AddRow(); Table.SetCell("Host", vClients[a]->GetRemoteIP()); if (vClients[a]->GetNetwork()) { Table.SetCell("Network", vClients[a]->GetNetwork()->GetName()); } } 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 (map<CString, CUser*>::const_iterator it = msUsers.begin(); it != msUsers.end(); ++it) { 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("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); CServer *pServer = NULL; 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 (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 sChan = sLine.Token(1, true); if (sChan.empty()) { PutStatus("Usage: EnableChan <channel>"); } else { const vector<CChan*>& vChans = m_pNetwork->GetChans(); vector<CChan*>::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(); } PutStatus("There were [" + CString(uMatches) + "] channels matching [" + sChan + "]"); PutStatus("Enabled [" + CString(uEnabled) + "] channels"); } } else if (sCommand.Equals("LISTCHANS")) { if (!m_pNetwork) { PutStatus("You must be connected with a network to use this command"); return; } CUser* pUser = m_pUser; CIRCNetwork* pNetwork = m_pNetwork; const CString sNick = sLine.Token(1); const CString sNetwork = sLine.Token(2); if (!sNick.empty()) { if (!m_pUser->IsAdmin()) { PutStatus("Usage: ListChans"); return; } pUser = CZNC::Get().FindUser(sNick); if (!pUser) { PutStatus("No such user [" + sNick + "]"); return; } pNetwork = pUser->FindNetwork(sNetwork); if (!pNetwork) { PutStatus("No such network for user [" + sNetwork + "]"); return; } } const vector<CChan*>& vChans = pNetwork->GetChans(); CIRCSock* pIRCSock = pNetwork->GetIRCSock(); const CString& sPerms = (pIRCSock) ? pIRCSock->GetPerms() : ""; if (!vChans.size()) { PutStatus("There are no channels defined."); return; } CTable Table; Table.AddColumn("Name"); Table.AddColumn("Status"); Table.AddColumn("Conf"); Table.AddColumn("Buf"); Table.AddColumn("Modes"); Table.AddColumn("Users"); for (unsigned int p = 0; p < sPerms.size(); p++) { CString sPerm; sPerm += sPerms[p]; Table.AddColumn(sPerm); } unsigned int uNumDetached = 0, uNumDisabled = 0, uNumJoined = 0; for (unsigned int a = 0; a < vChans.size(); a++) { const CChan* pChan = vChans[a]; Table.AddRow(); Table.SetCell("Name", pChan->GetPermStr() + pChan->GetName()); Table.SetCell("Status", ((vChans[a]->IsOn()) ? ((vChans[a]->IsDetached()) ? "Detached" : "Joined") : ((vChans[a]->IsDisabled()) ? "Disabled" : "Trying"))); Table.SetCell("Conf", CString((pChan->InConfig()) ? "yes" : "")); Table.SetCell("Buf", CString((pChan->KeepBuffer()) ? "*" : "") + CString(pChan->GetBufferCount())); Table.SetCell("Modes", pChan->GetModeString()); Table.SetCell("Users", CString(pChan->GetNickCount())); map<char, unsigned int> mPerms = pChan->GetPermCounts(); for (unsigned int b = 0; b < sPerms.size(); b++) { char cPerm = sPerms[b]; Table.SetCell(CString(cPerm), CString(mPerms[cPerm])); } if(pChan->IsDetached()) uNumDetached++; if(pChan->IsOn()) uNumJoined++; if(pChan->IsDisabled()) uNumDisabled++; } PutStatus(Table); PutStatus("Total: " + CString(vChans.size()) + " - Joined: " + CString(uNumJoined) + " - Detached: " + CString(uNumDetached) + " - Disabled: " + CString(uNumDisabled)); } else if (sCommand.Equals("ADDNETWORK")) { #ifndef ENABLE_ADD_NETWORK if (!m_pUser->IsAdmin()) { PutStatus("Permission denied"); return; } #endif CString sNetwork = sLine.Token(1); if (sNetwork.empty()) { PutStatus("Usage: AddNetwork <name>"); return; } if (m_pUser->AddNetwork(sNetwork)) { PutStatus("Network added. Use /znc JumpNetwork " + sNetwork + ", or connect to ZNC with username " + m_pUser->GetUserName() + "/" + sNetwork + " (instead of just " + m_pUser->GetUserName() + ") to connect to it."); } else { PutStatus("Unable to add that network"); PutStatus("Perhaps that network is already added"); } } else if (m_pUser->IsAdmin() && sCommand.Equals("DELNETWORK")) { CString sNetwork = sLine.Token(1); if (sNetwork.empty()) { PutStatus("Usage: DelNetwork <name>"); return; } if (m_pNetwork && m_pNetwork->GetName().Equals(sNetwork)) { SetNetwork(NULL); } if (m_pUser->DeleteNetwork(sNetwork)) { PutStatus("Network deleted"); } else { PutStatus("Failed to delete network"); PutStatus("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("User not found " + sLine.Token(1)); return; } } const vector<CIRCNetwork*>& vNetworks = pUser->GetNetworks(); CTable Table; Table.AddColumn("Network"); Table.AddColumn("OnIRC"); Table.AddColumn("IRC Server"); Table.AddColumn("IRC User"); Table.AddColumn("Channels"); for (unsigned int a = 0; a < vNetworks.size(); a++) { CIRCNetwork* pNetwork = vNetworks[a]; Table.AddRow(); Table.SetCell("Network", pNetwork->GetName()); 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"); } } if (PutStatus(Table) == 0) { PutStatus("No networks"); } } else if (sCommand.Equals("JUMPNETWORK")) { CString sNetwork = sLine.Token(1); if (sNetwork.empty()) { PutStatus("No network supplied."); return; } if (m_pNetwork && (m_pNetwork->GetName() == sNetwork)) { PutStatus("You are already connected with this network."); return; } CIRCNetwork *pNetwork = m_pUser->FindNetwork(sNetwork); if (pNetwork) { PutStatus("Switched to " + sNetwork); SetNetwork(pNetwork); } else { PutStatus("You don't have a network named " + sNetwork); } } else if (sCommand.Equals("MODE")) { CString sNetwork = sLine.Token(1); if (sNetwork.empty()) { PutStatus("Syntax: MODE <support/default>"); return; } if (m_pNetwork && (m_pNetwork->GetName() == sNetwork)) { PutStatus("You are already in this mode."); return; } CIRCNetwork *pNetwork = m_pUser->FindNetwork(sNetwork); if (pNetwork) { PutStatus("You are now in " + sNetwork + " mode."); SetNetwork(pNetwork); } else { PutStatus("ERROR! Contact GeekBouncer admins immediately"); } } else if (m_pUser->IsAdmin() && sCommand.Equals("ADDSERVER")) { CString sServer = sLine.Token(1); if (!m_pNetwork) { PutStatus("You must be connected with a network to use this command"); return; } if (sServer.empty()) { PutStatus("Usage: AddServer <host> [[+]port] [pass]"); return; } if (m_pNetwork->AddServer(sLine.Token(1, true))) { PutStatus("Server added"); } else { PutStatus("Unable to add that server"); PutStatus("Perhaps the server is already added or openssl is disabled?"); } } else if (m_pUser->IsAdmin() && sCommand.Equals("REMSERVER") || sCommand.Equals("DELSERVER")) { if (!m_pNetwork) { PutStatus("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("Usage: RemServer <host> [port] [pass]"); return; } if (!m_pNetwork->HasServers()) { PutStatus("You don't have any servers added."); return; } if (m_pNetwork->DelServer(sServer, uPort, sPass)) { PutStatus("Server removed"); } else { PutStatus("No such server"); } } else if (sCommand.Equals("LISTSERVERS")) { if (!m_pNetwork) { PutStatus("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("Host"); Table.AddColumn("Port"); Table.AddColumn("SSL"); Table.AddColumn("Pass"); for (unsigned int a = 0; a < vServers.size(); a++) { CServer* pServer = vServers[a]; Table.AddRow(); Table.SetCell("Host", pServer->GetName() + (pServer == pCurServ ? "*" : "")); Table.SetCell("Port", CString(pServer->GetPort())); Table.SetCell("SSL", (pServer->IsSSL()) ? "SSL" : ""); Table.SetCell("Pass", pServer->GetPass()); } PutStatus(Table); } else { PutStatus("You don't have any servers added."); } } else if (sCommand.Equals("TOPICS")) { if (!m_pNetwork) { PutStatus("You must be connected with a network to use this command"); return; } const vector<CChan*>& vChans = m_pNetwork->GetChans(); CTable Table; Table.AddColumn("Name"); Table.AddColumn("Set By"); Table.AddColumn("Topic"); for (unsigned int a = 0; a < vChans.size(); a++) { CChan* pChan = vChans[a]; Table.AddRow(); Table.SetCell("Name", pChan->GetName()); Table.SetCell("Set By", pChan->GetTopicOwner()); Table.SetCell("Topic", pChan->GetTopic()); } PutStatus(Table); } else if (sCommand.Equals("LISTMODS") || sCommand.Equals("LISTMODULES")) { if (m_pUser->IsAdmin()) { CModules& GModules = CZNC::Get().GetModules(); if (!GModules.size()) { PutStatus("No global modules loaded."); } else { PutStatus("Global modules:"); CTable GTable; GTable.AddColumn("Name"); GTable.AddColumn("Arguments"); for (unsigned int b = 0; b < GModules.size(); b++) { GTable.AddRow(); GTable.SetCell("Name", GModules[b]->GetModName()); GTable.SetCell("Arguments", GModules[b]->GetArgs()); } PutStatus(GTable); } } CModules& Modules = m_pUser->GetModules(); if (!Modules.size()) { PutStatus("Your user has no modules loaded."); } else { PutStatus("User modules:"); CTable Table; Table.AddColumn("Name"); Table.AddColumn("Arguments"); for (unsigned int b = 0; b < Modules.size(); b++) { Table.AddRow(); Table.SetCell("Name", Modules[b]->GetModName()); Table.SetCell("Arguments", Modules[b]->GetArgs()); } PutStatus(Table); } if (m_pNetwork) { CModules& NetworkModules = m_pNetwork->GetModules(); if (NetworkModules.empty()) { PutStatus("This network has no modules loaded."); } else { PutStatus("Network modules:"); CTable Table; Table.AddColumn("Name"); Table.AddColumn("Arguments"); for (unsigned int b = 0; b < NetworkModules.size(); b++) { Table.AddRow(); Table.SetCell("Name", NetworkModules[b]->GetModName()); Table.SetCell("Arguments", NetworkModules[b]->GetArgs()); } PutStatus(Table); } } return; } else if (sCommand.Equals("LISTAVAILMODS") || sCommand.Equals("LISTAVAILABLEMODULES")) { if (m_pUser->DenyLoadMod()) { PutStatus("Access Denied."); return; } if (m_pUser->IsAdmin()) { set<CModInfo> ssGlobalMods; CZNC::Get().GetModules().GetAvailableMods(ssGlobalMods, CModInfo::GlobalModule); if (ssGlobalMods.empty()) { PutStatus("No global modules available."); } else { PutStatus("Global modules:"); CTable GTable; GTable.AddColumn("Name"); GTable.AddColumn("Description"); set<CModInfo>::iterator it; for (it = ssGlobalMods.begin(); it != ssGlobalMods.end(); ++it) { const CModInfo& Info = *it; GTable.AddRow(); GTable.SetCell("Name", (CZNC::Get().GetModules().FindModule(Info.GetName()) ? "*" : " ") + Info.GetName()); GTable.SetCell("Description", Info.GetDescription().Ellipsize(128)); } PutStatus(GTable); } } set<CModInfo> ssUserMods; CZNC::Get().GetModules().GetAvailableMods(ssUserMods); if (!ssUserMods.size()) { PutStatus("No user modules available."); } else { PutStatus("User modules:"); CTable Table; Table.AddColumn("Name"); Table.AddColumn("Description"); set<CModInfo>::iterator it; for (it = ssUserMods.begin(); it != ssUserMods.end(); ++it) { const CModInfo& Info = *it; Table.AddRow(); Table.SetCell("Name", (m_pUser->GetModules().FindModule(Info.GetName()) ? "*" : " ") + Info.GetName()); Table.SetCell("Description", Info.GetDescription().Ellipsize(128)); } PutStatus(Table); } set<CModInfo> ssNetworkMods; CZNC::Get().GetModules().GetAvailableMods(ssNetworkMods, CModInfo::NetworkModule); if (!ssNetworkMods.size()) { PutStatus("No network modules available."); } else { PutStatus("Network modules:"); CTable Table; Table.AddColumn("Name"); Table.AddColumn("Description"); set<CModInfo>::const_iterator it; for (it = ssNetworkMods.begin(); it != ssNetworkMods.end(); ++it) { const CModInfo& Info = *it; Table.AddRow(); Table.SetCell("Name", ((m_pNetwork && m_pNetwork->GetModules().FindModule(Info.GetName())) ? "*" : " ") + Info.GetName()); Table.SetCell("Description", Info.GetDescription().Ellipsize(128)); } PutStatus(Table); } 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); if (sType.Equals("global")) { eType = CModInfo::GlobalModule; } else if (sType.Equals("user")) { eType = CModInfo::UserModule; } else if (sType.Equals("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("Unable to load [" + sMod + "]: Access Denied."); return; } if (sMod.empty()) { PutStatus("Usage: LoadMod [type] <module> [args]"); return; } CModInfo ModInfo; CString sRetMsg; if (!CZNC::Get().GetModules().GetModInfo(ModInfo, sMod, sRetMsg)) { PutStatus("Unable to find modinfo [" + sMod + "] [" + sRetMsg + "]"); return; } if (sType.Equals("default")) { eType = ModInfo.GetDefaultType(); } if (eType == CModInfo::GlobalModule && !m_pUser->IsAdmin()) { PutStatus("Unable to load global module [" + sMod + "]: Access Denied."); return; } if (eType == CModInfo::NetworkModule && !m_pNetwork) { PutStatus("Unable to load network module [" + sMod + "] Not connected with a network."); return; } CString sModRet; bool b = false; switch (eType) { case CModInfo::GlobalModule: b = CZNC::Get().GetModules().LoadModule(sMod, sArgs, eType, NULL, NULL, sModRet); break; case CModInfo::UserModule: b = m_pUser->GetModules().LoadModule(sMod, sArgs, eType, m_pUser, NULL, sModRet); break; case CModInfo::NetworkModule: b = m_pNetwork->GetModules().LoadModule(sMod, sArgs, eType, m_pUser, m_pNetwork, sModRet); break; default: sModRet = "Unable to load module [" + sMod + "]: Unknown module type"; } if (b) sModRet = "Loaded module [" + sMod + "] " + sModRet; PutStatus(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); if (sType.Equals("global")) { eType = CModInfo::GlobalModule; } else if (sType.Equals("user")) { eType = CModInfo::UserModule; } else if (sType.Equals("network")) { eType = CModInfo::NetworkModule; } else { sMod = sType; sType = "default"; } if (m_pUser->DenyLoadMod()) { PutStatus("Unable to unload [" + sMod + "] Access Denied."); return; } if (sMod.empty()) { PutStatus("Usage: UnloadMod [type] <module>"); return; } if (sType.Equals("default")) { CModInfo ModInfo; CString sRetMsg; if (!CZNC::Get().GetModules().GetModInfo(ModInfo, sMod, sRetMsg)) { PutStatus("Unable to find modinfo [" + sMod + "] [" + sRetMsg + "]"); return; } eType = ModInfo.GetDefaultType(); } if (eType == CModInfo::GlobalModule && !m_pUser->IsAdmin()) { PutStatus("Unable to unload global module [" + sMod + "]: Access Denied."); return; } if (eType == CModInfo::NetworkModule && !m_pNetwork) { PutStatus("Unable to unload network module [" + sMod + "] Not connected with a network."); 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 = "Unable to unload module [" + sMod + "]: Unknown module type"; } 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("Unable to reload modules. Access Denied."); return; } if (sType.Equals("global")) { eType = CModInfo::GlobalModule; } else if (sType.Equals("user")) { eType = CModInfo::UserModule; } else if (sType.Equals("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("Usage: ReloadMod [type] <module> [args]"); return; } if (sType.Equals("default")) { CModInfo ModInfo; CString sRetMsg; if (!CZNC::Get().GetModules().GetModInfo(ModInfo, sMod, sRetMsg)) { PutStatus("Unable to find modinfo for [" + sMod + "] [" + sRetMsg + "]"); return; } eType = ModInfo.GetDefaultType(); } if (eType == CModInfo::GlobalModule && !m_pUser->IsAdmin()) { PutStatus("Unable to reload global module [" + sMod + "]: Access Denied."); return; } if (eType == CModInfo::NetworkModule && !m_pNetwork) { PutStatus("Unable to load network module [" + sMod + "] Not connected with a network."); return; } CString sModRet; switch (eType) { case CModInfo::GlobalModule: CZNC::Get().GetModules().ReloadModule(sMod, sArgs, NULL, NULL, sModRet); break; case CModInfo::UserModule: m_pUser->GetModules().ReloadModule(sMod, sArgs, m_pUser, NULL, sModRet); break; case CModInfo::NetworkModule: m_pNetwork->GetModules().ReloadModule(sMod, sArgs, m_pUser, m_pNetwork, sModRet); break; default: sModRet = "Unable to reload module [" + sMod + "]: Unknown module type"; } PutStatus(sModRet); return; } else if ((sCommand.Equals("UPDATEMOD") || sCommand.Equals("UPDATEMODULE")) && m_pUser->IsAdmin() ) { CString sMod = sLine.Token(1); if (sMod.empty()) { PutStatus("Usage: UpdateMod <module>"); return; } PutStatus("Reloading [" + sMod + "] everywhere"); if (CZNC::Get().UpdateModule(sMod)) { PutStatus("Done"); } else { PutStatus("Done, but there were errors, [" + sMod + "] could not be loaded everywhere."); } } else if ((sCommand.Equals("ADDBINDHOST") || sCommand.Equals("ADDVHOST")) && m_pUser->IsAdmin()) { CString sHost = sLine.Token(1); if (sHost.empty()) { PutStatus("Usage: AddBindHost <host>"); return; } if (CZNC::Get().AddBindHost(sHost)) { PutStatus("Done"); } else { PutStatus("The host [" + sHost + "] is already in the list"); } } else if ((sCommand.Equals("REMBINDHOST") || sCommand.Equals("REMVHOST") || sCommand.Equals("DELVHOST")) && m_pUser->IsAdmin()) { CString sHost = sLine.Token(1); if (sHost.empty()) { PutStatus("Usage: RemBindHost <host>"); return; } if (CZNC::Get().RemBindHost(sHost)) { PutStatus("Done"); } else { PutStatus("The host [" + sHost + "] is not in the list"); } } else if ((sCommand.Equals("LISTBINDHOSTS") || sCommand.Equals("LISTVHOSTS")) && (m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) { const VCString& vsHosts = CZNC::Get().GetBindHosts(); if (vsHosts.empty()) { PutStatus("No bind hosts configured"); return; } CTable Table; Table.AddColumn("Host"); VCString::const_iterator it; for (it = vsHosts.begin(); it != vsHosts.end(); ++it) { Table.AddRow(); Table.SetCell("Host", *it); } PutStatus(Table); } else if ((sCommand.Equals("SETBINDHOST") || sCommand.Equals("SETVHOST")) && (m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) { CString sHost = sLine.Token(1); if (sHost.empty()) { PutStatus("Usage: SetBindHost <host>"); return; } if (sHost.Equals(m_pUser->GetBindHost())) { PutStatus("You already have this bind host!"); return; } const VCString& vsHosts = CZNC::Get().GetBindHosts(); if (!m_pUser->IsAdmin() && !vsHosts.empty()) { VCString::const_iterator it; bool bFound = false; for (it = vsHosts.begin(); it != vsHosts.end(); ++it) { if (sHost.Equals(*it)) { bFound = true; break; } } if (!bFound) { PutStatus("You may not use this bind host. See [ListBindHosts] for a list"); return; } } m_pUser->SetBindHost(sHost); PutStatus("Set bind host to [" + m_pUser->GetBindHost() + "]"); } else if ((sCommand.Equals("CLEARBINDHOST") || sCommand.Equals("CLEARVHOST")) && (m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) { m_pUser->SetBindHost(""); PutStatus("Bind Host Cleared"); } else if (sCommand.Equals("PLAYBUFFER")) { if (!m_pNetwork) { PutStatus("You must be connected with a network to use this command"); return; } CString sChan = sLine.Token(1); if (sChan.empty()) { PutStatus("Usage: PlayBuffer <#chan>"); return; } CChan* pChan = m_pNetwork->FindChan(sChan); if (!pChan) { PutStatus("You are not on [" + sChan + "]"); return; } if (!pChan->IsOn()) { PutStatus("You are not on [" + sChan + "] [trying]"); return; } if (pChan->GetBuffer().IsEmpty()) { PutStatus("The buffer for [" + sChan + "] is empty"); return; } pChan->SendBuffer(this); } else if (sCommand.Equals("CLEARBUFFER")) { if (!m_pNetwork) { PutStatus("You must be connected with a network to use this command"); return; } CString sChan = sLine.Token(1); if (sChan.empty()) { PutStatus("Usage: ClearBuffer <#chan>"); return; } CChan* pChan = m_pNetwork->FindChan(sChan); if (!pChan) { PutStatus("You are not on [" + sChan + "]"); return; } const vector<CChan*>& vChans = m_pNetwork->GetChans(); vector<CChan*>::const_iterator it; unsigned int uMatches = 0; for (it = vChans.begin(); it != vChans.end(); ++it) { if (!(*it)->GetName().WildCmp(sChan)) continue; uMatches++; (*it)->ClearBuffer(); } PutStatus("The buffer for [" + CString(uMatches) + "] channels matching [" + sChan + "] has been cleared"); } else if (sCommand.Equals("CLEARALLCHANNELBUFFERS")) { if (!m_pNetwork) { PutStatus("You must be connected with a network to use this command"); return; } vector<CChan*>::const_iterator it; const vector<CChan*>& vChans = m_pNetwork->GetChans(); for (it = vChans.begin(); it != vChans.end(); ++it) { (*it)->ClearBuffer(); } PutStatus("All channel buffers have been cleared"); } else if (sCommand.Equals("SETBUFFER")) { if (!m_pNetwork) { PutStatus("You must be connected with a network to use this command"); return; } CString sChan = sLine.Token(1); if (sChan.empty()) { PutStatus("Usage: SetBuffer <#chan> [linecount]"); return; } unsigned int uLineCount = sLine.Token(2).ToUInt(); const vector<CChan*>& vChans = m_pNetwork->GetChans(); vector<CChan*>::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; CZNC::TrafficStatsMap traffic = CZNC::Get().GetTrafficStats(Users, ZNC, Total); CZNC::TrafficStatsMap::const_iterator it; CTable Table; Table.AddColumn("Username"); Table.AddColumn("In"); Table.AddColumn("Out"); Table.AddColumn("Total"); for (it = traffic.begin(); it != traffic.end(); ++it) { Table.AddRow(); Table.SetCell("Username", it->first); Table.SetCell("In", CString::ToByteStr(it->second.first)); Table.SetCell("Out", CString::ToByteStr(it->second.second)); Table.SetCell("Total", CString::ToByteStr(it->second.first + it->second.second)); } Table.AddRow(); Table.SetCell("Username", "<Users>"); Table.SetCell("In", CString::ToByteStr(Users.first)); Table.SetCell("Out", CString::ToByteStr(Users.second)); Table.SetCell("Total", CString::ToByteStr(Users.first + Users.second)); Table.AddRow(); Table.SetCell("Username", "<ZNC>"); Table.SetCell("In", CString::ToByteStr(ZNC.first)); Table.SetCell("Out", CString::ToByteStr(ZNC.second)); Table.SetCell("Total", CString::ToByteStr(ZNC.first + ZNC.second)); Table.AddRow(); Table.SetCell("Username", "<Total>"); Table.SetCell("In", CString::ToByteStr(Total.first)); Table.SetCell("Out", CString::ToByteStr(Total.second)); Table.SetCell("Total", CString::ToByteStr(Total.first + Total.second)); PutStatus(Table); } else if (sCommand.Equals("UPTIME")) { PutStatus("Running for " + CZNC::Get().GetUptime()); } else if (m_pUser->IsAdmin() && (sCommand.Equals("LISTPORTS") || sCommand.Equals("ADDPORT") || sCommand.Equals("DELPORT"))) { UserPortCommand(sLine); } else { PutStatus("Unknown command [" + sCommand + "] try 'Help'"); } }