PageRenderTime 926ms CodeModel.GetById 81ms app.highlight 687ms RepoModel.GetById 138ms app.codeStats 1ms

/indra/newview/llgroupmgr.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1951 lines | 1523 code | 276 blank | 152 comment | 270 complexity | e00fc6792d6c32595b64fa858b867823 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/** 
   2 * @file llgroupmgr.cpp
   3 * @brief LLGroupMgr class implementation
   4 *
   5 * $LicenseInfo:firstyear=2004&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27/**
  28 * Manager for aggregating all client knowledge for specific groups
  29 * Keeps a cache of group information.
  30 */
  31
  32#include "llviewerprecompiledheaders.h"
  33
  34#include "llgroupmgr.h"
  35
  36#include <vector>
  37#include <algorithm>
  38
  39#include "llagent.h"
  40#include "llui.h"
  41#include "message.h"
  42#include "roles_constants.h"
  43#include "lltransactiontypes.h"
  44#include "llstatusbar.h"
  45#include "lleconomy.h"
  46#include "llviewerwindow.h"
  47#include "llpanelgroup.h"
  48#include "llgroupactions.h"
  49#include "llnotificationsutil.h"
  50#include "lluictrlfactory.h"
  51#include "lltrans.h"
  52#include <boost/regex.hpp>
  53
  54#if LL_MSVC
  55#pragma warning(push)   
  56// disable boost::lexical_cast warning
  57#pragma warning (disable:4702)
  58#endif
  59
  60#include <boost/lexical_cast.hpp>
  61
  62#if LL_MSVC
  63#pragma warning(pop)   // Restore all warnings to the previous state
  64#endif
  65
  66const U32 MAX_CACHED_GROUPS = 10;
  67
  68//
  69// LLRoleActionSet
  70//
  71LLRoleActionSet::LLRoleActionSet()
  72: mActionSetData(NULL)
  73{ }
  74
  75LLRoleActionSet::~LLRoleActionSet()
  76{
  77	delete mActionSetData;
  78	std::for_each(mActions.begin(), mActions.end(), DeletePointer());
  79}
  80
  81//
  82// LLGroupMemberData
  83//
  84
  85LLGroupMemberData::LLGroupMemberData(const LLUUID& id, 
  86										S32 contribution,
  87										U64 agent_powers,
  88										const std::string& title,
  89										const std::string& online_status,
  90										BOOL is_owner) : 
  91	mID(id), 
  92	mContribution(contribution), 
  93	mAgentPowers(agent_powers), 
  94	mTitle(title), 
  95	mOnlineStatus(online_status),
  96	mIsOwner(is_owner)
  97{
  98}
  99
 100LLGroupMemberData::~LLGroupMemberData()
 101{
 102}
 103
 104void LLGroupMemberData::addRole(const LLUUID& role, LLGroupRoleData* rd)
 105{
 106	mRolesList[role] = rd;
 107}
 108
 109bool LLGroupMemberData::removeRole(const LLUUID& role)
 110{
 111	role_list_t::iterator it = mRolesList.find(role);
 112
 113	if (it != mRolesList.end())
 114	{
 115		mRolesList.erase(it);
 116		return true;
 117	}
 118
 119	return false;
 120}
 121
 122//
 123// LLGroupRoleData
 124//
 125
 126LLGroupRoleData::LLGroupRoleData(const LLUUID& role_id, 
 127								const std::string& role_name,
 128								const std::string& role_title,
 129								const std::string& role_desc,
 130								const U64 role_powers,
 131								const S32 member_count) :
 132	mRoleID(role_id),
 133	mMemberCount(member_count),
 134	mMembersNeedsSort(FALSE)
 135{
 136	mRoleData.mRoleName = role_name;
 137	mRoleData.mRoleTitle = role_title;
 138	mRoleData.mRoleDescription = role_desc;
 139	mRoleData.mRolePowers = role_powers;
 140	mRoleData.mChangeType = RC_UPDATE_NONE;
 141}
 142
 143LLGroupRoleData::LLGroupRoleData(const LLUUID& role_id, 
 144								LLRoleData role_data,
 145								const S32 member_count) :
 146	mRoleID(role_id),
 147	mRoleData(role_data),
 148	mMemberCount(member_count),
 149	mMembersNeedsSort(FALSE)
 150{
 151
 152}
 153
 154LLGroupRoleData::~LLGroupRoleData()
 155{	
 156}
 157
 158S32 LLGroupRoleData::getMembersInRole(uuid_vec_t members,
 159									  BOOL needs_sort)
 160{
 161	if (mRoleID.isNull())
 162	{
 163		// This is the everyone role, just return the size of members, 
 164		// because everyone is in the everyone role.
 165		return members.size();
 166	}
 167
 168	// Sort the members list, if needed.
 169	if (mMembersNeedsSort)
 170	{
 171		std::sort(mMemberIDs.begin(), mMemberIDs.end());
 172		mMembersNeedsSort = FALSE;
 173	}
 174	if (needs_sort)
 175	{
 176		// Sort the members parameter.
 177		std::sort(members.begin(), members.end());
 178	}
 179
 180	// Return the number of members in the intersection.
 181	S32 max_size = llmin( members.size(), mMemberIDs.size() );
 182	uuid_vec_t in_role( max_size );
 183	uuid_vec_t::iterator in_role_end;
 184	in_role_end = std::set_intersection(mMemberIDs.begin(), mMemberIDs.end(),
 185									members.begin(), members.end(),
 186									in_role.begin());
 187	return in_role_end - in_role.begin();
 188}
 189			  
 190void LLGroupRoleData::addMember(const LLUUID& member)
 191{
 192	mMembersNeedsSort = TRUE;
 193	mMemberIDs.push_back(member);
 194}
 195
 196bool LLGroupRoleData::removeMember(const LLUUID& member)
 197{
 198	uuid_vec_t::iterator it = std::find(mMemberIDs.begin(),mMemberIDs.end(),member);
 199
 200	if (it != mMemberIDs.end())
 201	{
 202		mMembersNeedsSort = TRUE;
 203		mMemberIDs.erase(it);
 204		return true;
 205	}
 206
 207	return false;
 208}
 209
 210void LLGroupRoleData::clearMembers()
 211{
 212	mMembersNeedsSort = FALSE;
 213	mMemberIDs.clear();
 214}
 215
 216
 217//
 218// LLGroupMgrGroupData
 219//
 220
 221LLGroupMgrGroupData::LLGroupMgrGroupData(const LLUUID& id) : 
 222	mID(id), 
 223	mShowInList(TRUE), 
 224	mOpenEnrollment(FALSE), 
 225	mMembershipFee(0),
 226	mAllowPublish(FALSE),
 227	mListInProfile(FALSE),
 228	mMaturePublish(FALSE),
 229	mChanged(FALSE),
 230	mMemberCount(0),
 231	mRoleCount(0),
 232	mReceivedRoleMemberPairs(0),
 233	mMemberDataComplete(FALSE),
 234	mRoleDataComplete(FALSE),
 235	mRoleMemberDataComplete(FALSE),
 236	mGroupPropertiesDataComplete(FALSE),
 237	mPendingRoleMemberRequest(FALSE)
 238{
 239}
 240
 241BOOL LLGroupMgrGroupData::getRoleData(const LLUUID& role_id, LLRoleData& role_data)
 242{
 243	role_data_map_t::const_iterator it;
 244
 245	// Do we have changes for it?
 246	it = mRoleChanges.find(role_id);
 247	if (it != mRoleChanges.end()) 
 248	{
 249		if ((*it).second.mChangeType == RC_DELETE) return FALSE;
 250
 251		role_data = (*it).second;
 252		return TRUE;
 253	}
 254
 255	// Ok, no changes, hasn't been deleted, isn't a new role, just find the role.
 256	role_list_t::const_iterator rit = mRoles.find(role_id);
 257	if (rit != mRoles.end())
 258	{
 259		role_data = (*rit).second->getRoleData();
 260		return TRUE;
 261	}
 262
 263	// This role must not exist.
 264	return FALSE;
 265}
 266
 267
 268void LLGroupMgrGroupData::setRoleData(const LLUUID& role_id, LLRoleData role_data)
 269{
 270	// If this is a newly created group, we need to change the data in the created list.
 271	role_data_map_t::iterator it;
 272	it = mRoleChanges.find(role_id);
 273	if (it != mRoleChanges.end())
 274	{
 275		if ((*it).second.mChangeType == RC_CREATE)
 276		{
 277			role_data.mChangeType = RC_CREATE;
 278			mRoleChanges[role_id] = role_data;
 279			return;
 280		}
 281		else if ((*it).second.mChangeType == RC_DELETE)
 282		{
 283			// Don't do anything for a role being deleted.
 284			return;
 285		}
 286	}
 287
 288	// Not a new role, so put it in the changes list.
 289	LLRoleData old_role_data;
 290	role_list_t::iterator rit = mRoles.find(role_id);
 291	if (rit != mRoles.end())
 292	{
 293		bool data_change = ( ((*rit).second->mRoleData.mRoleDescription != role_data.mRoleDescription)
 294							|| ((*rit).second->mRoleData.mRoleName != role_data.mRoleName)
 295							|| ((*rit).second->mRoleData.mRoleTitle != role_data.mRoleTitle) );
 296		bool powers_change = ((*rit).second->mRoleData.mRolePowers != role_data.mRolePowers);
 297		
 298		if (!data_change && !powers_change)
 299		{
 300			// We are back to the original state, the changes have been 'undone' so take out the change.
 301			mRoleChanges.erase(role_id);
 302			return;
 303		}
 304
 305		if (data_change && powers_change)
 306		{
 307			role_data.mChangeType = RC_UPDATE_ALL;
 308		}
 309		else if (data_change)
 310		{
 311			role_data.mChangeType = RC_UPDATE_DATA;
 312		}
 313		else
 314	{
 315			role_data.mChangeType = RC_UPDATE_POWERS;
 316		}
 317
 318		mRoleChanges[role_id] = role_data;
 319	}
 320	else
 321		{
 322		llwarns << "Change being made to non-existant role " << role_id << llendl;
 323	}
 324}
 325
 326BOOL LLGroupMgrGroupData::pendingRoleChanges()
 327{
 328	return (!mRoleChanges.empty());
 329}
 330
 331// This is a no-op if the role has already been created.
 332void LLGroupMgrGroupData::createRole(const LLUUID& role_id, LLRoleData role_data)
 333{
 334	if (mRoleChanges.find(role_id) != mRoleChanges.end())
 335	{
 336		llwarns << "create role for existing role! " << role_id << llendl;
 337	}
 338	else
 339	{
 340		role_data.mChangeType = RC_CREATE;
 341		mRoleChanges[role_id] = role_data;
 342	}
 343}
 344
 345void LLGroupMgrGroupData::deleteRole(const LLUUID& role_id)
 346{
 347	role_data_map_t::iterator it;
 348
 349	// If this was a new role, just discard it.
 350	it = mRoleChanges.find(role_id);
 351	if (it != mRoleChanges.end() 
 352		&& (*it).second.mChangeType == RC_CREATE)
 353	{
 354		mRoleChanges.erase(it);
 355		return;
 356	}
 357
 358	LLRoleData rd;
 359	rd.mChangeType = RC_DELETE;
 360	mRoleChanges[role_id] = rd;
 361}
 362
 363void LLGroupMgrGroupData::addRolePower(const LLUUID &role_id, U64 power)
 364{
 365	LLRoleData rd;
 366	if (getRoleData(role_id,rd))
 367	{	
 368		rd.mRolePowers |= power;
 369		setRoleData(role_id,rd);
 370	}
 371	else
 372	{
 373		llwarns << "addRolePower: no role data found for " << role_id << llendl;
 374	}
 375}
 376
 377void LLGroupMgrGroupData::removeRolePower(const LLUUID &role_id, U64 power)
 378{
 379	LLRoleData rd;
 380	if (getRoleData(role_id,rd))
 381	{
 382		rd.mRolePowers &= ~power;
 383		setRoleData(role_id,rd);
 384	}
 385	else
 386	{
 387		llwarns << "removeRolePower: no role data found for " << role_id << llendl;
 388	}
 389}
 390
 391U64 LLGroupMgrGroupData::getRolePowers(const LLUUID& role_id)
 392{
 393	LLRoleData rd;
 394	if (getRoleData(role_id,rd))
 395	{
 396		return rd.mRolePowers;
 397	}
 398	else
 399	{
 400		llwarns << "getRolePowers: no role data found for " << role_id << llendl;
 401		return GP_NO_POWERS;
 402	}
 403}
 404
 405void LLGroupMgrGroupData::removeData()
 406{
 407	// Remove member data first, because removeRoleData will walk the member list
 408	removeMemberData();
 409	removeRoleData();
 410}
 411
 412void LLGroupMgrGroupData::removeMemberData()
 413{
 414	for (member_list_t::iterator mi = mMembers.begin(); mi != mMembers.end(); ++mi)
 415	{
 416		delete mi->second;
 417	}
 418	mMembers.clear();
 419	mMemberDataComplete = FALSE;
 420}
 421
 422void LLGroupMgrGroupData::removeRoleData()
 423{
 424	for (member_list_t::iterator mi = mMembers.begin(); mi != mMembers.end(); ++mi)
 425	{
 426		LLGroupMemberData* data = mi->second;
 427		if (data)
 428		{
 429			data->clearRoles();
 430		}
 431	}
 432
 433	for (role_list_t::iterator ri = mRoles.begin(); ri != mRoles.end(); ++ri)
 434	{
 435		LLGroupRoleData* data = ri->second;
 436		delete data;
 437	}
 438	mRoles.clear();
 439	mReceivedRoleMemberPairs = 0;
 440	mRoleDataComplete = FALSE;
 441	mRoleMemberDataComplete = FALSE;
 442}
 443
 444void LLGroupMgrGroupData::removeRoleMemberData()
 445{
 446	for (member_list_t::iterator mi = mMembers.begin(); mi != mMembers.end(); ++mi)
 447	{
 448		LLGroupMemberData* data = mi->second;
 449		if (data)
 450		{
 451			data->clearRoles();
 452		}
 453	}
 454
 455	for (role_list_t::iterator ri = mRoles.begin(); ri != mRoles.end(); ++ri)
 456	{
 457		LLGroupRoleData* data = ri->second;
 458		if (data)
 459		{
 460			data->clearMembers();
 461		}
 462	}
 463
 464	mReceivedRoleMemberPairs = 0;
 465	mRoleMemberDataComplete = FALSE;
 466}
 467
 468LLGroupMgrGroupData::~LLGroupMgrGroupData()
 469{
 470	removeData();
 471}
 472
 473bool LLGroupMgrGroupData::changeRoleMember(const LLUUID& role_id, 
 474										   const LLUUID& member_id, 
 475										   LLRoleMemberChangeType rmc)
 476{
 477	role_list_t::iterator ri = mRoles.find(role_id);
 478	member_list_t::iterator mi = mMembers.find(member_id);
 479
 480	if (ri == mRoles.end()
 481		|| mi == mMembers.end() )
 482	{
 483		if (ri == mRoles.end()) llwarns << "LLGroupMgrGroupData::changeRoleMember couldn't find role " << role_id << llendl;
 484		if (mi == mMembers.end()) llwarns << "LLGroupMgrGroupData::changeRoleMember couldn't find member " << member_id << llendl;
 485		return false;
 486	}
 487
 488	LLGroupRoleData* grd = ri->second;
 489	LLGroupMemberData* gmd = mi->second;
 490
 491	if (!grd || !gmd)
 492	{
 493		llwarns << "LLGroupMgrGroupData::changeRoleMember couldn't get member or role data." << llendl;
 494		return false;
 495	}
 496
 497	if (RMC_ADD == rmc)
 498	{
 499		llinfos << " adding member to role." << llendl;
 500		grd->addMember(member_id);
 501		gmd->addRole(role_id,grd);
 502
 503		//TODO move this into addrole function
 504		//see if they added someone to the owner role and update isOwner
 505		gmd->mIsOwner = (role_id == mOwnerRole) ? TRUE : gmd->mIsOwner;
 506	}
 507	else if (RMC_REMOVE == rmc)
 508	{
 509		llinfos << " removing member from role." << llendl;
 510		grd->removeMember(member_id);
 511		gmd->removeRole(role_id);
 512
 513		//see if they removed someone from the owner role and update isOwner
 514		gmd->mIsOwner = (role_id == mOwnerRole) ? FALSE : gmd->mIsOwner;
 515	}
 516
 517	lluuid_pair role_member;
 518	role_member.first = role_id;
 519	role_member.second = member_id;
 520
 521	change_map_t::iterator it = mRoleMemberChanges.find(role_member);
 522	if (it != mRoleMemberChanges.end())
 523	{
 524		// There was already a role change for this role_member
 525		if (it->second.mChange == rmc)
 526		{
 527			// Already recorded this change?  Weird.
 528			llinfos << "Received duplicate change for "
 529					<< " role: " << role_id << " member " << member_id 
 530					<< " change " << (rmc == RMC_ADD ? "ADD" : "REMOVE") << llendl;
 531		}
 532		else
 533		{
 534			// The only two operations (add and remove) currently cancel each other out
 535			// If that changes this will need more logic
 536			if (rmc == RMC_NONE)
 537			{
 538				llwarns << "changeRoleMember: existing entry with 'RMC_NONE' change! This shouldn't happen." << llendl;
 539				LLRoleMemberChange rc(role_id,member_id,rmc);
 540				mRoleMemberChanges[role_member] = rc;
 541			}
 542			else
 543			{
 544				mRoleMemberChanges.erase(it);
 545			}
 546		}
 547	}
 548	else
 549	{
 550		LLRoleMemberChange rc(role_id,member_id,rmc);
 551		mRoleMemberChanges[role_member] = rc;
 552	}
 553
 554	recalcAgentPowers(member_id);
 555
 556	mChanged = TRUE;
 557	return true;
 558}
 559
 560void LLGroupMgrGroupData::recalcAllAgentPowers()
 561{
 562	LLGroupMemberData* gmd;
 563
 564	for (member_list_t::iterator mit = mMembers.begin();
 565		 mit != mMembers.end(); ++mit)
 566	{
 567		gmd = mit->second;
 568		if (!gmd) continue;
 569
 570		gmd->mAgentPowers = 0;
 571		for (LLGroupMemberData::role_list_t::iterator it = gmd->mRolesList.begin();
 572			 it != gmd->mRolesList.end(); ++it)
 573		{
 574			LLGroupRoleData* grd = (*it).second;
 575			if (!grd) continue;
 576
 577			gmd->mAgentPowers |= grd->mRoleData.mRolePowers;
 578		}
 579	}
 580}
 581
 582void LLGroupMgrGroupData::recalcAgentPowers(const LLUUID& agent_id)
 583{
 584	member_list_t::iterator mi = mMembers.find(agent_id);
 585	if (mi == mMembers.end()) return;
 586
 587	LLGroupMemberData* gmd = mi->second;
 588
 589	if (!gmd) return;
 590
 591	gmd->mAgentPowers = 0;
 592	for (LLGroupMemberData::role_list_t::iterator it = gmd->mRolesList.begin();
 593		 it != gmd->mRolesList.end(); ++it)
 594	{
 595		LLGroupRoleData* grd = (*it).second;
 596		if (!grd) continue;
 597
 598		gmd->mAgentPowers |= grd->mRoleData.mRolePowers;
 599	}
 600}
 601
 602bool packRoleUpdateMessageBlock(LLMessageSystem* msg, 
 603								const LLUUID& group_id,
 604								const LLUUID& role_id, 
 605								const LLRoleData& role_data, 
 606								bool start_message)
 607{
 608	if (start_message)
 609	{
 610		msg->newMessage("GroupRoleUpdate");
 611		msg->nextBlock("AgentData");
 612		msg->addUUID("AgentID",gAgent.getID());
 613		msg->addUUID("SessionID",gAgent.getSessionID());
 614		msg->addUUID("GroupID",group_id);
 615		start_message = false;
 616	}
 617
 618	msg->nextBlock("RoleData");
 619	msg->addUUID("RoleID",role_id);
 620	msg->addString("Name", role_data.mRoleName);
 621	msg->addString("Description", role_data.mRoleDescription);
 622	msg->addString("Title", role_data.mRoleTitle);
 623	msg->addU64("Powers", role_data.mRolePowers);
 624	msg->addU8("UpdateType", (U8)role_data.mChangeType);
 625
 626	if (msg->isSendFullFast())
 627	{
 628		gAgent.sendReliableMessage();
 629		start_message = true;
 630	}
 631
 632	return start_message;
 633}
 634
 635void LLGroupMgrGroupData::sendRoleChanges()
 636{
 637	// Commit changes locally
 638	LLGroupRoleData* grd;
 639	role_list_t::iterator role_it;
 640	LLMessageSystem* msg = gMessageSystem;
 641	bool start_message = true;
 642
 643	bool need_role_cleanup = false;
 644	bool need_role_data = false;
 645	bool need_power_recalc = false;
 646
 647	// Apply all changes
 648	for (role_data_map_t::iterator iter = mRoleChanges.begin();
 649		 iter != mRoleChanges.end(); )
 650	{
 651		role_data_map_t::iterator it = iter++; // safely incrament iter
 652		const LLUUID& role_id = (*it).first;
 653		const LLRoleData& role_data = (*it).second;
 654
 655		// Commit to local data set
 656		role_it = mRoles.find((*it).first);
 657		if ( (mRoles.end() == role_it 
 658				&& RC_CREATE != role_data.mChangeType)
 659			|| (mRoles.end() != role_it
 660				&& RC_CREATE == role_data.mChangeType))
 661		{
 662			continue;
 663		}
 664	
 665		// NOTE: role_it is valid EXCEPT for the RC_CREATE case
 666		switch (role_data.mChangeType)
 667		{
 668			case RC_CREATE:
 669			{
 670				// NOTE: role_it is NOT valid in this case
 671				grd = new LLGroupRoleData(role_id, role_data, 0);
 672				mRoles[role_id] = grd;
 673				need_role_data = true;
 674				break;
 675			}
 676			case RC_DELETE:
 677			{
 678				LLGroupRoleData* group_role_data = (*role_it).second;
 679				delete group_role_data;
 680				mRoles.erase(role_it);
 681				need_role_cleanup = true;
 682				need_power_recalc = true;
 683				break;
 684			}
 685			case RC_UPDATE_ALL:
 686				// fall through
 687			case RC_UPDATE_POWERS:
 688				need_power_recalc = true;
 689				// fall through
 690			case RC_UPDATE_DATA:
 691				// fall through
 692			default: 
 693			{
 694				LLGroupRoleData* group_role_data = (*role_it).second;
 695				group_role_data->setRoleData(role_data); // NOTE! might modify mRoleChanges!
 696				break;
 697			}
 698		}
 699
 700		// Update dataserver
 701		start_message = packRoleUpdateMessageBlock(msg,getID(),role_id,role_data,start_message);
 702	}
 703
 704	if (!start_message)
 705	{
 706		gAgent.sendReliableMessage();
 707	}
 708
 709	// If we delete a role then all the role-member pairs are invalid!
 710	if (need_role_cleanup)
 711	{
 712		removeRoleMemberData();
 713	}
 714
 715	// If we create a new role, then we need to re-fetch all the role data.
 716	if (need_role_data)
 717	{
 718		LLGroupMgr::getInstance()->sendGroupRoleDataRequest(getID());
 719	}
 720
 721	// Clean up change lists	
 722	mRoleChanges.clear();
 723
 724	// Recalculate all the agent powers because role powers have now changed.
 725	if (need_power_recalc)
 726	{
 727		recalcAllAgentPowers();
 728	}
 729}
 730
 731void LLGroupMgrGroupData::cancelRoleChanges()
 732{
 733	// Clear out all changes!
 734	mRoleChanges.clear();
 735}
 736//
 737// LLGroupMgr
 738//
 739
 740LLGroupMgr::LLGroupMgr()
 741{
 742}
 743
 744LLGroupMgr::~LLGroupMgr()
 745{
 746	clearGroups();
 747}
 748
 749void LLGroupMgr::clearGroups()
 750{
 751	std::for_each(mRoleActionSets.begin(), mRoleActionSets.end(), DeletePointer());
 752	mRoleActionSets.clear();
 753	std::for_each(mGroups.begin(), mGroups.end(), DeletePairedPointer());
 754	mGroups.clear();
 755	mObservers.clear();
 756}
 757
 758void LLGroupMgr::clearGroupData(const LLUUID& group_id)
 759{
 760	group_map_t::iterator iter = mGroups.find(group_id);
 761	if (iter != mGroups.end())
 762	{
 763		delete (*iter).second;
 764		mGroups.erase(iter);
 765	}
 766}
 767
 768void LLGroupMgr::addObserver(LLGroupMgrObserver* observer) 
 769{ 
 770	if( observer->getID() != LLUUID::null )
 771		mObservers.insert(std::pair<LLUUID, LLGroupMgrObserver*>(observer->getID(), observer));
 772}
 773
 774void LLGroupMgr::addObserver(const LLUUID& group_id, LLParticularGroupObserver* observer)
 775{
 776	if(group_id.notNull() && observer)
 777	{
 778		mParticularObservers[group_id].insert(observer);
 779	}
 780}
 781
 782void LLGroupMgr::removeObserver(LLGroupMgrObserver* observer)
 783{
 784	if (!observer)
 785	{
 786		return;
 787	}
 788	observer_multimap_t::iterator it;
 789	it = mObservers.find(observer->getID());
 790	while (it != mObservers.end())
 791	{
 792		if (it->second == observer)
 793		{
 794			mObservers.erase(it);
 795			break;
 796		}
 797		else
 798		{
 799			++it;
 800		}
 801	}
 802}
 803
 804void LLGroupMgr::removeObserver(const LLUUID& group_id, LLParticularGroupObserver* observer)
 805{
 806	if(group_id.isNull() || !observer)
 807	{
 808		return;
 809	}
 810
 811    observer_map_t::iterator obs_it = mParticularObservers.find(group_id);
 812    if(obs_it == mParticularObservers.end())
 813        return;
 814
 815    obs_it->second.erase(observer);
 816
 817    if (obs_it->second.size() == 0)
 818    	mParticularObservers.erase(obs_it);
 819}
 820
 821LLGroupMgrGroupData* LLGroupMgr::getGroupData(const LLUUID& id)
 822{
 823	group_map_t::iterator gi = mGroups.find(id);
 824
 825	if (gi != mGroups.end())
 826	{
 827		return gi->second;
 828	}
 829	return NULL;
 830}
 831
 832// Helper function for LLGroupMgr::processGroupMembersReply
 833// This reformats date strings from MM/DD/YYYY to YYYY/MM/DD ( e.g. 1/27/2008 -> 2008/1/27 )
 834// so that the sorter can sort by year before month before day.
 835static void formatDateString(std::string &date_string)
 836{
 837	using namespace boost;
 838	cmatch result;
 839	const regex expression("([0-9]{1,2})/([0-9]{1,2})/([0-9]{4})");
 840	if (regex_match(date_string.c_str(), result, expression))
 841	{
 842		// convert matches to integers so that we can pad them with zeroes on Linux
 843		S32 year	= boost::lexical_cast<S32>(result[3]);
 844		S32 month	= boost::lexical_cast<S32>(result[1]);
 845		S32 day		= boost::lexical_cast<S32>(result[2]);
 846
 847		// ISO 8601 date format
 848		date_string = llformat("%04d/%02d/%02d", year, month, day);
 849	}
 850}
 851
 852// static
 853void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data)
 854{
 855	lldebugs << "LLGroupMgr::processGroupMembersReply" << llendl;
 856	LLUUID agent_id;
 857	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
 858	if (gAgent.getID() != agent_id)
 859	{
 860		llwarns << "Got group members reply for another agent!" << llendl;
 861		return;
 862	}
 863
 864	LLUUID group_id;
 865	msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id );
 866
 867	LLUUID request_id;
 868	msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_RequestID, request_id);
 869
 870	LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
 871	if (!group_datap || (group_datap->mMemberRequestID != request_id))
 872	{
 873		llwarns << "processGroupMembersReply: Received incorrect (stale?) group or request id" << llendl;
 874		return;
 875	}
 876
 877	msg->getS32(_PREHASH_GroupData, "MemberCount", group_datap->mMemberCount );
 878
 879	if (group_datap->mMemberCount > 0)
 880	{
 881		S32 contribution = 0;
 882		std::string online_status;
 883		std::string title;
 884		U64 agent_powers = 0;
 885		BOOL is_owner = FALSE;
 886
 887		S32 num_members = msg->getNumberOfBlocksFast(_PREHASH_MemberData);
 888		for (S32 i = 0; i < num_members; i++)
 889		{
 890			LLUUID member_id;
 891
 892			msg->getUUIDFast(_PREHASH_MemberData, _PREHASH_AgentID, member_id, i );
 893			msg->getS32(_PREHASH_MemberData, _PREHASH_Contribution, contribution, i);
 894			msg->getU64(_PREHASH_MemberData, "AgentPowers", agent_powers, i);
 895			msg->getStringFast(_PREHASH_MemberData, _PREHASH_OnlineStatus, online_status, i);
 896			msg->getString(_PREHASH_MemberData, "Title", title, i);
 897			msg->getBOOL(_PREHASH_MemberData,"IsOwner",is_owner,i);
 898
 899			if (member_id.notNull())
 900			{
 901				if (online_status == "Online")
 902				{
 903					static std::string localized_online(LLTrans::getString("group_member_status_online"));
 904					online_status = localized_online;
 905				}
 906				else
 907				{
 908					formatDateString(online_status); // reformat for sorting, e.g. 12/25/2008 -> 2008/12/25
 909				}
 910				
 911				//llinfos << "Member " << member_id << " has powers " << std::hex << agent_powers << std::dec << llendl;
 912				LLGroupMemberData* newdata = new LLGroupMemberData(member_id, 
 913																	contribution, 
 914																	agent_powers, 
 915																	title,
 916																	online_status,
 917																	is_owner);
 918#if LL_DEBUG
 919				LLGroupMgrGroupData::member_list_t::iterator mit = group_datap->mMembers.find(member_id);
 920				if (mit != group_datap->mMembers.end())
 921				{
 922					llinfos << " *** Received duplicate member data for agent " << member_id << llendl;
 923				}
 924#endif
 925				group_datap->mMembers[member_id] = newdata;
 926			}
 927			else
 928			{
 929				llinfos << "Received null group member data." << llendl;
 930			}
 931		}
 932
 933		//if group members are loaded while titles are missing, load the titles.
 934		if(group_datap->mTitles.size() < 1)
 935		{
 936			LLGroupMgr::getInstance()->sendGroupTitlesRequest(group_id);
 937		}
 938	}
 939
 940	if (group_datap->mMembers.size() ==  (U32)group_datap->mMemberCount)
 941	{
 942		group_datap->mMemberDataComplete = TRUE;
 943		group_datap->mMemberRequestID.setNull();
 944		// We don't want to make role-member data requests until we have all the members
 945		if (group_datap->mPendingRoleMemberRequest)
 946		{
 947			group_datap->mPendingRoleMemberRequest = FALSE;
 948			LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_datap->mID);
 949		}
 950	}
 951
 952	group_datap->mChanged = TRUE;
 953	LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA);
 954}
 955
 956//static 
 957void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data)
 958{
 959	lldebugs << "LLGroupMgr::processGroupPropertiesReply" << llendl;
 960	LLUUID agent_id;
 961	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
 962	if (gAgent.getID() != agent_id)
 963	{
 964		llwarns << "Got group properties reply for another agent!" << llendl;
 965		return;
 966	}
 967
 968	LLUUID group_id;
 969	std::string	name;
 970	std::string	charter;
 971	BOOL	show_in_list = FALSE;
 972	LLUUID	founder_id;
 973	U64		powers_mask = GP_NO_POWERS;
 974	S32		money = 0;
 975	std::string	member_title;
 976	LLUUID	insignia_id;
 977	LLUUID	owner_role;
 978	U32		membership_fee = 0;
 979	BOOL	open_enrollment = FALSE;
 980	S32		num_group_members = 0;
 981	S32		num_group_roles = 0;
 982	BOOL	allow_publish = FALSE;
 983	BOOL	mature = FALSE;
 984
 985	msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id );
 986	msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_FounderID, founder_id);	
 987	msg->getStringFast(_PREHASH_GroupData, _PREHASH_Name, name );
 988	msg->getStringFast(_PREHASH_GroupData, _PREHASH_Charter, charter );
 989	msg->getBOOLFast(_PREHASH_GroupData, _PREHASH_ShowInList, show_in_list );
 990	msg->getStringFast(_PREHASH_GroupData, _PREHASH_MemberTitle, member_title );
 991	msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_InsigniaID, insignia_id );
 992	msg->getU64Fast(_PREHASH_GroupData, _PREHASH_PowersMask, powers_mask );
 993	msg->getU32Fast(_PREHASH_GroupData, _PREHASH_MembershipFee, membership_fee );
 994	msg->getBOOLFast(_PREHASH_GroupData, _PREHASH_OpenEnrollment, open_enrollment );
 995	msg->getS32Fast(_PREHASH_GroupData, _PREHASH_GroupMembershipCount, num_group_members);
 996	msg->getS32(_PREHASH_GroupData, "GroupRolesCount", num_group_roles);
 997	msg->getS32Fast(_PREHASH_GroupData, _PREHASH_Money, money);
 998	msg->getBOOL("GroupData", "AllowPublish", allow_publish);
 999	msg->getBOOL("GroupData", "MaturePublish", mature);
