Update old style callbacks for chatFromLogFile functions to lambdas Keep track of people's log's name using their IDs, but don't rename. Fallback on ID if name is empty (if the grid is a meanie) Also track group names this way, sometimes those change. Prefer std::array, since we're in the area.
4347 lines
137 KiB
C++
4347 lines
137 KiB
C++
/**
|
|
* @file llstartup.cpp
|
|
* @brief startup routines.
|
|
*
|
|
* $LicenseInfo:firstyear=2004&license=viewergpl$
|
|
*
|
|
* Copyright (c) 2004-2009, Linden Research, Inc.
|
|
*
|
|
* Second Life Viewer Source Code
|
|
* The source code in this file ("Source Code") is provided by Linden Lab
|
|
* to you under the terms of the GNU General Public License, version 2.0
|
|
* ("GPL"), unless you have obtained a separate licensing agreement
|
|
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
|
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
|
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
|
*
|
|
* There are special exceptions to the terms and conditions of the GPL as
|
|
* it is applied to this Source Code. View the full text of the exception
|
|
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
|
* online at
|
|
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
|
*
|
|
* By copying, modifying or distributing this software, you acknowledge
|
|
* that you have read and understood your obligations described above,
|
|
* and agree to abide by those obligations.
|
|
*
|
|
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
|
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
|
* COMPLETENESS OR PERFORMANCE.
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
#include "llstartup.h"
|
|
|
|
#if LL_WINDOWS
|
|
# include <process.h> // _spawnl()
|
|
#else
|
|
# include <sys/stat.h> // mkdir()
|
|
#endif
|
|
|
|
#include "llviewermedia_streamingaudio.h"
|
|
#include "llaudioengine.h"
|
|
|
|
#ifdef LL_FMODSTUDIO
|
|
# include "llaudioengine_fmodstudio.h"
|
|
#endif
|
|
|
|
#ifdef LL_OPENAL
|
|
#include "llaudioengine_openal.h"
|
|
#endif
|
|
|
|
#include "aosystem.h"
|
|
#include "hippogridmanager.h"
|
|
#include "hippolimits.h"
|
|
#include "statemachine/aifilepicker.h"
|
|
#include "lfsimfeaturehandler.h"
|
|
|
|
#include "llares.h"
|
|
#include "llavatarnamecache.h"
|
|
#include "llexperiencecache.h"
|
|
#include "lllandmark.h"
|
|
#include "llcachename.h"
|
|
#include "lldir.h"
|
|
#include "llerrorcontrol.h"
|
|
#include "llfiltersd2xmlrpc.h"
|
|
#include "llfocusmgr.h"
|
|
#include "llhttpsender.h"
|
|
#include "llimageworker.h"
|
|
|
|
#include "llloginflags.h"
|
|
#include "llmd5.h"
|
|
#include "llmemorystream.h"
|
|
#include "llmessageconfig.h"
|
|
#include "llmoveview.h"
|
|
#include "llnotifications.h"
|
|
#include "llnotificationsutil.h"
|
|
#include "llregionhandle.h"
|
|
#include "llsd.h"
|
|
#include "llsdserialize.h"
|
|
#include "llsdutil_math.h"
|
|
#include "llsecondlifeurls.h"
|
|
#include "llstring.h"
|
|
#include "lltexteditor.h"
|
|
#include "llurlentry.h"
|
|
#include "lluserrelations.h"
|
|
#include "llversioninfo.h"
|
|
#include "llviewercontrol.h"
|
|
#include "llvfs.h"
|
|
#include "llxorcipher.h" // saved password, MAC address
|
|
#include "imageids.h"
|
|
#include "message.h"
|
|
#include "v3math.h"
|
|
|
|
#include "llagent.h"
|
|
#include "llagentbenefits.h"
|
|
#include "llagentcamera.h"
|
|
#include "llagentwearables.h"
|
|
#include "llagentpilot.h"
|
|
#include "llfloateravatarlist.h"
|
|
#include "llfloateravatarpicker.h"
|
|
#include "llcallbacklist.h"
|
|
#include "llcallingcard.h"
|
|
#include "llcolorscheme.h"
|
|
#include "llconsole.h"
|
|
#include "llcontainerview.h"
|
|
#include "llfloaterstats.h"
|
|
#include "lldebugview.h"
|
|
#include "lldrawable.h"
|
|
#include "lleventnotifier.h"
|
|
#include "llface.h"
|
|
#include "llfeaturemanager.h"
|
|
#include "llfirstuse.h"
|
|
#include "llfloateractivespeakers.h"
|
|
#include "llfloateravatar.h"
|
|
#include "llfloaterbeacons.h"
|
|
#include "llfloatercamera.h"
|
|
#include "llfloaterchat.h"
|
|
#include "llfloaterdestinations.h"
|
|
#include "llfloatergesture.h"
|
|
#include "llfloaterhud.h"
|
|
#include "llfloaterinventory.h"
|
|
#include "llfloaterland.h"
|
|
#include "llfloatertopobjects.h"
|
|
#include "llfloatertos.h"
|
|
#include "llfloaterworldmap.h"
|
|
#include "llframestats.h"
|
|
#include "llframestatview.h"
|
|
#include "llgesturemgr.h"
|
|
#include "llgroupmgr.h"
|
|
#include "llhudeffecttrail.h"
|
|
#include "llhudmanager.h"
|
|
#include "llhttpclient.h"
|
|
#include "llimagebmp.h"
|
|
#include "llimview.h" // for gIMMgr
|
|
#include "llinventoryfunctions.h"
|
|
#include "llinventorymodelbackgroundfetch.h"
|
|
#include "llinventorypanel.h"
|
|
#include "llkeyboard.h"
|
|
#include "llloginhandler.h" // gLoginHandler, SLURL support
|
|
#include "llpanellogin.h"
|
|
#include "llmediafilter.h"
|
|
#include "llmutelist.h"
|
|
#include "llnotify.h"
|
|
#include "llpanelavatar.h"
|
|
#include "llpaneldirbrowser.h"
|
|
#include "llpaneldirland.h"
|
|
#include "llpanelevent.h"
|
|
#include "llpanelclassified.h"
|
|
#include "llpanelpick.h"
|
|
#include "llpanelgrouplandmoney.h"
|
|
#include "llpanelgroupnotices.h"
|
|
#include "llpreview.h"
|
|
#include "llpreviewscript.h"
|
|
#include "llproxy.h"
|
|
#include "llproductinforequest.h"
|
|
#include "llremoteparcelrequest.h"
|
|
#include "llsecondlifeurls.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 "llurldispatcher.h"
|
|
#include "llurlhistory.h"
|
|
#include "llurlwhitelist.h"
|
|
#include "lluserauth.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 "llviewerparcelmedia.h"
|
|
#include "llviewerparcelmgr.h"
|
|
#include "llviewerregion.h"
|
|
#include "llviewerstats.h"
|
|
#include "llviewerthrottle.h"
|
|
#include "llviewerwindow.h"
|
|
#include "llvoavatarself.h"
|
|
#include "llvoclouds.h"
|
|
#include "llweb.h"
|
|
#include "llwind.h"
|
|
#include "llworld.h"
|
|
#include "llworldmap.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 "llnameui.h"
|
|
#include "llwlparammanager.h"
|
|
#include "llwaterparammanager.h"
|
|
#include "llagentlanguage.h"
|
|
#include "llwearable.h"
|
|
#include "llinventorybridge.h"
|
|
#include "llappearancemgr.h"
|
|
#include "llvoicechannel.h"
|
|
#include "jcfloaterareasearch.h"
|
|
#include "generichandlers.h"
|
|
|
|
// <edit>
|
|
#include "floaterlocalassetbrowse.h"
|
|
#include "llpanellogin.h"
|
|
//#include "llfloateravatars.h"
|
|
//#include "llactivation.h"
|
|
#include "wlfPanel_AdvSettings.h" //Lower right Windlight and Rendering options
|
|
#include "lldaycyclemanager.h"
|
|
#include "llfloaterblacklist.h"
|
|
#include "scriptcounter.h"
|
|
#include "shfloatermediaticker.h"
|
|
#include "shupdatechecker.h"
|
|
#include "llpacketring.h"
|
|
// </edit>
|
|
|
|
#include "llpathfindingmanager.h"
|
|
|
|
#include "lgghunspell_wrapper.h"
|
|
|
|
// [RLVa:KB]
|
|
#include "rlvhandler.h"
|
|
// [/RLVa:KB]
|
|
|
|
#include "llevents.h"
|
|
#include "llexperiencelog.h"
|
|
#if LL_WINDOWS
|
|
#include "llwindebug.h"
|
|
#include "lldxhardware.h"
|
|
#endif
|
|
|
|
#include "NACLantispam.h" // for NaCl Antispam Registry
|
|
|
|
//
|
|
// exported globals
|
|
//
|
|
bool gAgentMovementCompleted = false;
|
|
|
|
std::string SCREEN_HOME_FILENAME = "screen_home.bmp";
|
|
std::string SCREEN_LAST_FILENAME = "screen_last.bmp";
|
|
|
|
LLPointer<LLViewerTexture> gStartTexture;
|
|
|
|
//
|
|
// Imported globals
|
|
//
|
|
extern S32 gStartImageWidth;
|
|
extern S32 gStartImageHeight;
|
|
extern std::string gWindowTitle;
|
|
|
|
//
|
|
// local globals
|
|
//
|
|
|
|
static LLHost gAgentSimHost;
|
|
//static BOOL gSkipOptionalUpdate = FALSE;
|
|
|
|
static bool gGotUseCircuitCodeAck = false;
|
|
static std::string sInitialOutfit;
|
|
static std::string sInitialOutfitGender; // "male" or "female"
|
|
static boost::signals2::connection sWearablesLoadedCon;
|
|
|
|
static bool gUseCircuitCallbackCalled = false;
|
|
|
|
EStartupState LLStartUp::gStartupState = STATE_FIRST;
|
|
LLSLURL LLStartUp::sStartSLURL;
|
|
|
|
|
|
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 mBenefitsSuccessfullyInit = false;
|
|
|
|
|
|
boost::scoped_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState"));
|
|
boost::scoped_ptr<LLViewerStats::PhaseMap> LLStartUp::sPhases(new LLViewerStats::PhaseMap);
|
|
|
|
//
|
|
// local function declaration
|
|
//
|
|
|
|
void login_show();
|
|
void show_first_run_dialog();
|
|
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 update_app(BOOL mandatory, const std::string& message);
|
|
bool update_dialog_callback(const LLSD& notification, const LLSD& response);
|
|
void login_packet_failed(void**, S32 result);
|
|
void use_circuit_callback(void**, S32 result);
|
|
void register_viewer_callbacks(LLMessageSystem* msg);
|
|
void init_stat_view();
|
|
void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32);
|
|
bool callback_choose_gender(const LLSD& notification, const LLSD& response);
|
|
void init_start_screen(S32 location_id);
|
|
void release_start_screen();
|
|
void reset_login();
|
|
void apply_udp_blacklist(const std::string& csv);
|
|
// <FS:CR> Aurora Sim
|
|
//bool process_login_success_response(std::string& password);
|
|
bool process_login_success_response(std::string& password, U32& first_sim_size_x, U32& first_sim_size_y);
|
|
// </FS:CR> Aurora Sim
|
|
void on_benefits_failed_callback(const LLSD& notification, const LLSD& response);
|
|
void transition_back_to_login_panel(const std::string& emsg);
|
|
|
|
void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is_group)
|
|
{
|
|
LLNameUI::refreshAll(id, full_name);
|
|
|
|
// TODO: Actually be intelligent about the refresh.
|
|
// For now, just brute force refresh the dialogs.
|
|
dialog_refresh_all();
|
|
}
|
|
|
|
void simfeature_debug_update(const std::string& val, const std::string& setting)
|
|
{
|
|
//if (!val.empty()) // Singu Note: Should we only update the setting if not empty?
|
|
gSavedSettings.setString(setting, val);
|
|
}
|
|
|
|
//
|
|
// exported functionality
|
|
//
|
|
|
|
//
|
|
// local classes
|
|
//
|
|
|
|
namespace
|
|
{
|
|
class LLNullHTTPSender : public LLHTTPSender
|
|
{
|
|
virtual void send(const LLHost& host,
|
|
const std::string& message, const LLSD& body,
|
|
LLHTTPClient::ResponderPtr response) const
|
|
{
|
|
LL_WARNS("AppInit") << " attemped to send " << message << " to " << host
|
|
<< " with null sender" << LL_ENDL;
|
|
}
|
|
};
|
|
}
|
|
|
|
class LLGestureInventoryFetchObserver : public LLInventoryFetchItemsObserver
|
|
{
|
|
public:
|
|
LLGestureInventoryFetchObserver(const uuid_vec_t& item_ids) : LLInventoryFetchItemsObserver(item_ids) {}
|
|
virtual void done()
|
|
{
|
|
// we've downloaded all the items, so repaint the dialog
|
|
LLFloaterGesture::refreshAll();
|
|
|
|
gInventory.removeObserver(this);
|
|
delete this;
|
|
}
|
|
};
|
|
|
|
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);
|
|
}
|
|
|
|
void set_flags_and_update_appearance()
|
|
{
|
|
LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
|
|
LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op);
|
|
}
|
|
|
|
|
|
void hooked_process_sound_trigger(LLMessageSystem *msg, void **)
|
|
{
|
|
process_sound_trigger(msg,NULL);
|
|
LLFloaterAvatarList::sound_trigger_hook(msg,NULL);
|
|
}
|
|
|
|
void convert_legacy_settings()
|
|
{
|
|
// Convert legacy settings to new ones here.
|
|
if (!gSavedPerAccountSettings.getBOOL("DefaultUploadPermissionsConverted"))
|
|
{
|
|
gSavedSettings.setBOOL("UploadsEveryoneCopy", gSavedSettings.getBOOL("EveryoneCopy"));
|
|
bool val = gSavedPerAccountSettings.getBOOL("EveryoneExport");
|
|
gSavedPerAccountSettings.setBOOL("UploadsEveryoneExport", val);
|
|
gSavedPerAccountSettings.setBOOL("ObjectsEveryoneExport", val);
|
|
val = gSavedSettings.getBOOL("NextOwnerCopy");
|
|
gSavedSettings.setBOOL("UploadsNextOwnerCopy", val);
|
|
gSavedSettings.setBOOL("ObjectsNextOwnerCopy", val);
|
|
val = gSavedSettings.getBOOL("NextOwnerModify");
|
|
gSavedSettings.setBOOL("UploadsNextOwnerModify", val);
|
|
gSavedSettings.setBOOL("ObjectsNextOwnerModify", val);
|
|
val = gSavedSettings.getBOOL("NextOwnerTransfer");
|
|
gSavedSettings.setBOOL("UploadsNextOwnerTransfer", val);
|
|
gSavedSettings.setBOOL("ObjectsNextOwnerTransfer", val);
|
|
val = gSavedSettings.getBOOL("NextOwnerTransfer");
|
|
gSavedSettings.setBOOL("UploadsShareWithGroup", gSavedSettings.getBOOL("ShareWithGroup"));
|
|
gSavedPerAccountSettings.setBOOL("DefaultUploadPermissionsConverted", true);
|
|
}
|
|
}
|
|
|
|
void init_audio()
|
|
{
|
|
if (FALSE == gSavedSettings.getBOOL("NoAudio"))
|
|
{
|
|
gAudiop = NULL;
|
|
|
|
#ifdef LL_FMODSTUDIO
|
|
if (!gAudiop
|
|
#if !LL_WINDOWS
|
|
&& NULL == getenv("LL_BAD_FMODSTUDIO_DRIVER")
|
|
#endif // !LL_WINDOWS
|
|
)
|
|
{
|
|
gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODSTUDIO(gSavedSettings.getBOOL("SHEnableFMODExProfiler"), gSavedSettings.getBOOL("SHEnableFMODEXVerboseDebugging"));
|
|
}
|
|
#endif
|
|
|
|
#ifdef LL_OPENAL
|
|
if (!gAudiop
|
|
#if !LL_WINDOWS
|
|
&& NULL == getenv("LL_BAD_OPENAL_DRIVER")
|
|
#endif // !LL_WINDOWS
|
|
)
|
|
{
|
|
gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL();
|
|
}
|
|
#endif
|
|
|
|
if (gAudiop)
|
|
{
|
|
#if LL_WINDOWS
|
|
// FMOD 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
|
|
bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle);
|
|
if(init)
|
|
{
|
|
gAudiop->setMuted(TRUE);
|
|
if(gSavedSettings.getBOOL("AllowLargeSounds"))
|
|
gAudiop->setAllowLargeSounds(true);
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL;
|
|
delete gAudiop;
|
|
gAudiop = NULL;
|
|
}
|
|
|
|
if (gAudiop)
|
|
{
|
|
// 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());
|
|
}
|
|
// Unmute audio if desired and setup volumes.
|
|
// This is a not-uncommon crash site, so surround it with
|
|
// llinfos output to aid diagnosis.
|
|
LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL;
|
|
audio_update_volume(false);
|
|
LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL;
|
|
}
|
|
}
|
|
}
|
|
LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL;
|
|
}
|
|
|
|
// Returns false to skip other idle processing. Should only return
|
|
// true when all initialization done.
|
|
bool idle_startup()
|
|
{
|
|
const F32 PRECACHING_DELAY = gSavedSettings.getF32("PrecachingDelay");
|
|
const F32 TIMEOUT_SECONDS = 5.f;
|
|
const S32 MAX_TIMEOUT_COUNT = 3;
|
|
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_method;
|
|
static std::string auth_desc;
|
|
static std::string auth_message;
|
|
static std::string firstname;
|
|
static std::string lastname;
|
|
static LLUUID web_login_key;
|
|
static std::string password;
|
|
static std::vector<const char*> requested_options;
|
|
static std::string redirect_uri;
|
|
|
|
// <FS:CR> Aurora Sim
|
|
static U32 first_sim_size_x = 256;
|
|
static U32 first_sim_size_y = 256;
|
|
// </FS:CR> Aurora Sim
|
|
static LLVector3 initial_sun_direction(1.f, 0.f, 0.f);
|
|
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;
|
|
|
|
// 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();
|
|
|
|
if (gNoRender)
|
|
{
|
|
// HACK, skip optional updates if you're running drones
|
|
//gSkipOptionalUpdate = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Update images?
|
|
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);
|
|
|
|
/////////////////////////////////////////////////
|
|
//
|
|
// Initialize stuff that doesn't need data from simulators
|
|
//
|
|
glggHunSpell->initSettings();
|
|
|
|
// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-10 (RLVa-1.0.0g) | Modified: RLVa-0.2.1d
|
|
if ( (gSavedSettings.controlExists(RLV_SETTING_MAIN)) && (gSavedSettings.getBOOL(RLV_SETTING_MAIN)) )
|
|
rlv_handler_t::setEnabled(TRUE);
|
|
// [/RLVa:KB]
|
|
|
|
if (LLFeatureManager::getInstance()->isSafe())
|
|
{
|
|
LLNotificationsUtil::add("DisplaySetToSafe");
|
|
}
|
|
else if ((gSavedSettings.getS32("LastFeatureVersion") < LLFeatureManager::getInstance()->getVersion()) &&
|
|
(gSavedSettings.getS32("LastFeatureVersion") != 0))
|
|
{
|
|
LLNotificationsUtil::add("DisplaySetToRecommended");
|
|
}
|
|
else if (!gViewerWindow->getInitAlert().empty())
|
|
{
|
|
LLNotifications::instance().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());
|
|
|
|
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(gSavedSettings.getString("StatsPilotFile"));
|
|
gFrameStats.setFilename(gSavedSettings.getString("StatsFile"));
|
|
gFrameStats.setSummaryFilename(gSavedSettings.getString("StatsSummaryFile"));
|
|
|
|
//gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps"));
|
|
|
|
// Load the throttle settings
|
|
gViewerThrottle.load();
|
|
|
|
if (ll_init_ares() == NULL || !gAres->isInitialized())
|
|
{
|
|
std::string diagnostic = "Could not start address resolution system";
|
|
LL_WARNS("AppInit") << diagnostic << LL_ENDL;
|
|
LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic));
|
|
}
|
|
|
|
//
|
|
// Initialize messaging system
|
|
//
|
|
LL_DEBUGS("AppInit") << "Initializing messaging system..." << LL_ENDL;
|
|
|
|
auto app_settings_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, LLStringUtil::null);
|
|
std::string message_template_path = gDirUtilp->add(app_settings_path, "message_template.msg");
|
|
|
|
LLFILE* found_template = NULL;
|
|
found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */
|
|
|
|
if (!found_template)
|
|
{
|
|
app_settings_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE,
|
|
#if LL_WINDOWS
|
|
// On the windows dev builds, unpackaged, the message_template.msg
|
|
// file will be located in:
|
|
// indra/build-vc**/newview/<config>/app_settings.
|
|
"app_settings"
|
|
#elif LL_DARWIN
|
|
// On Mac dev builds, message_template.msg lives in:
|
|
// indra/build-*/newview/<config>/Second Life/Contents/Resources/app_settings
|
|
"../Resources/app_settings"
|
|
#else // LL_LINUX and other
|
|
// On the linux dev builds, the message_template.msg
|
|
// file will be located in:
|
|
// indra/build-linux**/newview/packaged/app_settings.
|
|
"../app_settings"
|
|
#endif
|
|
, LLStringUtil::null);
|
|
message_template_path = gDirUtilp->add(app_settings_path, "message_template.msg");
|
|
found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */
|
|
}
|
|
|
|
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");
|
|
}
|
|
|
|
LLHTTPSender::setDefaultSender(new LLNullHTTPSender());
|
|
|
|
// 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::getMajor(),
|
|
LLVersionInfo::getMinor(),
|
|
LLVersionInfo::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));
|
|
}
|
|
|
|
// Take into account dev checkout status on all platforms, by using app_settings_path ~Liru
|
|
LLMessageConfig::initClass("viewer", app_settings_path);
|
|
|
|
}
|
|
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(gVFS);
|
|
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, gVFS, gStaticVFS);
|
|
|
|
|
|
F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage");
|
|
msg->mPacketRing->setDropPercentage(dropPercent);
|
|
|
|
F32 inBandwidth = gSavedSettings.getF32("InBandwidth");
|
|
F32 outBandwidth = gSavedSettings.getF32("OutBandwidth");
|
|
if (inBandwidth != 0.f)
|
|
{
|
|
LL_DEBUGS("AppInit") << "Setting packetring incoming bandwidth to " << inBandwidth << LL_ENDL;
|
|
msg->mPacketRing->setUseInThrottle(TRUE);
|
|
msg->mPacketRing->setInBandwidth(inBandwidth);
|
|
}
|
|
if (outBandwidth != 0.f)
|
|
{
|
|
LL_DEBUGS("AppInit") << "Setting packetring outgoing bandwidth to " << outBandwidth << LL_ENDL;
|
|
msg->mPacketRing->setUseOutThrottle(TRUE);
|
|
msg->mPacketRing->setOutBandwidth(outBandwidth);
|
|
}
|
|
}
|
|
|
|
LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL;
|
|
|
|
//-------------------------------------------------
|
|
// Load file- and dirpicker {context, default path} map.
|
|
//-------------------------------------------------
|
|
|
|
AIFilePicker::loadFile("filepicker_contexts.xml");
|
|
|
|
if (LLTimer::knownBadTimer())
|
|
{
|
|
LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL;
|
|
}
|
|
|
|
//
|
|
// Log on to system
|
|
//
|
|
/*if (!LLStartUp::sSLURLCommand.empty())
|
|
{
|
|
// this might be a secondlife:///app/login URL
|
|
gLoginHandler.parseDirectLogin(LLStartUp::sSLURLCommand);
|
|
}*/
|
|
if (!gLoginHandler.getFirstName().empty()
|
|
|| !gLoginHandler.getLastName().empty()
|
|
|| !gLoginHandler.getWebLoginKey().isNull() )
|
|
{
|
|
// We have at least some login information on a SLURL
|
|
firstname = gLoginHandler.getFirstName();
|
|
lastname = gLoginHandler.getLastName();
|
|
web_login_key = gLoginHandler.getWebLoginKey();
|
|
|
|
// Show the login screen if we don't have everything
|
|
show_connect_box =
|
|
firstname.empty() || lastname.empty() || web_login_key.isNull();
|
|
}
|
|
else if(gSavedSettings.getLLSD("UserLoginInfo").size() == 3)
|
|
{
|
|
LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo");
|
|
firstname = cmd_line_login[0].asString();
|
|
lastname = cmd_line_login[1].asString();
|
|
|
|
LLMD5 pass((unsigned char*)cmd_line_login[2].asString().c_str());
|
|
char md5pass[33]; /* Flawfinder: ignore */
|
|
pass.hex_digest(md5pass);
|
|
password = md5pass;
|
|
|
|
show_connect_box = false;
|
|
|
|
gSavedSettings.setBOOL("AutoLogin", TRUE);
|
|
}
|
|
else if (gSavedSettings.getBOOL("AutoLogin"))
|
|
{
|
|
firstname = gSavedSettings.getString("FirstName");
|
|
lastname = gSavedSettings.getString("LastName");
|
|
password = LLStartUp::loadPasswordFromDisk();
|
|
gSavedSettings.setBOOL("RememberName", true);
|
|
gSavedSettings.setBOOL("RememberPassword", TRUE);
|
|
|
|
show_connect_box = false;
|
|
}
|
|
else
|
|
{
|
|
// if not automatically logging in, display login dialog
|
|
// a valid grid is selected
|
|
firstname = gSavedSettings.getString("FirstName");
|
|
lastname = gSavedSettings.getString("LastName");
|
|
password = LLStartUp::loadPasswordFromDisk();
|
|
show_connect_box = true;
|
|
}
|
|
|
|
|
|
// Go to the next startup state
|
|
LLStartUp::setStartupState( STATE_BROWSER_INIT );
|
|
check_for_updates();
|
|
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);
|
|
display_startup();
|
|
// LLViewerMedia::initBrowser();
|
|
LLStartUp::setStartupState( STATE_LOGIN_SHOW );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (STATE_LOGIN_SHOW == LLStartUp::getStartupState())
|
|
{
|
|
LL_DEBUGS("AppInit") << "Initializing Window" << LL_ENDL;
|
|
|
|
gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
|
|
|
|
// *NOTE: This is where LLViewerParcelMgr::getInstance() used to get allocated before becoming LLViewerParcelMgr::getInstance().
|
|
|
|
// *NOTE: This is where gHUDManager used to bet allocated before becoming LLHUDManager::getInstance().
|
|
|
|
// *NOTE: This is where gMuteList used to get allocated before becoming LLMuteList::getInstance().
|
|
|
|
gGenericHandlers = new GenericHandlers();
|
|
|
|
// Initialize UI
|
|
if (!gNoRender)
|
|
{
|
|
// 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.
|
|
display_startup();
|
|
LLToolMgr::getInstance()->initTools();
|
|
|
|
display_startup();
|
|
// Load local textures now, maybe someone wants to use them in UI (why?)
|
|
LocalAssetBrowser::instance(); // <edit/>
|
|
// Quickly get something onscreen to look at.
|
|
gViewerWindow->initWorldUI();
|
|
display_startup();
|
|
}
|
|
|
|
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.
|
|
// LLPanelLogin::getFields(firstname, lastname, password);
|
|
|
|
if (gNoRender)
|
|
{
|
|
LL_ERRS("AppInit") << "Need to autologin or use command line with norender!" << LL_ENDL;
|
|
}
|
|
// Make sure the process dialog doesn't hide things
|
|
display_startup();
|
|
gViewerWindow->setShowProgress(FALSE);
|
|
display_startup();
|
|
|
|
// Show the login dialog.
|
|
login_show();
|
|
display_startup();
|
|
static bool sSetFields(LLPanelLogin::getLoginHistory().size() > 0); // If there were no entries to be loaded, use what's available
|
|
if (!sSetFields)
|
|
{
|
|
LLPanelLogin::setFields(firstname, lastname, password);
|
|
sSetFields = true; // Never reset the fields again!
|
|
display_startup();
|
|
LLPanelLogin::giveFocus();
|
|
}
|
|
|
|
gSavedSettings.setBOOL("FirstRunThisInstall", FALSE);
|
|
|
|
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 );
|
|
}
|
|
|
|
display_startup();
|
|
gViewerWindow->setNormalControlsVisible( FALSE );
|
|
display_startup();
|
|
gLoginMenuBarView->setVisible( TRUE );
|
|
display_startup();
|
|
gLoginMenuBarView->setEnabled( TRUE );
|
|
display_startup();
|
|
|
|
// Push our window frontmost
|
|
// Singu Note: Actually, don't! But flash the window to let the user know
|
|
auto& window(*gViewerWindow->getWindow());
|
|
window.show(false);
|
|
if (gSavedSettings.getBOOL("LiruFlashWhenMinimized")) // No, we're not minimized, but if you flash my bar, I will give you the biggest SIGSEGV ~Liru <3
|
|
window.flashIcon(5.f);
|
|
display_startup();
|
|
|
|
// DEV-16927. The following code removes errant keystrokes that happen while the window is being
|
|
// first made visible.
|
|
#ifdef _WIN32
|
|
MSG msg;
|
|
while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) )
|
|
{
|
|
display_startup();
|
|
}
|
|
#endif
|
|
timeout.reset();
|
|
return FALSE;
|
|
}
|
|
|
|
if (STATE_LOGIN_WAIT == LLStartUp::getStartupState())
|
|
{
|
|
// Don't do anything. Wait for the login view to call the login_callback,
|
|
// which will push us to the next state.
|
|
display_startup();
|
|
// Sleep so we don't spin the CPU
|
|
ms_sleep(1);
|
|
return FALSE;
|
|
}
|
|
|
|
if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState())
|
|
{
|
|
// 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;
|
|
}
|
|
|
|
//reset the values that could have come in from a slurl
|
|
if (!gLoginHandler.getWebLoginKey().isNull())
|
|
{
|
|
firstname = gLoginHandler.getFirstName();
|
|
lastname = gLoginHandler.getLastName();
|
|
web_login_key = gLoginHandler.getWebLoginKey();
|
|
}
|
|
|
|
if (show_connect_box)
|
|
{
|
|
// TODO if not use viewer auth
|
|
// Load all the name information out of the login view
|
|
LLPanelLogin::getFields(firstname, lastname, password);
|
|
// end TODO
|
|
|
|
// HACK: Try to make not jump on login
|
|
gKeyboard->resetKeys();
|
|
}
|
|
|
|
if (!firstname.empty() && !lastname.empty())
|
|
{
|
|
gSavedSettings.setString("FirstName", firstname);
|
|
gSavedSettings.setString("LastName", lastname);
|
|
|
|
LL_INFOS("AppInit") << "Attempting login as: " << firstname << " " << lastname << LL_ENDL;
|
|
gDebugInfo["LoginName"] = firstname + " " + lastname;
|
|
}
|
|
else
|
|
{
|
|
// User tried to login on a non-SecondLife grid with an empty lastname.
|
|
LLSD subs;
|
|
subs["GRIDNAME"] = gHippoGridManager->getConnectedGrid()->getGridName();
|
|
LLNotificationsUtil::add(firstname.empty() ? "EmptyFirstNameMessage" : "EmptyLastNameMessage", subs);
|
|
LLStartUp::setStartupState(STATE_LOGIN_SHOW);
|
|
return FALSE;
|
|
}
|
|
|
|
LLScriptEdCore::parseFunctions("lsl_functions_sl.xml"); //Singu Note: This parsing function essentially replaces the entirety of the lscript_library library
|
|
|
|
gHippoGridManager->setCurrentGridAsConnected();
|
|
gHippoLimits->setLimits();
|
|
if(!gHippoGridManager->getConnectedGrid()->isSecondLife())
|
|
{
|
|
LLTrans::setDefaultArg("[CURRENCY]",gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); //replace [CURRENCY] with OS$, not L$ for instance.
|
|
LLTrans::setDefaultArg("[CURRENCY_TEXT]",gHippoGridManager->getConnectedGrid()->getCurrencyText()); //replace [CURRENCYTEXT] with OS DOllars, not Linden Dollars for instance.
|
|
LLTrans::setDefaultArg("[SECOND_LIFE]", gHippoGridManager->getConnectedGrid()->getGridName());
|
|
LLTrans::setDefaultArg("[SECOND_LIFE_GRID]", gHippoGridManager->getConnectedGrid()->getGridName() + " Grid");
|
|
LLTrans::setDefaultArg("[GRID_OWNER]", gHippoGridManager->getConnectedGrid()->getGridOwner());
|
|
LLScriptEdCore::parseFunctions("lsl_functions_os.xml"); //Singu Note: This appends to the base functions parsed from lsl_functions_sl.xml
|
|
}
|
|
// Avination doesn't want the viewer to do bandwidth throttling (it is done serverside, taking UDP into account too).
|
|
AIPerService::setNoHTTPBandwidthThrottling(gHippoGridManager->getConnectedGrid()->isAvination());
|
|
|
|
// create necessary directories
|
|
// *FIX: these mkdir's should error check
|
|
if (gHippoGridManager->getCurrentGrid()->isSecondLife())
|
|
{
|
|
gDirUtilp->setLindenUserDir(LLStringUtil::null, firstname, lastname);
|
|
}
|
|
else
|
|
{
|
|
gDirUtilp->setLindenUserDir(gHippoGridManager->getConnectedGrid()->getGridNick(), firstname, lastname);
|
|
}
|
|
LLFile::mkdir(gDirUtilp->getLindenUserDir());
|
|
|
|
// Set PerAccountSettingsFile to the default value.
|
|
gSavedSettings.setString("PerAccountSettingsFile",
|
|
gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,
|
|
LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount")));
|
|
|
|
// Note: can't store warnings files per account because some come up before login
|
|
|
|
// Overwrite default user settings with user settings
|
|
LLAppViewer::instance()->loadSettingsFromDirectory(AIReadAccess<settings_map_type>(gSettings), "Account");
|
|
|
|
// 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", time_corrected());
|
|
}
|
|
|
|
convert_legacy_settings();
|
|
|
|
//Default the path if one isn't set.
|
|
if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty())
|
|
{
|
|
const std::string dir = gSavedSettings.getString("InstantMessageLogPathAnyAccount");
|
|
gDirUtilp->setChatLogsDir(dir.empty() ? gDirUtilp->getOSUserAppDir() : dir);
|
|
gSavedPerAccountSettings.setString("InstantMessageLogPath",gDirUtilp->getChatLogsDir());
|
|
}
|
|
else
|
|
{
|
|
gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath"));
|
|
}
|
|
|
|
//Get these logs out of my newview root directory, PLEASE.
|
|
gDirUtilp->setPerAccountChatLogsDir(gHippoGridManager->getCurrentGrid()->isSecondLife() ? LLStringUtil::null : gHippoGridManager->getConnectedGrid()->getGridNick(),
|
|
gSavedSettings.getString("FirstName"), gSavedSettings.getString("LastName"));
|
|
LLFile::mkdir(gDirUtilp->getChatLogsDir());
|
|
LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir());
|
|
|
|
NACLAntiSpamRegistry::startup(); // NaCl - Antispam
|
|
|
|
//good a place as any to create user windlight directories
|
|
std::string user_windlight_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight", ""));
|
|
LLFile::mkdir(user_windlight_path_name.c_str());
|
|
|
|
std::string user_windlight_skies_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", ""));
|
|
LLFile::mkdir(user_windlight_skies_path_name.c_str());
|
|
|
|
std::string user_windlight_water_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", ""));
|
|
LLFile::mkdir(user_windlight_water_path_name.c_str());
|
|
|
|
std::string user_windlight_days_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/days", ""));
|
|
LLFile::mkdir(user_windlight_days_path_name.c_str());
|
|
|
|
// <edit>
|
|
LLFloaterBlacklist::loadFromSave();
|
|
// </edit>
|
|
|
|
if (show_connect_box)
|
|
{
|
|
/*std::string location;
|
|
LLPanelLogin::getLocation( location );
|
|
LLURLSimString::setString( location );
|
|
*/
|
|
// END TODO
|
|
//LLPanelLogin::close();
|
|
}
|
|
|
|
// Load URL History File
|
|
LLURLHistory::loadFile("url_history.xml");
|
|
|
|
//-------------------------------------------------
|
|
// 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: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.1d
|
|
#ifndef RLV_EXTENSION_STARTLOCATION
|
|
if (rlv_handler_t::isEnabled())
|
|
#else
|
|
if ( (rlv_handler_t::isEnabled()) && (RlvSettings::getLoginLastLocation()) )
|
|
#endif // RLV_EXTENSION_STARTLOCATION
|
|
{
|
|
// 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);
|
|
|
|
if (!gNoRender)
|
|
{
|
|
init_start_screen(agent_location_id);
|
|
}
|
|
|
|
// Display the startup progress bar.
|
|
gViewerWindow->setShowProgress(!gSavedSettings.getBOOL("AscentDisableLogoutScreens"));
|
|
gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit"));
|
|
|
|
gViewerWindow->revealIntroPanel();
|
|
// Poke the VFS, which could potentially block for a while if
|
|
// Windows XP is acting up
|
|
set_startup_status(0.07f, LLTrans::getString("LoginVerifyingCache"), LLStringUtil::null);
|
|
display_startup();
|
|
|
|
gVFS->pokeFiles();
|
|
|
|
// color init must be after saved settings loaded
|
|
init_colors();
|
|
|
|
if (gSavedSettings.getBOOL("VivoxLicenseAccepted"))
|
|
{
|
|
// skipping over STATE_LOGIN_VOICE_LICENSE since we don't need it
|
|
// skipping over STATE_UPDATE_CHECK because that just waits for input
|
|
LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT );
|
|
}
|
|
else
|
|
{
|
|
LLStartUp::setStartupState(STATE_LOGIN_VOICE_LICENSE);
|
|
LLFirstUse::voiceLicenseAgreement();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (STATE_LOGIN_VOICE_LICENSE == LLStartUp::getStartupState())
|
|
{
|
|
LL_DEBUGS("AppInitStartupState") << "STATE_LOGIN_VOICE_LICENSE" << LL_ENDL;
|
|
// prompt the user to agree to the voice license before enabling voice.
|
|
// only send users here on first login, otherwise continue
|
|
// on to STATE_LOGIN_AUTH_INIT
|
|
return FALSE;
|
|
}
|
|
|
|
if (STATE_UPDATE_CHECK == LLStartUp::getStartupState())
|
|
{
|
|
// wait for user to give input via dialog box
|
|
return FALSE;
|
|
}
|
|
|
|
if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState())
|
|
{
|
|
//#define LL_MINIMIAL_REQUESTED_OPTIONS
|
|
gDebugInfo["GridName"] = LLViewerLogin::getInstance()->getGridLabel();
|
|
|
|
// *Note: this is where gUserAuth used to be created.
|
|
requested_options.clear();
|
|
requested_options.push_back("inventory-root");
|
|
requested_options.push_back("inventory-skeleton");
|
|
//requested_options.push_back("inventory-meat");
|
|
//requested_options.push_back("inventory-skel-targets");
|
|
#if (!defined LL_MINIMIAL_REQUESTED_OPTIONS)
|
|
if(FALSE == gSavedSettings.getBOOL("NoInventoryLibrary"))
|
|
{
|
|
requested_options.push_back("inventory-lib-root");
|
|
requested_options.push_back("inventory-lib-owner");
|
|
requested_options.push_back("inventory-skel-lib");
|
|
// requested_options.push_back("inventory-meat-lib");
|
|
}
|
|
|
|
requested_options.push_back("initial-outfit");
|
|
requested_options.push_back("gestures");
|
|
requested_options.push_back("event_categories");
|
|
requested_options.push_back("event_notifications");
|
|
requested_options.push_back("classified_categories");
|
|
requested_options.push_back("adult_compliant");
|
|
//requested_options.push_back("inventory-targets");
|
|
requested_options.push_back("buddy-list");
|
|
requested_options.push_back("ui-config");
|
|
#endif
|
|
requested_options.push_back("max_groups");
|
|
requested_options.push_back("max-agent-groups");
|
|
requested_options.push_back("map-server-url");
|
|
requested_options.push_back("tutorial_setting");
|
|
requested_options.push_back("login-flags");
|
|
requested_options.push_back("global-textures");
|
|
// <singu> Opensim requested options
|
|
requested_options.push_back("avatar_picker_url");
|
|
requested_options.push_back("destination_guide_url");
|
|
// </singu>
|
|
if(gSavedSettings.getBOOL("ConnectAsGod"))
|
|
{
|
|
gSavedSettings.setBOOL("UseDebugMenus", TRUE);
|
|
requested_options.push_back("god-connect");
|
|
}
|
|
auth_method = "login_to_simulator";
|
|
|
|
auth_desc = LLTrans::getString("LoginInProgress");
|
|
set_startup_status(progress, auth_desc, auth_message);
|
|
LLStartUp::setStartupState( STATE_XMLRPC_LEGACY_LOGIN ); // XMLRPC
|
|
}
|
|
|
|
if (STATE_XMLRPC_LEGACY_LOGIN == LLStartUp::getStartupState())
|
|
{
|
|
LL_DEBUGS() << "STATE_XMLRPC_LEGACY_LOGIN" << LL_ENDL;
|
|
progress += 0.02f;
|
|
display_startup();
|
|
|
|
LLSLURL start_slurl = LLStartUp::getStartSLURL();
|
|
std::stringstream start;
|
|
LLSLURL::SLURL_TYPE start_slurl_type = start_slurl.getType();
|
|
switch ( start_slurl_type )
|
|
{
|
|
case LLSLURL::LOCATION:
|
|
{
|
|
// a startup URL was specified
|
|
std::stringstream unescaped_start;
|
|
unescaped_start << "uri:"
|
|
<< start_slurl.getRegion() << "&"
|
|
<< start_slurl.getPosition().mV[VX] << "&"
|
|
<< start_slurl.getPosition().mV[VY] << "&"
|
|
<< start_slurl.getPosition().mV[VZ];
|
|
start << xml_escape_string(unescaped_start.str());
|
|
}
|
|
break;
|
|
case LLSLURL::HOME_LOCATION:
|
|
start << "home";
|
|
break;
|
|
case LLSLURL::LAST_LOCATION:
|
|
start << "last";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
char hashed_mac_string[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */
|
|
LLMD5 hashed_mac;
|
|
hashed_mac.update( gMACAddress, MAC_ADDRESS_BYTES );
|
|
hashed_mac.finalize();
|
|
hashed_mac.hex_digest(hashed_mac_string);
|
|
|
|
LLViewerLogin* vl = LLViewerLogin::getInstance();
|
|
std::string grid_uri = vl->getCurrentGridURI();
|
|
if(!redirect_uri.empty())
|
|
grid_uri = redirect_uri;
|
|
//redirect_uri.clear(); //Should this be cleared immediately after consumption? Doing this will break retrying on http error.
|
|
|
|
LL_INFOS() << "Authenticating with " << grid_uri << LL_ENDL;
|
|
|
|
// Always write curl I/O debug info for the login attempt.
|
|
Debug(gCurlIo = dc::curl.is_on() && !dc::curlio.is_on(); if (gCurlIo) dc::curlio.on());
|
|
|
|
// TODO if statement here to use web_login_key
|
|
// OGPX : which routine would this end up in? the LLSD or XMLRPC, or ....?
|
|
LLUserAuth::getInstance()->authenticate(
|
|
grid_uri,
|
|
auth_method,
|
|
firstname,
|
|
lastname,
|
|
password, // web_login_key,
|
|
start.str(),
|
|
//gSkipOptionalUpdate,
|
|
true,
|
|
gAcceptTOS,
|
|
gAcceptCriticalMessage,
|
|
gLastExecEvent,
|
|
requested_options,
|
|
hashed_mac_string,
|
|
LLAppViewer::instance()->getSerialNumber());
|
|
|
|
gAuthString = hashed_mac_string;
|
|
|
|
// reset globals
|
|
gAcceptTOS = FALSE;
|
|
gAcceptCriticalMessage = FALSE;
|
|
/*std::string temp_uri = sAuthUris[sAuthUriNum];
|
|
LLStringUtil::toLower(temp_uri);
|
|
// detect SecondLife and force platform setting
|
|
if (temp_uri.find("aditi") != std::string::npos ||
|
|
temp_uri.find("agni") != std::string::npos ||
|
|
temp_uri.find("://216.82.") != std::string::npos)
|
|
gHippoGridManager->getCurrentGrid()->setPlatform(HippoGridInfo::PLATFORM_SECONDLIFE);
|
|
*/
|
|
LLStartUp::setStartupState( STATE_LOGIN_NO_DATA_YET );
|
|
return FALSE;
|
|
}
|
|
|
|
if(STATE_LOGIN_NO_DATA_YET == LLStartUp::getStartupState())
|
|
{
|
|
LL_DEBUGS("AppInit") << "STATE_LOGIN_NO_DATA_YET" << LL_ENDL;
|
|
// 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);
|
|
// Process messages to keep from dropping circuit.
|
|
LLMessageSystem* msg = gMessageSystem;
|
|
while (msg->checkAllMessages(gFrameCount, gServicePump))
|
|
{
|
|
}
|
|
msg->processAcks();
|
|
LLUserAuth::UserAuthcode error = LLUserAuth::getInstance()->authResponse();
|
|
if(LLUserAuth::E_NO_RESPONSE_YET == error)
|
|
{
|
|
LL_DEBUGS("AppInit") << "waiting..." << LL_ENDL;
|
|
return FALSE;
|
|
}
|
|
LLStartUp::setStartupState( STATE_LOGIN_DOWNLOADING );
|
|
progress += 0.01f;
|
|
set_startup_status(progress, auth_desc, auth_message);
|
|
return FALSE;
|
|
}
|
|
|
|
if(STATE_LOGIN_DOWNLOADING == LLStartUp::getStartupState())
|
|
{
|
|
LL_DEBUGS("AppInit") << "STATE_LOGIN_DOWNLOADING" << LL_ENDL;
|
|
// Process messages to keep from dropping circuit.
|
|
LLMessageSystem* msg = gMessageSystem;
|
|
while (msg->checkAllMessages(gFrameCount, gServicePump))
|
|
{
|
|
}
|
|
msg->processAcks();
|
|
LLUserAuth::UserAuthcode error = LLUserAuth::getInstance()->authResponse();
|
|
if(LLUserAuth::E_DOWNLOADING == error)
|
|
{
|
|
LL_DEBUGS("AppInit") << "downloading..." << LL_ENDL;
|
|
return FALSE;
|
|
}
|
|
LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE );
|
|
progress += 0.01f;
|
|
set_startup_status(progress, LLTrans::getString("LoginProcessingResponse"), auth_message);
|
|
return FALSE;
|
|
}
|
|
|
|
if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState())
|
|
{
|
|
LL_DEBUGS("AppInit") << "STATE_LOGIN_PROCESS_RESPONSE" << LL_ENDL;
|
|
std::ostringstream emsg;
|
|
bool quit = false;
|
|
//bool update = false;
|
|
bool successful_login = false;
|
|
LLUserAuth::UserAuthcode error = LLUserAuth::getInstance()->authResponse();
|
|
// reset globals
|
|
gAcceptTOS = FALSE;
|
|
gAcceptCriticalMessage = FALSE;
|
|
std::string login_response;
|
|
std::string reason_response;
|
|
std::string message_response;
|
|
std::string message_id;
|
|
LLSD response;
|
|
|
|
switch(error)
|
|
{
|
|
case LLUserAuth::E_OK:
|
|
response = LLUserAuth::getInstance()->getResponse();
|
|
login_response = response["login"].asString();
|
|
reason_response = response["reason"].asString();
|
|
message_response = response["message"].asString();
|
|
message_id = response["message_id"].asString();
|
|
{
|
|
std::stringstream dump_str;
|
|
dump_str << response;
|
|
LL_DEBUGS("AppInit") << dump_str.str() << LL_ENDL;
|
|
}
|
|
|
|
if(login_response == "true")
|
|
{
|
|
// Yay, login!
|
|
successful_login = true;
|
|
Debug(if (gCurlIo) dc::curlio.off()); // Login succeeded: restore dc::curlio to original state.
|
|
LLPanelLogin::close(); // Singu Note: Actually destroy the login panel here, otherwise user interaction gets lost upon failed login.
|
|
}
|
|
else if(login_response == "indeterminate")
|
|
{
|
|
progress += 0.01f;
|
|
auth_message = message_response;
|
|
auth_method = response["next_method"].asString();
|
|
redirect_uri = response["next_url"].asString();
|
|
if(auth_method.substr(0, 5) == "login")
|
|
{
|
|
auth_desc = LLTrans::getString("LoginAuthenticating");
|
|
}
|
|
else
|
|
{
|
|
auth_desc = LLTrans::getString("LoginMaintenance");
|
|
}
|
|
set_startup_status(progress, auth_desc, auth_message);
|
|
LLStartUp::setStartupState(STATE_XMLRPC_LEGACY_LOGIN );
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
|
|
emsg << LLTrans::getString("LoginFailed") + "\n";
|
|
|
|
if (!message_response.empty())
|
|
{
|
|
// XUI: fix translation for strings returned during login
|
|
// We need a generic table for translations
|
|
std::string big_reason = LLAgent::sTeleportErrorMessages[ message_response ];
|
|
if ( big_reason.size() == 0 )
|
|
{
|
|
emsg << message_response;
|
|
}
|
|
else
|
|
{
|
|
emsg << big_reason;
|
|
}
|
|
}
|
|
|
|
if(reason_response == "tos")
|
|
{
|
|
if (show_connect_box)
|
|
{
|
|
LL_DEBUGS("AppInit") << "Need tos agreement" << LL_ENDL;
|
|
|
|
LLStartUp::setStartupState( STATE_UPDATE_CHECK );
|
|
LLFloaterTOS* tos_dialog = LLFloaterTOS::show(LLFloaterTOS::TOS_TOS,
|
|
message_response);
|
|
tos_dialog->startModal();
|
|
// LLFloaterTOS deletes itself.
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
quit = true;
|
|
}
|
|
}
|
|
if(reason_response == "critical")
|
|
{
|
|
if (show_connect_box)
|
|
{
|
|
LL_DEBUGS("AppInit") << "Need critical message" << LL_ENDL;
|
|
LLStartUp::setStartupState( STATE_UPDATE_CHECK );
|
|
LLFloaterTOS* tos_dialog = LLFloaterTOS::show(LLFloaterTOS::TOS_CRITICAL_MESSAGE,
|
|
message_response);
|
|
tos_dialog->startModal();
|
|
// LLFloaterTOS deletes itself.
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
quit = true;
|
|
}
|
|
}
|
|
if(reason_response == "key")
|
|
{
|
|
// Couldn't login because user/password is wrong
|
|
// Clear the password
|
|
password = "";
|
|
}
|
|
/*if(reason_response == "update")
|
|
{
|
|
auth_message = message_response;
|
|
update = true;
|
|
}
|
|
if(reason_response == "optional")
|
|
{
|
|
LL_DEBUGS("AppInit") << "Login got optional update" << LL_ENDL;
|
|
auth_message = message_response;
|
|
if (show_connect_box)
|
|
{
|
|
update_app(FALSE, auth_message);
|
|
LLStartUp::setStartupState( STATE_UPDATE_CHECK );
|
|
gSkipOptionalUpdate = TRUE;
|
|
return false;
|
|
}
|
|
}*/
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
static int http_failures = 0;
|
|
http_failures = (error == LLUserAuth::E_HTTP_SERVER_ERROR) ? http_failures + 1 : 0;
|
|
if ((error == LLUserAuth::E_HTTP_SERVER_ERROR && http_failures <= 3) ||
|
|
LLViewerLogin::getInstance()->tryNextURI())
|
|
{
|
|
static int login_attempt_number = 0;
|
|
std::ostringstream s;
|
|
LLStringUtil::format_map_t args;
|
|
args["[NUMBER]"] = llformat("%d", ++login_attempt_number);
|
|
auth_desc = LLTrans::getString("LoginAttempt", args);
|
|
LLStartUp::setStartupState( STATE_XMLRPC_LEGACY_LOGIN );
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
emsg << "Unable to connect to " << gHippoGridManager->getCurrentGrid()->getGridName() << ".\n";
|
|
emsg << LLUserAuth::getInstance()->errorMessage();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Version update and we're not showing the dialog
|
|
if(quit)
|
|
{
|
|
LLUserAuth::getInstance()->reset();
|
|
LLAppViewer::instance()->forceQuit();
|
|
return false;
|
|
}
|
|
|
|
// XML-RPC successful login path here
|
|
if (successful_login)
|
|
{
|
|
// unpack login data needed by the application
|
|
if (process_login_success_response(password, first_sim_size_x, first_sim_size_y))
|
|
{
|
|
std::string name = firstname;
|
|
bool secondlife(gHippoGridManager->getCurrentGrid()->isSecondLife());
|
|
if (!secondlife ||
|
|
!boost::algorithm::iequals(lastname, "Resident"))
|
|
{
|
|
name += ' ' + lastname;
|
|
}
|
|
if (gSavedSettings.getBOOL("LiruGridInTitle")) gWindowTitle += "- " + gHippoGridManager->getCurrentGrid()->getGridName() + ' ';
|
|
gViewerWindow->getWindow()->setTitle(gWindowTitle += "- " + name);
|
|
|
|
if (!secondlife)
|
|
{
|
|
LFSimFeatureHandler& inst(LFSimFeatureHandler::instance());
|
|
inst.setDestinationGuideURLCallback(boost::bind(simfeature_debug_update, _1, "DestinationGuideURL"));
|
|
inst.setSearchURLCallback(boost::bind(simfeature_debug_update, _1, "SearchURL"));
|
|
}
|
|
|
|
// Pass the user information to the voice chat server interface.
|
|
LLVoiceClient::getInstance()->userAuthorized(name, gAgentID);
|
|
// create the default proximal channel
|
|
LLVoiceChannel::initClass();
|
|
LLStartUp::setStartupState( STATE_WORLD_INIT );
|
|
}
|
|
else
|
|
{
|
|
if (gNoRender)
|
|
{
|
|
LL_WARNS("AppInit") << "Bad login - missing return values" << LL_ENDL;
|
|
LL_WARNS("AppInit") << emsg.str() << LL_ENDL;
|
|
exit(0);
|
|
}
|
|
// Bounce back to the login screen.
|
|
LLSD args;
|
|
args["ERROR_MESSAGE"] = emsg.str();
|
|
LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);
|
|
transition_back_to_login_panel(emsg.str());
|
|
show_connect_box = true;
|
|
}
|
|
}
|
|
else // if(!successful_login)
|
|
{
|
|
if (gNoRender)
|
|
{
|
|
LL_WARNS("AppInit") << "Failed to login!" << LL_ENDL;
|
|
LL_WARNS("AppInit") << emsg.str() << LL_ENDL;
|
|
exit(0);
|
|
}
|
|
// Bounce back to the login screen.
|
|
LLSD args;
|
|
args["ERROR_MESSAGE"] = emsg.str();
|
|
LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL;
|
|
LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);
|
|
transition_back_to_login_panel(emsg.str());
|
|
show_connect_box = true;
|
|
return FALSE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// World Init
|
|
//---------------------------------------------------------------------
|
|
if (STATE_WORLD_INIT == LLStartUp::getStartupState())
|
|
{
|
|
set_startup_status(0.40f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD);
|
|
|
|
// Initialize the rest of the world.
|
|
gViewerWindow->initWorldUI_postLogin();
|
|
|
|
display_startup();
|
|
// We should have an agent id by this point.
|
|
llassert(!(gAgentID == LLUUID::null));
|
|
|
|
// Finish agent initialization. (Requires gSavedSettings, builds camera)
|
|
gAgent.init();
|
|
display_startup();
|
|
gAgentCamera.init();
|
|
display_startup();
|
|
set_underclothes_menu_options();
|
|
display_startup();
|
|
|
|
// 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);
|
|
|
|
//
|
|
// Initialize classes w/graphics stuff.
|
|
//
|
|
gTextureList.doPrefetchImages();
|
|
display_startup();
|
|
|
|
LLSurface::initClasses();
|
|
display_startup();
|
|
|
|
|
|
LLFace::initClass();
|
|
display_startup();
|
|
|
|
LLDrawable::initClass();
|
|
display_startup();
|
|
|
|
// init the shader managers
|
|
|
|
LLAvatarAppearance::initClass();
|
|
display_startup();
|
|
|
|
//LLDayCycleManager::initClass();
|
|
//display_startup();
|
|
|
|
// RN: don't initialize VO classes in drone mode, they are too closely tied to rendering
|
|
LLViewerObject::initVOClasses();
|
|
display_startup();
|
|
|
|
// 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 );
|
|
display_startup();
|
|
// 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));
|
|
display_startup();
|
|
|
|
// <FS:CR> Aurora Sim
|
|
LLWorld::getInstance()->setRegionSize(first_sim_size_x, first_sim_size_y);
|
|
// </FS:CR> Aurora Sim
|
|
LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim);
|
|
display_startup();
|
|
|
|
LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle);
|
|
LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL;
|
|
|
|
regionp->setSeedCapability(gFirstSimSeedCap);
|
|
LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL;
|
|
display_startup();
|
|
// Set agent's initial region to be the one we just created.
|
|
gAgent.setRegion(regionp);
|
|
display_startup();
|
|
// 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);
|
|
|
|
display_startup();
|
|
LLStartUp::initExperiences();
|
|
|
|
display_startup();
|
|
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();
|
|
LLMediaFilter::getInstance();
|
|
LLStartUp::setStartupState( STATE_FONT_INIT );
|
|
display_startup();
|
|
return FALSE;
|
|
}
|
|
|
|
// Loading fonts takes several seconds
|
|
if (STATE_FONT_INIT == LLStartUp::getStartupState())
|
|
{
|
|
LLStartUp::fontInit();
|
|
LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT );
|
|
display_startup();
|
|
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
|
|
{
|
|
U32 num_retries = regionp->getNumSeedCapRetries();
|
|
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);
|
|
}
|
|
else
|
|
{
|
|
set_startup_status(0.4f, LLTrans::getString("LoginRequestSeedCapGrant"), gAgent.mMOTD);
|
|
}
|
|
}
|
|
display_startup();
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// Seed Capability Granted
|
|
// no newMessage calls should happen before this point
|
|
//---------------------------------------------------------------------
|
|
if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState())
|
|
{
|
|
display_startup();
|
|
update_texture_fetch();
|
|
display_startup();
|
|
|
|
if ( gViewerWindow != NULL)
|
|
{ // This isn't the first logon attempt, so show the UI
|
|
gViewerWindow->setNormalControlsVisible( TRUE );
|
|
}
|
|
gLoginMenuBarView->setVisible( FALSE );
|
|
gLoginMenuBarView->setEnabled( FALSE );
|
|
display_startup();
|
|
LLRect window(0, gViewerWindow->getWindowHeight(), gViewerWindow->getWindowWidth(), 0);
|
|
gViewerWindow->adjustControlRectanglesForFirstUse(window);
|
|
|
|
if (!gNoRender)
|
|
{
|
|
//Set up cloud rendertypes. Passed argument is unused.
|
|
handleCloudSettingsChanged(LLSD());
|
|
display_startup();
|
|
|
|
|
|
LLError::logToFixedBuffer(gDebugView->mDebugConsolep);
|
|
display_startup();
|
|
|
|
// set initial visibility of debug console
|
|
gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole"));
|
|
display_startup();
|
|
if (gSavedSettings.getBOOL("ShowDebugStats"))
|
|
{
|
|
LLFloaterStats::showInstance();
|
|
display_startup();
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
display_startup();
|
|
|
|
// Debugging info parameters
|
|
gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms
|
|
display_startup();
|
|
|
|
#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
|
|
display_startup();
|
|
|
|
gXferManager->registerCallbacks(gMessageSystem);
|
|
display_startup();
|
|
|
|
LLStartUp::initNameCache();
|
|
LLLogChat::initializeIDMap(); // Name cache loaded, create a happy mappy
|
|
display_startup();
|
|
|
|
// update the voice settings *after* gCacheName initialization
|
|
// so that we can construct voice UI that relies on the name cache
|
|
LLVoiceClient::getInstance()->updateSettings();
|
|
display_startup();
|
|
|
|
// *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);
|
|
display_startup();
|
|
|
|
//reset statistics
|
|
LLViewerStats::instance().resetStats();
|
|
|
|
if (!gNoRender)
|
|
{
|
|
//
|
|
// Set up all of our statistics UI stuff.
|
|
//
|
|
display_startup();
|
|
init_stat_view();
|
|
}
|
|
|
|
display_startup();
|
|
//
|
|
// Set up region and surface defaults
|
|
//
|
|
|
|
|
|
// Sets up the parameters for the first simulator
|
|
|
|
LL_DEBUGS("AppInit") << "Initializing camera..." << LL_ENDL;
|
|
gFrameTime = totalTime();
|
|
F32 last_time = gFrameTimeSeconds;
|
|
gFrameTimeSeconds = (S64)(gFrameTime - gStartTime)/SEC_TO_MICROSEC;
|
|
|
|
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->getWindowDisplayHeight());
|
|
if (gViewerWindow->getWindow()->getFullscreen())
|
|
{
|
|
LLViewerCamera::getInstance()->setAspect(gViewerWindow->getDisplayAspectRatio());
|
|
}
|
|
else
|
|
{
|
|
LLViewerCamera::getInstance()->setAspect( (F32) gViewerWindow->getWindowWidth() / (F32) gViewerWindow->getWindowHeight());
|
|
}
|
|
// Initialize FOV
|
|
LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle"));
|
|
display_startup();
|
|
|
|
// 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();
|
|
display_startup();
|
|
|
|
// Initialize global class data needed for surfaces (i.e. textures)
|
|
if (!gNoRender)
|
|
{
|
|
LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
|
|
// Initialize all of the viewer object classes for the first time (doing things like texture fetches.
|
|
LLGLStateValidator::checkStates();
|
|
LLGLStateValidator::checkTextureChannels();
|
|
|
|
gSky.init(initial_sun_direction);
|
|
|
|
LLGLStateValidator::checkStates();
|
|
LLGLStateValidator::checkTextureChannels();
|
|
}
|
|
|
|
display_startup();
|
|
|
|
LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL;
|
|
// For all images pre-loaded into viewer cache, decode them.
|
|
// 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);
|
|
display_startup();
|
|
gTextureList.decodeAllImages(1.f);
|
|
}
|
|
LLStartUp::setStartupState( STATE_WORLD_WAIT );
|
|
|
|
display_startup();
|
|
|
|
// 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,
|
|
MAX_TIMEOUT_COUNT,
|
|
FALSE,
|
|
F32Seconds(TIMEOUT_SECONDS),
|
|
use_circuit_callback,
|
|
NULL);
|
|
|
|
timeout.reset();
|
|
display_startup();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// Agent Send
|
|
//---------------------------------------------------------------------
|
|
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 );
|
|
}
|
|
LLMessageSystem* msg = gMessageSystem;
|
|
while (msg->checkAllMessages(gFrameCount, gServicePump))
|
|
{
|
|
display_startup();
|
|
}
|
|
msg->processAcks();
|
|
display_startup();
|
|
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);
|
|
display_startup();
|
|
// 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());
|
|
if (!mBenefitsSuccessfullyInit) msg->newMessageFast(_PREHASH_EconomyDataRequest);
|
|
gAgent.sendReliableMessage();
|
|
}
|
|
display_startup();
|
|
|
|
// 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();
|
|
display_startup();
|
|
return FALSE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// Agent Wait
|
|
//---------------------------------------------------------------------
|
|
if (STATE_AGENT_WAIT == LLStartUp::getStartupState())
|
|
{
|
|
LLMessageSystem* msg = gMessageSystem;
|
|
while (msg->checkAllMessages(gFrameCount, gServicePump))
|
|
{
|
|
if (gAgentMovementCompleted)
|
|
{
|
|
// Sometimes we have more than one message in the
|
|
// queue. break out of this loop and continue
|
|
// processing. If we don't, then this could skip one
|
|
// or more login steps.
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got "
|
|
<< msg->getMessageName() << LL_ENDL;
|
|
}
|
|
display_startup();
|
|
}
|
|
msg->processAcks();
|
|
|
|
display_startup();
|
|
|
|
if (gAgentMovementCompleted)
|
|
{
|
|
LLStartUp::setStartupState( STATE_INVENTORY_SEND );
|
|
}
|
|
display_startup();
|
|
return FALSE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// Inventory Send
|
|
//---------------------------------------------------------------------
|
|
if (STATE_INVENTORY_SEND == LLStartUp::getStartupState())
|
|
{
|
|
display_startup();
|
|
// Inform simulator of our language preference
|
|
LLAgentLanguage::update();
|
|
display_startup();
|
|
// unpack thin inventory
|
|
LLSD response = LLUserAuth::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());
|
|
}
|
|
}
|
|
display_startup();
|
|
|
|
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()));
|
|
}
|
|
}
|
|
display_startup();
|
|
|
|
LLSD inv_skel_lib = response["inventory-skel-lib"];
|
|
if(inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull())
|
|
{
|
|
if(!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID()))
|
|
{
|
|
LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL;
|
|
}
|
|
}
|
|
display_startup();
|
|
|
|
LLSD inv_skeleton = response["inventory-skeleton"];
|
|
if(inv_skeleton.isDefined())
|
|
{
|
|
if(!gInventory.loadSkeleton(inv_skeleton, gAgent.getID()))
|
|
{
|
|
LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL;
|
|
}
|
|
}
|
|
display_startup();
|
|
|
|
LLSD buddy_list = response["buddy-list"];
|
|
if(buddy_list.isDefined())
|
|
{
|
|
LLAvatarTracker::buddy_map_t list;
|
|
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)
|
|
{
|
|
LLSD buddy_id = (*it)["buddy_id"];
|
|
if(buddy_id.isDefined())
|
|
{
|
|
agent_id = buddy_id.asUUID();
|
|
}
|
|
|
|
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);
|
|
display_startup();
|
|
}
|
|
|
|
LLSD ui_config = response["ui-config"];
|
|
if(ui_config.isDefined())
|
|
{
|
|
for(LLSD::array_const_iterator it = ui_config.beginArray(),
|
|
end = ui_config.endArray(); it != end; ++it)
|
|
{
|
|
LLSD allow_first_life = (*it)["allow_first_life"];
|
|
if(allow_first_life.isDefined())
|
|
{
|
|
if (allow_first_life.asString() == "Y")
|
|
{
|
|
LLPanelAvatar::sAllowFirstLife = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
display_startup();
|
|
|
|
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());
|
|
}
|
|
|
|
LLSD use_tutorial = (*it)["use_tutorial"];
|
|
if(use_tutorial.asString() == "true")
|
|
{
|
|
show_hud = true;
|
|
}
|
|
}
|
|
}
|
|
display_startup();
|
|
// 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"))
|
|
{
|
|
LLFloaterHUD::showHUD();
|
|
}
|
|
display_startup();
|
|
|
|
LLSD event_categories = response["event_categories"];
|
|
if(event_categories.isDefined())
|
|
{
|
|
LLEventInfo::loadCategories(event_categories);
|
|
}
|
|
display_startup();
|
|
|
|
LLSD event_notifications = response["event_notifications"];
|
|
if(event_notifications.isDefined())
|
|
{
|
|
gEventNotifier.load(event_notifications);
|
|
}
|
|
display_startup();
|
|
|
|
LLSD classified_categories = response["classified_categories"];
|
|
if(classified_categories.isDefined())
|
|
{
|
|
LLClassifiedInfo::loadCategories(classified_categories);
|
|
}
|
|
display_startup();
|
|
|
|
// This method MUST be called before gInventory.findCategoryUUIDForType because of
|
|
// gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap.
|
|
gInventory.buildParentChildMap();
|
|
gInventory.createCommonSystemCategories();
|
|
|
|
// 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();
|
|
|
|
display_startup();
|
|
|
|
//all categories loaded. lets create "My Favorites" category
|
|
gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true);
|
|
|
|
// set up callbacks
|
|
LL_INFOS() << "Registering Callbacks" << LL_ENDL;
|
|
LLMessageSystem* msg = gMessageSystem;
|
|
LL_INFOS() << " Inventory" << LL_ENDL;
|
|
LLInventoryModel::registerCallbacks(msg);
|
|
LL_INFOS() << " AvatarTracker" << LL_ENDL;
|
|
LLAvatarTracker::instance().registerCallbacks(msg);
|
|
LL_INFOS() << " Landmark" << LL_ENDL;
|
|
LLLandmark::registerCallbacks(msg);
|
|
display_startup();
|
|
|
|
// request mute list
|
|
LL_INFOS() << "Requesting Mute List" << LL_ENDL;
|
|
LLMuteList::getInstance()->requestFromServer(gAgent.getID());
|
|
display_startup();
|
|
// Get L$ and ownership credit information
|
|
LL_INFOS() << "Requesting Money Balance" << LL_ENDL;
|
|
LLStatusBar::sendMoneyBalanceRequest();
|
|
display_startup();
|
|
// request all group information
|
|
LL_INFOS() << "Requesting Agent Data" << LL_ENDL;
|
|
gAgent.sendAgentDataUpdateRequest();
|
|
display_startup();
|
|
bool shown_at_exit = gSavedSettings.getBOOL("ShowInventory");
|
|
|
|
// Create the inventory views
|
|
LL_INFOS() << "Creating Inventory Views" << LL_ENDL;
|
|
LLPanelMainInventory::showAgentInventory();
|
|
display_startup();
|
|
|
|
// Hide the inventory if it wasn't shown at exit
|
|
if(!shown_at_exit)
|
|
{
|
|
LLPanelMainInventory::toggleVisibility(NULL);
|
|
}
|
|
display_startup();
|
|
|
|
// [RLVa:KB] - Checked: 2009-11-27 (RLVa-1.1.0f) | Added: RLVa-1.1.0f
|
|
if (rlv_handler_t::isEnabled())
|
|
{
|
|
// Regularly process a select subset of retained commands during logon
|
|
gIdleCallbacks.addFunction(RlvHandler::onIdleStartup, new LLTimer());
|
|
}
|
|
// [/RLVa:KB]
|
|
|
|
LLStartUp::setStartupState( STATE_MISC );
|
|
display_startup();
|
|
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 = LLUserAuth::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);
|
|
}
|
|
}
|
|
|
|
display_startup();
|
|
|
|
// *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp)
|
|
//check_merchant_status();
|
|
|
|
display_startup();
|
|
|
|
// We're successfully logged in.
|
|
gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE);
|
|
|
|
|
|
// 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 );
|
|
};
|
|
|
|
display_startup();
|
|
|
|
if (!gNoRender)
|
|
{
|
|
//Now that we're loading the world, initialize the audio engine.
|
|
init_audio();
|
|
display_startup();
|
|
|
|
// 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
|
|
= LLUserAuth::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;
|
|
display_startup();
|
|
|
|
if (gSavedSettings.getBOOL("ShowMiniMap"))
|
|
{
|
|
LLFloaterMap::showInstance();
|
|
}
|
|
if (gSavedSettings.getBOOL("ShowRadar"))
|
|
{
|
|
LLFloaterAvatarList::showInstance();
|
|
}
|
|
// <edit>
|
|
else if (gSavedSettings.getBOOL("RadarKeepOpen"))
|
|
{
|
|
LLFloaterAvatarList::getInstance()->close();
|
|
}
|
|
if (gSavedSettings.getBOOL("SHShowMediaTicker"))
|
|
{
|
|
SHFloaterMediaTicker::showInstance();
|
|
}
|
|
// </edit>
|
|
if (gSavedSettings.getBOOL("ShowCameraControls"))
|
|
{
|
|
LLFloaterCamera::showInstance();
|
|
}
|
|
if (gSavedSettings.getBOOL("ShowMovementControls"))
|
|
{
|
|
LLFloaterMove::showInstance();
|
|
}
|
|
|
|
if (gSavedSettings.getBOOL("ShowActiveSpeakers"))
|
|
{
|
|
LLFloaterActiveSpeakers::showInstance();
|
|
}
|
|
|
|
if (gSavedSettings.getBOOL("ShowBeaconsFloater"))
|
|
{
|
|
LLFloaterBeacons::showInstance();
|
|
}
|
|
if (gSavedSettings.getBOOL("ShowAvatarFloater"))
|
|
{
|
|
LLFloaterAvatar::showInstance();
|
|
}
|
|
if (gSavedSettings.getBOOL("DestinationGuideShown"))
|
|
{
|
|
LLFloaterDestinations::showInstance();
|
|
}
|
|
|
|
LLMessageSystem* msg = gMessageSystem;
|
|
msg->setHandlerFuncFast(_PREHASH_SoundTrigger, hooked_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;
|
|
|
|
gRenderStartTime.reset();
|
|
// We're not allowed to call reset() when paused, and we might or might not be paused depending on
|
|
// whether or not the main window lost focus before we get here (see LLViewerWindow::handleFocusLost).
|
|
// The simplest, legal way to make sure we're unpaused is to just pause/unpause here.
|
|
gForegroundTime.pause();
|
|
gForegroundTime.unpause();
|
|
gForegroundTime.reset();
|
|
|
|
if (gSavedSettings.getBOOL("FetchInventoryOnLogin")
|
|
)
|
|
{
|
|
// Fetch inventory in the background
|
|
LLInventoryModelBackgroundFetch::instance().start();
|
|
}
|
|
|
|
// 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();
|
|
|
|
// 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 "<<start_slurl.asString()<<LL_ENDL;
|
|
|
|
if (((start_slurl.getType() == LLSLURL::LOCATION) && (gAgentStartLocation == "url")) ||
|
|
((start_slurl.getType() == LLSLURL::LAST_LOCATION) && (gAgentStartLocation == "last")) ||
|
|
((start_slurl.getType() == LLSLURL::HOME_LOCATION) && (gAgentStartLocation == "home")))
|
|
{
|
|
// Start location is OK
|
|
// Disabled code to restore camera location and focus if logging in to default location
|
|
static bool samename = false;
|
|
if (samename)
|
|
{
|
|
// restore old camera pos
|
|
gAgentCamera.setFocusOnAvatar(FALSE, FALSE);
|
|
gAgentCamera.setCameraPosAndFocusGlobal(gSavedSettings.getVector3d("CameraPosOnLogout"), gSavedSettings.getVector3d("FocusPosOnLogout"), LLUUID::null);
|
|
BOOL limit_hit = FALSE;
|
|
gAgentCamera.calcCameraPositionTargetGlobal(&limit_hit);
|
|
if (limit_hit)
|
|
{
|
|
gAgentCamera.setFocusOnAvatar(TRUE, FALSE);
|
|
}
|
|
gAgentCamera.stopCameraAnimation();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::string msg;
|
|
switch(start_slurl.getType())
|
|
{
|
|
case LLSLURL::LOCATION:
|
|
{
|
|
|
|
msg = "AvatarMovedDesired";
|
|
break;
|
|
}
|
|
case LLSLURL::HOME_LOCATION:
|
|
{
|
|
msg = "AvatarMovedHome";
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
msg = "AvatarMovedLast";
|
|
}
|
|
}
|
|
LLNotificationsUtil::add(msg);
|
|
}
|
|
}
|
|
|
|
display_startup();
|
|
//DEV-17797. get null folder. Any items found here moved to Lost and Found
|
|
LLInventoryModelBackgroundFetch::instance().findLostItems();
|
|
display_startup();
|
|
|
|
LLStartUp::setStartupState( STATE_PRECACHE );
|
|
timeout.reset();
|
|
return FALSE;
|
|
}
|
|
|
|
if (STATE_PRECACHE == LLStartUp::getStartupState())
|
|
{
|
|
display_startup();
|
|
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);
|
|
gAgentWearables.sendDummyAgentWearablesUpdate();
|
|
callAfterCategoryFetch(LLAppearanceMgr::instance().getCOF(), set_flags_and_update_appearance);
|
|
}
|
|
|
|
display_startup();
|
|
|
|
// 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);
|
|
display_startup();
|
|
if (!LLViewerShaderMgr::sInitialized)
|
|
{
|
|
LLViewerShaderMgr::sInitialized = TRUE;
|
|
LLViewerShaderMgr::instance()->setShaders();
|
|
display_startup();
|
|
}
|
|
//Precache UI sounds.
|
|
precache_audio();
|
|
}
|
|
|
|
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 );
|
|
return TRUE;
|
|
}
|
|
|
|
display_startup();
|
|
|
|
if (wearables_time > MAX_WEARABLES_TIME)
|
|
{
|
|
LLNotificationsUtil::add("ClothingLoading");
|
|
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_WEARABLES_TOO_LONG);
|
|
LLStartUp::setStartupState( STATE_CLEANUP );
|
|
return TRUE;
|
|
}
|
|
|
|
if (gAgent.isFirstLogin())
|
|
{
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
display_startup();
|
|
update_texture_fetch();
|
|
display_startup();
|
|
set_startup_status(0.9f + 0.1f * wearables_time / MAX_WEARABLES_TIME,
|
|
LLTrans::getString("LoginDownloadingClothing"),
|
|
gAgent.mMOTD);
|
|
display_startup();
|
|
return TRUE;
|
|
}
|
|
|
|
if (STATE_CLEANUP == LLStartUp::getStartupState())
|
|
{
|
|
set_startup_status(1.0, LLStringUtil::null, LLStringUtil::null);
|
|
display_startup();
|
|
|
|
if (!mBenefitsSuccessfullyInit && gHippoGridManager->getConnectedGrid()->isSecondLife())
|
|
{
|
|
LLNotificationsUtil::add("FailedToGetBenefits", LLSD(), LLSD(), boost::bind(on_benefits_failed_callback, _1, _2));
|
|
}
|
|
|
|
// Let the map know about the inventory.
|
|
LLFloaterWorldMap* floater_world_map = gFloaterWorldMap;
|
|
if(floater_world_map)
|
|
{
|
|
floater_world_map->observeInventory(&gInventory);
|
|
floater_world_map->observeFriends();
|
|
}
|
|
|
|
// Start the AO now that settings have loaded and login successful -- MC
|
|
AOSystem::start();
|
|
|
|
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);
|
|
display_startup();
|
|
|
|
// 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();
|
|
if (gSavedSettings.getBOOL("LoginAsGod"))
|
|
{
|
|
gAgent.requestEnterGodMode();
|
|
}
|
|
|
|
// Start automatic replay if the flag is set.
|
|
if (gSavedSettings.getBOOL("StatsAutoRun"))
|
|
{
|
|
LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL;
|
|
gAgentPilot.startPlayback();
|
|
}
|
|
|
|
// 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();
|
|
|
|
// Clean up the userauth stuff.
|
|
LLUserAuth::getInstance()->reset();
|
|
|
|
LLStartUp::setStartupState( STATE_STARTED );
|
|
display_startup();
|
|
|
|
if (gSavedSettings.getBOOL("SpeedRez"))
|
|
{
|
|
// Speed up rezzing if requested.
|
|
F32 dist1 = gSavedSettings.getF32("RenderFarClip");
|
|
F32 dist2 = gSavedSettings.getF32("SavedRenderFarClip");
|
|
gSavedDrawDistance = (dist1 >= dist2 ? dist1 : dist2);
|
|
gSavedSettings.setF32("SavedRenderFarClip", gSavedDrawDistance);
|
|
gSavedSettings.setF32("RenderFarClip", 32.0f);
|
|
}
|
|
|
|
//Agent avatar is ready. Create the listener.
|
|
audio_update_listener();
|
|
|
|
// reset keyboard focus to sane state of pointing at world
|
|
gFocusMgr.setKeyboardFocus(NULL);
|
|
|
|
#if 0 // sjb: enable for auto-enabling timer display
|
|
gDebugView->mFastTimerView->setVisible(TRUE);
|
|
#endif
|
|
|
|
LLAppViewer::instance()->handleLoginComplete();
|
|
|
|
// reset timers now that we are running "logged in" logic
|
|
LLFastTimer::reset();
|
|
display_startup();
|
|
|
|
llassert(LLPathfindingManager::getInstance() != NULL);
|
|
LLPathfindingManager::getInstance()->initSystem();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LL_WARNS("AppInit") << "Reached end of idle_startup for state " << LLStartUp::getStartupState() << LL_ENDL;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// local function definition
|
|
//
|
|
|
|
void login_show()
|
|
{
|
|
LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL;
|
|
|
|
|
|
// This creates the LLPanelLogin instance.
|
|
LLPanelLogin::show();
|
|
|
|
// UI textures have been previously loaded in doPreloadImages()
|
|
}
|
|
|
|
|
|
// static
|
|
std::string LLStartUp::loadPasswordFromDisk()
|
|
{
|
|
// Only load password if we also intend to save it (otherwise the user
|
|
// wonders what we're doing behind his back). JC
|
|
BOOL remember_password = gSavedSettings.getBOOL("RememberPassword");
|
|
if (!remember_password)
|
|
{
|
|
return std::string("");
|
|
}
|
|
|
|
std::string hashed_password("");
|
|
|
|
// Look for legacy "marker" password from settings.ini
|
|
hashed_password = gSavedSettings.getString("Marker");
|
|
if (!hashed_password.empty())
|
|
{
|
|
// Stomp the Marker entry.
|
|
gSavedSettings.setString("Marker", "");
|
|
|
|
// Return that password.
|
|
return hashed_password;
|
|
}
|
|
|
|
std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
|
|
"password.dat");
|
|
LLFILE* fp = LLFile::fopen(filepath, "rb"); /* Flawfinder: ignore */
|
|
if (!fp)
|
|
{
|
|
return hashed_password;
|
|
}
|
|
|
|
// UUID is 16 bytes, written into ASCII is 32 characters
|
|
// without trailing \0
|
|
const S32 HASHED_LENGTH = 32;
|
|
U8 buffer[HASHED_LENGTH+1];
|
|
|
|
if (1 != fread(buffer, HASHED_LENGTH, 1, fp))
|
|
{
|
|
return hashed_password;
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
// Decipher with MAC address
|
|
LLXORCipher cipher(gMACAddress, 6);
|
|
cipher.decrypt(buffer, HASHED_LENGTH);
|
|
|
|
buffer[HASHED_LENGTH] = '\0';
|
|
|
|
// Check to see if the mac address generated a bad hashed
|
|
// password. It should be a hex-string or else the mac adress has
|
|
// changed. This is a security feature to make sure that if you
|
|
// get someone's password.dat file, you cannot hack their account.
|
|
if(LLStringOps::isHexString(std::string(reinterpret_cast<const char*>(buffer), HASHED_LENGTH)))
|
|
{
|
|
hashed_password.assign((char*)buffer);
|
|
}
|
|
|
|
return hashed_password;
|
|
}
|
|
|
|
|
|
// static
|
|
void LLStartUp::savePasswordToDisk(const std::string& hashed_password)
|
|
{
|
|
std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
|
|
"password.dat");
|
|
LLFILE* fp = LLFile::fopen(filepath, "wb"); /* Flawfinder: ignore */
|
|
if (!fp)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Encipher with MAC address
|
|
const S32 HASHED_LENGTH = 32;
|
|
U8 buffer[HASHED_LENGTH+1];
|
|
|
|
LLStringUtil::copy((char*)buffer, hashed_password.c_str(), HASHED_LENGTH+1);
|
|
|
|
LLXORCipher cipher(gMACAddress, 6);
|
|
cipher.encrypt(buffer, HASHED_LENGTH);
|
|
|
|
if (fwrite(buffer, HASHED_LENGTH, 1, fp) != 1)
|
|
{
|
|
LL_WARNS("AppInit") << "Short write" << LL_ENDL;
|
|
}
|
|
|
|
fclose(fp);
|
|
}
|
|
|
|
|
|
// static
|
|
void LLStartUp::deletePasswordFromDisk()
|
|
{
|
|
std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
|
|
"password.dat");
|
|
LLFile::remove(filepath);
|
|
}
|
|
|
|
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;
|
|
const std::string &url = gHippoGridManager->getConnectedGrid()->getRegisterUrl();
|
|
if (!url.empty()) {
|
|
LLWeb::loadURL(url);
|
|
} else {
|
|
LL_WARNS() << "Account creation URL is empty" << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
LLPanelLogin::giveFocus();
|
|
return false;
|
|
}
|
|
|
|
|
|
LLColor4 get_text_color(const LLChat& chat, bool from_im = false); //llfloaterchat.cpp
|
|
|
|
void set_startup_status(const F32 frac, const std::string& string, const std::string& msg)
|
|
{
|
|
if(gSavedSettings.getBOOL("AscentDisableLogoutScreens"))
|
|
{
|
|
static std::string last_d;
|
|
std::string new_d = string;
|
|
if(new_d != last_d)
|
|
{
|
|
last_d = new_d;
|
|
LLChat chat;
|
|
chat.mText = new_d;
|
|
chat.mSourceType = (EChatSourceType)(CHAT_SOURCE_OBJECT+1);
|
|
if(gConsole)
|
|
gConsole->addConsoleLine(chat.mText, gSavedSettings.getColor4("SystemChatColor"));
|
|
LLFloaterChat::addChatHistory(chat,false);
|
|
|
|
if(new_d == LLTrans::getString("LoginWaitingForRegionHandshake"))
|
|
{
|
|
chat.mText = "MOTD: "+msg;
|
|
chat.mSourceType = (EChatSourceType)(CHAT_SOURCE_OBJECT+1);
|
|
if(gConsole)
|
|
gConsole->addConsoleLine(chat.mText, gSavedSettings.getColor4("SystemChatColor"));
|
|
LLFloaterChat::addChatHistory(chat,false);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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
|
|
{
|
|
const std::string &url = gHippoGridManager->getConnectedGrid()->getSupportUrl();
|
|
if (!url.empty()) LLWeb::loadURL(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;
|
|
}
|
|
|
|
LLPanelLogin::giveFocus();
|
|
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;
|
|
LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status);
|
|
reset_login();
|
|
}
|
|
else
|
|
{
|
|
gGotUseCircuitCodeAck = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void pass_processObjectPropertiesFamily(LLMessageSystem *msg, void**)
|
|
{
|
|
// Send the result to the corresponding requesters.
|
|
LLSelectMgr::processObjectPropertiesFamily(msg, NULL);
|
|
JCFloaterAreaSearch::processObjectPropertiesFamily(msg, NULL);
|
|
}
|
|
|
|
void process_script_running_reply(LLMessageSystem* msg, void** v)
|
|
{
|
|
LLLiveLSLEditor::processScriptRunningReply(msg, v);
|
|
ScriptCounter::processScriptRunningReply(msg);
|
|
}
|
|
|
|
void register_viewer_callbacks(LLMessageSystem* msg)
|
|
{
|
|
msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data );
|
|
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);
|
|
msg->setHandlerFunc("AgentCachedTextureResponse", LLAgent::processAgentCachedTextureResponse);
|
|
msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures);
|
|
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);
|
|
msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties, NULL);
|
|
msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, pass_processObjectPropertiesFamily, 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, process_script_running_reply);
|
|
|
|
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::processAvatarPropertiesReply);
|
|
msg->setHandlerFunc("AvatarInterestsReply",
|
|
&LLAvatarPropertiesProcessor::processAvatarInterestsReply);
|
|
msg->setHandlerFunc("AvatarGroupsReply",
|
|
&LLAvatarPropertiesProcessor::processAvatarGroupsReply);
|
|
// ratings deprecated
|
|
//msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply,
|
|
// LLPanelAvatar::processAvatarStatisticsReply);
|
|
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);
|
|
|
|
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);
|
|
|
|
msg->setHandlerFunc("DirPlacesReply", LLPanelDirBrowser::processDirPlacesReply);
|
|
msg->setHandlerFunc("DirPeopleReply", LLPanelDirBrowser::processDirPeopleReply);
|
|
msg->setHandlerFunc("DirEventsReply", LLPanelDirBrowser::processDirEventsReply);
|
|
msg->setHandlerFunc("DirGroupsReply", LLPanelDirBrowser::processDirGroupsReply);
|
|
//msg->setHandlerFunc("DirPicksReply", LLPanelDirBrowser::processDirPicksReply);
|
|
msg->setHandlerFunc("DirClassifiedReply", LLPanelDirBrowser::processDirClassifiedReply);
|
|
msg->setHandlerFunc("DirLandReply", LLPanelDirBrowser::processDirLandReply);
|
|
//msg->setHandlerFunc("DirPopularReply",LLPanelDirBrowser::processDirPopularReply);
|
|
|
|
msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply);
|
|
|
|
msg->setHandlerFunc("MapLayerReply", LLWorldMap::processMapLayerReply);
|
|
msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply);
|
|
msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply);
|
|
|
|
msg->setHandlerFunc("EventInfoReply", LLPanelEvent::processEventInfoReply);
|
|
msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply);
|
|
// msg->setHandlerFunc("ClassifiedInfoReply", LLPanelClassified::processClassifiedInfoReply);
|
|
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->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message);
|
|
}
|
|
|
|
|
|
void init_stat_view()
|
|
{
|
|
LLFrameStatView *frameviewp = gDebugView->mFrameStatView;
|
|
frameviewp->setup(gFrameStats);
|
|
frameviewp->mShowPercent = FALSE;
|
|
}
|
|
|
|
void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32)
|
|
{
|
|
// nothing
|
|
}
|
|
|
|
// *HACK: Must match name in Library or agent inventory
|
|
const std::string COMMON_GESTURES_FOLDER = "Common Gestures";
|
|
const std::string MALE_GESTURES_FOLDER = "Male Gestures";
|
|
const std::string FEMALE_GESTURES_FOLDER = "Female Gestures";
|
|
const std::string MALE_OUTFIT_FOLDER = "Male Shape & Outfit";
|
|
const std::string FEMALE_OUTFIT_FOLDER = "Female Shape & Outfit";
|
|
const S32 OPT_CLOSED_WINDOW = -1;
|
|
const S32 OPT_MALE = 0;
|
|
const S32 OPT_FEMALE = 1;
|
|
|
|
bool callback_choose_gender(const LLSD& notification, const LLSD& response)
|
|
{
|
|
S32 option = LLNotification::getSelectedOption(notification, response);
|
|
switch(option)
|
|
{
|
|
case OPT_MALE:
|
|
LLStartUp::loadInitialOutfit( MALE_OUTFIT_FOLDER, "male" );
|
|
break;
|
|
|
|
case OPT_FEMALE:
|
|
case OPT_CLOSED_WINDOW:
|
|
default:
|
|
LLStartUp::loadInitialOutfit( FEMALE_OUTFIT_FOLDER, "female" );
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
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.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
|
|
|
|
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 outfit - if not there, create some default
|
|
// wearables.
|
|
LLUUID cat_id = findDescendentCategoryIDByName(
|
|
gInventory.getLibraryRootFolderID(),
|
|
outfit_folder_name);
|
|
if (cat_id.isNull())
|
|
{
|
|
LL_DEBUGS() << "standard wearables" << LL_ENDL;
|
|
gAgentWearables.createStandardWearables();
|
|
}
|
|
else
|
|
{
|
|
// FIXME SH-3860 - this creates a race condition, where COF
|
|
// changes (base outfit link added) after appearance update
|
|
// request has been submitted.
|
|
sWearablesLoadedCon = gAgentWearables.addLoadedCallback(LLStartUp::saveInitialOutfit);
|
|
|
|
bool do_copy = true;
|
|
bool do_append = false;
|
|
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
|
|
// Need to fetch cof contents before we can wear.
|
|
callAfterCategoryFetch(LLAppearanceMgr::instance().getCOF(),
|
|
boost::bind(&LLAppearanceMgr::wearInventoryCategory, LLAppearanceMgr::getInstance(), cat, do_copy, do_append));
|
|
LL_DEBUGS() << "initial outfit category id: " << cat_id << LL_ENDL;
|
|
}
|
|
|
|
gAgent.setOutfitChosen(TRUE);
|
|
gAgentWearables.sendDummyAgentWearablesUpdate();
|
|
}
|
|
|
|
//static
|
|
void LLStartUp::saveInitialOutfit()
|
|
{
|
|
if (sInitialOutfit.empty()) {
|
|
LL_DEBUGS() << "sInitialOutfit is empty" << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
if (sWearablesLoadedCon.connected())
|
|
{
|
|
LL_DEBUGS("Avatar") << "sWearablesLoadedCon is connected, disconnecting" << LL_ENDL;
|
|
sWearablesLoadedCon.disconnect();
|
|
}
|
|
LL_DEBUGS("Avatar") << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << LL_ENDL;
|
|
LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false);
|
|
}
|
|
|
|
std::string& LLStartUp::getInitialOutfitName()
|
|
{
|
|
return sInitialOutfit;
|
|
}
|
|
|
|
// Loads a bitmap to display during load
|
|
// location_id = 0 => last position
|
|
// location_id = 1 => home position
|
|
void init_start_screen(S32 location_id)
|
|
{
|
|
if (gStartTexture.notNull())
|
|
{
|
|
gStartTexture = NULL;
|
|
LL_INFOS("AppInit") << "re-initializing start screen" << LL_ENDL;
|
|
}
|
|
|
|
LL_DEBUGS("AppInit") << "Loading startup bitmap..." << LL_ENDL;
|
|
|
|
std::string temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter();
|
|
|
|
if ((S32)START_LOCATION_ID_LAST == location_id)
|
|
{
|
|
temp_str += SCREEN_LAST_FILENAME;
|
|
}
|
|
else
|
|
{
|
|
temp_str += SCREEN_HOME_FILENAME;
|
|
}
|
|
|
|
LLPointer<LLImageBMP> start_image_bmp = new LLImageBMP;
|
|
|
|
// Turn off start screen to get around the occasional readback
|
|
// driver bug
|
|
if(!gSavedSettings.getBOOL("UseStartScreen"))
|
|
{
|
|
LL_INFOS("AppInit") << "Bitmap load disabled" << LL_ENDL;
|
|
return;
|
|
}
|
|
else if(!start_image_bmp->load(temp_str) )
|
|
{
|
|
LL_WARNS("AppInit") << "Bitmap load failed" << LL_ENDL;
|
|
gStartTexture = NULL;
|
|
}
|
|
else
|
|
{
|
|
gStartImageWidth = start_image_bmp->getWidth();
|
|
gStartImageHeight = start_image_bmp->getHeight();
|
|
|
|
LLPointer<LLImageRaw> raw = new LLImageRaw;
|
|
if (!start_image_bmp->decode(raw, 0.0f))
|
|
{
|
|
LL_WARNS("AppInit") << "Bitmap decode failed" << LL_ENDL;
|
|
gStartTexture = NULL;
|
|
}
|
|
else
|
|
{
|
|
raw->expandToPowerOfTwo();
|
|
gStartTexture = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE) ;
|
|
}
|
|
}
|
|
|
|
if(gStartTexture.isNull())
|
|
{
|
|
gStartTexture = LLViewerTexture::sBlackImagep ;
|
|
gStartImageWidth = gStartTexture->getWidth() ;
|
|
gStartImageHeight = gStartTexture->getHeight() ;
|
|
}
|
|
}
|
|
|
|
|
|
// 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_VOICE_LICENSE );
|
|
RTNENUM( STATE_UPDATE_CHECK );
|
|
RTNENUM( STATE_LOGIN_AUTH_INIT );
|
|
RTNENUM( STATE_XMLRPC_LEGACY_LOGIN );
|
|
RTNENUM( STATE_LOGIN_NO_DATA_YET );
|
|
RTNENUM( STATE_LOGIN_DOWNLOADING );
|
|
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_MISC );
|
|
RTNENUM( STATE_PRECACHE );
|
|
RTNENUM( STATE_WEARABLES_WAIT );
|
|
RTNENUM( STATE_CLEANUP );
|
|
RTNENUM( STATE_STARTED );
|
|
}
|
|
#undef RTNENUM
|
|
// Never reached.
|
|
return llformat("(state #%d)", state);
|
|
}
|
|
|
|
|
|
// static
|
|
void LLStartUp::setStartupState( EStartupState state )
|
|
{
|
|
LL_INFOS("AppInit") << "Startup state changing from " <<
|
|
getStartupStateString() << " to " <<
|
|
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);
|
|
}
|
|
|
|
void reset_login()
|
|
{
|
|
gAgentWearables.cleanup();
|
|
gAgentCamera.cleanup();
|
|
gAgent.cleanup();
|
|
LLWorld::getInstance()->destroyClass();
|
|
|
|
// OGPX : Save URL history file
|
|
// This needs to be done on login failure because it gets read on *every* login attempt
|
|
LLURLHistory::saveFile("url_history.xml");
|
|
|
|
LLStartUp::setStartupState( STATE_LOGIN_SHOW );
|
|
|
|
if ( gViewerWindow )
|
|
{ // Hide menus and normal buttons
|
|
gViewerWindow->setNormalControlsVisible( FALSE );
|
|
gLoginMenuBarView->setVisible( TRUE );
|
|
gLoginMenuBarView->setEnabled( TRUE );
|
|
}
|
|
|
|
// Clear the console
|
|
if (gConsole) gConsole->clear();
|
|
|
|
// Hide any other stuff
|
|
LLFloaterMap::hideInstance();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool LLStartUp::canGoFullscreen()
|
|
{
|
|
return gStartupState >= STATE_WORLD_INIT;
|
|
}
|
|
|
|
// 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());
|
|
display_startup();
|
|
|
|
// LLViewerMedia::initClass();
|
|
LLViewerParcelMedia::initClass();
|
|
}
|
|
|
|
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());
|
|
display_startup();
|
|
|
|
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
|
|
S32 phoenix_name_system = gSavedSettings.getS32("PhoenixNameSystem");
|
|
LLAvatarNameCache::initClass(false, gSavedSettings.getBOOL("UsePeopleAPI"));
|
|
LLAvatarNameCache::setUseDisplayNames(phoenix_name_system > 0 && phoenix_name_system < 4);
|
|
LLAvatarNameCache::setUseUsernames(!phoenix_name_system || phoenix_name_system == 1 || phoenix_name_system == 3);
|
|
}
|
|
|
|
|
|
void LLStartUp::initExperiences()
|
|
{
|
|
// Should trigger loading the cache.
|
|
LLExperienceCache::instance().setCapabilityQuery(
|
|
boost::bind(&LLAgent::getRegionCapability, &gAgent, _1));
|
|
|
|
LLExperienceLog::instance().initialize();
|
|
}
|
|
|
|
void LLStartUp::cleanupNameCache()
|
|
{
|
|
LLAvatarNameCache::cleanupClass();
|
|
|
|
delete gCacheName;
|
|
gCacheName = nullptr;
|
|
}
|
|
|
|
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(), "clicked",
|
|
NULL, false);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void LLStartUp::setStartSLURL(const LLSLURL& slurl)
|
|
{
|
|
LL_DEBUGS("AppInit")<<slurl.asString()<<LL_ENDL;
|
|
|
|
if ( slurl.isSpatial() )
|
|
{
|
|
std::string new_start = slurl.getSLURLString();
|
|
LL_DEBUGS("AppInit")<<new_start<<LL_ENDL;
|
|
sStartSLURL = slurl;
|
|
LLPanelLogin::onUpdateStartSLURL(slurl); // updates grid if needed
|
|
|
|
// remember that this is where we wanted to log in...if the login fails,
|
|
// the next attempt will default to the same place.
|
|
gSavedSettings.setString("NextLoginLocation", new_start);
|
|
// following a successful login, this is cleared
|
|
// and the default reverts to LoginLocation
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AppInit")<<"Invalid start SLURL (ignored): "<<slurl.asString()<<LL_ENDL;
|
|
}
|
|
}
|
|
|
|
// static
|
|
LLSLURL& LLStartUp::getStartSLURL()
|
|
{
|
|
return sStartSLURL;
|
|
}
|
|
|
|
/*
|
|
bool LLStartUp::handleSocksProxy(bool reportOK)
|
|
{
|
|
std::string httpProxyType = gSavedSettings.getString("Socks5HttpProxyType");
|
|
|
|
// Determine the http proxy type (if any)
|
|
if ((httpProxyType.compare("Web") == 0) && gSavedSettings.getBOOL("BrowserProxyEnabled"))
|
|
{
|
|
LLHost httpHost;
|
|
httpHost.setHostByName(gSavedSettings.getString("BrowserProxyAddress"));
|
|
httpHost.setPort(gSavedSettings.getS32("BrowserProxyPort"));
|
|
LLSocks::getInstance()->EnableHttpProxy(httpHost,LLPROXY_HTTP);
|
|
}
|
|
else if ((httpProxyType.compare("Socks") == 0) && gSavedSettings.getBOOL("Socks5ProxyEnabled"))
|
|
{
|
|
LLHost httpHost;
|
|
httpHost.setHostByName(gSavedSettings.getString("Socks5ProxyHost"));
|
|
httpHost.setPort(gSavedSettings.getU32("Socks5ProxyPort"));
|
|
LLSocks::getInstance()->EnableHttpProxy(httpHost,LLPROXY_SOCKS);
|
|
}
|
|
else
|
|
{
|
|
LLSocks::getInstance()->DisableHttpProxy();
|
|
}
|
|
|
|
bool use_socks_proxy = gSavedSettings.getBOOL("Socks5ProxyEnabled");
|
|
if (use_socks_proxy)
|
|
{
|
|
|
|
// Determine and update LLSocks with the saved authentication system
|
|
std::string auth_type = gSavedSettings.getString("Socks5AuthType");
|
|
|
|
if (auth_type.compare("None") == 0)
|
|
{
|
|
LLSocks::getInstance()->setAuthNone();
|
|
}
|
|
|
|
if (auth_type.compare("UserPass") == 0)
|
|
{
|
|
LLSocks::getInstance()->setAuthPassword(gSavedSettings.getString("Socks5Username"),gSavedSettings.getString("Socks5Password"));
|
|
}
|
|
|
|
// Start the proxy and check for errors
|
|
int status = LLSocks::getInstance()->startProxy(gSavedSettings.getString("Socks5ProxyHost"), gSavedSettings.getU32("Socks5ProxyPort"));
|
|
LLSD subs;
|
|
subs["PROXY"] = gSavedSettings.getString("Socks5ProxyHost");
|
|
|
|
switch(status)
|
|
{
|
|
case SOCKS_OK:
|
|
if (reportOK == true)
|
|
{
|
|
LLNotificationsUtil::add("SOCKS_CONNECT_OK", subs);
|
|
}
|
|
return true;
|
|
break;
|
|
|
|
case SOCKS_CONNECT_ERROR: // TCP Fail
|
|
LLNotificationsUtil::add("SOCKS_CONNECT_ERROR", subs);
|
|
break;
|
|
|
|
case SOCKS_NOT_PERMITTED: // Socks5 server rule set refused connection
|
|
LLNotificationsUtil::add("SOCKS_NOT_PERMITTED", subs);
|
|
break;
|
|
|
|
case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server
|
|
LLNotificationsUtil::add("SOCKS_NOT_ACCEPTABLE", subs);
|
|
break;
|
|
|
|
case SOCKS_AUTH_FAIL: // Authentication failed
|
|
LLNotificationsUtil::add("SOCKS_AUTH_FAIL", subs);
|
|
break;
|
|
|
|
case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed
|
|
LLNotificationsUtil::add("SOCKS_UDP_FWD_NOT_GRANTED", subs);
|
|
break;
|
|
|
|
case SOCKS_HOST_CONNECT_FAILED: // Failed to open a TCP channel to the socks server
|
|
LLNotificationsUtil::add("SOCKS_HOST_CONNECT_FAILED", subs);
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
LLSocks::getInstance()->stopProxy(); //ensure no UDP proxy is running and its all cleaned up
|
|
}
|
|
|
|
return true;
|
|
}
|
|
*/
|
|
|
|
/**
|
|
* 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("Socks5HttpProxyType");
|
|
|
|
// 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)
|
|
{
|
|
std::string socks_user = gSavedSettings.getString("Socks5Username");
|
|
std::string socks_password = gSavedSettings.getString("Socks5Password");
|
|
|
|
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");
|
|
|
|
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."<< LL_ENDL;
|
|
|
|
// Set the missing or wrong configuration back to something valid.
|
|
gSavedSettings.setString("Socks5HttpProxyType", "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)
|
|
{
|
|
LLPanelLogin::giveFocus();
|
|
return false;
|
|
}
|
|
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;
|
|
}
|
|
|
|
// FIXME PREMIUM - for testing if login does not yet provide Premium Plus. Should be removed thereafter.
|
|
//if (succ && !LLAgentBenefitsMgr::has("Premium Plus"))
|
|
//{
|
|
// LLAgentBenefitsMgr::init("Premium Plus", packages_sd["Premium"]["benefits"]);
|
|
// llassert(LLAgentBenefitsMgr::has("Premium Plus"));
|
|
//}
|
|
return succ;
|
|
}
|
|
|
|
bool process_login_success_response(std::string& password, U32& first_sim_size_x, U32& first_sim_size_y)
|
|
{
|
|
LLSD response = LLUserAuth::getInstance()->getResponse();
|
|
|
|
mBenefitsSuccessfullyInit = init_benefits(response);
|
|
|
|
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;
|
|
|
|
// Agent id needed for parcel info request in LLUrlEntryParcel
|
|
// to resolve parcel name.
|
|
LLUrlEntryParcel::setAgentID(gAgentID);
|
|
|
|
text = response["session_id"].asString();
|
|
if(!text.empty()) gAgentSessionID.set(text);
|
|
gDebugInfo["SessionID"] = text;
|
|
|
|
// 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);
|
|
|
|
std::string firstname;
|
|
std::string lastname;
|
|
text = response["first_name"].asString();
|
|
if(!text.empty())
|
|
{
|
|
// Remove quotes from string. Login.cgi sends these to force
|
|
// names that look like numbers into strings.
|
|
firstname.assign(text);
|
|
LLStringUtil::replaceChar(firstname, '"', ' ');
|
|
LLStringUtil::trim(firstname);
|
|
}
|
|
text = response["last_name"].asString();
|
|
if(!text.empty()) lastname.assign(text);
|
|
gSavedSettings.setString("FirstName", firstname);
|
|
gSavedSettings.setString("LastName", lastname);
|
|
|
|
if (gSavedSettings.getBOOL("RememberPassword"))
|
|
{
|
|
// Successful login means the password is valid, so save it.
|
|
LLStartUp::savePasswordToDisk(password);
|
|
}
|
|
else
|
|
{
|
|
// Don't leave password from previous session sitting around
|
|
// during this login session.
|
|
LLStartUp::deletePasswordFromDisk();
|
|
password.assign(""); // clear the password so it isn't saved to login history either
|
|
}
|
|
|
|
{
|
|
// Save the login history data to disk
|
|
std::string history_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "saved_logins_sg2.xml");
|
|
|
|
LLSavedLogins history_data = LLSavedLogins::loadFile(history_file);
|
|
std::string grid_name = gHippoGridManager->getConnectedGrid()->getGridName();
|
|
history_data.deleteEntry(firstname, lastname, grid_name);
|
|
if (gSavedSettings.getBOOL("RememberName"))
|
|
{
|
|
LLSavedLoginEntry login_entry(firstname, lastname, password, grid_name);
|
|
history_data.addEntry(login_entry);
|
|
}
|
|
else
|
|
{
|
|
// Clear the old-style login data as well
|
|
gSavedSettings.setString("FirstName", std::string(""));
|
|
gSavedSettings.setString("LastName", std::string(""));
|
|
}
|
|
|
|
LLSavedLogins::saveFile(history_data, history_file);
|
|
}
|
|
|
|
// 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]);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
// <FS:CR> Aurora Sim
|
|
text = response["region_size_x"].asString();
|
|
if (!text.empty()) LLViewerParcelMgr::getInstance()->init(first_sim_size_x = atoi(text.c_str()));
|
|
// Patrick Sapinski commented here on 2/10/2011 that y is currently unused and major refactor is required - Liru (11/6/2013)
|
|
text = response["region_size_y"].asString();
|
|
if (!text.empty()) first_sim_size_y = atoi(text.c_str());
|
|
// </FS:CR> 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(), 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 = (server_utc_time - now);
|
|
}
|
|
}
|
|
|
|
std::string home_location = response["home"];
|
|
if(!home_location.empty())
|
|
{
|
|
size_t len = home_location.size();
|
|
LLMemoryStream mstr((U8*)home_location.c_str(), 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);
|
|
}
|
|
|
|
gAgent.mMOTD.assign(response["message"]);
|
|
|
|
// 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") ? TRUE : FALSE);
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
flag = login_flags["daylight_savings"].asString();
|
|
if(flag == "Y")
|
|
{
|
|
gPacificDaylightTime = (flag == "Y");
|
|
}
|
|
}
|
|
std::string map_server_url = response["map-server-url"];
|
|
if(!map_server_url.empty())
|
|
{
|
|
gSavedSettings.setString("MapServerURL", map_server_url);
|
|
LLWorldMap::gotMapServerURL(true);
|
|
}
|
|
|
|
auto& grid = *gHippoGridManager->getConnectedGrid();
|
|
bool opensim = !grid.isSecondLife();
|
|
if (opensim)
|
|
{
|
|
std::string web_profile_url = response["web_profile_url"];
|
|
//if(!web_profile_url.empty()) // Singu Note: We're using this to check if this grid supports web profiles at all, so set empty if empty.
|
|
gSavedSettings.setString("WebProfileURL", web_profile_url);
|
|
}
|
|
else if(!grid.isInProductionGrid())
|
|
{
|
|
gSavedSettings.setString("WebProfileURL", "https://my-demo.secondlife.com/[AGENT_NAME]");
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
LLSD global_textures = response["global-textures"][0];
|
|
if(global_textures.size())
|
|
{
|
|
// Extract sun and moon texture IDs. These are used
|
|
// in the LLVOSky constructor, but I can't figure out
|
|
// how to pass them in. JC
|
|
LLUUID id = global_textures["sun_texture_id"];
|
|
if(id.notNull())
|
|
{
|
|
gSunTextureID = id;
|
|
}
|
|
|
|
id = global_textures["moon_texture_id"];
|
|
if(id.notNull())
|
|
{
|
|
gMoonTextureID = id;
|
|
}
|
|
|
|
#if ENABLE_CLASSIC_CLOUDS
|
|
id = global_textures["cloud_texture_id"];
|
|
if(id.notNull())
|
|
{
|
|
gCloudTextureID = id;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// 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())
|
|
{
|
|
gSavedSettings.setString("AgentAppearanceServiceURL", agent_appearance_url);
|
|
}
|
|
|
|
// Override grid info with anything sent in the login response
|
|
std::string tmp = response["gridname"].asString();
|
|
if (!tmp.empty()) grid.setGridName(tmp);
|
|
tmp = response["loginuri"].asString();
|
|
if (!tmp.empty()) grid.setLoginUri(tmp);
|
|
tmp = response["welcome"].asString();
|
|
if (!tmp.empty()) grid.setLoginPage(tmp);
|
|
tmp = response["loginpage"].asString();
|
|
if (!tmp.empty()) grid.setLoginPage(tmp);
|
|
tmp = response["economy"].asString();
|
|
if (!tmp.empty()) grid.setHelperUri(tmp);
|
|
tmp = response["helperuri"].asString();
|
|
if (!tmp.empty()) grid.setHelperUri(tmp);
|
|
tmp = response["about"].asString();
|
|
if (!tmp.empty()) grid.setWebSite(tmp);
|
|
tmp = response["website"].asString();
|
|
if (!tmp.empty()) grid.setWebSite(tmp);
|
|
tmp = response["help"].asString();
|
|
if (!tmp.empty()) grid.setSupportUrl(tmp);
|
|
tmp = response["support"].asString();
|
|
if (!tmp.empty()) grid.setSupportUrl(tmp);
|
|
tmp = response["register"].asString();
|
|
if (!tmp.empty()) grid.setRegisterUrl(tmp);
|
|
tmp = response["account"].asString();
|
|
if (!tmp.empty()) grid.setRegisterUrl(tmp);
|
|
tmp = response["password"].asString();
|
|
if (!tmp.empty()) grid.setPasswordUrl(tmp);
|
|
tmp = response["search"].asString();
|
|
if (!tmp.empty()) grid.setSearchUrl(tmp);
|
|
else if (opensim) tmp = grid.getSearchUrl(); // Fallback from grid info response for setting
|
|
if (opensim)
|
|
{
|
|
gSavedSettings.setString("SearchURL", tmp); // Singu Note: For web search purposes, always set this setting
|
|
tmp = response["avatar_picker_url"].asString();
|
|
gSavedSettings.setString("AvatarPickerURL", tmp);
|
|
gMenuBarView->getChildView("Avatar Picker")->setVisible(!tmp.empty());
|
|
gSavedSettings.setString("DestinationGuideURL", response["destination_guide_url"].asString());
|
|
tmp = response["classified_fee"].asString();
|
|
grid.setClassifiedFee(tmp.empty() ? 0 : atoi(tmp.c_str()));
|
|
}
|
|
tmp = response["currency"].asString();
|
|
if (!tmp.empty())
|
|
{
|
|
LLTrans::setDefaultArg("[CURRENCY]", tmp);
|
|
grid.setCurrencySymbol(tmp);
|
|
}
|
|
tmp = response["currency_text"].asString();
|
|
if (!tmp.empty())
|
|
{
|
|
LLTrans::setDefaultArg("[CURRENCY_TEXT]", tmp);
|
|
grid.setCurrencyText(tmp);
|
|
}
|
|
tmp = response["real_currency"].asString();
|
|
if (!tmp.empty()) grid.setRealCurrencySymbol(tmp);
|
|
tmp = response["directory_fee"].asString();
|
|
if (!tmp.empty()) grid.setDirectoryFee(atoi(tmp.c_str()));
|
|
if (mBenefitsSuccessfullyInit)
|
|
tmp = response["VoiceConnector"].asString();
|
|
if (!tmp.empty()) grid.setVoiceConnector(tmp);
|
|
tmp = response["upc_supported"].asString();
|
|
if (!tmp.empty()) grid.setUPCSupported(true);
|
|
if (opensim && !mBenefitsSuccessfullyInit)
|
|
LLAgentBenefitsMgr::instance().initNonSL(response);
|
|
gHippoGridManager->saveFile();
|
|
gHippoLimits->setLimits();
|
|
|
|
// 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::openIDSetup(openid_url, openid_token);
|
|
}
|
|
|
|
bool success = false;
|
|
// JC: gesture loading done below, when we have an asset system
|
|
// in place. Don't delete/clear user_credentials until then.
|
|
|
|
if(gAgentID.notNull()
|
|
&& gAgentSessionID.notNull()
|
|
&& gMessageSystem->mOurCircuitCode
|
|
&& gFirstSim.isOk()
|
|
&& gInventory.getRootFolderID().notNull())
|
|
{
|
|
success = true;
|
|
}
|
|
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);
|
|
}
|
|
|