eqemu-server/world/console.cpp
2019-03-10 00:10:47 -08:00

507 lines
21 KiB
C++

#include "console.h"
#include "clientlist.h"
#include "login_server.h"
#include "login_server_list.h"
#include "world_config.h"
#include "world_console_connection.h"
#include "worlddb.h"
#include "zonelist.h"
#include "zoneserver.h"
#include "../common/string_util.h"
#include "../common/md5.h"
#include <fmt/format.h>
extern ClientList client_list;
extern ZSList zoneserver_list;
extern LoginServerList loginserverlist;
struct EQ::Net::ConsoleLoginStatus CheckLogin(const std::string& username, const std::string& password) {
struct EQ::Net::ConsoleLoginStatus ret;
ret.account_id = database.CheckLogin(username.c_str(), password.c_str());
if (ret.account_id == 0) {
return ret;
}
char account_name[64];
database.GetAccountName(ret.account_id, account_name);
ret.account_name = account_name;
ret.status = database.CheckStatus(ret.account_id);
return ret;
}
void ConsoleNull(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
}
void ConsoleWhoami(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
connection->SendLine(fmt::format("You are logged in as '{0}'", connection->UserName()));
connection->SendLine(fmt::format("You are known as '*{0}'", connection->UserName()));
connection->SendLine(fmt::format("AccessLevel: '{0}'", connection->Admin()));
}
void ConsoleZoneStatus(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
WorldConsoleTCPConnection console_connection(connection);
zoneserver_list.SendZoneStatus(0, connection->Admin(), &console_connection);
}
void ConsoleWho(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
Who_All_Struct whom;
memset(&whom, 0, sizeof(whom));
whom.lvllow = 0xFFFF;
whom.lvlhigh = 0xFFFF;
whom.wclass = 0xFFFF;
whom.wrace = 0xFFFF;
whom.gmlookup = 0xFFFF;
for (auto &arg : args) {
if (strcasecmp(arg.c_str(), "gm") == 0) {
whom.gmlookup = 1;
}
else if (StringIsNumber(arg)) {
if (whom.lvllow == 0xFFFF) {
whom.lvllow = atoi(arg.c_str());
whom.lvlhigh = whom.lvllow;
}
else if (atoi(arg.c_str()) > int(whom.lvllow))
whom.lvlhigh = atoi(arg.c_str());
else
whom.lvllow = atoi(arg.c_str());
}
else {
strn0cpy(whom.whom, arg.c_str(), sizeof(whom.whom));
}
}
WorldConsoleTCPConnection console_connection(connection);
client_list.ConsoleSendWhoAll(0, connection->Admin(), &whom, &console_connection);
}
void ConsoleUptime(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 1) {
return;
}
if (StringIsNumber(args[0]) && atoi(args[0].c_str()) > 0) {
auto pack = new ServerPacket(ServerOP_Uptime, sizeof(ServerUptime_Struct));
ServerUptime_Struct* sus = (ServerUptime_Struct*)pack->pBuffer;
snprintf(sus->adminname, sizeof(sus->adminname), "*%s", connection->UserName().c_str());
sus->zoneserverid = atoi(args[0].c_str());
ZoneServer* zs = zoneserver_list.FindByID(sus->zoneserverid);
if (zs)
zs->SendPacket(pack);
else
connection->SendLine("Zoneserver not found.");
delete pack;
}
else {
WorldConsoleTCPConnection console_connection(connection);
ZSList::ShowUpTime(&console_connection);
}
}
void ConsoleMd5(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 1) {
return;
}
uint8 md5[16];
MD5::Generate((const uchar*)args[0].c_str(), strlen(args[0].c_str()), md5);
connection->SendLine(StringFormat("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]));
}
void ConsoleEmote(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 3) {
return;
}
auto join_args = args;
join_args.erase(join_args.begin(), join_args.begin() + 2);
if (strcasecmp(args[0].c_str(), "world") == 0)
zoneserver_list.SendEmoteMessageRaw(0, 0, 0, atoi(args[1].c_str()), JoinString(join_args, " ").c_str());
else {
ZoneServer* zs = zoneserver_list.FindByName(args[0].c_str());
if (zs != 0)
zs->SendEmoteMessageRaw(0, 0, 0, atoi(args[1].c_str()), JoinString(join_args, " ").c_str());
else
zoneserver_list.SendEmoteMessageRaw(args[0].c_str(), 0, 0, atoi(args[1].c_str()), JoinString(join_args, " ").c_str());
}
}
void ConsoleAcceptMessages(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 1) {
connection->SendLine("Usage: acceptmessages [on/off]");
return;
}
if (strcasecmp(args[0].c_str(), "on") == 0)
connection->SetAcceptMessages(true);
else if (strcasecmp(args[0].c_str(), "off") == 0)
connection->SetAcceptMessages(false);
else
connection->SendLine("Usage: acceptmessages [on/off]");
}
void ConsoleTell(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 2) {
return;
}
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], connection->UserName().c_str());
std::string to = args[0];
auto join_args = args;
join_args.erase(join_args.begin(), join_args.begin() + 1);
zoneserver_list.SendChannelMessage(tmpname, to.c_str(), 7, 0, JoinString(join_args, " ").c_str());
}
void ConsoleBroadcast(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 1) {
return;
}
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], connection->UserName().c_str());
zoneserver_list.SendChannelMessage(tmpname, 0, 6, 0, JoinString(args, " ").c_str());
}
void ConsoleGMSay(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 1) {
return;
}
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], connection->UserName().c_str());
zoneserver_list.SendChannelMessage(tmpname, 0, 11, 0, JoinString(args, " ").c_str());
}
void ConsoleOOC(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 1) {
return;
}
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], connection->UserName().c_str());
zoneserver_list.SendChannelMessage(tmpname, 0, 5, 0, JoinString(args, " ").c_str());
}
void ConsoleAuction(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 1) {
return;
}
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], connection->UserName().c_str());
zoneserver_list.SendChannelMessage(tmpname, 0, 4, 0, JoinString(args, " ").c_str());
}
void ConsoleKick(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 1) {
return;
}
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], connection->UserName().c_str());
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, args[0].c_str());
skp->adminrank = connection->Admin();
zoneserver_list.SendPacket(pack);
delete pack;
}
void ConsoleLock(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
WorldConfig::LockWorld();
if (loginserverlist.Connected()) {
loginserverlist.SendStatus();
connection->SendLine("World locked.");
}
else {
connection->SendLine("World locked, but login server not connected.");
}
}
void ConsoleUnlock(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
WorldConfig::UnlockWorld();
if (loginserverlist.Connected()) {
loginserverlist.SendStatus();
connection->SendLine("World unlocked.");
}
else {
connection->SendLine("World unlocked, but login server not connected.");
}
}
void ConsoleZoneShutdown(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 1) {
connection->SendLine("Usage: zoneshutdown zoneshortname");
return;
}
if (args[0].length() == 0) {
connection->SendLine("Usage: zoneshutdown zoneshortname");
}
else {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], connection->UserName().c_str());
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 (StringIsNumber(args[0]))
s->ZoneServerID = atoi(args[0].c_str());
else
s->zoneid = database.GetZoneID(args[0].c_str());
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
connection->SendLine("Error: ZoneShutdown: neither ID nor name specified");
if (zs == 0)
connection->SendLine("Error: ZoneShutdown: zoneserver not found");
else
zs->SendPacket(pack);
delete pack;
}
}
void ConsoleZoneBootup(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 2) {
return;
}
if (args[1].length() == 0 || !StringIsNumber(args[0])) {
connection->SendLine("Usage: zonebootup ZoneServerID# zoneshortname");
}
else {
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], connection->UserName().c_str());
Log(Logs::Detail, Logs::World_Server, "Console ZoneBootup: %s, %s, %s", tmpname, args[1].c_str(), args[0].c_str());
if (args.size() > 2) {
zoneserver_list.SOPZoneBootup(tmpname, atoi(args[0].c_str()), args[1].c_str(), (bool)(strcasecmp(args[1].c_str(), "static") == 0));
}
else {
zoneserver_list.SOPZoneBootup(tmpname, atoi(args[0].c_str()), args[1].c_str(), false);
}
}
}
void ConsoleZoneLock(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 1) {
return;
}
if (strcasecmp(args[0].c_str(), "list") == 0) {
WorldConsoleTCPConnection console_connection(connection);
zoneserver_list.ListLockedZones(0, &console_connection);
}
else if (strcasecmp(args[0].c_str(), "lock") == 0 && connection->Admin() >= 101) {
if (args.size() < 2) {
return;
}
uint16 tmp = database.GetZoneID(args[1].c_str());
if (tmp) {
if (zoneserver_list.SetLockedZone(tmp, true))
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone locked: %s", database.GetZoneName(tmp));
else
connection->SendLine("Failed to change lock");
}
else
connection->SendLine("Usage: #zonelock lock [zonename]");
}
else if (strcasecmp(args[0].c_str(), "unlock") == 0 && connection->Admin() >= 101) {
if (args.size() < 2) {
return;
}
uint16 tmp = database.GetZoneID(args[1].c_str());
if (tmp) {
if (zoneserver_list.SetLockedZone(tmp, false))
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone unlocked: %s", database.GetZoneName(tmp));
else
connection->SendLine("Failed to change lock");
}
else
connection->SendLine("Usage: #zonelock unlock [zonename]");
}
else {
connection->SendLine("#zonelock sub-commands");
connection->SendLine(" list");
if (connection->Admin() >= 101) {
connection->SendLine(" lock [zonename]");
connection->SendLine(" unlock [zonename]");
}
}
}
void ConsoleFlag(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 2) {
return;
}
if (args[1].length() == 0 || !StringIsNumber(args[0]))
connection->SendLine("Usage: flag [status] [accountname]");
else
{
if (atoi(args[0].c_str()) > connection->Admin())
connection->SendLine("You cannot set people's status to higher than your own");
else if (!database.SetAccountStatus(args[1].c_str(), atoi(args[0].c_str())))
connection->SendLine("Unable to flag account!");
else
connection->SendLine("Account Flaged");
}
}
void ConsoleSetPass(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() != 2) {
connection->SendLine("Format: setpass accountname password");
}
else {
int16 tmpstatus = 0;
uint32 tmpid = database.GetAccountIDByName(args[0].c_str(), &tmpstatus);
if (!tmpid)
connection->SendLine("Error: Account not found");
else if (tmpstatus > connection->Admin())
connection->SendLine("Cannot change password: Account's status is higher than yours");
else if (database.SetLocalPassword(tmpid, args[1].c_str()))
connection->SendLine("Password changed.");
else
connection->SendLine("Error changing password.");
}
}
void ConsoleVersion(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
connection->SendLine(StringFormat("Current version information."));
connection->SendLine(StringFormat(" %s", CURRENT_VERSION));
connection->SendLine(StringFormat(" Compiled on: %s at %s", COMPILE_DATE, COMPILE_TIME));
connection->SendLine(StringFormat(" Last modified on: %s", LAST_MODIFIED));
}
void ConsoleWorldShutdown(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() == 2) {
int32 time, interval;
if (StringIsNumber(args[0]) && StringIsNumber(args[1]) && ((time = atoi(args[0].c_str()))>0) && ((interval = atoi(args[1].c_str()))>0)) {
zoneserver_list.WorldShutDown(time, interval);
}
else {
connection->SendLine("Usage: worldshutdown [now] [disable] ([time] [interval])");
}
}
else if(args.size() == 1) {
if (strcasecmp(args[0].c_str(), "now") == 0) {
zoneserver_list.WorldShutDown(0, 0);
}
else if (strcasecmp(args[0].c_str(), "disable") == 0) {
connection->SendLine("<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 {
connection->SendLine("Usage: worldshutdown [now] [disable] ([time] [interval])");
}
}
else {
connection->SendLine("Usage: worldshutdown [now] [disable] ([time] [interval])");
}
}
void ConsoleIpLookup(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() > 0) {
WorldConsoleTCPConnection console_connection(connection);
client_list.SendCLEList(connection->Admin(), 0, &console_connection, args[0].c_str());
}
}
void ConsoleSignalCharByName(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
if (args.size() < 2) {
return;
}
connection->SendLine(StringFormat("Signal Sent to %s with ID %i", (char*) args[0].c_str(), atoi(args[1].c_str())));
uint32 message_len = strlen((char*) args[0].c_str()) + 1;
auto pack = new ServerPacket(ServerOP_CZSignalClientByName,
sizeof(CZClientSignalByName_Struct) + message_len);
CZClientSignalByName_Struct* CZSC = (CZClientSignalByName_Struct*) pack->pBuffer;
strn0cpy(CZSC->Name, (char*) args[0].c_str(), 64);
CZSC->data = atoi(args[1].c_str());
zoneserver_list.SendPacket(pack);
safe_delete(pack);
}
void ConsoleReloadWorld(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
connection->SendLine("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);
}
void ConsoleQuit(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector<std::string>& args) {
connection->SendLine("Exiting...");
connection->Close();
}
void RegisterConsoleFunctions(std::unique_ptr<EQ::Net::ConsoleServer>& console)
{
console->RegisterLogin(std::bind(CheckLogin, std::placeholders::_1, std::placeholders::_2));
console->RegisterCall("whoami", 50, "whoami", std::bind(ConsoleWhoami, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("who", 50, "who", std::bind(ConsoleWho, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("zonestatus", 50, "zonestatus", std::bind(ConsoleZoneStatus, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("uptime", 50, "uptime [zoneID#]", std::bind(ConsoleUptime, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("md5", 50, "md5", std::bind(ConsoleMd5, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("emote", 50, "emote [zonename or charname or world] [type] [message]", std::bind(ConsoleEmote, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("echo", 50, "echo [on/off]", std::bind(ConsoleNull, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("acceptmessages", 50, "acceptmessages [on/off]", std::bind(ConsoleAcceptMessages, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("tell", 50, "tell [name] [message]", std::bind(ConsoleTell, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("broadcast", 50, "broadcast [message]", std::bind(ConsoleBroadcast, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("gmsay", 50, "gmsay [message]", std::bind(ConsoleGMSay, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("ooc", 50, "ooc [message]", std::bind(ConsoleOOC, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("auction", 50, "auction [message]", std::bind(ConsoleAuction, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("kick", 150, "kick [charname]", std::bind(ConsoleKick, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("lock", 150, "lock", std::bind(ConsoleLock, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("unlock", 150, "unlock", std::bind(ConsoleUnlock, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("zoneshutdown", 150, "zoneshutdown [zonename or ZoneServerID]", std::bind(ConsoleZoneShutdown, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("zonebootup", 150, "zonebootup [ZoneServerID] [zonename]", std::bind(ConsoleZoneBootup, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("zonelock", 150, "zonelock [list|lock|unlock] [zonename]", std::bind(ConsoleZoneLock, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("flag", 200, "flag [status] [accountname]", std::bind(ConsoleFlag, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("setpass", 200, "setpass [accountname] [newpass]", std::bind(ConsoleSetPass, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("version", 50, "version", std::bind(ConsoleVersion, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("worldshutdown", 200, "worldshutdown", std::bind(ConsoleWorldShutdown, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("iplookup", 50, "IPLookup [name]", std::bind(ConsoleIpLookup, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("lsreconnect", 50, "LSReconnect", std::bind(ConsoleNull, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("signalcharbyname", 50, "signalcharbyname charname ID", std::bind(ConsoleSignalCharByName, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("reloadworld", 200, "reloadworld", std::bind(ConsoleReloadWorld, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("ping", 50, "ping", std::bind(ConsoleNull, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("quit", 50, "quit", std::bind(ConsoleQuit, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
console->RegisterCall("exit", 50, "exit", std::bind(ConsoleQuit, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
}