Files
SingularityViewer/indra/newview/llpanellogin.cpp
Aleric Inglewood 6f8ea87c46 Add ResponderHeadersOnly.
ResponderHeadersOnly is a base class for responders that use
HTTPClient::head or HTTPClient::getHeaderOnly. It already
has a needsHeaders() that return true and only allows for
completedHeaders to be overridden.

I removed the CURLOPT_HEADER option for these cases, because
that only causes the headers to be send to the writeCallback
as if they are part of the body, in addition to the headerCallback;
That gave raise to some confusion for the existing code (ie,
unexpected errors when trying to decode the body as LLSD and
duplicated 'low speed' information for the Timeout policy code.
2012-11-13 21:46:35 +01:00

1278 lines
34 KiB
C++

/**
* @file llpanellogin.cpp
* @brief Login dialog and logo display
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-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 "llpanellogin.h"
#include "llpanelgeneral.h"
#include "hippogridmanager.h"
#include "indra_constants.h" // for key and mask constants
#include "llfontgl.h"
#include "llmd5.h"
#include "llsecondlifeurls.h"
#include "sgversion.h"
#include "v4color.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llcommandhandler.h" // for secondlife:///app/login/
#include "llcombobox.h"
#include "llviewercontrol.h"
#include "llfloaterabout.h"
#include "llfloatertest.h"
#include "llfloaterpreference.h"
#include "llfocusmgr.h"
#include "lllineeditor.h"
#include "llnotificationsutil.h"
#include "llstartup.h"
#include "lltextbox.h"
#include "llui.h"
#include "lluiconstants.h"
#include "llurlhistory.h" // OGPX : regionuri text box has a history of region uris (if FN/LN are loaded at startup)
#include "llurlsimstring.h"
#include "llviewerbuild.h"
#include "llviewertexturelist.h"
#include "llviewermenu.h" // for handle_preferences()
#include "llviewernetwork.h"
#include "llviewerwindow.h" // to link into child list
#include "llnotify.h"
#include "llurlsimstring.h"
#include "lluictrlfactory.h"
#include "llhttpclient.h"
#include "llweb.h"
#include "llmediactrl.h"
#include "llfloatermediabrowser.h"
#include "llfloatertos.h"
#include "llglheaders.h"
// [RLVa:KB]
#include "rlvhandler.h"
// [/RLVa:KB]
// <edit>
#include "llappviewer.h"
#include "llspinctrl.h"
#include "llviewermessage.h"
#include <boost/lexical_cast.hpp>
// </edit>
#include <boost/algorithm/string.hpp>
#include "llstring.h"
#include <cctype>
#define USE_VIEWER_AUTH 0
class AIHTTPTimeoutPolicy;
extern AIHTTPTimeoutPolicy iamHereLogin_timeout;
const S32 BLACK_BORDER_HEIGHT = 160;
const S32 MAX_PASSWORD = 16;
LLPanelLogin *LLPanelLogin::sInstance = NULL;
BOOL LLPanelLogin::sCapslockDidNotification = FALSE;
static bool nameSplit(const std::string& full, std::string& first, std::string& last) {
std::vector<std::string> fragments;
boost::algorithm::split(fragments, full, boost::is_any_of(" ."));
if (!fragments.size() || !fragments[0].length())
return false;
first = fragments[0];
if (fragments.size() == 1)
{
if (gHippoGridManager->getConnectedGrid()->isSecondLife())
last = "Resident";
else
last = "";
}
else
last = fragments[1];
return (fragments.size() <= 2);
}
static std::string nameJoin(const std::string& first,const std::string& last, bool strip_resident) {
if (last.empty() || (strip_resident && boost::algorithm::iequals(last, "Resident")))
return first;
else {
if(std::islower(last[0]))
return first + "." + last;
else
return first + " " + last;
}
}
static std::string getDisplayString(const std::string& first, const std::string& last, const std::string& grid, bool is_secondlife) {
if(grid == gHippoGridManager->getDefaultGridNick())
return nameJoin(first, last, is_secondlife);
else
return nameJoin(first, last, is_secondlife) + " (" + grid + ")";
}
static std::string getDisplayString(const LLSavedLoginEntry& entry) {
return getDisplayString(entry.getFirstName(), entry.getLastName(), entry.getGrid(), entry.isSecondLife());
}
class LLLoginRefreshHandler : public LLCommandHandler
{
public:
// don't allow from external browsers
LLLoginRefreshHandler() : LLCommandHandler("login_refresh", true) { }
bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)
{
if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)
{
LLPanelLogin::loadLoginPage();
}
return true;
}
};
LLLoginRefreshHandler gLoginRefreshHandler;
// <edit>
std::string gFullName;
// </edit>
// helper class that trys to download a URL from a web site and calls a method
// on parent class indicating if the web server is working or not
class LLIamHereLogin : public LLHTTPClient::ResponderHeadersOnly
{
private:
LLIamHereLogin( LLPanelLogin* parent ) :
mParent( parent )
{}
LLPanelLogin* mParent;
public:
static boost::intrusive_ptr< LLIamHereLogin > build( LLPanelLogin* parent )
{
return boost::intrusive_ptr< LLIamHereLogin >( new LLIamHereLogin( parent ) );
};
virtual void setParent( LLPanelLogin* parentIn )
{
mParent = parentIn;
};
/*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers)
{
if (mParent)
{
mParent->setSiteIsAlive(200 <= status && status < 300);
}
}
virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return iamHereLogin_timeout; }
};
// this is global and not a class member to keep crud out of the header file
namespace {
boost::intrusive_ptr< LLIamHereLogin > gResponsePtr = 0;
};
void set_start_location(LLUICtrl* ctrl, void* data)
{
LLURLSimString::setString(ctrl->getValue().asString());
}
//---------------------------------------------------------------------------
// Public methods
//---------------------------------------------------------------------------
LLPanelLogin::LLPanelLogin(const LLRect &rect,
void (*callback)(S32 option, void* user_data),
void *cb_data)
: LLPanel(std::string("panel_login"), LLRect(0,600,800,0), FALSE), // not bordered
mLogoImage(),
mCallback(callback),
mCallbackData(cb_data),
mHtmlAvailable( TRUE )
{
setFocusRoot(TRUE);
setBackgroundVisible(FALSE);
setBackgroundOpaque(TRUE);
// instance management
if (LLPanelLogin::sInstance)
{
llwarns << "Duplicate instance of login view deleted" << llendl;
delete LLPanelLogin::sInstance;
// Don't leave bad pointer in gFocusMgr
gFocusMgr.setDefaultKeyboardFocus(NULL);
}
LLPanelLogin::sInstance = this;
// add to front so we are the bottom-most child
gViewerWindow->getRootView()->addChildInBack(this);
// Logo
mLogoImage = LLUI::getUIImage("startup_logo.j2c");
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_login.xml");
#if USE_VIEWER_AUTH
//leave room for the login menu bar
setRect(LLRect(0, rect.getHeight()-18, rect.getWidth(), 0));
#endif
reshape(rect.getWidth(), rect.getHeight());
#if !USE_VIEWER_AUTH
LLComboBox* name_combo = sInstance->getChild<LLComboBox>("name_combo");
name_combo->setCommitCallback(onSelectLoginEntry);
name_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLoginComboLostFocus, this, name_combo));
name_combo->setPrevalidate(LLLineEditor::prevalidatePrintableNotPipe);
name_combo->setSuppressTentative(true);
name_combo->setSuppressAutoComplete(true);
childSetCommitCallback("remember_name_check", onNameCheckChanged);
childSetCommitCallback("password_edit", mungePassword);
childSetKeystrokeCallback("password_edit", onPassKey, this);
childSetUserData("password_edit", this);
// change z sort of clickable text to be behind buttons
sendChildToBack(getChildView("channel_text"));
sendChildToBack(getChildView("forgot_password_text"));
LLLineEditor* edit = getChild<LLLineEditor>("password_edit");
if (edit) edit->setDrawAsterixes(TRUE);
//OGPX : This keeps the uris in a history file
//OGPX TODO: should this be inside an OGP only check?
LLComboBox* regioncombo = getChild<LLComboBox>("regionuri_edit");
regioncombo->setAllowTextEntry(TRUE, 256, FALSE);
std::string current_regionuri = gSavedSettings.getString("CmdLineRegionURI");
// iterate on uri list adding to combobox (couldn't figure out how to add them all in one call)
// ... and also append the command line value we might have gotten to the URLHistory
LLSD regionuri_history = LLURLHistory::getURLHistory("regionuri");
LLSD::array_iterator iter_history = regionuri_history.beginArray();
LLSD::array_iterator iter_end = regionuri_history.endArray();
for (; iter_history != iter_end; ++iter_history)
{
regioncombo->addSimpleElement((*iter_history).asString());
}
if ( LLURLHistory::appendToURLCollection("regionuri",current_regionuri))
{
// since we are in login, another read of urlhistory file is going to happen
// so we need to persist the new value we just added (or maybe we should do it in startup.cpp?)
// since URL history only populated on create of sInstance, add to combo list directly
regioncombo->addSimpleElement(current_regionuri);
}
// select which is displayed if we have a current URL.
regioncombo->setSelectedByValue(LLSD(current_regionuri),TRUE);
//llinfos << " url history: " << LLSDOStreamer<LLSDXMLFormatter>(LLURLHistory::getURLHistory("regionuri")) << llendl;
LLComboBox* combo = getChild<LLComboBox>("start_location_combo");
combo->setAllowTextEntry(TRUE, 128, FALSE);
// The XML file loads the combo with the following labels:
// 0 - "My Home"
// 1 - "My Last Location"
// 2 - "<Type region name>"
BOOL login_last = gSavedSettings.getBOOL("LoginLastLocation");
std::string sim_string = LLURLSimString::sInstance.mSimString;
if (!sim_string.empty())
{
// Replace "<Type region name>" with this region name
combo->remove(2);
combo->add( sim_string );
combo->setTextEntry(sim_string);
combo->setCurrentByIndex( 2 );
}
else if (login_last)
{
combo->setCurrentByIndex( 1 );
}
else
{
combo->setCurrentByIndex( 0 );
}
combo->setCommitCallback( &set_start_location );
childSetAction("connect_btn", onClickConnect, this);
setDefaultBtn("connect_btn");
// childSetAction("quit_btn", onClickQuit, this);
childSetAction("grids_btn", onClickGrids, this);
childSetCommitCallback("grids_combo", onSelectGrid, this);
std::string channel = gVersionChannel;
std::string version = llformat("%d.%d.%d (%d)",
gVersionMajor,
gVersionMinor,
gVersionPatch,
LL_VIEWER_BUILD );
LLTextBox* channel_text = getChild<LLTextBox>("channel_text");
channel_text->setTextArg("[CHANNEL]", channel); // though not displayed
channel_text->setTextArg("[VERSION]", version);
channel_text->setClickedCallback(onClickVersion);
channel_text->setCallbackUserData(this);
LLTextBox* forgot_password_text = getChild<LLTextBox>("forgot_password_text");
forgot_password_text->setClickedCallback(onClickForgotPassword);
LLTextBox* create_new_account_text = getChild<LLTextBox>("create_new_account_text");
create_new_account_text->setClickedCallback(onClickNewAccount);
#endif
// get the web browser control
LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
web_browser->addObserver(this);
// Need to handle login secondlife:///app/ URLs
web_browser->setTrusted( true );
// don't make it a tab stop until SL-27594 is fixed
web_browser->setTabStop(FALSE);
// web_browser->navigateToLocalPage( "loading", "loading.html" );
// make links open in external browser
web_browser->setOpenInExternalBrowser( true );
// force the size to be correct (XML doesn't seem to be sufficient to do this) (with some padding so the other login screen doesn't show through)
LLRect htmlRect = getRect();
#if USE_VIEWER_AUTH
htmlRect.setCenterAndSize( getRect().getCenterX() - 2, getRect().getCenterY(), getRect().getWidth() + 6, getRect().getHeight());
#else
htmlRect.setCenterAndSize( getRect().getCenterX() - 2, getRect().getCenterY() + 40, getRect().getWidth() + 6, getRect().getHeight() - 78 );
#endif
web_browser->setRect( htmlRect );
web_browser->reshape( htmlRect.getWidth(), htmlRect.getHeight(), TRUE );
reshape( getRect().getWidth(), getRect().getHeight(), 1 );
updateGridCombo();
childSetVisible("create_new_account_text",
!gHippoGridManager->getConnectedGrid()->getRegisterUrl().empty());
childSetVisible("forgot_password_text",
!gHippoGridManager->getConnectedGrid()->getPasswordUrl().empty());
loadLoginPage();
#if !USE_VIEWER_AUTH
// Initialize visibility (and don't force visibility - use prefs)
refreshLocation( false );
#endif
}
void LLPanelLogin::setSiteIsAlive( bool alive )
{
LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
// if the contents of the site was retrieved
if ( alive )
{
if ( web_browser )
{
loadLoginPage();
web_browser->setVisible(true);
// mark as available
mHtmlAvailable = TRUE;
}
}
else
// the site is not available (missing page, server down, other badness)
{
#if !USE_VIEWER_AUTH
if ( web_browser )
{
// hide browser control (revealing default one)
web_browser->setVisible( FALSE );
// mark as unavailable
mHtmlAvailable = FALSE;
}
#else
if ( web_browser )
{
web_browser->navigateToLocalPage( "loading-error" , "index.html" );
// mark as available
mHtmlAvailable = TRUE;
}
#endif
}
}
void LLPanelLogin::mungePassword(LLUICtrl* caller, void* user_data)
{
LLPanelLogin* self = (LLPanelLogin*)user_data;
LLLineEditor* editor = (LLLineEditor*)caller;
std::string password = editor->getText();
// Re-md5 if we've changed at all
if (password != self->mIncomingPassword)
{
LLMD5 pass((unsigned char *)password.c_str());
char munged_password[MD5HEX_STR_SIZE];
pass.hex_digest(munged_password);
self->mMungedPassword = munged_password;
}
}
LLPanelLogin::~LLPanelLogin()
{
LLPanelLogin::sInstance = NULL;
// tell the responder we're not here anymore
if ( gResponsePtr )
gResponsePtr->setParent( 0 );
//// We know we're done with the image, so be rid of it.
//gTextureList.deleteImage( mLogoImage );
if ( gFocusMgr.getDefaultKeyboardFocus() == this )
{
gFocusMgr.setDefaultKeyboardFocus(NULL);
}
}
void LLPanelLogin::setLoginHistory(LLSavedLogins const& login_history)
{
sInstance->mLoginHistoryData = login_history;
LLComboBox* login_combo = sInstance->getChild<LLComboBox>("name_combo");
llassert(login_combo);
login_combo->clear();
LLSavedLoginsList const& saved_login_entries(login_history.getEntries());
for (LLSavedLoginsList::const_reverse_iterator i = saved_login_entries.rbegin();
i != saved_login_entries.rend(); ++i)
{
LLSD e = i->asLLSD();
if (e.isMap() && gHippoGridManager->getGrid(i->getGrid()))
login_combo->add(getDisplayString(*i), e);
}
}
// virtual
void LLPanelLogin::draw()
{
gGL.pushMatrix();
{
F32 image_aspect = 1.333333f;
F32 view_aspect = (F32)getRect().getWidth() / (F32)getRect().getHeight();
// stretch image to maintain aspect ratio
if (image_aspect > view_aspect)
{
gGL.translatef(-0.5f * (image_aspect / view_aspect - 1.f) * getRect().getWidth(), 0.f, 0.f);
gGL.scalef(image_aspect / view_aspect, 1.f, 1.f);
}
S32 width = getRect().getWidth();
S32 height = getRect().getHeight();
if ( mHtmlAvailable )
{
#if !USE_VIEWER_AUTH
// draw a background box in black
gl_rect_2d( 0, height - 264, width, 264, LLColor4( 0.0f, 0.0f, 0.0f, 1.f ) );
// draw the bottom part of the background image - just the blue background to the native client UI
mLogoImage->draw(0, -264, width + 8, mLogoImage->getHeight());
#endif
}
else
{
// the HTML login page is not available so default to the original screen
S32 offscreen_part = height / 3;
mLogoImage->draw(0, -offscreen_part, width, height+offscreen_part);
};
}
gGL.popMatrix();
LLPanel::draw();
}
// virtual
BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask)
{
if (( KEY_RETURN == key ) && (MASK_ALT == mask))
{
gViewerWindow->toggleFullscreen(FALSE);
return TRUE;
}
if (('P' == key) && (MASK_CONTROL == mask))
{
LLFloaterPreference::show(NULL);
return TRUE;
}
if (('T' == key) && (MASK_CONTROL == mask))
{
new LLFloaterSimple("floater_test.xml");
return TRUE;
}
if ( KEY_F1 == key )
{
llinfos << "Spawning HTML help window" << llendl;
gViewerHtmlHelp.show();
return TRUE;
}
# if !LL_RELEASE_FOR_DOWNLOAD
if ( KEY_F2 == key )
{
llinfos << "Spawning floater TOS window" << llendl;
LLFloaterTOS* tos_dialog = LLFloaterTOS::show(LLFloaterTOS::TOS_TOS,"");
tos_dialog->startModal();
return TRUE;
}
#endif
if (KEY_RETURN == key && MASK_NONE == mask)
{
// let the panel handle UICtrl processing: calls onClickConnect()
return LLPanel::handleKeyHere(key, mask);
}
return LLPanel::handleKeyHere(key, mask);
}
// virtual
void LLPanelLogin::setFocus(BOOL b)
{
if(b != hasFocus())
{
if(b)
{
LLPanelLogin::giveFocus();
}
else
{
LLPanel::setFocus(b);
}
}
}
// static
void LLPanelLogin::giveFocus()
{
#if USE_VIEWER_AUTH
if (sInstance)
{
sInstance->setFocus(TRUE);
}
#else
if( sInstance )
{
// Grab focus and move cursor to first blank input field
std::string first = sInstance->getChild<LLComboBox>("name_combo")->getTextEntry();
std::string pass = sInstance->childGetText("password_edit");
BOOL have_first = !first.empty();
BOOL have_pass = !pass.empty();
if (!have_first)
{
// User doesn't have a name, so start there.
LLComboBox* combo = sInstance->getChild<LLComboBox>("name_combo");
combo->setFocusText(TRUE);
}
else if (!have_pass)
{
LLLineEditor* edit = NULL;
// User saved his name but not his password. Move
// focus to password field.
edit = sInstance->getChild<LLLineEditor>("password_edit");
edit->setFocus(TRUE);
edit->selectAll();
}
else
{
// else, we have both name and password.
// We get here waiting for the login to happen.
LLButton* connect_btn = sInstance->getChild<LLButton>("connect_btn");
connect_btn->setFocus(TRUE);
}
}
#endif
}
// static
void LLPanelLogin::show(const LLRect &rect,
void (*callback)(S32 option, void* user_data),
void* callback_data)
{
new LLPanelLogin(rect, callback, callback_data);
if( !gFocusMgr.getKeyboardFocus() )
{
// Grab focus and move cursor to first enabled control
sInstance->setFocus(TRUE);
}
// Make sure that focus always goes here (and use the latest sInstance that was just created)
gFocusMgr.setDefaultKeyboardFocus(sInstance);
}
// static
void LLPanelLogin::setFields(const std::string& firstname,
const std::string& lastname,
const std::string& password)
{
if (!sInstance)
{
llwarns << "Attempted fillFields with no login view shown" << llendl;
return;
}
LLComboBox* login_combo = sInstance->getChild<LLComboBox>("name_combo");
llassert_always(firstname.find(' ') == std::string::npos);
login_combo->setLabel(nameJoin(firstname, lastname, false));
// Max "actual" password length is 16 characters.
// Hex digests are always 32 characters.
if (password.length() == 32)
{
// This is a MD5 hex digest of a password.
// We don't actually use the password input field,
// fill it with MAX_PASSWORD characters so we get a
// nice row of asterixes.
const std::string filler("123456789!123456");
sInstance->childSetText("password_edit", filler);
sInstance->mIncomingPassword = filler;
sInstance->mMungedPassword = password;
}
else
{
// this is a normal text password
sInstance->childSetText("password_edit", password);
sInstance->mIncomingPassword = password;
LLMD5 pass((unsigned char *)password.c_str());
char munged_password[MD5HEX_STR_SIZE];
pass.hex_digest(munged_password);
sInstance->mMungedPassword = munged_password;
}
}
// static
void LLPanelLogin::setFields(const LLSavedLoginEntry& entry, bool takeFocus)
{
if (!sInstance)
{
llwarns << "Attempted setFields with no login view shown" << llendl;
return;
}
LLCheckBoxCtrl* remember_pass_check = sInstance->getChild<LLCheckBoxCtrl>("remember_check");
std::string fullname = nameJoin(entry.getFirstName(), entry.getLastName(), entry.isSecondLife());
LLComboBox* login_combo = sInstance->getChild<LLComboBox>("name_combo");
login_combo->setTextEntry(fullname);
login_combo->resetTextDirty();
//sInstance->childSetText("name_combo", fullname);
std::string grid = entry.getGrid();
if(!grid.empty() && gHippoGridManager->getGrid(grid) && grid != gHippoGridManager->getCurrentGridNick()) {
gHippoGridManager->setCurrentGrid(grid);
LLPanelLogin::refreshLoginPage();
}
if (entry.getPassword().empty())
{
sInstance->childSetText("password_edit", std::string(""));
remember_pass_check->setValue(LLSD(false));
}
else
{
const std::string filler("123456789!123456");
sInstance->childSetText("password_edit", filler);
sInstance->mIncomingPassword = filler;
sInstance->mMungedPassword = entry.getPassword();
remember_pass_check->setValue(LLSD(true));
}
if (takeFocus)
{
giveFocus();
}
}
// static
void LLPanelLogin::getFields(std::string *firstname,
std::string *lastname,
std::string *password)
{
if (!sInstance)
{
llwarns << "Attempted getFields with no login view shown" << llendl;
return;
}
nameSplit(sInstance->getChild<LLComboBox>("name_combo")->getTextEntry(), *firstname, *lastname);
LLStringUtil::trim(*firstname);
LLStringUtil::trim(*lastname);
*password = sInstance->mMungedPassword;
}
// static
void LLPanelLogin::getLocation(std::string &location)
{
if (!sInstance)
{
llwarns << "Attempted getLocation with no login view shown" << llendl;
return;
}
LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
location = combo->getValue().asString();
}
// static
void LLPanelLogin::refreshLocation( bool force_visible )
{
if (!sInstance) return;
#if USE_VIEWER_AUTH
loadLoginPage();
#else
LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
if (LLURLSimString::parse())
{
combo->setCurrentByIndex( 3 ); // BUG? Maybe 2?
combo->setTextEntry(LLURLSimString::sInstance.mSimString);
}
else
{
BOOL login_last = gSavedSettings.getBOOL("LoginLastLocation");
combo->setCurrentByIndex( login_last ? 1 : 0 );
}
BOOL show_start = TRUE;
if ( ! force_visible )
show_start = gSavedSettings.getBOOL("ShowStartLocation");
// [RLVa:KB] - Alternate: Snowglobe-1.2.4 | Checked: 2009-07-08 (RLVa-1.0.0e)
// TODO-RLVa: figure out some way to make this work with RLV_EXTENSION_STARTLOCATION
#ifndef RLV_EXTENSION_STARTLOCATION
if (rlv_handler_t::isEnabled())
{
show_start = FALSE;
}
#endif // RLV_EXTENSION_STARTLOCATION
// [/RLVa:KB]
sInstance->childSetVisible("start_location_combo", show_start); // maintain ShowStartLocation if legacy
sInstance->childSetVisible("start_location_text", show_start);
sInstance->childSetVisible("regionuri_edit",FALSE); // Do Not show regionuri box if legacy
#endif
}
// static
void LLPanelLogin::close()
{
if (sInstance)
{
gViewerWindow->getRootView()->removeChild( LLPanelLogin::sInstance );
gFocusMgr.setDefaultKeyboardFocus(NULL);
delete sInstance;
sInstance = NULL;
}
}
// static
void LLPanelLogin::setAlwaysRefresh(bool refresh)
{
if (LLStartUp::getStartupState() >= STATE_LOGIN_CLEANUP) return;
LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
if (web_browser)
{
web_browser->setAlwaysRefresh(refresh);
}
}
void LLPanelLogin::updateGridCombo()
{
const std::string &defaultGrid = gHippoGridManager->getDefaultGridNick();
const std::string &currentGrid = gHippoGridManager->getCurrentGridNick();
LLComboBox *grids = getChild<LLComboBox>("grids_combo");
S32 selectIndex = -1, i = 0;
grids->removeall();
if (defaultGrid != "") {
grids->add(defaultGrid);
selectIndex = i++;
}
HippoGridManager::GridIterator it, end = gHippoGridManager->endGrid();
for (it = gHippoGridManager->beginGrid(); it != end; ++it) {
std::string grid = it->second->getGridName();
if (grid != defaultGrid) {
grids->add(grid);
if (grid == currentGrid) selectIndex = i;
i++;
}
}
if (selectIndex >= 0) {
grids->setCurrentByIndex(selectIndex);
} else {
grids->setLabel(LLStringExplicit("")); // LLComboBox::removeall() does not clear the label
}
}
// static
void LLPanelLogin::refreshLoginPage()
{
if (!sInstance || (LLStartUp::getStartupState() >= STATE_LOGIN_CLEANUP))
return;
sInstance->updateGridCombo();
sInstance->childSetVisible("create_new_account_text",
!gHippoGridManager->getConnectedGrid()->getRegisterUrl().empty());
sInstance->childSetVisible("forgot_password_text",
!gHippoGridManager->getConnectedGrid()->getPasswordUrl().empty());
// kick off a request to grab the url manually
gResponsePtr = LLIamHereLogin::build(sInstance);
std::string login_page = gHippoGridManager->getConnectedGrid()->getLoginPage();
if (!login_page.empty()) {
LLHTTPClient::head(login_page, gResponsePtr.get());
} else {
sInstance->setSiteIsAlive(false);
}
}
void LLPanelLogin::loadLoginPage()
{
if (!sInstance) return;
sInstance->updateGridCombo();
std::ostringstream oStr;
std::string login_page = gHippoGridManager->getConnectedGrid()->getLoginPage();
if (login_page.empty())
{
sInstance->setSiteIsAlive(false);
return;
}
oStr << login_page;
// Use the right delimeter depending on how LLURI parses the URL
LLURI login_page_uri = LLURI(login_page);
std::string first_query_delimiter = "&";
if (login_page_uri.queryMap().size() == 0)
{
first_query_delimiter = "?";
}
// Language
std::string language = LLUI::getLanguage();
oStr << first_query_delimiter<<"lang=" << language;
// First Login?
if (gSavedSettings.getBOOL("FirstLoginThisInstall"))
{
oStr << "&firstlogin=TRUE";
}
std::string version = llformat("%d.%d.%d (%d)",
gVersionMajor, gVersionMinor, gVersionPatch, gVersionBuild);
if(login_page.find("secondlife.com") == -1) {
oStr << "&channel=" << LLWeb::curlEscape(gVersionChannel);
oStr << "&version=" << LLWeb::curlEscape(version);
}
// Grid
if (gHippoGridManager->getConnectedGrid()->isSecondLife()) {
// find second life grid from login URI
// yes, this is heuristic, but hey, it is just to get the right login page...
std::string tmp = gHippoGridManager->getConnectedGrid()->getLoginUri();
int i = tmp.find(".lindenlab.com");
if (i != std::string::npos) {
tmp = tmp.substr(0, i);
i = tmp.rfind('.');
if (i == std::string::npos)
i = tmp.rfind('/');
if (i != std::string::npos) {
tmp = tmp.substr(i+1);
oStr << "&grid=" << LLWeb::curlEscape(tmp);
}
}
}
else if (gHippoGridManager->getConnectedGrid()->isOpenSimulator()){
oStr << "&grid=" << gHippoGridManager->getConnectedGrid()->getGridNick();
}
else if (gHippoGridManager->getConnectedGrid()->getPlatform() == HippoGridInfo::PLATFORM_AURORA)
{
oStr << "&grid=" << LLWeb::curlEscape(LLViewerLogin::getInstance()->getGridLabel());
}
gViewerWindow->setMenuBackgroundColor(false, !LLViewerLogin::getInstance()->isInProductionGrid());
gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor());
#if USE_VIEWER_AUTH
LLURLSimString::sInstance.parse();
std::string location;
std::string region;
std::string password;
if (LLURLSimString::parse())
{
std::ostringstream oRegionStr;
location = "specify";
oRegionStr << LLURLSimString::sInstance.mSimName << "/" << LLURLSimString::sInstance.mX << "/"
<< LLURLSimString::sInstance.mY << "/"
<< LLURLSimString::sInstance.mZ;
region = oRegionStr.str();
}
else
{
if (gSavedSettings.getBOOL("LoginLastLocation"))
{
location = "last";
}
else
{
location = "home";
}
}
std::string firstname, lastname;
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();
password = cmd_line_login[2].asString();
}
if (firstname.empty())
{
firstname = gSavedSettings.getString("FirstName");
}
if (lastname.empty())
{
lastname = gSavedSettings.getString("LastName");
}
std::string curl_region = LLWeb::curlEscape(region);
oStr <<"firstname=" << firstname <<
"&lastname=" << lastname << "&location=" << location << "&region=" << curl_region;
if (!password.empty())
{
oStr << "&password=" << password;
}
else if (!(password = load_password_from_disk()).empty())
{
oStr << "&password=$1$" << password;
}
if (gAutoLogin)
{
oStr << "&auto_login=TRUE";
}
if (gSavedSettings.getBOOL("ShowStartLocation"))
{
oStr << "&show_start_location=TRUE";
}
if (gSavedSettings.getBOOL("RememberPassword"))
{
oStr << "&remember_password=TRUE";
}
BOOL show_server = sInstance ? sInstance->mShowServerCombo : FALSE;
if (show_server || gSavedSettings.getBOOL("ForceShowGrid"))
{
oStr << "&show_grid=TRUE";
}
#endif
LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
// navigate to the "real" page
web_browser->navigateTo( oStr.str(), "text/html" );
}
void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event)
{
if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
{
LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
if (web_browser)
{
// *HACK HACK HACK HACK!
/* Stuff a Tab key into the browser now so that the first field will
** get the focus! The embedded javascript on the page that properly
** sets the initial focus in a real web browser is not working inside
** the viewer, so this is an UGLY HACK WORKAROUND for now.
*/
// Commented out as it's not reliable
//web_browser->handleKey(KEY_TAB, MASK_NONE, false);
}
}
}
bool LLPanelLogin::getRememberLogin()
{
bool remember = false;
if (sInstance)
{
LLCheckBoxCtrl* remember_login = sInstance->getChild<LLCheckBoxCtrl>("remember_name_check");
if (remember_login)
{
remember = remember_login->getValue().asBoolean();
}
}
else
{
llwarns << "Attempted to query rememberLogin with no login view shown" << llendl;
}
return remember;
}
//---------------------------------------------------------------------------
// Protected methods
//---------------------------------------------------------------------------
// static
void LLPanelLogin::onClickConnect(void *)
{
if (sInstance && sInstance->mCallback)
{
// tell the responder we're not here anymore
if ( gResponsePtr )
gResponsePtr->setParent( 0 );
// JC - Make sure the fields all get committed.
sInstance->setFocus(FALSE);
std::string first, last, password;
if (nameSplit(sInstance->getChild<LLComboBox>("name_combo")->getTextEntry(), first, last))
{
// has both first and last name typed
sInstance->mCallback(0, sInstance->mCallbackData);
}
else
{
if (gHippoGridManager->getConnectedGrid()->getRegisterUrl().empty()) {
LLNotificationsUtil::add("MustHaveAccountToLogInNoLinks");
} else {
LLNotificationsUtil::add("MustHaveAccountToLogIn", LLSD(), LLSD(),
LLPanelLogin::newAccountAlertCallback);
}
}
}
}
// static
bool LLPanelLogin::newAccountAlertCallback(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotification::getSelectedOption(notification, response);
if (0 == option)
{
llinfos << "Going to account creation URL" << llendl;
LLWeb::loadURLExternal( CREATE_ACCOUNT_URL );
}
else
{
sInstance->setFocus(TRUE);
}
return false;
}
// static
void LLPanelLogin::onClickNewAccount(void*)
{
const std::string &url = gHippoGridManager->getConnectedGrid()->getRegisterUrl();
if (!url.empty()) {
llinfos << "Going to account creation URL." << llendl;
LLWeb::loadURLExternal(url);
} else {
llinfos << "Account creation URL is empty." << llendl;
sInstance->setFocus(TRUE);
}
}
// static
void LLPanelLogin::onClickGrids(void*)
{
//LLFloaterPreference::overrideLastTab(LLPreferenceCore::TAB_GRIDS);
LLFloaterPreference::show(NULL);
LLFloaterPreference::switchTab(LLPreferenceCore::TAB_GRIDS);
}
// static
void LLPanelLogin::onSelectGrid(LLUICtrl *ctrl, void*)
{
gHippoGridManager->setCurrentGrid(ctrl->getValue());
LLPanelLogin::refreshLoginPage();
}
// *NOTE: This function is dead as of 2008 August. I left it here in case
// we suddenly decide to put the Quit button back. JC
// static
void LLPanelLogin::onClickQuit(void*)
{
if (sInstance && sInstance->mCallback)
{
// tell the responder we're not here anymore
if ( gResponsePtr )
gResponsePtr->setParent( 0 );
sInstance->mCallback(1, sInstance->mCallbackData);
}
}
// static
void LLPanelLogin::onClickVersion(void*)
{
LLFloaterAbout::show(NULL);
}
//static
void LLPanelLogin::onClickForgotPassword(void*)
{
if (sInstance )
{
const std::string &url = gHippoGridManager->getConnectedGrid()->getPasswordUrl();
if (!url.empty()) {
LLWeb::loadURLExternal(url);
} else {
llwarns << "Link for 'forgotton password' not set." << llendl;
}
}
}
// static
void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)
{
if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE)
{
LLNotificationsUtil::add("CapsKeyOn");
sCapslockDidNotification = TRUE;
}
}
// static
void LLPanelLogin::onSelectLoginEntry(LLUICtrl* ctrl, void* data)
{
if (sInstance)
{
LLComboBox* combo = sInstance->getChild<LLComboBox>("name_combo");
if (ctrl == combo)
{
LLSD selected_entry = combo->getSelectedValue();
if (!selected_entry.isUndefined())
{
LLSavedLoginEntry entry(selected_entry);
setFields(entry);
}
// This stops the automatic matching of the first name to a selected grid.
LLViewerLogin::getInstance()->setNameEditted(true);
}
}
}
void LLPanelLogin::onLoginComboLostFocus(LLComboBox* combo_box)
{
if(combo_box->isTextDirty())
{
clearPassword();
combo_box->resetTextDirty();
}
}
// static
void LLPanelLogin::onNameCheckChanged(LLUICtrl* ctrl, void* data)
{
if (sInstance)
{
LLCheckBoxCtrl* remember_login_check = sInstance->getChild<LLCheckBoxCtrl>("remember_name_check");
LLCheckBoxCtrl* remember_pass_check = sInstance->getChild<LLCheckBoxCtrl>("remember_check");
if (remember_login_check && remember_pass_check)
{
if (remember_login_check->getValue().asBoolean())
{
remember_pass_check->setEnabled(true);
}
else
{
remember_pass_check->setValue(LLSD(false));
remember_pass_check->setEnabled(false);
}
}
}
}
// static
void LLPanelLogin::clearPassword()
{
std::string blank;
sInstance->childSetText("password_edit", blank);
sInstance->mIncomingPassword = blank;
sInstance->mMungedPassword = blank;
}