#include "llviewerprecompiledheaders.h" #include "hippoGridManager.h" #include #include #include #include #include #include #include #include #include "llviewercontrol.h" #include "llweb.h" #include "hippoRestRequest.h" // ******************************************************************** // Global Variables HippoGridManager *gHippoGridManager = 0; HippoGridInfo HippoGridInfo::FALLBACK_GRIDINFO(""); // ******************************************************************** // ******************************************************************** // HippoGridInfo // ******************************************************************** // ******************************************************************** // ******************************************************************** // Initialize HippoGridInfo::HippoGridInfo(const std::string &gridNick) : mPlatform(PLATFORM_OTHER), mRenderCompat(true), mCurrencySymbol("OS$"), mRealCurrencySymbol("US$"), mDirectoryFee(30) { std::string nick = gridNick; mGridNick = sanitizeGridNick( nick ); } // ******************************************************************** // Getters HippoGridInfo::Platform HippoGridInfo::getPlatform() { return mPlatform; } bool HippoGridInfo::isOpenSimulator() const { return (mPlatform == HippoGridInfo::PLATFORM_OPENSIM); } bool HippoGridInfo::isSecondLife() const { return (mPlatform == HippoGridInfo::PLATFORM_SECONDLIFE); } const std::string& HippoGridInfo::getGridNick() const { return mGridNick; } const std::string& HippoGridInfo::getGridName() const { return mGridName; } const std::string& HippoGridInfo::getLoginUri() const { return mLoginUri; } const std::string& HippoGridInfo::getLoginPage() const { return mLoginPage; } const std::string& HippoGridInfo::getHelperUri() const { return mHelperUri; } const std::string& HippoGridInfo::getWebSite() const { return mWebSite; } const std::string& HippoGridInfo::getSupportUrl() const { return mSupportUrl; } const std::string& HippoGridInfo::getRegisterUrl() const { return mRegisterUrl; } const std::string& HippoGridInfo::getPasswordUrl() const { return mPasswordUrl; } const std::string& HippoGridInfo::getSearchUrl() const { return mSearchUrl; } const std::string& HippoGridInfo::getFirstName() const { return mFirstName; } const std::string& HippoGridInfo::getLastName() const { return mLastName; } const std::string& HippoGridInfo::getAvatarPassword() const { return mAvatarPassword; } bool HippoGridInfo::isRenderCompat() const { return mRenderCompat; } const std::string& HippoGridInfo::getCurrencySymbol() const { return mCurrencySymbol; } const std::string& HippoGridInfo::getRealCurrencySymbol() const { return mRealCurrencySymbol; } // ******************************************************************** // Setters void HippoGridInfo::setPlatform(Platform platform) { mPlatform = platform; mCurrencySymbol = (mPlatform == PLATFORM_SECONDLIFE)? "L$": "OS$"; } void HippoGridInfo::setPlatform(const std::string &platform) { std::string tmp = platform; for (unsigned i=0; imXmlState = XML_GRIDNICK; else if (strcasecmp(name, "gridname") == 0) self->mXmlState = XML_GRIDNAME; else if (strcasecmp(name, "platform") == 0) self->mXmlState = XML_PLATFORM; else if ((strcasecmp(name, "login") == 0) || (strcasecmp(name, "loginuri") == 0)) self->mXmlState = XML_LOGINURI; else if ((strcasecmp(name, "welcome") == 0) || (strcasecmp(name, "loginpage") == 0)) self->mXmlState = XML_LOGINPAGE; else if ((strcasecmp(name, "economy") == 0) || (strcasecmp(name, "helperuri") == 0)) self->mXmlState = XML_HELPERURI; else if ((strcasecmp(name, "about") == 0) || (strcasecmp(name, "website") == 0)) self->mXmlState = XML_WEBSITE; else if ((strcasecmp(name, "help") == 0) || (strcasecmp(name, "support") == 0)) self->mXmlState = XML_SUPPORT; else if ((strcasecmp(name, "register") == 0) || (strcasecmp(name, "account") == 0)) self->mXmlState = XML_REGISTER; else if (strcasecmp(name, "password") == 0) self->mXmlState = XML_PASSWORD; //else if (strcasecmp(name, "search") == 0) //self->mXmlState = XML_SEARCH; } //static void HippoGridInfo::onXmlElementEnd(void *userData, const XML_Char *name) { HippoGridInfo *self = (HippoGridInfo*)userData; self->mXmlState = XML_VOID; } //static void HippoGridInfo::onXmlCharacterData(void *userData, const XML_Char *s, int len) { HippoGridInfo *self = (HippoGridInfo*)userData; switch (self->mXmlState) { case XML_GRIDNICK: { if (self->mGridNick == "") self->mGridNick.assign(s, len); self->mGridNick = sanitizeGridNick(self->mGridNick); break; } case XML_PLATFORM: { std::string platform(s, len); self->setPlatform(platform); break; } case XML_LOGINURI: { std::string loginuri(s, len); self->mLoginUri = sanitizeUri( loginuri ); break; } case XML_HELPERURI: { std::string helperuri(s, len); self->mHelperUri = sanitizeUri( helperuri ); break; } case XML_SEARCH: { //self->mSearchUrl.assign(s, len); //sanitizeQueryUrl(mSearchUrl); break; } case XML_GRIDNAME: self->mGridName.assign(s, len); break; case XML_LOGINPAGE: self->mLoginPage.assign(s, len); break; case XML_WEBSITE: self->mWebSite.assign(s, len); break; case XML_SUPPORT: self->mSupportUrl.assign(s, len); break; case XML_REGISTER: self->mRegisterUrl.assign(s, len); break; case XML_PASSWORD: self->mPasswordUrl.assign(s, len); break; case XML_VOID: break; } } bool HippoGridInfo::retrieveGridInfo() { if (mLoginUri == "") return false; std::string reply; int result = HippoRestRequest::getBlocking(mLoginUri + "get_grid_info", &reply); if (result != 200) return false; llinfos << "Received: " << reply << llendl; bool success = true; XML_Parser parser = XML_ParserCreate(0); XML_SetUserData(parser, this); XML_SetElementHandler(parser, onXmlElementStart, onXmlElementEnd); XML_SetCharacterDataHandler(parser, onXmlCharacterData); mXmlState = XML_VOID; if (!XML_Parse(parser, reply.data(), reply.size(), TRUE)) { llwarns << "XML Parse Error: " << XML_ErrorString(XML_GetErrorCode(parser)) << llendl; success = false; } XML_ParserFree(parser); return success; } std::string HippoGridInfo::getUploadFee() const { std::string fee; formatFee(fee, LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(), true); return fee; } std::string HippoGridInfo::getGroupCreationFee() const { std::string fee; formatFee(fee, LLGlobalEconomy::Singleton::getInstance()->getPriceGroupCreate(), false); return fee; } std::string HippoGridInfo::getDirectoryFee() const { std::string fee; formatFee(fee, mDirectoryFee, true); if (fee != "free") fee += "/week"; return fee; } void HippoGridInfo::formatFee(std::string &fee, int cost, bool showFree) const { if (showFree && (cost == 0)) { fee = "free"; } else { fee = llformat("%s%d", getCurrencySymbol().c_str(), cost); } } // ******************************************************************** // Static Helpers // static const char *HippoGridInfo::getPlatformString(Platform platform) { static const char *platformStrings[PLATFORM_LAST] = { "Other", "OpenSim", "SecondLife" }; if ((platform < PLATFORM_OTHER) || (platform >= PLATFORM_LAST)) platform = PLATFORM_OTHER; return platformStrings[platform]; } // static std::string HippoGridInfo::sanitizeGridNick(std::string &gridnick) { std::string tmp; int size = gridnick.size(); for (int i=0; i::iterator it, end = mGridInfo.end(); for (it=mGridInfo.begin(); it != end; ++it) { delete it->second; } mGridInfo.clear(); } void HippoGridManager::init() { HippoGridInfo::initFallback(); loadFromFile(); // !!!### gSavedSettings.getControl("CmdLineLoginURI"); // !!!### gSavedSettings.getString("CmdLineLoginPage"); // !!!### gSavedSettings.getString("CmdLineHelperURI"); // !!!### LLString::compareInsensitive(gGridInfo[grid_index].mLabel, grid_name.c_str())) } void HippoGridManager::discardAndReload() { cleanup(); loadFromFile(); } // ******************************************************************** // Public Access HippoGridInfo* HippoGridManager::getGrid(const std::string &grid) const { std::map::const_iterator it; it = mGridInfo.find(grid); if (it != mGridInfo.end()) { return it->second; } else { return 0; } } HippoGridInfo* HippoGridManager::getConnectedGrid() const { return (mConnectedGrid)? mConnectedGrid: getCurrentGrid(); } HippoGridInfo* HippoGridManager::getCurrentGrid() const { HippoGridInfo *grid = getGrid(mCurrentGrid); if (grid) { return grid; } else { return &HippoGridInfo::FALLBACK_GRIDINFO; } } const std::string& HippoGridManager::getDefaultGridNick() const { return mDefaultGrid; } const std::string& HippoGridManager::getCurrentGridNick() const { return mCurrentGrid; } void HippoGridManager::setCurrentGridAsConnected() { mConnectedGrid = getCurrentGrid(); } void HippoGridManager::addGrid(HippoGridInfo *grid) { if (!grid) return; const std::string &nick = grid->getGridNick(); if (nick == "") { llwarns << "Ignoring to try adding grid with empty nick." << llendl; delete grid; return; } if (mGridInfo.find(nick) != mGridInfo.end()) { llwarns << "Ignoring to try adding existing grid " << nick << '.' << llendl; delete grid; return; } mGridInfo[nick] = grid; } void HippoGridManager::deleteGrid(const std::string &grid) { GridIterator it = mGridInfo.find(grid); if (it == mGridInfo.end()) { llwarns << "Trying to delete non-existing grid " << grid << '.' << llendl; return; } mGridInfo.erase(it); llinfos << "Number of grids now: " << mGridInfo.size() << llendl; if (mGridInfo.empty()) llinfos << "Grid info map is empty." << llendl; if (grid == mDefaultGrid) setDefaultGrid(""); // sets first grid, if map not empty if (grid == mCurrentGrid) mCurrentGrid = mDefaultGrid; } void HippoGridManager::setDefaultGrid(const std::string &grid) { GridIterator it = mGridInfo.find(grid); if (it != mGridInfo.end()) { mDefaultGrid = grid; } else if (mGridInfo.find("secondlife") != mGridInfo.end()) { mDefaultGrid = "secondlife"; } else if (!mGridInfo.empty()) { mDefaultGrid = mGridInfo.begin()->first; } else { mDefaultGrid = ""; } } void HippoGridManager::setCurrentGrid(const std::string &grid) { GridIterator it = mGridInfo.find(grid); if (it != mGridInfo.end()) { mCurrentGrid = grid; } else if (!mGridInfo.empty()) { llwarns << "Unknown grid '" << grid << "'. Setting to default grid." << llendl; mCurrentGrid = mDefaultGrid; } } // ******************************************************************** // Persistent Store void HippoGridManager::loadFromFile() { mDefaultGridsVersion = 0; // load user grid info parseFile(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "grid_info.xml"), false); // merge default grid info, if newer. Force load, if list of grids is empty. parseFile(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "default_grids.xml"), !mGridInfo.empty()); // merge grid info from web site, if newer. Force load, if list of grids is empty. if (gSavedSettings.getBOOL("CheckForGridUpdates")) parseUrl("http://imprudenceviewer.org/app/grids/", !mGridInfo.empty()); std::string last_grid = gSavedSettings.getString("LastSelectedGrid"); if (last_grid.empty()) last_grid = gSavedSettings.getString("DefaultGrid"); setDefaultGrid(last_grid); setCurrentGrid(last_grid); } void HippoGridManager::parseUrl(const char *url, bool mergeIfNewer) { llinfos << "Loading grid info from '" << url << "'." << llendl; // query update server std::string escaped_url = LLWeb::escapeURL(url); LLSD response = LLHTTPClient::blockingGet(url); // check response, return on error S32 status = response["status"].asInteger(); if ((status != 200) || !response["body"].isArray()) { llinfos << "GridInfo Update failed (" << status << "): " << (response["body"].isString()? response["body"].asString(): "") << llendl; return; } LLSD gridInfo = response["body"]; parseData(gridInfo, mergeIfNewer); } void HippoGridManager::parseFile(const std::string &fileName, bool mergeIfNewer) { llifstream infile; infile.open(fileName.c_str()); if(!infile.is_open()) { llwarns << "Cannot find grid info file " << fileName << " to load." << llendl; return; } LLSD gridInfo; if (LLSDSerialize::fromXML(gridInfo, infile) <= 0) { llwarns << "Unable to parse grid info file " << fileName << '.' << llendl; return; } llinfos << "Loading grid info file " << fileName << '.' << llendl; parseData(gridInfo, mergeIfNewer); } void HippoGridManager::parseData(LLSD &gridInfo, bool mergeIfNewer) { if (mergeIfNewer) { LLSD::array_const_iterator it, end = gridInfo.endArray(); for (it = gridInfo.beginArray(); it != end; ++it) { LLSD gridMap = *it; if (gridMap.has("default_grids_version")) { int version = gridMap["default_grids_version"]; if (version <= mDefaultGridsVersion) return; else break; } } if (it == end) { llwarns << "Grid data has no version number." << llendl; return; } } llinfos << "Loading grid data." << llendl; LLSD::array_const_iterator it, end = gridInfo.endArray(); for (it = gridInfo.beginArray(); it != end; ++it) { LLSD gridMap = *it; if (gridMap.has("default_grids_version")) { mDefaultGridsVersion = gridMap["default_grids_version"]; } else if (gridMap.has("gridnick") && gridMap.has("loginuri")) { std::string gridnick = gridMap["gridnick"]; HippoGridInfo *grid; GridIterator it = mGridInfo.find(gridnick); bool newGrid = (it == mGridInfo.end()); if (newGrid) { // create new grid info grid = new HippoGridInfo(gridnick); } else { // update existing grid info grid = it->second; } grid->setLoginUri(gridMap["loginuri"]); if (gridMap.has("platform")) grid->setPlatform(gridMap["platform"]); if (gridMap.has("gridname")) grid->setGridName(gridMap["gridname"]); if (gridMap.has("loginpage")) grid->setLoginPage(gridMap["loginpage"]); if (gridMap.has("helperuri")) grid->setHelperUri(gridMap["helperuri"]); if (gridMap.has("website")) grid->setWebSite(gridMap["website"]); if (gridMap.has("support")) grid->setSupportUrl(gridMap["support"]); if (gridMap.has("register")) grid->setRegisterUrl(gridMap["register"]); if (gridMap.has("password")) grid->setPasswordUrl(gridMap["password"]); //if (gridMap.has("search")) grid->setSearchUrl(gridMap["search"]); if (gridMap.has("render_compat")) grid->setRenderCompat(gridMap["render_compat"]); // if (gridMap.has("firstname")) grid->setFirstName(gridMap["firstname"]); // if (gridMap.has("lastname")) grid->setLastName(gridMap["lastname"]); // if (gridMap.has("avatarpassword")) grid->setAvatarPassword(gridMap["avatarpassword"]); if (newGrid) addGrid(grid); } } } void HippoGridManager::saveFile() { // save default grid to client settings gSavedSettings.setString("DefaultGrid", mDefaultGrid); // build LLSD LLSD gridInfo; gridInfo[0]["default_grids_version"] = mDefaultGridsVersion; // add grids S32 i = 1; GridIterator it, end = mGridInfo.end(); for (it = mGridInfo.begin(); it != end; ++it, i++) { HippoGridInfo *grid = it->second; gridInfo[i]["gridnick"] = grid->getGridNick(); gridInfo[i]["platform"] = HippoGridInfo::getPlatformString(grid->getPlatform()); gridInfo[i]["gridname"] = grid->getGridName(); gridInfo[i]["loginuri"] = grid->getLoginUri(); gridInfo[i]["loginpage"] = grid->getLoginPage(); gridInfo[i]["helperuri"] = grid->getHelperUri(); gridInfo[i]["website"] = grid->getWebSite(); gridInfo[i]["support"] = grid->getSupportUrl(); gridInfo[i]["register"] = grid->getRegisterUrl(); gridInfo[i]["password"] = grid->getPasswordUrl(); // gridInfo[i]["firstname"] = grid->getFirstName(); // gridInfo[i]["lastname"] = grid->getLastName(); // gridInfo[i]["avatarpassword"] = grid->getAvatarPassword(); //gridInfo[i]["search"] = grid->getSearchUrl(); gridInfo[i]["render_compat"] = grid->isRenderCompat(); } // write client grid info file std::string fileName = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "grid_info.xml"); llofstream file; file.open(fileName.c_str()); if (file.is_open()) { LLSDSerialize::toPrettyXML(gridInfo, file); file.close(); llinfos << "Saved grids to " << fileName << llendl; } else { llerrs << "Unable to open grid info file: " << fileName << llendl; } }