00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llpanellogin.h"
00035 #include "llpanelgeneral.h"
00036
00037 #include "indra_constants.h"
00038 #include "llfontgl.h"
00039 #include "llmd5.h"
00040 #include "llsecondlifeurls.h"
00041 #include "llwindow.h"
00042 #include "llversionviewer.h"
00043 #include "v4color.h"
00044
00045 #include "llbutton.h"
00046 #include "llcheckboxctrl.h"
00047 #include "llcombobox.h"
00048 #include "llviewercontrol.h"
00049 #include "llfloaterabout.h"
00050 #include "llfloatertest.h"
00051 #include "llfloaterpreference.h"
00052 #include "llfloaterproject.h"
00053 #include "llfocusmgr.h"
00054 #include "lllineeditor.h"
00055 #include "lltextbox.h"
00056 #include "llui.h"
00057 #include "lluiconstants.h"
00058 #include "llurlsimstring.h"
00059 #include "llviewerbuild.h"
00060 #include "llviewerimagelist.h"
00061 #include "llviewermenu.h"
00062 #include "llviewernetwork.h"
00063 #include "llviewerwindow.h"
00064 #include "llnotify.h"
00065 #include "viewer.h"
00066 #include "llvieweruictrlfactory.h"
00067 #include "llhttpclient.h"
00068 #include "llweb.h"
00069 #include "llwebbrowserctrl.h"
00070
00071 #include "llfloaterhtmlhelp.h"
00072 #include "llfloatertos.h"
00073
00074 #include "llglheaders.h"
00075
00076 const S32 BLACK_BORDER_HEIGHT = 160;
00077 const S32 MAX_PASSWORD = 16;
00078
00079 LLPanelLogin *LLPanelLogin::sInstance = NULL;
00080 BOOL LLPanelLogin::sCapslockDidNotification = FALSE;
00081
00082
00083
00084 class LLIamHereLogin : public LLHTTPClient::Responder
00085 {
00086 private:
00087 LLIamHereLogin( LLPanelLogin* parent ) :
00088 mParent( parent )
00089 {}
00090
00091 LLPanelLogin* mParent;
00092
00093 public:
00094 static boost::intrusive_ptr< LLIamHereLogin > build( LLPanelLogin* parent )
00095 {
00096 return boost::intrusive_ptr< LLIamHereLogin >( new LLIamHereLogin( parent ) );
00097 };
00098
00099 virtual void setParent( LLPanelLogin* parentIn )
00100 {
00101 mParent = parentIn;
00102 };
00103
00104 virtual void result( const LLSD& content )
00105 {
00106 if ( mParent )
00107 mParent->setSiteIsAlive( true );
00108 };
00109
00110 virtual void error( U32 status, const std::string& reason )
00111 {
00112 if ( mParent )
00113 mParent->setSiteIsAlive( false );
00114 };
00115 };
00116
00117
00118 namespace {
00119 boost::intrusive_ptr< LLIamHereLogin > gResponsePtr = 0;
00120 };
00121
00122
00123
00124
00125 LLPanelLogin::LLPanelLogin(const LLRect &rect,
00126 BOOL show_server,
00127 void (*callback)(S32 option, void* user_data),
00128 void *cb_data)
00129 : LLPanel("panel_login", LLRect(0,600,800,0), FALSE),
00130 mLogoImage(),
00131 mCallback(callback),
00132 mCallbackData(cb_data),
00133 mHtmlAvailable( TRUE )
00134 {
00135 mIsFocusRoot = TRUE;
00136
00137 setBackgroundVisible(FALSE);
00138 setBackgroundOpaque(TRUE);
00139
00140
00141 if (LLPanelLogin::sInstance)
00142 {
00143 llwarns << "Duplicate instance of login view deleted" << llendl;
00144 delete LLPanelLogin::sInstance;
00145
00146
00147 gFocusMgr.setDefaultKeyboardFocus(NULL);
00148 }
00149
00150 LLPanelLogin::sInstance = this;
00151
00152
00153 gViewerWindow->getRootView()->addChildAtEnd(this);
00154
00155
00156 mLogoImage = gImageList.getImage("startup_logo.tga", LLUUID::null, MIPMAP_FALSE, TRUE);
00157
00158 gUICtrlFactory->buildPanel(this, "panel_login.xml");
00159 setRect(rect);
00160 reshape(rect.getWidth(), rect.getHeight());
00161
00162 childSetPrevalidate("first_name_edit", LLLineEditor::prevalidatePrintableNoSpace);
00163 childSetPrevalidate("last_name_edit", LLLineEditor::prevalidatePrintableNoSpace);
00164
00165 childSetCommitCallback("password_edit", mungePassword);
00166 childSetKeystrokeCallback("password_edit", onPassKey, this);
00167 childSetUserData("password_edit", this);
00168
00169 LLLineEditor* edit = LLUICtrlFactory::getLineEditorByName(this, "password_edit");
00170 if (edit) edit->setDrawAsterixes(TRUE);
00171
00172 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(this, "start_location_combo");
00173 if (combo)
00174 {
00175 combo->setAllowTextEntry(TRUE, 128, FALSE);
00176
00177
00178
00179
00180
00181
00182 BOOL login_last = gSavedSettings.getBOOL("LoginLastLocation");
00183 LLString sim_string = LLURLSimString::sInstance.mSimString;
00184 if (!sim_string.empty())
00185 {
00186
00187 combo->remove(2);
00188 combo->add( sim_string );
00189 combo->setTextEntry(sim_string);
00190 combo->setCurrentByIndex( 2 );
00191 }
00192 else if (login_last)
00193 {
00194 combo->setCurrentByIndex( 1 );
00195 }
00196 else
00197 {
00198 combo->setCurrentByIndex( 0 );
00199 }
00200
00201 combo->setCommitCallback( &LLPanelGeneral::set_start_location );
00202 }
00203
00204
00205 childSetVisible("server_combo", show_server);
00206
00207 childSetAction("new_account_btn", onClickNewAccount, this);
00208 childSetVisible("new_account_btn", !gHideLinks);
00209
00210 childSetAction("connect_btn", onClickConnect, this);
00211
00212 setDefaultBtn("connect_btn");
00213
00214 childSetAction("preferences_btn", LLFloaterPreference::show, this);
00215
00216 childSetAction("quit_btn", onClickQuit, this);
00217
00218 LLTextBox* text = LLUICtrlFactory::getTextBoxByName(this, "version_text");
00219 if (text)
00220 {
00221 LLString version = llformat("%d.%d.%d (%d) Rev. %d",
00222 LL_VERSION_MAJOR,
00223 LL_VERSION_MINOR,
00224 LL_VERSION_PATCH,
00225 LL_VIEWER_BUILD,
00226 LL_VERSION_REVISION );
00227 text->setText(version);
00228 text->setClickedCallback(onClickVersion);
00229 text->setCallbackUserData(this);
00230
00231
00232
00233 S32 right = getRect().mRight;
00234 LLRect r = text->getRect();
00235 const S32 PAD = 2;
00236 r.setOriginAndSize( right - r.getWidth() - PAD, PAD,
00237 r.getWidth(), r.getHeight() );
00238 text->setRect(r);
00239 }
00240
00241 LLTextBox* channel_text = LLUICtrlFactory::getTextBoxByName(this, "channel_text");
00242 if (channel_text)
00243 {
00244 channel_text->setText(gChannelName);
00245 channel_text->setClickedCallback(onClickVersion);
00246 channel_text->setCallbackUserData(this);
00247
00248
00249
00250 S32 right = getRect().mRight;
00251 LLRect r = channel_text->getRect();
00252 const S32 PAD = 2;
00253 S32 version_string_top = r.mTop;
00254 if(text)
00255 {
00256 version_string_top = text->getRect().mTop;
00257 }
00258 r.setOriginAndSize(
00259 right - r.getWidth() - PAD,
00260 version_string_top,
00261 r.getWidth(),
00262 r.getHeight());
00263 channel_text->setRect(r);
00264 }
00265
00266
00267 #if LL_LIBXUL_ENABLED
00268 LLWebBrowserCtrl* web_browser = LLUICtrlFactory::getWebBrowserCtrlByName(this, "login_html");
00269 if ( web_browser )
00270 {
00271
00272 web_browser->setTabStop(FALSE);
00273
00274
00275 std::string loading_path( gDirUtilp->getExpandedFilename( LL_PATH_SKINS, "" ) );
00276 loading_path.append( gDirUtilp->getDirDelimiter() );
00277 loading_path.append( "html" );
00278 loading_path.append( gDirUtilp->getDirDelimiter() );
00279 loading_path.append( "loading" );
00280 loading_path.append( gDirUtilp->getDirDelimiter() );
00281 loading_path.append( "loading.html" );
00282 web_browser->navigateTo( loading_path.c_str() );
00283
00284
00285 web_browser->setOpenInExternalBrowser( true );
00286
00287
00288 LLRect htmlRect = mRect;
00289 htmlRect.setCenterAndSize( mRect.getCenterX() - 2, mRect.getCenterY() + 40, mRect.getWidth() + 6, mRect.getHeight() - 78 );
00290 web_browser->setRect( htmlRect );
00291 web_browser->reshape( htmlRect.getWidth(), htmlRect.getHeight(), TRUE );
00292 reshape( mRect.getWidth(), mRect.getHeight(), 1 );
00293
00294
00295 gResponsePtr = LLIamHereLogin::build( this );
00296 LLHTTPClient::get( childGetValue( "real_url" ).asString(), gResponsePtr );
00297 };
00298 #else
00299 mHtmlAvailable = FALSE;
00300 #endif
00301
00302
00303 refreshLocation( false );
00304 }
00305
00306 void LLPanelLogin::setSiteIsAlive( bool alive )
00307 {
00308 #if LL_LIBXUL_ENABLED
00309 LLWebBrowserCtrl* web_browser = LLUICtrlFactory::getWebBrowserCtrlByName(this, "login_html");
00310
00311 if ( alive )
00312 {
00313 if ( web_browser )
00314 {
00315
00316 web_browser->navigateTo( childGetValue( "real_url" ).asString() );
00317
00318
00319 mHtmlAvailable = TRUE;
00320 };
00321 }
00322 else
00323
00324 {
00325 if ( web_browser )
00326 {
00327
00328 web_browser->setVisible( FALSE );
00329
00330
00331 mHtmlAvailable = FALSE;
00332 };
00333 };
00334 #else
00335 mHtmlAvailable = FALSE;
00336 #endif
00337 }
00338
00339 void LLPanelLogin::mungePassword(LLUICtrl* caller, void* user_data)
00340 {
00341 LLPanelLogin* self = (LLPanelLogin*)user_data;
00342 LLLineEditor* editor = (LLLineEditor*)caller;
00343 std::string password = editor->getText();
00344
00345
00346 if (password != self->mIncomingPassword)
00347 {
00348 LLMD5 pass((unsigned char *)password.c_str());
00349 char munged_password[MD5HEX_STR_SIZE];
00350 pass.hex_digest(munged_password);
00351 self->mMungedPassword = munged_password;
00352 }
00353 }
00354
00355 LLPanelLogin::~LLPanelLogin()
00356 {
00357 LLPanelLogin::sInstance = NULL;
00358
00359
00360 if ( gResponsePtr )
00361 gResponsePtr->setParent( 0 );
00362
00363
00364 gImageList.deleteImage( mLogoImage );
00365 }
00366
00367
00368 void LLPanelLogin::draw()
00369 {
00370 if (!getVisible()) return;
00371
00372 BOOL target_fullscreen;
00373 S32 target_width;
00374 S32 target_height;
00375 gViewerWindow->getTargetWindow(target_fullscreen, target_width, target_height);
00376
00377 childSetVisible("full_screen_text", target_fullscreen);
00378
00379 glPushMatrix();
00380 {
00381 F32 image_aspect = 1.333333f;
00382 F32 view_aspect = (F32)mRect.getWidth() / (F32)mRect.getHeight();
00383
00384 if (image_aspect > view_aspect)
00385 {
00386 glTranslatef(-0.5f * (image_aspect / view_aspect - 1.f) * mRect.getWidth(), 0.f, 0.f);
00387 glScalef(image_aspect / view_aspect, 1.f, 1.f);
00388 }
00389
00390
00391
00392
00393
00394
00395
00396
00397 S32 width = mRect.getWidth();
00398 S32 height = mRect.getHeight();
00399
00400 if ( mHtmlAvailable )
00401 {
00402
00403 gl_rect_2d( 0, height - 264, width, 264, LLColor4( 0.0f, 0.0f, 0.0f, 1.f ) );
00404
00405
00406 gl_draw_scaled_image(0, -264, width + 8, mLogoImage->getHeight(), mLogoImage);
00407 }
00408 else
00409 {
00410
00411 S32 offscreen_part = height / 3;
00412 gl_draw_scaled_image(0, -offscreen_part, width, height+offscreen_part, mLogoImage);
00413 };
00414 }
00415 glPopMatrix();
00416
00417 LLPanel::draw();
00418 }
00419
00420
00421 BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
00422 {
00423 if (getVisible() && getEnabled())
00424 {
00425 if (( KEY_RETURN == key ) && (MASK_ALT == mask))
00426 {
00427 gViewerWindow->toggleFullscreen(FALSE);
00428 return TRUE;
00429 }
00430
00431 if (('P' == key) && (MASK_CONTROL == mask))
00432 {
00433 LLFloaterPreference::show(NULL);
00434 return TRUE;
00435 }
00436
00437 if (('T' == key) && (MASK_CONTROL == mask))
00438 {
00439 new LLFloaterSimple("floater_test.xml");
00440 return TRUE;
00441 }
00442
00443 if (('N' == key) && (MASK_CONTROL == mask))
00444 {
00445 gFloaterProject = new LLFloaterNetwork2080();
00446 gFloaterProject->show();
00447 return TRUE;
00448 }
00449 #if LL_LIBXUL_ENABLED
00450 if ( KEY_F1 == key )
00451 {
00452 llinfos << "Spawning HTML help window" << llendl;
00453 gViewerHtmlHelp.show();
00454 return TRUE;
00455 }
00456
00457 # if !LL_RELEASE_FOR_DOWNLOAD
00458 if ( KEY_F2 == key )
00459 {
00460 llinfos << "Spawning floater TOS window" << llendl;
00461 LLFloaterTOS* tos_dialog = LLFloaterTOS::show(LLFloaterTOS::TOS_TOS,"");
00462 tos_dialog->startModal();
00463 return TRUE;
00464 }
00465 # endif
00466 #endif
00467
00468 if (!called_from_parent)
00469 {
00470 if (KEY_RETURN == key && MASK_NONE == mask)
00471 {
00472
00473 return LLPanel::handleKeyHere(key, mask, called_from_parent);
00474 }
00475 }
00476 }
00477
00478 return LLPanel::handleKeyHere(key, mask, called_from_parent);
00479 }
00480
00481
00482 void LLPanelLogin::setFocus(BOOL b)
00483 {
00484 if(b != hasFocus())
00485 {
00486 if(b)
00487 {
00488 LLPanelLogin::giveFocus();
00489 }
00490 else
00491 {
00492 LLPanel::setFocus(b);
00493 }
00494 }
00495 }
00496
00497
00498 void LLPanelLogin::giveFocus()
00499 {
00500 if( sInstance )
00501 {
00502
00503 std::string first = sInstance->childGetText("first_name_edit");
00504 std::string pass = sInstance->childGetText("password_edit");
00505
00506 BOOL have_first = !first.empty();
00507 BOOL have_pass = !pass.empty();
00508
00509 LLLineEditor* edit = NULL;
00510 if (have_first && !have_pass)
00511 {
00512
00513
00514 edit = LLUICtrlFactory::getLineEditorByName(sInstance, "password_edit");
00515 }
00516 else
00517 {
00518
00519 edit = LLUICtrlFactory::getLineEditorByName(sInstance, "first_name_edit");
00520 }
00521
00522 if (edit)
00523 {
00524 edit->setFocus(TRUE);
00525 edit->selectAll();
00526 }
00527 }
00528 }
00529
00530
00531
00532 void LLPanelLogin::show(const LLRect &rect,
00533 BOOL show_server,
00534 void (*callback)(S32 option, void* user_data),
00535 void* callback_data)
00536 {
00537 new LLPanelLogin(rect, show_server, callback, callback_data);
00538
00539 if( !gFocusMgr.getKeyboardFocus() )
00540 {
00541
00542 sInstance->setFocus(TRUE);
00543 }
00544
00545
00546 gFocusMgr.setDefaultKeyboardFocus(sInstance);
00547 }
00548
00549
00550 void LLPanelLogin::setFields(const std::string& firstname, const std::string& lastname, const std::string& password,
00551 BOOL remember)
00552 {
00553 if (!sInstance)
00554 {
00555 llwarns << "Attempted fillFields with no login view shown" << llendl;
00556 return;
00557 }
00558
00559 sInstance->childSetText("first_name_edit", firstname);
00560 sInstance->childSetText("last_name_edit", lastname);
00561
00562
00563
00564 if (password.length() == 32)
00565 {
00566
00567
00568
00569
00570 const std::string filler("123456789!123456");
00571 sInstance->childSetText("password_edit", filler);
00572 sInstance->mIncomingPassword = filler;
00573 sInstance->mMungedPassword = password;
00574 }
00575 else
00576 {
00577
00578 sInstance->childSetText("password_edit", password);
00579 sInstance->mIncomingPassword = password;
00580 LLMD5 pass((unsigned char *)password.c_str());
00581 char munged_password[MD5HEX_STR_SIZE];
00582 pass.hex_digest(munged_password);
00583 sInstance->mMungedPassword = munged_password;
00584 }
00585
00586 sInstance->childSetValue("remember_check", remember);
00587 }
00588
00589
00590
00591 void LLPanelLogin::addServer(const char *server, S32 domain_name)
00592 {
00593 if (!sInstance)
00594 {
00595 llwarns << "Attempted addServer with no login view shown" << llendl;
00596 return;
00597 }
00598
00599 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "server_combo");
00600 if (combo)
00601 {
00602 combo->add(server, LLSD(domain_name) );
00603 combo->setCurrentByIndex(0);
00604 }
00605 }
00606
00607
00608 void LLPanelLogin::getFields(LLString &firstname, LLString &lastname, LLString &password,
00609 BOOL &remember)
00610 {
00611 if (!sInstance)
00612 {
00613 llwarns << "Attempted getFields with no login view shown" << llendl;
00614 return;
00615 }
00616
00617 firstname = sInstance->childGetText("first_name_edit");
00618 LLString::trim(firstname);
00619
00620 lastname = sInstance->childGetText("last_name_edit");
00621 LLString::trim(lastname);
00622
00623 password = sInstance->mMungedPassword;
00624 remember = sInstance->childGetValue("remember_check");
00625 }
00626
00627
00628
00629 BOOL LLPanelLogin::getServer(LLString &server, S32 &domain_name)
00630 {
00631 BOOL user_picked = FALSE;
00632 if (!sInstance)
00633 {
00634 llwarns << "Attempted getServer with no login view shown" << llendl;
00635 }
00636 else
00637 {
00638 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "server_combo");
00639 if (combo)
00640 {
00641 LLSD combo_val = combo->getValue();
00642 if (LLSD::TypeInteger == combo_val.type())
00643 {
00644 domain_name = combo->getValue().asInteger();
00645
00646 if ((S32)USERSERVER_OTHER == domain_name)
00647 {
00648 server = gUserServerName;
00649 }
00650 }
00651 else
00652 {
00653
00654 domain_name = (S32)USERSERVER_OTHER;
00655 server = combo_val.asString();
00656 }
00657 user_picked = combo->isDirty();
00658 }
00659 }
00660
00661 return user_picked;
00662 }
00663
00664
00665 void LLPanelLogin::getLocation(LLString &location)
00666 {
00667 if (!sInstance)
00668 {
00669 llwarns << "Attempted getLocation with no login view shown" << llendl;
00670 return;
00671 }
00672
00673 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "start_location_combo");
00674 if (combo)
00675 {
00676 location = combo->getValue().asString();
00677 }
00678 }
00679
00680
00681 void LLPanelLogin::refreshLocation( bool force_visible )
00682 {
00683 if (!sInstance) return;
00684
00685 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "start_location_combo");
00686 if (!combo) return;
00687
00688 LLString sim_string = LLURLSimString::sInstance.mSimString;
00689 if (!sim_string.empty())
00690 {
00691 combo->setCurrentByIndex( 3 );
00692 combo->setTextEntry(sim_string);
00693 }
00694 else
00695 {
00696 BOOL login_last = gSavedSettings.getBOOL("LoginLastLocation");
00697 combo->setCurrentByIndex( login_last ? 1 : 0 );
00698 }
00699
00700 BOOL show_start = TRUE;
00701
00702 if ( ! force_visible )
00703 show_start = gSavedSettings.getBOOL("ShowStartLocation");
00704
00705 sInstance->childSetVisible("start_location_combo", show_start);
00706 sInstance->childSetVisible("start_location_text", show_start);
00707 }
00708
00709
00710 void LLPanelLogin::close()
00711 {
00712 if (sInstance)
00713 {
00714 gViewerWindow->getRootView()->removeChild( LLPanelLogin::sInstance );
00715
00716 gFocusMgr.setDefaultKeyboardFocus(NULL);
00717
00718 delete sInstance;
00719 sInstance = NULL;
00720 }
00721 }
00722
00723
00724
00725
00726
00727
00728
00729 void LLPanelLogin::onClickConnect(void *)
00730 {
00731 if (sInstance && sInstance->mCallback)
00732 {
00733
00734 if ( gResponsePtr )
00735 gResponsePtr->setParent( 0 );
00736
00737
00738 sInstance->setFocus(FALSE);
00739
00740 LLString first = sInstance->childGetText("first_name_edit");
00741 LLString last = sInstance->childGetText("last_name_edit");
00742 if (!first.empty() && !last.empty())
00743 {
00744
00745
00746
00747 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "server_combo");
00748 if (combo)
00749 {
00750 S32 selected_server = combo->getValue();
00751 if (selected_server == USERSERVER_NONE)
00752 {
00753 LLString custom_server = combo->getValue().asString();
00754 gSavedSettings.setString("CustomServer", custom_server);
00755 }
00756 }
00757 sInstance->mCallback(0, sInstance->mCallbackData);
00758 }
00759 else
00760 {
00761
00762
00763 onClickNewAccount(NULL);
00764 }
00765 }
00766 }
00767
00768
00769
00770 void LLPanelLogin::newAccountAlertCallback(S32 option, void*)
00771 {
00772 if (0 == option)
00773 {
00774 llinfos << "Going to account creation URL" << llendl;
00775 LLWeb::loadURL( CREATE_ACCOUNT_URL );
00776 }
00777 else
00778 {
00779 sInstance->setFocus(TRUE);
00780 }
00781 }
00782
00783
00784
00785 void LLPanelLogin::onClickNewAccount(void*)
00786 {
00787 if (gHideLinks)
00788 {
00789 gViewerWindow->alertXml("MustHaveAccountToLogInNoLinks");
00790 }
00791 else
00792 {
00793 gViewerWindow->alertXml("MustHaveAccountToLogIn",
00794 LLPanelLogin::newAccountAlertCallback);
00795 }
00796 }
00797
00798
00799
00800 void LLPanelLogin::onClickQuit(void*)
00801 {
00802 if (sInstance && sInstance->mCallback)
00803 {
00804
00805 if ( gResponsePtr )
00806 gResponsePtr->setParent( 0 );
00807
00808 sInstance->mCallback(1, sInstance->mCallbackData);
00809 }
00810 }
00811
00812
00813
00814 void LLPanelLogin::onClickVersion(void*)
00815 {
00816 LLFloaterAbout::show(NULL);
00817 }
00818
00819
00820 void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)
00821 {
00822 if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE)
00823 {
00824 LLNotifyBox::showXml("CapsKeyOn");
00825 sCapslockDidNotification = TRUE;
00826 }
00827 }