AString cWebAdmin::GetHTMLEscapedString(const AString & a_Input) { AString dst; dst.reserve(a_Input.length()); // Loop over input and substitute HTML characters for their alternatives: size_t len = a_Input.length(); for (size_t i = 0; i < len; i++) { switch (a_Input[i]) { case '&': dst.append("&"); break; case '\'': dst.append("'"); break; case '"': dst.append("""); break; case '<': dst.append("<"); break; case '>': dst.append(">"); break; default: { dst.push_back(a_Input[i]); break; } } // switch (a_Input[i]) } // for i - a_Input[] return dst; }
virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) override { if (!a_HelpString.empty()) { m_Commands.push_back(AStringPair(a_Command, a_HelpString)); if (m_MaxLen < a_Command.length()) { m_MaxLen = a_Command.length(); } } return false; }
int cParsedNBT::FindTagByPath(int a_Tag, const AString & a_Path) const { if (a_Tag < 0) { return -1; } size_t Begin = 0; size_t Length = a_Path.length(); int Tag = a_Tag; for (size_t i = 0; i < Length; i++) { if (a_Path[i] != '\\') { continue; } Tag = FindChildByName(Tag, a_Path.c_str() + Begin, i - Begin - 1); if (Tag < 0) { return -1; } Begin = i + 1; } // for i - a_Path[] if (Begin < Length) { Tag = FindChildByName(Tag, a_Path.c_str() + Begin, Length - Begin); } return Tag; }
cCallback (const AString & a_PlayerName) : m_BestRating(0), m_NameLength(a_PlayerName.length()), m_PlayerName(a_PlayerName), m_BestMatch(), m_NumMatches(0) {}
void cSHA1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out) { Checksum Digest; memcpy(Digest, a_Digest, sizeof(Digest)); bool IsNegative = (Digest[0] >= 0x80); if (IsNegative) { // Two's complement: bool carry = true; // Add one to the whole number for (int i = 19; i >= 0; i--) { Digest[i] = ~Digest[i]; if (carry) { carry = (Digest[i] == 0xff); Digest[i]++; } } } a_Out.clear(); a_Out.reserve(40); for (int i = 0; i < 20; i++) { AppendPrintf(a_Out, "%02x", Digest[i]); } while ((a_Out.length() > 0) && (a_Out[0] == '0')) { a_Out.erase(0, 1); } if (IsNegative) { a_Out.insert(0, "-"); } }
void cSocketInputStream::Error(const AString & a_ErrorMsg) { send(m_Socket, a_ErrorMsg.c_str(), static_cast<int>(a_ErrorMsg.length()), 0); static const char EndLine[] = "\n"; send(m_Socket, EndLine, sizeof(EndLine) - 1, 0); }
// Converts a raw 160-bit SHA1 digest into a Java Hex representation // According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802 static void DigestToJava(byte a_Digest[20], AString & a_Out) { bool IsNegative = (a_Digest[0] >= 0x80); if (IsNegative) { // Two's complement: bool carry = true; // Add one to the whole number for (int i = 19; i >= 0; i--) { a_Digest[i] = ~a_Digest[i]; if (carry) { carry = (a_Digest[i] == 0xff); a_Digest[i]++; } } } a_Out.clear(); a_Out.reserve(40); for (int i = 0; i < 20; i++) { AppendPrintf(a_Out, "%02x", a_Digest[i]); } while ((a_Out.length() > 0) && (a_Out[0] == '0')) { a_Out.erase(0, 1); } if (IsNegative) { a_Out.insert(0, "-"); } }
AString GetOSErrorString( int a_ErrNo) { char buffer[ 1024 ]; AString Out; #ifdef _WIN32 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, a_ErrNo, 0, buffer, ARRAYCOUNT(buffer), NULL); Printf(Out, "%d: %s", a_ErrNo, buffer); if (!Out.empty() && (Out[Out.length() - 1] == '\n')) { Out.erase(Out.length() - 2); } return Out; #else // _WIN32 // According to http://linux.die.net/man/3/strerror_r there are two versions of strerror_r(): #if !defined(__APPLE__) && ( _GNU_SOURCE) && !defined(ANDROID_NDK) // GNU version of strerror_r() char * res = strerror_r( errno, buffer, ARRAYCOUNT(buffer)); if (res != NULL) { Printf(Out, "%d: %s", a_ErrNo, res); return Out; } #else // XSI version of strerror_r(): int res = strerror_r( errno, buffer, ARRAYCOUNT(buffer)); if (res == 0) { Printf(Out, "%d: %s", a_ErrNo, buffer); return Out; } #endif // strerror_r() version else { Printf(Out, "Error %d while getting error string for error #%d!", errno, a_ErrNo); return Out; } #endif // else _WIN32 }
cCallback (const AString & a_PlayerName, cPlayerListCallback & a_Callback) : m_Callback( a_Callback ) , BestMatch( NULL ) , BestRating( 0 ) , NumMatches( 0 ) , NameLength( a_PlayerName.length() ) , PlayerName( a_PlayerName ) {}
cPiece::cVerticalStrategyPtr CreateVerticalStrategyFromString(const AString & a_StrategyDesc, bool a_LogWarnings) { // Break apart the strategy class, the first parameter before the first pipe char: auto idxPipe = a_StrategyDesc.find('|'); if (idxPipe == AString::npos) { idxPipe = a_StrategyDesc.length(); } AString StrategyClass = a_StrategyDesc.substr(0, idxPipe); // Create a strategy class based on the class string: cPiece::cVerticalStrategyPtr Strategy; if (NoCaseCompare(StrategyClass, "Fixed") == 0) { Strategy = std::make_shared<cVerticalStrategyFixed>(); } else if (NoCaseCompare(StrategyClass, "Range") == 0) { Strategy = std::make_shared<cVerticalStrategyRange>(); } else if (NoCaseCompare(StrategyClass, "TerrainTop") == 0) { Strategy = std::make_shared<cVerticalStrategyTerrainTop>(); } else if (NoCaseCompare(StrategyClass, "TerrainOrOceanTop") == 0) { Strategy = std::make_shared<cVerticalStrategyTerrainOrOceanTop>(); } else { return nullptr; } // Initialize the strategy's parameters: AString Params; if (idxPipe < a_StrategyDesc.length()) { Params = a_StrategyDesc.substr(idxPipe + 1); } if (!Strategy->InitializeFromString(Params, a_LogWarnings)) { return nullptr; } return Strategy; }
void cMobHeadEntity::SetOwner(const AString & a_Owner) { if ((a_Owner.length() > 16) || (m_Type != SKULL_TYPE_PLAYER)) { return; } m_Owner = a_Owner; }
int cFile::Printf(const char * a_Fmt, ...) { AString buf; va_list args; va_start(args, a_Fmt); AppendVPrintf(buf, a_Fmt, args); va_end(args); return Write(buf.c_str(), buf.length()); }
AStringVector cFile::GetFolderContents(const AString & a_Folder) { AStringVector AllFiles; #ifdef _WIN32 // If the folder name doesn't contain the terminating slash / backslash, add it: AString FileFilter = a_Folder; if ( !FileFilter.empty() && (FileFilter[FileFilter.length() - 1] != '\\') && (FileFilter[FileFilter.length() - 1] != '/') ) { FileFilter.push_back('\\'); } // Find all files / folders: FileFilter.append("*.*"); HANDLE hFind; WIN32_FIND_DATAA FindFileData; if ((hFind = FindFirstFileA(FileFilter.c_str(), &FindFileData)) != INVALID_HANDLE_VALUE) { do { AllFiles.push_back(FindFileData.cFileName); } while (FindNextFileA(hFind, &FindFileData)); FindClose(hFind); } #else // _WIN32 DIR * dp; AString Folder = a_Folder; if (Folder.empty()) { Folder = "."; } if ((dp = opendir(Folder.c_str())) == nullptr) { LOGERROR("Error (%i) opening directory \"%s\"\n", errno, Folder.c_str()); } else { struct dirent *dirp; while ((dirp = readdir(dp)) != nullptr) { AllFiles.push_back(dirp->d_name); } closedir(dp); } #endif // else _WIN32 return AllFiles; }
AString cPlayer::GetUUIDFileName(const AString & a_UUID) { AString UUID = cMojangAPI::MakeUUIDDashed(a_UUID); ASSERT(UUID.length() == 36); AString res("players/"); res.append(UUID, 0, 2); res.push_back('/'); res.append(UUID, 2, AString::npos); res.append(".json"); return res; }
void cMonster::SetCustomName(const AString & a_CustomName) { m_CustomName = a_CustomName; // The maximal length is 64 if (a_CustomName.length() > 64) { m_CustomName = a_CustomName.substr(0, 64); } if (m_World != nullptr) { m_World->BroadcastEntityMetadata(*this); } }
void cProtocol132::StartEncryption(const Byte * a_Key) { m_Encryptor.Init(a_Key, a_Key); m_Decryptor.Init(a_Key, a_Key); m_IsEncrypted = true; // Prepare the m_AuthServerID: cSHA1Checksum Checksum; AString ServerID = cRoot::Get()->GetServer()->GetServerID(); Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length()); Checksum.Update(a_Key, 16); Checksum.Update((const Byte *)cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size()); Byte Digest[20]; Checksum.Finalize(Digest); cSHA1Checksum::DigestToJava(Digest, m_AuthServerID); }
void cProtocol132::StartEncryption(const byte * a_Key) { m_Encryptor.SetKey(a_Key, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(a_Key, 16))(Name::FeedbackSize(), 1)); m_Decryptor.SetKey(a_Key, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(a_Key, 16))(Name::FeedbackSize(), 1)); m_IsEncrypted = true; // Prepare the m_AuthServerID: CryptoPP::SHA1 Checksum; AString ServerID = cRoot::Get()->GetServer()->GetServerID(); Checksum.Update((const byte *)ServerID.c_str(), ServerID.length()); Checksum.Update(a_Key, 16); Checksum.Update((const byte *)m_ServerPublicKey.c_str(), m_ServerPublicKey.length()); byte Digest[20]; Checksum.Final(Digest); DigestToJava(Digest, m_AuthServerID); }
void cPluginManager::TabCompleteCommand(const AString & a_Text, AStringVector & a_Results, cPlayer * a_Player) { for (CommandMap::iterator itr = m_Commands.begin(), end = m_Commands.end(); itr != end; ++itr) { if (NoCaseCompare(itr->first.substr(0, a_Text.length()), a_Text) != 0) { // Command name doesn't match continue; } if ((a_Player != NULL) && !a_Player->HasPermission(itr->second.m_Permission)) { // Player doesn't have permission for the command continue; } a_Results.push_back(itr->first); } }
void cProtocolRecognizer::SendDisconnect(const AString & a_Reason) { if (m_Protocol != nullptr) { m_Protocol->SendDisconnect(a_Reason); } else { // This is used when the client sends a server-ping, respond with the default packet: static const int Packet = 0xff; // PACKET_DISCONNECT SendData((const char *)&Packet, 1); // WriteByte() AString UTF16 = UTF8ToRawBEUTF16(a_Reason.c_str(), a_Reason.length()); static const u_short Size = htons((u_short)(UTF16.size() / 2)); SendData((const char *)&Size, 2); // WriteShort() SendData(UTF16.data(), UTF16.size()); // WriteString() } }
void cCompositeChat::AddStyle(AString & a_Style, const AString & a_AddStyle) { if (a_AddStyle.empty()) { return; } if (a_AddStyle[0] == '@') { size_t idx = a_Style.find('@'); if ((idx != AString::npos) && (idx != a_Style.length())) { a_Style.erase(idx, 2); } a_Style.append(a_AddStyle); return; } a_Style.append(a_AddStyle); }
bool cFile::CreateFolderRecursive(const AString & a_FolderPath) { // Special case: Fail if the path is empty if (a_FolderPath.empty()) { return false; } // Go through each path element and create the folder: auto len = a_FolderPath.length(); auto PathSep = GetPathSeparator()[0]; for (decltype(len) i = 0; i < len; i++) { if (a_FolderPath[i] == PathSep) { CreateFolder(a_FolderPath.substr(0, i)); } } CreateFolder(a_FolderPath); // Check the result by querying whether the final path exists: return IsFolder(a_FolderPath); }
void cPluginManager::TabCompleteCommand(const AString & a_Text, AStringVector & a_Results, cPlayer * a_Player) { for (CommandMap::iterator itr = m_Commands.begin(), end = m_Commands.end(); itr != end; ++itr) { if (NoCaseCompare(itr->first.substr(0, a_Text.length()), a_Text) != 0) { // Command name doesn't match continue; } if ((a_Player != nullptr) && !a_Player->HasPermission(itr->second.m_Permission)) { // Player doesn't have permission for the command continue; } /* Client expects to only get back the last part of a space separated command. Find the position of the beginning of the last part: Position of last space + 1 for space separated commands string::npos + 1 = 0 for commands that are not separated Then skip all commands that have too many subcommands. When the client asks for suggestions for "/time s" the server must skip all commands that consist of more than 2 words just as "/time set day". Or in other words, the position of the last space (separator) in the strings must be equal or string::npos for both. */ size_t LastSpaceInText = a_Text.find_last_of(' ') + 1; size_t LastSpaceInSuggestion = itr->first.find_last_of(' ') + 1; if (LastSpaceInText != LastSpaceInSuggestion) { // Suggestion has more subcommands than a_Text continue; } a_Results.push_back(itr->first.substr(LastSpaceInSuggestion)); } }
void cCompositeChat::AddChatPartStyle(Json::Value & a_Value, const AString & a_PartStyle) const { size_t len = a_PartStyle.length(); for (size_t i = 0; i < len; i++) { switch (a_PartStyle[i]) { case 'b': { // bold a_Value["bold"] = Json::Value(true); break; } case 'i': { // italic a_Value["italic"] = Json::Value(true); break; } case 'u': { // Underlined a_Value["underlined"] = Json::Value(true); break; } case 's': { // strikethrough a_Value["strikethrough"] = Json::Value(true); break; } case 'o': { // obfuscated a_Value["obfuscated"] = Json::Value(true); break; } case '@': { // Color, specified by the next char: i++; if (i >= len) { // String too short, didn't contain a color break; } switch (a_PartStyle[i]) { case '0': a_Value["color"] = Json::Value("black"); break; case '1': a_Value["color"] = Json::Value("dark_blue"); break; case '2': a_Value["color"] = Json::Value("dark_green"); break; case '3': a_Value["color"] = Json::Value("dark_aqua"); break; case '4': a_Value["color"] = Json::Value("dark_red"); break; case '5': a_Value["color"] = Json::Value("dark_purple"); break; case '6': a_Value["color"] = Json::Value("gold"); break; case '7': a_Value["color"] = Json::Value("gray"); break; case '8': a_Value["color"] = Json::Value("dark_gray"); break; case '9': a_Value["color"] = Json::Value("blue"); break; case 'a': a_Value["color"] = Json::Value("green"); break; case 'b': a_Value["color"] = Json::Value("aqua"); break; case 'c': a_Value["color"] = Json::Value("red"); break; case 'd': a_Value["color"] = Json::Value("light_purple"); break; case 'e': a_Value["color"] = Json::Value("yellow"); break; case 'f': a_Value["color"] = Json::Value("white"); break; } // switch (color) } // case '@' } // switch (Style[i]) } // for i - a_PartStyle[] }
void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) { if (!a_Request.HasAuth()) { a_Connection.SendNeedAuth("MCServer WebAdmin"); return; } // Check auth: AString UserPassword = m_IniFile.GetValue("User:"******"Password", ""); if ((UserPassword == "") || (a_Request.GetAuthPassword() != UserPassword)) { a_Connection.SendNeedAuth("MCServer WebAdmin - bad username or password"); return; } // Check if the contents should be wrapped in the template: AString URL = a_Request.GetBareURL(); ASSERT(URL.length() > 0); bool ShouldWrapInTemplate = ((URL.length() > 1) && (URL[1] != '~')); // Retrieve the request data: cWebadminRequestData * Data = (cWebadminRequestData *)(a_Request.GetUserData()); if (Data == NULL) { a_Connection.SendStatusAndReason(500, "Bad UserData"); return; } // Wrap it all up for the Lua call: AString Template; HTTPTemplateRequest TemplateRequest; TemplateRequest.Request.Username = a_Request.GetAuthUsername(); TemplateRequest.Request.Method = a_Request.GetMethod(); TemplateRequest.Request.Path = URL.substr(1); if (Data->m_Form.Finish()) { for (cHTTPFormParser::const_iterator itr = Data->m_Form.begin(), end = Data->m_Form.end(); itr != end; ++itr) { HTTPFormData HTTPfd; HTTPfd.Value = itr->second; HTTPfd.Type = ""; HTTPfd.Name = itr->first; TemplateRequest.Request.FormData[itr->first] = HTTPfd; TemplateRequest.Request.PostParams[itr->first] = itr->second; } // for itr - Data->m_Form[] // Parse the URL into individual params: size_t idxQM = a_Request.GetURL().find('?'); if (idxQM != AString::npos) { cHTTPFormParser URLParams(cHTTPFormParser::fpkURL, a_Request.GetURL().c_str() + idxQM + 1, a_Request.GetURL().length() - idxQM - 1, *Data); URLParams.Finish(); for (cHTTPFormParser::const_iterator itr = URLParams.begin(), end = URLParams.end(); itr != end; ++itr) { TemplateRequest.Request.Params[itr->first] = itr->second; } // for itr - URLParams[] } } // Try to get the template from the Lua template script if (ShouldWrapInTemplate) { if (m_TemplateScript.Call("ShowPage", this, &TemplateRequest, cLuaState::Return, Template)) { cHTTPResponse Resp; Resp.SetContentType("text/html"); a_Connection.Send(Resp); a_Connection.Send(Template.c_str(), Template.length()); return; } a_Connection.SendStatusAndReason(500, "m_TemplateScript failed"); return; } AString BaseURL = GetBaseURL(URL); AString Menu; Template = "{CONTENT}"; AString FoundPlugin; for (PluginList::iterator itr = m_Plugins.begin(); itr != m_Plugins.end(); ++itr) { cWebPlugin * WebPlugin = *itr; std::list< std::pair<AString, AString> > NameList = WebPlugin->GetTabNames(); for (std::list< std::pair<AString, AString> >::iterator Names = NameList.begin(); Names != NameList.end(); ++Names) { Menu += "<li><a href='" + BaseURL + WebPlugin->GetWebTitle().c_str() + "/" + (*Names).second + "'>" + (*Names).first + "</a></li>"; } } sWebAdminPage Page = GetPage(TemplateRequest.Request); AString Content = Page.Content; FoundPlugin = Page.PluginName; if (!Page.TabName.empty()) { FoundPlugin += " - " + Page.TabName; } if (FoundPlugin.empty()) // Default page { Content = GetDefaultPage(); } if (ShouldWrapInTemplate && (URL.size() > 1)) { Content += "\n<p><a href='" + BaseURL + "'>Go back</a></p>"; } int MemUsageKiB = cRoot::GetPhysicalRAMUsage(); if (MemUsageKiB > 0) { ReplaceString(Template, "{MEM}", Printf("%.02f", (double)MemUsageKiB / 1024)); ReplaceString(Template, "{MEMKIB}", Printf("%d", MemUsageKiB)); } else { ReplaceString(Template, "{MEM}", "unknown"); ReplaceString(Template, "{MEMKIB}", "unknown"); } ReplaceString(Template, "{USERNAME}", a_Request.GetAuthUsername()); ReplaceString(Template, "{MENU}", Menu); ReplaceString(Template, "{PLUGIN_NAME}", FoundPlugin); ReplaceString(Template, "{CONTENT}", Content); ReplaceString(Template, "{TITLE}", "MCServer"); AString NumChunks; Printf(NumChunks, "%d", cRoot::Get()->GetTotalChunkCount()); ReplaceString(Template, "{NUMCHUNKS}", NumChunks); cHTTPResponse Resp; Resp.SetContentType("text/html"); a_Connection.Send(Resp); a_Connection.Send(Template.c_str(), Template.length()); }
bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect) { m_Filename = a_FileName; // Normally you would use ifstream, but the SGI CC compiler has // a few bugs with ifstream. So ... fstream used. fstream f; AString line; AString keyname, valuename, value; AString::size_type pLeft, pRight; bool IsFromExampleRedirect = false; f.open((FILE_IO_PREFIX + a_FileName).c_str(), ios::in); if (f.fail()) { f.clear(); if (a_AllowExampleRedirect) { // Retry with the .example.ini file instead of .ini: AString ExPath(a_FileName.substr(0, a_FileName.length() - 4)); ExPath.append(".example.ini"); f.open((FILE_IO_PREFIX + ExPath).c_str(), ios::in); if (f.fail()) { return false; } IsFromExampleRedirect = true; } else { return false; } } bool IsFirstLine = true; while (getline(f, line)) { // To be compatible with Win32, check for existence of '\r'. // Win32 files have the '\r' and Unix files don't at the end of a line. // Note that the '\r' will be written to INI files from // Unix so that the created INI file can be read under Win32 // without change. // Removes UTF-8 Byte Order Markers (BOM) if, present. if (IsFirstLine) { RemoveBom(line); IsFirstLine = false; } size_t lineLength = line.length(); if (lineLength == 0) { continue; } if (line[lineLength - 1] == '\r') { line = line.substr(0, lineLength - 1); } if (line.length() == 0) { continue; } // Check that the user hasn't opened a binary file by checking the first // character of each line! if (!isprint(line[0])) { printf("%s: Binary-check failed on char %d\n", __FUNCTION__, line[0]); f.close(); return false; } if ((pLeft = line.find_first_of(";#[=")) == AString::npos) { continue; } switch (line[pLeft]) { case '[': { if ( ((pRight = line.find_last_of("]")) != AString::npos) && (pRight > pLeft) ) { keyname = line.substr(pLeft + 1, pRight - pLeft - 1); AddKeyName(keyname); } break; } case '=': { valuename = line.substr(0, pLeft); value = line.substr(pLeft + 1); AddValue(keyname, valuename, value); break; } case ';': case '#': { if (names.empty()) { AddHeaderComment(line.substr(pLeft + 1)); } else { AddKeyComment(keyname, line.substr(pLeft + 1)); } break; } } // switch (line[pLeft]) } // while (getline()) f.close(); if (keys.empty() && names.empty() && comments.empty()) { // File be empty or unreadable, equivalent to nonexistant return false; } if (IsFromExampleRedirect) { WriteFile(FILE_IO_PREFIX + a_FileName); } return true; }
void cCompositeChat::ParseText(const AString & a_ParseText) { size_t len = a_ParseText.length(); size_t first = 0; // First character of the currently parsed block AString CurrentStyle; AString CurrentText; for (size_t i = 0; i < len; i++) { switch (a_ParseText[i]) { case '@': { // Color code i++; if (i >= len) { // Not enough following text break; } if (a_ParseText[i] == '@') { // "@@" escape, just put a "@" into the current text and keep parsing as text if (i > first + 1) { CurrentText.append(a_ParseText.c_str() + first, i - first - 1); } first = i + 1; continue; } else { // True color code. Create a part for the CurrentText and start parsing anew: if (i >= first) { CurrentText.append(a_ParseText.c_str() + first, i - first - 1); first = i + 1; } if (!CurrentText.empty()) { m_Parts.push_back(new cTextPart(CurrentText, CurrentStyle)); CurrentText.clear(); } AddStyle(CurrentStyle, a_ParseText.substr(i - 1, 2)); } break; } case ':': { const char * LinkPrefixes[] = { "http", "https" }; for (size_t Prefix = 0; Prefix < ARRAYCOUNT(LinkPrefixes); Prefix++) { size_t PrefixLen = strlen(LinkPrefixes[Prefix]); if ( (i >= first + PrefixLen) && // There is enough space in front of the colon for the prefix (strncmp(a_ParseText.c_str() + i - PrefixLen, LinkPrefixes[Prefix], PrefixLen) == 0) // the prefix matches ) { // Add everything before this as a text part: if (i > first + PrefixLen) { CurrentText.append(a_ParseText.c_str() + first, i - first - PrefixLen); first = i - PrefixLen; } if (!CurrentText.empty()) { AddTextPart(CurrentText, CurrentStyle); CurrentText.clear(); } // Go till the last non-whitespace char in the text: for (; i < len; i++) { if (isspace(a_ParseText[i])) { break; } } AddUrlPart(a_ParseText.substr(first, i - first), a_ParseText.substr(first, i - first), CurrentStyle); first = i; break; } } // for Prefix - LinkPrefix[] break; } // case ':' } // switch (a_ParseText[i]) } // for i - a_ParseText[] if (first < len) { AddTextPart(a_ParseText.substr(first, len - first), CurrentStyle); } }
bool cGroupManager::LoadGroups() { cIniFile IniFile; if (!IniFile.ReadFile("groups.ini")) { LOGWARNING("Regenerating groups.ini, all groups will be reset"); IniFile.AddHeaderComment(" This is the MCServer permissions manager groups file"); IniFile.AddHeaderComment(" It stores all defined groups such as Administrators, Players, or Moderators"); IniFile.SetValue("Owner", "Permissions", "*", true); IniFile.SetValue("Owner", "Color", "2", true); IniFile.SetValue("Moderator", "Permissions", "core.time,core.item,core.tpa,core.tpaccept,core.ban,core.unban,core.save-all,core.toggledownfall"); IniFile.SetValue("Moderator", "Color", "2", true); IniFile.SetValue("Moderator", "Inherits", "Player", true); IniFile.SetValue("Player", "Permissions", "core.portal", true); IniFile.SetValue("Player", "Color", "f", true); IniFile.SetValue("Player", "Inherits", "Default", true); IniFile.SetValue("Default", "Permissions", "core.help,core.plugins,core.spawn,core.worlds,core.back,core.motd,core.build,core.locate,core.viewdistance", true); IniFile.SetValue("Default", "Color", "f", true); IniFile.WriteFile("groups.ini"); } int NumKeys = IniFile.GetNumKeys(); for (int i = 0; i < NumKeys; i++) { AString KeyName = IniFile.GetKeyName(i); cGroup * Group = GetGroup(KeyName.c_str()); Group->ClearPermission(); // Needed in case the groups are reloaded. LOGD("Loading group %s", KeyName.c_str()); Group->SetName(KeyName); AString Color = IniFile.GetValue(KeyName, "Color", "-"); if ((Color != "-") && (Color.length() >= 1)) { Group->SetColor(cChatColor::Color + Color[0]); } else { Group->SetColor(cChatColor::White); } AString Commands = IniFile.GetValue(KeyName, "Commands", ""); if (!Commands.empty()) { AStringVector Split = StringSplitAndTrim(Commands, ","); for (size_t i = 0; i < Split.size(); i++) { Group->AddCommand(Split[i]); } } AString Permissions = IniFile.GetValue(KeyName, "Permissions", ""); if (!Permissions.empty()) { AStringVector Split = StringSplitAndTrim(Permissions, ","); for (size_t i = 0; i < Split.size(); i++) { Group->AddPermission(Split[i]); } } AString Groups = IniFile.GetValue(KeyName, "Inherits", ""); if (!Groups.empty()) { AStringVector Split = StringSplitAndTrim(Groups, ","); for (size_t i = 0; i < Split.size(); i++) { Group->InheritFrom(GetGroup(Split[i].c_str())); } } } // Always return true, we can handle writefile fails later. return true; }
void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) { // Create a list of names to query, by removing those that are already cached: AStringVector NamesToQuery; NamesToQuery.reserve(a_PlayerNames.size()); { cCSLock Lock(m_CSNameToUUID); for (AStringVector::const_iterator itr = a_PlayerNames.begin(), end = a_PlayerNames.end(); itr != end; ++itr) { if (m_NameToUUID.find(*itr) == m_NameToUUID.end()) { NamesToQuery.push_back(*itr); } } // for itr - a_PlayerNames[] } // Lock(m_CSNameToUUID) while (!NamesToQuery.empty()) { // Create the request body - a JSON containing up to MAX_PER_QUERY playernames: Json::Value root; int Count = 0; AStringVector::iterator itr = NamesToQuery.begin(), end = NamesToQuery.end(); for (; (itr != end) && (Count < MAX_PER_QUERY); ++itr, ++Count) { Json::Value req(*itr); root.append(req); } // for itr - a_PlayerNames[] NamesToQuery.erase(NamesToQuery.begin(), itr); Json::FastWriter Writer; AString RequestBody = Writer.write(root); // Create the HTTP request: AString Request; Request += "POST " + m_NameToUUIDAddress + " HTTP/1.0\r\n"; // We need to use HTTP 1.0 because we don't handle Chunked transfer encoding Request += "Host: " + m_NameToUUIDServer + "\r\n"; Request += "User-Agent: MCServer\r\n"; Request += "Connection: close\r\n"; Request += "Content-Type: application/json\r\n"; Request += Printf("Content-Length: %u\r\n", (unsigned)RequestBody.length()); Request += "\r\n"; Request += RequestBody; // Get the response from the server: AString Response; if (!SecureRequest(m_NameToUUIDServer, Request, Response)) { continue; } // Check the HTTP status line: const AString Prefix("HTTP/1.1 200 OK"); AString HexDump; if (Response.compare(0, Prefix.size(), Prefix)) { LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } // Erase the HTTP headers from the response: size_t idxHeadersEnd = Response.find("\r\n\r\n"); if (idxHeadersEnd == AString::npos) { LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } Response.erase(0, idxHeadersEnd + 4); // Parse the returned string into Json: Json::Reader reader; if (!reader.parse(Response, root, false) || !root.isArray()) { LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__); LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } // Store the returned results into cache: size_t JsonCount = root.size(); Int64 Now = time(NULL); { cCSLock Lock(m_CSNameToUUID); for (size_t idx = 0; idx < JsonCount; ++idx) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); if (JsonUUID.empty()) { continue; } m_NameToUUID[StrToLower(JsonName)] = sProfile(JsonName, JsonUUID, "", "", Now); } // for idx - root[] } // cCSLock (m_CSNameToUUID) // Also cache the UUIDToName: { cCSLock Lock(m_CSUUIDToName); for (size_t idx = 0; idx < JsonCount; ++idx) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); if (JsonUUID.empty()) { continue; } m_UUIDToName[JsonUUID] = sProfile(JsonName, JsonUUID, "", "", Now); } // for idx - root[] } } // while (!NamesToQuery.empty()) }