diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llgroupmgr.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/newview/llgroupmgr.cpp')
-rw-r--r-- | indra/newview/llgroupmgr.cpp | 5014 |
1 files changed, 2507 insertions, 2507 deletions
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 6aba2ca0da..e0366f20c1 100644 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -1,2507 +1,2507 @@ -/** - * @file llgroupmgr.cpp - * @brief LLGroupMgr class implementation - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -/** - * Manager for aggregating all client knowledge for specific groups - * Keeps a cache of group information. - */ - -#include "llviewerprecompiledheaders.h" - -#include "llgroupmgr.h" - -#include <vector> -#include <algorithm> - -#include "llappviewer.h" -#include "llagent.h" -#include "llavatarnamecache.h" -#include "llui.h" -#include "message.h" -#include "roles_constants.h" -#include "lltransactiontypes.h" -#include "llstatusbar.h" -#include "llviewerwindow.h" -#include "llpanelgroupcreate.h" -#include "llgroupactions.h" -#include "llnotificationsutil.h" -#include "lluictrlfactory.h" -#include "lltrans.h" -#include "llviewerregion.h" -#include <boost/regex.hpp> -#include "llcorehttputil.h" -#include "lluiusage.h" - - -#if LL_MSVC -#pragma warning(push) -// disable boost::lexical_cast warning -#pragma warning (disable:4702) -#endif - -#include <boost/lexical_cast.hpp> - -#if LL_MSVC -#pragma warning(pop) // Restore all warnings to the previous state -#endif - -const U32 MAX_CACHED_GROUPS = 20; - -// -// LLRoleActionSet -// -LLRoleActionSet::LLRoleActionSet() -: mActionSetData(NULL) -{ } - -LLRoleActionSet::~LLRoleActionSet() -{ - delete mActionSetData; - std::for_each(mActions.begin(), mActions.end(), DeletePointer()); - mActions.clear(); -} - -// -// LLGroupMemberData -// - -LLGroupMemberData::LLGroupMemberData(const LLUUID& id, - S32 contribution, - U64 agent_powers, - const std::string& title, - const std::string& online_status, - bool is_owner) : - mID(id), - mContribution(contribution), - mAgentPowers(agent_powers), - mTitle(title), - mOnlineStatus(online_status), - mIsOwner(is_owner) -{ -} - -LLGroupMemberData::~LLGroupMemberData() -{ -} - -void LLGroupMemberData::addRole(const LLUUID& role, LLGroupRoleData* rd) -{ - mRolesList[role] = rd; -} - -bool LLGroupMemberData::removeRole(const LLUUID& role) -{ - role_list_t::iterator it = mRolesList.find(role); - - if (it != mRolesList.end()) - { - mRolesList.erase(it); - return true; - } - - return false; -} - -// -// LLGroupRoleData -// - -LLGroupRoleData::LLGroupRoleData(const LLUUID& role_id, - const std::string& role_name, - const std::string& role_title, - const std::string& role_desc, - const U64 role_powers, - const S32 member_count) : - mRoleID(role_id), - mMemberCount(member_count), - mMembersNeedsSort(false) -{ - mRoleData.mRoleName = role_name; - mRoleData.mRoleTitle = role_title; - mRoleData.mRoleDescription = role_desc; - mRoleData.mRolePowers = role_powers; - mRoleData.mChangeType = RC_UPDATE_NONE; -} - -LLGroupRoleData::LLGroupRoleData(const LLUUID& role_id, - LLRoleData role_data, - const S32 member_count) : - mRoleID(role_id), - mRoleData(role_data), - mMemberCount(member_count), - mMembersNeedsSort(false) -{ - -} - -LLGroupRoleData::~LLGroupRoleData() -{ -} - -S32 LLGroupRoleData::getMembersInRole(uuid_vec_t members, - bool needs_sort) -{ - if (mRoleID.isNull()) - { - // This is the everyone role, just return the size of members, - // because everyone is in the everyone role. - return members.size(); - } - - // Sort the members list, if needed. - if (mMembersNeedsSort) - { - std::sort(mMemberIDs.begin(), mMemberIDs.end()); - mMembersNeedsSort = false; - } - if (needs_sort) - { - // Sort the members parameter. - std::sort(members.begin(), members.end()); - } - - // Return the number of members in the intersection. - S32 max_size = llmin( members.size(), mMemberIDs.size() ); - uuid_vec_t in_role( max_size ); - uuid_vec_t::iterator in_role_end; - in_role_end = std::set_intersection(mMemberIDs.begin(), mMemberIDs.end(), - members.begin(), members.end(), - in_role.begin()); - return in_role_end - in_role.begin(); -} - -void LLGroupRoleData::addMember(const LLUUID& member) -{ - mMembersNeedsSort = true; - mMemberIDs.push_back(member); -} - -bool LLGroupRoleData::removeMember(const LLUUID& member) -{ - uuid_vec_t::iterator it = std::find(mMemberIDs.begin(),mMemberIDs.end(),member); - - if (it != mMemberIDs.end()) - { - mMembersNeedsSort = true; - mMemberIDs.erase(it); - return true; - } - - return false; -} - -void LLGroupRoleData::clearMembers() -{ - mMembersNeedsSort = false; - mMemberIDs.clear(); -} - - -// -// LLGroupMgrGroupData -// - -LLGroupMgrGroupData::LLGroupMgrGroupData(const LLUUID& id) : - mID(id), - mShowInList(true), - mOpenEnrollment(false), - mMembershipFee(0), - mAllowPublish(false), - mListInProfile(false), - mMaturePublish(false), - mChanged(false), - mMemberCount(0), - mRoleCount(0), - mReceivedRoleMemberPairs(0), - mMemberDataComplete(false), - mRoleDataComplete(false), - mRoleMemberDataComplete(false), - mGroupPropertiesDataComplete(false), - mPendingRoleMemberRequest(false), - mAccessTime(0.0f), - mPendingBanRequest(false) -{ - mMemberVersion.generate(); -} - -void LLGroupMgrGroupData::setAccessed() -{ - mAccessTime = (F32)LLFrameTimer::getTotalSeconds(); -} - -bool LLGroupMgrGroupData::getRoleData(const LLUUID& role_id, LLRoleData& role_data) -{ - role_data_map_t::const_iterator it; - - // Do we have changes for it? - it = mRoleChanges.find(role_id); - if (it != mRoleChanges.end()) - { - if ((*it).second.mChangeType == RC_DELETE) return false; - - role_data = (*it).second; - return true; - } - - // Ok, no changes, hasn't been deleted, isn't a new role, just find the role. - role_list_t::const_iterator rit = mRoles.find(role_id); - if (rit != mRoles.end()) - { - role_data = (*rit).second->getRoleData(); - return true; - } - - // This role must not exist. - return false; -} - - -void LLGroupMgrGroupData::setRoleData(const LLUUID& role_id, LLRoleData role_data) -{ - // If this is a newly created group, we need to change the data in the created list. - role_data_map_t::iterator it; - it = mRoleChanges.find(role_id); - if (it != mRoleChanges.end()) - { - if ((*it).second.mChangeType == RC_CREATE) - { - role_data.mChangeType = RC_CREATE; - mRoleChanges[role_id] = role_data; - return; - } - else if ((*it).second.mChangeType == RC_DELETE) - { - // Don't do anything for a role being deleted. - return; - } - } - - // Not a new role, so put it in the changes list. - LLRoleData old_role_data; - role_list_t::iterator rit = mRoles.find(role_id); - if (rit != mRoles.end()) - { - bool data_change = ( ((*rit).second->mRoleData.mRoleDescription != role_data.mRoleDescription) - || ((*rit).second->mRoleData.mRoleName != role_data.mRoleName) - || ((*rit).second->mRoleData.mRoleTitle != role_data.mRoleTitle) ); - bool powers_change = ((*rit).second->mRoleData.mRolePowers != role_data.mRolePowers); - - if (!data_change && !powers_change) - { - // We are back to the original state, the changes have been 'undone' so take out the change. - mRoleChanges.erase(role_id); - return; - } - - if (data_change && powers_change) - { - role_data.mChangeType = RC_UPDATE_ALL; - } - else if (data_change) - { - role_data.mChangeType = RC_UPDATE_DATA; - } - else - { - role_data.mChangeType = RC_UPDATE_POWERS; - } - - mRoleChanges[role_id] = role_data; - } - else - { - LL_WARNS() << "Change being made to non-existant role " << role_id << LL_ENDL; - } -} - -bool LLGroupMgrGroupData::pendingRoleChanges() -{ - return (!mRoleChanges.empty()); -} - -// This is a no-op if the role has already been created. -void LLGroupMgrGroupData::createRole(const LLUUID& role_id, LLRoleData role_data) -{ - if (mRoleChanges.find(role_id) != mRoleChanges.end()) - { - LL_WARNS() << "create role for existing role! " << role_id << LL_ENDL; - } - else - { - role_data.mChangeType = RC_CREATE; - mRoleChanges[role_id] = role_data; - } -} - -void LLGroupMgrGroupData::deleteRole(const LLUUID& role_id) -{ - role_data_map_t::iterator it; - - // If this was a new role, just discard it. - it = mRoleChanges.find(role_id); - if (it != mRoleChanges.end() - && (*it).second.mChangeType == RC_CREATE) - { - mRoleChanges.erase(it); - return; - } - - LLRoleData rd; - rd.mChangeType = RC_DELETE; - mRoleChanges[role_id] = rd; -} - -void LLGroupMgrGroupData::addRolePower(const LLUUID &role_id, U64 power) -{ - LLRoleData rd; - if (getRoleData(role_id,rd)) - { - rd.mRolePowers |= power; - setRoleData(role_id,rd); - } - else - { - LL_WARNS() << "addRolePower: no role data found for " << role_id << LL_ENDL; - } -} - -void LLGroupMgrGroupData::removeRolePower(const LLUUID &role_id, U64 power) -{ - LLRoleData rd; - if (getRoleData(role_id,rd)) - { - rd.mRolePowers &= ~power; - setRoleData(role_id,rd); - } - else - { - LL_WARNS() << "removeRolePower: no role data found for " << role_id << LL_ENDL; - } -} - -U64 LLGroupMgrGroupData::getRolePowers(const LLUUID& role_id) -{ - LLRoleData rd; - if (getRoleData(role_id,rd)) - { - return rd.mRolePowers; - } - else - { - LL_WARNS() << "getRolePowers: no role data found for " << role_id << LL_ENDL; - return GP_NO_POWERS; - } -} - -void LLGroupMgrGroupData::removeData() -{ - // Remove member data first, because removeRoleData will walk the member list - removeMemberData(); - removeRoleData(); -} - -void LLGroupMgrGroupData::removeMemberData() -{ - for (member_list_t::iterator mi = mMembers.begin(); mi != mMembers.end(); ++mi) - { - delete mi->second; - } - mMembers.clear(); - mMemberDataComplete = false; - mMemberVersion.generate(); -} - -void LLGroupMgrGroupData::removeRoleData() -{ - for (member_list_t::iterator mi = mMembers.begin(); mi != mMembers.end(); ++mi) - { - LLGroupMemberData* data = mi->second; - if (data) - { - data->clearRoles(); - } - } - - for (role_list_t::iterator ri = mRoles.begin(); ri != mRoles.end(); ++ri) - { - LLGroupRoleData* data = ri->second; - delete data; - } - mRoles.clear(); - mReceivedRoleMemberPairs = 0; - mRoleDataComplete = false; - mRoleMemberDataComplete= false; -} - -void LLGroupMgrGroupData::removeRoleMemberData() -{ - for (member_list_t::iterator mi = mMembers.begin(); mi != mMembers.end(); ++mi) - { - LLGroupMemberData* data = mi->second; - if (data) - { - data->clearRoles(); - } - } - - for (role_list_t::iterator ri = mRoles.begin(); ri != mRoles.end(); ++ri) - { - LLGroupRoleData* data = ri->second; - if (data) - { - data->clearMembers(); - } - } - - mReceivedRoleMemberPairs = 0; - mRoleMemberDataComplete= false; -} - -LLGroupMgrGroupData::~LLGroupMgrGroupData() -{ - removeData(); -} - -bool LLGroupMgrGroupData::changeRoleMember(const LLUUID& role_id, - const LLUUID& member_id, - LLRoleMemberChangeType rmc) -{ - role_list_t::iterator ri = mRoles.find(role_id); - member_list_t::iterator mi = mMembers.find(member_id); - - if (ri == mRoles.end() - || mi == mMembers.end() ) - { - if (ri == mRoles.end()) LL_WARNS() << "LLGroupMgrGroupData::changeRoleMember couldn't find role " << role_id << LL_ENDL; - if (mi == mMembers.end()) LL_WARNS() << "LLGroupMgrGroupData::changeRoleMember couldn't find member " << member_id << LL_ENDL; - return false; - } - - LLGroupRoleData* grd = ri->second; - LLGroupMemberData* gmd = mi->second; - - if (!grd || !gmd) - { - LL_WARNS() << "LLGroupMgrGroupData::changeRoleMember couldn't get member or role data." << LL_ENDL; - return false; - } - - if (RMC_ADD == rmc) - { - LL_INFOS() << " adding member to role." << LL_ENDL; - grd->addMember(member_id); - gmd->addRole(role_id,grd); - - //TODO move this into addrole function - //see if they added someone to the owner role and update isOwner - gmd->mIsOwner = (role_id == mOwnerRole) ? true : gmd->mIsOwner; - } - else if (RMC_REMOVE == rmc) - { - LL_INFOS() << " removing member from role." << LL_ENDL; - grd->removeMember(member_id); - gmd->removeRole(role_id); - - //see if they removed someone from the owner role and update isOwner - gmd->mIsOwner = (role_id == mOwnerRole) ? false : gmd->mIsOwner; - } - - lluuid_pair role_member; - role_member.first = role_id; - role_member.second = member_id; - - change_map_t::iterator it = mRoleMemberChanges.find(role_member); - if (it != mRoleMemberChanges.end()) - { - // There was already a role change for this role_member - if (it->second.mChange == rmc) - { - // Already recorded this change? Weird. - LL_INFOS() << "Received duplicate change for " - << " role: " << role_id << " member " << member_id - << " change " << (rmc == RMC_ADD ? "ADD" : "REMOVE") << LL_ENDL; - } - else - { - // The only two operations (add and remove) currently cancel each other out - // If that changes this will need more logic - if (rmc == RMC_NONE) - { - LL_WARNS() << "changeRoleMember: existing entry with 'RMC_NONE' change! This shouldn't happen." << LL_ENDL; - LLRoleMemberChange rc(role_id,member_id,rmc); - mRoleMemberChanges[role_member] = rc; - } - else - { - mRoleMemberChanges.erase(it); - } - } - } - else - { - LLRoleMemberChange rc(role_id,member_id,rmc); - mRoleMemberChanges[role_member] = rc; - } - - recalcAgentPowers(member_id); - - mChanged = true; - return true; -} - -void LLGroupMgrGroupData::recalcAllAgentPowers() -{ - LLGroupMemberData* gmd; - - for (member_list_t::iterator mit = mMembers.begin(); - mit != mMembers.end(); ++mit) - { - gmd = mit->second; - if (!gmd) continue; - - gmd->mAgentPowers = 0; - for (LLGroupMemberData::role_list_t::iterator it = gmd->mRolesList.begin(); - it != gmd->mRolesList.end(); ++it) - { - LLGroupRoleData* grd = (*it).second; - if (!grd) continue; - - gmd->mAgentPowers |= grd->mRoleData.mRolePowers; - } - } -} - -void LLGroupMgrGroupData::recalcAgentPowers(const LLUUID& agent_id) -{ - member_list_t::iterator mi = mMembers.find(agent_id); - if (mi == mMembers.end()) return; - - LLGroupMemberData* gmd = mi->second; - - if (!gmd) return; - - gmd->mAgentPowers = 0; - for (LLGroupMemberData::role_list_t::iterator it = gmd->mRolesList.begin(); - it != gmd->mRolesList.end(); ++it) - { - LLGroupRoleData* grd = (*it).second; - if (!grd) continue; - - gmd->mAgentPowers |= grd->mRoleData.mRolePowers; - } -} - -bool LLGroupMgrGroupData::isSingleMemberNotOwner() -{ - return mMembers.size() == 1 && !mMembers.begin()->second->isOwner(); -} - -bool packRoleUpdateMessageBlock(LLMessageSystem* msg, - const LLUUID& group_id, - const LLUUID& role_id, - const LLRoleData& role_data, - bool start_message) -{ - if (start_message) - { - msg->newMessage("GroupRoleUpdate"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID",gAgent.getID()); - msg->addUUID("SessionID",gAgent.getSessionID()); - msg->addUUID("GroupID",group_id); - start_message = false; - } - - msg->nextBlock("RoleData"); - msg->addUUID("RoleID",role_id); - msg->addString("Name", role_data.mRoleName); - msg->addString("Description", role_data.mRoleDescription); - msg->addString("Title", role_data.mRoleTitle); - msg->addU64("Powers", role_data.mRolePowers); - msg->addU8("UpdateType", (U8)role_data.mChangeType); - - if (msg->isSendFullFast()) - { - gAgent.sendReliableMessage(); - start_message = true; - } - - return start_message; -} - -void LLGroupMgrGroupData::sendRoleChanges() -{ - // Commit changes locally - LLGroupRoleData* grd; - role_list_t::iterator role_it; - LLMessageSystem* msg = gMessageSystem; - bool start_message = true; - - bool need_role_cleanup = false; - bool need_role_data = false; - bool need_power_recalc = false; - - // Apply all changes - for (role_data_map_t::iterator iter = mRoleChanges.begin(); - iter != mRoleChanges.end(); ) - { - role_data_map_t::iterator it = iter++; // safely incrament iter - const LLUUID& role_id = (*it).first; - const LLRoleData& role_data = (*it).second; - - // Commit to local data set - role_it = mRoles.find((*it).first); - if ( (mRoles.end() == role_it - && RC_CREATE != role_data.mChangeType) - || (mRoles.end() != role_it - && RC_CREATE == role_data.mChangeType)) - { - continue; - } - - // NOTE: role_it is valid EXCEPT for the RC_CREATE case - switch (role_data.mChangeType) - { - case RC_CREATE: - { - // NOTE: role_it is NOT valid in this case - grd = new LLGroupRoleData(role_id, role_data, 0); - mRoles[role_id] = grd; - need_role_data = true; - break; - } - case RC_DELETE: - { - LLGroupRoleData* group_role_data = (*role_it).second; - delete group_role_data; - mRoles.erase(role_it); - need_role_cleanup = true; - need_power_recalc = true; - break; - } - case RC_UPDATE_ALL: - // fall through - case RC_UPDATE_POWERS: - need_power_recalc = true; - // fall through - case RC_UPDATE_DATA: - // fall through - default: - { - LLGroupRoleData* group_role_data = (*role_it).second; - group_role_data->setRoleData(role_data); // NOTE! might modify mRoleChanges! - break; - } - } - - // Update dataserver - start_message = packRoleUpdateMessageBlock(msg,getID(),role_id,role_data,start_message); - } - - if (!start_message) - { - gAgent.sendReliableMessage(); - } - - // If we delete a role then all the role-member pairs are invalid! - if (need_role_cleanup) - { - removeRoleMemberData(); - } - - // If we create a new role, then we need to re-fetch all the role data. - if (need_role_data) - { - LLGroupMgr::getInstance()->sendGroupRoleDataRequest(getID()); - } - - // Clean up change lists - mRoleChanges.clear(); - - // Recalculate all the agent powers because role powers have now changed. - if (need_power_recalc) - { - recalcAllAgentPowers(); - } -} - -void LLGroupMgrGroupData::cancelRoleChanges() -{ - // Clear out all changes! - mRoleChanges.clear(); -} - -void LLGroupMgrGroupData::createBanEntry(const LLUUID& ban_id, const LLGroupBanData& ban_data) -{ - mBanList[ban_id] = ban_data; -} - -void LLGroupMgrGroupData::removeBanEntry(const LLUUID& ban_id) -{ - mBanList.erase(ban_id); -} - -void LLGroupMgrGroupData::banMemberById(const LLUUID& participant_uuid) -{ - if (!mMemberDataComplete || - !mRoleDataComplete || - !(mRoleMemberDataComplete && mMembers.size())) - { - LL_WARNS() << "No Role-Member data yet, setting ban request to pending." << LL_ENDL; - mPendingBanRequest = true; - mPendingBanMemberID = participant_uuid; - - if (!mMemberDataComplete || !mMembers.size()) - { - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID); - } - - if (!mRoleDataComplete) - { - LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mID); - } - - return; - } - - LLGroupMgrGroupData::member_list_t::iterator mi = mMembers.find((participant_uuid)); - if (mi == mMembers.end()) - { - if (!mPendingBanRequest) - { - mPendingBanRequest = true; - mPendingBanMemberID = participant_uuid; - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID); // member isn't in members list, request reloading - } - else - { - mPendingBanRequest = false; - } - - return; - } - - mPendingBanRequest = false; - - LLGroupMemberData* member_data = (*mi).second; - if (member_data && member_data->isInRole(mOwnerRole)) - { - return; // can't ban group owner - } - - std::vector<LLUUID> ids; - ids.push_back(participant_uuid); - - LLGroupBanData ban_data; - createBanEntry(participant_uuid, ban_data); - LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mID, LLGroupMgr::BAN_CREATE, ids); - LLGroupMgr::getInstance()->sendGroupMemberEjects(mID, ids); - LLGroupMgr::getInstance()->sendGroupMembersRequest(mID); - LLSD args; - LLAvatarName av_name; - LLAvatarNameCache::get(participant_uuid, &av_name); - args["AVATAR_NAME"] = av_name.getUserName(); - args["GROUP_NAME"] = mName; - LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args)); -} - -// -// LLGroupMgr -// - -LLGroupMgr::LLGroupMgr(): - mMemberRequestInFlight(false) -{ -} - -LLGroupMgr::~LLGroupMgr() -{ - clearGroups(); -} - -void LLGroupMgr::clearGroups() -{ - std::for_each(mRoleActionSets.begin(), mRoleActionSets.end(), DeletePointer()); - mRoleActionSets.clear(); - std::for_each(mGroups.begin(), mGroups.end(), DeletePairedPointer()); - mGroups.clear(); - mObservers.clear(); -} - -void LLGroupMgr::clearGroupData(const LLUUID& group_id) -{ - group_map_t::iterator iter = mGroups.find(group_id); - if (iter != mGroups.end()) - { - delete (*iter).second; - mGroups.erase(iter); - } -} - -void LLGroupMgr::addObserver(LLGroupMgrObserver* observer) -{ - if( observer->getID() != LLUUID::null ) - mObservers.insert(std::pair<LLUUID, LLGroupMgrObserver*>(observer->getID(), observer)); -} - -void LLGroupMgr::addObserver(const LLUUID& group_id, LLParticularGroupObserver* observer) -{ - if(group_id.notNull() && observer) - { - mParticularObservers[group_id].insert(observer); - } -} - -void LLGroupMgr::removeObserver(LLGroupMgrObserver* observer) -{ - if (!observer) - { - return; - } - observer_multimap_t::iterator it; - it = mObservers.find(observer->getID()); - while (it != mObservers.end()) - { - if (it->second == observer) - { - mObservers.erase(it); - break; - } - else - { - ++it; - } - } -} - -void LLGroupMgr::removeObserver(const LLUUID& group_id, LLParticularGroupObserver* observer) -{ - if(group_id.isNull() || !observer) - { - return; - } - - observer_map_t::iterator obs_it = mParticularObservers.find(group_id); - if(obs_it == mParticularObservers.end()) - return; - - obs_it->second.erase(observer); - - if (obs_it->second.size() == 0) - mParticularObservers.erase(obs_it); -} - -LLGroupMgrGroupData* LLGroupMgr::getGroupData(const LLUUID& id) -{ - group_map_t::iterator gi = mGroups.find(id); - - if (gi != mGroups.end()) - { - return gi->second; - } - return NULL; -} - -// Helper function for LLGroupMgr::processGroupMembersReply -// This reformats date strings from MM/DD/YYYY to YYYY/MM/DD ( e.g. 1/27/2008 -> 2008/1/27 ) -// so that the sorter can sort by year before month before day. -static void formatDateString(std::string &date_string) -{ - using namespace boost; - cmatch result; - const regex expression("([0-9]{1,2})/([0-9]{1,2})/([0-9]{4})"); - if (regex_match(date_string.c_str(), result, expression)) - { - // convert matches to integers so that we can pad them with zeroes on Linux - S32 year = boost::lexical_cast<S32>(result[3]); - S32 month = boost::lexical_cast<S32>(result[1]); - S32 day = boost::lexical_cast<S32>(result[2]); - - // ISO 8601 date format - date_string = llformat("%04d/%02d/%02d", year, month, day); - } -} - -// static -void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) -{ - LL_PROFILE_ZONE_SCOPED; - - LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupMembersReply" << LL_ENDL; - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); - if (gAgent.getID() != agent_id) - { - LL_WARNS() << "Got group members reply for another agent!" << LL_ENDL; - return; - } - - LLUUID group_id; - msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id ); - - LLUUID request_id; - msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_RequestID, request_id); - - LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); - if (!group_datap || (group_datap->mMemberRequestID != request_id)) - { - LL_WARNS() << "processGroupMembersReply: Received incorrect (stale?) group or request id" << LL_ENDL; - return; - } - - msg->getS32(_PREHASH_GroupData, "MemberCount", group_datap->mMemberCount ); - - if (group_datap->mMemberCount > 0) - { - S32 contribution = 0; - std::string online_status; - std::string title; - U64 agent_powers = 0; - bool is_owner = false; - - S32 num_members = msg->getNumberOfBlocksFast(_PREHASH_MemberData); - for (S32 i = 0; i < num_members; i++) - { - LLUUID member_id; - - msg->getUUIDFast(_PREHASH_MemberData, _PREHASH_AgentID, member_id, i ); - msg->getS32(_PREHASH_MemberData, _PREHASH_Contribution, contribution, i); - msg->getU64(_PREHASH_MemberData, "AgentPowers", agent_powers, i); - msg->getStringFast(_PREHASH_MemberData, _PREHASH_OnlineStatus, online_status, i); - msg->getString(_PREHASH_MemberData, "Title", title, i); - msg->getBOOL(_PREHASH_MemberData,"IsOwner",is_owner,i); - - if (member_id.notNull()) - { - if (online_status == "Online") - { - static std::string localized_online(LLTrans::getString("group_member_status_online")); - online_status = localized_online; - } - else - { - formatDateString(online_status); // reformat for sorting, e.g. 12/25/2008 -> 2008/12/25 - } - - //LL_INFOS() << "Member " << member_id << " has powers " << std::hex << agent_powers << std::dec << LL_ENDL; - LLGroupMemberData* newdata = new LLGroupMemberData(member_id, - contribution, - agent_powers, - title, - online_status, - is_owner); -#if LL_DEBUG - LLGroupMgrGroupData::member_list_t::iterator mit = group_datap->mMembers.find(member_id); - if (mit != group_datap->mMembers.end()) - { - LL_INFOS() << " *** Received duplicate member data for agent " << member_id << LL_ENDL; - } -#endif - group_datap->mMembers[member_id] = newdata; - } - else - { - LL_INFOS() << "Received null group member data." << LL_ENDL; - } - } - - //if group members are loaded while titles are missing, load the titles. - if(group_datap->mTitles.size() < 1) - { - LLGroupMgr::getInstance()->sendGroupTitlesRequest(group_id); - } - } - - group_datap->mMemberVersion.generate(); - - if (group_datap->mMembers.size() == (U32)group_datap->mMemberCount) - { - group_datap->mMemberDataComplete = true; - group_datap->mMemberRequestID.setNull(); - // We don't want to make role-member data requests until we have all the members - if (group_datap->mPendingRoleMemberRequest) - { - group_datap->mPendingRoleMemberRequest = false; - LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_datap->mID); - } - } - - group_datap->mChanged = true; - LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA); -} - -//static -void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data) -{ - LL_PROFILE_ZONE_SCOPED; - - LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupPropertiesReply" << LL_ENDL; - if (!msg) - { - LL_ERRS() << "Can't access the messaging system" << LL_ENDL; - return; - } - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); - if (gAgent.getID() != agent_id) - { - LL_WARNS() << "Got group properties reply for another agent!" << LL_ENDL; - return; - } - - LLUUID group_id; - std::string name; - std::string charter; - bool show_in_list = false; - LLUUID founder_id; - U64 powers_mask = GP_NO_POWERS; - S32 money = 0; - std::string member_title; - LLUUID insignia_id; - LLUUID owner_role; - U32 membership_fee = 0; - bool open_enrollment = false; - S32 num_group_members = 0; - S32 num_group_roles = 0; - bool allow_publish = false; - bool mature = false; - - msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id ); - msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_FounderID, founder_id); - msg->getStringFast(_PREHASH_GroupData, _PREHASH_Name, name ); - msg->getStringFast(_PREHASH_GroupData, _PREHASH_Charter, charter ); - msg->getBOOLFast(_PREHASH_GroupData, _PREHASH_ShowInList, show_in_list ); - msg->getStringFast(_PREHASH_GroupData, _PREHASH_MemberTitle, member_title ); - msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_InsigniaID, insignia_id ); - msg->getU64Fast(_PREHASH_GroupData, _PREHASH_PowersMask, powers_mask ); - msg->getU32Fast(_PREHASH_GroupData, _PREHASH_MembershipFee, membership_fee ); - msg->getBOOLFast(_PREHASH_GroupData, _PREHASH_OpenEnrollment, open_enrollment ); - msg->getS32Fast(_PREHASH_GroupData, _PREHASH_GroupMembershipCount, num_group_members); - msg->getS32(_PREHASH_GroupData, "GroupRolesCount", num_group_roles); - msg->getS32Fast(_PREHASH_GroupData, _PREHASH_Money, money); - msg->getBOOL("GroupData", "AllowPublish", allow_publish); - msg->getBOOL("GroupData", "MaturePublish", mature); - msg->getUUID(_PREHASH_GroupData, "OwnerRole", owner_role); - - LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->createGroupData(group_id); - - group_datap->mName = name; - group_datap->mCharter = charter; - group_datap->mShowInList = show_in_list; - group_datap->mInsigniaID = insignia_id; - group_datap->mFounderID = founder_id; - group_datap->mMembershipFee = membership_fee; - group_datap->mOpenEnrollment = open_enrollment; - group_datap->mAllowPublish = allow_publish; - group_datap->mMaturePublish = mature; - group_datap->mOwnerRole = owner_role; - group_datap->mMemberCount = num_group_members; - group_datap->mRoleCount = num_group_roles + 1; // Add the everyone role. - - group_datap->mGroupPropertiesDataComplete = true; - group_datap->mChanged = true; - - properties_request_map_t::iterator request = LLGroupMgr::getInstance()->mPropRequests.find(group_id); - if (request != LLGroupMgr::getInstance()->mPropRequests.end()) - { - LLGroupMgr::getInstance()->mPropRequests.erase(request); - } - else - { - LL_DEBUGS("GrpMgr") << "GroupPropertyResponse received with no pending request. Response was slow." << LL_ENDL; - } - LLGroupMgr::getInstance()->notifyObservers(GC_PROPERTIES); -} - -// static -void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data) -{ - LL_PROFILE_ZONE_SCOPED; - - LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupRoleDataReply" << LL_ENDL; - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); - if (gAgent.getID() != agent_id) - { - LL_WARNS() << "Got group role data reply for another agent!" << LL_ENDL; - return; - } - - LLUUID group_id; - msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id ); - - LLUUID request_id; - msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_RequestID, request_id); - - LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); - if (!group_datap || (group_datap->mRoleDataRequestID != request_id)) - { - LL_WARNS() << "processGroupPropertiesReply: Received incorrect (stale?) group or request id" << LL_ENDL; - return; - } - - msg->getS32(_PREHASH_GroupData, "RoleCount", group_datap->mRoleCount ); - - std::string name; - std::string title; - std::string desc; - U64 powers = 0; - U32 member_count = 0; - LLUUID role_id; - - U32 num_blocks = msg->getNumberOfBlocks("RoleData"); - U32 i = 0; - for (i=0; i< num_blocks; ++i) - { - msg->getUUID("RoleData", "RoleID", role_id, i ); - - msg->getString("RoleData","Name",name,i); - msg->getString("RoleData","Title",title,i); - msg->getString("RoleData","Description",desc,i); - msg->getU64("RoleData","Powers",powers,i); - msg->getU32("RoleData","Members",member_count,i); - - //there are 3 predifined roles - Owners, Officers, Everyone - //there names are defined in lldatagroups.cpp - //lets change names from server to localized strings - if(name == "Everyone") - { - name = LLTrans::getString("group_role_everyone"); - } - else if(name == "Officers") - { - name = LLTrans::getString("group_role_officers"); - } - else if(name == "Owners") - { - name = LLTrans::getString("group_role_owners"); - } - - - - LL_DEBUGS("GrpMgr") << "Adding role data: " << name << " {" << role_id << "}" << LL_ENDL; - LLGroupRoleData* rd = new LLGroupRoleData(role_id,name,title,desc,powers,member_count); - group_datap->mRoles[role_id] = rd; - } - - if (group_datap->mRoles.size() == (U32)group_datap->mRoleCount) - { - group_datap->mRoleDataComplete = true; - group_datap->mRoleDataRequestID.setNull(); - // We don't want to make role-member data requests until we have all the role data - if (group_datap->mPendingRoleMemberRequest) - { - group_datap->mPendingRoleMemberRequest = false; - LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_datap->mID); - } - } - - group_datap->mChanged = true; - LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_DATA); -} - -// static -void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data) -{ - LL_PROFILE_ZONE_SCOPED; - - LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupRoleMembersReply" << LL_ENDL; - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); - if (gAgent.getID() != agent_id) - { - LL_WARNS() << "Got group role members reply for another agent!" << LL_ENDL; - return; - } - - LLUUID request_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_RequestID, request_id); - - LLUUID group_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id ); - - U32 total_pairs; - msg->getU32(_PREHASH_AgentData, "TotalPairs", total_pairs); - - LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); - if (!group_datap || (group_datap->mRoleMembersRequestID != request_id)) - { - LL_WARNS() << "processGroupRoleMembersReply: Received incorrect (stale?) group or request id" << LL_ENDL; - return; - } - - U32 num_blocks = msg->getNumberOfBlocks("MemberData"); - U32 i; - LLUUID member_id; - LLUUID role_id; - LLGroupRoleData* rd = NULL; - LLGroupMemberData* md = NULL; - - LLGroupMgrGroupData::role_list_t::iterator ri; - LLGroupMgrGroupData::member_list_t::iterator mi; - - // If total_pairs == 0, there are no members in any custom roles. - if (total_pairs > 0) - { - for (i = 0;i < num_blocks; ++i) - { - msg->getUUID("MemberData","RoleID",role_id,i); - msg->getUUID("MemberData","MemberID",member_id,i); - - if (role_id.notNull() && member_id.notNull() ) - { - rd = NULL; - ri = group_datap->mRoles.find(role_id); - if (ri != group_datap->mRoles.end()) - { - rd = ri->second; - } - - md = NULL; - mi = group_datap->mMembers.find(member_id); - if (mi != group_datap->mMembers.end()) - { - md = mi->second; - } - - if (rd && md) - { - LL_DEBUGS("GrpMgr") << "Adding role-member pair: " << role_id << ", " << member_id << LL_ENDL; - rd->addMember(member_id); - md->addRole(role_id,rd); - } - else - { - if (!rd) LL_WARNS() << "Received role data for unknown role " << role_id << " in group " << group_id << LL_ENDL; - if (!md) LL_WARNS() << "Received role data for unknown member " << member_id << " in group " << group_id << LL_ENDL; - } - } - } - - group_datap->mReceivedRoleMemberPairs += num_blocks; - } - - if (group_datap->mReceivedRoleMemberPairs == total_pairs) - { - // Add role data for the 'everyone' role to all members - LLGroupRoleData* everyone = group_datap->mRoles[LLUUID::null]; - if (!everyone) - { - LL_WARNS() << "Everyone role not found!" << LL_ENDL; - } - else - { - for (LLGroupMgrGroupData::member_list_t::iterator mi = group_datap->mMembers.begin(); - mi != group_datap->mMembers.end(); ++mi) - { - LLGroupMemberData* data = mi->second; - if (data) - { - data->addRole(LLUUID::null,everyone); - } - } - } - - group_datap->mRoleMemberDataComplete= true; - group_datap->mRoleMembersRequestID.setNull(); - } - - group_datap->mChanged = true; - LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_MEMBER_DATA); - - if (group_datap->mPendingBanRequest) - { - group_datap->banMemberById(group_datap->mPendingBanMemberID); - } -} - -// static -void LLGroupMgr::processGroupTitlesReply(LLMessageSystem* msg, void** data) -{ - LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupTitlesReply" << LL_ENDL; - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); - if (gAgent.getID() != agent_id) - { - LL_WARNS() << "Got group properties reply for another agent!" << LL_ENDL; - return; - } - - LLUUID group_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id ); - LLUUID request_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_RequestID, request_id); - - LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); - if (!group_datap || (group_datap->mTitlesRequestID != request_id)) - { - LL_WARNS() << "processGroupTitlesReply: Received incorrect (stale?) group" << LL_ENDL; - return; - } - - LLGroupTitle title; - - S32 i = 0; - S32 blocks = msg->getNumberOfBlocksFast(_PREHASH_GroupData); - for (i=0; i<blocks; ++i) - { - msg->getString("GroupData","Title",title.mTitle,i); - msg->getUUID("GroupData","RoleID",title.mRoleID,i); - msg->getBOOL("GroupData","Selected",title.mSelected,i); - - if (!title.mTitle.empty()) - { - LL_DEBUGS("GrpMgr") << "LLGroupMgr adding title: " << title.mTitle << ", " << title.mRoleID << ", " << (title.mSelected ? 'Y' : 'N') << LL_ENDL; - group_datap->mTitles.push_back(title); - } - } - - group_datap->mChanged = true; - LLGroupMgr::getInstance()->notifyObservers(GC_TITLES); -} - -// static -void LLGroupMgr::processEjectGroupMemberReply(LLMessageSystem* msg, void ** data) -{ - LL_DEBUGS("GrpMgr") << "processEjectGroupMemberReply" << LL_ENDL; - LLUUID group_id; - msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id); - bool success; - msg->getBOOLFast(_PREHASH_EjectData, _PREHASH_Success, success); - - // If we had a failure, the group panel needs to be updated. - if (!success) - { - LLGroupActions::refresh(group_id); - } -} - -// static -void LLGroupMgr::processJoinGroupReply(LLMessageSystem* msg, void ** data) -{ - LL_DEBUGS("GrpMgr") << "processJoinGroupReply" << LL_ENDL; - LLUUID group_id; - bool success; - msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id); - msg->getBOOLFast(_PREHASH_GroupData, _PREHASH_Success, success); - - if (success) - { - // refresh all group information - gAgent.sendAgentDataUpdateRequest(); - - LLGroupMgr::getInstance()->clearGroupData(group_id); - // refresh the floater for this group, if any. - LLGroupActions::refresh(group_id); - } -} - -// static -void LLGroupMgr::processLeaveGroupReply(LLMessageSystem* msg, void ** data) -{ - LL_DEBUGS("GrpMgr") << "processLeaveGroupReply" << LL_ENDL; - LLUUID group_id; - bool success; - msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id); - msg->getBOOLFast(_PREHASH_GroupData, _PREHASH_Success, success); - - if (success) - { - // refresh all group information - gAgent.sendAgentDataUpdateRequest(); - - LLGroupMgr::getInstance()->clearGroupData(group_id); - // close the floater for this group, if any. - LLGroupActions::closeGroup(group_id); - } -} - -// static -void LLGroupMgr::processCreateGroupReply(LLMessageSystem* msg, void ** data) -{ - LLUUID group_id; - bool success; - std::string message; - - msg->getUUIDFast(_PREHASH_ReplyData, _PREHASH_GroupID, group_id ); - - msg->getBOOLFast(_PREHASH_ReplyData, _PREHASH_Success, success ); - msg->getStringFast(_PREHASH_ReplyData, _PREHASH_Message, message ); - - if (success) - { - // refresh all group information - gAgent.sendAgentDataUpdateRequest(); - - // HACK! We haven't gotten the agent group update yet, so ... um ... fake it. - // This is so when we go to modify the group we will be able to do so. - // This isn't actually too bad because real data will come down in 2 or 3 miliseconds and replace this. - LLGroupData gd; - gd.mAcceptNotices = true; - gd.mListInProfile = true; - gd.mContribution = 0; - gd.mID = group_id; - gd.mName = "new group"; - gd.mPowers = GP_ALL_POWERS; - - gAgent.mGroups.push_back(gd); - - LLPanelGroupCreate::refreshCreatedGroup(group_id); - //FIXME - //LLFloaterGroupInfo::closeCreateGroup(); - //LLFloaterGroupInfo::showFromUUID(group_id,"roles_tab"); - } - else - { - // *TODO: Translate - LLSD args; - args["MESSAGE"] = message; - LLNotificationsUtil::add("UnableToCreateGroup", args); - } -} - -LLGroupMgrGroupData* LLGroupMgr::createGroupData(const LLUUID& id) -{ - LLGroupMgrGroupData* group_datap = NULL; - - group_map_t::iterator existing_group = LLGroupMgr::getInstance()->mGroups.find(id); - if (existing_group == LLGroupMgr::getInstance()->mGroups.end()) - { - group_datap = new LLGroupMgrGroupData(id); - LLGroupMgr::getInstance()->addGroup(group_datap); - } - else - { - group_datap = existing_group->second; - } - - if (group_datap) - { - group_datap->setAccessed(); - } - - return group_datap; -} - -bool LLGroupMgr::hasPendingPropertyRequest(const LLUUID & id) -{ - properties_request_map_t::iterator existing_req = LLGroupMgr::getInstance()->mPropRequests.find(id); - if (existing_req != LLGroupMgr::getInstance()->mPropRequests.end()) - { - if (gFrameTime - existing_req->second < MIN_GROUP_PROPERTY_REQUEST_FREQ) - { - return true; - } - else - { - LLGroupMgr::getInstance()->mPropRequests.erase(existing_req); - } - } - return false; -} - -void LLGroupMgr::addPendingPropertyRequest(const LLUUID& id) -{ - LLGroupMgr::getInstance()->mPropRequests[id] = gFrameTime; -} - -void LLGroupMgr::notifyObservers(LLGroupChange gc) -{ - for (group_map_t::iterator gi = mGroups.begin(); gi != mGroups.end(); ++gi) - { - LLUUID group_id = gi->first; - if (gi->second->mChanged) - { - // notify LLGroupMgrObserver - // Copy the map because observers may remove themselves on update - observer_multimap_t observers = mObservers; - - // find all observers for this group id - observer_multimap_t::iterator oi = observers.lower_bound(group_id); - observer_multimap_t::iterator end = observers.upper_bound(group_id); - for (; oi != end; ++oi) - { - oi->second->changed(gc); - } - gi->second->mChanged = false; - - - // notify LLParticularGroupObserver - observer_map_t::iterator obs_it = mParticularObservers.find(group_id); - if(obs_it == mParticularObservers.end()) - return; - - observer_set_t& obs = obs_it->second; - for (observer_set_t::iterator ob_it = obs.begin(); ob_it != obs.end(); ++ob_it) - { - (*ob_it)->changed(group_id, gc); - } - } - } -} - -void LLGroupMgr::addGroup(LLGroupMgrGroupData* group_datap) -{ - while (mGroups.size() >= MAX_CACHED_GROUPS) - { - // LRU: Remove the oldest un-observed group from cache until group size is small enough - - F32 oldest_access = LLFrameTimer::getTotalSeconds(); - group_map_t::iterator oldest_gi = mGroups.end(); - - for (group_map_t::iterator gi = mGroups.begin(); gi != mGroups.end(); ++gi ) - { - observer_multimap_t::iterator oi = mObservers.find(gi->first); - if (oi == mObservers.end()) - { - if (gi->second - && (gi->second->getAccessTime() < oldest_access)) - { - oldest_access = gi->second->getAccessTime(); - oldest_gi = gi; - } - } - } - - if (oldest_gi != mGroups.end()) - { - delete oldest_gi->second; - mGroups.erase(oldest_gi); - } - else - { - // All groups must be currently open, none to remove. - // Just add the new group anyway, but get out of this loop as it - // will never drop below max_cached_groups. - break; - } - } - - mGroups[group_datap->getID()] = group_datap; -} - - -void LLGroupMgr::sendGroupPropertiesRequest(const LLUUID& group_id) -{ - LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupPropertiesRequest" << LL_ENDL; - // This will happen when we get the reply - //LLGroupMgrGroupData* group_datap = createGroupData(group_id); - - if (LLGroupMgr::getInstance()->hasPendingPropertyRequest(group_id)) - { - LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupPropertiesRequest suppressed repeat for " << group_id << LL_ENDL; - return; - } - LLGroupMgr::getInstance()->addPendingPropertyRequest(group_id); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("GroupProfileRequest"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID",gAgent.getID()); - msg->addUUID("SessionID",gAgent.getSessionID()); - msg->nextBlock("GroupData"); - msg->addUUID("GroupID",group_id); - gAgent.sendReliableMessage(); -} - -void LLGroupMgr::sendGroupMembersRequest(const LLUUID& group_id) -{ - LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupMembersRequest" << LL_ENDL; - LLGroupMgrGroupData* group_datap = createGroupData(group_id); - if (group_datap->mMemberRequestID.isNull()) - { - group_datap->removeMemberData(); - group_datap->mMemberRequestID.generate(); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("GroupMembersRequest"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID",gAgent.getID()); - msg->addUUID("SessionID",gAgent.getSessionID()); - msg->nextBlock("GroupData"); - msg->addUUID("GroupID",group_id); - msg->addUUID("RequestID",group_datap->mMemberRequestID); - gAgent.sendReliableMessage(); - } -} - - -void LLGroupMgr::sendGroupRoleDataRequest(const LLUUID& group_id) -{ - LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupRoleDataRequest" << LL_ENDL; - LLGroupMgrGroupData* group_datap = createGroupData(group_id); - if (group_datap->mRoleDataRequestID.isNull()) - { - group_datap->removeRoleData(); - group_datap->mRoleDataRequestID.generate(); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("GroupRoleDataRequest"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID",gAgent.getID()); - msg->addUUID("SessionID",gAgent.getSessionID()); - msg->nextBlock("GroupData"); - msg->addUUID("GroupID",group_id); - msg->addUUID("RequestID",group_datap->mRoleDataRequestID); - gAgent.sendReliableMessage(); - } -} - -void LLGroupMgr::sendGroupRoleMembersRequest(const LLUUID& group_id) -{ - LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupRoleMembersRequest" << LL_ENDL; - LLGroupMgrGroupData* group_datap = createGroupData(group_id); - - if (group_datap->mRoleMembersRequestID.isNull()) - { - // Don't send the request if we don't have all the member or role data - if (!group_datap->isMemberDataComplete() - || !group_datap->isRoleDataComplete()) - { - // *TODO: KLW FIXME: Should we start a member or role data request? - LL_INFOS("GrpMgr") << " Pending: " << (group_datap->mPendingRoleMemberRequest ? "Y" : "N") - << " MemberDataComplete: " << (group_datap->mMemberDataComplete ? "Y" : "N") - << " RoleDataComplete: " << (group_datap->mRoleDataComplete ? "Y" : "N") << LL_ENDL; - group_datap->mPendingRoleMemberRequest = true; - return; - } - - group_datap->removeRoleMemberData(); - group_datap->mRoleMembersRequestID.generate(); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("GroupRoleMembersRequest"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID",gAgent.getID()); - msg->addUUID("SessionID",gAgent.getSessionID()); - msg->nextBlock("GroupData"); - msg->addUUID("GroupID",group_id); - msg->addUUID("RequestID",group_datap->mRoleMembersRequestID); - gAgent.sendReliableMessage(); - } -} - -void LLGroupMgr::sendGroupTitlesRequest(const LLUUID& group_id) -{ - LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupTitlesRequest" << LL_ENDL; - LLGroupMgrGroupData* group_datap = createGroupData(group_id); - - group_datap->mTitles.clear(); - group_datap->mTitlesRequestID.generate(); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("GroupTitlesRequest"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID",gAgent.getID()); - msg->addUUID("SessionID",gAgent.getSessionID()); - msg->addUUID("GroupID",group_id); - msg->addUUID("RequestID",group_datap->mTitlesRequestID); - - gAgent.sendReliableMessage(); -} - -void LLGroupMgr::sendGroupTitleUpdate(const LLUUID& group_id, const LLUUID& title_role_id) -{ - LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupTitleUpdate" << LL_ENDL; - - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("GroupTitleUpdate"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID",gAgent.getID()); - msg->addUUID("SessionID",gAgent.getSessionID()); - msg->addUUID("GroupID",group_id); - msg->addUUID("TitleRoleID",title_role_id); - - gAgent.sendReliableMessage(); - - // Save the change locally - LLGroupMgrGroupData* group_datap = createGroupData(group_id); - for (std::vector<LLGroupTitle>::iterator iter = group_datap->mTitles.begin(); - iter != group_datap->mTitles.end(); ++iter) - { - if (iter->mRoleID == title_role_id) - { - iter->mSelected = true; - } - else if (iter->mSelected) - { - iter->mSelected = false; - } - } -} - -// static -void LLGroupMgr::sendCreateGroupRequest(const std::string& name, - const std::string& charter, - U8 show_in_list, - const LLUUID& insignia, - S32 membership_fee, - bool open_enrollment, - bool allow_publish, - bool mature_publish) -{ - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("CreateGroupRequest"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID",gAgent.getID()); - msg->addUUID("SessionID",gAgent.getSessionID()); - - msg->nextBlock("GroupData"); - msg->addString("Name",name); - msg->addString("Charter",charter); - msg->addBOOL("ShowInList",show_in_list); - msg->addUUID("InsigniaID",insignia); - msg->addS32("MembershipFee",membership_fee); - msg->addBOOL("OpenEnrollment",open_enrollment); - msg->addBOOL("AllowPublish",allow_publish); - msg->addBOOL("MaturePublish",mature_publish); - - gAgent.sendReliableMessage(); -} - -void LLGroupMgr::sendUpdateGroupInfo(const LLUUID& group_id) -{ - LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendUpdateGroupInfo" << LL_ENDL; - LLGroupMgrGroupData* group_datap = createGroupData(group_id); - - LLMessageSystem* msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_UpdateGroupInfo); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID,gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); - - msg->nextBlockFast(_PREHASH_GroupData); - msg->addUUIDFast(_PREHASH_GroupID,group_datap->getID()); - msg->addStringFast(_PREHASH_Charter,group_datap->mCharter); - msg->addBOOLFast(_PREHASH_ShowInList,group_datap->mShowInList); - msg->addUUIDFast(_PREHASH_InsigniaID,group_datap->mInsigniaID); - msg->addS32Fast(_PREHASH_MembershipFee,group_datap->mMembershipFee); - msg->addBOOLFast(_PREHASH_OpenEnrollment,group_datap->mOpenEnrollment); - msg->addBOOLFast(_PREHASH_AllowPublish,group_datap->mAllowPublish); - msg->addBOOLFast(_PREHASH_MaturePublish,group_datap->mMaturePublish); - - gAgent.sendReliableMessage(); - - // Not expecting a response, so let anyone else watching know the data has changed. - group_datap->mChanged = true; - notifyObservers(GC_PROPERTIES); -} - -void LLGroupMgr::sendGroupRoleMemberChanges(const LLUUID& group_id) -{ - LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupRoleMemberChanges" << LL_ENDL; - LLGroupMgrGroupData* group_datap = createGroupData(group_id); - - if (group_datap->mRoleMemberChanges.empty()) return; - - LLMessageSystem* msg = gMessageSystem; - - bool start_message = true; - for (LLGroupMgrGroupData::change_map_t::const_iterator citer = group_datap->mRoleMemberChanges.begin(); - citer != group_datap->mRoleMemberChanges.end(); ++citer) - { - if (start_message) - { - msg->newMessage("GroupRoleChanges"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID,gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_GroupID,group_id); - start_message = false; - } - msg->nextBlock("RoleChange"); - msg->addUUID("RoleID",citer->second.mRole); - msg->addUUID("MemberID",citer->second.mMember); - msg->addU32("Change",(U32)citer->second.mChange); - - if (msg->isSendFullFast()) - { - gAgent.sendReliableMessage(); - start_message = true; - } - } - - if (!start_message) - { - gAgent.sendReliableMessage(); - } - - group_datap->mRoleMemberChanges.clear(); - - // Not expecting a response, so let anyone else watching know the data has changed. - group_datap->mChanged = true; - notifyObservers(GC_ROLE_MEMBER_DATA); -} - -//static -void LLGroupMgr::sendGroupMemberJoin(const LLUUID& group_id) -{ - - LLUIUsage::instance().logCommand("Group.Join"); - - LLMessageSystem *msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_JoinGroupRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_GroupData); - msg->addUUIDFast(_PREHASH_GroupID, group_id); - - gAgent.sendReliableMessage(); -} - -// member_role_pairs is <member_id,role_id> -// static -void LLGroupMgr::sendGroupMemberInvites(const LLUUID& group_id, std::map<LLUUID,LLUUID>& member_role_pairs) -{ - bool start_message = true; - LLMessageSystem* msg = gMessageSystem; - - for (std::map<LLUUID,LLUUID>::iterator it = member_role_pairs.begin(); - it != member_role_pairs.end(); ++it) - { - if (start_message) - { - msg->newMessage("InviteGroupRequest"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID",gAgent.getID()); - msg->addUUID("SessionID",gAgent.getSessionID()); - msg->nextBlock("GroupData"); - msg->addUUID("GroupID",group_id); - start_message = false; - } - - msg->nextBlock("InviteData"); - msg->addUUID("InviteeID",(*it).first); - msg->addUUID("RoleID",(*it).second); - - if (msg->isSendFull()) - { - gAgent.sendReliableMessage(); - start_message = true; - } - } - - if (!start_message) - { - gAgent.sendReliableMessage(); - } -} - -//static -void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id, - uuid_vec_t& member_ids) -{ - bool start_message = true; - LLMessageSystem* msg = gMessageSystem; - - LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); - if (!group_datap) return; - - for (uuid_vec_t::iterator it = member_ids.begin(); - it != member_ids.end(); ++it) - { - LLUUID& ejected_member_id = (*it); - - // Can't use 'eject' to leave a group. - if (ejected_member_id == gAgent.getID()) continue; - - // Make sure they are in the group, and we need the member data - LLGroupMgrGroupData::member_list_t::iterator mit = group_datap->mMembers.find(ejected_member_id); - if (mit != group_datap->mMembers.end()) - { - // Add them to the message - if (start_message) - { - msg->newMessage("EjectGroupMemberRequest"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID",gAgent.getID()); - msg->addUUID("SessionID",gAgent.getSessionID()); - msg->nextBlock("GroupData"); - msg->addUUID("GroupID",group_id); - start_message = false; - } - - msg->nextBlock("EjectData"); - msg->addUUID("EjecteeID",ejected_member_id); - - if (msg->isSendFull()) - { - gAgent.sendReliableMessage(); - start_message = true; - } - - LLGroupMemberData* member_data = (*mit).second; - - // Clean up groupmgr - for (LLGroupMemberData::role_list_t::iterator rit = member_data->roleBegin(); - rit != member_data->roleEnd(); ++rit) - { - if ((*rit).first.notNull() && (*rit).second!=0) - { - (*rit).second->removeMember(ejected_member_id); - } - } - - group_datap->mMembers.erase(ejected_member_id); - - // member_data was introduced and is used here instead of (*mit).second to avoid crash because of invalid iterator - // It becomes invalid after line with erase above. EXT-4778 - delete member_data; - } - } - - if (!start_message) - { - gAgent.sendReliableMessage(); - } - - group_datap->mMemberVersion.generate(); -} - -void LLGroupMgr::getGroupBanRequestCoro(std::string url, LLUUID groupId) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - - std::string finalUrl = url + "?group_id=" + groupId.asString(); - - LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (!status) - { - LL_WARNS("GrpMgr") << "Error receiving group member data " << LL_ENDL; - return; - } - - if (result.has("ban_list")) - { - result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); - // group ban data received - processGroupBanRequest(result); - } -} - -void LLGroupMgr::postGroupBanRequestCoro(std::string url, LLUUID groupId, - U32 action, uuid_vec_t banList, bool update) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); - LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions); - - httpOptions->setFollowRedirects(false); - - httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); - - - std::string finalUrl = url + "?group_id=" + groupId.asString(); - - LLSD postData = LLSD::emptyMap(); - postData["ban_action"] = (LLSD::Integer)action; - // Add our list of potential banned residents to the list - postData["ban_ids"] = LLSD::emptyArray(); - LLSD banEntry; - - uuid_vec_t::const_iterator it = banList.begin(); - for (; it != banList.end(); ++it) - { - banEntry = (*it); - postData["ban_ids"].append(banEntry); - } - - LL_WARNS() << "post: " << ll_pretty_print_sd(postData) << LL_ENDL; - - LLSD result = httpAdapter->postAndSuspend(httpRequest, finalUrl, postData, httpOptions, httpHeaders); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (!status) - { - LL_WARNS("GrpMgr") << "Error posting group member data " << LL_ENDL; - return; - } - - if (result.has("ban_list")) - { - result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); - // group ban data received - processGroupBanRequest(result); - } - - if (update) - { - getGroupBanRequestCoro(url, groupId); - } -} - -void LLGroupMgr::sendGroupBanRequest( EBanRequestType request_type, - const LLUUID& group_id, - U32 ban_action, /* = BAN_NO_ACTION */ - const std::vector<LLUUID> &ban_list) /* = std::vector<LLUUID>() */ -{ - LLViewerRegion* currentRegion = gAgent.getRegion(); - if(!currentRegion) - { - LL_WARNS("GrpMgr") << "Agent does not have a current region. Uh-oh!" << LL_ENDL; - return; - } - - // Check to make sure we have our capabilities - if(!currentRegion->capabilitiesReceived()) - { - LL_WARNS("GrpMgr") << " Capabilities not received!" << LL_ENDL; - return; - } - - // Get our capability - std::string cap_url = currentRegion->getCapability("GroupAPIv1"); - if(cap_url.empty()) - { - return; - } - - U32 action = ban_action & ~BAN_UPDATE; - bool update = ((ban_action & BAN_UPDATE) == BAN_UPDATE); - - switch (request_type) - { - case REQUEST_GET: - LLCoros::instance().launch("LLGroupMgr::getGroupBanRequestCoro", - boost::bind(&LLGroupMgr::getGroupBanRequestCoro, this, cap_url, group_id)); - break; - case REQUEST_POST: - LLCoros::instance().launch("LLGroupMgr::postGroupBanRequestCoro", - boost::bind(&LLGroupMgr::postGroupBanRequestCoro, this, cap_url, group_id, - action, ban_list, update)); - break; - case REQUEST_PUT: - case REQUEST_DEL: - break; - } -} - -void LLGroupMgr::processGroupBanRequest(const LLSD& content) -{ - // Did we get anything in content? - if(!content.size()) - { - LL_WARNS("GrpMgr") << "No group member data received." << LL_ENDL; - return; - } - - LLUUID group_id = content["group_id"].asUUID(); - - LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id); - if (!gdatap) - return; - - gdatap->clearBanList(); - LLSD::map_const_iterator i = content["ban_list"].beginMap(); - LLSD::map_const_iterator iEnd = content["ban_list"].endMap(); - for(;i != iEnd; ++i) - { - const LLUUID ban_id(i->first); - LLSD ban_entry(i->second); - - LLGroupBanData ban_data; - if(ban_entry.has("ban_date")) - { - ban_data.mBanDate = ban_entry["ban_date"].asDate(); - // TODO: Ban Reason - } - - gdatap->createBanEntry(ban_id, ban_data); - } - - gdatap->mChanged = true; - LLGroupMgr::getInstance()->notifyObservers(GC_BANLIST); -} - -void LLGroupMgr::groupMembersRequestCoro(std::string url, LLUUID groupId) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); - - mMemberRequestInFlight = true; - - LLSD postData = LLSD::emptyMap(); - postData["group_id"] = groupId; - - LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (!status) - { - LL_WARNS("GrpMgr") << "Error receiving group member data " << LL_ENDL; - mMemberRequestInFlight = false; - return; - } - - result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); - LLGroupMgr::processCapGroupMembersRequest(result); - mMemberRequestInFlight = false; -} - -void LLGroupMgr::sendCapGroupMembersRequest(const LLUUID& group_id) -{ - static U32 lastGroupMemberRequestFrame = 0; - - // Have we requested the information already this frame? - // Todo: make this per group, we can invite to one group and simultaneously be checking another one - if ((lastGroupMemberRequestFrame == gFrameCount) || (mMemberRequestInFlight)) - return; - - LLViewerRegion* currentRegion = gAgent.getRegion(); - // Thank you FS:Ansariel! - if(!currentRegion) - { - LL_WARNS("GrpMgr") << "Agent does not have a current region. Uh-oh!" << LL_ENDL; - return; - } - - // Check to make sure we have our capabilities - if(!currentRegion->capabilitiesReceived()) - { - LL_WARNS("GrpMgr") << " Capabilities not received!" << LL_ENDL; - return; - } - - // Get our capability - std::string cap_url = currentRegion->getCapability("GroupMemberData"); - - // Thank you FS:Ansariel! - if(cap_url.empty()) - { - LL_INFOS("GrpMgr") << "Region has no GroupMemberData capability. Falling back to UDP fetch." << LL_ENDL; - sendGroupMembersRequest(group_id); - return; - } - - LLGroupMgrGroupData* group_datap = createGroupData(group_id); //make sure group exists - group_datap->mMemberRequestID.generate(); // mark as pending - - lastGroupMemberRequestFrame = gFrameCount; - - LLCoros::instance().launch("LLGroupMgr::groupMembersRequestCoro", - boost::bind(&LLGroupMgr::groupMembersRequestCoro, this, cap_url, group_id)); -} - - -void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) -{ - // Did we get anything in content? - if(!content.size()) - { - LL_DEBUGS("GrpMgr") << "No group member data received." << LL_ENDL; - return; - } - - LLUUID group_id = content["group_id"].asUUID(); - - LLGroupMgrGroupData* group_datap = getGroupData(group_id); - if(!group_datap) - { - LL_WARNS("GrpMgr") << "Received incorrect, possibly stale, group or request id" << LL_ENDL; - return; - } - - // If we have no members, there's no reason to do anything else - S32 num_members = content["member_count"]; - if (num_members < 1) - { - LL_INFOS("GrpMgr") << "Received empty group members list for group id: " << group_id.asString() << LL_ENDL; - // Set mMemberDataComplete for correct handling of empty responses. See MAINT-5237 - group_datap->mMemberDataComplete = true; - group_datap->mChanged = true; - LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA); - return; - } - - group_datap->mMemberCount = num_members; - - LLSD member_list = content["members"]; - LLSD titles = content["titles"]; - LLSD defaults = content["defaults"]; - - std::string online_status; - std::string title; - S32 contribution; - U64 member_powers; - // If this is changed to a bool, make sure to change the LLGroupMemberData constructor - bool is_owner; - - // Compute this once, rather than every time. - U64 default_powers = llstrtou64(defaults["default_powers"].asString().c_str(), NULL, 16); - - LLSD::map_const_iterator member_iter_start = member_list.beginMap(); - LLSD::map_const_iterator member_iter_end = member_list.endMap(); - for( ; member_iter_start != member_iter_end; ++member_iter_start) - { - // Reset defaults - online_status = "unknown"; - title = titles[0].asString(); - contribution = 0; - member_powers = default_powers; - is_owner = false; - - const LLUUID member_id(member_iter_start->first); - LLSD member_info = member_iter_start->second; - - if(member_info.has("last_login")) - { - online_status = member_info["last_login"].asString(); - if(online_status == "Online") - online_status = LLTrans::getString("group_member_status_online"); - else - formatDateString(online_status); - } - - if(member_info.has("title")) - title = titles[member_info["title"].asInteger()].asString(); - - if(member_info.has("powers")) - member_powers = llstrtou64(member_info["powers"].asString().c_str(), NULL, 16); - - if(member_info.has("donated_square_meters")) - contribution = member_info["donated_square_meters"]; - - if(member_info.has("owner")) - is_owner = true; - - LLGroupMemberData* data = new LLGroupMemberData(member_id, - contribution, - member_powers, - title, - online_status, - is_owner); - - LLGroupMemberData* member_old = group_datap->mMembers[member_id]; - if (member_old && group_datap->mRoleMemberDataComplete) - { - LLGroupMemberData::role_list_t::iterator rit = member_old->roleBegin(); - LLGroupMemberData::role_list_t::iterator end = member_old->roleEnd(); - - for ( ; rit != end; ++rit) - { - data->addRole((*rit).first,(*rit).second); - } - } - else - { - group_datap->mRoleMemberDataComplete = false; - } - - group_datap->mMembers[member_id] = data; - } - - group_datap->mMemberVersion.generate(); - - // Technically, we have this data, but to prevent completely overhauling - // this entire system (it would be nice, but I don't have the time), - // I'm going to be dumb and just call services I most likely don't need - // with the thought being that the system might need it to be done. - // - // TODO: - // Refactor to reduce multiple calls for data we already have. - if(group_datap->mTitles.size() < 1) - sendGroupTitlesRequest(group_id); - - - group_datap->mMemberDataComplete = true; - group_datap->mMemberRequestID.setNull(); - // Make the role-member data request - if (group_datap->mPendingRoleMemberRequest || !group_datap->mRoleMemberDataComplete) - { - group_datap->mPendingRoleMemberRequest = false; - sendGroupRoleMembersRequest(group_id); - } - - group_datap->mChanged = true; - notifyObservers(GC_MEMBER_DATA); - -} - - -void LLGroupMgr::sendGroupRoleChanges(const LLUUID& group_id) -{ - LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupRoleChanges" << LL_ENDL; - LLGroupMgrGroupData* group_datap = getGroupData(group_id); - - if (group_datap && group_datap->pendingRoleChanges()) - { - group_datap->sendRoleChanges(); - - // Not expecting a response, so let anyone else watching know the data has changed. - group_datap->mChanged = true; - notifyObservers(GC_ROLE_DATA); - } -} - -void LLGroupMgr::cancelGroupRoleChanges(const LLUUID& group_id) -{ - LL_DEBUGS("GrpMgr") << "LLGroupMgr::cancelGroupRoleChanges" << LL_ENDL; - LLGroupMgrGroupData* group_datap = getGroupData(group_id); - - if (group_datap) group_datap->cancelRoleChanges(); -} - -//static -bool LLGroupMgr::parseRoleActions(const std::string& xml_filename) -{ - LLXMLNodePtr root; - - bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root); - - if (!success || !root || !root->hasName( "role_actions" )) - { - LL_ERRS() << "Problem reading UI role_actions file: " << xml_filename << LL_ENDL; - return false; - } - - LLXMLNodeList role_list; - - root->getChildren("action_set", role_list, false); - - for (LLXMLNodeList::iterator role_iter = role_list.begin(); role_iter != role_list.end(); ++role_iter) - { - LLXMLNodePtr action_set = role_iter->second; - - LLRoleActionSet* role_action_set = new LLRoleActionSet(); - LLRoleAction* role_action_data = new LLRoleAction(); - - // name= - std::string action_set_name; - if (action_set->getAttributeString("name", action_set_name)) - { - LL_DEBUGS("GrpMgr") << "Loading action set " << action_set_name << LL_ENDL; - role_action_data->mName = action_set_name; - } - else - { - LL_WARNS() << "Unable to parse action set with no name" << LL_ENDL; - delete role_action_set; - delete role_action_data; - continue; - } - // description= - std::string set_description; - if (action_set->getAttributeString("description", set_description)) - { - role_action_data->mDescription = set_description; - } - // long description= - std::string set_longdescription; - if (action_set->getAttributeString("longdescription", set_longdescription)) - { - role_action_data->mLongDescription = set_longdescription; - } - - // power mask= - U64 set_power_mask = 0; - - LLXMLNodeList action_list; - LLXMLNodeList::iterator action_iter; - - action_set->getChildren("action", action_list, false); - - for (action_iter = action_list.begin(); action_iter != action_list.end(); ++action_iter) - { - LLXMLNodePtr action = action_iter->second; - - LLRoleAction* role_action = new LLRoleAction(); - - // name= - std::string action_name; - if (action->getAttributeString("name", action_name)) - { - LL_DEBUGS("GrpMgr") << "Loading action " << action_name << LL_ENDL; - role_action->mName = action_name; - } - else - { - LL_WARNS() << "Unable to parse action with no name" << LL_ENDL; - delete role_action; - continue; - } - // description= - std::string description; - if (action->getAttributeString("description", description)) - { - role_action->mDescription = description; - } - // long description= - std::string longdescription; - if (action->getAttributeString("longdescription", longdescription)) - { - role_action->mLongDescription = longdescription; - } - // description= - S32 power_bit = 0; - if (action->getAttributeS32("value", power_bit)) - { - if (0 <= power_bit && power_bit < 64) - { - role_action->mPowerBit = 0x1LL << power_bit; - } - } - - set_power_mask |= role_action->mPowerBit; - - role_action_set->mActions.push_back(role_action); - } - - role_action_data->mPowerBit = set_power_mask; - role_action_set->mActionSetData = role_action_data; - - LLGroupMgr::getInstance()->mRoleActionSets.push_back(role_action_set); - } - return true; -} - -// static -void LLGroupMgr::debugClearAllGroups(void*) -{ - LLGroupMgr::getInstance()->clearGroups(); - LLGroupMgr::parseRoleActions("role_actions.xml"); -} - - +/**
+ * @file llgroupmgr.cpp
+ * @brief LLGroupMgr class implementation
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+/**
+ * Manager for aggregating all client knowledge for specific groups
+ * Keeps a cache of group information.
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llgroupmgr.h"
+
+#include <vector>
+#include <algorithm>
+
+#include "llappviewer.h"
+#include "llagent.h"
+#include "llavatarnamecache.h"
+#include "llui.h"
+#include "message.h"
+#include "roles_constants.h"
+#include "lltransactiontypes.h"
+#include "llstatusbar.h"
+#include "llviewerwindow.h"
+#include "llpanelgroupcreate.h"
+#include "llgroupactions.h"
+#include "llnotificationsutil.h"
+#include "lluictrlfactory.h"
+#include "lltrans.h"
+#include "llviewerregion.h"
+#include <boost/regex.hpp>
+#include "llcorehttputil.h"
+#include "lluiusage.h"
+
+
+#if LL_MSVC
+#pragma warning(push)
+// disable boost::lexical_cast warning
+#pragma warning (disable:4702)
+#endif
+
+#include <boost/lexical_cast.hpp>
+
+#if LL_MSVC
+#pragma warning(pop) // Restore all warnings to the previous state
+#endif
+
+const U32 MAX_CACHED_GROUPS = 20;
+
+//
+// LLRoleActionSet
+//
+LLRoleActionSet::LLRoleActionSet()
+: mActionSetData(NULL)
+{ }
+
+LLRoleActionSet::~LLRoleActionSet()
+{
+ delete mActionSetData;
+ std::for_each(mActions.begin(), mActions.end(), DeletePointer());
+ mActions.clear();
+}
+
+//
+// LLGroupMemberData
+//
+
+LLGroupMemberData::LLGroupMemberData(const LLUUID& id,
+ S32 contribution,
+ U64 agent_powers,
+ const std::string& title,
+ const std::string& online_status,
+ bool is_owner) :
+ mID(id),
+ mContribution(contribution),
+ mAgentPowers(agent_powers),
+ mTitle(title),
+ mOnlineStatus(online_status),
+ mIsOwner(is_owner)
+{
+}
+
+LLGroupMemberData::~LLGroupMemberData()
+{
+}
+
+void LLGroupMemberData::addRole(const LLUUID& role, LLGroupRoleData* rd)
+{
+ mRolesList[role] = rd;
+}
+
+bool LLGroupMemberData::removeRole(const LLUUID& role)
+{
+ role_list_t::iterator it = mRolesList.find(role);
+
+ if (it != mRolesList.end())
+ {
+ mRolesList.erase(it);
+ return true;
+ }
+
+ return false;
+}
+
+//
+// LLGroupRoleData
+//
+
+LLGroupRoleData::LLGroupRoleData(const LLUUID& role_id,
+ const std::string& role_name,
+ const std::string& role_title,
+ const std::string& role_desc,
+ const U64 role_powers,
+ const S32 member_count) :
+ mRoleID(role_id),
+ mMemberCount(member_count),
+ mMembersNeedsSort(false)
+{
+ mRoleData.mRoleName = role_name;
+ mRoleData.mRoleTitle = role_title;
+ mRoleData.mRoleDescription = role_desc;
+ mRoleData.mRolePowers = role_powers;
+ mRoleData.mChangeType = RC_UPDATE_NONE;
+}
+
+LLGroupRoleData::LLGroupRoleData(const LLUUID& role_id,
+ LLRoleData role_data,
+ const S32 member_count) :
+ mRoleID(role_id),
+ mRoleData(role_data),
+ mMemberCount(member_count),
+ mMembersNeedsSort(false)
+{
+
+}
+
+LLGroupRoleData::~LLGroupRoleData()
+{
+}
+
+S32 LLGroupRoleData::getMembersInRole(uuid_vec_t members,
+ bool needs_sort)
+{
+ if (mRoleID.isNull())
+ {
+ // This is the everyone role, just return the size of members,
+ // because everyone is in the everyone role.
+ return members.size();
+ }
+
+ // Sort the members list, if needed.
+ if (mMembersNeedsSort)
+ {
+ std::sort(mMemberIDs.begin(), mMemberIDs.end());
+ mMembersNeedsSort = false;
+ }
+ if (needs_sort)
+ {
+ // Sort the members parameter.
+ std::sort(members.begin(), members.end());
+ }
+
+ // Return the number of members in the intersection.
+ S32 max_size = llmin( members.size(), mMemberIDs.size() );
+ uuid_vec_t in_role( max_size );
+ uuid_vec_t::iterator in_role_end;
+ in_role_end = std::set_intersection(mMemberIDs.begin(), mMemberIDs.end(),
+ members.begin(), members.end(),
+ in_role.begin());
+ return in_role_end - in_role.begin();
+}
+
+void LLGroupRoleData::addMember(const LLUUID& member)
+{
+ mMembersNeedsSort = true;
+ mMemberIDs.push_back(member);
+}
+
+bool LLGroupRoleData::removeMember(const LLUUID& member)
+{
+ uuid_vec_t::iterator it = std::find(mMemberIDs.begin(),mMemberIDs.end(),member);
+
+ if (it != mMemberIDs.end())
+ {
+ mMembersNeedsSort = true;
+ mMemberIDs.erase(it);
+ return true;
+ }
+
+ return false;
+}
+
+void LLGroupRoleData::clearMembers()
+{
+ mMembersNeedsSort = false;
+ mMemberIDs.clear();
+}
+
+
+//
+// LLGroupMgrGroupData
+//
+
+LLGroupMgrGroupData::LLGroupMgrGroupData(const LLUUID& id) :
+ mID(id),
+ mShowInList(true),
+ mOpenEnrollment(false),
+ mMembershipFee(0),
+ mAllowPublish(false),
+ mListInProfile(false),
+ mMaturePublish(false),
+ mChanged(false),
+ mMemberCount(0),
+ mRoleCount(0),
+ mReceivedRoleMemberPairs(0),
+ mMemberDataComplete(false),
+ mRoleDataComplete(false),
+ mRoleMemberDataComplete(false),
+ mGroupPropertiesDataComplete(false),
+ mPendingRoleMemberRequest(false),
+ mAccessTime(0.0f),
+ mPendingBanRequest(false)
+{
+ mMemberVersion.generate();
+}
+
+void LLGroupMgrGroupData::setAccessed()
+{
+ mAccessTime = (F32)LLFrameTimer::getTotalSeconds();
+}
+
+bool LLGroupMgrGroupData::getRoleData(const LLUUID& role_id, LLRoleData& role_data)
+{
+ role_data_map_t::const_iterator it;
+
+ // Do we have changes for it?
+ it = mRoleChanges.find(role_id);
+ if (it != mRoleChanges.end())
+ {
+ if ((*it).second.mChangeType == RC_DELETE) return false;
+
+ role_data = (*it).second;
+ return true;
+ }
+
+ // Ok, no changes, hasn't been deleted, isn't a new role, just find the role.
+ role_list_t::const_iterator rit = mRoles.find(role_id);
+ if (rit != mRoles.end())
+ {
+ role_data = (*rit).second->getRoleData();
+ return true;
+ }
+
+ // This role must not exist.
+ return false;
+}
+
+
+void LLGroupMgrGroupData::setRoleData(const LLUUID& role_id, LLRoleData role_data)
+{
+ // If this is a newly created group, we need to change the data in the created list.
+ role_data_map_t::iterator it;
+ it = mRoleChanges.find(role_id);
+ if (it != mRoleChanges.end())
+ {
+ if ((*it).second.mChangeType == RC_CREATE)
+ {
+ role_data.mChangeType = RC_CREATE;
+ mRoleChanges[role_id] = role_data;
+ return;
+ }
+ else if ((*it).second.mChangeType == RC_DELETE)
+ {
+ // Don't do anything for a role being deleted.
+ return;
+ }
+ }
+
+ // Not a new role, so put it in the changes list.
+ LLRoleData old_role_data;
+ role_list_t::iterator rit = mRoles.find(role_id);
+ if (rit != mRoles.end())
+ {
+ bool data_change = ( ((*rit).second->mRoleData.mRoleDescription != role_data.mRoleDescription)
+ || ((*rit).second->mRoleData.mRoleName != role_data.mRoleName)
+ || ((*rit).second->mRoleData.mRoleTitle != role_data.mRoleTitle) );
+ bool powers_change = ((*rit).second->mRoleData.mRolePowers != role_data.mRolePowers);
+
+ if (!data_change && !powers_change)
+ {
+ // We are back to the original state, the changes have been 'undone' so take out the change.
+ mRoleChanges.erase(role_id);
+ return;
+ }
+
+ if (data_change && powers_change)
+ {
+ role_data.mChangeType = RC_UPDATE_ALL;
+ }
+ else if (data_change)
+ {
+ role_data.mChangeType = RC_UPDATE_DATA;
+ }
+ else
+ {
+ role_data.mChangeType = RC_UPDATE_POWERS;
+ }
+
+ mRoleChanges[role_id] = role_data;
+ }
+ else
+ {
+ LL_WARNS() << "Change being made to non-existant role " << role_id << LL_ENDL;
+ }
+}
+
+bool LLGroupMgrGroupData::pendingRoleChanges()
+{
+ return (!mRoleChanges.empty());
+}
+
+// This is a no-op if the role has already been created.
+void LLGroupMgrGroupData::createRole(const LLUUID& role_id, LLRoleData role_data)
+{
+ if (mRoleChanges.find(role_id) != mRoleChanges.end())
+ {
+ LL_WARNS() << "create role for existing role! " << role_id << LL_ENDL;
+ }
+ else
+ {
+ role_data.mChangeType = RC_CREATE;
+ mRoleChanges[role_id] = role_data;
+ }
+}
+
+void LLGroupMgrGroupData::deleteRole(const LLUUID& role_id)
+{
+ role_data_map_t::iterator it;
+
+ // If this was a new role, just discard it.
+ it = mRoleChanges.find(role_id);
+ if (it != mRoleChanges.end()
+ && (*it).second.mChangeType == RC_CREATE)
+ {
+ mRoleChanges.erase(it);
+ return;
+ }
+
+ LLRoleData rd;
+ rd.mChangeType = RC_DELETE;
+ mRoleChanges[role_id] = rd;
+}
+
+void LLGroupMgrGroupData::addRolePower(const LLUUID &role_id, U64 power)
+{
+ LLRoleData rd;
+ if (getRoleData(role_id,rd))
+ {
+ rd.mRolePowers |= power;
+ setRoleData(role_id,rd);
+ }
+ else
+ {
+ LL_WARNS() << "addRolePower: no role data found for " << role_id << LL_ENDL;
+ }
+}
+
+void LLGroupMgrGroupData::removeRolePower(const LLUUID &role_id, U64 power)
+{
+ LLRoleData rd;
+ if (getRoleData(role_id,rd))
+ {
+ rd.mRolePowers &= ~power;
+ setRoleData(role_id,rd);
+ }
+ else
+ {
+ LL_WARNS() << "removeRolePower: no role data found for " << role_id << LL_ENDL;
+ }
+}
+
+U64 LLGroupMgrGroupData::getRolePowers(const LLUUID& role_id)
+{
+ LLRoleData rd;
+ if (getRoleData(role_id,rd))
+ {
+ return rd.mRolePowers;
+ }
+ else
+ {
+ LL_WARNS() << "getRolePowers: no role data found for " << role_id << LL_ENDL;
+ return GP_NO_POWERS;
+ }
+}
+
+void LLGroupMgrGroupData::removeData()
+{
+ // Remove member data first, because removeRoleData will walk the member list
+ removeMemberData();
+ removeRoleData();
+}
+
+void LLGroupMgrGroupData::removeMemberData()
+{
+ for (member_list_t::iterator mi = mMembers.begin(); mi != mMembers.end(); ++mi)
+ {
+ delete mi->second;
+ }
+ mMembers.clear();
+ mMemberDataComplete = false;
+ mMemberVersion.generate();
+}
+
+void LLGroupMgrGroupData::removeRoleData()
+{
+ for (member_list_t::iterator mi = mMembers.begin(); mi != mMembers.end(); ++mi)
+ {
+ LLGroupMemberData* data = mi->second;
+ if (data)
+ {
+ data->clearRoles();
+ }
+ }
+
+ for (role_list_t::iterator ri = mRoles.begin(); ri != mRoles.end(); ++ri)
+ {
+ LLGroupRoleData* data = ri->second;
+ delete data;
+ }
+ mRoles.clear();
+ mReceivedRoleMemberPairs = 0;
+ mRoleDataComplete = false;
+ mRoleMemberDataComplete= false;
+}
+
+void LLGroupMgrGroupData::removeRoleMemberData()
+{
+ for (member_list_t::iterator mi = mMembers.begin(); mi != mMembers.end(); ++mi)
+ {
+ LLGroupMemberData* data = mi->second;
+ if (data)
+ {
+ data->clearRoles();
+ }
+ }
+
+ for (role_list_t::iterator ri = mRoles.begin(); ri != mRoles.end(); ++ri)
+ {
+ LLGroupRoleData* data = ri->second;
+ if (data)
+ {
+ data->clearMembers();
+ }
+ }
+
+ mReceivedRoleMemberPairs = 0;
+ mRoleMemberDataComplete= false;
+}
+
+LLGroupMgrGroupData::~LLGroupMgrGroupData()
+{
+ removeData();
+}
+
+bool LLGroupMgrGroupData::changeRoleMember(const LLUUID& role_id,
+ const LLUUID& member_id,
+ LLRoleMemberChangeType rmc)
+{
+ role_list_t::iterator ri = mRoles.find(role_id);
+ member_list_t::iterator mi = mMembers.find(member_id);
+
+ if (ri == mRoles.end()
+ || mi == mMembers.end() )
+ {
+ if (ri == mRoles.end()) LL_WARNS() << "LLGroupMgrGroupData::changeRoleMember couldn't find role " << role_id << LL_ENDL;
+ if (mi == mMembers.end()) LL_WARNS() << "LLGroupMgrGroupData::changeRoleMember couldn't find member " << member_id << LL_ENDL;
+ return false;
+ }
+
+ LLGroupRoleData* grd = ri->second;
+ LLGroupMemberData* gmd = mi->second;
+
+ if (!grd || !gmd)
+ {
+ LL_WARNS() << "LLGroupMgrGroupData::changeRoleMember couldn't get member or role data." << LL_ENDL;
+ return false;
+ }
+
+ if (RMC_ADD == rmc)
+ {
+ LL_INFOS() << " adding member to role." << LL_ENDL;
+ grd->addMember(member_id);
+ gmd->addRole(role_id,grd);
+
+ //TODO move this into addrole function
+ //see if they added someone to the owner role and update isOwner
+ gmd->mIsOwner = (role_id == mOwnerRole) ? true : gmd->mIsOwner;
+ }
+ else if (RMC_REMOVE == rmc)
+ {
+ LL_INFOS() << " removing member from role." << LL_ENDL;
+ grd->removeMember(member_id);
+ gmd->removeRole(role_id);
+
+ //see if they removed someone from the owner role and update isOwner
+ gmd->mIsOwner = (role_id == mOwnerRole) ? false : gmd->mIsOwner;
+ }
+
+ lluuid_pair role_member;
+ role_member.first = role_id;
+ role_member.second = member_id;
+
+ change_map_t::iterator it = mRoleMemberChanges.find(role_member);
+ if (it != mRoleMemberChanges.end())
+ {
+ // There was already a role change for this role_member
+ if (it->second.mChange == rmc)
+ {
+ // Already recorded this change? Weird.
+ LL_INFOS() << "Received duplicate change for "
+ << " role: " << role_id << " member " << member_id
+ << " change " << (rmc == RMC_ADD ? "ADD" : "REMOVE") << LL_ENDL;
+ }
+ else
+ {
+ // The only two operations (add and remove) currently cancel each other out
+ // If that changes this will need more logic
+ if (rmc == RMC_NONE)
+ {
+ LL_WARNS() << "changeRoleMember: existing entry with 'RMC_NONE' change! This shouldn't happen." << LL_ENDL;
+ LLRoleMemberChange rc(role_id,member_id,rmc);
+ mRoleMemberChanges[role_member] = rc;
+ }
+ else
+ {
+ mRoleMemberChanges.erase(it);
+ }
+ }
+ }
+ else
+ {
+ LLRoleMemberChange rc(role_id,member_id,rmc);
+ mRoleMemberChanges[role_member] = rc;
+ }
+
+ recalcAgentPowers(member_id);
+
+ mChanged = true;
+ return true;
+}
+
+void LLGroupMgrGroupData::recalcAllAgentPowers()
+{
+ LLGroupMemberData* gmd;
+
+ for (member_list_t::iterator mit = mMembers.begin();
+ mit != mMembers.end(); ++mit)
+ {
+ gmd = mit->second;
+ if (!gmd) continue;
+
+ gmd->mAgentPowers = 0;
+ for (LLGroupMemberData::role_list_t::iterator it = gmd->mRolesList.begin();
+ it != gmd->mRolesList.end(); ++it)
+ {
+ LLGroupRoleData* grd = (*it).second;
+ if (!grd) continue;
+
+ gmd->mAgentPowers |= grd->mRoleData.mRolePowers;
+ }
+ }
+}
+
+void LLGroupMgrGroupData::recalcAgentPowers(const LLUUID& agent_id)
+{
+ member_list_t::iterator mi = mMembers.find(agent_id);
+ if (mi == mMembers.end()) return;
+
+ LLGroupMemberData* gmd = mi->second;
+
+ if (!gmd) return;
+
+ gmd->mAgentPowers = 0;
+ for (LLGroupMemberData::role_list_t::iterator it = gmd->mRolesList.begin();
+ it != gmd->mRolesList.end(); ++it)
+ {
+ LLGroupRoleData* grd = (*it).second;
+ if (!grd) continue;
+
+ gmd->mAgentPowers |= grd->mRoleData.mRolePowers;
+ }
+}
+
+bool LLGroupMgrGroupData::isSingleMemberNotOwner()
+{
+ return mMembers.size() == 1 && !mMembers.begin()->second->isOwner();
+}
+
+bool packRoleUpdateMessageBlock(LLMessageSystem* msg,
+ const LLUUID& group_id,
+ const LLUUID& role_id,
+ const LLRoleData& role_data,
+ bool start_message)
+{
+ if (start_message)
+ {
+ msg->newMessage("GroupRoleUpdate");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID",gAgent.getID());
+ msg->addUUID("SessionID",gAgent.getSessionID());
+ msg->addUUID("GroupID",group_id);
+ start_message = false;
+ }
+
+ msg->nextBlock("RoleData");
+ msg->addUUID("RoleID",role_id);
+ msg->addString("Name", role_data.mRoleName);
+ msg->addString("Description", role_data.mRoleDescription);
+ msg->addString("Title", role_data.mRoleTitle);
+ msg->addU64("Powers", role_data.mRolePowers);
+ msg->addU8("UpdateType", (U8)role_data.mChangeType);
+
+ if (msg->isSendFullFast())
+ {
+ gAgent.sendReliableMessage();
+ start_message = true;
+ }
+
+ return start_message;
+}
+
+void LLGroupMgrGroupData::sendRoleChanges()
+{
+ // Commit changes locally
+ LLGroupRoleData* grd;
+ role_list_t::iterator role_it;
+ LLMessageSystem* msg = gMessageSystem;
+ bool start_message = true;
+
+ bool need_role_cleanup = false;
+ bool need_role_data = false;
+ bool need_power_recalc = false;
+
+ // Apply all changes
+ for (role_data_map_t::iterator iter = mRoleChanges.begin();
+ iter != mRoleChanges.end(); )
+ {
+ role_data_map_t::iterator it = iter++; // safely incrament iter
+ const LLUUID& role_id = (*it).first;
+ const LLRoleData& role_data = (*it).second;
+
+ // Commit to local data set
+ role_it = mRoles.find((*it).first);
+ if ( (mRoles.end() == role_it
+ && RC_CREATE != role_data.mChangeType)
+ || (mRoles.end() != role_it
+ && RC_CREATE == role_data.mChangeType))
+ {
+ continue;
+ }
+
+ // NOTE: role_it is valid EXCEPT for the RC_CREATE case
+ switch (role_data.mChangeType)
+ {
+ case RC_CREATE:
+ {
+ // NOTE: role_it is NOT valid in this case
+ grd = new LLGroupRoleData(role_id, role_data, 0);
+ mRoles[role_id] = grd;
+ need_role_data = true;
+ break;
+ }
+ case RC_DELETE:
+ {
+ LLGroupRoleData* group_role_data = (*role_it).second;
+ delete group_role_data;
+ mRoles.erase(role_it);
+ need_role_cleanup = true;
+ need_power_recalc = true;
+ break;
+ }
+ case RC_UPDATE_ALL:
+ // fall through
+ case RC_UPDATE_POWERS:
+ need_power_recalc = true;
+ // fall through
+ case RC_UPDATE_DATA:
+ // fall through
+ default:
+ {
+ LLGroupRoleData* group_role_data = (*role_it).second;
+ group_role_data->setRoleData(role_data); // NOTE! might modify mRoleChanges!
+ break;
+ }
+ }
+
+ // Update dataserver
+ start_message = packRoleUpdateMessageBlock(msg,getID(),role_id,role_data,start_message);
+ }
+
+ if (!start_message)
+ {
+ gAgent.sendReliableMessage();
+ }
+
+ // If we delete a role then all the role-member pairs are invalid!
+ if (need_role_cleanup)
+ {
+ removeRoleMemberData();
+ }
+
+ // If we create a new role, then we need to re-fetch all the role data.
+ if (need_role_data)
+ {
+ LLGroupMgr::getInstance()->sendGroupRoleDataRequest(getID());
+ }
+
+ // Clean up change lists
+ mRoleChanges.clear();
+
+ // Recalculate all the agent powers because role powers have now changed.
+ if (need_power_recalc)
+ {
+ recalcAllAgentPowers();
+ }
+}
+
+void LLGroupMgrGroupData::cancelRoleChanges()
+{
+ // Clear out all changes!
+ mRoleChanges.clear();
+}
+
+void LLGroupMgrGroupData::createBanEntry(const LLUUID& ban_id, const LLGroupBanData& ban_data)
+{
+ mBanList[ban_id] = ban_data;
+}
+
+void LLGroupMgrGroupData::removeBanEntry(const LLUUID& ban_id)
+{
+ mBanList.erase(ban_id);
+}
+
+void LLGroupMgrGroupData::banMemberById(const LLUUID& participant_uuid)
+{
+ if (!mMemberDataComplete ||
+ !mRoleDataComplete ||
+ !(mRoleMemberDataComplete && mMembers.size()))
+ {
+ LL_WARNS() << "No Role-Member data yet, setting ban request to pending." << LL_ENDL;
+ mPendingBanRequest = true;
+ mPendingBanMemberID = participant_uuid;
+
+ if (!mMemberDataComplete || !mMembers.size())
+ {
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID);
+ }
+
+ if (!mRoleDataComplete)
+ {
+ LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mID);
+ }
+
+ return;
+ }
+
+ LLGroupMgrGroupData::member_list_t::iterator mi = mMembers.find((participant_uuid));
+ if (mi == mMembers.end())
+ {
+ if (!mPendingBanRequest)
+ {
+ mPendingBanRequest = true;
+ mPendingBanMemberID = participant_uuid;
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID); // member isn't in members list, request reloading
+ }
+ else
+ {
+ mPendingBanRequest = false;
+ }
+
+ return;
+ }
+
+ mPendingBanRequest = false;
+
+ LLGroupMemberData* member_data = (*mi).second;
+ if (member_data && member_data->isInRole(mOwnerRole))
+ {
+ return; // can't ban group owner
+ }
+
+ std::vector<LLUUID> ids;
+ ids.push_back(participant_uuid);
+
+ LLGroupBanData ban_data;
+ createBanEntry(participant_uuid, ban_data);
+ LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mID, LLGroupMgr::BAN_CREATE, ids);
+ LLGroupMgr::getInstance()->sendGroupMemberEjects(mID, ids);
+ LLGroupMgr::getInstance()->sendGroupMembersRequest(mID);
+ LLSD args;
+ LLAvatarName av_name;
+ LLAvatarNameCache::get(participant_uuid, &av_name);
+ args["AVATAR_NAME"] = av_name.getUserName();
+ args["GROUP_NAME"] = mName;
+ LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args));
+}
+
+//
+// LLGroupMgr
+//
+
+LLGroupMgr::LLGroupMgr():
+ mMemberRequestInFlight(false)
+{
+}
+
+LLGroupMgr::~LLGroupMgr()
+{
+ clearGroups();
+}
+
+void LLGroupMgr::clearGroups()
+{
+ std::for_each(mRoleActionSets.begin(), mRoleActionSets.end(), DeletePointer());
+ mRoleActionSets.clear();
+ std::for_each(mGroups.begin(), mGroups.end(), DeletePairedPointer());
+ mGroups.clear();
+ mObservers.clear();
+}
+
+void LLGroupMgr::clearGroupData(const LLUUID& group_id)
+{
+ group_map_t::iterator iter = mGroups.find(group_id);
+ if (iter != mGroups.end())
+ {
+ delete (*iter).second;
+ mGroups.erase(iter);
+ }
+}
+
+void LLGroupMgr::addObserver(LLGroupMgrObserver* observer)
+{
+ if( observer->getID() != LLUUID::null )
+ mObservers.insert(std::pair<LLUUID, LLGroupMgrObserver*>(observer->getID(), observer));
+}
+
+void LLGroupMgr::addObserver(const LLUUID& group_id, LLParticularGroupObserver* observer)
+{
+ if(group_id.notNull() && observer)
+ {
+ mParticularObservers[group_id].insert(observer);
+ }
+}
+
+void LLGroupMgr::removeObserver(LLGroupMgrObserver* observer)
+{
+ if (!observer)
+ {
+ return;
+ }
+ observer_multimap_t::iterator it;
+ it = mObservers.find(observer->getID());
+ while (it != mObservers.end())
+ {
+ if (it->second == observer)
+ {
+ mObservers.erase(it);
+ break;
+ }
+ else
+ {
+ ++it;
+ }
+ }
+}
+
+void LLGroupMgr::removeObserver(const LLUUID& group_id, LLParticularGroupObserver* observer)
+{
+ if(group_id.isNull() || !observer)
+ {
+ return;
+ }
+
+ observer_map_t::iterator obs_it = mParticularObservers.find(group_id);
+ if(obs_it == mParticularObservers.end())
+ return;
+
+ obs_it->second.erase(observer);
+
+ if (obs_it->second.size() == 0)
+ mParticularObservers.erase(obs_it);
+}
+
+LLGroupMgrGroupData* LLGroupMgr::getGroupData(const LLUUID& id)
+{
+ group_map_t::iterator gi = mGroups.find(id);
+
+ if (gi != mGroups.end())
+ {
+ return gi->second;
+ }
+ return NULL;
+}
+
+// Helper function for LLGroupMgr::processGroupMembersReply
+// This reformats date strings from MM/DD/YYYY to YYYY/MM/DD ( e.g. 1/27/2008 -> 2008/1/27 )
+// so that the sorter can sort by year before month before day.
+static void formatDateString(std::string &date_string)
+{
+ using namespace boost;
+ cmatch result;
+ const regex expression("([0-9]{1,2})/([0-9]{1,2})/([0-9]{4})");
+ if (regex_match(date_string.c_str(), result, expression))
+ {
+ // convert matches to integers so that we can pad them with zeroes on Linux
+ S32 year = boost::lexical_cast<S32>(result[3]);
+ S32 month = boost::lexical_cast<S32>(result[1]);
+ S32 day = boost::lexical_cast<S32>(result[2]);
+
+ // ISO 8601 date format
+ date_string = llformat("%04d/%02d/%02d", year, month, day);
+ }
+}
+
+// static
+void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data)
+{
+ LL_PROFILE_ZONE_SCOPED;
+
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupMembersReply" << LL_ENDL;
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
+ if (gAgent.getID() != agent_id)
+ {
+ LL_WARNS() << "Got group members reply for another agent!" << LL_ENDL;
+ return;
+ }
+
+ LLUUID group_id;
+ msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id );
+
+ LLUUID request_id;
+ msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_RequestID, request_id);
+
+ LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
+ if (!group_datap || (group_datap->mMemberRequestID != request_id))
+ {
+ LL_WARNS() << "processGroupMembersReply: Received incorrect (stale?) group or request id" << LL_ENDL;
+ return;
+ }
+
+ msg->getS32(_PREHASH_GroupData, "MemberCount", group_datap->mMemberCount );
+
+ if (group_datap->mMemberCount > 0)
+ {
+ S32 contribution = 0;
+ std::string online_status;
+ std::string title;
+ U64 agent_powers = 0;
+ bool is_owner = false;
+
+ S32 num_members = msg->getNumberOfBlocksFast(_PREHASH_MemberData);
+ for (S32 i = 0; i < num_members; i++)
+ {
+ LLUUID member_id;
+
+ msg->getUUIDFast(_PREHASH_MemberData, _PREHASH_AgentID, member_id, i );
+ msg->getS32(_PREHASH_MemberData, _PREHASH_Contribution, contribution, i);
+ msg->getU64(_PREHASH_MemberData, "AgentPowers", agent_powers, i);
+ msg->getStringFast(_PREHASH_MemberData, _PREHASH_OnlineStatus, online_status, i);
+ msg->getString(_PREHASH_MemberData, "Title", title, i);
+ msg->getBOOL(_PREHASH_MemberData,"IsOwner",is_owner,i);
+
+ if (member_id.notNull())
+ {
+ if (online_status == "Online")
+ {
+ static std::string localized_online(LLTrans::getString("group_member_status_online"));
+ online_status = localized_online;
+ }
+ else
+ {
+ formatDateString(online_status); // reformat for sorting, e.g. 12/25/2008 -> 2008/12/25
+ }
+
+ //LL_INFOS() << "Member " << member_id << " has powers " << std::hex << agent_powers << std::dec << LL_ENDL;
+ LLGroupMemberData* newdata = new LLGroupMemberData(member_id,
+ contribution,
+ agent_powers,
+ title,
+ online_status,
+ is_owner);
+#if LL_DEBUG
+ LLGroupMgrGroupData::member_list_t::iterator mit = group_datap->mMembers.find(member_id);
+ if (mit != group_datap->mMembers.end())
+ {
+ LL_INFOS() << " *** Received duplicate member data for agent " << member_id << LL_ENDL;
+ }
+#endif
+ group_datap->mMembers[member_id] = newdata;
+ }
+ else
+ {
+ LL_INFOS() << "Received null group member data." << LL_ENDL;
+ }
+ }
+
+ //if group members are loaded while titles are missing, load the titles.
+ if(group_datap->mTitles.size() < 1)
+ {
+ LLGroupMgr::getInstance()->sendGroupTitlesRequest(group_id);
+ }
+ }
+
+ group_datap->mMemberVersion.generate();
+
+ if (group_datap->mMembers.size() == (U32)group_datap->mMemberCount)
+ {
+ group_datap->mMemberDataComplete = true;
+ group_datap->mMemberRequestID.setNull();
+ // We don't want to make role-member data requests until we have all the members
+ if (group_datap->mPendingRoleMemberRequest)
+ {
+ group_datap->mPendingRoleMemberRequest = false;
+ LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_datap->mID);
+ }
+ }
+
+ group_datap->mChanged = true;
+ LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA);
+}
+
+//static
+void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data)
+{
+ LL_PROFILE_ZONE_SCOPED;
+
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupPropertiesReply" << LL_ENDL;
+ if (!msg)
+ {
+ LL_ERRS() << "Can't access the messaging system" << LL_ENDL;
+ return;
+ }
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
+ if (gAgent.getID() != agent_id)
+ {
+ LL_WARNS() << "Got group properties reply for another agent!" << LL_ENDL;
+ return;
+ }
+
+ LLUUID group_id;
+ std::string name;
+ std::string charter;
+ bool show_in_list = false;
+ LLUUID founder_id;
+ U64 powers_mask = GP_NO_POWERS;
+ S32 money = 0;
+ std::string member_title;
+ LLUUID insignia_id;
+ LLUUID owner_role;
+ U32 membership_fee = 0;
+ bool open_enrollment = false;
+ S32 num_group_members = 0;
+ S32 num_group_roles = 0;
+ bool allow_publish = false;
+ bool mature = false;
+
+ msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id );
+ msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_FounderID, founder_id);
+ msg->getStringFast(_PREHASH_GroupData, _PREHASH_Name, name );
+ msg->getStringFast(_PREHASH_GroupData, _PREHASH_Charter, charter );
+ msg->getBOOLFast(_PREHASH_GroupData, _PREHASH_ShowInList, show_in_list );
+ msg->getStringFast(_PREHASH_GroupData, _PREHASH_MemberTitle, member_title );
+ msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_InsigniaID, insignia_id );
+ msg->getU64Fast(_PREHASH_GroupData, _PREHASH_PowersMask, powers_mask );
+ msg->getU32Fast(_PREHASH_GroupData, _PREHASH_MembershipFee, membership_fee );
+ msg->getBOOLFast(_PREHASH_GroupData, _PREHASH_OpenEnrollment, open_enrollment );
+ msg->getS32Fast(_PREHASH_GroupData, _PREHASH_GroupMembershipCount, num_group_members);
+ msg->getS32(_PREHASH_GroupData, "GroupRolesCount", num_group_roles);
+ msg->getS32Fast(_PREHASH_GroupData, _PREHASH_Money, money);
+ msg->getBOOL("GroupData", "AllowPublish", allow_publish);
+ msg->getBOOL("GroupData", "MaturePublish", mature);
+ msg->getUUID(_PREHASH_GroupData, "OwnerRole", owner_role);
+
+ LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->createGroupData(group_id);
+
+ group_datap->mName = name;
+ group_datap->mCharter = charter;
+ group_datap->mShowInList = show_in_list;
+ group_datap->mInsigniaID = insignia_id;
+ group_datap->mFounderID = founder_id;
+ group_datap->mMembershipFee = membership_fee;
+ group_datap->mOpenEnrollment = open_enrollment;
+ group_datap->mAllowPublish = allow_publish;
+ group_datap->mMaturePublish = mature;
+ group_datap->mOwnerRole = owner_role;
+ group_datap->mMemberCount = num_group_members;
+ group_datap->mRoleCount = num_group_roles + 1; // Add the everyone role.
+
+ group_datap->mGroupPropertiesDataComplete = true;
+ group_datap->mChanged = true;
+
+ properties_request_map_t::iterator request = LLGroupMgr::getInstance()->mPropRequests.find(group_id);
+ if (request != LLGroupMgr::getInstance()->mPropRequests.end())
+ {
+ LLGroupMgr::getInstance()->mPropRequests.erase(request);
+ }
+ else
+ {
+ LL_DEBUGS("GrpMgr") << "GroupPropertyResponse received with no pending request. Response was slow." << LL_ENDL;
+ }
+ LLGroupMgr::getInstance()->notifyObservers(GC_PROPERTIES);
+}
+
+// static
+void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data)
+{
+ LL_PROFILE_ZONE_SCOPED;
+
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupRoleDataReply" << LL_ENDL;
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
+ if (gAgent.getID() != agent_id)
+ {
+ LL_WARNS() << "Got group role data reply for another agent!" << LL_ENDL;
+ return;
+ }
+
+ LLUUID group_id;
+ msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id );
+
+ LLUUID request_id;
+ msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_RequestID, request_id);
+
+ LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
+ if (!group_datap || (group_datap->mRoleDataRequestID != request_id))
+ {
+ LL_WARNS() << "processGroupPropertiesReply: Received incorrect (stale?) group or request id" << LL_ENDL;
+ return;
+ }
+
+ msg->getS32(_PREHASH_GroupData, "RoleCount", group_datap->mRoleCount );
+
+ std::string name;
+ std::string title;
+ std::string desc;
+ U64 powers = 0;
+ U32 member_count = 0;
+ LLUUID role_id;
+
+ U32 num_blocks = msg->getNumberOfBlocks("RoleData");
+ U32 i = 0;
+ for (i=0; i< num_blocks; ++i)
+ {
+ msg->getUUID("RoleData", "RoleID", role_id, i );
+
+ msg->getString("RoleData","Name",name,i);
+ msg->getString("RoleData","Title",title,i);
+ msg->getString("RoleData","Description",desc,i);
+ msg->getU64("RoleData","Powers",powers,i);
+ msg->getU32("RoleData","Members",member_count,i);
+
+ //there are 3 predifined roles - Owners, Officers, Everyone
+ //there names are defined in lldatagroups.cpp
+ //lets change names from server to localized strings
+ if(name == "Everyone")
+ {
+ name = LLTrans::getString("group_role_everyone");
+ }
+ else if(name == "Officers")
+ {
+ name = LLTrans::getString("group_role_officers");
+ }
+ else if(name == "Owners")
+ {
+ name = LLTrans::getString("group_role_owners");
+ }
+
+
+
+ LL_DEBUGS("GrpMgr") << "Adding role data: " << name << " {" << role_id << "}" << LL_ENDL;
+ LLGroupRoleData* rd = new LLGroupRoleData(role_id,name,title,desc,powers,member_count);
+ group_datap->mRoles[role_id] = rd;
+ }
+
+ if (group_datap->mRoles.size() == (U32)group_datap->mRoleCount)
+ {
+ group_datap->mRoleDataComplete = true;
+ group_datap->mRoleDataRequestID.setNull();
+ // We don't want to make role-member data requests until we have all the role data
+ if (group_datap->mPendingRoleMemberRequest)
+ {
+ group_datap->mPendingRoleMemberRequest = false;
+ LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_datap->mID);
+ }
+ }
+
+ group_datap->mChanged = true;
+ LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_DATA);
+}
+
+// static
+void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data)
+{
+ LL_PROFILE_ZONE_SCOPED;
+
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupRoleMembersReply" << LL_ENDL;
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
+ if (gAgent.getID() != agent_id)
+ {
+ LL_WARNS() << "Got group role members reply for another agent!" << LL_ENDL;
+ return;
+ }
+
+ LLUUID request_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_RequestID, request_id);
+
+ LLUUID group_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id );
+
+ U32 total_pairs;
+ msg->getU32(_PREHASH_AgentData, "TotalPairs", total_pairs);
+
+ LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
+ if (!group_datap || (group_datap->mRoleMembersRequestID != request_id))
+ {
+ LL_WARNS() << "processGroupRoleMembersReply: Received incorrect (stale?) group or request id" << LL_ENDL;
+ return;
+ }
+
+ U32 num_blocks = msg->getNumberOfBlocks("MemberData");
+ U32 i;
+ LLUUID member_id;
+ LLUUID role_id;
+ LLGroupRoleData* rd = NULL;
+ LLGroupMemberData* md = NULL;
+
+ LLGroupMgrGroupData::role_list_t::iterator ri;
+ LLGroupMgrGroupData::member_list_t::iterator mi;
+
+ // If total_pairs == 0, there are no members in any custom roles.
+ if (total_pairs > 0)
+ {
+ for (i = 0;i < num_blocks; ++i)
+ {
+ msg->getUUID("MemberData","RoleID",role_id,i);
+ msg->getUUID("MemberData","MemberID",member_id,i);
+
+ if (role_id.notNull() && member_id.notNull() )
+ {
+ rd = NULL;
+ ri = group_datap->mRoles.find(role_id);
+ if (ri != group_datap->mRoles.end())
+ {
+ rd = ri->second;
+ }
+
+ md = NULL;
+ mi = group_datap->mMembers.find(member_id);
+ if (mi != group_datap->mMembers.end())
+ {
+ md = mi->second;
+ }
+
+ if (rd && md)
+ {
+ LL_DEBUGS("GrpMgr") << "Adding role-member pair: " << role_id << ", " << member_id << LL_ENDL;
+ rd->addMember(member_id);
+ md->addRole(role_id,rd);
+ }
+ else
+ {
+ if (!rd) LL_WARNS() << "Received role data for unknown role " << role_id << " in group " << group_id << LL_ENDL;
+ if (!md) LL_WARNS() << "Received role data for unknown member " << member_id << " in group " << group_id << LL_ENDL;
+ }
+ }
+ }
+
+ group_datap->mReceivedRoleMemberPairs += num_blocks;
+ }
+
+ if (group_datap->mReceivedRoleMemberPairs == total_pairs)
+ {
+ // Add role data for the 'everyone' role to all members
+ LLGroupRoleData* everyone = group_datap->mRoles[LLUUID::null];
+ if (!everyone)
+ {
+ LL_WARNS() << "Everyone role not found!" << LL_ENDL;
+ }
+ else
+ {
+ for (LLGroupMgrGroupData::member_list_t::iterator mi = group_datap->mMembers.begin();
+ mi != group_datap->mMembers.end(); ++mi)
+ {
+ LLGroupMemberData* data = mi->second;
+ if (data)
+ {
+ data->addRole(LLUUID::null,everyone);
+ }
+ }
+ }
+
+ group_datap->mRoleMemberDataComplete= true;
+ group_datap->mRoleMembersRequestID.setNull();
+ }
+
+ group_datap->mChanged = true;
+ LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_MEMBER_DATA);
+
+ if (group_datap->mPendingBanRequest)
+ {
+ group_datap->banMemberById(group_datap->mPendingBanMemberID);
+ }
+}
+
+// static
+void LLGroupMgr::processGroupTitlesReply(LLMessageSystem* msg, void** data)
+{
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupTitlesReply" << LL_ENDL;
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
+ if (gAgent.getID() != agent_id)
+ {
+ LL_WARNS() << "Got group properties reply for another agent!" << LL_ENDL;
+ return;
+ }
+
+ LLUUID group_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id );
+ LLUUID request_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_RequestID, request_id);
+
+ LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
+ if (!group_datap || (group_datap->mTitlesRequestID != request_id))
+ {
+ LL_WARNS() << "processGroupTitlesReply: Received incorrect (stale?) group" << LL_ENDL;
+ return;
+ }
+
+ LLGroupTitle title;
+
+ S32 i = 0;
+ S32 blocks = msg->getNumberOfBlocksFast(_PREHASH_GroupData);
+ for (i=0; i<blocks; ++i)
+ {
+ msg->getString("GroupData","Title",title.mTitle,i);
+ msg->getUUID("GroupData","RoleID",title.mRoleID,i);
+ msg->getBOOL("GroupData","Selected",title.mSelected,i);
+
+ if (!title.mTitle.empty())
+ {
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr adding title: " << title.mTitle << ", " << title.mRoleID << ", " << (title.mSelected ? 'Y' : 'N') << LL_ENDL;
+ group_datap->mTitles.push_back(title);
+ }
+ }
+
+ group_datap->mChanged = true;
+ LLGroupMgr::getInstance()->notifyObservers(GC_TITLES);
+}
+
+// static
+void LLGroupMgr::processEjectGroupMemberReply(LLMessageSystem* msg, void ** data)
+{
+ LL_DEBUGS("GrpMgr") << "processEjectGroupMemberReply" << LL_ENDL;
+ LLUUID group_id;
+ msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id);
+ bool success;
+ msg->getBOOLFast(_PREHASH_EjectData, _PREHASH_Success, success);
+
+ // If we had a failure, the group panel needs to be updated.
+ if (!success)
+ {
+ LLGroupActions::refresh(group_id);
+ }
+}
+
+// static
+void LLGroupMgr::processJoinGroupReply(LLMessageSystem* msg, void ** data)
+{
+ LL_DEBUGS("GrpMgr") << "processJoinGroupReply" << LL_ENDL;
+ LLUUID group_id;
+ bool success;
+ msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id);
+ msg->getBOOLFast(_PREHASH_GroupData, _PREHASH_Success, success);
+
+ if (success)
+ {
+ // refresh all group information
+ gAgent.sendAgentDataUpdateRequest();
+
+ LLGroupMgr::getInstance()->clearGroupData(group_id);
+ // refresh the floater for this group, if any.
+ LLGroupActions::refresh(group_id);
+ }
+}
+
+// static
+void LLGroupMgr::processLeaveGroupReply(LLMessageSystem* msg, void ** data)
+{
+ LL_DEBUGS("GrpMgr") << "processLeaveGroupReply" << LL_ENDL;
+ LLUUID group_id;
+ bool success;
+ msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id);
+ msg->getBOOLFast(_PREHASH_GroupData, _PREHASH_Success, success);
+
+ if (success)
+ {
+ // refresh all group information
+ gAgent.sendAgentDataUpdateRequest();
+
+ LLGroupMgr::getInstance()->clearGroupData(group_id);
+ // close the floater for this group, if any.
+ LLGroupActions::closeGroup(group_id);
+ }
+}
+
+// static
+void LLGroupMgr::processCreateGroupReply(LLMessageSystem* msg, void ** data)
+{
+ LLUUID group_id;
+ bool success;
+ std::string message;
+
+ msg->getUUIDFast(_PREHASH_ReplyData, _PREHASH_GroupID, group_id );
+
+ msg->getBOOLFast(_PREHASH_ReplyData, _PREHASH_Success, success );
+ msg->getStringFast(_PREHASH_ReplyData, _PREHASH_Message, message );
+
+ if (success)
+ {
+ // refresh all group information
+ gAgent.sendAgentDataUpdateRequest();
+
+ // HACK! We haven't gotten the agent group update yet, so ... um ... fake it.
+ // This is so when we go to modify the group we will be able to do so.
+ // This isn't actually too bad because real data will come down in 2 or 3 miliseconds and replace this.
+ LLGroupData gd;
+ gd.mAcceptNotices = true;
+ gd.mListInProfile = true;
+ gd.mContribution = 0;
+ gd.mID = group_id;
+ gd.mName = "new group";
+ gd.mPowers = GP_ALL_POWERS;
+
+ gAgent.mGroups.push_back(gd);
+
+ LLPanelGroupCreate::refreshCreatedGroup(group_id);
+ //FIXME
+ //LLFloaterGroupInfo::closeCreateGroup();
+ //LLFloaterGroupInfo::showFromUUID(group_id,"roles_tab");
+ }
+ else
+ {
+ // *TODO: Translate
+ LLSD args;
+ args["MESSAGE"] = message;
+ LLNotificationsUtil::add("UnableToCreateGroup", args);
+ }
+}
+
+LLGroupMgrGroupData* LLGroupMgr::createGroupData(const LLUUID& id)
+{
+ LLGroupMgrGroupData* group_datap = NULL;
+
+ group_map_t::iterator existing_group = LLGroupMgr::getInstance()->mGroups.find(id);
+ if (existing_group == LLGroupMgr::getInstance()->mGroups.end())
+ {
+ group_datap = new LLGroupMgrGroupData(id);
+ LLGroupMgr::getInstance()->addGroup(group_datap);
+ }
+ else
+ {
+ group_datap = existing_group->second;
+ }
+
+ if (group_datap)
+ {
+ group_datap->setAccessed();
+ }
+
+ return group_datap;
+}
+
+bool LLGroupMgr::hasPendingPropertyRequest(const LLUUID & id)
+{
+ properties_request_map_t::iterator existing_req = LLGroupMgr::getInstance()->mPropRequests.find(id);
+ if (existing_req != LLGroupMgr::getInstance()->mPropRequests.end())
+ {
+ if (gFrameTime - existing_req->second < MIN_GROUP_PROPERTY_REQUEST_FREQ)
+ {
+ return true;
+ }
+ else
+ {
+ LLGroupMgr::getInstance()->mPropRequests.erase(existing_req);
+ }
+ }
+ return false;
+}
+
+void LLGroupMgr::addPendingPropertyRequest(const LLUUID& id)
+{
+ LLGroupMgr::getInstance()->mPropRequests[id] = gFrameTime;
+}
+
+void LLGroupMgr::notifyObservers(LLGroupChange gc)
+{
+ for (group_map_t::iterator gi = mGroups.begin(); gi != mGroups.end(); ++gi)
+ {
+ LLUUID group_id = gi->first;
+ if (gi->second->mChanged)
+ {
+ // notify LLGroupMgrObserver
+ // Copy the map because observers may remove themselves on update
+ observer_multimap_t observers = mObservers;
+
+ // find all observers for this group id
+ observer_multimap_t::iterator oi = observers.lower_bound(group_id);
+ observer_multimap_t::iterator end = observers.upper_bound(group_id);
+ for (; oi != end; ++oi)
+ {
+ oi->second->changed(gc);
+ }
+ gi->second->mChanged = false;
+
+
+ // notify LLParticularGroupObserver
+ observer_map_t::iterator obs_it = mParticularObservers.find(group_id);
+ if(obs_it == mParticularObservers.end())
+ return;
+
+ observer_set_t& obs = obs_it->second;
+ for (observer_set_t::iterator ob_it = obs.begin(); ob_it != obs.end(); ++ob_it)
+ {
+ (*ob_it)->changed(group_id, gc);
+ }
+ }
+ }
+}
+
+void LLGroupMgr::addGroup(LLGroupMgrGroupData* group_datap)
+{
+ while (mGroups.size() >= MAX_CACHED_GROUPS)
+ {
+ // LRU: Remove the oldest un-observed group from cache until group size is small enough
+
+ F32 oldest_access = LLFrameTimer::getTotalSeconds();
+ group_map_t::iterator oldest_gi = mGroups.end();
+
+ for (group_map_t::iterator gi = mGroups.begin(); gi != mGroups.end(); ++gi )
+ {
+ observer_multimap_t::iterator oi = mObservers.find(gi->first);
+ if (oi == mObservers.end())
+ {
+ if (gi->second
+ && (gi->second->getAccessTime() < oldest_access))
+ {
+ oldest_access = gi->second->getAccessTime();
+ oldest_gi = gi;
+ }
+ }
+ }
+
+ if (oldest_gi != mGroups.end())
+ {
+ delete oldest_gi->second;
+ mGroups.erase(oldest_gi);
+ }
+ else
+ {
+ // All groups must be currently open, none to remove.
+ // Just add the new group anyway, but get out of this loop as it
+ // will never drop below max_cached_groups.
+ break;
+ }
+ }
+
+ mGroups[group_datap->getID()] = group_datap;
+}
+
+
+void LLGroupMgr::sendGroupPropertiesRequest(const LLUUID& group_id)
+{
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupPropertiesRequest" << LL_ENDL;
+ // This will happen when we get the reply
+ //LLGroupMgrGroupData* group_datap = createGroupData(group_id);
+
+ if (LLGroupMgr::getInstance()->hasPendingPropertyRequest(group_id))
+ {
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupPropertiesRequest suppressed repeat for " << group_id << LL_ENDL;
+ return;
+ }
+ LLGroupMgr::getInstance()->addPendingPropertyRequest(group_id);
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("GroupProfileRequest");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID",gAgent.getID());
+ msg->addUUID("SessionID",gAgent.getSessionID());
+ msg->nextBlock("GroupData");
+ msg->addUUID("GroupID",group_id);
+ gAgent.sendReliableMessage();
+}
+
+void LLGroupMgr::sendGroupMembersRequest(const LLUUID& group_id)
+{
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupMembersRequest" << LL_ENDL;
+ LLGroupMgrGroupData* group_datap = createGroupData(group_id);
+ if (group_datap->mMemberRequestID.isNull())
+ {
+ group_datap->removeMemberData();
+ group_datap->mMemberRequestID.generate();
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("GroupMembersRequest");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID",gAgent.getID());
+ msg->addUUID("SessionID",gAgent.getSessionID());
+ msg->nextBlock("GroupData");
+ msg->addUUID("GroupID",group_id);
+ msg->addUUID("RequestID",group_datap->mMemberRequestID);
+ gAgent.sendReliableMessage();
+ }
+}
+
+
+void LLGroupMgr::sendGroupRoleDataRequest(const LLUUID& group_id)
+{
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupRoleDataRequest" << LL_ENDL;
+ LLGroupMgrGroupData* group_datap = createGroupData(group_id);
+ if (group_datap->mRoleDataRequestID.isNull())
+ {
+ group_datap->removeRoleData();
+ group_datap->mRoleDataRequestID.generate();
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("GroupRoleDataRequest");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID",gAgent.getID());
+ msg->addUUID("SessionID",gAgent.getSessionID());
+ msg->nextBlock("GroupData");
+ msg->addUUID("GroupID",group_id);
+ msg->addUUID("RequestID",group_datap->mRoleDataRequestID);
+ gAgent.sendReliableMessage();
+ }
+}
+
+void LLGroupMgr::sendGroupRoleMembersRequest(const LLUUID& group_id)
+{
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupRoleMembersRequest" << LL_ENDL;
+ LLGroupMgrGroupData* group_datap = createGroupData(group_id);
+
+ if (group_datap->mRoleMembersRequestID.isNull())
+ {
+ // Don't send the request if we don't have all the member or role data
+ if (!group_datap->isMemberDataComplete()
+ || !group_datap->isRoleDataComplete())
+ {
+ // *TODO: KLW FIXME: Should we start a member or role data request?
+ LL_INFOS("GrpMgr") << " Pending: " << (group_datap->mPendingRoleMemberRequest ? "Y" : "N")
+ << " MemberDataComplete: " << (group_datap->mMemberDataComplete ? "Y" : "N")
+ << " RoleDataComplete: " << (group_datap->mRoleDataComplete ? "Y" : "N") << LL_ENDL;
+ group_datap->mPendingRoleMemberRequest = true;
+ return;
+ }
+
+ group_datap->removeRoleMemberData();
+ group_datap->mRoleMembersRequestID.generate();
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("GroupRoleMembersRequest");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID",gAgent.getID());
+ msg->addUUID("SessionID",gAgent.getSessionID());
+ msg->nextBlock("GroupData");
+ msg->addUUID("GroupID",group_id);
+ msg->addUUID("RequestID",group_datap->mRoleMembersRequestID);
+ gAgent.sendReliableMessage();
+ }
+}
+
+void LLGroupMgr::sendGroupTitlesRequest(const LLUUID& group_id)
+{
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupTitlesRequest" << LL_ENDL;
+ LLGroupMgrGroupData* group_datap = createGroupData(group_id);
+
+ group_datap->mTitles.clear();
+ group_datap->mTitlesRequestID.generate();
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("GroupTitlesRequest");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID",gAgent.getID());
+ msg->addUUID("SessionID",gAgent.getSessionID());
+ msg->addUUID("GroupID",group_id);
+ msg->addUUID("RequestID",group_datap->mTitlesRequestID);
+
+ gAgent.sendReliableMessage();
+}
+
+void LLGroupMgr::sendGroupTitleUpdate(const LLUUID& group_id, const LLUUID& title_role_id)
+{
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupTitleUpdate" << LL_ENDL;
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("GroupTitleUpdate");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID",gAgent.getID());
+ msg->addUUID("SessionID",gAgent.getSessionID());
+ msg->addUUID("GroupID",group_id);
+ msg->addUUID("TitleRoleID",title_role_id);
+
+ gAgent.sendReliableMessage();
+
+ // Save the change locally
+ LLGroupMgrGroupData* group_datap = createGroupData(group_id);
+ for (std::vector<LLGroupTitle>::iterator iter = group_datap->mTitles.begin();
+ iter != group_datap->mTitles.end(); ++iter)
+ {
+ if (iter->mRoleID == title_role_id)
+ {
+ iter->mSelected = true;
+ }
+ else if (iter->mSelected)
+ {
+ iter->mSelected = false;
+ }
+ }
+}
+
+// static
+void LLGroupMgr::sendCreateGroupRequest(const std::string& name,
+ const std::string& charter,
+ U8 show_in_list,
+ const LLUUID& insignia,
+ S32 membership_fee,
+ bool open_enrollment,
+ bool allow_publish,
+ bool mature_publish)
+{
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("CreateGroupRequest");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID",gAgent.getID());
+ msg->addUUID("SessionID",gAgent.getSessionID());
+
+ msg->nextBlock("GroupData");
+ msg->addString("Name",name);
+ msg->addString("Charter",charter);
+ msg->addBOOL("ShowInList",show_in_list);
+ msg->addUUID("InsigniaID",insignia);
+ msg->addS32("MembershipFee",membership_fee);
+ msg->addBOOL("OpenEnrollment",open_enrollment);
+ msg->addBOOL("AllowPublish",allow_publish);
+ msg->addBOOL("MaturePublish",mature_publish);
+
+ gAgent.sendReliableMessage();
+}
+
+void LLGroupMgr::sendUpdateGroupInfo(const LLUUID& group_id)
+{
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendUpdateGroupInfo" << LL_ENDL;
+ LLGroupMgrGroupData* group_datap = createGroupData(group_id);
+
+ LLMessageSystem* msg = gMessageSystem;
+
+ msg->newMessageFast(_PREHASH_UpdateGroupInfo);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID,gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
+
+ msg->nextBlockFast(_PREHASH_GroupData);
+ msg->addUUIDFast(_PREHASH_GroupID,group_datap->getID());
+ msg->addStringFast(_PREHASH_Charter,group_datap->mCharter);
+ msg->addBOOLFast(_PREHASH_ShowInList,group_datap->mShowInList);
+ msg->addUUIDFast(_PREHASH_InsigniaID,group_datap->mInsigniaID);
+ msg->addS32Fast(_PREHASH_MembershipFee,group_datap->mMembershipFee);
+ msg->addBOOLFast(_PREHASH_OpenEnrollment,group_datap->mOpenEnrollment);
+ msg->addBOOLFast(_PREHASH_AllowPublish,group_datap->mAllowPublish);
+ msg->addBOOLFast(_PREHASH_MaturePublish,group_datap->mMaturePublish);
+
+ gAgent.sendReliableMessage();
+
+ // Not expecting a response, so let anyone else watching know the data has changed.
+ group_datap->mChanged = true;
+ notifyObservers(GC_PROPERTIES);
+}
+
+void LLGroupMgr::sendGroupRoleMemberChanges(const LLUUID& group_id)
+{
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupRoleMemberChanges" << LL_ENDL;
+ LLGroupMgrGroupData* group_datap = createGroupData(group_id);
+
+ if (group_datap->mRoleMemberChanges.empty()) return;
+
+ LLMessageSystem* msg = gMessageSystem;
+
+ bool start_message = true;
+ for (LLGroupMgrGroupData::change_map_t::const_iterator citer = group_datap->mRoleMemberChanges.begin();
+ citer != group_datap->mRoleMemberChanges.end(); ++citer)
+ {
+ if (start_message)
+ {
+ msg->newMessage("GroupRoleChanges");
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID,gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
+ msg->addUUIDFast(_PREHASH_GroupID,group_id);
+ start_message = false;
+ }
+ msg->nextBlock("RoleChange");
+ msg->addUUID("RoleID",citer->second.mRole);
+ msg->addUUID("MemberID",citer->second.mMember);
+ msg->addU32("Change",(U32)citer->second.mChange);
+
+ if (msg->isSendFullFast())
+ {
+ gAgent.sendReliableMessage();
+ start_message = true;
+ }
+ }
+
+ if (!start_message)
+ {
+ gAgent.sendReliableMessage();
+ }
+
+ group_datap->mRoleMemberChanges.clear();
+
+ // Not expecting a response, so let anyone else watching know the data has changed.
+ group_datap->mChanged = true;
+ notifyObservers(GC_ROLE_MEMBER_DATA);
+}
+
+//static
+void LLGroupMgr::sendGroupMemberJoin(const LLUUID& group_id)
+{
+
+ LLUIUsage::instance().logCommand("Group.Join");
+
+ LLMessageSystem *msg = gMessageSystem;
+
+ msg->newMessageFast(_PREHASH_JoinGroupRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_GroupData);
+ msg->addUUIDFast(_PREHASH_GroupID, group_id);
+
+ gAgent.sendReliableMessage();
+}
+
+// member_role_pairs is <member_id,role_id>
+// static
+void LLGroupMgr::sendGroupMemberInvites(const LLUUID& group_id, std::map<LLUUID,LLUUID>& member_role_pairs)
+{
+ bool start_message = true;
+ LLMessageSystem* msg = gMessageSystem;
+
+ for (std::map<LLUUID,LLUUID>::iterator it = member_role_pairs.begin();
+ it != member_role_pairs.end(); ++it)
+ {
+ if (start_message)
+ {
+ msg->newMessage("InviteGroupRequest");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID",gAgent.getID());
+ msg->addUUID("SessionID",gAgent.getSessionID());
+ msg->nextBlock("GroupData");
+ msg->addUUID("GroupID",group_id);
+ start_message = false;
+ }
+
+ msg->nextBlock("InviteData");
+ msg->addUUID("InviteeID",(*it).first);
+ msg->addUUID("RoleID",(*it).second);
+
+ if (msg->isSendFull())
+ {
+ gAgent.sendReliableMessage();
+ start_message = true;
+ }
+ }
+
+ if (!start_message)
+ {
+ gAgent.sendReliableMessage();
+ }
+}
+
+//static
+void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id,
+ uuid_vec_t& member_ids)
+{
+ bool start_message = true;
+ LLMessageSystem* msg = gMessageSystem;
+
+ LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
+ if (!group_datap) return;
+
+ for (uuid_vec_t::iterator it = member_ids.begin();
+ it != member_ids.end(); ++it)
+ {
+ LLUUID& ejected_member_id = (*it);
+
+ // Can't use 'eject' to leave a group.
+ if (ejected_member_id == gAgent.getID()) continue;
+
+ // Make sure they are in the group, and we need the member data
+ LLGroupMgrGroupData::member_list_t::iterator mit = group_datap->mMembers.find(ejected_member_id);
+ if (mit != group_datap->mMembers.end())
+ {
+ // Add them to the message
+ if (start_message)
+ {
+ msg->newMessage("EjectGroupMemberRequest");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID",gAgent.getID());
+ msg->addUUID("SessionID",gAgent.getSessionID());
+ msg->nextBlock("GroupData");
+ msg->addUUID("GroupID",group_id);
+ start_message = false;
+ }
+
+ msg->nextBlock("EjectData");
+ msg->addUUID("EjecteeID",ejected_member_id);
+
+ if (msg->isSendFull())
+ {
+ gAgent.sendReliableMessage();
+ start_message = true;
+ }
+
+ LLGroupMemberData* member_data = (*mit).second;
+
+ // Clean up groupmgr
+ for (LLGroupMemberData::role_list_t::iterator rit = member_data->roleBegin();
+ rit != member_data->roleEnd(); ++rit)
+ {
+ if ((*rit).first.notNull() && (*rit).second!=0)
+ {
+ (*rit).second->removeMember(ejected_member_id);
+ }
+ }
+
+ group_datap->mMembers.erase(ejected_member_id);
+
+ // member_data was introduced and is used here instead of (*mit).second to avoid crash because of invalid iterator
+ // It becomes invalid after line with erase above. EXT-4778
+ delete member_data;
+ }
+ }
+
+ if (!start_message)
+ {
+ gAgent.sendReliableMessage();
+ }
+
+ group_datap->mMemberVersion.generate();
+}
+
+void LLGroupMgr::getGroupBanRequestCoro(std::string url, LLUUID groupId)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ std::string finalUrl = url + "?group_id=" + groupId.asString();
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("GrpMgr") << "Error receiving group member data " << LL_ENDL;
+ return;
+ }
+
+ if (result.has("ban_list"))
+ {
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ // group ban data received
+ processGroupBanRequest(result);
+ }
+}
+
+void LLGroupMgr::postGroupBanRequestCoro(std::string url, LLUUID groupId,
+ U32 action, uuid_vec_t banList, bool update)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+ LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions);
+
+ httpOptions->setFollowRedirects(false);
+
+ httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
+
+
+ std::string finalUrl = url + "?group_id=" + groupId.asString();
+
+ LLSD postData = LLSD::emptyMap();
+ postData["ban_action"] = (LLSD::Integer)action;
+ // Add our list of potential banned residents to the list
+ postData["ban_ids"] = LLSD::emptyArray();
+ LLSD banEntry;
+
+ uuid_vec_t::const_iterator it = banList.begin();
+ for (; it != banList.end(); ++it)
+ {
+ banEntry = (*it);
+ postData["ban_ids"].append(banEntry);
+ }
+
+ LL_WARNS() << "post: " << ll_pretty_print_sd(postData) << LL_ENDL;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, finalUrl, postData, httpOptions, httpHeaders);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("GrpMgr") << "Error posting group member data " << LL_ENDL;
+ return;
+ }
+
+ if (result.has("ban_list"))
+ {
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ // group ban data received
+ processGroupBanRequest(result);
+ }
+
+ if (update)
+ {
+ getGroupBanRequestCoro(url, groupId);
+ }
+}
+
+void LLGroupMgr::sendGroupBanRequest( EBanRequestType request_type,
+ const LLUUID& group_id,
+ U32 ban_action, /* = BAN_NO_ACTION */
+ const std::vector<LLUUID> &ban_list) /* = std::vector<LLUUID>() */
+{
+ LLViewerRegion* currentRegion = gAgent.getRegion();
+ if(!currentRegion)
+ {
+ LL_WARNS("GrpMgr") << "Agent does not have a current region. Uh-oh!" << LL_ENDL;
+ return;
+ }
+
+ // Check to make sure we have our capabilities
+ if(!currentRegion->capabilitiesReceived())
+ {
+ LL_WARNS("GrpMgr") << " Capabilities not received!" << LL_ENDL;
+ return;
+ }
+
+ // Get our capability
+ std::string cap_url = currentRegion->getCapability("GroupAPIv1");
+ if(cap_url.empty())
+ {
+ return;
+ }
+
+ U32 action = ban_action & ~BAN_UPDATE;
+ bool update = ((ban_action & BAN_UPDATE) == BAN_UPDATE);
+
+ switch (request_type)
+ {
+ case REQUEST_GET:
+ LLCoros::instance().launch("LLGroupMgr::getGroupBanRequestCoro",
+ boost::bind(&LLGroupMgr::getGroupBanRequestCoro, this, cap_url, group_id));
+ break;
+ case REQUEST_POST:
+ LLCoros::instance().launch("LLGroupMgr::postGroupBanRequestCoro",
+ boost::bind(&LLGroupMgr::postGroupBanRequestCoro, this, cap_url, group_id,
+ action, ban_list, update));
+ break;
+ case REQUEST_PUT:
+ case REQUEST_DEL:
+ break;
+ }
+}
+
+void LLGroupMgr::processGroupBanRequest(const LLSD& content)
+{
+ // Did we get anything in content?
+ if(!content.size())
+ {
+ LL_WARNS("GrpMgr") << "No group member data received." << LL_ENDL;
+ return;
+ }
+
+ LLUUID group_id = content["group_id"].asUUID();
+
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id);
+ if (!gdatap)
+ return;
+
+ gdatap->clearBanList();
+ LLSD::map_const_iterator i = content["ban_list"].beginMap();
+ LLSD::map_const_iterator iEnd = content["ban_list"].endMap();
+ for(;i != iEnd; ++i)
+ {
+ const LLUUID ban_id(i->first);
+ LLSD ban_entry(i->second);
+
+ LLGroupBanData ban_data;
+ if(ban_entry.has("ban_date"))
+ {
+ ban_data.mBanDate = ban_entry["ban_date"].asDate();
+ // TODO: Ban Reason
+ }
+
+ gdatap->createBanEntry(ban_id, ban_data);
+ }
+
+ gdatap->mChanged = true;
+ LLGroupMgr::getInstance()->notifyObservers(GC_BANLIST);
+}
+
+void LLGroupMgr::groupMembersRequestCoro(std::string url, LLUUID groupId)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
+
+ mMemberRequestInFlight = true;
+
+ LLSD postData = LLSD::emptyMap();
+ postData["group_id"] = groupId;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("GrpMgr") << "Error receiving group member data " << LL_ENDL;
+ mMemberRequestInFlight = false;
+ return;
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ LLGroupMgr::processCapGroupMembersRequest(result);
+ mMemberRequestInFlight = false;
+}
+
+void LLGroupMgr::sendCapGroupMembersRequest(const LLUUID& group_id)
+{
+ static U32 lastGroupMemberRequestFrame = 0;
+
+ // Have we requested the information already this frame?
+ // Todo: make this per group, we can invite to one group and simultaneously be checking another one
+ if ((lastGroupMemberRequestFrame == gFrameCount) || (mMemberRequestInFlight))
+ return;
+
+ LLViewerRegion* currentRegion = gAgent.getRegion();
+ // Thank you FS:Ansariel!
+ if(!currentRegion)
+ {
+ LL_WARNS("GrpMgr") << "Agent does not have a current region. Uh-oh!" << LL_ENDL;
+ return;
+ }
+
+ // Check to make sure we have our capabilities
+ if(!currentRegion->capabilitiesReceived())
+ {
+ LL_WARNS("GrpMgr") << " Capabilities not received!" << LL_ENDL;
+ return;
+ }
+
+ // Get our capability
+ std::string cap_url = currentRegion->getCapability("GroupMemberData");
+
+ // Thank you FS:Ansariel!
+ if(cap_url.empty())
+ {
+ LL_INFOS("GrpMgr") << "Region has no GroupMemberData capability. Falling back to UDP fetch." << LL_ENDL;
+ sendGroupMembersRequest(group_id);
+ return;
+ }
+
+ LLGroupMgrGroupData* group_datap = createGroupData(group_id); //make sure group exists
+ group_datap->mMemberRequestID.generate(); // mark as pending
+
+ lastGroupMemberRequestFrame = gFrameCount;
+
+ LLCoros::instance().launch("LLGroupMgr::groupMembersRequestCoro",
+ boost::bind(&LLGroupMgr::groupMembersRequestCoro, this, cap_url, group_id));
+}
+
+
+void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
+{
+ // Did we get anything in content?
+ if(!content.size())
+ {
+ LL_DEBUGS("GrpMgr") << "No group member data received." << LL_ENDL;
+ return;
+ }
+
+ LLUUID group_id = content["group_id"].asUUID();
+
+ LLGroupMgrGroupData* group_datap = getGroupData(group_id);
+ if(!group_datap)
+ {
+ LL_WARNS("GrpMgr") << "Received incorrect, possibly stale, group or request id" << LL_ENDL;
+ return;
+ }
+
+ // If we have no members, there's no reason to do anything else
+ S32 num_members = content["member_count"];
+ if (num_members < 1)
+ {
+ LL_INFOS("GrpMgr") << "Received empty group members list for group id: " << group_id.asString() << LL_ENDL;
+ // Set mMemberDataComplete for correct handling of empty responses. See MAINT-5237
+ group_datap->mMemberDataComplete = true;
+ group_datap->mChanged = true;
+ LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA);
+ return;
+ }
+
+ group_datap->mMemberCount = num_members;
+
+ LLSD member_list = content["members"];
+ LLSD titles = content["titles"];
+ LLSD defaults = content["defaults"];
+
+ std::string online_status;
+ std::string title;
+ S32 contribution;
+ U64 member_powers;
+ // If this is changed to a bool, make sure to change the LLGroupMemberData constructor
+ bool is_owner;
+
+ // Compute this once, rather than every time.
+ U64 default_powers = llstrtou64(defaults["default_powers"].asString().c_str(), NULL, 16);
+
+ LLSD::map_const_iterator member_iter_start = member_list.beginMap();
+ LLSD::map_const_iterator member_iter_end = member_list.endMap();
+ for( ; member_iter_start != member_iter_end; ++member_iter_start)
+ {
+ // Reset defaults
+ online_status = "unknown";
+ title = titles[0].asString();
+ contribution = 0;
+ member_powers = default_powers;
+ is_owner = false;
+
+ const LLUUID member_id(member_iter_start->first);
+ LLSD member_info = member_iter_start->second;
+
+ if(member_info.has("last_login"))
+ {
+ online_status = member_info["last_login"].asString();
+ if(online_status == "Online")
+ online_status = LLTrans::getString("group_member_status_online");
+ else
+ formatDateString(online_status);
+ }
+
+ if(member_info.has("title"))
+ title = titles[member_info["title"].asInteger()].asString();
+
+ if(member_info.has("powers"))
+ member_powers = llstrtou64(member_info["powers"].asString().c_str(), NULL, 16);
+
+ if(member_info.has("donated_square_meters"))
+ contribution = member_info["donated_square_meters"];
+
+ if(member_info.has("owner"))
+ is_owner = true;
+
+ LLGroupMemberData* data = new LLGroupMemberData(member_id,
+ contribution,
+ member_powers,
+ title,
+ online_status,
+ is_owner);
+
+ LLGroupMemberData* member_old = group_datap->mMembers[member_id];
+ if (member_old && group_datap->mRoleMemberDataComplete)
+ {
+ LLGroupMemberData::role_list_t::iterator rit = member_old->roleBegin();
+ LLGroupMemberData::role_list_t::iterator end = member_old->roleEnd();
+
+ for ( ; rit != end; ++rit)
+ {
+ data->addRole((*rit).first,(*rit).second);
+ }
+ }
+ else
+ {
+ group_datap->mRoleMemberDataComplete = false;
+ }
+
+ group_datap->mMembers[member_id] = data;
+ }
+
+ group_datap->mMemberVersion.generate();
+
+ // Technically, we have this data, but to prevent completely overhauling
+ // this entire system (it would be nice, but I don't have the time),
+ // I'm going to be dumb and just call services I most likely don't need
+ // with the thought being that the system might need it to be done.
+ //
+ // TODO:
+ // Refactor to reduce multiple calls for data we already have.
+ if(group_datap->mTitles.size() < 1)
+ sendGroupTitlesRequest(group_id);
+
+
+ group_datap->mMemberDataComplete = true;
+ group_datap->mMemberRequestID.setNull();
+ // Make the role-member data request
+ if (group_datap->mPendingRoleMemberRequest || !group_datap->mRoleMemberDataComplete)
+ {
+ group_datap->mPendingRoleMemberRequest = false;
+ sendGroupRoleMembersRequest(group_id);
+ }
+
+ group_datap->mChanged = true;
+ notifyObservers(GC_MEMBER_DATA);
+
+}
+
+
+void LLGroupMgr::sendGroupRoleChanges(const LLUUID& group_id)
+{
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupRoleChanges" << LL_ENDL;
+ LLGroupMgrGroupData* group_datap = getGroupData(group_id);
+
+ if (group_datap && group_datap->pendingRoleChanges())
+ {
+ group_datap->sendRoleChanges();
+
+ // Not expecting a response, so let anyone else watching know the data has changed.
+ group_datap->mChanged = true;
+ notifyObservers(GC_ROLE_DATA);
+ }
+}
+
+void LLGroupMgr::cancelGroupRoleChanges(const LLUUID& group_id)
+{
+ LL_DEBUGS("GrpMgr") << "LLGroupMgr::cancelGroupRoleChanges" << LL_ENDL;
+ LLGroupMgrGroupData* group_datap = getGroupData(group_id);
+
+ if (group_datap) group_datap->cancelRoleChanges();
+}
+
+//static
+bool LLGroupMgr::parseRoleActions(const std::string& xml_filename)
+{
+ LLXMLNodePtr root;
+
+ bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
+
+ if (!success || !root || !root->hasName( "role_actions" ))
+ {
+ LL_ERRS() << "Problem reading UI role_actions file: " << xml_filename << LL_ENDL;
+ return false;
+ }
+
+ LLXMLNodeList role_list;
+
+ root->getChildren("action_set", role_list, false);
+
+ for (LLXMLNodeList::iterator role_iter = role_list.begin(); role_iter != role_list.end(); ++role_iter)
+ {
+ LLXMLNodePtr action_set = role_iter->second;
+
+ LLRoleActionSet* role_action_set = new LLRoleActionSet();
+ LLRoleAction* role_action_data = new LLRoleAction();
+
+ // name=
+ std::string action_set_name;
+ if (action_set->getAttributeString("name", action_set_name))
+ {
+ LL_DEBUGS("GrpMgr") << "Loading action set " << action_set_name << LL_ENDL;
+ role_action_data->mName = action_set_name;
+ }
+ else
+ {
+ LL_WARNS() << "Unable to parse action set with no name" << LL_ENDL;
+ delete role_action_set;
+ delete role_action_data;
+ continue;
+ }
+ // description=
+ std::string set_description;
+ if (action_set->getAttributeString("description", set_description))
+ {
+ role_action_data->mDescription = set_description;
+ }
+ // long description=
+ std::string set_longdescription;
+ if (action_set->getAttributeString("longdescription", set_longdescription))
+ {
+ role_action_data->mLongDescription = set_longdescription;
+ }
+
+ // power mask=
+ U64 set_power_mask = 0;
+
+ LLXMLNodeList action_list;
+ LLXMLNodeList::iterator action_iter;
+
+ action_set->getChildren("action", action_list, false);
+
+ for (action_iter = action_list.begin(); action_iter != action_list.end(); ++action_iter)
+ {
+ LLXMLNodePtr action = action_iter->second;
+
+ LLRoleAction* role_action = new LLRoleAction();
+
+ // name=
+ std::string action_name;
+ if (action->getAttributeString("name", action_name))
+ {
+ LL_DEBUGS("GrpMgr") << "Loading action " << action_name << LL_ENDL;
+ role_action->mName = action_name;
+ }
+ else
+ {
+ LL_WARNS() << "Unable to parse action with no name" << LL_ENDL;
+ delete role_action;
+ continue;
+ }
+ // description=
+ std::string description;
+ if (action->getAttributeString("description", description))
+ {
+ role_action->mDescription = description;
+ }
+ // long description=
+ std::string longdescription;
+ if (action->getAttributeString("longdescription", longdescription))
+ {
+ role_action->mLongDescription = longdescription;
+ }
+ // description=
+ S32 power_bit = 0;
+ if (action->getAttributeS32("value", power_bit))
+ {
+ if (0 <= power_bit && power_bit < 64)
+ {
+ role_action->mPowerBit = 0x1LL << power_bit;
+ }
+ }
+
+ set_power_mask |= role_action->mPowerBit;
+
+ role_action_set->mActions.push_back(role_action);
+ }
+
+ role_action_data->mPowerBit = set_power_mask;
+ role_action_set->mActionSetData = role_action_data;
+
+ LLGroupMgr::getInstance()->mRoleActionSets.push_back(role_action_set);
+ }
+ return true;
+}
+
+// static
+void LLGroupMgr::debugClearAllGroups(void*)
+{
+ LLGroupMgr::getInstance()->clearGroups();
+ LLGroupMgr::parseRoleActions("role_actions.xml");
+}
+
+
|