Console wip, change how we send acks back to some old behavior

This commit is contained in:
KimLS 2017-04-04 23:21:32 -07:00
parent 281483efc1
commit 8509f05f0a
9 changed files with 1070 additions and 883 deletions

View File

@ -125,11 +125,24 @@ void EQEmuConfig::do_world(TiXmlElement *ele)
if (text) {
WorldTCPPort = atoi(text);
}
text = sub_ele->Attribute("telnet");
if (text && !strcasecmp(text, "enabled")) {
}
sub_ele = ele->FirstChildElement("telnet");
if (sub_ele != nullptr) {
text = sub_ele->Attribute("ip");
if (text) {
TelnetIP = text;
}
text = sub_ele->Attribute("port");
if (text) {
TelnetTCPPort = atoi(text);
}
text = sub_ele->Attribute("enabled");
if (text && !strcasecmp(text, "true")) {
TelnetEnabled = true;
}
}
// Get the <http> element
sub_ele = ele->FirstChildElement("http");
if (sub_ele != nullptr) {
@ -390,6 +403,12 @@ std::string EQEmuConfig::GetByName(const std::string &var_name) const
if (var_name == "WorldIP") {
return (WorldIP);
}
if (var_name == "TelnetTCPPort") {
return (itoa(TelnetTCPPort));
}
if (var_name == "TelnetIP") {
return (TelnetIP);
}
if (var_name == "TelnetEnabled") {
return (TelnetEnabled ? "true" : "false");
}
@ -510,6 +529,8 @@ void EQEmuConfig::Dump() const
std::cout << "Locked = " << Locked << std::endl;
std::cout << "WorldTCPPort = " << WorldTCPPort << std::endl;
std::cout << "WorldIP = " << WorldIP << std::endl;
std::cout << "TelnetTCPPort = " << TelnetTCPPort << std::endl;
std::cout << "TelnetIP = " << TelnetIP << std::endl;
std::cout << "TelnetEnabled = " << TelnetEnabled << std::endl;
std::cout << "WorldHTTPPort = " << WorldHTTPPort << std::endl;
std::cout << "WorldHTTPMimeFile = " << WorldHTTPMimeFile << std::endl;

View File

@ -49,6 +49,8 @@ class EQEmuConfig : public XMLParser
bool Locked;
uint16 WorldTCPPort;
std::string WorldIP;
uint16 TelnetTCPPort;
std::string TelnetIP;
bool TelnetEnabled;
int32 MaxClients;
bool WorldHTTPEnabled;
@ -135,6 +137,7 @@ class EQEmuConfig : public XMLParser
// World
Locked = false;
WorldTCPPort = 9000;
TelnetTCPPort = 9001;
TelnetEnabled = false;
WorldHTTPEnabled = false;
WorldHTTPPort = 9080;
@ -189,6 +192,7 @@ class EQEmuConfig : public XMLParser
DefaultStatus = 0;
// For where zones need to connect to.
WorldIP = "127.0.0.1";
TelnetIP = "127.0.0.1";
// Dynamics to start
//DynamicCount=5;
MaxClients = -1;

View File

@ -119,6 +119,7 @@ void EQ::Net::DaybreakConnectionManager::Process()
auto time_since_last_recv = std::chrono::duration_cast<std::chrono::milliseconds>(now - connection->m_last_recv);
if ((size_t)time_since_last_recv.count() > m_options.connect_stale_ms) {
iter = m_connections.erase(iter);
Log(Logs::Detail, Logs::Netcode, "Disconnect reason: Connect Mode Timeout {0} > {1}", (size_t)time_since_last_recv.count(), m_options.connect_stale_ms);
connection->ChangeStatus(StatusDisconnecting);
continue;
}
@ -127,6 +128,7 @@ void EQ::Net::DaybreakConnectionManager::Process()
auto time_since_last_recv = std::chrono::duration_cast<std::chrono::milliseconds>(now - connection->m_last_recv);
if ((size_t)time_since_last_recv.count() > m_options.stale_connection_ms) {
iter = m_connections.erase(iter);
Log(Logs::Detail, Logs::Netcode, "Disconnect reason: Time since last recv {0} > {1}", (size_t)time_since_last_recv.count(), m_options.stale_connection_ms);
connection->ChangeStatus(StatusDisconnecting);
continue;
}
@ -276,7 +278,7 @@ EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner
m_encode_passes[1] = owner->m_options.encode_passes[1];
m_hold_time = Clock::now();
m_buffered_packets_length = 0;
m_resend_delay = 500;
m_resend_delay = m_owner->m_options.resend_delay_ms + 25;
m_rolling_ping = 100;
m_combined.reset(new char[512]);
m_combined[0] = 0;
@ -299,7 +301,7 @@ EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner
m_crc_bytes = 0;
m_hold_time = Clock::now();
m_buffered_packets_length = 0;
m_resend_delay = 500;
m_resend_delay = m_resend_delay = m_owner->m_options.resend_delay_ms + 25;
m_rolling_ping = 100;
m_combined.reset(new char[512]);
m_combined[0] = 0;
@ -318,6 +320,7 @@ void EQ::Net::DaybreakConnection::Close()
SendDisconnect();
m_close_time = Clock::now();
Log(Logs::Detail, Logs::Netcode, "Disconnect reason: Server Request");
ChangeStatus(StatusDisconnecting);
}
else {
@ -355,6 +358,11 @@ void EQ::Net::DaybreakConnection::ResetStats()
void EQ::Net::DaybreakConnection::Process()
{
try {
m_resend_delay = (size_t)(m_stats.last_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms;
if (m_resend_delay > 500) {
m_resend_delay = 500;
}
auto now = Clock::now();
auto time_since_hold = (size_t)std::chrono::duration_cast<std::chrono::milliseconds>(now - m_hold_time).count();
if (time_since_hold >= m_owner->m_options.hold_length_ms) {
@ -719,6 +727,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
SendDisconnect();
}
Log(Logs::Detail, Logs::Netcode, "Disconnect reason: OP_SessionRequest from client.");
ChangeStatus(StatusDisconnecting);
break;
}
@ -747,10 +756,6 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
DynamicPacket out;
out.PutSerialize(0, response);
InternalSend(out);
m_resend_delay = (size_t)(request.avg_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms;
m_resend_delay = std::min(m_resend_delay, m_owner->m_options.resend_delay_max);
m_resend_delay = std::max(m_resend_delay, m_owner->m_options.resend_delay_min);
break;
}
case OP_SessionStatResponse:
@ -1051,7 +1056,7 @@ void EQ::Net::DaybreakConnection::Ack(int stream, uint16_t seq)
auto iter = s->sent_packets.begin();
while (iter != s->sent_packets.end()) {
if (iter->first <= seq) {
uint64_t round_time = (uint64_t)std::chrono::duration_cast<std::chrono::milliseconds>(now - iter->second.first_sent).count();
uint64_t round_time = (uint64_t)std::chrono::duration_cast<std::chrono::milliseconds>(now - iter->second.last_sent).count();
m_stats.total_ping += round_time;
m_stats.total_acks++;
m_stats.max_ping = std::max(m_stats.max_ping, round_time);
@ -1072,7 +1077,7 @@ void EQ::Net::DaybreakConnection::OutOfOrderAck(int stream, uint16_t seq)
auto s = &m_streams[stream];
auto iter = s->sent_packets.find(seq);
if (iter != s->sent_packets.end()) {
uint64_t round_time = (uint64_t)std::chrono::duration_cast<std::chrono::milliseconds>(now - iter->second.first_sent).count();
uint64_t round_time = (uint64_t)std::chrono::duration_cast<std::chrono::milliseconds>(now - iter->second.last_sent).count();
m_stats.total_ping += round_time;
m_stats.total_acks++;
m_stats.max_ping = std::max(m_stats.max_ping, round_time);

View File

@ -209,10 +209,10 @@ namespace EQ
DaybreakConnectionManagerOptions() {
max_connection_count = 0;
keepalive_delay_ms = 9000;
resend_delay_ms = 300;
resend_delay_ms = 50;
resend_delay_factor = 1.5;
resend_delay_min = 50;
resend_delay_max = 1000;
resend_delay_max = 500;
connect_delay_ms = 500;
stale_connection_ms = 90000;
connect_stale_ms = 5000;

View File

@ -6,6 +6,7 @@ SET(world_sources
client.cpp
cliententry.cpp
clientlist.cpp
console.cpp
eql_config.cpp
launcher_link.cpp
launcher_list.cpp
@ -31,6 +32,7 @@ SET(world_headers
client.h
cliententry.h
clientlist.h
console.h
eql_config.h
launcher_link.h
launcher_list.h

View File

@ -1,890 +1,103 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/global_define.h"
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "../common/version.h"
#include "console.h"
#include "zoneserver.h"
#include "worlddb.h"
#include "../common/packet_dump.h"
#include "../common/seperator.h"
#include "../common/eq_packet_structs.h"
#include "../common/eq_packet.h"
#include "login_server.h"
#include "login_server_list.h"
#include "../common/serverinfo.h"
#include "../common/md5.h"
#include "../common/opcodemgr.h"
#include "../common/rulesys.h"
#include "../common/ruletypes.h"
#include "../common/string_util.h"
#include "world_config.h"
#include "zoneserver.h"
#include "zonelist.h"
#include "clientlist.h"
#include "launcher_list.h"
#include "ucs.h"
#include "queryserv.h"
#include "../common/eqemu_config.h"
#include "../common/util/uuid.h"
#include "../common/eqemu_logsys.h"
#include "../common//net/packet.h"
#ifdef _WINDOWS
#define snprintf _snprintf
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#endif
extern ZSList zoneserver_list;
extern uint32 numzones;
extern LoginServerList loginserverlist;
extern ClientList client_list;
extern LauncherList launcher_list;
extern UCSConnection UCSLink;
extern QueryServConnection QSLink;
extern volatile bool RunLoops;
ConsoleList console_list;
void CatchSignal(int sig_num);
Console::Console(EmuTCPConnection* itcpc)
: WorldTCPConnection(),
timeout_timer(RuleI(Console, SessionTimeOut)),
prompt_timer(1)
ConsoleConnection::ConsoleConnection(ConsoleServer *parent, std::shared_ptr<EQ::Net::TCPConnection> connection)
{
tcpc = itcpc;
tcpc->SetEcho(true);
state = 0;
paccountid = 0;
memset(paccountname, 0, sizeof(paccountname));
admin = 0;
pAcceptMessages = false;
m_parent = parent;
m_connection = connection;
m_uuid = EQ::Util::UUID::Generate().ToString();
m_connection->OnRead(std::bind(&ConsoleConnection::OnRead, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
m_connection->OnDisconnect(std::bind(&ConsoleConnection::OnDisconnect, this, std::placeholders::_1));
m_connection->Start();
Clear();
}
Console::~Console() {
if (tcpc)
tcpc->Free();
ConsoleConnection::~ConsoleConnection()
{
}
void Console::Die() {
state = CONSOLE_STATE_CLOSED;
struct in_addr in;
in.s_addr = GetIP();
Log(Logs::Detail, Logs::World_Server,"Removing console from %s:%d",inet_ntoa(in),GetPort());
tcpc->Disconnect();
void ConsoleConnection::Clear()
{
EQ::Net::DynamicPacket clear;
clear.PutUInt8(0, 0);
m_connection->Write((const char*)clear.Data(), clear.Length());
}
bool Console::SendChannelMessage(const ServerChannelMessage_Struct* scm) {
if (!pAcceptMessages)
return false;
switch (scm->chan_num) {
if(RuleB(Chat, ServerWideAuction)){
case 4: {
SendMessage(1, "%s auctions, '%s'", scm->from, scm->message);
break;
}
}
if(RuleB(Chat, ServerWideOOC)){
case 5: {
SendMessage(1, "%s says ooc, '%s'", scm->from, scm->message);
break;
}
}
case 6: {
SendMessage(1, "%s BROADCASTS, '%s'", scm->from, scm->message);
void ConsoleConnection::SendLine(const std::string &line)
{
m_connection->Write(line.c_str(), line.length());
SendNewLine();
}
void ConsoleConnection::SendNewLine()
{
EQ::Net::DynamicPacket newline;
newline.PutUInt8(0, 10);
newline.PutUInt8(1, 13);
m_connection->Write((const char*)newline.Data(), newline.Length());
}
void ConsoleConnection::OnRead(EQ::Net::TCPConnection *c, const unsigned char *data, size_t sz)
{
m_buffer.insert(m_buffer.end(), (const char*)data, (const char*)data + sz);
ProcessReadBuffer();
}
void ConsoleConnection::ProcessReadBuffer()
{
size_t buffer_start = 0;
for (size_t i = 0; i < m_buffer.size(); ++i) {
char c = m_buffer[i];
switch (c) {
case 0:
//Clear buffer
break;
}
case 7: {
SendMessage(1, "[%s] tells you, '%s'", scm->from, scm->message);
auto pack = new ServerPacket(ServerOP_ChannelMessage,
sizeof(ServerChannelMessage_Struct) + strlen(scm->message) + 1);
memcpy(pack->pBuffer, scm, pack->size);
ServerChannelMessage_Struct* scm2 = (ServerChannelMessage_Struct*) pack->pBuffer;
strcpy(scm2->deliverto, scm2->from);
scm2->noreply = true;
client_list.SendPacket(scm->from, pack);
safe_delete(pack);
case 10:
case 13:
//New Line
break;
}
case 11: {
SendMessage(1, "%s GMSAYS, '%s'", scm->from, scm->message);
case 8:
//Backspace
break;
}
default: {
return false;
}
}
return true;
}
bool Console::SendEmoteMessage(uint32 type, const char* message, ...) {
if (!message)
return false;
if (!pAcceptMessages)
return false;
va_list argptr;
char buffer[1024];
va_start(argptr, message);
vsnprintf(buffer, sizeof(buffer), message, argptr);
va_end(argptr);
SendMessage(1, message);
return true;
}
bool Console::SendEmoteMessageRaw(uint32 type, const char* message) {
if (!message)
return false;
if (!pAcceptMessages)
return false;
SendMessage(1, message);
return true;
}
void Console::SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...) {
if (!message)
return;
if (to_guilddbid != 0 || to_minstatus > Admin())
return;
va_list argptr;
char buffer[1024];
va_start(argptr, message);
vsnprintf(buffer, sizeof(buffer), message, argptr);
va_end(argptr);
SendEmoteMessageRaw(to, to_guilddbid, to_minstatus, type, buffer);
}
void Console::SendEmoteMessageRaw(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message) {
if (!message)
return;
if (to_guilddbid != 0 || to_minstatus > Admin())
return;
SendMessage(1, message);
}
void Console::SendMessage(uint8 newline, const char* message, ...) {
if (!message)
return;
char* buffer = 0;
uint32 bufsize = 1500;
if (message)
bufsize += strlen(message);
buffer = new char[bufsize];
memset(buffer, 0, bufsize);
if (message != 0) {
va_list argptr;
va_start(argptr, message);
vsnprintf(buffer, bufsize - 512, message, argptr);
va_end(argptr);
}
if (newline) {
char outbuf[3];
outbuf[0] = 13;
outbuf[1] = 10;
outbuf[2] = 0;
for (int i=0; i < newline; i++)
strcat(buffer, outbuf);
}
tcpc->Send((uchar*) buffer, strlen(buffer));
safe_delete_array(buffer);
}
bool Console::Process() {
if (state == CONSOLE_STATE_CLOSED)
return false;
if (!tcpc->Connected()) {
struct in_addr in;
in.s_addr = GetIP();
Log(Logs::Detail, Logs::World_Server,"Removing console (!tcpc->Connected) from %s:%d",inet_ntoa(in),GetPort());
return false;
}
//if we have not gotten the special markers after this timer, send login prompt
if(prompt_timer.Check()) {
struct in_addr in;
in.s_addr = GetIP();
std::string connecting_ip = inet_ntoa(in);
SendMessage(2, StringFormat("Establishing connection from IP: %s Port: %d", inet_ntoa(in), GetPort()).c_str());
if (connecting_ip.find("127.0.0.1") != std::string::npos) {
SendMessage(2, StringFormat("Connecting established from local host, auto assuming admin").c_str());
state = CONSOLE_STATE_CONNECTED;
tcpc->SetEcho(false);
admin = 255;
SendPrompt();
}
else {
if (tcpc->GetMode() == EmuTCPConnection::modeConsole)
tcpc->Send((const uchar*) "Username: ", strlen("Username: "));
}
prompt_timer.Disable();
}
if (timeout_timer.Check()) {
SendMessage(1, 0);
SendMessage(1, "Timeout, disconnecting...");
struct in_addr in;
in.s_addr = GetIP();
Log(Logs::Detail, Logs::World_Server,"TCP connection timeout from %s:%d",inet_ntoa(in),GetPort());
return false;
}
if (tcpc->GetMode() == EmuTCPConnection::modePacket) {
struct in_addr in;
in.s_addr = GetIP();
if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeZone) {
auto zs = new ZoneServer(tcpc);
Log(Logs::Detail, Logs::World_Server,"New zoneserver #%d from %s:%d", zs->GetID(), inet_ntoa(in), GetPort());
zoneserver_list.Add(zs);
numzones++;
tcpc = 0;
} else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeLauncher) {
Log(Logs::Detail, Logs::World_Server,"New launcher from %s:%d", inet_ntoa(in), GetPort());
launcher_list.Add(tcpc);
tcpc = 0;
}
else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeUCS)
{
Log(Logs::Detail, Logs::World_Server,"New UCS Connection from %s:%d", inet_ntoa(in), GetPort());
UCSLink.SetConnection(tcpc);
tcpc = 0;
}
else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeQueryServ)
{
Log(Logs::Detail, Logs::World_Server,"New QS Connection from %s:%d", inet_ntoa(in), GetPort());
QSLink.SetConnection(tcpc);
tcpc = 0;
}
else {
Log(Logs::Detail, Logs::World_Server,"Unsupported packet mode from %s:%d", inet_ntoa(in), GetPort());
}
return false;
}
char* command = 0;
while ((command = tcpc->PopLine())) {
timeout_timer.Start();
ProcessCommand(command);
delete command;
}
return true;
}
void ConsoleList::Add(Console* con) {
list.Insert(con);
}
void ConsoleList::Process() {
LinkedListIterator<Console*> iterator(list);
iterator.Reset();
while(iterator.MoreElements()) {
if (!iterator.GetData()->Process())
iterator.RemoveCurrent();
else
iterator.Advance();
}
}
void ConsoleList::KillAll() {
LinkedListIterator<Console*> iterator(list);
iterator.Reset();
while(iterator.MoreElements()) {
iterator.GetData()->Die();
iterator.RemoveCurrent();
}
}
void ConsoleList::SendConsoleWho(WorldTCPConnection* connection, const char* to, int16 admin, char** output, uint32* outsize, uint32* outlen) {
LinkedListIterator<Console*> iterator(list);
iterator.Reset();
struct in_addr in;
int x = 0;
while(iterator.MoreElements()) {
in.s_addr = iterator.GetData()->GetIP();
if (admin >= iterator.GetData()->Admin())
AppendAnyLenString(output, outsize, outlen, " Console: %s:%i AccID: %i AccName: %s", inet_ntoa(in), iterator.GetData()->GetPort(), iterator.GetData()->AccountID(), iterator.GetData()->AccountName());
else
AppendAnyLenString(output, outsize, outlen, " Console: AccID: %i AccName: %s", iterator.GetData()->AccountID(), iterator.GetData()->AccountName());
if (*outlen >= 3584) {
connection->SendEmoteMessageRaw(to, 0, 0, 10, *output);
safe_delete(*output);
*outsize = 0;
*outlen = 0;
}
else {
if (connection->IsConsole())
AppendAnyLenString(output, outsize, outlen, "\r\n");
else
AppendAnyLenString(output, outsize, outlen, "\n");
}
x++;
iterator.Advance();
}
AppendAnyLenString(output, outsize, outlen, "%i consoles connected", x);
}
void ConsoleList::SendChannelMessage(const ServerChannelMessage_Struct* scm) {
LinkedListIterator<Console*> iterator(list);
iterator.Reset();
while(iterator.MoreElements()) {
iterator.GetData()->SendChannelMessage(scm);
iterator.Advance();
}
}
void ConsoleList::SendEmoteMessage(uint32 type, const char* message, ...) {
va_list argptr;
char buffer[1024];
va_start(argptr, message);
vsnprintf(buffer, sizeof(buffer), message, argptr);
va_end(argptr);
SendEmoteMessageRaw(type, buffer);
}
void ConsoleList::SendEmoteMessageRaw(uint32 type, const char* message) {
LinkedListIterator<Console*> iterator(list);
iterator.Reset();
while(iterator.MoreElements()) {
iterator.GetData()->SendEmoteMessageRaw(type, message);
iterator.Advance();
}
}
Console* ConsoleList::FindByAccountName(const char* accname) {
LinkedListIterator<Console*> iterator(list);
iterator.Reset();
while(iterator.MoreElements()) {
if (strcasecmp(iterator.GetData()->AccountName(), accname) == 0)
return iterator.GetData();
iterator.Advance();
}
return 0;
}
void Console::ProcessCommand(const char* command) {
switch(state)
{
case CONSOLE_STATE_USERNAME:
{
if (strlen(command) >= 16) {
SendMessage(1, 0);
SendMessage(2, "Username buffer overflow.");
SendMessage(1, "Bye Bye.");
state = CONSOLE_STATE_CLOSED;
return;
}
strcpy(paccountname, command);
state = CONSOLE_STATE_PASSWORD;
SendMessage(0, "Password: ");
tcpc->SetEcho(false);
break;
}
case CONSOLE_STATE_PASSWORD:
{
if (strlen(command) >= 16) {
SendMessage(1, 0);
SendMessage(2, "Password buffer overflow.");
SendMessage(1, "Bye Bye.");
state = CONSOLE_STATE_CLOSED;
return;
}
paccountid = database.CheckLogin(paccountname ,command);
if (paccountid == 0) {
SendMessage(1, 0);
SendMessage(2, "Login failed.");
SendMessage(1, "Bye Bye.");
state = CONSOLE_STATE_CLOSED;
return;
}
database.GetAccountName(paccountid, paccountname); // fixes case and stuff
admin = database.CheckStatus(paccountid);
if (!(admin >= consoleLoginStatus)) {
SendMessage(1, 0);
SendMessage(2, "Access denied.");
SendMessage(1, "Bye Bye.");
state = CONSOLE_STATE_CLOSED;
return;
}
Log(Logs::Detail, Logs::World_Server,"TCP console authenticated: Username=%s, Admin=%d",paccountname,admin);
SendMessage(1, 0);
SendMessage(2, "Login accepted.");
state = CONSOLE_STATE_CONNECTED;
tcpc->SetEcho(true);
SendPrompt();
break;
}
case CONSOLE_STATE_CONNECTED: {
Log(Logs::Detail, Logs::World_Server,"TCP command: %s: \"%s\"",paccountname ,command);
Seperator sep(command);
if (strcasecmp(sep.arg[0], "help") == 0 || strcmp(sep.arg[0], "?") == 0) {
SendMessage(1, " whoami");
SendMessage(1, " who");
SendMessage(1, " zonestatus");
SendMessage(1, " uptime [zoneID#]");
SendMessage(1, " emote [zonename or charname or world] [type] [message]");
SendMessage(1, " echo [on/off]");
SendMessage(1, " acceptmessages [on/off]");
SendMessage(1, " tell [name] [message]");
SendMessage(1, " broadcast [message]");
SendMessage(1, " gmsay [message]");
SendMessage(1, " ooc [message]");
SendMessage(1, " auction [message]");
if (admin >= consoleKickStatus)
SendMessage(1, " kick [charname]");
if (admin >= consoleLockStatus)
SendMessage(1, " lock/unlock");
if (admin >= consoleZoneStatus) {
SendMessage(1, " zoneshutdown [zonename or ZoneServerID]");
SendMessage(1, " zonebootup [ZoneServerID] [zonename]");
SendMessage(1, " zonelock [list|lock|unlock] [zonename]");
}
if (admin >= consoleFlagStatus)
SendMessage(1, " flag [status] [accountname]");
if (admin >= consolePassStatus)
SendMessage(1, " setpass [accountname] [newpass]");
if (admin >= consoleWorldStatus) {
SendMessage(1, " version");
SendMessage(1, " worldshutdown");
}
if (admin >= 201) {
SendMessage(1, " IPLookup [name]");
}
if (admin >= 100) {
SendMessage(1, " LSReconnect");
SendMessage(1, " signalcharbyname charname ID");
SendMessage(1, " reloadworld");
}
}
else if (strcasecmp(sep.arg[0], "ping") == 0) {
// do nothing
}
else if (strcasecmp(sep.arg[0], "signalcharbyname") == 0) {
SendMessage(1, "Signal Sent to %s with ID %i", (char*) sep.arg[1], atoi(sep.arg[2]));
uint32 message_len = strlen((char*) sep.arg[1]) + 1;
auto pack = new ServerPacket(ServerOP_CZSignalClientByName,
sizeof(CZClientSignalByName_Struct) + message_len);
CZClientSignalByName_Struct* CZSC = (CZClientSignalByName_Struct*) pack->pBuffer;
strn0cpy(CZSC->Name, (char*) sep.arg[1], 64);
CZSC->data = atoi(sep.arg[2]);
zoneserver_list.SendPacket(pack);
safe_delete(pack);
}
else if (strcasecmp(sep.arg[0], "setpass") == 0 && admin >= consolePassStatus) {
if (sep.argnum != 2)
SendMessage(1, "Format: setpass accountname password");
else {
int16 tmpstatus = 0;
uint32 tmpid = database.GetAccountIDByName(sep.arg[1], &tmpstatus);
if (!tmpid)
SendMessage(1, "Error: Account not found");
else if (tmpstatus > admin)
SendMessage(1, "Cannot change password: Account's status is higher than yours");
else if (database.SetLocalPassword(tmpid, sep.arg[2]))
SendMessage(1, "Password changed.");
else
SendMessage(1, "Error changing password.");
}
}
else if (strcasecmp(sep.arg[0], "uptime") == 0) {
if (sep.IsNumber(1) && atoi(sep.arg[1]) > 0) {
auto pack = new ServerPacket(ServerOP_Uptime, sizeof(ServerUptime_Struct));
ServerUptime_Struct* sus = (ServerUptime_Struct*) pack->pBuffer;
snprintf(sus->adminname, sizeof(sus->adminname), "*%s", this->GetName());
sus->zoneserverid = atoi(sep.arg[1]);
ZoneServer* zs = zoneserver_list.FindByID(sus->zoneserverid);
if (zs)
zs->SendPacket(pack);
else
SendMessage(1, "Zoneserver not found.");
delete pack;
}
else {
ZSList::ShowUpTime(this);
}
}
else if (strcasecmp(sep.arg[0], "md5") == 0) {
uint8 md5[16];
MD5::Generate((const uchar*) sep.argplus[1], strlen(sep.argplus[1]), md5);
SendMessage(1, "MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7], md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15]);
}
else if (strcasecmp(sep.arg[0], "whoami") == 0) {
SendMessage(1, "You are logged in as '%s'", this->AccountName());
SendMessage(1, "You are known as '*%s'", this->AccountName());
SendMessage(1, "AccessLevel: %d", this->Admin());
}
else if (strcasecmp(sep.arg[0], "echo") == 0) {
if (strcasecmp(sep.arg[1], "on") == 0)
tcpc->SetEcho(true);
else if (strcasecmp(sep.arg[1], "off") == 0) {
if (pAcceptMessages)
SendMessage(1, "Echo can not be turned off while acceptmessages is on");
else
tcpc->SetEcho(false);
}
else
SendMessage(1, "Usage: echo [on/off]");
}
else if (strcasecmp(sep.arg[0], "acceptmessages") == 0) {
if (strcasecmp(sep.arg[1], "on") == 0)
if (tcpc->GetEcho())
SendMessage(1, "AcceptMessages can not be turned on while echo is on");
else
pAcceptMessages = true;
else if (strcasecmp(sep.arg[1], "off") == 0)
pAcceptMessages = false;
else
SendMessage(1, "Usage: acceptmessages [on/off]");
}
else if (strcasecmp(sep.arg[0], "tell") == 0) {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
zoneserver_list.SendChannelMessage(tmpname, sep.arg[1], 7, 0, sep.argplus[2]);
}
else if (strcasecmp(sep.arg[0], "broadcast") == 0) {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
zoneserver_list.SendChannelMessage(tmpname, 0, 6, 0, sep.argplus[1]);
}
else if (strcasecmp(sep.arg[0], "ooc") == 0) {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
zoneserver_list.SendChannelMessage(tmpname, 0, 5, 0, sep.argplus[1]);
}
else if (strcasecmp(sep.arg[0], "auction") == 0) {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
zoneserver_list.SendChannelMessage(tmpname, 0, 4, 0, sep.argplus[1]);
}
else if (strcasecmp(sep.arg[0], "gmsay") == 0 || strcasecmp(sep.arg[0], "pr") == 0) {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
zoneserver_list.SendChannelMessage(tmpname, 0, 11, 0, sep.argplus[1]);
}
else if (strcasecmp(sep.arg[0], "emote") == 0) {
if (strcasecmp(sep.arg[1], "world") == 0)
zoneserver_list.SendEmoteMessageRaw(0, 0, 0, atoi(sep.arg[2]), sep.argplus[3]);
else {
ZoneServer* zs = zoneserver_list.FindByName(sep.arg[1]);
if (zs != 0)
zs->SendEmoteMessageRaw(0, 0, 0, atoi(sep.arg[2]), sep.argplus[3]);
else
zoneserver_list.SendEmoteMessageRaw(sep.arg[1], 0, 0, atoi(sep.arg[2]), sep.argplus[3]);
}
}
else if (strcasecmp(sep.arg[0], "movechar") == 0) {
if(sep.arg[1][0]==0 || sep.arg[2][0] == 0)
SendMessage(1, "Usage: movechar [charactername] [zonename]");
else {
if (!database.GetZoneID(sep.arg[2]))
SendMessage(1, "Error: Zone '%s' not found", sep.arg[2]);
else if (!database.CheckUsedName((char*) sep.arg[1])) {
if (!database.MoveCharacterToZone((char*) sep.arg[1], (char*) sep.arg[2]))
SendMessage(1, "Character Move Failed!");
else
SendMessage(1, "Character has been moved.");
}
else
SendMessage(1, "Character Does Not Exist");
}
}
else if (strcasecmp(sep.arg[0], "flag") == 0 && this->Admin() >= consoleFlagStatus) {
// SCORPIOUS2K - reversed parameter order for flag
if(sep.arg[2][0]==0 || !sep.IsNumber(1))
SendMessage(1, "Usage: flag [status] [accountname]");
else
{
if (atoi(sep.arg[1]) > this->Admin())
SendMessage(1, "You cannot set people's status to higher than your own");
else if (atoi(sep.arg[1]) < 0 && this->Admin() < consoleFlagStatus)
SendMessage(1, "You have too low of status to change flags");
else if (!database.SetAccountStatus(sep.arg[2], atoi(sep.arg[1])))
SendMessage(1, "Unable to flag account!");
else
SendMessage(1, "Account Flaged");
}
}
else if (strcasecmp(sep.arg[0], "kick") == 0 && admin >= consoleKickStatus) {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
auto pack = new ServerPacket;
pack->opcode = ServerOP_KickPlayer;
pack->size = sizeof(ServerKickPlayer_Struct);
pack->pBuffer = new uchar[pack->size];
ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*) pack->pBuffer;
strcpy(skp->adminname, tmpname);
strcpy(skp->name, sep.arg[1]);
skp->adminrank = this->Admin();
zoneserver_list.SendPacket(pack);
delete pack;
}
else if (strcasecmp(sep.arg[0], "who") == 0) {
auto whom = new Who_All_Struct;
memset(whom, 0, sizeof(Who_All_Struct));
whom->lvllow = 0xFFFF;
whom->lvlhigh = 0xFFFF;
whom->wclass = 0xFFFF;
whom->wrace = 0xFFFF;
whom->gmlookup = 0xFFFF;
for (int i=1; i<=sep.argnum; i++) {
if (strcasecmp(sep.arg[i], "gm") == 0)
whom->gmlookup = 1;
else if (sep.IsNumber(i)) {
if (whom->lvllow == 0xFFFF) {
whom->lvllow = atoi(sep.arg[i]);
whom->lvlhigh = whom->lvllow;
}
else if (atoi(sep.arg[i]) > int(whom->lvllow))
whom->lvlhigh = atoi(sep.arg[i]);
else
whom->lvllow = atoi(sep.arg[i]);
}
else
strn0cpy(whom->whom, sep.arg[i], sizeof(whom->whom));
}
client_list.ConsoleSendWhoAll(0, admin, whom, this);
delete whom;
}
else if (strcasecmp(sep.arg[0], "zonestatus") == 0) {
zoneserver_list.SendZoneStatus(0, admin, this);
}
else if (strcasecmp(sep.arg[0], "exit") == 0 || strcasecmp(sep.arg[0], "quit") == 0) {
SendMessage(1, "Bye Bye.");
state = CONSOLE_STATE_CLOSED;
}
else if (strcasecmp(sep.arg[0], "zoneshutdown") == 0 && admin >= consoleZoneStatus) {
if (sep.arg[1][0] == 0) {
SendMessage(1, "Usage: zoneshutdown zoneshortname");
} else {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
auto pack = new ServerPacket;
pack->size = sizeof(ServerZoneStateChange_struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, sizeof(ServerZoneStateChange_struct));
ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer;
pack->opcode = ServerOP_ZoneShutdown;
strcpy(s->adminname, tmpname);
if (sep.arg[1][0] >= '0' && sep.arg[1][0] <= '9')
s->ZoneServerID = atoi(sep.arg[1]);
else
s->zoneid = database.GetZoneID(sep.arg[1]);
ZoneServer* zs = 0;
if (s->ZoneServerID != 0)
zs = zoneserver_list.FindByID(s->ZoneServerID);
else if (s->zoneid != 0)
zs = zoneserver_list.FindByName(database.GetZoneName(s->zoneid));
else
SendMessage(1, "Error: ZoneShutdown: neither ID nor name specified");
if (zs == 0)
SendMessage(1, "Error: ZoneShutdown: zoneserver not found");
else
zs->SendPacket(pack);
delete pack;
}
}
else if (strcasecmp(sep.arg[0], "zonebootup") == 0 && admin >= consoleZoneStatus) {
if (sep.arg[2][0] == 0 || !sep.IsNumber(1)) {
SendMessage(1, "Usage: zonebootup ZoneServerID# zoneshortname");
} else {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
Log(Logs::Detail, Logs::World_Server,"Console ZoneBootup: %s, %s, %s",tmpname,sep.arg[2],sep.arg[1]);
zoneserver_list.SOPZoneBootup(tmpname, atoi(sep.arg[1]), sep.arg[2], (bool) (strcasecmp(sep.arg[3], "static") == 0));
}
}
else if (strcasecmp(sep.arg[0], "worldshutdown") == 0 && admin >= consoleWorldStatus) {
int32 time, interval;
if(sep.IsNumber(1) && sep.IsNumber(2) && ((time=atoi(sep.arg[1]))>0) && ((interval=atoi(sep.arg[2]))>0)) {
zoneserver_list.WorldShutDown(time, interval);
}
else if(strcasecmp(sep.arg[1], "now") == 0) {
zoneserver_list.WorldShutDown(0, 0);
}
else if(strcasecmp(sep.arg[1], "disable") == 0) {
SendEmoteMessage(0,0,0,15,"<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World shutdown aborted.");
zoneserver_list.SendEmoteMessage(0,0,0,15,"<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World shutdown aborted.");
zoneserver_list.shutdowntimer->Disable();
zoneserver_list.reminder->Disable();
}
else {
SendMessage(1, "Usage: worldshutdown [now] [disable] ([time] [interval])");
//Go ahead and shut down since that's what this used to do when invoked this way.
zoneserver_list.WorldShutDown(0, 0);
}
}
else if (strcasecmp(sep.arg[0], "lock") == 0 && admin >= consoleLockStatus) {
WorldConfig::LockWorld();
if (loginserverlist.Connected()) {
loginserverlist.SendStatus();
SendMessage(1, "World locked.");
}
else {
SendMessage(1, "World locked, but login server not connected.");
}
}
else if (strcasecmp(sep.arg[0], "unlock") == 0 && admin >= consoleLockStatus) {
WorldConfig::UnlockWorld();
if (loginserverlist.Connected()) {
loginserverlist.SendStatus();
SendMessage(1, "World unlocked.");
}
else {
SendMessage(1, "World unlocked, but login server not connected.");
}
}
else if (strcasecmp(sep.arg[0], "version") == 0 && admin >= consoleWorldStatus) {
SendMessage(1, "Current version information.");
SendMessage(1, " %s", CURRENT_VERSION);
SendMessage(1, " Compiled on: %s at %s", COMPILE_DATE, COMPILE_TIME);
SendMessage(1, " Last modified on: %s", LAST_MODIFIED);
}
else if (strcasecmp(sep.arg[0], "serverinfo") == 0 && admin >= 200) {
if (strcasecmp(sep.arg[1], "os") == 0) {
#ifdef _WINDOWS
GetOS();
char intbuffer [sizeof(unsigned long)];
SendMessage(1, "Operating system information.");
SendMessage(1, " %s", Ver_name);
SendMessage(1, " Build number: %s", ultoa(Ver_build, intbuffer, 10));
SendMessage(1, " Minor version: %s", ultoa(Ver_min, intbuffer, 10));
SendMessage(1, " Major version: %s", ultoa(Ver_maj, intbuffer, 10));
SendMessage(1, " Platform Id: %s", ultoa(Ver_pid, intbuffer, 10));
#else
char os_string[100];
SendMessage(1, "Operating system information.");
SendMessage(1, " %s", GetOS(os_string));
#endif
}
else {
SendMessage(1, "Usage: Serverinfo [type]");
SendMessage(1, " OS - Operating system version information.");
}
}
else if (strcasecmp(sep.arg[0], "IPLookup") == 0 && admin >= 201) {
client_list.SendCLEList(admin, 0, this, sep.argplus[1]);
}
else if (strcasecmp(sep.arg[0], "LSReconnect") == 0 && admin >= 100) {
#ifdef _WINDOWS
_beginthread(AutoInitLoginServer, 0, nullptr);
#else
pthread_t thread;
pthread_create(&thread, nullptr, &AutoInitLoginServer, nullptr);
#endif
RunLoops = true;
SendMessage(1, " Login Server Reconnect manually restarted by Console");
Log(Logs::Detail, Logs::World_Server,"Login Server Reconnect manually restarted by Console");
}
else if (strcasecmp(sep.arg[0], "zonelock") == 0 && admin >= consoleZoneStatus) {
if (strcasecmp(sep.arg[1], "list") == 0) {
zoneserver_list.ListLockedZones(0, this);
}
else if (strcasecmp(sep.arg[1], "lock") == 0 && admin >= 101) {
uint16 tmp = database.GetZoneID(sep.arg[2]);
if (tmp) {
if (zoneserver_list.SetLockedZone(tmp, true))
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone locked: %s", database.GetZoneName(tmp));
else
SendMessage(1, "Failed to change lock");
}
else
SendMessage(1, "Usage: #zonelock lock [zonename]");
}
else if (strcasecmp(sep.arg[1], "unlock") == 0 && admin >= 101) {
uint16 tmp = database.GetZoneID(sep.arg[2]);
if (tmp) {
if (zoneserver_list.SetLockedZone(tmp, false))
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone unlocked: %s", database.GetZoneName(tmp));
else
SendMessage(1, "Failed to change lock");
}
else
SendMessage(1, "Usage: #zonelock unlock [zonename]");
}
else {
SendMessage(1, "#zonelock sub-commands");
SendMessage(1, " list");
if (admin >= 101) {
SendMessage(1, " lock [zonename]");
SendMessage(1, " unlock [zonename]");
}
}
}
else if (strcasecmp(sep.arg[0], "reloadworld") == 0 && admin > 101)
{
SendEmoteMessage(0,0,0,15,"Reloading World...");
auto pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct));
ReloadWorld_Struct* RW = (ReloadWorld_Struct*) pack->pBuffer;
RW->Option = 1;
zoneserver_list.SendPacket(pack);
safe_delete(pack);
}
else if (strcasecmp(sep.arg[0], "") == 0){
/* Hit Enter with no command */
}
else {
SendMessage(1, "Command unknown.");
}
if (state == CONSOLE_STATE_CONNECTED)
SendPrompt();
break;
}
default: {
default:
break;
}
}
}
void Console::SendPrompt() {
if (tcpc->GetEcho())
SendMessage(0, "%s> ", paccountname);
void ConsoleConnection::ProcessCommand(const std::string &cmd)
{
}
void ConsoleConnection::OnDisconnect(EQ::Net::TCPConnection *c)
{
m_parent->ConnectionDisconnected(this);
}
ConsoleServer::ConsoleServer()
{
auto config = EQEmuConfig::get();
m_server.reset(new EQ::Net::TCPServer());
m_server->Listen(config->TelnetTCPPort, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
ConsoleConnection *c = new ConsoleConnection(this, connection);
m_connections.insert(std::make_pair(c->GetUUID(), std::unique_ptr<ConsoleConnection>(c)));
});
}
ConsoleServer::~ConsoleServer()
{
}
void ConsoleServer::ConnectionDisconnected(ConsoleConnection *c)
{
auto iter = m_connections.find(c->GetUUID());
if (iter != m_connections.end()) {
m_connections.erase(iter);
}
}

45
world/console.h Normal file
View File

@ -0,0 +1,45 @@
#pragma once
#include "../common/net/tcp_server.h"
#include "../common/event/timer.h"
#include <map>
#include <vector>
class ConsoleServer;
class ConsoleConnection
{
public:
ConsoleConnection(ConsoleServer *parent, std::shared_ptr<EQ::Net::TCPConnection> connection);
~ConsoleConnection();
std::string GetUUID() const { return m_uuid; }
void Clear();
void SendLine(const std::string &line);
void SendNewLine();
private:
void OnRead(EQ::Net::TCPConnection* c, const unsigned char* data, size_t sz);
void ProcessReadBuffer();
void ProcessCommand(const std::string& cmd);
void OnDisconnect(EQ::Net::TCPConnection* c);
ConsoleServer *m_parent;
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
std::string m_uuid;
std::vector<char> m_buffer;
};
class ConsoleServer
{
public:
ConsoleServer();
~ConsoleServer();
void ConnectionDisconnected(ConsoleConnection *c);
private:
std::unique_ptr<EQ::Net::TCPServer> m_server;
std::map<std::string, std::unique_ptr<ConsoleConnection>> m_connections;
friend class ConsoleConnection;
};

890
world/console.old.cpp Normal file
View File

@ -0,0 +1,890 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/global_define.h"
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "../common/version.h"
#include "console.h"
#include "zoneserver.h"
#include "worlddb.h"
#include "../common/packet_dump.h"
#include "../common/seperator.h"
#include "../common/eq_packet_structs.h"
#include "../common/eq_packet.h"
#include "login_server.h"
#include "login_server_list.h"
#include "../common/serverinfo.h"
#include "../common/md5.h"
#include "../common/opcodemgr.h"
#include "../common/rulesys.h"
#include "../common/ruletypes.h"
#include "../common/string_util.h"
#include "world_config.h"
#include "zoneserver.h"
#include "zonelist.h"
#include "clientlist.h"
#include "launcher_list.h"
#include "ucs.h"
#include "queryserv.h"
#ifdef _WINDOWS
#define snprintf _snprintf
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#endif
extern ZSList zoneserver_list;
extern uint32 numzones;
extern LoginServerList loginserverlist;
extern ClientList client_list;
extern LauncherList launcher_list;
extern UCSConnection UCSLink;
extern QueryServConnection QSLink;
extern volatile bool RunLoops;
ConsoleList console_list;
void CatchSignal(int sig_num);
Console::Console(EmuTCPConnection* itcpc)
: WorldTCPConnection(),
timeout_timer(RuleI(Console, SessionTimeOut)),
prompt_timer(1)
{
tcpc = itcpc;
tcpc->SetEcho(true);
state = 0;
paccountid = 0;
memset(paccountname, 0, sizeof(paccountname));
admin = 0;
pAcceptMessages = false;
}
Console::~Console() {
if (tcpc)
tcpc->Free();
}
void Console::Die() {
state = CONSOLE_STATE_CLOSED;
struct in_addr in;
in.s_addr = GetIP();
Log(Logs::Detail, Logs::World_Server,"Removing console from %s:%d",inet_ntoa(in),GetPort());
tcpc->Disconnect();
}
bool Console::SendChannelMessage(const ServerChannelMessage_Struct* scm) {
if (!pAcceptMessages)
return false;
switch (scm->chan_num) {
if(RuleB(Chat, ServerWideAuction)){
case 4: {
SendMessage(1, "%s auctions, '%s'", scm->from, scm->message);
break;
}
}
if(RuleB(Chat, ServerWideOOC)){
case 5: {
SendMessage(1, "%s says ooc, '%s'", scm->from, scm->message);
break;
}
}
case 6: {
SendMessage(1, "%s BROADCASTS, '%s'", scm->from, scm->message);
break;
}
case 7: {
SendMessage(1, "[%s] tells you, '%s'", scm->from, scm->message);
auto pack = new ServerPacket(ServerOP_ChannelMessage,
sizeof(ServerChannelMessage_Struct) + strlen(scm->message) + 1);
memcpy(pack->pBuffer, scm, pack->size);
ServerChannelMessage_Struct* scm2 = (ServerChannelMessage_Struct*) pack->pBuffer;
strcpy(scm2->deliverto, scm2->from);
scm2->noreply = true;
client_list.SendPacket(scm->from, pack);
safe_delete(pack);
break;
}
case 11: {
SendMessage(1, "%s GMSAYS, '%s'", scm->from, scm->message);
break;
}
default: {
return false;
}
}
return true;
}
bool Console::SendEmoteMessage(uint32 type, const char* message, ...) {
if (!message)
return false;
if (!pAcceptMessages)
return false;
va_list argptr;
char buffer[1024];
va_start(argptr, message);
vsnprintf(buffer, sizeof(buffer), message, argptr);
va_end(argptr);
SendMessage(1, message);
return true;
}
bool Console::SendEmoteMessageRaw(uint32 type, const char* message) {
if (!message)
return false;
if (!pAcceptMessages)
return false;
SendMessage(1, message);
return true;
}
void Console::SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...) {
if (!message)
return;
if (to_guilddbid != 0 || to_minstatus > Admin())
return;
va_list argptr;
char buffer[1024];
va_start(argptr, message);
vsnprintf(buffer, sizeof(buffer), message, argptr);
va_end(argptr);
SendEmoteMessageRaw(to, to_guilddbid, to_minstatus, type, buffer);
}
void Console::SendEmoteMessageRaw(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message) {
if (!message)
return;
if (to_guilddbid != 0 || to_minstatus > Admin())
return;
SendMessage(1, message);
}
void Console::SendMessage(uint8 newline, const char* message, ...) {
if (!message)
return;
char* buffer = 0;
uint32 bufsize = 1500;
if (message)
bufsize += strlen(message);
buffer = new char[bufsize];
memset(buffer, 0, bufsize);
if (message != 0) {
va_list argptr;
va_start(argptr, message);
vsnprintf(buffer, bufsize - 512, message, argptr);
va_end(argptr);
}
if (newline) {
char outbuf[3];
outbuf[0] = 13;
outbuf[1] = 10;
outbuf[2] = 0;
for (int i=0; i < newline; i++)
strcat(buffer, outbuf);
}
tcpc->Send((uchar*) buffer, strlen(buffer));
safe_delete_array(buffer);
}
bool Console::Process() {
if (state == CONSOLE_STATE_CLOSED)
return false;
if (!tcpc->Connected()) {
struct in_addr in;
in.s_addr = GetIP();
Log(Logs::Detail, Logs::World_Server,"Removing console (!tcpc->Connected) from %s:%d",inet_ntoa(in),GetPort());
return false;
}
//if we have not gotten the special markers after this timer, send login prompt
if(prompt_timer.Check()) {
struct in_addr in;
in.s_addr = GetIP();
std::string connecting_ip = inet_ntoa(in);
SendMessage(2, StringFormat("Establishing connection from IP: %s Port: %d", inet_ntoa(in), GetPort()).c_str());
if (connecting_ip.find("127.0.0.1") != std::string::npos) {
SendMessage(2, StringFormat("Connecting established from local host, auto assuming admin").c_str());
state = CONSOLE_STATE_CONNECTED;
tcpc->SetEcho(false);
admin = 255;
SendPrompt();
}
else {
if (tcpc->GetMode() == EmuTCPConnection::modeConsole)
tcpc->Send((const uchar*) "Username: ", strlen("Username: "));
}
prompt_timer.Disable();
}
if (timeout_timer.Check()) {
SendMessage(1, 0);
SendMessage(1, "Timeout, disconnecting...");
struct in_addr in;
in.s_addr = GetIP();
Log(Logs::Detail, Logs::World_Server,"TCP connection timeout from %s:%d",inet_ntoa(in),GetPort());
return false;
}
if (tcpc->GetMode() == EmuTCPConnection::modePacket) {
struct in_addr in;
in.s_addr = GetIP();
if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeZone) {
auto zs = new ZoneServer(tcpc);
Log(Logs::Detail, Logs::World_Server,"New zoneserver #%d from %s:%d", zs->GetID(), inet_ntoa(in), GetPort());
zoneserver_list.Add(zs);
numzones++;
tcpc = 0;
} else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeLauncher) {
Log(Logs::Detail, Logs::World_Server,"New launcher from %s:%d", inet_ntoa(in), GetPort());
launcher_list.Add(tcpc);
tcpc = 0;
}
else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeUCS)
{
Log(Logs::Detail, Logs::World_Server,"New UCS Connection from %s:%d", inet_ntoa(in), GetPort());
UCSLink.SetConnection(tcpc);
tcpc = 0;
}
else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeQueryServ)
{
Log(Logs::Detail, Logs::World_Server,"New QS Connection from %s:%d", inet_ntoa(in), GetPort());
QSLink.SetConnection(tcpc);
tcpc = 0;
}
else {
Log(Logs::Detail, Logs::World_Server,"Unsupported packet mode from %s:%d", inet_ntoa(in), GetPort());
}
return false;
}
char* command = 0;
while ((command = tcpc->PopLine())) {
timeout_timer.Start();
ProcessCommand(command);
delete command;
}
return true;
}
void ConsoleList::Add(Console* con) {
list.Insert(con);
}
void ConsoleList::Process() {
LinkedListIterator<Console*> iterator(list);
iterator.Reset();
while(iterator.MoreElements()) {
if (!iterator.GetData()->Process())
iterator.RemoveCurrent();
else
iterator.Advance();
}
}
void ConsoleList::KillAll() {
LinkedListIterator<Console*> iterator(list);
iterator.Reset();
while(iterator.MoreElements()) {
iterator.GetData()->Die();
iterator.RemoveCurrent();
}
}
void ConsoleList::SendConsoleWho(WorldTCPConnection* connection, const char* to, int16 admin, char** output, uint32* outsize, uint32* outlen) {
LinkedListIterator<Console*> iterator(list);
iterator.Reset();
struct in_addr in;
int x = 0;
while(iterator.MoreElements()) {
in.s_addr = iterator.GetData()->GetIP();
if (admin >= iterator.GetData()->Admin())
AppendAnyLenString(output, outsize, outlen, " Console: %s:%i AccID: %i AccName: %s", inet_ntoa(in), iterator.GetData()->GetPort(), iterator.GetData()->AccountID(), iterator.GetData()->AccountName());
else
AppendAnyLenString(output, outsize, outlen, " Console: AccID: %i AccName: %s", iterator.GetData()->AccountID(), iterator.GetData()->AccountName());
if (*outlen >= 3584) {
connection->SendEmoteMessageRaw(to, 0, 0, 10, *output);
safe_delete(*output);
*outsize = 0;
*outlen = 0;
}
else {
if (connection->IsConsole())
AppendAnyLenString(output, outsize, outlen, "\r\n");
else
AppendAnyLenString(output, outsize, outlen, "\n");
}
x++;
iterator.Advance();
}
AppendAnyLenString(output, outsize, outlen, "%i consoles connected", x);
}
void ConsoleList::SendChannelMessage(const ServerChannelMessage_Struct* scm) {
LinkedListIterator<Console*> iterator(list);
iterator.Reset();
while(iterator.MoreElements()) {
iterator.GetData()->SendChannelMessage(scm);
iterator.Advance();
}
}
void ConsoleList::SendEmoteMessage(uint32 type, const char* message, ...) {
va_list argptr;
char buffer[1024];
va_start(argptr, message);
vsnprintf(buffer, sizeof(buffer), message, argptr);
va_end(argptr);
SendEmoteMessageRaw(type, buffer);
}
void ConsoleList::SendEmoteMessageRaw(uint32 type, const char* message) {
LinkedListIterator<Console*> iterator(list);
iterator.Reset();
while(iterator.MoreElements()) {
iterator.GetData()->SendEmoteMessageRaw(type, message);
iterator.Advance();
}
}
Console* ConsoleList::FindByAccountName(const char* accname) {
LinkedListIterator<Console*> iterator(list);
iterator.Reset();
while(iterator.MoreElements()) {
if (strcasecmp(iterator.GetData()->AccountName(), accname) == 0)
return iterator.GetData();
iterator.Advance();
}
return 0;
}
void Console::ProcessCommand(const char* command) {
switch(state)
{
case CONSOLE_STATE_USERNAME:
{
if (strlen(command) >= 16) {
SendMessage(1, 0);
SendMessage(2, "Username buffer overflow.");
SendMessage(1, "Bye Bye.");
state = CONSOLE_STATE_CLOSED;
return;
}
strcpy(paccountname, command);
state = CONSOLE_STATE_PASSWORD;
SendMessage(0, "Password: ");
tcpc->SetEcho(false);
break;
}
case CONSOLE_STATE_PASSWORD:
{
if (strlen(command) >= 16) {
SendMessage(1, 0);
SendMessage(2, "Password buffer overflow.");
SendMessage(1, "Bye Bye.");
state = CONSOLE_STATE_CLOSED;
return;
}
paccountid = database.CheckLogin(paccountname ,command);
if (paccountid == 0) {
SendMessage(1, 0);
SendMessage(2, "Login failed.");
SendMessage(1, "Bye Bye.");
state = CONSOLE_STATE_CLOSED;
return;
}
database.GetAccountName(paccountid, paccountname); // fixes case and stuff
admin = database.CheckStatus(paccountid);
if (!(admin >= consoleLoginStatus)) {
SendMessage(1, 0);
SendMessage(2, "Access denied.");
SendMessage(1, "Bye Bye.");
state = CONSOLE_STATE_CLOSED;
return;
}
Log(Logs::Detail, Logs::World_Server,"TCP console authenticated: Username=%s, Admin=%d",paccountname,admin);
SendMessage(1, 0);
SendMessage(2, "Login accepted.");
state = CONSOLE_STATE_CONNECTED;
tcpc->SetEcho(true);
SendPrompt();
break;
}
case CONSOLE_STATE_CONNECTED: {
Log(Logs::Detail, Logs::World_Server,"TCP command: %s: \"%s\"",paccountname ,command);
Seperator sep(command);
if (strcasecmp(sep.arg[0], "help") == 0 || strcmp(sep.arg[0], "?") == 0) {
SendMessage(1, " whoami");
SendMessage(1, " who");
SendMessage(1, " zonestatus");
SendMessage(1, " uptime [zoneID#]");
SendMessage(1, " emote [zonename or charname or world] [type] [message]");
SendMessage(1, " echo [on/off]");
SendMessage(1, " acceptmessages [on/off]");
SendMessage(1, " tell [name] [message]");
SendMessage(1, " broadcast [message]");
SendMessage(1, " gmsay [message]");
SendMessage(1, " ooc [message]");
SendMessage(1, " auction [message]");
if (admin >= consoleKickStatus)
SendMessage(1, " kick [charname]");
if (admin >= consoleLockStatus)
SendMessage(1, " lock/unlock");
if (admin >= consoleZoneStatus) {
SendMessage(1, " zoneshutdown [zonename or ZoneServerID]");
SendMessage(1, " zonebootup [ZoneServerID] [zonename]");
SendMessage(1, " zonelock [list|lock|unlock] [zonename]");
}
if (admin >= consoleFlagStatus)
SendMessage(1, " flag [status] [accountname]");
if (admin >= consolePassStatus)
SendMessage(1, " setpass [accountname] [newpass]");
if (admin >= consoleWorldStatus) {
SendMessage(1, " version");
SendMessage(1, " worldshutdown");
}
if (admin >= 201) {
SendMessage(1, " IPLookup [name]");
}
if (admin >= 100) {
SendMessage(1, " LSReconnect");
SendMessage(1, " signalcharbyname charname ID");
SendMessage(1, " reloadworld");
}
}
else if (strcasecmp(sep.arg[0], "ping") == 0) {
// do nothing
}
else if (strcasecmp(sep.arg[0], "signalcharbyname") == 0) {
SendMessage(1, "Signal Sent to %s with ID %i", (char*) sep.arg[1], atoi(sep.arg[2]));
uint32 message_len = strlen((char*) sep.arg[1]) + 1;
auto pack = new ServerPacket(ServerOP_CZSignalClientByName,
sizeof(CZClientSignalByName_Struct) + message_len);
CZClientSignalByName_Struct* CZSC = (CZClientSignalByName_Struct*) pack->pBuffer;
strn0cpy(CZSC->Name, (char*) sep.arg[1], 64);
CZSC->data = atoi(sep.arg[2]);
zoneserver_list.SendPacket(pack);
safe_delete(pack);
}
else if (strcasecmp(sep.arg[0], "setpass") == 0 && admin >= consolePassStatus) {
if (sep.argnum != 2)
SendMessage(1, "Format: setpass accountname password");
else {
int16 tmpstatus = 0;
uint32 tmpid = database.GetAccountIDByName(sep.arg[1], &tmpstatus);
if (!tmpid)
SendMessage(1, "Error: Account not found");
else if (tmpstatus > admin)
SendMessage(1, "Cannot change password: Account's status is higher than yours");
else if (database.SetLocalPassword(tmpid, sep.arg[2]))
SendMessage(1, "Password changed.");
else
SendMessage(1, "Error changing password.");
}
}
else if (strcasecmp(sep.arg[0], "uptime") == 0) {
if (sep.IsNumber(1) && atoi(sep.arg[1]) > 0) {
auto pack = new ServerPacket(ServerOP_Uptime, sizeof(ServerUptime_Struct));
ServerUptime_Struct* sus = (ServerUptime_Struct*) pack->pBuffer;
snprintf(sus->adminname, sizeof(sus->adminname), "*%s", this->GetName());
sus->zoneserverid = atoi(sep.arg[1]);
ZoneServer* zs = zoneserver_list.FindByID(sus->zoneserverid);
if (zs)
zs->SendPacket(pack);
else
SendMessage(1, "Zoneserver not found.");
delete pack;
}
else {
ZSList::ShowUpTime(this);
}
}
else if (strcasecmp(sep.arg[0], "md5") == 0) {
uint8 md5[16];
MD5::Generate((const uchar*) sep.argplus[1], strlen(sep.argplus[1]), md5);
SendMessage(1, "MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7], md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15]);
}
else if (strcasecmp(sep.arg[0], "whoami") == 0) {
SendMessage(1, "You are logged in as '%s'", this->AccountName());
SendMessage(1, "You are known as '*%s'", this->AccountName());
SendMessage(1, "AccessLevel: %d", this->Admin());
}
else if (strcasecmp(sep.arg[0], "echo") == 0) {
if (strcasecmp(sep.arg[1], "on") == 0)
tcpc->SetEcho(true);
else if (strcasecmp(sep.arg[1], "off") == 0) {
if (pAcceptMessages)
SendMessage(1, "Echo can not be turned off while acceptmessages is on");
else
tcpc->SetEcho(false);
}
else
SendMessage(1, "Usage: echo [on/off]");
}
else if (strcasecmp(sep.arg[0], "acceptmessages") == 0) {
if (strcasecmp(sep.arg[1], "on") == 0)
if (tcpc->GetEcho())
SendMessage(1, "AcceptMessages can not be turned on while echo is on");
else
pAcceptMessages = true;
else if (strcasecmp(sep.arg[1], "off") == 0)
pAcceptMessages = false;
else
SendMessage(1, "Usage: acceptmessages [on/off]");
}
else if (strcasecmp(sep.arg[0], "tell") == 0) {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
zoneserver_list.SendChannelMessage(tmpname, sep.arg[1], 7, 0, sep.argplus[2]);
}
else if (strcasecmp(sep.arg[0], "broadcast") == 0) {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
zoneserver_list.SendChannelMessage(tmpname, 0, 6, 0, sep.argplus[1]);
}
else if (strcasecmp(sep.arg[0], "ooc") == 0) {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
zoneserver_list.SendChannelMessage(tmpname, 0, 5, 0, sep.argplus[1]);
}
else if (strcasecmp(sep.arg[0], "auction") == 0) {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
zoneserver_list.SendChannelMessage(tmpname, 0, 4, 0, sep.argplus[1]);
}
else if (strcasecmp(sep.arg[0], "gmsay") == 0 || strcasecmp(sep.arg[0], "pr") == 0) {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
zoneserver_list.SendChannelMessage(tmpname, 0, 11, 0, sep.argplus[1]);
}
else if (strcasecmp(sep.arg[0], "emote") == 0) {
if (strcasecmp(sep.arg[1], "world") == 0)
zoneserver_list.SendEmoteMessageRaw(0, 0, 0, atoi(sep.arg[2]), sep.argplus[3]);
else {
ZoneServer* zs = zoneserver_list.FindByName(sep.arg[1]);
if (zs != 0)
zs->SendEmoteMessageRaw(0, 0, 0, atoi(sep.arg[2]), sep.argplus[3]);
else
zoneserver_list.SendEmoteMessageRaw(sep.arg[1], 0, 0, atoi(sep.arg[2]), sep.argplus[3]);
}
}
else if (strcasecmp(sep.arg[0], "movechar") == 0) {
if(sep.arg[1][0]==0 || sep.arg[2][0] == 0)
SendMessage(1, "Usage: movechar [charactername] [zonename]");
else {
if (!database.GetZoneID(sep.arg[2]))
SendMessage(1, "Error: Zone '%s' not found", sep.arg[2]);
else if (!database.CheckUsedName((char*) sep.arg[1])) {
if (!database.MoveCharacterToZone((char*) sep.arg[1], (char*) sep.arg[2]))
SendMessage(1, "Character Move Failed!");
else
SendMessage(1, "Character has been moved.");
}
else
SendMessage(1, "Character Does Not Exist");
}
}
else if (strcasecmp(sep.arg[0], "flag") == 0 && this->Admin() >= consoleFlagStatus) {
// SCORPIOUS2K - reversed parameter order for flag
if(sep.arg[2][0]==0 || !sep.IsNumber(1))
SendMessage(1, "Usage: flag [status] [accountname]");
else
{
if (atoi(sep.arg[1]) > this->Admin())
SendMessage(1, "You cannot set people's status to higher than your own");
else if (atoi(sep.arg[1]) < 0 && this->Admin() < consoleFlagStatus)
SendMessage(1, "You have too low of status to change flags");
else if (!database.SetAccountStatus(sep.arg[2], atoi(sep.arg[1])))
SendMessage(1, "Unable to flag account!");
else
SendMessage(1, "Account Flaged");
}
}
else if (strcasecmp(sep.arg[0], "kick") == 0 && admin >= consoleKickStatus) {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
auto pack = new ServerPacket;
pack->opcode = ServerOP_KickPlayer;
pack->size = sizeof(ServerKickPlayer_Struct);
pack->pBuffer = new uchar[pack->size];
ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*) pack->pBuffer;
strcpy(skp->adminname, tmpname);
strcpy(skp->name, sep.arg[1]);
skp->adminrank = this->Admin();
zoneserver_list.SendPacket(pack);
delete pack;
}
else if (strcasecmp(sep.arg[0], "who") == 0) {
auto whom = new Who_All_Struct;
memset(whom, 0, sizeof(Who_All_Struct));
whom->lvllow = 0xFFFF;
whom->lvlhigh = 0xFFFF;
whom->wclass = 0xFFFF;
whom->wrace = 0xFFFF;
whom->gmlookup = 0xFFFF;
for (int i=1; i<=sep.argnum; i++) {
if (strcasecmp(sep.arg[i], "gm") == 0)
whom->gmlookup = 1;
else if (sep.IsNumber(i)) {
if (whom->lvllow == 0xFFFF) {
whom->lvllow = atoi(sep.arg[i]);
whom->lvlhigh = whom->lvllow;
}
else if (atoi(sep.arg[i]) > int(whom->lvllow))
whom->lvlhigh = atoi(sep.arg[i]);
else
whom->lvllow = atoi(sep.arg[i]);
}
else
strn0cpy(whom->whom, sep.arg[i], sizeof(whom->whom));
}
client_list.ConsoleSendWhoAll(0, admin, whom, this);
delete whom;
}
else if (strcasecmp(sep.arg[0], "zonestatus") == 0) {
zoneserver_list.SendZoneStatus(0, admin, this);
}
else if (strcasecmp(sep.arg[0], "exit") == 0 || strcasecmp(sep.arg[0], "quit") == 0) {
SendMessage(1, "Bye Bye.");
state = CONSOLE_STATE_CLOSED;
}
else if (strcasecmp(sep.arg[0], "zoneshutdown") == 0 && admin >= consoleZoneStatus) {
if (sep.arg[1][0] == 0) {
SendMessage(1, "Usage: zoneshutdown zoneshortname");
} else {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
auto pack = new ServerPacket;
pack->size = sizeof(ServerZoneStateChange_struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, sizeof(ServerZoneStateChange_struct));
ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer;
pack->opcode = ServerOP_ZoneShutdown;
strcpy(s->adminname, tmpname);
if (sep.arg[1][0] >= '0' && sep.arg[1][0] <= '9')
s->ZoneServerID = atoi(sep.arg[1]);
else
s->zoneid = database.GetZoneID(sep.arg[1]);
ZoneServer* zs = 0;
if (s->ZoneServerID != 0)
zs = zoneserver_list.FindByID(s->ZoneServerID);
else if (s->zoneid != 0)
zs = zoneserver_list.FindByName(database.GetZoneName(s->zoneid));
else
SendMessage(1, "Error: ZoneShutdown: neither ID nor name specified");
if (zs == 0)
SendMessage(1, "Error: ZoneShutdown: zoneserver not found");
else
zs->SendPacket(pack);
delete pack;
}
}
else if (strcasecmp(sep.arg[0], "zonebootup") == 0 && admin >= consoleZoneStatus) {
if (sep.arg[2][0] == 0 || !sep.IsNumber(1)) {
SendMessage(1, "Usage: zonebootup ZoneServerID# zoneshortname");
} else {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], paccountname);
Log(Logs::Detail, Logs::World_Server,"Console ZoneBootup: %s, %s, %s",tmpname,sep.arg[2],sep.arg[1]);
zoneserver_list.SOPZoneBootup(tmpname, atoi(sep.arg[1]), sep.arg[2], (bool) (strcasecmp(sep.arg[3], "static") == 0));
}
}
else if (strcasecmp(sep.arg[0], "worldshutdown") == 0 && admin >= consoleWorldStatus) {
int32 time, interval;
if(sep.IsNumber(1) && sep.IsNumber(2) && ((time=atoi(sep.arg[1]))>0) && ((interval=atoi(sep.arg[2]))>0)) {
zoneserver_list.WorldShutDown(time, interval);
}
else if(strcasecmp(sep.arg[1], "now") == 0) {
zoneserver_list.WorldShutDown(0, 0);
}
else if(strcasecmp(sep.arg[1], "disable") == 0) {
SendEmoteMessage(0,0,0,15,"<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World shutdown aborted.");
zoneserver_list.SendEmoteMessage(0,0,0,15,"<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World shutdown aborted.");
zoneserver_list.shutdowntimer->Disable();
zoneserver_list.reminder->Disable();
}
else {
SendMessage(1, "Usage: worldshutdown [now] [disable] ([time] [interval])");
//Go ahead and shut down since that's what this used to do when invoked this way.
zoneserver_list.WorldShutDown(0, 0);
}
}
else if (strcasecmp(sep.arg[0], "lock") == 0 && admin >= consoleLockStatus) {
WorldConfig::LockWorld();
if (loginserverlist.Connected()) {
loginserverlist.SendStatus();
SendMessage(1, "World locked.");
}
else {
SendMessage(1, "World locked, but login server not connected.");
}
}
else if (strcasecmp(sep.arg[0], "unlock") == 0 && admin >= consoleLockStatus) {
WorldConfig::UnlockWorld();
if (loginserverlist.Connected()) {
loginserverlist.SendStatus();
SendMessage(1, "World unlocked.");
}
else {
SendMessage(1, "World unlocked, but login server not connected.");
}
}
else if (strcasecmp(sep.arg[0], "version") == 0 && admin >= consoleWorldStatus) {
SendMessage(1, "Current version information.");
SendMessage(1, " %s", CURRENT_VERSION);
SendMessage(1, " Compiled on: %s at %s", COMPILE_DATE, COMPILE_TIME);
SendMessage(1, " Last modified on: %s", LAST_MODIFIED);
}
else if (strcasecmp(sep.arg[0], "serverinfo") == 0 && admin >= 200) {
if (strcasecmp(sep.arg[1], "os") == 0) {
#ifdef _WINDOWS
GetOS();
char intbuffer [sizeof(unsigned long)];
SendMessage(1, "Operating system information.");
SendMessage(1, " %s", Ver_name);
SendMessage(1, " Build number: %s", ultoa(Ver_build, intbuffer, 10));
SendMessage(1, " Minor version: %s", ultoa(Ver_min, intbuffer, 10));
SendMessage(1, " Major version: %s", ultoa(Ver_maj, intbuffer, 10));
SendMessage(1, " Platform Id: %s", ultoa(Ver_pid, intbuffer, 10));
#else
char os_string[100];
SendMessage(1, "Operating system information.");
SendMessage(1, " %s", GetOS(os_string));
#endif
}
else {
SendMessage(1, "Usage: Serverinfo [type]");
SendMessage(1, " OS - Operating system version information.");
}
}
else if (strcasecmp(sep.arg[0], "IPLookup") == 0 && admin >= 201) {
client_list.SendCLEList(admin, 0, this, sep.argplus[1]);
}
else if (strcasecmp(sep.arg[0], "LSReconnect") == 0 && admin >= 100) {
#ifdef _WINDOWS
_beginthread(AutoInitLoginServer, 0, nullptr);
#else
pthread_t thread;
pthread_create(&thread, nullptr, &AutoInitLoginServer, nullptr);
#endif
RunLoops = true;
SendMessage(1, " Login Server Reconnect manually restarted by Console");
Log(Logs::Detail, Logs::World_Server,"Login Server Reconnect manually restarted by Console");
}
else if (strcasecmp(sep.arg[0], "zonelock") == 0 && admin >= consoleZoneStatus) {
if (strcasecmp(sep.arg[1], "list") == 0) {
zoneserver_list.ListLockedZones(0, this);
}
else if (strcasecmp(sep.arg[1], "lock") == 0 && admin >= 101) {
uint16 tmp = database.GetZoneID(sep.arg[2]);
if (tmp) {
if (zoneserver_list.SetLockedZone(tmp, true))
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone locked: %s", database.GetZoneName(tmp));
else
SendMessage(1, "Failed to change lock");
}
else
SendMessage(1, "Usage: #zonelock lock [zonename]");
}
else if (strcasecmp(sep.arg[1], "unlock") == 0 && admin >= 101) {
uint16 tmp = database.GetZoneID(sep.arg[2]);
if (tmp) {
if (zoneserver_list.SetLockedZone(tmp, false))
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone unlocked: %s", database.GetZoneName(tmp));
else
SendMessage(1, "Failed to change lock");
}
else
SendMessage(1, "Usage: #zonelock unlock [zonename]");
}
else {
SendMessage(1, "#zonelock sub-commands");
SendMessage(1, " list");
if (admin >= 101) {
SendMessage(1, " lock [zonename]");
SendMessage(1, " unlock [zonename]");
}
}
}
else if (strcasecmp(sep.arg[0], "reloadworld") == 0 && admin > 101)
{
SendEmoteMessage(0,0,0,15,"Reloading World...");
auto pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct));
ReloadWorld_Struct* RW = (ReloadWorld_Struct*) pack->pBuffer;
RW->Option = 1;
zoneserver_list.SendPacket(pack);
safe_delete(pack);
}
else if (strcasecmp(sep.arg[0], "") == 0){
/* Hit Enter with no command */
}
else {
SendMessage(1, "Command unknown.");
}
if (state == CONSOLE_STATE_CONNECTED)
SendPrompt();
break;
}
default: {
break;
}
}
}
void Console::SendPrompt() {
if (tcpc->GetEcho())
SendMessage(0, "%s> ", paccountname);
}

View File

@ -81,6 +81,7 @@ union semun {
#include "ucs.h"
#include "queryserv.h"
#include "web_interface.h"
#include "console.h"
#include "../common/net/tcp_server.h"
#include "../common/net/servertalk_server.h"
@ -375,6 +376,12 @@ int main(int argc, char** argv) {
database.LoadCharacterCreateAllocations();
database.LoadCharacterCreateCombos();
std::unique_ptr<ConsoleServer> console;
if (Config->TelnetEnabled) {
Log(Logs::General, Logs::World_Server, "Console (TCP) listener started.");
console.reset(new ConsoleServer());
}
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
server_connection.reset(new EQ::Net::ServertalkServer());