//////////////////////////////////////////////////////////////////////////////// // Scorched3D (c) 2000-2004 // // This file is part of Scorched3D. // // Scorched3D 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; either version 2 of the License, or // (at your option) any later version. // // Scorched3D is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; 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 Scorched3D; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct LogFile { wxString fileName; time_t fileTime; }; static inline bool lt_logfile(const LogFile &o1, const LogFile &o2) { return o1.fileTime < o2.fileTime; } static const char *getField(std::map &fields, const char *field) { std::map::iterator itor = fields.find(field); if (itor != fields.end()) { return (*itor).second.c_str(); } return 0; } static std::string getFile(const char *filename) { char buffer[100]; std::string file; FILE *in = fopen(filename, "r"); if (in) { while (fgets(buffer, 100, in)) { file += buffer; } fclose(in); } return file; } static std::string concatLines(std::list &lines) { std::string result; std::list::iterator itor; for (itor = lines.begin(); itor != lines.end(); itor++) { result.append(*itor).append("
"); } return result; } bool ServerWebHandler::PlayerHandler::processRequest(const char *url, std::map &fields, std::string &text) { // Check for an add const char *addType = getField(fields, "add"); if (addType) { TankAIAdder::addTankAI(*ScorchedServer::instance(), addType); } std::map &tanks = ScorchedServer::instance()->getTankContainer().getAllTanks(); std::map::iterator itor; // Check for any action const char *action = getField(fields, "action"); if (action) { for (itor = tanks.begin(); itor != tanks.end(); itor++) { // Is this tank selected Tank *tank = (*itor).second; if (getField(fields, formatString("player-%u", tank->getPlayerId()))) { if (0 == strcmp(action, "Kick")) { ServerCommon::kickPlayer(tank->getPlayerId()); break; } else if (0 == strcmp(action, "Mute")) { tank->getState().setMuted(true); } else if (0 == strcmp(action, "UnMute")) { tank->getState().setMuted(false); } else if (0 == strcmp(action, "Flag")) { ServerCommon::banPlayer(tank->getPlayerId(), ServerBanned::Flagged); } else if (0 == strcmp(action, "Poor")) { ServerCommon::poorPlayer(tank->getPlayerId()); } else if (0 == strcmp(action, "PermMute")) { ServerCommon::banPlayer(tank->getPlayerId(), ServerBanned::Muted); } else if (0 == strcmp(action, "UnPermMute")) { ServerCommon::banPlayer(tank->getPlayerId(), ServerBanned::NotBanned); } else if (0 == strcmp(action, "Banned")) { ServerCommon::banPlayer(tank->getPlayerId(), ServerBanned::Banned); } else if (0 == strcmp(action, "Slap")) { ServerCommon::slapPlayer(tank->getPlayerId(), 25.0f); } else if (0 == strcmp(action, "ShowAliases")) { std::list aliases = StatsLogger::instance()->getAliases(tank); fields["MESSAGE"] = concatLines(aliases); return ServerWebServer::getHtmlTemplate("message.html", fields, text); } else if (0 == strcmp(action, "ShowIPAliases")) { std::list aliases = StatsLogger::instance()->getIpAliases(tank); fields["MESSAGE"] = concatLines(aliases); return ServerWebServer::getHtmlTemplate("message.html", fields, text); } else { Logger::log(formatString("Unknown web handler player action \"%s\"", action)); } } } } // Player Entries std::string players; for (itor = tanks.begin(); itor != tanks.end(); itor++) { Tank *tank = (*itor).second; std::string cleanName; std::string dirtyName(tank->getName()); XMLNode::removeSpecialChars(dirtyName, cleanName); players += formatString( "" "dest=%i ip=%s id=%i" // Id "%s" // Name "%s" // Type "%s" // Time "%s" // Score "%s" // State "%s" // Team "" // Select "\n", tank->getDestinationId(), NetInterface::getIpName(tank->getIpAddress()), tank->getPlayerId(), cleanName.c_str(), tank->getTankAI()?tank->getTankAI()->getName():"Human", tank->getScore().getTimePlayedString(), tank->getScore().getScoreString(), tank->getState().getStateString(), TankColorGenerator::getTeamName(tank->getTeam()), tank->getPlayerId() ); } fields["PLAYERS"] = players; fields["NOPLAYERS"] = formatString("%i/%i", tanks.size(), ScorchedServer::instance()->getOptionsGame().getNoMaxPlayers()); // Add entries std::string add; std::list &ais = ScorchedServer::instance()->getTankAIs().getAis(); std::list::iterator aiitor; for (aiitor = ais.begin(); aiitor != ais.end(); aiitor++) { TankAI *ai = (*aiitor); if (ai->availableForPlayers()) { add += formatString( "", ai->getName()); } } fields["ADD"] = add; return ServerWebServer::getHtmlTemplate("player.html", fields, text); } bool ServerWebHandler::LogHandler::processRequest(const char *url, std::map &fields, std::string &text) { std::deque &entries = ServerLog::instance()->getEntries(); const int pagesize = 20; int start = (int(entries.size()) / pagesize) * pagesize; const char *page = getField(fields, "page"); if (page) start = atoi(page); else start = entries.size() - pagesize; // Log entries std::string log; int min = MAX(start, 0); int max = MIN((int) entries.size(), start + pagesize); for (int i=min; i" "%u" "%s" "\n", i, cleanText.c_str()); } fields["LOG"] = log; // Pages std::string pages; for (int i =0; i<=int(entries.size())/pagesize-1; i++) { pages += formatString("%i - %i ", fields["sid"].c_str(), i * pagesize, i * pagesize, i * pagesize + pagesize - 1); } pages += formatString("Last", fields["sid"].c_str()); fields["PAGES"] = pages; return ServerWebServer::getHtmlTemplate("log.html", fields, text); } bool ServerWebHandler::LogFileHandler::processRequest(const char *url, std::map &fields, std::string &text) { std::deque &entries = ServerLog::instance()->getEntries(); const char *logFilename = getField(fields, "filename"); if (logFilename) { text.append(formatString( "HTTP/1.1 200 OK\r\n" "Server: Scorched3D\r\n" "Content-Type: text/plain\r\n" "Content-Disposition: filename=%s.txt\r\n" "Connection: Close\r\n" "\r\n", logFilename)); const char *filename = getLogFile(logFilename); std::string file = getFile(filename); fields["FILE"] = file; return ServerWebServer::getTemplate("logfile.html", fields, text); } else { std::vector logFiles; const char *dirName = getLogFile(""); wxDir dir(wxString(dirName, wxConvUTF8)); if (dir.IsOpened()) { wxString filename; bool cont = dir.GetFirst(&filename, wxT("*.log"), wxDIR_FILES); while (cont) { const char *fullFilename = getLogFile(filename.mb_str(wxConvUTF8)); LogFile logFile; logFile.fileName = filename; logFile.fileTime = s3d_fileModTime(fullFilename); logFiles.push_back(logFile); cont = dir.GetNext(&filename); } } std::sort(logFiles.begin(), logFiles.end(), lt_logfile); std::string log; std::vector::iterator itor; for (itor = logFiles.begin(); itor != logFiles.end(); itor++) { LogFile &logFile = *itor; const char *fileName = logFile.fileName.mb_str(wxConvUTF8); log += formatString( "" "%s" "%s" "\n", fileName, fields["sid"].c_str(), fileName, ctime(&logFile.fileTime)); } fields["LOG"] = log; return ServerWebServer::getHtmlTemplate("logfiles.html", fields, text); } return false; } bool ServerWebHandler::GameHandler::processRequest(const char *url, std::map &fields, std::string &text) { // Check for any action const char *action = getField(fields, "action"); if (action) { if (0 == strcmp(action, "NewGame")) { ServerCommon::startNewGame(); } else if (0 == strcmp(action, "KillAll")) { ServerCommon::killAll(); } } std::map &tanks = ScorchedServer::instance()->getTankContainer().getPlayingTanks(); fields["PLAYERS"] = formatString("%i/%i", tanks.size(), ScorchedServer::instance()->getOptionsGame().getNoMaxPlayers()); unsigned int state = ScorchedServer::instance()->getGameState().getState(); fields["STATE"] = ((state == ServerState::ServerStateTooFewPlayers)?"Not Playing":"Playing"); fields["ROUND"] = formatString("%i/%i", ScorchedServer::instance()->getOptionsTransient().getCurrentRoundNo(), ScorchedServer::instance()->getOptionsGame().getNoRounds()); fields["MOVE"] = formatString("%i/%i", ScorchedServer::instance()->getOptionsTransient().getCurrentGameNo(), ScorchedServer::instance()->getOptionsGame().getNoMaxRoundTurns()); fields["BI"] = formatString("%uK", NetInterface::getBytesIn() / 1000); fields["BO"] = formatString("%uK", NetInterface::getBytesOut() / 1000); fields["P"] = formatString("%u", NetInterface::getPings()); fields["C"] = formatString("%u", NetInterface::getConnects()); return ServerWebServer::getHtmlTemplate("game.html", fields, text); } bool ServerWebHandler::ServerHandler::processRequest(const char *url, std::map &fields, std::string &text) { // Check for any action const char *action = getField(fields, "action"); if (action) { if (0 == strcmp(action, "Stop Server")) { exit(0); } } unsigned int state = ScorchedServer::instance()->getGameState().getState(); fields["STATE"] = ((state == ServerState::ServerStateTooFewPlayers)?"Not Playing":"Playing"); return ServerWebServer::getHtmlTemplate("server.html", fields, text); } bool ServerWebHandler::SettingsHandler::processRequest(const char *url, std::map &fields, std::string &text) { std::list::iterator itor; std::list &options = ScorchedServer::instance()->getOptionsGame(). getChangedOptions().getOptions(); const char *action = getField(fields, "action"); if (action && 0 == strcmp(action, "Load")) { ScorchedServer::instance()->getOptionsGame().getChangedOptions(). readOptionsFromFile((char *) OptionsParam::instance()->getServerFile()); } else { // Check if any changes have been made for (itor = options.begin(); itor != options.end(); itor++) { OptionEntry *entry = (*itor); std::map::iterator findItor = fields.find(entry->getName()); if (findItor != fields.end()) { const char *value = (*findItor).second.c_str(); entry->setValueFromString(value); } } } // Show the current settings std::string settings; for (itor = options.begin(); itor != options.end(); itor++) { OptionEntry *entry = (*itor); if (!(entry->getData() & OptionEntry::DataDepricated)) { std::string value; if (entry->getEntryType() == OptionEntry::OptionEntryTextType) { value = formatString("", entry->getName(), entry->getValueAsString()); } else if (entry->getEntryType() == OptionEntry::OptionEntryBoolType) { OptionEntryBool *boolEntry = (OptionEntryBool *) entry; value = formatString( "On" "Off", entry->getName(), (boolEntry->getValue()?"checked":""), entry->getName(), (!boolEntry->getValue()?"checked":"")); } else if (entry->getEntryType() == OptionEntry::OptionEntryBoundedIntType) { OptionEntryBoundedInt *intEntry = (OptionEntryBoundedInt *) entry; value = formatString(""); } else if (entry->getEntryType() == OptionEntry::OptionEntryEnumType) { OptionEntryEnum *enumEntry = (OptionEntryEnum *) entry; value = formatString(""); } else if (entry->getEntryType() == OptionEntry::OptionEntryStringEnumType) { OptionEntryStringEnum *enumEntry = (OptionEntryStringEnum *) entry; value = formatString(""); } else { value = formatString("", entry->getName(), entry->getValueAsString()); } bool different = (0 != strcmp(entry->getValueAsString(), entry->getDefaultValueAsString())); std::string desc = entry->getDescription(); desc.append("
Default value : "); if (different) desc.append(""); desc.append(entry->getDefaultValueAsString()); if (different) desc.append(""); settings += formatString("%s" "%s" "%s\n", entry->getName(), desc.c_str(), value.c_str()); } } fields["SETTINGS"] = settings; if (action && 0 == strcmp(action, "Save")) { ScorchedServer::instance()->getOptionsGame().getChangedOptions(). writeOptionsToFile((char *) OptionsParam::instance()->getServerFile()); } return ServerWebServer::getHtmlTemplate("settings.html", fields, text); } bool ServerWebHandler::TalkHandler::processRequest(const char *url, std::map &fields, std::string &text) { const char *say = getField(fields, "text"); if (say) { const char *type = getField(fields, "type"); if (!type || 0 == strcmp(type, "all")) { ServerCommon::sendString(0, say); } else if (0 == strcmp(type, "message")) { ServerCommon::sendStringMessage(0, say); } else if (0 == strcmp(type, "admin")) { ServerCommon::sendStringAdmin(say); } } std::string texts; std::list &textsList = ServerTextHandler::instance()->getLastMessages(); std::list::iterator textsListItor; for (textsListItor = textsList.begin(); textsListItor != textsList.end(); textsListItor++) { std::string cleanText; XMLNode::removeSpecialChars((*textsListItor), cleanText); texts += cleanText; texts += "
\n"; } fields["TEXTS"] = texts; const char *refreshRate = getField(fields, "RefreshRate"); int refreshSeconds = 0; if (refreshRate) refreshSeconds = atoi(refreshRate); else fields["RefreshRate"]="0"; if (refreshSeconds > 0) fields["Meta"] = formatString("", refreshSeconds, url,fields["sid"].c_str(),refreshRate); return ServerWebServer::getHtmlTemplate("talk.html", fields, text); } bool ServerWebHandler::BannedHandler::processRequest(const char *url, std::map &fields, std::string &text) { const char *action = getField(fields, "action"); if (action && 0 == strcmp(action, "Load")) ScorchedServerUtil::instance()->bannedPlayers.load(true); const char *selected = getField(fields, "selected"); std::string banned; std::list &bannedIps = ScorchedServerUtil::instance()->bannedPlayers.getBannedIps(); std::list::iterator itor; for (itor = bannedIps.begin(); itor != bannedIps.end(); itor++) { ServerBanned::BannedRange &range = (*itor); std::string mask = NetInterface::getIpName(range.mask); std::map::iterator ipitor; for (ipitor = range.ips.begin(); ipitor != range.ips.end(); ipitor++) { unsigned int ip = (*ipitor).first; ServerBanned::BannedEntry &entry = (*ipitor).second; std::string ipName = NetInterface::getIpName(ip); if (selected && 0 == strcmp(selected, ipName.c_str())) entry.type = ServerBanned::NotBanned; std::string cleanName; XMLNode::removeSpecialChars(entry.name, cleanName); banned += formatString("%s%s%s%s%s%s" "" // Select "", (entry.bantime?ctime(&entry.bantime):""), cleanName.c_str(), entry.uniqueid.c_str(), ServerBanned::getBannedTypeStr(entry.type), ipName.c_str(), mask.c_str(), ipName.c_str()); } } fields["BANNED"] = banned; if (action && 0 == strcmp(action, "Save")) ScorchedServerUtil::instance()->bannedPlayers.save(); return ServerWebServer::getHtmlTemplate("banned.html", fields, text); } bool ServerWebHandler::ModsHandler::processRequest(const char *url, std::map &fields, std::string &text) { std::string modfiles; std::map &modFiles = ScorchedServer::instance()->getModFiles().getFiles(); std::map::iterator itor; for (itor = modFiles.begin(); itor != modFiles.end(); itor++) { ModFileEntry *entry = (*itor).second; std::string cleanFileName; std::string dirtyFileName(entry->getFileName()); XMLNode::removeSpecialChars(dirtyFileName, cleanFileName); modfiles += formatString("%s%u%u%u", cleanFileName.c_str(), entry->getCompressedSize(), entry->getCompressedCrc(), entry->getUncompressedSize()); } fields["MODFILES"] = modfiles; return ServerWebServer::getHtmlTemplate("mods.html", fields, text); }