1000	msg->getUUID(_PREHASH_GroupData, "OwnerRole", owner_role);
1001
1002	LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->createGroupData(group_id);
1003
1004	group_datap->mName = name;
1005	group_datap->mCharter = charter;
1006	group_datap->mShowInList = show_in_list;
1007	group_datap->mInsigniaID = insignia_id;
1008	group_datap->mFounderID = founder_id;
1009	group_datap->mMembershipFee = membership_fee;
1010	group_datap->mOpenEnrollment = open_enrollment;
1011	group_datap->mAllowPublish = allow_publish;
1012	group_datap->mMaturePublish = mature;
1013	group_datap->mOwnerRole = owner_role;
1014	group_datap->mMemberCount = num_group_members;
1015	group_datap->mRoleCount = num_group_roles + 1; // Add the everyone role.
1016	
1017	group_datap->mGroupPropertiesDataComplete = TRUE;
1018	group_datap->mChanged = TRUE;
1019
1020	LLGroupMgr::getInstance()->notifyObservers(GC_PROPERTIES);
1021}
1022
1023// static
1024void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data)
1025{
1026	lldebugs << "LLGroupMgr::processGroupRoleDataReply" << llendl;
1027	LLUUID agent_id;
1028	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
1029	if (gAgent.getID() != agent_id)
1030	{
1031		llwarns << "Got group role data reply for another agent!" << llendl;
1032		return;
1033	}
1034
1035	LLUUID group_id;
1036	msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id );
1037
1038	LLUUID request_id;
1039	msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_RequestID, request_id);
1040
1041	LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
1042	if (!group_datap || (group_datap->mRoleDataRequestID != request_id))
1043	{
1044		llwarns << "processGroupPropertiesReply: Received incorrect (stale?) group or request id" << llendl;
1045		return;
1046	}
1047
1048	msg->getS32(_PREHASH_GroupData, "RoleCount", group_datap->mRoleCount );
1049
1050	std::string	name;
1051	std::string	title;
1052	std::string	desc;
1053	U64		powers = 0;
1054	U32		member_count = 0;
1055	LLUUID role_id;
1056
1057	U32 num_blocks = msg->getNumberOfBlocks("RoleData");
1058	U32 i = 0;
1059	for (i=0; i< num_blocks; ++i)
1060	{
1061		msg->getUUID("RoleData", "RoleID", role_id, i );
1062		
1063		msg->getString("RoleData","Name",name,i);
1064		msg->getString("RoleData","Title",title,i);
1065		msg->getString("RoleData","Description",desc,i);
1066		msg->getU64("RoleData","Powers",powers,i);
1067		msg->getU32("RoleData","Members",member_count,i);
1068
1069		//there are 3 predifined roles - Owners, Officers, Everyone
1070		//there names are defined in lldatagroups.cpp
1071		//lets change names from server to localized strings
1072		if(name == "Everyone")
1073		{
1074			name = LLTrans::getString("group_role_everyone");
1075		}
1076		else if(name == "Officers")
1077		{
1078			name = LLTrans::getString("group_role_officers");
1079		}
1080		else if(name == "Owners")
1081		{
1082			name = LLTrans::getString("group_role_owners");
1083		}
1084
1085
1086
1087		lldebugs << "Adding role data: " << name << " {" << role_id << "}" << llendl;
1088		LLGroupRoleData* rd = new LLGroupRoleData(role_id,name,title,desc,powers,member_count);
1089		group_datap->mRoles[role_id] = rd;
1090	}
1091
1092	if (group_datap->mRoles.size() == (U32)group_datap->mRoleCount)
1093	{
1094		group_datap->mRoleDataComplete = TRUE;
1095		group_datap->mRoleDataRequestID.setNull();
1096		// We don't want to make role-member data requests until we have all the role data
1097		if (group_datap->mPendingRoleMemberRequest)
1098		{
1099			group_datap->mPendingRoleMemberRequest = FALSE;
1100			LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_datap->mID);
1101		}
1102	}
1103
1104	group_datap->mChanged = TRUE;
1105	LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_DATA);
1106}
1107
1108// static
1109void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data)
1110{
1111	lldebugs << "LLGroupMgr::processGroupRoleMembersReply" << llendl;
1112	LLUUID agent_id;
1113	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
1114	if (gAgent.getID() != agent_id)
1115	{
1116		llwarns << "Got group role members reply for another agent!" << llendl;
1117		return;
1118	}
1119
1120	LLUUID request_id;
1121	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_RequestID, request_id);
1122
1123	LLUUID group_id;
1124	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id );
1125
1126	U32 total_pairs;
1127	msg->getU32(_PREHASH_AgentData, "TotalPairs", total_pairs);
1128
1129	LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
1130	if (!group_datap || (group_datap->mRoleMembersRequestID != request_id))
1131	{
1132		llwarns << "processGroupRoleMembersReply: Received incorrect (stale?) group or request id" << llendl;
1133		return;
1134	}
1135
1136	U32 num_blocks = msg->getNumberOfBlocks("MemberData");
1137	U32 i;
1138	LLUUID member_id;
1139	LLUUID role_id;
1140	LLGroupRoleData* rd = NULL;
1141	LLGroupMemberData* md = NULL;
1142
1143	LLGroupMgrGroupData::role_list_t::iterator ri;
1144	LLGroupMgrGroupData::member_list_t::iterator mi;
1145
1146	// If total_pairs == 0, there are no members in any custom roles.
1147	if (total_pairs > 0)
1148	{
1149		for (i = 0;i < num_blocks; ++i)
1150		{
1151			msg->getUUID("MemberData","RoleID",role_id,i);
1152			msg->getUUID("MemberData","MemberID",member_id,i);
1153
1154			if (role_id.notNull() && member_id.notNull() )
1155			{
1156				rd = NULL;
1157				ri = group_datap->mRoles.find(role_id);
1158				if (ri != group_datap->mRoles.end())
1159				{
1160					rd = ri->second;
1161				}
1162
1163				md = NULL;
1164				mi = group_datap->mMembers.find(member_id);
1165				if (mi != group_datap->mMembers.end())
1166				{
1167					md = mi->second;
1168				}
1169
1170				if (rd && md)
1171				{
1172					lldebugs << "Adding role-member pair: " << role_id << ", " << member_id << llendl;
1173					rd->addMember(member_id);
1174					md->addRole(role_id,rd);
1175				}
1176				else
1177				{
1178					if (!rd) llwarns << "Received role data for unknown role " << role_id << " in group " << group_id << llendl;
1179					if (!md) llwarns << "Received role data for unknown member " << member_id << " in group " << group_id << llendl;
1180				}
1181			}
1182		}
1183
1184		group_datap->mReceivedRoleMemberPairs += num_blocks;
1185	}
1186
1187	if (group_datap->mReceivedRoleMemberPairs == total_pairs)
1188	{
1189		// Add role data for the 'everyone' role to all members
1190		LLGroupRoleData* everyone = group_datap->mRoles[LLUUID::null];
1191		if (!everyone)
1192		{
1193			llwarns << "Everyone role not found!" << llendl;
1194		}
1195		else
1196		{
1197			for (LLGroupMgrGroupData::member_list_t::iterator mi = group_datap->mMembers.begin();
1198				 mi != group_datap->mMembers.end(); ++mi)
1199			{
1200				LLGroupMemberData* data = mi->second;
1201				if (data)
1202				{
1203					data->addRole(LLUUID::null,everyone);
1204				}
1205			}
1206		}
1207		
1208        group_datap->mRoleMemberDataComplete = TRUE;
1209		group_datap->mRoleMembersRequestID.setNull();
1210	}
1211
1212	group_datap->mChanged = TRUE;
1213	LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_MEMBER_DATA);
1214}
1215
1216// static
1217void LLGroupMgr::processGroupTitlesReply(LLMessageSystem* msg, void** data)
1218{
1219	lldebugs << "LLGroupMgr::processGroupTitlesReply" << llendl;
1220	LLUUID agent_id;
1221	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
1222	if (gAgent.getID() != agent_id)
1223	{
1224		llwarns << "Got group properties reply for another agent!" << llendl;
1225		return;
1226	}
1227
1228	LLUUID group_id;
1229	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id );
1230	LLUUID request_id;
1231	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_RequestID, request_id);
1232	
1233	LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
1234	if (!group_datap || (group_datap->mTitlesRequestID != request_id))
1235	{
1236		llwarns << "processGroupTitlesReply: Received incorrect (stale?) group" << llendl;
1237		return;
1238	}
1239
1240	LLGroupTitle title;
1241
1242	S32 i = 0;
1243	S32 blocks = msg->getNumberOfBlocksFast(_PREHASH_GroupData);
1244	for (i=0; i<blocks; ++i)
1245	{
1246		msg->getString("GroupData","Title",title.mTitle,i);
1247		msg->getUUID("GroupData","RoleID",title.mRoleID,i);
1248		msg->getBOOL("GroupData","Selected",title.mSelected,i);
1249
1250		if (!title.mTitle.empty())
1251		{
1252			lldebugs << "LLGroupMgr adding title: " << title.mTitle << ", " << title.mRoleID << ", " << (title.mSelected ? 'Y' : 'N') << llendl;
1253			group_datap->mTitles.push_back(title);
1254		}
1255	}
1256
1257	group_datap->mChanged = TRUE;
1258	LLGroupMgr::getInstance()->notifyObservers(GC_TITLES);
1259}
1260
1261// static
1262void LLGroupMgr::processEjectGroupMemberReply(LLMessageSystem* msg, void ** data)
1263{
1264	lldebugs << "processEjectGroupMemberReply" << llendl;
1265	LLUUID group_id;
1266	msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id);
1267	BOOL success;
1268	msg->getBOOLFast(_PREHASH_EjectData, _PREHASH_Success, success);
1269
1270	// If we had a failure, the group panel needs to be updated.
1271	if (!success)
1272	{
1273		LLGroupActions::refresh(group_id);
1274	}
1275}
1276
1277// static
1278void LLGroupMgr::processJoinGroupReply(LLMessageSystem* msg, void ** data)
1279{
1280	lldebugs << "processJoinGroupReply" << llendl;
1281	LLUUID group_id;
1282	BOOL success;
1283	msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id);
1284	msg->getBOOLFast(_PREHASH_GroupData, _PREHASH_Success, success);
1285
1286	if (success)
1287	{
1288		// refresh all group information
1289		gAgent.sendAgentDataUpdateRequest();
1290
1291		LLGroupMgr::getInstance()->clearGroupData(group_id);
1292		// refresh the floater for this group, if any.
1293		LLGroupActions::refresh(group_id);
1294	}
1295}
1296
1297// static
1298void LLGroupMgr::processLeaveGroupReply(LLMessageSystem* msg, void ** data)
1299{
1300	lldebugs << "processLeaveGroupReply" << llendl;
1301	LLUUID group_id;
1302	BOOL success;
1303	msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id);
1304	msg->getBOOLFast(_PREHASH_GroupData, _PREHASH_Success, success);
1305
1306	if (success)
1307	{
1308		// refresh all group information
1309		gAgent.sendAgentDataUpdateRequest();
1310
1311		LLGroupMgr::getInstance()->clearGroupData(group_id);
1312		// close the floater for this group, if any.
1313		LLGroupActions::closeGroup(group_id);
1314	}
1315}
1316
1317// static
1318void LLGroupMgr::processCreateGroupReply(LLMessageSystem* msg, void ** data)
1319{
1320	LLUUID group_id;
1321	BOOL success;
1322	std::string message;
1323
1324	msg->getUUIDFast(_PREHASH_ReplyData, _PREHASH_GroupID, group_id );
1325
1326	msg->getBOOLFast(_PREHASH_ReplyData, _PREHASH_Success,	success );
1327	msg->getStringFast(_PREHASH_ReplyData, _PREHASH_Message, message );
1328
1329	if (success)
1330	{
1331		// refresh all group information
1332		gAgent.sendAgentDataUpdateRequest();
1333
1334		// HACK! We haven't gotten the agent group update yet, so ... um ... fake it.
1335		// This is so when we go to modify the group we will be able to do so.
1336		// This isn't actually too bad because real data will come down in 2 or 3 miliseconds and replace this.
1337		LLGroupData gd;
1338		gd.mAcceptNotices = TRUE;
1339		gd.mListInProfile = TRUE;
1340		gd.mContribution = 0;
1341		gd.mID = group_id;
1342		gd.mName = "new group";
1343		gd.mPowers = GP_ALL_POWERS;
1344
1345		gAgent.mGroups.push_back(gd);
1346
1347		LLPanelGroup::refreshCreatedGroup(group_id);
1348		//FIXME
1349		//LLFloaterGroupInfo::closeCreateGroup();
1350		//LLFloaterGroupInfo::showFromUUID(group_id,"roles_tab");
1351	}
1352	else
1353	{
1354		// *TODO: Translate
1355		LLSD args;
1356		args["MESSAGE"] = message;
1357		LLNotificationsUtil::add("UnableToCreateGroup", args);
1358	}
1359}
1360
1361LLGroupMgrGroupData* LLGroupMgr::createGroupData(const LLUUID& id)
1362{
1363	LLGroupMgrGroupData* group_datap;
1364
1365	group_map_t::iterator existing_group = LLGroupMgr::getInstance()->mGroups.find(id);
1366	if (existing_group == LLGroupMgr::getInstance()->mGroups.end())
1367	{
1368		group_datap = new LLGroupMgrGroupData(id);
1369		LLGroupMgr::getInstance()->addGroup(group_datap);
1370	}
1371	else
1372	{
1373		group_datap = existing_group->second;
1374	}
1375
1376	return group_datap;
1377}
1378
1379void LLGroupMgr::notifyObservers(LLGroupChange gc)
1380{
1381	for (group_map_t::iterator gi = mGroups.begin(); gi != mGroups.end(); ++gi)
1382	{
1383		LLUUID group_id = gi->first;
1384		if (gi->second->mChanged)
1385		{
1386			// notify LLGroupMgrObserver
1387			// Copy the map because observers may remove themselves on update
1388			observer_multimap_t observers = mObservers;
1389
1390			// find all observers for this group id
1391			observer_multimap_t::iterator oi = observers.lower_bound(group_id);
1392			observer_multimap_t::iterator end = observers.upper_bound(group_id);
1393			for (; oi != end; ++oi)
1394			{
1395				oi->second->changed(gc);
1396			}
1397			gi->second->mChanged = FALSE;
1398
1399
1400			// notify LLParticularGroupObserver
1401		    observer_map_t::iterator obs_it = mParticularObservers.find(group_id);
1402		    if(obs_it == mParticularObservers.end())
1403		        return;
1404
1405		    observer_set_t& obs = obs_it->second;
1406		    for (observer_set_t::iterator ob_it = obs.begin(); ob_it != obs.end(); ++ob_it)
1407		    {
1408		        (*ob_it)->changed(group_id, gc);
1409		    }
1410		}
1411	}
1412}
1413
1414void LLGroupMgr::addGroup(LLGroupMgrGroupData* group_datap)
1415{
1416	if (mGroups.size() > MAX_CACHED_GROUPS)
1417	{
1418		// get rid of groups that aren't observed
1419		for (group_map_t::iterator gi = mGroups.begin(); gi != mGroups.end() && mGroups.size() > MAX_CACHED_GROUPS / 2; )
1420		{
1421			observer_multimap_t::iterator oi = mObservers.find(gi->first);
1422			if (oi == mObservers.end())
1423			{
1424				// not observed
1425				LLGroupMgrGroupData* unobserved_groupp = gi->second;
1426				delete unobserved_groupp;
1427				mGroups.erase(gi++);
1428			}
1429			else
1430			{
1431				++gi;
1432			}
1433		}
1434	}
1435	mGroups[group_datap->getID()] = group_datap;
1436}
1437
1438
1439void LLGroupMgr::sendGroupPropertiesRequest(const LLUUID& group_id)
1440{
1441	lldebugs << "LLGroupMgr::sendGroupPropertiesRequest" << llendl;
1442	// This will happen when we get the reply
1443	//LLGroupMgrGroupData* group_datap = createGroupData(group_id);
1444	
1445	LLMessageSystem* msg = gMessageSystem;
1446	msg->newMessage("GroupProfileRequest");
1447	msg->nextBlock("AgentData");
1448	msg->addUUID("AgentID",gAgent.getID());
1449	msg->addUUID("SessionID",gAgent.getSessionID());
1450	msg->nextBlock("GroupData");
1451	msg->addUUID("GroupID",group_id);
1452	gAgent.sendReliableMessage();
1453}
1454
1455void LLGroupMgr::sendGroupMembersRequest(const LLUUID& group_id)
1456{
1457	lldebugs << "LLGroupMgr::sendGroupMembersRequest" << llendl;
1458	LLGroupMgrGroupData* group_datap = createGroupData(group_id);
1459	if (group_datap->mMemberRequestID.isNull())
1460	{
1461		group_datap->removeMemberData();
1462		group_datap->mMemberRequestID.generate();
1463
1464		LLMessageSystem* msg = gMessageSystem;
1465		msg->newMessage("GroupMembersRequest");
1466		msg->nextBlock("AgentData");
1467		msg->addUUID("AgentID",gAgent.getID());
1468		msg->addUUID("SessionID",gAgent.getSessionID());
1469		msg->nextBlock("GroupData");
1470		msg->addUUID("GroupID",group_id);
1471		msg->addUUID("RequestID",group_datap->mMemberRequestID);
1472		gAgent.sendReliableMessage();
1473	}
1474}
1475
1476void LLGroupMgr::sendGroupRoleDataRequest(const LLUUID& group_id)
1477{
1478	lldebugs << "LLGroupMgr::sendGroupRoleDataRequest" << llendl;
1479	LLGroupMgrGroupData* group_datap = createGroupData(group_id);
1480	if (group_datap->mRoleDataRequestID.isNull())
1481	{
1482		group_datap->removeRoleData();
1483		group_datap->mRoleDataRequestID.generate();
1484
1485		LLMessageSystem* msg = gMessageSystem;
1486		msg->newMessage("GroupRoleDataRequest");
1487		msg->nextBlock("AgentData");
1488		msg->addUUID("AgentID",gAgent.getID());
1489		msg->addUUID("SessionID",gAgent.getSessionID());
1490		msg->nextBlock("GroupData");
1491		msg->addUUID("GroupID",group_id);
1492		msg->addUUID("RequestID",group_datap->mRoleDataRequestID);
1493		gAgent.sendReliableMessage();
1494	}
1495}
1496
1497void LLGroupMgr::sendGroupRoleMembersRequest(const LLUUID& group_id)
1498{
1499	lldebugs << "LLGroupMgr::sendGroupRoleMembersRequest" << llendl;
1500	LLGroupMgrGroupData* group_datap = createGroupData(group_id);
1501	
1502	if (group_datap->mRoleMembersRequestID.isNull())
1503	{
1504		// Don't send the request if we don't have all the member or role data
1505		if (!group_datap->isMemberDataComplete()
1506			|| !group_datap->isRoleDataComplete())
1507		{
1508			// *TODO: KLW FIXME: Should we start a member or role data request?
1509			llinfos << " Pending: " << (group_datap->mPendingRoleMemberRequest ? "Y" : "N")
1510				<< " MemberDataComplete: " << (group_datap->mMemberDataComplete ? "Y" : "N")
1511				<< " RoleDataComplete: " << (group_datap->mRoleDataComplete ? "Y" : "N") << llendl;
1512			group_datap->mPendingRoleMemberRequest = TRUE;
1513			return;
1514		}
1515
1516		group_datap->removeRoleMemberData();
1517		group_datap->mRoleMembersRequestID.generate();
1518
1519		LLMessageSystem* msg = gMessageSystem;
1520		msg->newMessage("GroupRoleMembersRequest");
1521		msg->nextBlock("AgentData");
1522		msg->addUUID("AgentID",gAgent.getID());
1523		msg->addUUID("SessionID",gAgent.getSessionID());
1524		msg->nextBlock("GroupData");
1525		msg->addUUID("GroupID",group_id);
1526		msg->addUUID("RequestID",group_datap->mRoleMembersRequestID);
1527		gAgent.sendReliableMessage();
1528	}
1529}
1530
1531void LLGroupMgr::sendGroupTitlesRequest(const LLUUID& group_id)
1532{
1533	lldebugs << "LLGroupMgr::sendGroupTitlesRequest" << llendl;
1534	LLGroupMgrGroupData* group_datap = createGroupData(group_id);
1535	
1536	group_datap->mTitles.clear();
1537	group_datap->mTitlesRequestID.generate();
1538
1539	LLMessageSystem* msg = gMessageSystem;
1540	msg->newMessage("GroupTitlesRequest");
1541	msg->nextBlock("AgentData");
1542	msg->addUUID("AgentID",gAgent.getID());
1543	msg->addUUID("SessionID",gAgent.getSessionID());
1544	msg->addUUID("GroupID",group_id);
1545	msg->addUUID("RequestID",group_datap->mTitlesRequestID);
1546
1547	gAgent.sendReliableMessage();
1548}
1549
1550void LLGroupMgr::sendGroupTitleUpdate(const LLUUID& group_id, const LLUUID& title_role_id)
1551{
1552	lldebugs << "LLGroupMgr::sendGroupTitleUpdate" << llendl;
1553
1554	LLMessageSystem* msg = gMessageSystem;
1555	msg->newMessage("GroupTitleUpdate");
1556	msg->nextBlock("AgentData");
1557	msg->addUUID("AgentID",gAgent.getID());
1558	msg->addUUID("SessionID",gAgent.getSessionID());
1559	msg->addUUID("GroupID",group_id);
1560	msg->addUUID("TitleRoleID",title_role_id);
1561
1562	gAgent.sendReliableMessage();
1563
1564	// Save the change locally
1565	LLGroupMgrGroupData* group_datap = createGroupData(group_id);
1566	for (std::vector<LLGroupTitle>::iterator iter = group_datap->mTitles.begin();
1567		 iter != group_datap->mTitles.end(); ++iter)
1568	{
1569		if (iter->mRoleID == title_role_id)
1570		{
1571			iter->mSelected = TRUE;
1572		}
1573		else if (iter->mSelected)
1574		{
1575			iter->mSelected = FALSE;
1576		}
1577	}
1578}
1579
1580// static
1581void LLGroupMgr::sendCreateGroupRequest(const std::string& name,
1582										const std::string& charter,
1583										U8 show_in_list,
1584										const LLUUID& insignia,
1585										S32 membership_fee,
1586										BOOL open_enrollment,
1587										BOOL allow_publish,
1588										BOOL mature_publish)
1589{
1590	LLMessageSystem* msg = gMessageSystem;
1591	msg->newMessage("CreateGroupRequest");
1592	msg->nextBlock("AgentData");
1593	msg->addUUID("AgentID",gAgent.getID());
1594	msg->addUUID("SessionID",gAgent.getSessionID());
1595
1596	msg->nextBlock("GroupData");
1597	msg->addString("Name",name);
1598	msg->addString("Charter",charter);
1599	msg->addBOOL("ShowInList",show_in_list);
1600	msg->addUUID("InsigniaID",insignia);
1601	msg->addS32("MembershipFee",membership_fee);
1602	msg->addBOOL("OpenEnrollment",open_enrollment);
1603	msg->addBOOL("AllowPublish",allow_publish);
1604	msg->addBOOL("MaturePublish",mature_publish);
1605
1606	gAgent.sendReliableMessage();
1607}
1608
1609void LLGroupMgr::sendUpdateGroupInfo(const LLUUID& group_id)
1610{
1611	lldebugs << "LLGroupMgr::sendUpdateGroupInfo" << llendl;
1612	LLGroupMgrGroupData* group_datap = createGroupData(group_id);
1613
1614	LLMessageSystem* msg = gMessageSystem;
1615
1616	msg->newMessageFast(_PREHASH_UpdateGroupInfo);
1617	msg->nextBlockFast(_PREHASH_AgentData);
1618	msg->addUUIDFast(_PREHASH_AgentID,gAgent.getID());
1619	msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
1620
1621	msg->nextBlockFast(_PREHASH_GroupData);
1622	msg->addUUIDFast(_PREHASH_GroupID,group_datap->getID());
1623	msg->addStringFast(_PREHASH_Charter,group_datap->mCharter);
1624	msg->addBOOLFast(_PREHASH_ShowInList,group_datap->mShowInList);
1625	msg->addUUIDFast(_PREHASH_InsigniaID,group_datap->mInsigniaID);
1626	msg->addS32Fast(_PREHASH_MembershipFee,group_datap->mMembershipFee);
1627	msg->addBOOLFast(_PREHASH_OpenEnrollment,group_datap->mOpenEnrollment);
1628	msg->addBOOLFast(_PREHASH_AllowPublish,group_datap->mAllowPublish);
1629	msg->addBOOLFast(_PREHASH_MaturePublish,group_datap->mMaturePublish);
1630
1631	gAgent.sendReliableMessage();
1632
1633	// Not expecting a response, so let anyone else watching know the data has changed.
1634	group_datap->mChanged = TRUE;
1635	notifyObservers(GC_PROPERTIES);
1636}
1637
1638void LLGroupMgr::sendGroupRoleMemberChanges(const LLUUID& group_id)
1639{
1640	lldebugs << "LLGroupMgr::sendGroupRoleMemberChanges" << llendl;
1641	LLGroupMgrGroupData* group_datap = createGroupData(group_id);
1642
1643	if (group_datap->mRoleMemberChanges.empty()) return;
1644
1645	LLMessageSystem* msg = gMessageSystem;
1646
1647	bool start_message = true;
1648	for (LLGroupMgrGroupData::change_map_t::const_iterator citer = group_datap->mRoleMemberChanges.begin();
1649		 citer != group_datap->mRoleMemberChanges.end(); ++citer)
1650	{
1651		if (start_message)
1652		{
1653			msg->newMessage("GroupRoleChanges");
1654			msg->nextBlockFast(_PREHASH_AgentData);
1655			msg->addUUIDFast(_PREHASH_AgentID,gAgent.getID());
1656			msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
1657			msg->addUUIDFast(_PREHASH_GroupID,group_id);
1658			start_message = false;
1659		}
1660		msg->nextBlock("RoleChange");
1661		msg->addUUID("RoleID",citer->second.mRole);
1662		msg->addUUID("MemberID",citer->second.mMember);
1663		msg->addU32("Change",(U32)citer->second.mChange);
1664
1665		if (msg->isSendFullFast())
1666		{
1667			gAgent.sendReliableMessage();
1668			start_message = true;
1669		}
1670	}
1671
1672	if (!start_message)
1673	{
1674		gAgent.sendReliableMessage();
1675	}
1676
1677	group_datap->mRoleMemberChanges.clear();
1678
1679	// Not expecting a response, so let anyone else watching know the data has changed.
1680	group_datap->mChanged = TRUE;
1681	notifyObservers(GC_ROLE_MEMBER_DATA);
1682}
1683
1684//static
1685void LLGroupMgr::sendGroupMemberJoin(const LLUUID& group_id)
1686{
1687	LLMessageSystem *msg = gMessageSystem;
1688
1689	msg->newMessageFast(_PREHASH_JoinGroupRequest);
1690	msg->nextBlockFast(_PREHASH_AgentData);
1691	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
1692	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1693	msg->nextBlockFast(_PREHASH_GroupData);
1694	msg->addUUIDFast(_PREHASH_GroupID, group_id);
1695
1696	gAgent.sendReliableMessage();
1697}
1698
1699// member_role_pairs is <member_id,role_id>
1700// static
1701void LLGroupMgr::sendGroupMemberInvites(const LLUUID& group_id, std::map<LLUUID,LLUUID>& member_role_pairs)
1702{
1703	bool start_message = true;
1704	LLMessageSystem* msg = gMessageSystem;
1705
1706	for (std::map<LLUUID,LLUUID>::iterator it = member_role_pairs.begin();
1707		 it != member_role_pairs.end(); ++it)
1708	{
1709		if (start_message)
1710		{
1711			msg->newMessage("InviteGroupRequest");
1712			msg->nextBlock("AgentData");
1713			msg->addUUID("AgentID",gAgent.getID());
1714			msg->addUUID("SessionID",gAgent.getSessionID());
1715			msg->nextBlock("GroupData");
1716			msg->addUUID("GroupID",group_id);
1717			start_message = false;
1718		}
1719
1720		msg->nextBlock("InviteData");
1721		msg->addUUID("InviteeID",(*it).first);
1722		msg->addUUID("RoleID",(*it).second);
1723
1724		if (msg->isSendFull())
1725		{
1726			gAgent.sendReliableMessage();
1727			start_message = true;
1728		}
1729	}
1730
1731	if (!start_message)
1732	{
1733		gAgent.sendReliableMessage();
1734	}
1735}
1736
1737//static
1738void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id,
1739									   uuid_vec_t& member_ids)
1740{
1741	bool start_message = true;
1742	LLMessageSystem* msg = gMessageSystem;
1743
1744	
1745
1746	LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
1747	if (!group_datap) return;
1748
1749	for (uuid_vec_t::iterator it = member_ids.begin();
1750		 it != member_ids.end(); ++it)
1751	{
1752		LLUUID& ejected_member_id = (*it);
1753
1754		// Can't use 'eject' to leave a group.
1755		if (ejected_member_id == gAgent.getID()) continue;
1756
1757		// Make sure they are in the group, and we need the member data
1758		LLGroupMgrGroupData::member_list_t::iterator mit = group_datap->mMembers.find(ejected_member_id);
1759		if (mit != group_datap->mMembers.end())
1760		{
1761			// Add them to the message
1762			if (start_message)
1763			{
1764				msg->newMessage("EjectGroupMemberRequest");
1765				msg->nextBlock("AgentData");
1766				msg->addUUID("AgentID",gAgent.getID());
1767				msg->addUUID("SessionID",gAgent.getSessionID());
1768				msg->nextBlock("GroupData");
1769				msg->addUUID("GroupID",group_id);
1770				start_message = false;
1771			}
1772			
1773			msg->nextBlock("EjectData");
1774			msg->addUUID("EjecteeID",ejected_member_id);
1775
1776			if (msg->isSendFull())
1777			{
1778				gAgent.sendReliableMessage();
1779				start_message = true;
1780			}
1781
1782			LLGroupMemberData* member_data = (*mit).second;
1783
1784			// Clean up groupmgr
1785			for (LLGroupMemberData::role_list_t::iterator rit = member_data->roleBegin();
1786				 rit != member_data->roleEnd(); ++rit)
1787			{
1788				if ((*rit).first.notNull() && (*rit).second!=0)
1789				{
1790					(*rit).second->removeMember(ejected_member_id);
1791				}
1792			}
1793			
1794			group_datap->mMembers.erase(ejected_member_id);
1795			
1796			// member_data was introduced and is used here instead of (*mit).second to avoid crash because of invalid iterator
1797			// It becomes invalid after line with erase above. EXT-4778
1798			delete member_data;
1799		}
1800	}
1801
1802	if (!start_message)
1803	{
1804		gAgent.sendReliableMessage();
1805	}
1806}
1807
1808void LLGroupMgr::sendGroupRoleChanges(const LLUUID& group_id)
1809{
1810	lldebugs << "LLGroupMgr::sendGroupRoleChanges" << llendl;
1811	LLGroupMgrGroupData* group_datap = getGroupData(group_id);
1812
1813	if (group_datap && group_datap->pendingRoleChanges())
1814	{
1815		group_datap->sendRoleChanges();
1816	
1817		// Not expecting a response, so let anyone else watching know the data has changed.
1818		group_datap->mChanged = TRUE;
1819		notifyObservers(GC_ROLE_DATA);
1820	}
1821}
1822
1823void LLGroupMgr::cancelGroupRoleChanges(const LLUUID& group_id)
1824{
1825	lldebugs << "LLGroupMgr::cancelGroupRoleChanges" << llendl;
1826	LLGroupMgrGroupData* group_datap = getGroupData(group_id);
1827
1828	if (group_datap) group_datap->cancelRoleChanges();
1829}
1830
1831//static
1832bool LLGroupMgr::parseRoleActions(const std::string& xml_filename)
1833{
1834	LLXMLNodePtr root;
1835
1836	BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);	
1837	
1838	if (!success || !root || !root->hasName( "role_actions" ))
1839	{
1840		llerrs << "Problem reading UI role_actions file: " << xml_filename << llendl;
1841		return f

Large files files are truncated, but you can click here to view the full file