/** * @file llstartup.cpp * @brief startup routines. * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llappviewer.h" #include "llstartup.h" #if LL_WINDOWS # include // _spawnl() #else # include // mkdir() #endif #include // std::unique_ptr #include "llviewermedia_streamingaudio.h" #include "llaudioengine.h" #ifdef LL_FMODSTUDIO # include "llaudioengine_fmodstudio.h" #endif #ifdef LL_OPENAL #include "llaudioengine_openal.h" #endif #include "llavatarnamecache.h" #include "llexperiencecache.h" #include "lllandmark.h" #include "llcachename.h" #include "lldir.h" #include "lldonotdisturbnotificationstorage.h" #include "llerrorcontrol.h" #include "llfloaterreg.h" #include "llfocusmgr.h" #include "llfloatergridstatus.h" #include "llfloaterimsession.h" #include "lllocationhistory.h" #include "llgltfmateriallist.h" #include "llimageworker.h" #include "llregex.h" #include "llloginflags.h" #include "llmd5.h" #include "llmemorystream.h" #include "llmessageconfig.h" #include "llmoveview.h" #include "llfloaterimcontainer.h" #include "llfloaterimnearbychat.h" #include "llnotifications.h" #include "llnotificationsutil.h" #include "llpersistentnotificationstorage.h" #include "llpresetsmanager.h" #include "llteleporthistory.h" #include "llregionhandle.h" #include "llsd.h" #include "llsdserialize.h" #include "llsdutil_math.h" #include "llstring.h" #include "lluserrelations.h" #include "llversioninfo.h" #include "llviewercontrol.h" #include "llviewerhelp.h" #include "llxorcipher.h" // saved password, MAC address #include "llwindow.h" #include "message.h" #include "v3math.h" #include "llagent.h" #include "llagentbenefits.h" #include "llagentcamera.h" #include "llagentpicksinfo.h" #include "llagentwearables.h" #include "llagentpilot.h" #include "llfloateravatarpicker.h" #include "llcallbacklist.h" #include "llcallingcard.h" #include "llclassifiedinfo.h" #include "llconsole.h" #include "llcontainerview.h" #include "llconversationlog.h" #include "lldebugview.h" #include "lldrawable.h" #include "lleventnotifier.h" #include "llface.h" #include "llfeaturemanager.h" //#include "llfirstuse.h" #include "llfloaterhud.h" #include "llfloaterland.h" #include "llfloatertopobjects.h" #include "llfloaterworldmap.h" #include "llgesturemgr.h" #include "llgroupmgr.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" #include "llbufferstream.h" // For SL Grid Status #include "llimage.h" #include "llinventorybridge.h" #include "llinventorymodel.h" #include "llinventorymodelbackgroundfetch.h" #include "llkeyboard.h" #include "llloginhandler.h" // gLoginHandler, SLURL support #include "lllogininstance.h" // Host the login module. // [FS Login Panel] //#include "llpanellogin.h" #include "fspanellogin.h" // [FS Login Panel] #include "llmutelist.h" #include "llavatarpropertiesprocessor.h" #include "llpanelgrouplandmoney.h" #include "llpanelgroupnotices.h" #include "llparcel.h" #include "llpreview.h" #include "llpreviewscript.h" #include "llproxy.h" #include "llproductinforequest.h" #include "llqueryflags.h" #include "llsecapi.h" #include "llselectmgr.h" #include "llsky.h" #include "llstatview.h" #include "llstatusbar.h" // sendMoneyBalanceRequest(), owns L$ balance #include "llsurface.h" #include "lltexturecache.h" #include "lltexturefetch.h" #include "lltoolmgr.h" #include "lltrans.h" #include "llui.h" #include "lluiusage.h" #include "llurldispatcher.h" #include "llurlentry.h" #include "llslurl.h" #include "llurlhistory.h" #include "llurlwhitelist.h" #include "llvieweraudio.h" #include "llviewerassetstorage.h" #include "llviewercamera.h" #include "llviewerdisplay.h" #include "llviewergenericmessage.h" #include "llviewergesture.h" #include "llviewertexturelist.h" #include "llviewermedia.h" #include "llviewermenu.h" #include "llviewermessage.h" #include "llviewernetwork.h" #include "llviewerobjectlist.h" #include "llviewerparcelaskplay.h" #include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "llviewerstats.h" #include "llviewerstatsrecorder.h" #include "llviewerthrottle.h" #include "llviewerwindow.h" #include "llvoavatar.h" #include "llvoavatarself.h" #include "llweb.h" #include "llworld.h" #include "llworldmapmessage.h" #include "llxfermanager.h" #include "pipeline.h" #include "llappviewer.h" #include "llfasttimerview.h" #include "llfloatermap.h" #include "llweb.h" #include "llvoiceclient.h" #include "llnamelistctrl.h" #include "llnamebox.h" #include "llnameeditor.h" #include "llpostprocess.h" #include "llagentlanguage.h" #include "llwearable.h" #include "llinventorybridge.h" #include "llappearancemgr.h" #include "llavatariconctrl.h" #include "llvoicechannel.h" #include "llpathfindingmanager.h" #include "llremoteparcelrequest.h" // [RLVa:KB] - Checked: RLVa-1.2.0 #include "rlvhandler.h" // [/RLVa:KB] #include "lllogin.h" #include "llevents.h" #include "llstartuplistener.h" #include "lltoolbarview.h" #include "llexperiencelog.h" #include "llcleanup.h" #include "llenvironment.h" #include "llstacktrace.h" #include "threadpool.h" #include "llperfstats.h" #if LL_WINDOWS #include "lldxhardware.h" #endif // Firestorm includes // [FS communication UI] //#include "llfloaterimsession.h" #include "fsfloaterim.h" // [FS communication UI] #include "growlmanager.h" #include "fsassetblacklist.h" #include "fsavatarrenderpersistence.h" #include "fscommon.h" #include "fscorehttputil.h" #include "fsdata.h" #include "fsfloatercontacts.h" #include "fsfloaterimcontainer.h" #include "fsfloaternearbychat.h" #include "fsfloatersearch.h" #include "fsfloaterstreamtitle.h" #include "fsfloaterwearablefavorites.h" #include "fslslbridge.h" #include "fsradar.h" #include "fsregistrarutils.h" #include "fsscriptlibrary.h" #include "lfsimfeaturehandler.h" #include "lggcontactsets.h" #include "llfloatersearch.h" #include "llfloatersidepanelcontainer.h" #include "llfriendcard.h" #include "llnotificationmanager.h" #include "llpresetsmanager.h" #include "llprogressview.h" #include "lltoolbarview.h" #include "NACLantispam.h" #include "streamtitledisplay.h" #include "tea.h" // // exported globals // bool gAgentMovementCompleted = false; S32 gMaxAgentGroups; // OpenSim legacy economy support const std::string SCREEN_HOME_FILENAME = "screen_home%s.png"; const std::string SCREEN_LAST_FILENAME = "screen_last%s.png"; LLPointer gStartTexture; // // Imported globals // extern S32 gStartImageWidth; extern S32 gStartImageHeight; extern std::string gWindowTitle; // // local globals // static bool gGotUseCircuitCodeAck = false; static std::string sInitialOutfit; static std::string sInitialOutfitGender; // "male" or "female" static bool gUseCircuitCallbackCalled = false; EStartupState LLStartUp::gStartupState = STATE_FIRST; LLSLURL LLStartUp::sStartSLURL; std::string LLStartUp::sStartSLURLString; static LLPointer gUserCredential; static std::string gDisplayName; static bool gRememberPassword = true; static bool gRememberUser = true; static U64 gFirstSimHandle = 0; static LLHost gFirstSim; static std::string gFirstSimSeedCap; static LLVector3 gAgentStartLookAt(1.0f, 0.f, 0.f); static std::string gAgentStartLocation = "safe"; static bool mLoginStatePastUI = false; static bool mBenefitsSuccessfullyInit = false; const F32 STATE_AGENT_WAIT_TIMEOUT = 240; //seconds const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_ABORT = 4; // Give region 4 chances std::unique_ptr LLStartUp::sStateWatcher(new LLEventStream("StartupState")); std::unique_ptr LLStartUp::sListener(new LLStartupListener()); std::unique_ptr LLStartUp::sPhases(new LLViewerStats::PhaseMap); // // local function declaration // void login_show(); void login_callback(S32 option, void* userdata); void show_release_notes_if_required(); //void show_first_run_dialog(); // Unused in Firestorm bool first_run_dialog_callback(const LLSD& notification, const LLSD& response); void set_startup_status(const F32 frac, const std::string& string, const std::string& msg); bool login_alert_status(const LLSD& notification, const LLSD& response); void use_circuit_callback(void**, S32 result); void register_viewer_callbacks(LLMessageSystem* msg); void asset_callback_nothing(const LLUUID&, LLAssetType::EType, void*, S32); bool callback_choose_gender(const LLSD& notification, const LLSD& response); void release_start_screen(); void reset_login(); LLSD transform_cert_args(LLPointer cert); void general_cert_done(const LLSD& notification, const LLSD& response); void trust_cert_done(const LLSD& notification, const LLSD& response); void apply_udp_blacklist(const std::string& csv); // Aurora Sim //bool process_login_success_response(); bool process_login_success_response(U32 &first_sim_size_x, U32 &first_sim_size_y); // Aurora Sim void on_benefits_failed_callback(const LLSD& notification, const LLSD& response); void transition_back_to_login_panel(const std::string& emsg); // FIRE-18250: Option to disable default eye movement void update_static_eyes(); // FIRE-18250 void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is_group) { LLNameBox::refreshAll(id, full_name, is_group); LLNameEditor::refreshAll(id, full_name, is_group); // TODO: Actually be intelligent about the refresh. // For now, just brute force refresh the dialogs. dialog_refresh_all(); } // // exported functionality // void do_startup_frame() { // Until after STATE_AGENT_SEND we don't get very many UDP packets to poll the socket, // and after STATE_PRECACHE the LLAppViewer::idleNetwork() will do UDP processing, // so we only bother to process between those two states. EStartupState state = LLStartUp::getStartupState(); if (state > STATE_AGENT_SEND && state < STATE_PRECACHE) { // drain the UDP socket... U64 t0 = totalTime(); constexpr U64 MAX_STARTUP_FRAME_TIME = 2000; // usec constexpr U64 MAX_STARTUP_FRAME_MESSAGES = 100; S32 num_messages = 0; bool needs_drain = false; LockMessageChecker lmc(gMessageSystem); while (lmc.checkAllMessages(gFrameCount, gServicePump)) { if (gDoDisconnect) { // We're disconnecting, don't process any more messages from the server // We're usually disconnecting due to either network corruption or a // server going down, so this is OK. break; } if (++num_messages >= MAX_STARTUP_FRAME_MESSAGES || (totalTime() - t0) > MAX_STARTUP_FRAME_TIME) { needs_drain = true; break; } } if (needs_drain || gMessageSystem->mPacketRing.getNumBufferedPackets() > 0) { gMessageSystem->drainUdpSocket(); } lmc.processAcks(); } // ...then call display_startup() display_startup(); } void pump_idle_startup_network(void) { // while there are message to process: // process one then call display_startup() { LockMessageChecker lmc(gMessageSystem); while (lmc.checkAllMessages(gFrameCount, gServicePump)) { display_startup(); } lmc.processAcks(); } // finally call one last display_startup() display_startup(); } // // local classes // // static bool sGridListRequestReady = false; void downloadGridlistComplete( LLSD const &aData ) { LL_DEBUGS() << aData << LL_ENDL; LLSD header = aData[ LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS ][ LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; LLDate lastModified; if (header.has("last-modified")) { lastModified.secondsSinceEpoch( FSCommon::secondsSinceEpochFromString( "%a, %d %b %Y %H:%M:%S %ZP", header["last-modified"].asString() ) ); } LLSD data = aData; data.erase( LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS ); std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "grids.remote.xml"); llofstream out_file; out_file.open(filename.c_str()); LLSDSerialize::toPrettyXML( data, out_file); out_file.close(); LL_INFOS() << "GridListRequest: got new list." << LL_ENDL; sGridListRequestReady = true; } void downloadGridlistError( LLSD const &aData, std::string const &aURL ) { LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(aData); if (status.getType() == HTTP_NOT_MODIFIED) { LL_INFOS("fsdata") << "Didn't download grid list from " << aURL << " - no newer version available" << LL_ENDL; } else { LL_WARNS() << "Failed to download grid list from " << aURL << LL_ENDL; } sGridListRequestReady = true; } void downloadGridstatusComplete(LLSD const &aData) { LLSD header = aData[ LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS ][ LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; const LLSD::Binary &rawData = aData[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary(); if (rawData.size() == 0) { FSCommon::report_to_nearby_chat(LLTrans::getString("SLGridStatusInvalidMsg")); LL_WARNS("SLGridStatusResponder") << "Error - empty output" << LL_ENDL; return; } std::string fetchedNews; fetchedNews.assign( rawData.begin(), rawData.end() ); size_t itemStart = fetchedNews.find(""); size_t itemEnd = fetchedNews.find(""); if (itemEnd != std::string::npos && itemStart != std::string::npos) { // Isolate latest news data itemStart += 6; std::string theNews = fetchedNews.substr(itemStart, itemEnd - itemStart); // Check for and remove CDATA characters if they're present size_t titleStart = theNews.find("<![CDATA["); if (titleStart != std::string::npos) { theNews.replace(titleStart, 16, "<title>"); } size_t titleEnd = theNews.find("]]>"); if (titleEnd != std::string::npos) { theNews.replace(titleEnd, 11, ""); } size_t descStart = theNews.find(""); } size_t descEnd = theNews.find("]]>"); if (descEnd != std::string::npos) { theNews.replace(descEnd, 17, ""); } size_t linkStart = theNews.find(""); } size_t linkEnd = theNews.find("]]>"); if (linkEnd != std::string::npos) { theNews.replace(linkEnd, 10, ""); } // Get indexes titleStart = theNews.find(""); descStart = theNews.find("<description>"); linkStart = theNews.find("<link>"); titleEnd = theNews.find(""); descEnd = theNews.find(""); linkEnd = theNews.find(""); if (titleStart != std::string::npos && descStart != std::string::npos && linkStart != std::string::npos && titleEnd != std::string::npos && descEnd != std::string::npos && linkEnd != std::string::npos) { titleStart += 7; descStart += 13; linkStart += 6; std::string newsTitle = theNews.substr(titleStart, titleEnd - titleStart); std::string newsDesc = theNews.substr(descStart, descEnd - descStart); std::string newsLink = theNews.substr(linkStart, linkEnd - linkStart); LLStringUtil::trim(newsTitle); LLStringUtil::trim(newsDesc); LLStringUtil::trim(newsLink); FSCommon::report_to_nearby_chat("[ " + newsTitle + " ] " + newsDesc + " [ " + newsLink + " ]"); } else { FSCommon::report_to_nearby_chat(LLTrans::getString("SLGridStatusInvalidMsg")); LL_WARNS("SLGridStatusResponder") << "Error - inner tag(s) missing" << LL_ENDL; } } else { FSCommon::report_to_nearby_chat(LLTrans::getString("SLGridStatusInvalidMsg")); LL_WARNS("SLGridStatusResponder") << "Error - output without " << LL_ENDL; } } void downloadGridstatusError(LLSD const &aData, std::string const &aURL) { LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(aData); LL_WARNS("SLGridStatusResponder") << "Error - status " << status.getType() << LL_ENDL; if (status.getType() == HTTP_INTERNAL_ERROR) { FSCommon::report_to_nearby_chat(LLTrans::getString("SLGridStatusTimedOut")); } else { LLStringUtil::format_map_t args; args["STATUS"] = llformat("%d", status.getType()); FSCommon::report_to_nearby_chat(LLTrans::getString("SLGridStatusOtherError", args)); } } // // Check for test build expiration bool is_testbuild_expired() { #if TESTBUILD std::string datestr = __DATE__; std::istringstream iss_date(datestr); std::string str_month; S32 day; S32 year; S32 month = 1; iss_date >> str_month >> day >> year; if (str_month == "Jan") month = 1; else if (str_month == "Feb") month = 2; else if (str_month == "Mar") month = 3; else if (str_month == "Apr") month = 4; else if (str_month == "May") month = 5; else if (str_month == "Jun") month = 6; else if (str_month == "Jul") month = 7; else if (str_month == "Aug") month = 8; else if (str_month == "Sep") month = 9; else if (str_month == "Oct") month = 10; else if (str_month == "Nov") month = 11; else if (str_month == "Dec") month = 12; tm t = {0}; t.tm_mon = month - 1; t.tm_mday = day; t.tm_year = year - 1900; t.tm_hour = 0; t.tm_min = 0; t.tm_sec = 0; time_t expiry_time = mktime(&t) + (S32(TESTBUILDPERIOD) + 1) * 24 * 60 * 60; time_t current_time = time(NULL); return current_time > expiry_time; #else return false; #endif } // void update_texture_fetch() { LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread gTextureList.updateImages(0.10f); if (LLImageGLThread::sEnabledTextures) { std::shared_ptr main_queue = LL::WorkQueue::getInstance("mainloop"); main_queue->runFor(std::chrono::milliseconds(1)); } } void set_flags_and_update_appearance() { // this may be called from a coroutine but has many side effects // in non-thread-safe classes, post to main loop auto work = []() { LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); LLInventoryModelBackgroundFetch::instance().start(); }; LLAppViewer::instance()->postToMainCoro(work); } // Returns false to skip other idle processing. Should only return // true when all initialization done. bool idle_startup() { if (gViewerWindow == NULL) { // We expect window to be initialized LL_WARNS_ONCE() << "gViewerWindow is not initialized" << LL_ENDL; return false; // No world yet } LL_PROFILE_ZONE_SCOPED; const F32 PRECACHING_DELAY = gSavedSettings.getF32("PrecachingDelay"); static LLTimer timeout; static LLTimer login_time; // until this is encapsulated, this little hack for the // auth/transform loop will do. static F32 progress = 0.10f; static std::string auth_desc; static std::string auth_message; // Aurora Sim static U32 first_sim_size_x = 256; static U32 first_sim_size_y = 256; // Aurora Sim static LLVector3 agent_start_position_region(10.f, 10.f, 10.f); // default for when no space server // last location by default static S32 agent_location_id = START_LOCATION_ID_LAST; static bool show_connect_box = true; //static bool stipend_since_login = false; // HACK: These are things from the main loop that usually aren't done // until initialization is complete, but need to be done here for things // to work. gIdleCallbacks.callFunctions(); gViewerWindow->updateUI(); LLMortician::updateClass(); const std::string delims (" "); std::string system; size_t begIdx, endIdx; std::string osString = LLOSInfo::instance().getOSStringSimple(); begIdx = osString.find_first_not_of (delims); endIdx = osString.find_first_of (delims, begIdx); system = osString.substr (begIdx, endIdx - begIdx); system += "Locale"; std::string locale = LLTrans::getString(system); if (locale != LLStringUtil::getLocale()) // is there a reason to do this on repeat? { LLStringUtil::setLocale(locale); // Not all locales have AMPM, test it if (LLStringOps::sAM.empty()) // Might already be overriden from LLAppViewer::init() { LLDate datetime(0.0); std::string val = datetime.toHTTPDateString("%p"); if (val.empty()) { LL_DEBUGS("InitInfo") << "Current locale \"" << locale << "\" " << "doesn't support AM/PM time format" << LL_ENDL; // fallback to declarations in strings.xml LLStringOps::sAM = LLTrans::getString("dateTimeAM"); LLStringOps::sPM = LLTrans::getString("dateTimePM"); } } } //note: Removing this line will cause incorrect button size in the login screen. -- bao. gTextureList.updateImages(0.01f) ; if ( STATE_FIRST == LLStartUp::getStartupState() ) { static bool first_call = true; if (first_call) { // Other phases get handled when startup state changes, // need to capture the initial state as well. LLStartUp::getPhases().startPhase(LLStartUp::getStartupStateString()); first_call = false; } gViewerWindow->showCursor(); gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); std::string beamsFolder(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "beams","")); LLFile::mkdir(beamsFolder.c_str()); std::string beamsColorsFolder(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "beamsColors","")); LLFile::mkdir(beamsColorsFolder.c_str()); ///////////////////////////////////////////////// // // Initialize stuff that doesn't need data from simulators // std::string lastGPU = gSavedSettings.getString("LastGPUString"); std::string thisGPU = LLFeatureManager::getInstance()->getGPUString(); GrowlManager::initiateManager(); // Growl support // Store current font and skin for system info (FIRE-6806) gSavedSettings.setString("FSInternalFontSettingsFile", gSavedSettings.getString("FSFontSettingsFile")); gSavedSettings.setString("FSInternalSkinCurrent", gSavedSettings.getString("FSSkinCurrentReadableName")); gSavedSettings.setString("FSInternalSkinCurrentTheme", gSavedSettings.getString("FSSkinCurrentThemeReadableName")); // // Notification not showing if hiding the UI gSavedSettings.setBOOL("FSInternalShowNavbarNavigationPanel", gSavedSettings.getBOOL("ShowNavbarNavigationPanel")); gSavedSettings.setBOOL("FSInternalShowNavbarFavoritesPanel", gSavedSettings.getBOOL("ShowNavbarFavoritesPanel")); // // Added to determine if toolbar gets hidden when empty if (gToolBarView) gToolBarView->setHideBottomOnEmpty(FSCommon::isLegacySkin()); if (LLFeatureManager::getInstance()->isSafe()) { LLNotificationsUtil::add("DisplaySetToSafe"); } else if ((gSavedSettings.getS32("LastFeatureVersion") < LLFeatureManager::getInstance()->getVersion()) && (gSavedSettings.getS32("LastFeatureVersion") != 0)) { LLNotificationsUtil::add("DisplaySetToRecommendedFeatureChange"); } else if ( ! lastGPU.empty() && (lastGPU != thisGPU)) { LLSD subs; subs["LAST_GPU"] = lastGPU; subs["THIS_GPU"] = thisGPU; LLNotificationsUtil::add("DisplaySetToRecommendedGPUChange", subs); } else if (!gViewerWindow->getInitAlert().empty()) { LLNotificationsUtil::add(gViewerWindow->getInitAlert()); } //------------------------------------------------- // Init the SOCKS 5 proxy if the user has configured // one. We need to do this early in case the user // is using SOCKS for HTTP so we get the login // screen and HTTP tables via SOCKS. //------------------------------------------------- LLStartUp::startLLProxy(); gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion()); gSavedSettings.setString("LastGPUString", thisGPU); std::string xml_file = LLUI::locateSkin("xui_version.xml"); LLXMLNodePtr root; bool xml_ok = false; if (LLXMLNode::parseFile(xml_file, root, NULL)) { if( (root->hasName("xui_version") ) ) { std::string value = root->getValue(); F32 version = 0.0f; LLStringUtil::convertToF32(value, version); if (version >= 1.0f) { xml_ok = true; } } } if (!xml_ok) { // If XML is bad, there's a good possibility that notifications.xml is ALSO bad. // If that's so, then we'll get a fatal error on attempting to load it, // which will display a nontranslatable error message that says so. // Otherwise, we'll display a reasonable error message that IS translatable. LLAppViewer::instance()->earlyExit("BadInstallation"); } // // Statistics stuff // // Load autopilot and stats stuff gAgentPilot.load(); //gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps")); // Load the throttle settings gViewerThrottle.load(); // // Initialize messaging system // LL_DEBUGS("AppInit") << "Initializing messaging system..." << LL_ENDL; std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg"); LLFILE* found_template = NULL; found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */ #if LL_WINDOWS // On the windows dev builds, unpackaged, the message_template.msg // file will be located in: // build-vc**/newview//app_settings if (!found_template) { message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg"); found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ } #elif LL_DARWIN // On Mac dev builds, message_template.msg lives in: // indra/build-*/newview//Second Life/Contents/Resources/app_settings if (!found_template) { message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "message_template.msg"); found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ } #endif if (found_template) { fclose(found_template); U32 port = gSavedSettings.getU32("UserConnectionPort"); if ((NET_USE_OS_ASSIGNED_PORT == port) && // if nothing specified on command line (-port) (gSavedSettings.getBOOL("ConnectionPortEnabled"))) { port = gSavedSettings.getU32("ConnectionPort"); } // TODO parameterize const F32 circuit_heartbeat_interval = 5; const F32 circuit_timeout = 100; const LLUseCircuitCodeResponder* responder = NULL; bool failure_is_fatal = true; if(!start_messaging_system( message_template_path, port, LLVersionInfo::instance().getMajor(), LLVersionInfo::instance().getMinor(), LLVersionInfo::instance().getPatch(), false, std::string(), responder, failure_is_fatal, circuit_heartbeat_interval, circuit_timeout)) { std::string diagnostic = llformat(" Error: %d", gMessageSystem->getErrorCode()); LL_WARNS("AppInit") << diagnostic << LL_ENDL; LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic)); } #if LL_WINDOWS // On the windows dev builds, unpackaged, the message.xml file will // be located in indra/build-vc**/newview//app_settings. std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml"); if (!LLFile::isfile(message_path.c_str())) { LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "")); } else { LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); } #else LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); #endif } else { LLAppViewer::instance()->earlyExit("MessageTemplateNotFound", LLSD().with("PATH", message_template_path)); } if(gMessageSystem && gMessageSystem->isOK()) { // Initialize all of the callbacks in case of bad message // system data LLMessageSystem* msg = gMessageSystem; msg->setExceptionFunc(MX_UNREGISTERED_MESSAGE, invalid_message_callback, NULL); msg->setExceptionFunc(MX_PACKET_TOO_SHORT, invalid_message_callback, NULL); // running off end of a packet is now valid in the case // when a reader has a newer message template than // the sender /*msg->setExceptionFunc(MX_RAN_OFF_END_OF_PACKET, invalid_message_callback, NULL);*/ msg->setExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE, invalid_message_callback, NULL); if (gSavedSettings.getBOOL("LogMessages")) { LL_DEBUGS("AppInit") << "Message logging activated!" << LL_ENDL; msg->startLogging(); } // start the xfer system. by default, choke the downloads // a lot... const S32 VIEWER_MAX_XFER = 3; start_xfer_manager(); gXferManager->setMaxIncomingXfers(VIEWER_MAX_XFER); F32 xfer_throttle_bps = gSavedSettings.getF32("XferThrottle"); if (xfer_throttle_bps > 1.f) { gXferManager->setUseAckThrottling(true); gXferManager->setAckThrottleBPS(xfer_throttle_bps); } gAssetStorage = new LLViewerAssetStorage(msg, gXferManager); F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage"); msg->mPacketRing.setDropPercentage(dropPercent); } LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL; // load global xml data FSData::instance().startDownload(); // // #ifndef SINGLEGRID if(!gSavedSettings.getBOOL("GridListDownload")) { sGridListRequestReady = true; } else { std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "grids.remote.xml"); llstat file_stat; //platform independent wrapper for stat time_t last_modified = 0; if(!LLFile::stat(filename, &file_stat))//exists { last_modified = file_stat.st_mtime; } std::string url = gSavedSettings.getString("GridListDownloadURL"); FSCoreHttpUtil::callbackHttpGet(url, last_modified, boost::bind(downloadGridlistComplete, _1), boost::bind(downloadGridlistError, _1, url)); } #else sGridListRequestReady = true; #endif #ifdef OPENSIM // // Fetch grid infos as needed LLGridManager::getInstance()->initGrids(); LLStartUp::setStartupState( STATE_FETCH_GRID_INFO ); // #else LLGridManager::getInstance()->initialize(std::string()); // fsdata support //LLStartUp::setStartupState( STATE_AUDIO_INIT ); LLStartUp::setStartupState( STATE_FETCH_GRID_INFO ); // #endif // OPENSIM // } if (STATE_FETCH_GRID_INFO == LLStartUp::getStartupState()) { // static LLFrameTimer grid_timer; const F32 grid_time = grid_timer.getElapsedTimeF32(); const F32 MAX_WAIT_TIME = 15.f;//don't wait forever if(grid_time > MAX_WAIT_TIME || #ifdef OPENSIM ( sGridListRequestReady && LLGridManager::getInstance()->isReadyToLogin() && #endif // fsdata support FSData::instance().getFSDataDone()) #ifdef OPENSIM ) #endif // { LLStartUp::setStartupState( STATE_AUDIO_INIT ); } else { ms_sleep(1); return false; } // } if (STATE_AUDIO_INIT == LLStartUp::getStartupState()) { // parsing slurls depending on the grid obviously // only works after we have a grid list // Anyway this belongs into the gridmanager as soon as // it is cleaner if(!LLStartUp::getStartSLURLString().empty()) { LLStartUp::setStartSLURL(LLStartUp::getStartSLURLString()); } // //------------------------------------------------- // Init audio, which may be needed for prefs dialog // or audio cues in connection UI. //------------------------------------------------- if (false == gSavedSettings.getBOOL("NoAudio")) { delete gAudiop; gAudiop = NULL; #ifdef LL_FMODSTUDIO #if !LL_WINDOWS if (NULL == getenv("LL_BAD_FMODSTUDIO_DRIVER")) #endif // !LL_WINDOWS { gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODSTUDIO(gSavedSettings.getBOOL("FMODProfilerEnable"), gSavedSettings.getU32("FMODResampleMethod")); } #endif #ifdef LL_OPENAL #if !LL_WINDOWS // if (NULL == getenv("LL_BAD_OPENAL_DRIVER")) if (!gAudiop && NULL == getenv("LL_BAD_OPENAL_DRIVER")) #else if (!gAudiop) #endif // !LL_WINDOWS { gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL(); } #endif if (gAudiop) { #if LL_WINDOWS // FMOD Studio and FMOD Ex on Windows needs the window handle to stop playing audio // when window is minimized. JC void* window_handle = (HWND)gViewerWindow->getPlatformWindow(); #else void* window_handle = NULL; #endif if (gAudiop->init(window_handle, LLAppViewer::instance()->getSecondLifeTitle())) { if (false == gSavedSettings.getBOOL("UseMediaPluginsForStreamingAudio")) { LL_INFOS("AppInit") << "Using default impl to render streaming audio" << LL_ENDL; gAudiop->setStreamingAudioImpl(gAudiop->createDefaultStreamingAudioImpl()); } // if the audio engine hasn't set up its own preferred handler for streaming audio // then set up the generic streaming audio implementation which uses media plugins if (NULL == gAudiop->getStreamingAudioImpl()) { LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); } // Output device selection gAudiop->setDevice(LLUUID(gSavedSettings.getString("FSOutputDeviceUUID"))); gAudiop->setMuted(true); } else { LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL; delete gAudiop; gAudiop = NULL; } } } LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL; if (LLTimer::knownBadTimer()) { LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL; } #ifdef LL_DISCORD LLAppViewer::initDiscordSocial(); #endif // // Log on to system // if (gUserCredential.isNull()) { gUserCredential = gLoginHandler.initializeLoginInfo(); } // Previous initializeLoginInfo may have generated user credentials. Re-check them. if (gUserCredential.isNull()) { show_connect_box = true; } else if (gSavedSettings.getBOOL("AutoLogin")) { // Log into last account // Option to not save password if using login cmdline switch; // gLoginHandler.initializeLoginInfo() sets AutoLogin to true, // so we end up here! //gRememberPassword = true; //gRememberUser = true; //gSavedSettings.setBOOL("RememberPassword", true); //gRememberUser = gSavedSettings.getBOOL("RememberUser"); if (gSavedSettings.getBOOL("FSLoginDontSavePassword")) { gRememberPassword = false; } else { gRememberPassword = true; gSavedSettings.setBOOL("RememberPassword", true); } // show_connect_box = false; } // Handled via FSLoginDontSavePassword debug setting //else if (gSavedSettings.getLLSD("UserLoginInfo").size() == 3) //{ // // Console provided login&password // gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); // gRememberUser = gSavedSettings.getBOOL("RememberUser"); // show_connect_box = false; //} // else { gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); gRememberUser = gSavedSettings.getBOOL("RememberUser"); show_connect_box = true; } // [RLVa:KB] - Patch: RLVa-2.1.0 if (gSavedSettings.get(RlvSettingNames::Main)) { show_connect_box = true; } // [/RVA:KB] //setup map of datetime strings to codes and slt & local time offset from utc // *TODO: Does this need to be here? LLStringOps::setupDatetimeInfo(false); // [FIRE-22130] for LOD Factors > 4 reset to the detected dafault if (gSavedSettings.getF32("RenderVolumeLODFactor") > 4.f) { bool feature_table_success = false; LLFeatureManager& feature_manager = LLFeatureManager::instance(); U32 level = gSavedSettings.getU32("RenderQualityPerformance"); if (feature_manager.isValidGraphicsLevel(level)) { std::string level_name = feature_manager.getNameForGraphicsLevel(level); LLFeatureList* feature_list = feature_manager.findMask(level_name); if (feature_list) { F32 new_val = feature_list->getRecommendedValue("RenderVolumeLODFactor"); if (new_val > 0.f && new_val <= 4.f) { feature_table_success = true; gSavedSettings.setF32("RenderVolumeLODFactor", new_val); LL_INFOS("AppInit") << "LOD Factor too high. Resetting to recommended value for graphics level '" << level_name << "': " << new_val << LL_ENDL; } } } if (!feature_table_success) { gSavedSettings.getControl("RenderVolumeLODFactor")->resetToDefault(true); if (gSavedSettings.getF32("RenderVolumeLODFactor") > 4.f) { gSavedSettings.setF32("RenderVolumeLODFactor", 2.f); } LL_INFOS("AppInit") << "LOD Factor too high. Resetting to recommended value for global default: " << gSavedSettings.getF32("RenderVolumeLODFactor") << LL_ENDL; } } // // Go to the next startup state LLStartUp::setStartupState( STATE_BROWSER_INIT ); return false; } if (STATE_BROWSER_INIT == LLStartUp::getStartupState()) { LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL; std::string msg = LLTrans::getString("LoginInitializingBrowser"); set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str()); do_startup_frame(); // LLViewerMedia::initBrowser(); LLStartUp::setStartupState( STATE_LOGIN_SHOW ); return false; } if (STATE_LOGIN_SHOW == LLStartUp::getStartupState()) { LL_DEBUGS("AppInit") << "Initializing Window, show_connect_box = " << show_connect_box << LL_ENDL; // if we've gone backwards in the login state machine, to this state where we show the UI // AND the debug setting to exit in this case is true, then go ahead and bail quickly if ( mLoginStatePastUI && gSavedSettings.getBOOL("QuitOnLoginActivated") ) { LL_DEBUGS("AppInit") << "taking QuitOnLoginActivated exit" << LL_ENDL; // no requirement for notification here - just exit LLAppViewer::instance()->earlyExitNoNotify(); } gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); // Login screen needs menus for preferences, but we can enter // this startup phase more than once. if (gLoginMenuBarView == NULL) { // Moved this to initBase() in llviewerwindow.cpp to get the edit menu set up // before any text widget uses it // initialize_spellcheck_menu(); // init_menus(); } show_release_notes_if_required(); if (show_connect_box) { LL_DEBUGS("AppInit") << "show_connect_box on" << LL_ENDL; // Load all the name information out of the login view // NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't // show the login view until login_show() is called below. if (gUserCredential.isNull()) { LL_DEBUGS("AppInit") << "loading credentials from gLoginHandler" << LL_ENDL; gUserCredential = gLoginHandler.initializeLoginInfo(); } // Make sure the process dialog doesn't hide things gViewerWindow->setShowProgress(false,false); // Show the login dialog login_show(); // connect dialog is already shown, so fill in the names // //LLPanelLogin::populateFields( gUserCredential, gRememberUser, gRememberPassword); if (gUserCredential.notNull() && !FSPanelLogin::isCredentialSet()) { FSPanelLogin::setFields(gUserCredential, true); } // // [FS Login Panel] //LLPanelLogin::giveFocus(); FSPanelLogin::giveFocus(); // [FS Login Panel] // MAINT-3231 Show first run dialog only for Desura viewer if (gSavedSettings.getString("sourceid") == "1208_desura") { if (gSavedSettings.getBOOL("FirstLoginThisInstall")) { LL_INFOS("AppInit") << "FirstLoginThisInstall, calling show_first_run_dialog()" << LL_ENDL; // Don't show first run dialog, ever, at all. // show_first_run_dialog(); } else { LL_DEBUGS("AppInit") << "FirstLoginThisInstall off" << LL_ENDL; } } do_startup_frame(); LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input } else { LL_DEBUGS("AppInit") << "show_connect_box off, skipping to STATE_LOGIN_CLEANUP" << LL_ENDL; // skip directly to message template verification LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); } gViewerWindow->setNormalControlsVisible( false ); gLoginMenuBarView->setVisible( true ); gLoginMenuBarView->setEnabled( true ); // Fixing chat toasts to not show on the login page when login progress screens are disabled. LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(LLNotificationsUI::NEARBY_CHAT_CHANNEL_UUID); if (chat_channel) { chat_channel->removeToastsFromChannel(); } // show_debug_menus(); // Hide the splash screen LL_DEBUGS("AppInit") << "Hide the splash screen and show window" << LL_ENDL; LLSplashScreen::hide(); // Push our window frontmost gViewerWindow->getWindow()->show(); // DEV-16927. The following code removes errant keystrokes that happen while the window is being // first made visible. #ifdef _WIN32 LL_DEBUGS("AppInit") << "Processing PeekMessage" << LL_ENDL; MSG msg; while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ) { } LL_DEBUGS("AppInit") << "PeekMessage processed" << LL_ENDL; #endif do_startup_frame(); timeout.reset(); return false; } if (STATE_LOGIN_WAIT == LLStartUp::getStartupState()) { // when we get to this state, we've already been past the login UI // (possiblely automatically) - flag this so we can test in the // STATE_LOGIN_SHOW state if we've gone backwards mLoginStatePastUI = true; // Don't do anything. Wait for the login view to call the login_callback, // which will push us to the next state. // display() function will be the one to run do_startup_frame() // Sleep so we don't spin the CPU ms_sleep(1); return false; } if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState()) { // Check for test build expiration if (is_testbuild_expired()) { LL_INFOS() << "This test version has expired and cannot be used any further." << LL_ENDL; LLNotificationsUtil::add("TestversionExpired", LLSD(), LLSD(), login_alert_done); LLStartUp::setStartupState(STATE_LOGIN_CONFIRM_NOTIFICATON); show_connect_box = true; return false; } // // Login block LLSD blocked = FSData::instance().allowedLogin(); if (blocked.isMap()) //hack for testing for an empty LLSD { LLNotificationsUtil::add("BlockLoginInfo", blocked, LLSD(), login_alert_done); LLStartUp::setStartupState(STATE_LOGIN_CONFIRM_NOTIFICATON); show_connect_box = true; return false; } // // Post login screen, we should see if any settings have changed that may // require us to either start/stop or change the socks proxy. As various communications // past this point may require the proxy to be up. if (!LLStartUp::startLLProxy()) { // Proxy start up failed, we should now bail the state machine // startLLProxy() will have reported an error to the user // already, so we just go back to the login screen. The user // could then change the preferences to fix the issue. LLStartUp::setStartupState(STATE_LOGIN_SHOW); return false; } // [RLVa:KB] - Checked: RLVa-0.2.1 if (gSavedSettings.get(RlvSettingNames::Main)) { RlvHandler::setEnabled(true); } // [/RLVa:KB] // reset the values that could have come in from a slurl // DEV-42215: Make sure they're not empty -- gUserCredential // might already have been set from gSavedSettings, and it's too bad // to overwrite valid values with empty strings. if (show_connect_box) { // TODO if not use viewer auth // Load all the name information out of the login view // [FS Login Panel] //LLPanelLogin::getFields(gUserCredential, gRememberUser, gRememberPassword); FSPanelLogin::getFields(gUserCredential, gRememberPassword); // [FS Login Panel] // end TODO // HACK: Try to make not jump on login gKeyboard->resetKeys(); } // when we get to this state, we've already been past the login UI // (possiblely automatically) - flag this so we can test in the // STATE_LOGIN_SHOW state if we've gone backwards mLoginStatePastUI = true; // save the credentials std::string userid = "unknown"; if (gUserCredential.notNull()) { userid = gUserCredential->userID(); // [FS Login Panel] //if (gRememberUser) //{ // gSecAPIHandler->addToCredentialMap("login_list", gUserCredential, gRememberPassword); // // Legacy viewers use this method to store user credentials, newer viewers // // reuse it to be compatible and to remember last session // gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); //} // [FS Login Panel] } // Option to not save password if using login cmdline switch //gSavedSettings.setBOOL("RememberPassword", gRememberPassword); //gSavedSettings.setBOOL("RememberUser", gRememberUser); if (!gSavedSettings.getBOOL("FSLoginDontSavePassword")) { gSavedSettings.setBOOL("RememberPassword", gRememberPassword); } // LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; // gDebugInfo["LoginName"] = userid; // [SL:KB] - Patch: Viewer-CrashReporting | Checked: 2010-11-16 (Catznip-2.6.0a) | Added: Catznip-2.4.0b if (gCrashSettings.getBOOL("CrashSubmitName")) { // Only include the agent name if the user consented gDebugInfo["LoginName"] = userid; } // [/SL:KB] // We don't save this version of the title because it'll // be replaced later, we hope. -- TS size_t underscore_pos = userid.find_first_of('_'); std::string display_id = userid.substr(0,underscore_pos); if ((underscore_pos != std::string::npos) && (underscore_pos < userid.length()-1)) { std::string id_last = userid.substr(underscore_pos+1); if (id_last.compare("Resident") != 0) { display_id = display_id + " " + id_last; } } std::string window_title = gWindowTitle + " - " + display_id; LLStringUtil::truncate(window_title, 255); gViewerWindow->setTitle(window_title); // create necessary directories // *FIX: these mkdir's should error check // Seperate user directories per grid //gDirUtilp->setLindenUserDir(userid, gridlabel); std::string gridlabel = LLGridManager::getInstance()->getGridLabel(); gDirUtilp->setLindenUserDir(userid, LLGridManager::getInstance()->getGridLabel()); // LLFile::mkdir(gDirUtilp->getLindenUserDir()); // As soon as directories are ready initialize notification storages if (!LLPersistentNotificationStorage::instanceExists()) { // check existance since this part of code can be reached // twice due to login failures LLPersistentNotificationStorage::initParamSingleton(); LLDoNotDisturbNotificationStorage::initParamSingleton(); } else { // reinitialize paths in case user switched grids or accounts LLPersistentNotificationStorage::getInstance()->reset(); LLDoNotDisturbNotificationStorage::getInstance()->reset(); } // Set PerAccountSettingsFile to the default value. std::string settings_per_account = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount")); gSavedSettings.setString("PerAccountSettingsFile", settings_per_account); gDebugInfo["PerAccountSettingsFilename"] = settings_per_account; // Note: can't store warnings files per account because some come up before login // Overwrite default user settings with user settings LLAppViewer::instance()->loadSettingsFromDirectory("Account"); // Restore bottom toolbar layout now he have the user settings LLLayoutStack* chat_bar_stack = gToolBarView->findChild("chat_bar_stack"); if (chat_bar_stack) { chat_bar_stack->refreshFromSettings(); } // // Convert 'LogInstantMessages' into 'KeepConversationLogTranscripts' for backward compatibility (CHUI-743). // FIRE-11410 - Don't do this, handle it in settings restore and first run //LLControlVariablePtr logInstantMessagesControl = gSavedPerAccountSettings.getControl("LogInstantMessages"); //if (logInstantMessagesControl.notNull()) //{ // gSavedPerAccountSettings.setS32("KeepConversationLogTranscripts", logInstantMessagesControl->getValue() ? 2 : 1); //} // Need to set the LastLogoff time here if we don't have one. LastLogoff is used for "Recent Items" calculation // and startup time is close enough if we don't have a real value. if (gSavedPerAccountSettings.getU32("LastLogoff") == 0) { gSavedPerAccountSettings.setU32("LastLogoff", (U32)time_corrected()); } //Default the path if one isn't set. // *NOTE: unable to check variable differ from "InstantMessageLogPath" because it was // provided in pre 2.0 viewer. See EXT-6661 if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty()) { gDirUtilp->setChatLogsDir(gDirUtilp->getOSUserAppDir()); gSavedPerAccountSettings.setString("InstantMessageLogPath", gDirUtilp->getChatLogsDir()); } else { gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath")); } // FIRE-18247: Handle non-existent chat log location if (!gDirUtilp->fileExists(gSavedPerAccountSettings.getString("InstantMessageLogPath"))) { gDirUtilp->setChatLogsDir(gDirUtilp->getOSUserAppDir()); gSavedPerAccountSettings.setString("InstantMessageLogPath", gDirUtilp->getChatLogsDir()); } // // FIRE-22853 Make snapshots to disk not remember path and filename if the user doesnt want them to. if (!gSavedPerAccountSettings.getBOOL("FSRememberSnapshotPathSessions")) { gSavedPerAccountSettings.setString("SnapshotBaseDir", gSavedPerAccountSettings.getControl("SnapshotBaseDir")->getDefault().asString()); gSavedPerAccountSettings.setString("SnapshotBaseName", gSavedPerAccountSettings.getControl("SnapshotBaseName")->getDefault().asString()); } // // Seperate user directories per grid //gDirUtilp->setPerAccountChatLogsDir(userid); gDirUtilp->setPerAccountChatLogsDir(userid, gridlabel); // LLFile::mkdir(gDirUtilp->getChatLogsDir()); LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); // NaCl - Antispam NACLAntiSpamRegistry::instance(); // NaCl End // Create user fonts directory std::string user_fonts_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "fonts", "")); LLFile::mkdir(user_fonts_path_name.c_str()); // Initalize Account based asset_blacklist FSAssetBlacklist::getInstance()->init(); // load per grid data FSData::instance().downloadAgents(); // if (show_connect_box) { LLSLURL slurl; // WS: Close the Panel only, if we have DisableLoginScreens enabled. Else fade away. if(gSavedSettings.getBOOL("FSDisableLoginScreens")) // [FS Login Panel] //LLPanelLogin::closePanel(); FSPanelLogin::closePanel(); // [FS Login Panel] } // Load URL History File LLURLHistory::loadFile("url_history.xml"); // Load location history LLLocationHistory::getInstance()->load(); // FIRE-10607: Avatar icon controls show wrong picture when switching between SL main/beta grid // Moved further down until we know what grid we are connecting to // Load Avatars icons cache //LLAvatarIconIDCache::getInstance()->load(); // // [FS Persisted Avatar Render Settings] //LLRenderMuteList::getInstance()->loadFromFile(); //------------------------------------------------- // Handle startup progress screen //------------------------------------------------- // on startup the user can request to go to their home, // their last location, or some URL "-url //sim/x/y[/z]" // All accounts have both a home and a last location, and we don't support // more locations than that. Choose the appropriate one. JC // [RLVa:KB] - Checked: RLVa-0.2.1 if ( (RlvHandler::isEnabled()) && (RlvSettings::getLoginLastLocation()) ) { // Force login at the last location LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST)); } // [/RLVa:KB] switch (LLStartUp::getStartSLURL().getType()) { case LLSLURL::LOCATION: agent_location_id = START_LOCATION_ID_URL; break; case LLSLURL::LAST_LOCATION: agent_location_id = START_LOCATION_ID_LAST; break; default: agent_location_id = START_LOCATION_ID_HOME; break; } gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); // Display the startup progress bar. gViewerWindow->initTextures(agent_location_id); gViewerWindow->setShowProgress(true,!gSavedSettings.getBOOL("FSDisableLoginScreens")); gViewerWindow->setProgressCancelButtonVisible(true, LLTrans::getString("Quit")); gViewerWindow->revealIntroPanel(); // Ansariel: Update viewer help menu; Needed if logging // in by autologin or on SL it would show // the non-functional "About [CURRENT_GRID]" // and "[CURRENT_GRID] Help" menu entries update_grid_help(); // fsdata agents support //LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); LLStartUp::setStartupState(STATE_AGENTS_WAIT); // return false; } // fsdata support if (STATE_AGENTS_WAIT == LLStartUp::getStartupState()) { static LLFrameTimer agents_timer; const F32 agents_time = agents_timer.getElapsedTimeF32(); const F32 MAX_AGENTS_TIME = 15.f; if(agents_time > MAX_AGENTS_TIME || FSData::instance().getAgentsDone()) { LLStartUp::setStartupState(STATE_LOGIN_AUTH_INIT); } else { ms_sleep(1); return false; } } // if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState()) { gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridId(); // Update progress status and the display loop. auth_desc = LLTrans::getString("LoginInProgress"); set_startup_status(progress, auth_desc, auth_message); progress += 0.02f; do_startup_frame(); // eLastExecEvent last_exec_event = gLastExecEvent; const std::string current_grid = LLGridManager::getInstance()->getGrid(); const std::string last_grid = gSavedSettings.getString("LastConnectedGrid"); if (!last_grid.empty() && last_grid != current_grid) { // don't report crashes on a different grid than the one connecting to, // since a bad OpenSim setup can crash the viewer a lot last_exec_event = LAST_EXEC_NORMAL; } LLTrans::setDefaultArg("CURRENT_GRID", LLGridManager::getInstance()->getGridLabel()); // // Setting initial values... LLLoginInstance* login = LLLoginInstance::getInstance(); login->setNotificationsInterface(LLNotifications::getInstance()); login->setSerialNumber(LLAppViewer::instance()->getSerialNumber()); // // login->setLastExecEvent(gLastExecEvent); login->setLastExecDuration(gLastExecDuration); login->setLastExecEvent(last_exec_event); // login->setLastAgentSessionId(gLastAgentSessionId); // This call to LLLoginInstance::connect() starts the // authentication process. login->connect(gUserCredential); #if defined(OPENSIM) && !defined(SINGLEGRID) // // LLGridManager::getInstance()->saveGridList(); // #endif // OPENSIM // LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK ); return false; } if(STATE_LOGIN_CURL_UNSTUCK == LLStartUp::getStartupState()) { // If we get here we have gotten past the potential stall // in curl, so take "may appear frozen" out of progress bar. JC auth_desc = LLTrans::getString("LoginInProgressNoFrozen"); set_startup_status(progress, auth_desc, auth_message); LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE ); return false; } if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState()) { // Generic failure message std::ostringstream emsg; emsg << LLTrans::getString("LoginFailedHeader") << "\n"; if(LLLoginInstance::getInstance()->authFailure()) { LL_INFOS("LLStartUp") << "Login failed, LLLoginInstance::getResponse(): " << LLLoginInstance::getInstance()->getResponse() << LL_ENDL; LLSD response = LLLoginInstance::getInstance()->getResponse(); // Still have error conditions that may need some // sort of handling - dig up specific message std::string reason_response = response["reason"]; std::string message_response = response["message"]; std::string message_id = response["message_id"]; std::string message; // actual string to show the user bool localized_by_id = false; if(!message_id.empty()) { LLSD message_args = response["message_args"]; if (message_args.has("TIME") && (message_id == "LoginFailedAcountSuspended" || message_id == "LoginFailedAccountMaintenance")) { LLDate date; std::string time_string; if (date.fromString(message_args["TIME"].asString())) { LLSD args; args["datetime"] = (S32)date.secondsSinceEpoch(); LLTrans::findString(time_string, "LocalTime", args); } else { time_string = message_args["TIME"].asString() + " " + LLTrans::getString("PacificTime"); } message_args["TIME"] = time_string; } // message will be filled in with the template and arguments if (LLTrans::findString(message, message_id, message_args)) { localized_by_id = true; } } if(!localized_by_id && !message_response.empty()) { // *HACK: "no_inventory_host" sent as the message itself. // Remove this clause when server is sending message_id as well. message = LLAgent::sTeleportErrorMessages[ message_response ]; } if (message.empty()) { // Fallback to server-supplied string; necessary since server // may add strings that this viewer is not yet aware of message = message_response; } emsg << message; if(reason_response == "key") { // Couldn't login because user/password is wrong // Clear the credential gUserCredential->clearAuthenticator(); } if(reason_response == "update" || reason_response == "optional") { // In the case of a needed update, quit. // Its either downloading or declined. // If optional was skipped this case shouldn't // be reached. LL_INFOS("LLStartUp") << "Forcing a quit due to update." << LL_ENDL; LLLoginInstance::getInstance()->disconnect(); LLAppViewer::instance()->forceQuit(); } else { if (reason_response != "tos" && reason_response != "mfa_challenge") { // Don't pop up a notification in the TOS or MFA cases because // the specialized floater has already scolded the user. std::string error_code; if(response.has("errorcode")) { error_code = response["errorcode"].asString(); } if ((reason_response == "CURLError") && (error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") && response.has("certificate")) { // This was a certificate error, so grab the certificate // and throw up the appropriate dialog. LLPointer certificate; try { certificate = gSecAPIHandler->getCertificate(response["certificate"]); } catch (LLCertException &cert_exception) { LL_WARNS("LLStartUp", "SECAPI") << "Caught " << cert_exception.what() << " certificate expception on getCertificate("<< response["certificate"] << ")" << LL_ENDL; LLSD args; args["REASON"] = LLTrans::getString(cert_exception.what()); LLNotificationsUtil::add("GeneralCertificateErrorShort", args, response, general_cert_done); reset_login(); gSavedSettings.setBOOL("AutoLogin", false); show_connect_box = true; } if(certificate) { LLSD args = transform_cert_args(certificate); if(error_code == "SSL_CACERT") { // if we are handling an untrusted CA, throw up the dialog // with the 'trust this CA' button. LLNotificationsUtil::add("TrustCertificateError", args, response, trust_cert_done); // Not needed here - done below //show_connect_box = true; } else { // the certificate exception returns a unique string for each type of exception. // we grab this string via the LLUserAuth object, and use that to grab the localized // string. args["REASON"] = LLTrans::getString(message_response); LLNotificationsUtil::add("GeneralCertificateError", args, response, general_cert_done); // Not needed here - done below & in transition_back_to_login_panel() //reset_login(); //gSavedSettings.setBOOL("AutoLogin", false); //show_connect_box = true; // } } } else if (reason_response == "BadType") { LLNotificationsUtil::add("LoginFailedToParse", LLSD(), LLSD(), login_alert_done); } else if (!message.empty()) { // This wasn't a certificate error, so throw up the normal // notificatioin message. LLSD args; args["ERROR_MESSAGE"] = emsg.str(); LL_INFOS("LLStartUp") << "Notification: " << args << LL_ENDL; LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); } } // Wait for notification confirmation //transition_back_to_login_panel(emsg.str()); LLStartUp::setStartupState(STATE_LOGIN_CONFIRM_NOTIFICATON); // show_connect_box = true; } } else if(LLLoginInstance::getInstance()->authSuccess()) { // Aurora Sim //if(process_login_success_response()) if(process_login_success_response(first_sim_size_x,first_sim_size_y)) // Aurora Sim { // const std::string current_grid = LLGridManager::getInstance()->getGrid(); gSavedSettings.setString("LastConnectedGrid", current_grid); // // Pass the user information to the voice chat server interface. LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID); // create the default proximal channel LLVoiceChannel::initClass(); if (gSavedSettings.getBOOL("FSRememberUsername")) { gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); } FSPanelLogin::clearPassword(); LLStartUp::setStartupState( STATE_WORLD_INIT); LLTrace::get_frame_recording().reset(); } else { LLSD args; args["ERROR_MESSAGE"] = emsg.str(); LL_INFOS("LLStartUp") << "Notification: " << args << LL_ENDL; LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); // Wait for notification confirmation //transition_back_to_login_panel(emsg.str()); LLStartUp::setStartupState(STATE_LOGIN_CONFIRM_NOTIFICATON); // show_connect_box = true; return false; } } return false; } // Wait for notification confirmation if (STATE_LOGIN_CONFIRM_NOTIFICATON == LLStartUp::getStartupState()) { do_startup_frame(); gViewerWindow->getProgressView()->setVisible(false); do_startup_frame(); ms_sleep(1); return false; } // //--------------------------------------------------------------------- // World Init //--------------------------------------------------------------------- if (STATE_WORLD_INIT == LLStartUp::getStartupState()) { set_startup_status(0.30f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD); do_startup_frame(); // We should have an agent id by this point. llassert(!(gAgentID == LLUUID::null)); // Force HTTP inventory enabled on Second Life #ifdef OPENSIM if (LLGridManager::getInstance()->isInSecondLife()) #endif { gMenuBarView->getChild("HTTP Textures")->setVisible(false); gMenuBarView->getChild("HTTP Inventory")->setVisible(false); } // // FIRE-10607: Avatar icon controls show wrong picture when switching between SL main/beta grid // Load Avatars icons cache - once we know the grid we are connecting to LLAvatarIconIDCache::getInstance()->load(); // // Restore original LLMessageSystem HTTP options for OpenSim gMessageSystem->setIsInSecondLife(LLGridManager::getInstance()->isInSecondLife()); // Finish agent initialization. (Requires gSavedSettings, builds camera) gAgent.init(); do_startup_frame(); gAgentCamera.init(); do_startup_frame(); do_startup_frame(); // Since we connected, save off the settings so the user doesn't have to // type the name/password again if we crash. gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), true); LLUIColorTable::instance().saveUserSettings(); do_startup_frame(); // // Initialize classes w/graphics stuff. // LLSurface::initClasses(); do_startup_frame(); do_startup_frame(); LLDrawable::initClass(); do_startup_frame(); // init the shader managers LLPostProcess::initClass(); do_startup_frame(); LLAvatarAppearance::initClass("avatar_lad.xml","avatar_skeleton.xml"); do_startup_frame(); LLViewerObject::initVOClasses(); do_startup_frame(); // Initialize all our tools. Must be done after saved settings loaded. // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton. LLToolMgr::getInstance()->initTools(); do_startup_frame(); // Pre-load floaters, like the world map, that are slow to spawn // due to XML complexity. gViewerWindow->initWorldUI(); do_startup_frame(); // This is where we used to initialize gWorldp. Original comment said: // World initialization must be done after above window init // User might have overridden far clip LLWorld::getInstance()->setLandFarClip(gAgentCamera.mDrawDistance); do_startup_frame(); // Before we create the first region, we need to set the agent's mOriginGlobal // This is necessary because creating objects before this is set will result in a // bad mPositionAgent cache. gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle)); do_startup_frame(); // Aurora Sim //LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim); LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim, first_sim_size_x, first_sim_size_y); // Aurora Sim do_startup_frame(); LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from init_idle(). Seed cap == " << gFirstSimSeedCap << LL_ENDL; regionp->setSeedCapability(gFirstSimSeedCap); LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL; do_startup_frame(); // Set agent's initial region to be the one we just created. gAgent.setRegion(regionp); do_startup_frame(); // Set agent's initial position, which will be read by LLVOAvatar when the avatar // object is created. I think this must be done after setting the region. JC gAgent.setPositionAgent(agent_start_position_region); do_startup_frame(); LLStartUp::initExperiences(); do_startup_frame(); // If logging should be enebled, turns it on and loads history from disk // Note: does not happen on init of singleton because preferences can use // this instance without logging in LLConversationLog::getInstance()->initLoggingState(); LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT ); return false; } //--------------------------------------------------------------------- // Load QuickTime/GStreamer and other multimedia engines, can be slow. // Do it while we're waiting on the network for our seed capability. JC //--------------------------------------------------------------------- if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState()) { LLStartUp::multimediaInit(); LLStartUp::setStartupState( STATE_FONT_INIT ); do_startup_frame(); return false; } // Loading fonts takes several seconds if (STATE_FONT_INIT == LLStartUp::getStartupState()) { LLStartUp::fontInit(); LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT ); do_startup_frame(); return false; } //--------------------------------------------------------------------- // Wait for Seed Cap Grant //--------------------------------------------------------------------- if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) { LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); if (regionp->capabilitiesReceived()) { LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); } else if (regionp->capabilitiesError()) { LL_WARNS("AppInit") << "Failed to get capabilities. Logging out and backing up to login screen!" << LL_ENDL; if (gRememberPassword) { LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); } else { LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); } // Session was created, don't just hang up on server, send a logout request LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_LogoutRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gAgent.sendReliableMessage(); reset_login(); } else { U32 num_retries = regionp->getNumSeedCapRetries(); if (num_retries > MAX_SEED_CAP_ATTEMPTS_BEFORE_ABORT) { LL_WARNS("AppInit") << "Failed to get capabilities. Logging out and backing up to login screen!" << LL_ENDL; if (gRememberPassword) { LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); } else { LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); } // Session was created, don't just hang up on server, send a logout request LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_LogoutRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gAgent.sendReliableMessage(); reset_login(); } else if (num_retries > 0) { LLStringUtil::format_map_t args; args["[NUMBER]"] = llformat("%d", num_retries + 1); set_startup_status(0.4f, LLTrans::getString("LoginRetrySeedCapGrant", args), gAgent.mMOTD.c_str()); } else { set_startup_status(0.4f, LLTrans::getString("LoginRequestSeedCapGrant"), gAgent.mMOTD.c_str()); } } do_startup_frame(); return false; } //--------------------------------------------------------------------- // Seed Capability Granted // no newMessage calls should happen before this point //--------------------------------------------------------------------- if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState()) { do_startup_frame(); // These textures are not warrantied to be cached, so needs // to hapen with caps granted gTextureList.doPrefetchImages(); // will init images, should be done with caps, but before gSky.init() LLEnvironment::getInstance()->initSingleton(); do_startup_frame(); update_texture_fetch(); do_startup_frame(); if ( gViewerWindow != NULL) { // This isn't the first logon attempt, so show the UI gViewerWindow->setNormalControlsVisible( true ); } gLoginMenuBarView->setVisible( false ); gLoginMenuBarView->setEnabled( false ); do_startup_frame(); // direct logging to the debug console's line buffer LLError::logToFixedBuffer(gDebugView->mDebugConsolep); do_startup_frame(); // set initial visibility of debug console gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole")); do_startup_frame(); // // Set message handlers // LL_INFOS("AppInit") << "Initializing communications..." << LL_ENDL; // register callbacks for messages. . . do this after initial handshake to make sure that we don't catch any unwanted register_viewer_callbacks(gMessageSystem); do_startup_frame(); // Debugging info parameters gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms do_startup_frame(); #ifndef LL_RELEASE_FOR_DOWNLOAD gMessageSystem->setTimeDecodes( true ); // Time the decode of each msg gMessageSystem->setTimeDecodesSpamThreshold( 0.05f ); // Spam if a single msg takes over 50ms to decode #endif do_startup_frame(); gXferManager->registerCallbacks(gMessageSystem); do_startup_frame(); LLStartUp::initNameCache(); do_startup_frame(); // update the voice settings *after* gCacheName initialization // so that we can construct voice UI that relies on the name cache if (LLVoiceClient::instanceExists()) { LLVoiceClient::getInstance()->updateSettings(); } do_startup_frame(); // OpenSim support: Init with defaults - we get the OpenSimExtras later during login LFSimFeatureHandler::instance(); // create a container's instance for start a controlling conversation windows // by the voice's events // [FS communication UI] //LLFloaterIMContainer *im_inst = LLFloaterIMContainer::getInstance(); //if(gAgent.isFirstLogin() && im_inst) //{ // im_inst->openFloater(im_inst->getKey()); //} FSFloaterIMContainer* floater_imcontainer = FSFloaterIMContainer::getInstance(); floater_imcontainer->initTabs(); if (gSavedSettings.getS32("ParcelMediaAutoPlayEnable") == 2) { LLViewerParcelAskPlay::getInstance()->loadSettings(); } // FIRE-3066: Force creation or FSFLoaterContacts here, this way it will register with LLAvatarTracker early enough. // Otherwise it is only create if isChatMultriTab() == true and LLIMFloaterContainer::getInstance is called // Moved here from llfloaternearbyvchat.cpp by Zi, to make this work even if LogShowHistory is false LLFloater *pContacts(FSFloaterContacts::getInstance()); // Load persisted avatar render settings FSAvatarRenderPersistence::instance().init(); // Do something with pContacts so no overzealous optimizer optimzes our neat little call to FSFloaterContacts::getInstance() away. if( pContacts ) LL_INFOS("AppInit") << "Constructed " << pContacts->getName() << LL_ENDL; // // FIRE-8560/FIRE-8592: We neet to create the instance of the radar // for the radar functions and the V2 friendlist here. // This is because of the standalone group panels that will // prevent doing this at login when receiving the agent group // data update. LLFloaterSidePanelContainer::getPanel("people", "panel_people"); FSRadar::instance(); LL_INFOS("AppInit") << "Radar initialized" << LL_ENDL; // // Register check function for registrar enable checks gFSRegistrarUtils.setEnableCheckFunction(std::bind(&FSCommon::checkIsActionEnabled, std::placeholders::_1, std::placeholders::_2)); // fsdata support FSData::instance().addAgents(); // // [FS communication UI] //gCacheName is required for nearby chat history loading //so I just moved nearby history loading a few states further if (gSavedPerAccountSettings.getBOOL("LogShowHistory")) { if (FSFloaterNearbyChat* nearby_chat = FSFloaterNearbyChat::getInstance()) nearby_chat->loadHistory(); } do_startup_frame(); // [FS communication UI] // FIRE-18250: Option to disable default eye movement gAgent.addRegionChangedCallback(boost::bind(&update_static_eyes)); update_static_eyes(); // gAgent.addRegionChangedCallback(boost::bind(&LLPerfStats::StatsRecorder::clearStats)); // *Note: this is where gWorldMap used to be initialized. // register null callbacks for audio until the audio system is initialized gMessageSystem->setHandlerFuncFast(_PREHASH_SoundTrigger, null_message_callback, NULL); gMessageSystem->setHandlerFuncFast(_PREHASH_AttachedSound, null_message_callback, NULL); do_startup_frame(); //reset statistics LLViewerStats::instance().resetStats(); do_startup_frame(); // // Set up region and surface defaults // // Sets up the parameters for the first simulator LL_DEBUGS("AppInit") << "Initializing camera..." << LL_ENDL; gFrameTime = totalTime(); F32Seconds last_time = gFrameTimeSeconds; gFrameTimeSeconds = (gFrameTime - gStartTime); gFrameIntervalSeconds = gFrameTimeSeconds - last_time; if (gFrameIntervalSeconds < 0.f) { gFrameIntervalSeconds = 0.f; } // Make sure agent knows correct aspect ratio // FOV limits depend upon aspect ratio so this needs to happen before initializing the FOV below LLViewerCamera::getInstance()->setViewHeightInPixels(gViewerWindow->getWorldViewHeightRaw()); LLViewerCamera::getInstance()->setAspect(gViewerWindow->getWorldViewAspectRatio()); // Initialize FOV LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle")); do_startup_frame(); // Move agent to starting location. The position handed to us by // the space server is in global coordinates, but the agent frame // is in region local coordinates. Therefore, we need to adjust // the coordinates handed to us to fit in the local region. gAgent.setPositionAgent(agent_start_position_region); gAgent.resetAxes(gAgentStartLookAt); gAgentCamera.stopCameraAnimation(); gAgentCamera.resetCamera(); do_startup_frame(); // Initialize global class data needed for surfaces (i.e. textures) LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL; // Initialize all of the viewer object classes for the first time (doing things like texture fetches. LLGLState::checkStates(); gSky.init(); LLGLState::checkStates(); do_startup_frame(); LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL; // For all images pre-loaded into viewer cache, init // priorities and fetching using decodeAllImages. // Most of the fetching and decoding likely to be done // by update_texture_fetch() later, while viewer waits. // // Need to do this AFTER we init the sky const S32 DECODE_TIME_SEC = 2; for (int i = 0; i < DECODE_TIME_SEC; i++) { F32 frac = (F32)i / (F32)DECODE_TIME_SEC; set_startup_status(0.45f + frac*0.1f, LLTrans::getString("LoginDecodingImages"), gAgent.mMOTD); do_startup_frame(); gTextureList.decodeAllImages(1.f); } LLStartUp::setStartupState( STATE_WORLD_WAIT ); do_startup_frame(); // JC - Do this as late as possible to increase likelihood Purify // will run. LLMessageSystem* msg = gMessageSystem; if (!msg->mOurCircuitCode) { LL_WARNS("AppInit") << "Attempting to connect to simulator with a zero circuit code!" << LL_ENDL; } gUseCircuitCallbackCalled = false; msg->enableCircuit(gFirstSim, true); // now, use the circuit info to tell simulator about us! LL_INFOS("AppInit") << "viewer: UserLoginLocationReply() Enabling " << gFirstSim << " with code " << msg->mOurCircuitCode << LL_ENDL; msg->newMessageFast(_PREHASH_UseCircuitCode); msg->nextBlockFast(_PREHASH_CircuitCode); msg->addU32Fast(_PREHASH_Code, msg->mOurCircuitCode); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); msg->sendReliable( gFirstSim, gSavedSettings.getS32("UseCircuitCodeMaxRetries"), false, (F32Seconds)gSavedSettings.getF32("UseCircuitCodeTimeout"), use_circuit_callback, NULL); timeout.reset(); do_startup_frame(); return false; } //--------------------------------------------------------------------- // World Wait //--------------------------------------------------------------------- if(STATE_WORLD_WAIT == LLStartUp::getStartupState()) { LL_DEBUGS("AppInit") << "Waiting for simulator ack...." << LL_ENDL; set_startup_status(0.59f, LLTrans::getString("LoginWaitingForRegionHandshake"), gAgent.mMOTD); if(gGotUseCircuitCodeAck) { LLStartUp::setStartupState( STATE_AGENT_SEND ); } pump_idle_startup_network(); return false; } //--------------------------------------------------------------------- // Agent Send //--------------------------------------------------------------------- if (STATE_AGENT_SEND == LLStartUp::getStartupState()) { LL_DEBUGS("AppInit") << "Connecting to region..." << LL_ENDL; set_startup_status(0.60f, LLTrans::getString("LoginConnectingToRegion"), gAgent.mMOTD); do_startup_frame(); // register with the message system so it knows we're // expecting this message LLMessageSystem* msg = gMessageSystem; msg->setHandlerFuncFast( _PREHASH_AgentMovementComplete, process_agent_movement_complete); LLViewerRegion* regionp = gAgent.getRegion(); if(regionp) { send_complete_agent_movement(regionp->getHost()); gAssetStorage->setUpstream(regionp->getHost()); gCacheName->setUpstream(regionp->getHost()); // OpenSim legacy economy support #ifdef OPENSIM if (!LLGridManager::instance().isInSecondLife()) { msg->newMessageFast(_PREHASH_EconomyDataRequest); gAgent.sendReliableMessage(); } #endif // } // It is entirely possible that we may get the friends list _before_ we have the callbacks registered to process that. // This will lead to the friends list not being processed properly and online statuses not being updated appropriately at login. // So, we need to make sure that we have the callbacks registered before we get the friends list. // This appears to crop up on some systems somewhere between STATE_AGENT_SEND and STATE_INVENTORY_SEND. It's happened to me a few times now. // -Geenz 2025-03-12 LL_INFOS() << " AvatarTracker" << LL_ENDL; LLAvatarTracker::instance().registerCallbacks(gMessageSystem); do_startup_frame(); // Create login effect // But not on first login, because you can't see your avatar then if (!gAgent.isFirstLogin()) { LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, true); effectp->setPositionGlobal(gAgent.getPositionGlobal()); effectp->setColor(LLColor4U(gAgent.getEffectColor())); LLHUDManager::getInstance()->sendEffects(); } LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT timeout.reset(); do_startup_frame(); return false; } //--------------------------------------------------------------------- // Agent Wait //--------------------------------------------------------------------- if (STATE_AGENT_WAIT == LLStartUp::getStartupState()) { do_startup_frame(); if (gAgentMovementCompleted) { LLStartUp::setStartupState( STATE_INVENTORY_SEND ); } do_startup_frame(); if (!gAgentMovementCompleted && timeout.getElapsedTimeF32() > STATE_AGENT_WAIT_TIMEOUT) { LL_WARNS("AppInit") << "Timeout on agent movement. Sending logout and backing up to login screen!" << LL_ENDL; if (gRememberPassword) { LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); } else { LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); } // Session was created, don't just hang up on server, send a logout request LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_LogoutRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gAgent.sendReliableMessage(); reset_login(); } return false; } //--------------------------------------------------------------------- // Inventory Send //--------------------------------------------------------------------- if (STATE_INVENTORY_SEND == LLStartUp::getStartupState()) { LL_PROFILE_ZONE_NAMED("State inventory send") do_startup_frame(); // request mute list LL_INFOS() << "Requesting Mute List" << LL_ENDL; LLMuteList::getInstance()->requestFromServer(gAgent.getID()); // Get L$ and ownership credit information LL_INFOS() << "Requesting Money Balance" << LL_ENDL; LLStatusBar::sendMoneyBalanceRequest(); // Moved before inventory creation. // request all group information LL_INFOS("Agent_GroupData") << "GROUPDEBUG: Requesting Agent Data during startup" << LL_ENDL; gAgent.sendAgentDataUpdateRequest(); // do_startup_frame(); // Inform simulator of our language preference LLAgentLanguage::update(); do_startup_frame(); // unpack thin inventory LLSD response = LLLoginInstance::getInstance()->getResponse(); //bool dump_buffer = false; LLSD inv_lib_root = response["inventory-lib-root"]; if(inv_lib_root.isDefined()) { // should only be one LLSD id = inv_lib_root[0]["folder_id"]; if(id.isDefined()) { gInventory.setLibraryRootFolderID(id.asUUID()); } } do_startup_frame(); LLSD inv_lib_owner = response["inventory-lib-owner"]; if(inv_lib_owner.isDefined()) { // should only be one LLSD id = inv_lib_owner[0]["agent_id"]; if(id.isDefined()) { gInventory.setLibraryOwnerID(LLUUID(id.asUUID())); } } do_startup_frame(); LLStartUp::setStartupState(STATE_INVENTORY_SKEL); do_startup_frame(); return false; } if (STATE_INVENTORY_SKEL == LLStartUp::getStartupState()) { LL_PROFILE_ZONE_NAMED("State inventory load skeleton") LLSD response = LLLoginInstance::getInstance()->getResponse(); LLSD inv_skel_lib = response["inventory-skel-lib"]; if (inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull()) { LL_PROFILE_ZONE_NAMED("load library inv") if (!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID())) { LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL; } } do_startup_frame(); LLSD inv_skeleton = response["inventory-skeleton"]; if (inv_skeleton.isDefined()) { LL_PROFILE_ZONE_NAMED("load personal inv") if (!gInventory.loadSkeleton(inv_skeleton, gAgent.getID())) { LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL; } } do_startup_frame(); LLStartUp::setStartupState(STATE_INVENTORY_SEND2); do_startup_frame(); return false; } if (STATE_INVENTORY_SEND2 == LLStartUp::getStartupState()) { LL_PROFILE_ZONE_NAMED("State inventory send2") LLSD response = LLLoginInstance::getInstance()->getResponse(); LLSD inv_basic = response["inventory-basic"]; if(inv_basic.isDefined()) { LL_INFOS() << "Basic inventory root folder id is " << inv_basic["folder_id"] << LL_ENDL; } LLSD buddy_list = response["buddy-list"]; if(buddy_list.isDefined()) { LLAvatarTracker::buddy_map_t list; // Reset on each iteration //LLUUID agent_id; //S32 has_rights = 0, given_rights = 0; // for(LLSD::array_const_iterator it = buddy_list.beginArray(), end = buddy_list.endArray(); it != end; ++it) { // Reset on each iteration LLUUID agent_id; S32 has_rights = 0, given_rights = 0; // LLSD buddy_id = (*it)["buddy_id"]; if(buddy_id.isDefined()) { agent_id = buddy_id.asUUID(); } // Can't add "friends" that have no ID else continue; LLSD buddy_rights_has = (*it)["buddy_rights_has"]; if(buddy_rights_has.isDefined()) { has_rights = buddy_rights_has.asInteger(); } LLSD buddy_rights_given = (*it)["buddy_rights_given"]; if(buddy_rights_given.isDefined()) { given_rights = buddy_rights_given.asInteger(); } list[agent_id] = new LLRelationship(given_rights, has_rights, false); } LLAvatarTracker::instance().addBuddyList(list); do_startup_frame(); } // Contact sets LGGContactSets* cs_instance = LGGContactSets::getInstance(); cs_instance->loadFromDisk(); LLAvatarNameCache::instance().setCustomNameCheckCallback(boost::bind(&LGGContactSets::checkCustomName, cs_instance, _1, _2, _3)); // bool show_hud = false; LLSD tutorial_setting = response["tutorial_setting"]; if(tutorial_setting.isDefined()) { for(LLSD::array_const_iterator it = tutorial_setting.beginArray(), end = tutorial_setting.endArray(); it != end; ++it) { LLSD tutorial_url = (*it)["tutorial_url"]; if(tutorial_url.isDefined()) { // Tutorial floater will append language code gSavedSettings.setString("TutorialURL", tutorial_url.asString()); } // For Viewer 2.0 we are not using the web-based tutorial // If we reverse that decision, put this code back and use // login.cgi to send a different URL with content that matches // the Viewer 2.0 UI. //LLSD use_tutorial = (*it)["use_tutorial"]; //if(use_tutorial.asString() == "true") //{ // show_hud = true; //} } } do_startup_frame(); // Either we want to show tutorial because this is the first login // to a Linden Help Island or the user quit with the tutorial // visible. JC if (show_hud || gSavedSettings.getBOOL("ShowTutorial")) { LLFloaterReg::showInstance("hud", LLSD(), false); } do_startup_frame(); LLSD event_notifications = response["event_notifications"]; if(event_notifications.isDefined()) { gEventNotifier.load(event_notifications); } do_startup_frame(); LLSD classified_categories = response["classified_categories"]; if(classified_categories.isDefined()) { LLClassifiedInfo::loadCategories(classified_categories); } do_startup_frame(); // This method MUST be called before gInventory.findCategoryUUIDForType because of // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. gInventory.buildParentChildMap(); // If buildParentChildMap succeeded, inventory will now be in // a usable state and gInventory.isInventoryUsable() will be // true. // if inventory is unusable, show warning. if (!gInventory.isInventoryUsable()) { LLNotificationsUtil::add("InventoryUnusable"); } LLInventoryModelBackgroundFetch::instance().start(); gInventory.createCommonSystemCategories(); LLStartUp::setStartupState(STATE_INVENTORY_CALLBACKS ); do_startup_frame(); return false; } //--------------------------------------------------------------------- // STATE_INVENTORY_CALLBACKS //--------------------------------------------------------------------- if (STATE_INVENTORY_CALLBACKS == LLStartUp::getStartupState()) { if (!LLInventoryModel::isSysFoldersReady()) { do_startup_frame(); return false; } LLInventoryModelBackgroundFetch::instance().start(); LLAppearanceMgr::instance().initCOFID(); LLUUID cof_id = LLAppearanceMgr::instance().getCOF(); LLViewerInventoryCategory* cof = gInventory.getCategory(cof_id); if (cof && cof->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) { // Special case, dupplicate request prevention. // Cof folder will be requested via FetchCOF // in appearance manager, prevent recursive fetch cof->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE); } // It's debatable whether this flag is a good idea - sets all // bits, and in general it isn't true that inventory // initialization generates all types of changes. Maybe add an // INITIALIZE mask bit instead? gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); gInventory.notifyObservers(); do_startup_frame(); // set up callbacks LL_INFOS() << "Registering Callbacks" << LL_ENDL; LLMessageSystem* msg = gMessageSystem; LL_INFOS() << " Inventory" << LL_ENDL; LLInventoryModel::registerCallbacks(msg); LL_INFOS() << " Landmark" << LL_ENDL; LLLandmark::registerCallbacks(msg); do_startup_frame(); // Moved before inventory creation. //// request all group information //LL_INFOS() << "Requesting Agent Data" << LL_ENDL; //gAgent.sendAgentDataUpdateRequest(); //do_startup_frame(); // // Create the inventory views LL_INFOS() << "Creating Inventory Views" << LL_ENDL; LLFloaterReg::getInstance("inventory"); do_startup_frame(); // [RLVa:KB] - Checked: RLVa-1.1.0 if (RlvHandler::isEnabled()) { // Regularly process a select subset of retained commands during logon gIdleCallbacks.addFunction(RlvHandler::onIdleStartup, new LLTimer()); } // [/RLVa:KB] LLStartUp::setStartupState( STATE_MISC ); do_startup_frame(); return false; } //--------------------------------------------------------------------- // Misc //--------------------------------------------------------------------- if (STATE_MISC == LLStartUp::getStartupState()) { // We have a region, and just did a big inventory download. // We can estimate the user's connection speed, and set their // max bandwidth accordingly. JC if (gSavedSettings.getBOOL("FirstLoginThisInstall")) { // This is actually a pessimistic computation, because TCP may not have enough // time to ramp up on the (small) default inventory file to truly measure max // bandwidth. JC F64 rate_bps = LLLoginInstance::getInstance()->getLastTransferRateBPS(); const F32 FAST_RATE_BPS = 600.f * 1024.f; const F32 FASTER_RATE_BPS = 750.f * 1024.f; F32 max_bandwidth = gViewerThrottle.getMaxBandwidth(); if (rate_bps > FASTER_RATE_BPS && rate_bps > max_bandwidth) { LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " << FASTER_RATE_BPS/1024.f << " kbps" << LL_ENDL; gViewerThrottle.setMaxBandwidth(FASTER_RATE_BPS / 1024.f); } else if (rate_bps > FAST_RATE_BPS && rate_bps > max_bandwidth) { LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " << FAST_RATE_BPS/1024.f << " kbps" << LL_ENDL; gViewerThrottle.setMaxBandwidth(FAST_RATE_BPS / 1024.f); } if (gSavedSettings.getBOOL("ShowHelpOnFirstLogin")) { gSavedSettings.setBOOL("HelpFloaterOpen", true); } // Set the show start location to true, now that the user has logged // on with this install. gSavedSettings.setBOOL("ShowStartLocation", true); // [FS Communication UI] LLFloaterReg::toggleInstanceOrBringToFront("fs_im_container"); // [FS Communication UI] } do_startup_frame(); // Load stored local environment if needed. LLEnvironment::instance().loadFromSettings(); // *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp) //check_merchant_status(); do_startup_frame(); // Compatibility with old backups // Put gSavedPerAccountSettings here, put gSavedSettings in llappviewer.cpp // *TODO: Should we keep these around forever or just three release cycles? if (gSavedSettings.getBOOL("FSFirstRunAfterSettingsRestore")) { // Post-chui merge logging change if (gSavedPerAccountSettings.getBOOL("LogInstantMessages")) gSavedPerAccountSettings.setS32("KeepConversationLogTranscript", 2); else gSavedPerAccountSettings.setS32("KeepConversationLogTranscript", 0); //ok, we're done, set it back to false. gSavedSettings.setBOOL("FSFirstRunAfterSettingsRestore", false); } do_startup_frame(); // if (gSavedSettings.getBOOL("HelpFloaterOpen")) { // show default topic LLViewerHelp::instance().showTopic(""); } do_startup_frame(); LLFloaterReg::showInitialVisibleInstances(); LLFloaterGridStatus::getInstance()->startGridStatusTimer(); do_startup_frame(); // [FS Login Panel] // based on the comments, we've successfully logged in so we can delete the 'forced' // URL that the updater set in settings.ini (in a mostly paranoid fashion) std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" ); if ( nextLoginLocation.length() ) { // clear it gSavedSettings.setString( "NextLoginLocation", "" ); // and make sure it's saved gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , true ); LLUIColorTable::instance().saveUserSettings(); }; // [FS Login Panel] do_startup_frame(); // JC: Initializing audio requests many sounds for download. init_audio(); do_startup_frame(); // JC: Initialize "active" gestures. This may also trigger // many gesture downloads, if this is the user's first // time on this machine or -purge has been run. LLSD gesture_options = LLLoginInstance::getInstance()->getResponse("gestures"); if (gesture_options.isDefined()) { LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size() << LL_ENDL; uuid_vec_t item_ids; for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(), end = gesture_options.endArray(); resp_it != end; ++resp_it) { // If the id is not specifed in the LLSD, // the LLSD operator[]() will return a null LLUUID. LLUUID item_id = (*resp_it)["item_id"]; LLUUID asset_id = (*resp_it)["asset_id"]; if (item_id.notNull() && asset_id.notNull()) { // Could schedule and delay these for later. const bool no_inform_server = false; const bool no_deactivate_similar = false; LLGestureMgr::instance().activateGestureWithAsset(item_id, asset_id, no_inform_server, no_deactivate_similar); // We need to fetch the inventory items for these gestures // so we have the names to populate the UI. item_ids.push_back(item_id); } } // no need to add gesture to inventory observer, it's already made in constructor LLGestureMgr::instance().setFetchIDs(item_ids); LLGestureMgr::instance().startFetch(); } gDisplaySwapBuffers = true; do_startup_frame(); LLMessageSystem* msg = gMessageSystem; msg->setHandlerFuncFast(_PREHASH_SoundTrigger, process_sound_trigger); msg->setHandlerFuncFast(_PREHASH_PreloadSound, process_preload_sound); msg->setHandlerFuncFast(_PREHASH_AttachedSound, process_attached_sound); msg->setHandlerFuncFast(_PREHASH_AttachedSoundGainChange, process_attached_sound_gain_change); LL_DEBUGS("AppInit") << "Initialization complete" << LL_ENDL; LL_DEBUGS("SceneLoadTiming", "Start") << "Scene Load Started " << LL_ENDL; gRenderStartTime.reset(); gForegroundTime.reset(); // HACK: Inform simulator of window size. // Do this here so it's less likely to race with RegisterNewAgent. // TODO: Put this into RegisterNewAgent // JC - 7/20/2002 gViewerWindow->sendShapeToSim(); LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA); // The reason we show the alert is because we want to // reduce confusion for when you log in and your provided // location is not your expected location. So, if this is // your first login, then you do not have an expectation, // thus, do not show this alert. if (!gAgent.isFirstLogin()) { LL_INFOS() << "gAgentStartLocation : " << gAgentStartLocation << LL_ENDL; LLSLURL start_slurl = LLStartUp::getStartSLURL(); LL_DEBUGS("AppInit") << "start slurl "< Load dynamic script library from xml #ifdef OPENSIM if (LLGridManager::getInstance()->isInOpenSim()) { if (!gScriptLibrary.loadLibrary(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "scriptlibrary_ossl.xml"))) { gScriptLibrary.loadLibrary(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "scriptlibrary_ossl.xml")); } } if (LLGridManager::getInstance()->isInAuroraSim()) { if (!gScriptLibrary.loadLibrary(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "scriptlibrary_aa.xml"))) { gScriptLibrary.loadLibrary(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "scriptlibrary_aa.xml")); } } #endif // OPENSIM do_startup_frame(); // LLStartUp::setStartupState( STATE_PRECACHE ); timeout.reset(); return false; } if (STATE_PRECACHE == LLStartUp::getStartupState()) { do_startup_frame(); F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY; // We now have an inventory skeleton, so if this is a user's first // login, we can start setting up their clothing and avatar // appearance. This helps to avoid the generic "Ruth" avatar in // the orientation island tutorial experience. JC if (gAgent.isFirstLogin() && !sInitialOutfit.empty() // registration set up an outfit && !sInitialOutfitGender.empty() // and a gender && isAgentAvatarValid() // can't wear clothes without object && !gAgent.isOutfitChosen()) // nothing already loading { // Start loading the wearables, textures, gestures LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender ); } // If not first login, we need to fetch COF contents and // compute appearance from that. if (isAgentAvatarValid() && !gAgent.isFirstLogin() && !gAgent.isOutfitChosen()) { gAgentWearables.notifyLoadingStarted(); gAgent.setOutfitChosen(true); // [Legacy Bake] //gAgentWearables.sendDummyAgentWearablesUpdate(); if (LLGridManager::getInstance()->isInSecondLife()) { gAgentWearables.sendDummyAgentWearablesUpdate(); } // [Legacy Bake] callAfterCOFFetch(set_flags_and_update_appearance); } do_startup_frame(); // wait precache-delay and for agent's avatar or a lot longer. if ((timeout_frac > 1.f) && isAgentAvatarValid()) { LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); } else if (timeout_frac > 10.f) { // If we exceed the wait above while isAgentAvatarValid is // not true yet, we will change startup state and // eventually (once avatar does get created) wind up at // the gender chooser. This should occur only in very // unusual circumstances, so set the timeout fairly high // to minimize mistaken hits here. LL_WARNS() << "Wait for valid avatar state exceeded " << timeout.getElapsedTimeF32() << " will invoke gender chooser" << LL_ENDL; LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); } else { update_texture_fetch(); set_startup_status(0.60f + 0.30f * timeout_frac, LLTrans::getString("LoginPrecaching"), gAgent.mMOTD.c_str()); do_startup_frame(); } return true; } if (STATE_WEARABLES_WAIT == LLStartUp::getStartupState()) { static LLFrameTimer wearables_timer; const F32 wearables_time = wearables_timer.getElapsedTimeF32(); const F32 MAX_WEARABLES_TIME = 10.f; if (!gAgent.isOutfitChosen() && isAgentAvatarValid()) { // No point in waiting for clothing, we don't even know // what outfit we want. Pop up a gender chooser dialog to // ask and proceed to draw the world. JC // // *NOTE: We might hit this case even if we have an // initial outfit, but if the load hasn't started // already then something is wrong so fall back // to generic outfits. JC LLNotificationsUtil::add("WelcomeChooseSex", LLSD(), LLSD(), callback_choose_gender); LLStartUp::setStartupState( STATE_CLEANUP ); } do_startup_frame(); if (gAgent.isOutfitChosen() && (wearables_time > MAX_WEARABLES_TIME)) { if (gInventory.isInventoryUsable()) { LLNotificationsUtil::add("ClothingLoading"); } record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time); LLStartUp::setStartupState( STATE_CLEANUP ); } else if (gAgent.isFirstLogin() && isAgentAvatarValid() && gAgentAvatarp->isFullyLoaded()) { // wait for avatar to be completely loaded if (isAgentAvatarValid() && gAgentAvatarp->isFullyLoaded()) { LL_DEBUGS("Avatar") << "avatar fully loaded" << LL_ENDL; LLStartUp::setStartupState( STATE_CLEANUP ); return true; } } else { // OK to just get the wearables if ( gAgentWearables.areWearablesLoaded() ) { // We have our clothing, proceed. LL_DEBUGS("Avatar") << "wearables loaded" << LL_ENDL; LLStartUp::setStartupState( STATE_CLEANUP ); return true; } // Can't fall through here, so return return true; } //fall through this frame to STATE_CLEANUP } if (STATE_CLEANUP == LLStartUp::getStartupState()) { set_startup_status(1.0, "", ""); do_startup_frame(); if (!mBenefitsSuccessfullyInit) { LLNotificationsUtil::add("FailedToGetBenefits", LLSD(), LLSD(), boost::bind(on_benefits_failed_callback, _1, _2)); } // Client LSL Bridge if (gSavedSettings.getBOOL("UseLSLBridge")) { if (!FSLSLBridge::instance().getBridgeCreating()) { FSLSLBridge::instance().initBridge(); } else { LL_INFOS("FSLSLBridge") << "LSL bridge already getting created - skipping bridge init" << LL_ENDL; } } // // Favorite Wearables FSFloaterWearableFavorites::initCategory(); // Bypass the calling card sync-crap to create the agent's calling card if (!gSavedSettings.getBOOL("FSCreateCallingCards")) { LLFriendCardsManager::createAgentCallingCard(); } // Let the map know about the inventory. LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); if(floater_world_map) { floater_world_map->observeInventory(&gInventory); floater_world_map->observeFriends(); } gViewerWindow->showCursor(); gViewerWindow->getWindow()->resetBusyCount(); gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); LL_DEBUGS("AppInit") << "Done releasing bitmap" << LL_ENDL; //gViewerWindow->revealIntroPanel(); gViewerWindow->setStartupComplete(); gViewerWindow->setProgressCancelButtonVisible(false); do_startup_frame(); // We're not away from keyboard, even though login might have taken // a while. JC gAgent.clearAFK(); // Have the agent start watching the friends list so we can update proxies gAgent.observeFriends(); // Start automatic replay if the flag is set. if (gSavedSettings.getBOOL("StatsAutoRun") || gAgentPilot.getReplaySession()) { LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL; gAgentPilot.startPlayback(); } show_debug_menus(); // Debug menu visiblity and First Use trigger // If we've got a startup URL, dispatch it //LLStartUp::dispatchURL(); // Retrieve information about the land data // (just accessing this the first time will fetch it, // then the data is cached for the viewer's lifetime) LLProductInfoRequestManager::instance(); // *FIX:Mani - What do I do here? // Need we really clear the Auth response data? // Clean up the userauth stuff. // LLUserAuth::getInstance()->reset(); LLStartUp::setStartupState( STATE_STARTED ); do_startup_frame(); // Draw Distance stepping; originally based on SpeedRez by Henri Beauchamp, licensed under LGPL if (gSavedSettings.getBOOL("FSRenderFarClipStepping")) { // progressive draw distance stepping if requested. LLPresetsManager::instance().setIsDrawDistanceSteppingActive(true); F32 dist1 = gSavedSettings.getF32("RenderFarClip"); F32 dist2 = gSavedSettings.getF32("FSSavedRenderFarClip"); gSavedDrawDistance = (dist1 >= dist2 ? dist1 : dist2); gSavedSettings.setF32("FSSavedRenderFarClip", gSavedDrawDistance); gSavedSettings.setF32("RenderFarClip", 32.0f); gLastDrawDistanceStep = 32.0f; } // // Unmute audio if desired and setup volumes. // This is a not-uncommon crash site, so surround it with // LL_INFOS() output to aid diagnosis. LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL; audio_update_volume(); LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL; // reset keyboard focus to sane state of pointing at world gFocusMgr.setKeyboardFocus(NULL); LLAppViewer::instance()->handleLoginComplete(); LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); // [FS communication UI] FSFloaterIM::initIMFloater(); // [FS communication UI] do_startup_frame(); llassert(LLPathfindingManager::getInstance() != NULL); LLPathfindingManager::getInstance()->initSystem(); gAgentAvatarp->sendHoverHeight(); // look for parcels we own send_places_query(LLUUID::null, LLUUID::null, "", DFQ_AGENT_OWNED, LLParcel::C_ANY, ""); LLUIUsage::instance().clear(); LLPerfStats::StatsRecorder::setAutotuneInit(); // Display Avatar Welcome Pack the first time a user logs in // (or clears their settings....) if (gSavedSettings.getBOOL("FirstLoginThisInstall")) { LLFloater* avatar_welcome_pack_floater = LLFloaterReg::findInstance("avatar_welcome_pack"); if (avatar_welcome_pack_floater != nullptr) { // There is a (very - 1 in ~50 times) hard to repro bug where the login // page is not hidden when the AWP floater is presented. This (agressive) // approach to always close it seems like the best fix for now. // [FS Login Panel] //LLPanelLogin::closePanel(); FSPanelLogin::closePanel(); // [FS Login Panel] avatar_welcome_pack_floater->setVisible(true); } } //// We're successfully logged in. // 2025-06 Moved lower down in the state machine so the Avatar Welcome Pack // floater display can be triggered correctly. gSavedSettings.setBOOL("FirstLoginThisInstall", false); // FIRE-6643 Display MOTD when login screens are disabled if (gSavedSettings.getBOOL("FSDisableLoginScreens")) { FSCommon::report_to_nearby_chat(gAgent.mMOTD); } // // if (gSavedSettings.getBOOL("AutoQueryGridStatus")) { FSCoreHttpUtil::callbackHttpGetRaw(gSavedSettings.getString("AutoQueryGridStatusURL"), downloadGridstatusComplete, [](const LLSD& data) { downloadGridstatusError(data, gSavedSettings.getString("AutoQueryGridStatusURL")); }); } // // Restore open IMs from previous session if (gSavedSettings.getBOOL("FSRestoreOpenIMs")) { FSFloaterIMContainer* floater_imcontainer = FSFloaterIMContainer::getInstance(); floater_imcontainer->restoreOpenIMs(); } // return true; } return true; } // // local function definition // void login_show() { LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL; // Hide the toolbars: may happen to come back here if login fails after login agent but before login in region if (gToolBarView) { gToolBarView->setVisible(false); } // [FS Login Panel] //LLPanelLogin::show( gViewerWindow->getWindowRectScaled(), login_callback, NULL ); FSPanelLogin::show( gViewerWindow->getWindowRectScaled(), login_callback, NULL ); // [FS Login Panel] // Whitelist reminder if( gSavedSettings.getBOOL("FSShowWhitelistReminder") ) { LLNotificationsUtil::add("WhitelistReminder"); gSavedSettings.setBOOL("FSShowWhitelistReminder", false); } // } // Callback for when login screen is closed. Option 0 = connect, option 1 = quit. void login_callback(S32 option, void *userdata) { const S32 CONNECT_OPTION = 0; const S32 QUIT_OPTION = 1; if (CONNECT_OPTION == option) { LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); return; } else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION { if (!gSavedSettings.getBOOL("RememberPassword")) { // turn off the setting and write out to disk gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , true ); LLUIColorTable::instance().saveUserSettings(); } // Next iteration through main loop should shut down the app cleanly. LLAppViewer::instance()->userQuit(); if (LLAppViewer::instance()->quitRequested()) { // [FS Login Panel] //LLPanelLogin::closePanel(); FSPanelLogin::closePanel(); // [FS Login Panel] } return; } else { LL_WARNS("AppInit") << "Unknown login button clicked" << LL_ENDL; } } void release_notes_coro(const std::string url) { if (url.empty()) { return; } LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("releaseNotesCoro", httpPolicy)); LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); httpOpts->setHeadersOnly(true); // only making sure it isn't 404 or something like that LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts); LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); if (!status) { return; } LLWeb::loadURLInternal(url); } void validate_release_notes_coro(const std::string url) { LLVersionInfo& versionInfo(LLVersionInfo::instance()); const boost::regex version_regex(R"(\b\d+\.\d+\.\d+\.\d+\b)"); if (url.find(versionInfo.getVersion()) == std::string::npos // has no our build version && ll_regex_search(url, version_regex)) // has any version { LL_INFOS() << "Received release notes url \"" << url << "\" wwith mismatching build, falling back to locally generated url" << LL_ENDL; // Updater only provides notes for a most recent version, if it is not // the current one, fall back to the hardcoded URL. LLSD info(LLAppViewer::instance()->getViewerInfo()); std::string alt_url = info["VIEWER_RELEASE_NOTES_URL"].asString(); release_notes_coro(alt_url); } else { release_notes_coro(url); } } /** * Check if user is running a new version of the viewer. * Display the Release Notes if it's not overriden by the "UpdaterShowReleaseNotes" setting. */ void show_release_notes_if_required() { static bool release_notes_shown = false; // We happen to know that instantiating LLVersionInfo implicitly // instantiates the LLEventMailDrop named "relnotes", which we (might) use // below. If viewer release notes stop working, might be because that // LLEventMailDrop got moved out of LLVersionInfo and hasn't yet been // instantiated. if (!release_notes_shown && (LLVersionInfo::instance().getChannelAndVersion() != gLastRunVersion) && LLVersionInfo::instance().getViewerMaturity() != LLVersionInfo::TEST_VIEWER // don't show Release Notes for the test builds && gSavedSettings.getBOOL("UpdaterShowReleaseNotes") && !gSavedSettings.getBOOL("FirstLoginThisInstall")) { #if LL_RELEASE_FOR_DOWNLOAD if (!gSavedSettings.getBOOL("CmdLineSkipUpdater") && !LLAppViewer::instance()->isUpdaterMissing()) { // Instantiate a "relnotes" listener which assumes any arriving event // is the release notes URL string. Since "relnotes" is an // LLEventMailDrop, this listener will be invoked whether or not the // URL has already been posted. If so, it will fire immediately; // otherwise it will fire whenever the URL is (later) posted. Either // way, it will display the release notes as soon as the URL becomes // available. LLEventPumps::instance().obtain("relnotes").listen( "showrelnotes", [](const LLSD& url) { LLCoros::instance().launch("releaseNotesCoro", boost::bind(&validate_release_notes_coro, url.asString())); return false; }); } else #endif // LL_RELEASE_FOR_DOWNLOAD { LLSD info(LLAppViewer::instance()->getViewerInfo()); std::string url = info["VIEWER_RELEASE_NOTES_URL"].asString(); LLCoros::instance().launch("releaseNotesCoro", boost::bind(&release_notes_coro, url)); } release_notes_shown = true; } } // Ditch the first run modal. Assume the user already has an account. //void show_first_run_dialog() //{ // LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback); //} bool first_run_dialog_callback(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (0 == option) { LL_DEBUGS("AppInit") << "First run dialog cancelling" << LL_ENDL; LLWeb::loadURLExternal(LLTrans::getString("create_account_url") ); } // [FS Login Panel] //LLPanelLogin::giveFocus(); FSPanelLogin::giveFocus(); // [FS Login Panel] return false; } void set_startup_status(const F32 frac, const std::string& string, const std::string& msg) { gViewerWindow->setProgressPercent(frac*100); gViewerWindow->setProgressString(string); gViewerWindow->setProgressMessage(msg); } bool login_alert_status(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); // Buttons switch( option ) { case 0: // OK break; // case 1: // Help // LLWeb::loadURL(LLNotifications::instance().getGlobalString("SUPPORT_URL") ); // break; case 2: // Teleport // Restart the login process, starting at our home locaton LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); break; default: LL_WARNS("AppInit") << "Missing case in login_alert_status switch" << LL_ENDL; } // [FS Login Panel] //LLPanelLogin::giveFocus(); FSPanelLogin::giveFocus(); // [FS Login Panel] return false; } void use_circuit_callback(void**, S32 result) { // bail if we're quitting. if(LLApp::isExiting()) return; if( !gUseCircuitCallbackCalled ) { gUseCircuitCallbackCalled = true; if (result) { // Make sure user knows something bad happened. JC LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; if (gRememberPassword) { LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); } else { LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); } reset_login(); } else { gGotUseCircuitCodeAck = true; } } } void register_viewer_callbacks(LLMessageSystem* msg) { msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data ); // OpenSim compatibility msg->setHandlerFuncFast(_PREHASH_ImageData, LLViewerTextureList::receiveImageHeader ); msg->setHandlerFuncFast(_PREHASH_ImagePacket, LLViewerTextureList::receiveImagePacket ); // msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update ); msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update ); msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update ); msg->setHandlerFuncFast(_PREHASH_ImprovedTerseObjectUpdate, process_terse_object_update_improved ); msg->setHandlerFunc("SimStats", process_sim_stats); msg->setHandlerFuncFast(_PREHASH_HealthMessage, process_health_message ); msg->setHandlerFuncFast(_PREHASH_EconomyData, process_economy_data); msg->setHandlerFunc("RegionInfo", LLViewerRegion::processRegionInfo); msg->setHandlerFuncFast(_PREHASH_ChatFromSimulator, process_chat_from_simulator); msg->setHandlerFuncFast(_PREHASH_KillObject, process_kill_object, NULL); msg->setHandlerFuncFast(_PREHASH_SimulatorViewerTimeMessage, process_time_synch, NULL); msg->setHandlerFuncFast(_PREHASH_EnableSimulator, process_enable_simulator); msg->setHandlerFuncFast(_PREHASH_DisableSimulator, process_disable_simulator); msg->setHandlerFuncFast(_PREHASH_KickUser, process_kick_user, NULL); msg->setHandlerFunc("CrossedRegion", process_crossed_region); msg->setHandlerFuncFast(_PREHASH_TeleportFinish, process_teleport_finish); msg->setHandlerFuncFast(_PREHASH_AlertMessage, process_alert_message); msg->setHandlerFunc("AgentAlertMessage", process_agent_alert_message); msg->setHandlerFuncFast(_PREHASH_MeanCollisionAlert, process_mean_collision_alert_message, NULL); msg->setHandlerFunc("ViewerFrozenMessage", process_frozen_message); msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value); msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation); msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); // [Legacy Bake] msg->setHandlerFunc("AgentCachedTextureResponse", LLAgent::processAgentCachedTextureResponse); msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures); // [Legacy Bake] msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties); msg->setHandlerFunc("ClearFollowCamProperties", process_clear_follow_cam_properties); msg->setHandlerFuncFast(_PREHASH_ImprovedInstantMessage, process_improved_im); msg->setHandlerFuncFast(_PREHASH_ScriptQuestion, process_script_question); // area search //msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties, NULL); msg->setHandlerFuncFast(_PREHASH_ObjectProperties, process_object_properties, NULL); // area search // Anti spam //msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, LLSelectMgr::processObjectPropertiesFamily, NULL); msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, process_object_properties_family, NULL); // msg->setHandlerFunc("ForceObjectSelect", LLSelectMgr::processForceObjectSelect); msg->setHandlerFuncFast(_PREHASH_MoneyBalanceReply, process_money_balance_reply, NULL); msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate, NULL); msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv, NULL); msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container, NULL); msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply, &LLLiveLSLEditor::processScriptRunningReply); msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack); msg->setHandlerFunc("LogoutReply", process_logout_reply); //msg->setHandlerFuncFast(_PREHASH_AddModifyAbility, // &LLAgent::processAddModifyAbility); //msg->setHandlerFuncFast(_PREHASH_RemoveModifyAbility, // &LLAgent::processRemoveModifyAbility); msg->setHandlerFuncFast(_PREHASH_AgentDataUpdate, &LLAgent::processAgentDataUpdate); msg->setHandlerFuncFast(_PREHASH_AgentGroupDataUpdate, &LLAgent::processAgentGroupDataUpdate); msg->setHandlerFunc("AgentDropGroup", &LLAgent::processAgentDropGroup); // land ownership messages msg->setHandlerFuncFast(_PREHASH_ParcelOverlay, LLViewerParcelMgr::processParcelOverlay); msg->setHandlerFuncFast(_PREHASH_ParcelProperties, LLViewerParcelMgr::processParcelProperties); msg->setHandlerFunc("ParcelAccessListReply", LLViewerParcelMgr::processParcelAccessListReply); msg->setHandlerFunc("ParcelDwellReply", LLViewerParcelMgr::processParcelDwellReply); msg->setHandlerFunc("AvatarPropertiesReply", &LLAvatarPropertiesProcessor::processAvatarLegacyPropertiesReply); msg->setHandlerFunc("AvatarInterestsReply", &LLAvatarPropertiesProcessor::processAvatarInterestsReply); msg->setHandlerFunc("AvatarGroupsReply", &LLAvatarPropertiesProcessor::processAvatarGroupsReply); msg->setHandlerFunc("AvatarNotesReply", &LLAvatarPropertiesProcessor::processAvatarNotesReply); msg->setHandlerFunc("AvatarPicksReply", &LLAvatarPropertiesProcessor::processAvatarPicksReply); msg->setHandlerFunc("AvatarClassifiedReply", &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply); msg->setHandlerFuncFast(_PREHASH_CreateGroupReply, LLGroupMgr::processCreateGroupReply); msg->setHandlerFuncFast(_PREHASH_JoinGroupReply, LLGroupMgr::processJoinGroupReply); msg->setHandlerFuncFast(_PREHASH_EjectGroupMemberReply, LLGroupMgr::processEjectGroupMemberReply); msg->setHandlerFuncFast(_PREHASH_LeaveGroupReply, LLGroupMgr::processLeaveGroupReply); msg->setHandlerFuncFast(_PREHASH_GroupProfileReply, LLGroupMgr::processGroupPropertiesReply); // ratings deprecated // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, // LLFloaterRate::processReputationIndividualReply); // [Legacy Bake] msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate, LLAgentWearables::processAgentInitialWearablesUpdate ); msg->setHandlerFunc("ScriptControlChange", LLAgent::processScriptControlChange ); msg->setHandlerFuncFast(_PREHASH_ViewerEffect, LLHUDManager::processViewerEffect); msg->setHandlerFuncFast(_PREHASH_GrantGodlikePowers, process_grant_godlike_powers); msg->setHandlerFuncFast(_PREHASH_GroupAccountSummaryReply, LLPanelGroupLandMoney::processGroupAccountSummaryReply); msg->setHandlerFuncFast(_PREHASH_GroupAccountDetailsReply, LLPanelGroupLandMoney::processGroupAccountDetailsReply); msg->setHandlerFuncFast(_PREHASH_GroupAccountTransactionsReply, LLPanelGroupLandMoney::processGroupAccountTransactionsReply); msg->setHandlerFuncFast(_PREHASH_UserInfoReply, process_user_info_reply); msg->setHandlerFunc("RegionHandshake", process_region_handshake, NULL); msg->setHandlerFunc("TeleportStart", process_teleport_start ); msg->setHandlerFunc("TeleportProgress", process_teleport_progress); msg->setHandlerFunc("TeleportFailed", process_teleport_failed, NULL); msg->setHandlerFunc("TeleportLocal", process_teleport_local, NULL); msg->setHandlerFunc("ImageNotInDatabase", LLViewerTextureList::processImageNotInDatabase, NULL); msg->setHandlerFuncFast(_PREHASH_GroupMembersReply, LLGroupMgr::processGroupMembersReply); msg->setHandlerFunc("GroupRoleDataReply", LLGroupMgr::processGroupRoleDataReply); msg->setHandlerFunc("GroupRoleMembersReply", LLGroupMgr::processGroupRoleMembersReply); msg->setHandlerFunc("GroupTitlesReply", LLGroupMgr::processGroupTitlesReply); // Special handler as this message is sometimes used for group land. msg->setHandlerFunc("PlacesReply", process_places_reply); msg->setHandlerFunc("GroupNoticesListReply", LLPanelGroupNotices::processGroupNoticesListReply); // FIRE-6310 - Legacy search handlers msg->setHandlerFunc("DirPeopleReply", FSPanelSearchPeople::processSearchReply); msg->setHandlerFunc("DirPlacesReply", FSPanelSearchPlaces::processSearchReply); msg->setHandlerFunc("DirGroupsReply", FSPanelSearchGroups::processSearchReply); msg->setHandlerFunc("DirEventsReply", FSPanelSearchEvents::processSearchReply); msg->setHandlerFunc("DirLandReply", FSPanelSearchLand::processSearchReply); msg->setHandlerFunc("DirClassifiedReply", FSPanelSearchClassifieds::processSearchReply); // FIRE-6310 msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply); msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply); msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply); msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply); msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply); msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply); msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply); msg->setHandlerFunc("ScriptDialog", process_script_dialog); msg->setHandlerFunc("LoadURL", process_load_url); msg->setHandlerFunc("ScriptTeleportRequest", process_script_teleport_request); msg->setHandlerFunc("EstateCovenantReply", process_covenant_reply); // calling cards msg->setHandlerFunc("OfferCallingCard", process_offer_callingcard); msg->setHandlerFunc("AcceptCallingCard", process_accept_callingcard); msg->setHandlerFunc("DeclineCallingCard", process_decline_callingcard); msg->setHandlerFunc("ParcelObjectOwnersReply", LLPanelLandObjects::processParcelObjectOwnersReply); msg->setHandlerFunc("InitiateDownload", process_initiate_download); msg->setHandlerFunc("LandStatReply", LLFloaterTopObjects::handle_land_reply); msg->setHandlerFunc("GenericMessage", process_generic_message); msg->setHandlerFunc("GenericStreamingMessage", process_generic_streaming_message); msg->setHandlerFunc("LargeGenericMessage", process_large_generic_message); msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message); } void asset_callback_nothing(const LLUUID&, LLAssetType::EType, void*, S32) { // nothing } const S32 OPT_CLOSED_WINDOW = -1; const S32 OPT_MALE = 0; const S32 OPT_FEMALE = 1; const S32 OPT_TRUST_CERT = 0; const S32 OPT_CANCEL_TRUST = 1; bool callback_choose_gender(const LLSD& notification, const LLSD& response) { // These defaults are returned from the server on login. They are set in login.xml. // If no default is returned from the server, they are retrieved from settings.xml. S32 option = LLNotification::getSelectedOption(notification, response); switch(option) { case OPT_MALE: LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" ); break; case OPT_FEMALE: case OPT_CLOSED_WINDOW: default: LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" ); break; } return false; } std::string get_screen_filename(const std::string& pattern) { // OpenSim support //if (LLGridManager::getInstance()->isInProductionGrid()) if (LLGridManager::getInstance()->isInSLMain()) // { return llformat(pattern.c_str(), ""); } else { const std::string& grid_id_str = LLGridManager::getInstance()->getGridId(); const std::string& grid_id_lower = utf8str_tolower(grid_id_str); std::string grid = "." + grid_id_lower; return llformat(pattern.c_str(), grid.c_str()); } } //static std::string LLStartUp::getScreenLastFilename() { return get_screen_filename(SCREEN_LAST_FILENAME); } //static std::string LLStartUp::getScreenHomeFilename() { return get_screen_filename(SCREEN_HOME_FILENAME); } //static void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, const std::string& gender_name ) { LL_DEBUGS() << "starting" << LL_ENDL; // Not going through the processAgentInitialWearables path, so need to set this here. LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); // Initiate creation of COF, since we're also bypassing that. gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); LLAppearanceMgr::getInstance()->initCOFID(); ESex gender; if (gender_name == "male") { LL_DEBUGS() << "male" << LL_ENDL; gender = SEX_MALE; } else { LL_DEBUGS() << "female" << LL_ENDL; gender = SEX_FEMALE; } if (!isAgentAvatarValid()) { LL_WARNS() << "Trying to load an initial outfit for an invalid agent avatar" << LL_ENDL; return; } gAgentAvatarp->setSex(gender); // try to find the requested outfit or folder // -- check for existing outfit in My Outfits bool do_copy = false; LLUUID cat_id = findDescendentCategoryIDByName( gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS), outfit_folder_name); // -- check for existing folder in Library if (cat_id.isNull()) { cat_id = findDescendentCategoryIDByName( gInventory.getLibraryRootFolderID(), outfit_folder_name); if (!cat_id.isNull()) { do_copy = true; } } if (cat_id.isNull()) { // -- final fallback: create standard wearables LL_DEBUGS() << "standard wearables" << LL_ENDL; gAgentWearables.createStandardWearables(); } else { bool do_append = false; LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); // Need to fetch cof contents before we can wear. if (do_copy) { callAfterCOFFetch(boost::bind(&LLAppearanceMgr::wearInventoryCategory, LLAppearanceMgr::getInstance(), cat, do_copy, do_append)); } else { callAfterCategoryLinksFetch(cat_id, boost::bind(&LLAppearanceMgr::wearInventoryCategory, LLAppearanceMgr::getInstance(), cat, do_copy, do_append)); } LL_DEBUGS() << "initial outfit category id: " << cat_id << LL_ENDL; } gAgent.setOutfitChosen(true); // [Legacy Bake] #ifdef OPENSIM if (LLGridManager::getInstance()->isInSecondLife()) #endif // [Legacy Bake] gAgentWearables.sendDummyAgentWearablesUpdate(); } std::string& LLStartUp::getInitialOutfitName() { return sInitialOutfit; } std::string LLStartUp::getUserId() { if (gUserCredential.isNull()) { return ""; } return gUserCredential->userID(); } // frees the bitmap void release_start_screen() { LL_DEBUGS("AppInit") << "Releasing bitmap..." << LL_ENDL; gStartTexture = NULL; } // static std::string LLStartUp::startupStateToString(EStartupState state) { #define RTNENUM(E) case E: return #E switch(state){ RTNENUM( STATE_FIRST ); RTNENUM( STATE_BROWSER_INIT ); RTNENUM( STATE_LOGIN_SHOW ); RTNENUM( STATE_LOGIN_WAIT ); RTNENUM( STATE_LOGIN_CLEANUP ); RTNENUM( STATE_LOGIN_AUTH_INIT ); RTNENUM( STATE_LOGIN_CURL_UNSTUCK ); RTNENUM( STATE_LOGIN_PROCESS_RESPONSE ); RTNENUM( STATE_WORLD_INIT ); RTNENUM( STATE_MULTIMEDIA_INIT ); RTNENUM( STATE_FONT_INIT ); RTNENUM( STATE_SEED_GRANTED_WAIT ); RTNENUM( STATE_SEED_CAP_GRANTED ); RTNENUM( STATE_WORLD_WAIT ); RTNENUM( STATE_AGENT_SEND ); RTNENUM( STATE_AGENT_WAIT ); RTNENUM( STATE_INVENTORY_SEND ); RTNENUM(STATE_INVENTORY_CALLBACKS ); RTNENUM( STATE_INVENTORY_SKEL ); RTNENUM( STATE_INVENTORY_SEND2 ); RTNENUM( STATE_MISC ); RTNENUM( STATE_PRECACHE ); RTNENUM( STATE_WEARABLES_WAIT ); RTNENUM( STATE_CLEANUP ); RTNENUM( STATE_STARTED ); // Add FS-specific startup states RTNENUM( STATE_FETCH_GRID_INFO ); RTNENUM( STATE_AUDIO_INIT); RTNENUM( STATE_AGENTS_WAIT ); RTNENUM( STATE_LOGIN_CONFIRM_NOTIFICATON ); // default: return llformat("(state #%d)", state); } #undef RTNENUM } // static void LLStartUp::setStartupState( EStartupState state ) { LL_INFOS("AppInit") << getStartupStateString() << " --> " << startupStateToString(state) << LL_ENDL; getPhases().stopPhase(getStartupStateString()); gStartupState = state; getPhases().startPhase(getStartupStateString()); postStartupState(); } void LLStartUp::postStartupState() { LLSD stateInfo; stateInfo["str"] = getStartupStateString(); stateInfo["enum"] = gStartupState; sStateWatcher->post(stateInfo); gDebugInfo["StartupState"] = getStartupStateString(); } void reset_login() { gAgentWearables.cleanup(); gAgentCamera.cleanup(); gAgent.cleanup(); gSky.cleanup(); // mVOSkyp is an inworld object. LLWorld::getInstance()->resetClass(); LLAppearanceMgr::getInstance()->cleanup(); if ( gViewerWindow ) { // Hide menus and normal buttons gViewerWindow->setNormalControlsVisible( false ); gLoginMenuBarView->setVisible( true ); gLoginMenuBarView->setEnabled( true ); } // Hide any other stuff // Fixing chat toasts to not show on the login page when login progress screens are disabled. LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(LLNotificationsUI::NEARBY_CHAT_CHANNEL_UUID); if (chat_channel) { chat_channel->removeToastsFromChannel(); } // LLFloaterReg::hideVisibleInstances(); // Improved menu and navigation bar //if (LLStartUp::getStartupState() > STATE_WORLD_INIT) //{ // gViewerWindow->resetStatusBarContainer(); //} // LLStartUp::setStartupState( STATE_BROWSER_INIT ); if (LLVoiceClient::instanceExists()) { LLVoiceClient::getInstance()->terminate(); } // Clear any verified certs and verify them again on next login // to ensure cert matches server instead of just getting reused LLPointer store = gSecAPIHandler->getCertificateStore(""); store->clearSertCache(); } //--------------------------------------------------------------------------- // Initialize all plug-ins except the web browser (which was initialized // early, before the login screen). JC void LLStartUp::multimediaInit() { LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL; std::string msg = LLTrans::getString("LoginInitializingMultimedia"); set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str()); do_startup_frame(); // Also initialise the stream titles. StreamTitleDisplay::instance(); FSStreamTitleManager::instance(); } void LLStartUp::fontInit() { LL_DEBUGS("AppInit") << "Initializing fonts...." << LL_ENDL; std::string msg = LLTrans::getString("LoginInitializingFonts"); set_startup_status(0.45f, msg.c_str(), gAgent.mMOTD.c_str()); do_startup_frame(); LLFontGL::loadDefaultFonts(); } void LLStartUp::initNameCache() { // Can be called multiple times if ( gCacheName ) return; gCacheName = new LLCacheName(gMessageSystem); gCacheName->addObserver(&callback_cache_name); gCacheName->localizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting")); gCacheName->localizeCacheName("nobody", LLTrans::getString("AvatarNameNobody")); gCacheName->localizeCacheName("none", LLTrans::getString("GroupNameNone")); // Load stored cache if possible LLAppViewer::instance()->loadNameCache(); // Start cache in not-running state until we figure out if we have // capabilities for display name lookup LLAvatarNameCache* cache_inst = LLAvatarNameCache::getInstance(); cache_inst->setUsePeopleAPI(gSavedSettings.getBOOL("UsePeopleAPI")); cache_inst->setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames")); cache_inst->setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames")); // Legacy name/Username format LLAvatarName::setUseLegacyFormat(gSavedSettings.getBOOL("FSNameTagShowLegacyUsernames")); // FIRE-6659: Legacy "Resident" name toggle LLAvatarName::setTrimResidentSurname(gSavedSettings.getBOOL("FSTrimLegacyNames")); } void LLStartUp::initExperiences() { // Should trigger loading the cache. LLExperienceCache::instance().setCapabilityQuery( boost::bind(&LLAgent::getRegionCapability, &gAgent, _1)); LLExperienceLog::instance().initialize(); } void LLStartUp::cleanupNameCache() { delete gCacheName; gCacheName = NULL; } bool LLStartUp::dispatchURL() { // ok, if we've gotten this far and have a startup URL if (!getStartSLURL().isValid()) { return false; } if(getStartSLURL().getType() != LLSLURL::APP) { // If we started with a location, but we're already // at that location, don't pop dialogs open. LLVector3 pos = gAgent.getPositionAgent(); LLVector3 slurlpos = getStartSLURL().getPosition(); F32 dx = pos.mV[VX] - slurlpos.mV[VX]; F32 dy = pos.mV[VY] - slurlpos.mV[VY]; const F32 SLOP = 2.f; // meters if( getStartSLURL().getRegion() != gAgent.getRegion()->getName() || (dx*dx > SLOP*SLOP) || (dy*dy > SLOP*SLOP) ) { LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(), LLCommandHandler::NAV_TYPE_CLICKED, NULL, false); } return true; } return false; } void LLStartUp::setStartSLURL(const LLSLURL& slurl) { sStartSLURL = slurl; switch(slurl.getType()) { case LLSLURL::HOME_LOCATION: { gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_HOME); break; } case LLSLURL::LAST_LOCATION: { gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_LAST); break; } // Support adding grids via SLURL #if OPENSIM && !SINGLEGRID case LLSLURL::APP: if (slurl.getAppCmd() == "gridmanager") { LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(), "clicked", NULL, false); break; } #endif // default: LLGridManager::getInstance()->setGridChoice(slurl.getGrid()); break; } // FIRE-29994: Start location doesn't get updated when selection a destination from the login splash screen FSPanelLogin::onUpdateStartSLURL(sStartSLURL); } // static LLSLURL& LLStartUp::getStartSLURL() { return sStartSLURL; } /** * Read all proxy configuration settings and set up both the HTTP proxy and * SOCKS proxy as needed. * * Any errors that are encountered will result in showing the user a notification. * When an error is encountered, * * @return Returns true if setup was successful, false if an error was encountered. */ bool LLStartUp::startLLProxy() { bool proxy_ok = true; std::string httpProxyType = gSavedSettings.getString("HttpProxyType"); // Set up SOCKS proxy (if needed) if (gSavedSettings.getBOOL("Socks5ProxyEnabled")) { // Determine and update LLProxy with the saved authentication system std::string auth_type = gSavedSettings.getString("Socks5AuthType"); if (auth_type.compare("UserPass") == 0) { LLPointer socks_cred = gSecAPIHandler->loadCredential("SOCKS5"); std::string socks_user = socks_cred->getIdentifier()["username"].asString(); std::string socks_password = socks_cred->getAuthenticator()["creds"].asString(); bool ok = LLProxy::getInstance()->setAuthPassword(socks_user, socks_password); if (!ok) { LLNotificationsUtil::add("SOCKS_BAD_CREDS"); proxy_ok = false; } } else if (auth_type.compare("None") == 0) { LLProxy::getInstance()->setAuthNone(); } else { LL_WARNS("Proxy") << "Invalid SOCKS 5 authentication type."<< LL_ENDL; // Unknown or missing setting. gSavedSettings.setString("Socks5AuthType", "None"); // Clear the SOCKS credentials. LLPointer socks_cred = new LLCredential("SOCKS5"); gSecAPIHandler->deleteCredential(socks_cred); LLProxy::getInstance()->setAuthNone(); } if (proxy_ok) { // Start the proxy and check for errors // If status != SOCKS_OK, stopSOCKSProxy() will already have been called when startSOCKSProxy() returns. LLHost socks_host; socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); int status = LLProxy::getInstance()->startSOCKSProxy(socks_host); if (status != SOCKS_OK) { LLSD subs; subs["HOST"] = gSavedSettings.getString("Socks5ProxyHost"); subs["PORT"] = (S32)gSavedSettings.getU32("Socks5ProxyPort"); std::string error_string; switch(status) { case SOCKS_CONNECT_ERROR: // TCP Fail error_string = "SOCKS_CONNECT_ERROR"; break; case SOCKS_NOT_PERMITTED: // SOCKS 5 server rule set refused connection error_string = "SOCKS_NOT_PERMITTED"; break; case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server error_string = "SOCKS_NOT_ACCEPTABLE"; break; case SOCKS_AUTH_FAIL: // Authentication failed error_string = "SOCKS_AUTH_FAIL"; break; case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed error_string = "SOCKS_UDP_FWD_NOT_GRANTED"; break; case SOCKS_HOST_CONNECT_FAILED: // Failed to open a TCP channel to the socks server error_string = "SOCKS_HOST_CONNECT_FAILED"; break; case SOCKS_INVALID_HOST: // Improperly formatted host address or port. error_string = "SOCKS_INVALID_HOST"; break; default: error_string = "SOCKS_UNKNOWN_STATUS"; // Something strange happened, LL_WARNS("Proxy") << "Unknown return from LLProxy::startProxy(): " << status << LL_ENDL; break; } LLNotificationsUtil::add(error_string, subs); proxy_ok = false; } } } else { LLProxy::getInstance()->stopSOCKSProxy(); // ensure no UDP proxy is running and it's all cleaned up } if (proxy_ok) { // Determine the HTTP proxy type (if any) if ((httpProxyType.compare("Web") == 0) && gSavedSettings.getBOOL("BrowserProxyEnabled")) { LLHost http_host; http_host.setHostByName(gSavedSettings.getString("BrowserProxyAddress")); http_host.setPort(gSavedSettings.getS32("BrowserProxyPort")); if (!LLProxy::getInstance()->enableHTTPProxy(http_host, LLPROXY_HTTP)) { LLSD subs; subs["HOST"] = http_host.getIPString(); subs["PORT"] = (S32)http_host.getPort(); LLNotificationsUtil::add("PROXY_INVALID_HTTP_HOST", subs); proxy_ok = false; } } else if ((httpProxyType.compare("Socks") == 0) && gSavedSettings.getBOOL("Socks5ProxyEnabled")) { LLHost socks_host; socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost")); socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort")); if (!LLProxy::getInstance()->enableHTTPProxy(socks_host, LLPROXY_SOCKS)) { LLSD subs; subs["HOST"] = socks_host.getIPString(); subs["PORT"] = (S32)socks_host.getPort(); LLNotificationsUtil::add("PROXY_INVALID_SOCKS_HOST", subs); proxy_ok = false; } } else if (httpProxyType.compare("None") == 0) { LLProxy::getInstance()->disableHTTPProxy(); } else { LL_WARNS("Proxy") << "Invalid other HTTP proxy configuration: " << httpProxyType << LL_ENDL; // Set the missing or wrong configuration back to something valid. gSavedSettings.setString("HttpProxyType", "None"); LLProxy::getInstance()->disableHTTPProxy(); // Leave proxy_ok alone, since this isn't necessarily fatal. } } return proxy_ok; } bool login_alert_done(const LLSD& notification, const LLSD& response) { // [FS Login Panel] //LLPanelLogin::giveFocus(); transition_back_to_login_panel(std::string()); // [FS Login Panel] return false; } // parse the certificate information into args for the // certificate notifications LLSD transform_cert_args(LLPointer cert) { LLSD args = LLSD::emptyMap(); std::string value; LLSD cert_info; cert->getLLSD(cert_info); // convert all of the elements in the cert into // args for the xml dialog, so we have flexability to // display various parts of the cert by only modifying // the cert alert dialog xml. for(LLSD::map_iterator iter = cert_info.beginMap(); iter != cert_info.endMap(); iter++) { // key usage and extended key usage // are actually arrays, and we want to format them as comma separated // strings, so special case those. LLSDSerialize::toXML(cert_info[iter->first], std::cout); if((iter->first == std::string(CERT_KEY_USAGE)) || (iter->first == std::string(CERT_EXTENDED_KEY_USAGE))) { value = ""; LLSD usage = cert_info[iter->first]; for (LLSD::array_iterator usage_iter = usage.beginArray(); usage_iter != usage.endArray(); usage_iter++) { if(usage_iter != usage.beginArray()) { value += ", "; } value += (*usage_iter).asString(); } } else { value = iter->second.asString(); } std::string name = iter->first; std::transform(name.begin(), name.end(), name.begin(), (int(*)(int))toupper); args[name.c_str()] = value; } return args; } // when we handle a cert error, give focus back to the login panel void general_cert_done(const LLSD& notification, const LLSD& response) { // [FS Login Panel] //LLStartUp::setStartupState( STATE_LOGIN_SHOW ); //LLPanelLogin::giveFocus(); transition_back_to_login_panel(std::string()); // [FS Login Panel] } // check to see if the user wants to trust the cert. // if they do, add it to the cert store and void trust_cert_done(const LLSD& notification, const LLSD& response) { S32 option = LLNotification::getSelectedOption(notification, response); switch(option) { case OPT_TRUST_CERT: { LLPointer cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]); LLPointer store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore")); store->add(cert); store->save(); LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); break; } case OPT_CANCEL_TRUST: // That's what transition_back_to_login_panel is for and does! //reset_login(); //gSavedSettings.setBOOL("AutoLogin", false); //LLStartUp::setStartupState( STATE_LOGIN_SHOW ); transition_back_to_login_panel(std::string()); // default: // [FS Login Panel] //LLPanelLogin::giveFocus(); transition_back_to_login_panel(std::string()); // [FS Login Panel] break; } } void apply_udp_blacklist(const std::string& csv) { std::string::size_type start = 0; std::string::size_type comma = 0; do { comma = csv.find(",", start); if (comma == std::string::npos) { comma = csv.length(); } std::string item(csv, start, comma-start); LL_DEBUGS() << "udp_blacklist " << item << LL_ENDL; gMessageSystem->banUdpMessage(item); start = comma + 1; } while(comma < csv.length()); } void on_benefits_failed_callback(const LLSD& notification, const LLSD& response) { LL_WARNS("Benefits") << "Failed to load benefits information" << LL_ENDL; } bool init_benefits(LLSD& response) { bool succ = true; std::string package_name = response["account_type"].asString(); const LLSD& benefits_sd = response["account_level_benefits"]; if (!LLAgentBenefitsMgr::init(package_name, benefits_sd) || !LLAgentBenefitsMgr::initCurrent(package_name, benefits_sd)) { succ = false; } else { LL_DEBUGS("Benefits") << "Initialized current benefits, level " << package_name << " from " << benefits_sd << LL_ENDL; } const LLSD& packages_sd = response["premium_packages"]; for(LLSD::map_const_iterator package_iter = packages_sd.beginMap(); package_iter != packages_sd.endMap(); ++package_iter) { std::string package_name = package_iter->first; const LLSD& benefits_sd = package_iter->second["benefits"]; if (LLAgentBenefitsMgr::init(package_name, benefits_sd)) { LL_DEBUGS("Benefits") << "Initialized benefits for package " << package_name << " from " << benefits_sd << LL_ENDL; } else { LL_WARNS("Benefits") << "Failed init for package " << package_name << " from " << benefits_sd << LL_ENDL; succ = false; } } if (!LLAgentBenefitsMgr::has("Base")) { LL_WARNS("Benefits") << "Benefits info did not include required package Base" << LL_ENDL; succ = false; } if (!LLAgentBenefitsMgr::has("Premium")) { LL_WARNS("Benefits") << "Benefits info did not include required package Premium" << LL_ENDL; succ = false; } return succ; } // Aurora Sim //bool process_login_success_response() bool process_login_success_response(U32 &first_sim_size_x, U32 &first_sim_size_y) // Aurora Sim { LLSD response = LLLoginInstance::getInstance()->getResponse(); // OpenSim legacy economy support //mBenefitsSuccessfullyInit = init_benefits(response); if (LLGridManager::instance().isInSecondLife()) { mBenefitsSuccessfullyInit = init_benefits(response); } else { mBenefitsSuccessfullyInit = true; } // std::string text(response["udp_blacklist"]); if(!text.empty()) { apply_udp_blacklist(text); } // unpack login data needed by the application text = response["agent_id"].asString(); if(!text.empty()) gAgentID.set(text); // gDebugInfo["AgentID"] = text; // [SL:KB] - Patch: Viewer-CrashReporting | Checked: 2010-11-16 (Catznip-2.6.0a) | Added: Catznip-2.4.0b if (gCrashSettings.getBOOL("CrashSubmitName")) { // Only include the agent UUID if the user consented gDebugInfo["AgentID"] = text; } // [/SL:KB] LLPerfStats::StatsRecorder::setEnabled(gSavedSettings.getBOOL("PerfStatsCaptureEnabled")); LLPerfStats::StatsRecorder::setFocusAv(gAgentID); // Agent id needed for parcel info request in LLUrlEntryParcel // to resolve parcel name. LLUrlEntryBase::setAgentID(gAgentID); text = response["session_id"].asString(); if(!text.empty()) gAgentSessionID.set(text); // gDebugInfo["SessionID"] = text; LLAppViewer::instance()->recordSessionToMarker(); // Session id needed for parcel info request in LLUrlEntryParcel // to resolve parcel name. LLUrlEntryParcel::setSessionID(gAgentSessionID); text = response["secure_session_id"].asString(); if(!text.empty()) gAgent.mSecureSessionID.set(text); // if the response contains a display name, use that, // otherwise if the response contains a first and/or last name, // use those. Otherwise use the credential identifier gDisplayName = ""; if (response.has("display_name")) { gDisplayName.assign(response["display_name"].asString()); if(!gDisplayName.empty()) { // Remove quotes from string. Login.cgi sends these to force // names that look like numbers into strings. LLStringUtil::replaceChar(gDisplayName, '"', ' '); LLStringUtil::trim(gDisplayName); } } std::string first_name; if(response.has("first_name")) { first_name = response["first_name"].asString(); LLStringUtil::replaceChar(first_name, '"', ' '); LLStringUtil::trim(first_name); gAgentUsername = first_name; } if(response.has("last_name") && !gAgentUsername.empty()) { std::string last_name = response["last_name"].asString(); if (last_name != "Resident") { LLStringUtil::replaceChar(last_name, '"', ' '); LLStringUtil::trim(last_name); gAgentUsername = gAgentUsername + " " + last_name; } } if(gDisplayName.empty()) { if(response.has("first_name")) { gDisplayName.assign(response["first_name"].asString()); LLStringUtil::replaceChar(gDisplayName, '"', ' '); LLStringUtil::trim(gDisplayName); } if(response.has("last_name")) { text.assign(response["last_name"].asString()); LLStringUtil::replaceChar(text, '"', ' '); LLStringUtil::trim(text); if(!gDisplayName.empty()) { gDisplayName += " "; } gDisplayName += text; } } if(gDisplayName.empty()) { gDisplayName.assign(gUserCredential->asString()); } // this is their actual ability to access content text = response["agent_access_max"].asString(); if (!text.empty()) { // agent_access can be 'A', 'M', and 'PG'. gAgent.setMaturity(text[0]); // FIRE-8854: Set the preferred maturity here to the maximum // in case the sim doesn't send it at login, like OpenSim // doesn't. If it does, it'll get overridden below. U32 preferredMaturity = (U32)LLAgent::convertTextToMaturity(text[0]); gSavedSettings.setU32("PreferredMaturity", preferredMaturity); } // this is the value of their preference setting for that content // which will always be <= agent_access_max text = response["agent_region_access"].asString(); if (!text.empty()) { U32 preferredMaturity = (U32)LLAgent::convertTextToMaturity(text[0]); gSavedSettings.setU32("PreferredMaturity", preferredMaturity); } text = response["start_location"].asString(); if(!text.empty()) { gAgentStartLocation.assign(text); } text = response["circuit_code"].asString(); if(!text.empty()) { gMessageSystem->mOurCircuitCode = strtoul(text.c_str(), NULL, 10); } std::string sim_ip_str = response["sim_ip"]; std::string sim_port_str = response["sim_port"]; if(!sim_ip_str.empty() && !sim_port_str.empty()) { U32 sim_port = strtoul(sim_port_str.c_str(), NULL, 10); gFirstSim.set(sim_ip_str, sim_port); if (gFirstSim.isOk()) { gMessageSystem->enableCircuit(gFirstSim, true); } } std::string region_x_str = response["region_x"]; std::string region_y_str = response["region_y"]; if(!region_x_str.empty() && !region_y_str.empty()) { U32 region_x = strtoul(region_x_str.c_str(), NULL, 10); U32 region_y = strtoul(region_y_str.c_str(), NULL, 10); gFirstSimHandle = to_region_handle(region_x, region_y); } // Aurora Sim text = response["region_size_x"].asString(); if (!text.empty()) { first_sim_size_x = strtoul(text.c_str(), NULL, 10); LLViewerParcelMgr::getInstance()->init((F32)first_sim_size_x); } //region Y size is currently unused, major refactoring required. - Patrick Sapinski (2/10/2011) text = response["region_size_y"].asString(); if(!text.empty()) first_sim_size_y = strtoul(text.c_str(), NULL, 10); // Aurora Sim const std::string look_at_str = response["look_at"]; if (!look_at_str.empty()) { size_t len = look_at_str.size(); LLMemoryStream mstr((U8*)look_at_str.c_str(), static_cast(len)); LLSD sd = LLSDSerialize::fromNotation(mstr, len); gAgentStartLookAt = ll_vector3_from_sd(sd); } text = response["seed_capability"].asString(); if (!text.empty()) gFirstSimSeedCap = text; text = response["seconds_since_epoch"].asString(); if(!text.empty()) { U32 server_utc_time = strtoul(text.c_str(), NULL, 10); if(server_utc_time) { time_t now = time(NULL); gUTCOffset = (S32)(server_utc_time - now); // Print server timestamp LLSD substitution; substitution["datetime"] = (S32)server_utc_time; std::string timeStr = "[month, datetime, slt] [day, datetime, slt] [year, datetime, slt] [hour, datetime, slt]:[min, datetime, slt]:[second, datetime, slt]"; LLStringUtil::format(timeStr, substitution); LL_INFOS("AppInit") << "Server SLT timestamp: " << timeStr << ". Server-viewer time offset before correction: " << gUTCOffset << "s" << LL_ENDL; } } // this is the base used to construct help URLs text = response["help_url_format"].asString(); if (!text.empty()) { // replace the default help URL format gSavedSettings.setString("HelpURLFormat",text); } std::string home_location = response["home"]; if(!home_location.empty()) { size_t len = home_location.size(); LLMemoryStream mstr((U8*)home_location.c_str(), static_cast(len)); LLSD sd = LLSDSerialize::fromNotation(mstr, len); S32 region_x = sd["region_handle"][0].asInteger(); S32 region_y = sd["region_handle"][1].asInteger(); U64 region_handle = to_region_handle(region_x, region_y); LLVector3 position = ll_vector3_from_sd(sd["position"]); gAgent.setHomePosRegion(region_handle, position); } // If MOTD has not been set by fsdata, fallback to LL MOTD // FIRE-8571, FIRE-9274 if (gAgent.mMOTD.empty() || !LLGridManager::getInstance()->isInSLMain()) // { gAgent.mMOTD.assign(response["message"]); } // fsdata opensim MOTD support #ifdef OPENSIM if (LLGridManager::getInstance()->isInOpenSim() && !FSData::instance().getOpenSimMOTD().empty()) { gAgent.mMOTD.assign(FSData::instance().getOpenSimMOTD()); } #endif // // Options... // Each 'option' is an array of submaps. // It appears that we only ever use the first element of the array. LLUUID inv_root_folder_id = response["inventory-root"][0]["folder_id"]; if(inv_root_folder_id.notNull()) { gInventory.setRootFolderID(inv_root_folder_id); //gInventory.mock(gAgent.getInventoryRootID()); } LLSD login_flags = response["login-flags"][0]; if(login_flags.size()) { std::string flag = login_flags["ever_logged_in"]; if(!flag.empty()) { gAgent.setFirstLogin(flag == "N"); } /* Flag is currently ignored by the viewer. flag = login_flags["stipend_since_login"]; if(flag == "Y") { stipend_since_login = true; } */ flag = login_flags["gendered"].asString(); if(flag == "Y") { // We don't care about this flag anymore; now base whether // outfit is chosen on COF contents, initial outfit // requested and available, etc. //gAgent.setGenderChosen(true); } bool pacific_daylight_time = false; flag = login_flags["daylight_savings"].asString(); if(flag == "Y") { pacific_daylight_time = (flag == "Y"); } //setup map of datetime strings to codes and slt & local time offset from utc LLStringOps::setupDatetimeInfo(pacific_daylight_time); // [FIRE-34775] Use PST/PDT when logged into OpenSim LLStringOps::setupUsingPacificTime(!LLGridManager::getInstance()->isInSecondLife()); // // [FIRE-36028] Fix OpenSim object permissions LLPermissions::setupIsInOpenSim(!LLGridManager::getInstance()->isInSecondLife()); // } // set up the voice configuration. Ultimately, we should pass this up as part of each voice // channel if we need to move to multiple voice servers per grid. LLSD voice_config_info = response["voice-config"]; if(voice_config_info.has("VoiceServerType")) { gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString()); } // Request the map server url std::string map_server_url = response["map-server-url"]; if(!map_server_url.empty()) { // We got an answer from the grid -> use that for map for the current session gSavedSettings.setString("CurrentMapServerURL", map_server_url); LL_INFOS("LLStartUp") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL; } else { // No answer from the grid -> use the default setting for current session map_server_url = gSavedSettings.getString("MapServerURL"); gSavedSettings.setString("CurrentMapServerURL", map_server_url); LL_INFOS("LLStartUp") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL; } // FIRE-8063: Read Aurora web profile url from login data #ifdef OPENSIM std::string web_profile_url = response["web_profile_url"]; if (!web_profile_url.empty()) { // We got an answer from the grid -> use that for map for the current session LLGridManager::instance().setWebProfileUrl(web_profile_url); LL_INFOS("LLStartup") << "web-profile-url : we got an answer from the grid : " << web_profile_url << LL_ENDL; } // FIRE-10567 - Set classified fee, if it's available. if (response.has("classified_fee")) { S32 classified_fee = response["classified_fee"]; LLGridManager::getInstance()->setClassifiedFee(classified_fee); } else { LLGridManager::getInstance()->setClassifiedFee(0); // Free is a sensible default } // Set a parcel listing fee, if it's available if (response.has("directory_fee")) { S32 directory_fee = response["directory_fee"]; LLGridManager::getInstance()->setDirectoryFee(directory_fee); } else { LLGridManager::getInstance()->setDirectoryFee(0); } #endif // OPENSIM // // Default male and female avatars allowing the user to choose their avatar on first login. // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard // "new ruth." Not to be confused with 'initial-outfit' below LLSD newuser_config = response["newuser-config"][0]; if(newuser_config.has("DefaultFemaleAvatar")) { gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString()); } if(newuser_config.has("DefaultMaleAvatar")) { gSavedSettings.setString("DefaultMaleAvatar", newuser_config["DefaultMaleAvatar"].asString()); } // Initial outfit for the user. LLSD initial_outfit = response["initial-outfit"][0]; if(initial_outfit.size()) { std::string flag = initial_outfit["folder_name"]; if(!flag.empty()) { // Initial outfit is a folder in your inventory, // must be an exact folder-name match. sInitialOutfit = flag; } flag = initial_outfit["gender"].asString(); if(!flag.empty()) { sInitialOutfitGender = flag; } } std::string fake_initial_outfit_name = gSavedSettings.getString("FakeInitialOutfitName"); if (!fake_initial_outfit_name.empty()) { gAgent.setFirstLogin(true); sInitialOutfit = fake_initial_outfit_name; if (sInitialOutfitGender.empty()) { sInitialOutfitGender = "female"; // just guess, will get overridden when outfit is worn anyway. } LL_WARNS() << "Faking first-time login with initial outfit " << sInitialOutfit << LL_ENDL; } // set the location of the Agent Appearance service, from which we can request // avatar baked textures if they are supported by the current region std::string agent_appearance_url = response["agent_appearance_service"]; if (!agent_appearance_url.empty()) { LLAppearanceMgr::instance().setAppearanceServiceURL(agent_appearance_url); } // Set the location of the snapshot sharing config endpoint // Debug setting doesn't exist anymore as of 14-09-2014 //std::string snapshot_config_url = response["snapshot_config_url"]; //if(!snapshot_config_url.empty()) //{ // gSavedSettings.setString("SnapshotConfigURL", snapshot_config_url); //} // // Start the process of fetching the OpenID session cookie for this user login std::string openid_url = response["openid_url"]; if(!openid_url.empty()) { std::string openid_token = response["openid_token"]; LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token); } LLLoginInstance::getInstance()->saveMFAHash(response); // OpenSim legacy economy support #ifdef OPENSIM if (!LLGridManager::instance().isInSecondLife()) { if (response.has("max-agent-groups") || response.has("max_groups")) { std::string max_agent_groups; response.has("max_groups") ? max_agent_groups = response["max_groups"].asString() : max_agent_groups = response["max-agent-groups"].asString(); gMaxAgentGroups = atoi(max_agent_groups.c_str()); LL_INFOS("LLStartup") << "gMaxAgentGroups read from login.cgi: " << gMaxAgentGroups << LL_ENDL; } else { gMaxAgentGroups = 0; LL_INFOS("LLStartup") << "did not receive max-agent-groups. unlimited groups activated" << LL_ENDL; } } #endif // // std::string prev_currency_symbol = Tea::getCurrency(); // // std::string currency = "L$"; #ifdef OPENSIM // if(response.has("currency")) { currency = response["currency"].asString(); LL_DEBUGS("OS_SETTINGS") << "currency " << currency << LL_ENDL; } else if (LLGridManager::getInstance()->isInOpenSim()) { currency = "OS$"; LL_DEBUGS("OS_SETTINGS") << "no currency in login response" << LL_ENDL; } Tea::setCurrency(currency); // // // Blank out the region currency which is set in in lfsimfeatureshandler Tea::setRegionCurrency(LLStringUtil::null); std::string new_currency_symbol = Tea::getCurrency(); // If currency symbol has changed, update currency symbols where manually necessary. if (new_currency_symbol != prev_currency_symbol) { LFSimFeatureHandler::updateCurrencySymbols(); } // // if(response.has("avatar_picker_url")) { LL_DEBUGS("OS_SETTINGS") << "avatar_picker_url " << response["avatar_picker_url"] << LL_ENDL; } else if (LLGridManager::getInstance()->isInOpenSim()) { LL_DEBUGS("OS_SETTINGS") << "no avatar_picker_url in login response" << LL_ENDL; } if(response.has("destination_guide_url")) { LL_DEBUGS("OS_SETTINGS") << "destination_guide_url " << response["destination_guide_url"] << LL_ENDL; } else if (LLGridManager::getInstance()->isInOpenSim()) { LL_DEBUGS("OS_SETTINGS") << "no destination_guide_url in login response" << LL_ENDL; } // // Legacy search killswitch! if (LLGridManager::getInstance()->isInOpenSim()) { LLFloaterReg::add("search", "floater_fs_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); } else #endif // OPENSIM { if (FSData::instance().enableLegacySearch()) { LLFloaterReg::add("search", "floater_fs_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); } else { LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); } } // // fsdata support if (FSData::instance().isAgentFlag(gAgentID, FSData::NO_USE)) { gAgentID.setNull(); } // bool success = false; // JC: gesture loading done below, when we have an asset system // in place. Don't delete/clear gUserCredentials until then. if(gAgentID.notNull() && gAgentSessionID.notNull() && gMessageSystem->mOurCircuitCode && gFirstSim.isOk() && gInventory.getRootFolderID().notNull()) { success = true; } LLAppViewer* pApp = LLAppViewer::instance(); pApp->writeDebugInfo(); //Write our static data now that we have username, session_id, etc. return success; } void transition_back_to_login_panel(const std::string& emsg) { // Bounce back to the login screen. reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW ); gSavedSettings.setBOOL("AutoLogin", false); } // FIRE-18250: Option to disable default eye movement //static void update_static_eyes() { if (gSavedPerAccountSettings.getBOOL("FSStaticEyes")) { LLUUID anim_id(gSavedSettings.getString("FSStaticEyesUUID")); gAgent.sendAnimationRequest(anim_id, ANIM_REQUEST_START); } } //