/** * @file llfloaterforgetuser.cpp * @brief LLFloaterForgetUser class definition. * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2019, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llfloaterforgetuser.h" #include "llappviewer.h" #include "llcheckboxctrl.h" #include "llfavoritesbar.h" #include "llnotificationsutil.h" #include "llpanellogin.h" // for helper function getUserName() and to repopulate list if nessesary #include "llscrolllistctrl.h" #include "llsecapi.h" #include "llstartup.h" #include "llviewercontrol.h" #include "llviewernetwork.h" LLFloaterForgetUser::LLFloaterForgetUser(const LLSD &key) : LLFloater("floater_forget_user"), mLoginPanelDirty(false) { } LLFloaterForgetUser::~LLFloaterForgetUser() { if (mLoginPanelDirty) { LLPanelLogin::resetFields(); } } BOOL LLFloaterForgetUser::postBuild() { mScrollList = getChild<LLScrollListCtrl>("user_list"); bool show_grid_marks = gSavedSettings.getBOOL("ForceShowGrid"); show_grid_marks |= !LLGridManager::getInstance()->isInProductionGrid(); std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(); if (!show_grid_marks) { // Figure out if there are records for more than one grid in storage for (std::map<std::string, std::string>::iterator grid_iter = known_grids.begin(); grid_iter != known_grids.end(); grid_iter++) { if (!grid_iter->first.empty() && grid_iter->first != MAINGRID) // a workaround since 'mIsInProductionGrid' might not be set { if (!gSecAPIHandler->emptyCredentialMap("login_list", grid_iter->first)) { show_grid_marks = true; break; } // "Legacy" viewer support LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid_iter->first); if (cred.notNull()) { const LLSD &ident = cred->getIdentifier(); if (ident.isMap() && ident.has("type")) { show_grid_marks = true; break; } } } } } mUserGridsCount.clear(); if (!show_grid_marks) { // just load maingrid loadGridToList(MAINGRID, false); } else { for (std::map<std::string, std::string>::iterator grid_iter = known_grids.begin(); grid_iter != known_grids.end(); grid_iter++) { if (!grid_iter->first.empty()) { loadGridToList(grid_iter->first, true); } } } mScrollList->selectFirstItem(); bool enable_button = mScrollList->getFirstSelectedIndex() != -1; LLCheckBoxCtrl *chk_box = getChild<LLCheckBoxCtrl>("delete_data"); chk_box->setEnabled(enable_button); chk_box->set(FALSE); LLButton *button = getChild<LLButton>("forget"); button->setEnabled(enable_button); button->setCommitCallback(boost::bind(&LLFloaterForgetUser::onForgetClicked, this)); return TRUE; } void LLFloaterForgetUser::onForgetClicked() { LLScrollListCtrl *scroll_list = getChild<LLScrollListCtrl>("user_list"); LLSD user_data = scroll_list->getSelectedValue(); const std::string user_id = user_data["user_id"]; LLCheckBoxCtrl *chk_box = getChild<LLCheckBoxCtrl>("delete_data"); BOOL delete_data = chk_box->getValue(); if (delete_data && mUserGridsCount[user_id] > 1) { // more than 1 grid uses this id LLNotificationsUtil::add("LoginRemoveMultiGridUserData", LLSD(), LLSD(), boost::bind(&LLFloaterForgetUser::onConfirmForget, this, _1, _2)); return; } processForgetUser(); } bool LLFloaterForgetUser::onConfirmForget(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (option == 0) { processForgetUser(); } return false; } // static bool LLFloaterForgetUser::onConfirmLogout(const LLSD& notification, const LLSD& response, const std::string &fav_id, const std::string &grid) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (option == 0) { // Remove creds std::string grid_id = LLGridManager::getInstance()->getGridId(grid); if (grid_id.empty()) { grid_id = grid; } gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid_id, LLStartUp::getUserId()); // doesn't write gSecAPIHandler->removeFromCredentialMap("login_list", grid, LLStartUp::getUserId()); LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid); if (cred.notNull() && cred->userID() == LLStartUp::getUserId()) { gSecAPIHandler->deleteCredential(cred); } // Clean favorites LLFavoritesOrderStorage::removeFavoritesRecordOfUser(fav_id, grid); // mark data for removal LLAppViewer::instance()->purgeUserDataOnExit(); LLAppViewer::instance()->requestQuit(); } return false; } void LLFloaterForgetUser::processForgetUser() { LLScrollListCtrl *scroll_list = getChild<LLScrollListCtrl>("user_list"); LLCheckBoxCtrl *chk_box = getChild<LLCheckBoxCtrl>("delete_data"); BOOL delete_data = chk_box->getValue(); LLSD user_data = scroll_list->getSelectedValue(); const std::string user_id = user_data["user_id"]; const std::string grid = user_data["grid"]; const std::string user_name = user_data["label"]; // for favorites if (delete_data && user_id == LLStartUp::getUserId() && LLStartUp::getStartupState() > STATE_LOGIN_WAIT) { // we can't delete data for user that is currently logged in // we need to pass grid because we are deleting data universal to grids, but specific grid's user LLNotificationsUtil::add("LoginCantRemoveCurUsername", LLSD(), LLSD(), boost::bind(onConfirmLogout, _1, _2, user_name, grid)); return; } // key is used for name of user's folder and in credencials // user_name is edentical to favorite's username forgetUser(user_id, user_name, grid, delete_data); mLoginPanelDirty = true; if (delete_data) { mUserGridsCount[user_id] = 0; //no data left to care about } else { mUserGridsCount[user_id]--; } // Update UI scroll_list->deleteSelectedItems(); scroll_list->selectFirstItem(); if (scroll_list->getFirstSelectedIndex() == -1) { LLButton *button = getChild<LLButton>("forget"); button->setEnabled(false); chk_box->setEnabled(false); } } //static void LLFloaterForgetUser::forgetUser(const std::string &userid, const std::string &fav_id, const std::string &grid, bool delete_data) { // Remove creds std::string grid_id = LLGridManager::getInstance()->getGridId(grid); if (grid_id.empty()) { grid_id = grid; } gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid_id, userid); // doesn't write gSecAPIHandler->removeFromCredentialMap("login_list", grid, userid); // write operation LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid); if (cred.notNull() && cred->userID() == userid) { gSecAPIHandler->deleteCredential(cred); } // Clean data if (delete_data) { std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + userid; gDirUtilp->deleteDirAndContents(user_path); // Clean favorites LLFavoritesOrderStorage::removeFavoritesRecordOfUser(fav_id, grid); // Note: we do not clean user-related files from cache because there are id dependent (inventory) // files and cache has separate cleaning mechanism either way. // Also this only cleans user from current grid, not all of them. } } void LLFloaterForgetUser::loadGridToList(const std::string &grid, bool show_grid_name) { std::string grid_label; if (show_grid_name) { grid_label = LLGridManager::getInstance()->getGridId(grid); //login id (shortened label) } if (gSecAPIHandler->hasCredentialMap("login_list", grid)) { LLSecAPIHandler::credential_map_t credencials; gSecAPIHandler->loadCredentialMap("login_list", grid, credencials); LLSecAPIHandler::credential_map_t::iterator cr_iter = credencials.begin(); LLSecAPIHandler::credential_map_t::iterator cr_end = credencials.end(); while (cr_iter != cr_end) { if (cr_iter->second.notNull()) // basic safety { std::string user_label = LLPanelLogin::getUserName(cr_iter->second); LLSD user_data; user_data["user_id"] = cr_iter->first; user_data["label"] = user_label; user_data["grid"] = grid; if (show_grid_name) { user_label += " (" + grid_label + ")"; } LLScrollListItem::Params item_params; item_params.value(user_data); item_params.columns.add() .value(user_label) .column("user") .font(LLFontGL::getFontSansSerifSmall()); mScrollList->addRow(item_params, ADD_BOTTOM); // Add one to grid count std::map<std::string, S32>::iterator found = mUserGridsCount.find(cr_iter->first); if (found != mUserGridsCount.end()) { found->second++; } else { mUserGridsCount[cr_iter->first] = 1; } } cr_iter++; } } else { // "Legacy" viewer support LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid); if (cred.notNull()) { const LLSD &ident = cred->getIdentifier(); if (ident.isMap() && ident.has("type")) { std::string user_label = LLPanelLogin::getUserName(cred); LLSD user_data; user_data["user_id"] = cred->userID(); user_data["label"] = user_label; user_data["grid"] = grid; if (show_grid_name) { user_label += " (" + grid_label + ")"; } LLScrollListItem::Params item_params; item_params.value(user_data); item_params.columns.add() .value(user_label) .column("user") .font(LLFontGL::getFontSansSerifSmall()); mScrollList->addRow(item_params, ADD_BOTTOM); // Add one to grid count std::map<std::string, S32>::iterator found = mUserGridsCount.find(cred->userID()); if (found != mUserGridsCount.end()) { found->second++; } else { mUserGridsCount[cred->userID()] = 1; } } } } }