PageRenderTime 83ms CodeModel.GetById 2ms app.highlight 73ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/newview/llcallingcard.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 904 lines | 689 code | 90 blank | 125 comment | 85 complexity | 6a9fbc1bac70948847a2a21a95981b46 MD5 | raw file
  1/** 
  2 * @file llcallingcard.cpp
  3 * @brief Implementation of the LLPreviewCallingCard class
  4 *
  5 * $LicenseInfo:firstyear=2002&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#include "llviewerprecompiledheaders.h"
 28
 29#if LL_WINDOWS
 30#pragma warning( disable : 4800 ) // performance warning in <functional>
 31#endif
 32
 33#include "llcallingcard.h"
 34
 35#include <vector>
 36#include <algorithm>
 37//#include <iterator>
 38
 39#include "indra_constants.h"
 40#include "llavatarnamecache.h"
 41#include "llcachename.h"
 42#include "llstl.h"
 43#include "lltimer.h"
 44#include "lluuid.h"
 45#include "message.h"
 46
 47#include "llagent.h"
 48#include "llavatarnamecache.h"
 49#include "llbutton.h"
 50#include "llinventoryobserver.h"
 51#include "llinventorymodel.h"
 52#include "llnotifications.h"
 53#include "llnotificationsutil.h"
 54#include "llresmgr.h"
 55#include "llslurl.h"
 56#include "llimview.h"
 57#include "llviewercontrol.h"
 58#include "llviewernetwork.h"
 59#include "llviewerobjectlist.h"
 60#include "llviewerwindow.h"
 61#include "llvoavatar.h"
 62#include "llavataractions.h"
 63
 64///----------------------------------------------------------------------------
 65/// Local function declarations, constants, enums, and typedefs
 66///----------------------------------------------------------------------------
 67
 68class LLTrackingData
 69{
 70public:
 71	LLTrackingData(const LLUUID& avatar_id, const std::string& name);
 72	bool haveTrackingInfo();
 73	void setTrackedCoarseLocation(const LLVector3d& global_pos);
 74	void agentFound(const LLUUID& prey,
 75					const LLVector3d& estimated_global_pos);
 76	
 77public:
 78	LLUUID mAvatarID;
 79	std::string mName;
 80	LLVector3d mGlobalPositionEstimate;
 81	bool mHaveInfo;
 82	bool mHaveCoarseInfo;
 83	LLTimer mCoarseLocationTimer;
 84	LLTimer mUpdateTimer;
 85	LLTimer mAgentGone;
 86};
 87
 88const F32 COARSE_FREQUENCY = 2.2f;
 89const F32 FIND_FREQUENCY = 29.7f;	// This results in a database query, so cut these back
 90const F32 OFFLINE_SECONDS = FIND_FREQUENCY + 8.0f;
 91
 92// static
 93LLAvatarTracker LLAvatarTracker::sInstance;
 94
 95static void on_avatar_name_cache_notify(const LLUUID& agent_id,
 96										const LLAvatarName& av_name,
 97										bool online,
 98										LLSD payload);
 99
100///----------------------------------------------------------------------------
101/// Class LLAvatarTracker
102///----------------------------------------------------------------------------
103
104LLAvatarTracker::LLAvatarTracker() :
105	mTrackingData(NULL),
106	mTrackedAgentValid(false),
107	//mInventory(NULL),
108	//mInventoryObserver(NULL),
109	mModifyMask(0x0)	
110{
111}
112
113LLAvatarTracker::~LLAvatarTracker()
114{
115	deleteTrackingData();
116	std::for_each(mObservers.begin(), mObservers.end(), DeletePointer());
117	std::for_each(mBuddyInfo.begin(), mBuddyInfo.end(), DeletePairedPointer());
118}
119
120void LLAvatarTracker::track(const LLUUID& avatar_id, const std::string& name)
121{
122	deleteTrackingData();
123	mTrackedAgentValid = false;
124	mTrackingData = new LLTrackingData(avatar_id, name);
125	findAgent();
126
127	// We track here because findAgent() is called on a timer (for now).
128	if(avatar_id.notNull())
129	{
130		LLMessageSystem* msg = gMessageSystem;
131		msg->newMessageFast(_PREHASH_TrackAgent);
132		msg->nextBlockFast(_PREHASH_AgentData);
133		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
134		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
135		msg->nextBlockFast(_PREHASH_TargetData);
136		msg->addUUIDFast(_PREHASH_PreyID, avatar_id);
137		gAgent.sendReliableMessage();
138	}
139}
140
141void LLAvatarTracker::untrack(const LLUUID& avatar_id)
142{
143	if (mTrackingData && mTrackingData->mAvatarID == avatar_id)
144	{
145		deleteTrackingData();
146		mTrackedAgentValid = false;
147		LLMessageSystem* msg = gMessageSystem;
148		msg->newMessageFast(_PREHASH_TrackAgent);
149		msg->nextBlockFast(_PREHASH_AgentData);
150		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
151		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
152		msg->nextBlockFast(_PREHASH_TargetData);
153		msg->addUUIDFast(_PREHASH_PreyID, LLUUID::null);
154		gAgent.sendReliableMessage();
155	}
156}
157
158void LLAvatarTracker::setTrackedCoarseLocation(const LLVector3d& global_pos)
159{
160	if(mTrackingData)
161	{
162		mTrackingData->setTrackedCoarseLocation(global_pos);
163	}
164}
165
166bool LLAvatarTracker::haveTrackingInfo()
167{
168	if(mTrackingData)
169	{
170		return mTrackingData->haveTrackingInfo();
171	}
172	return false;
173}
174
175LLVector3d LLAvatarTracker::getGlobalPos()
176{
177	if(!mTrackedAgentValid || !mTrackingData) return LLVector3d();
178	LLVector3d global_pos;
179	
180	LLViewerObject* object = gObjectList.findObject(mTrackingData->mAvatarID);
181	if(object && !object->isDead())
182	{
183		global_pos = object->getPositionGlobal();
184		// HACK - for making the tracker point above the avatar's head
185		// rather than its groin
186		global_pos.mdV[VZ] += 0.7f * ((LLVOAvatar *)object)->mBodySize.mV[VZ];
187
188		mTrackingData->mGlobalPositionEstimate = global_pos;
189	}
190	else
191	{
192		global_pos = mTrackingData->mGlobalPositionEstimate;
193	}
194
195	return global_pos;
196}
197
198void LLAvatarTracker::getDegreesAndDist(F32& rot,
199										F64& horiz_dist,
200										F64& vert_dist)
201{
202	if(!mTrackingData) return;
203
204	LLVector3d global_pos;
205
206	LLViewerObject* object = gObjectList.findObject(mTrackingData->mAvatarID);
207	if(object && !object->isDead())
208	{
209		global_pos = object->getPositionGlobal();
210		mTrackingData->mGlobalPositionEstimate = global_pos;
211	}
212	else
213	{
214		global_pos = mTrackingData->mGlobalPositionEstimate;
215	}
216	LLVector3d to_vec = global_pos - gAgent.getPositionGlobal();
217	horiz_dist = sqrt(to_vec.mdV[VX] * to_vec.mdV[VX] + to_vec.mdV[VY] * to_vec.mdV[VY]);
218	vert_dist = to_vec.mdV[VZ];
219	rot = F32(RAD_TO_DEG * atan2(to_vec.mdV[VY], to_vec.mdV[VX]));
220}
221
222const std::string& LLAvatarTracker::getName()
223{
224	if(mTrackingData)
225	{
226		return mTrackingData->mName;
227	}
228	else
229	{
230		return LLStringUtil::null;
231	}
232}
233
234const LLUUID& LLAvatarTracker::getAvatarID()
235{
236	if(mTrackingData)
237	{
238		return mTrackingData->mAvatarID;
239	}
240	else
241	{
242		return LLUUID::null;
243	}
244}
245
246S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds)
247{
248	using namespace std;
249
250	U32 new_buddy_count = 0;
251	std::string full_name;
252	LLUUID agent_id;
253	for(buddy_map_t::const_iterator itr = buds.begin(); itr != buds.end(); ++itr)
254	{
255		agent_id = (*itr).first;
256		buddy_map_t::const_iterator existing_buddy = mBuddyInfo.find(agent_id);
257		if(existing_buddy == mBuddyInfo.end())
258		{
259			++new_buddy_count;
260			mBuddyInfo[agent_id] = (*itr).second;
261			// IDEVO: is this necessary?  name is unused?
262			gCacheName->getFullName(agent_id, full_name);
263			addChangedMask(LLFriendObserver::ADD, agent_id);
264			lldebugs << "Added buddy " << agent_id
265					<< ", " << (mBuddyInfo[agent_id]->isOnline() ? "Online" : "Offline")
266					<< ", TO: " << mBuddyInfo[agent_id]->getRightsGrantedTo()
267					<< ", FROM: " << mBuddyInfo[agent_id]->getRightsGrantedFrom()
268					<< llendl;
269		}
270		else
271		{
272			LLRelationship* e_r = (*existing_buddy).second;
273			LLRelationship* n_r = (*itr).second;
274			llwarns << "!! Add buddy for existing buddy: " << agent_id
275					<< " [" << (e_r->isOnline() ? "Online" : "Offline") << "->" << (n_r->isOnline() ? "Online" : "Offline")
276					<< ", " <<  e_r->getRightsGrantedTo() << "->" << n_r->getRightsGrantedTo()
277					<< ", " <<  e_r->getRightsGrantedTo() << "->" << n_r->getRightsGrantedTo()
278					<< "]" << llendl;
279		}
280	}
281	notifyObservers();
282	
283	return new_buddy_count;
284}
285
286
287void LLAvatarTracker::copyBuddyList(buddy_map_t& buddies) const
288{
289	buddy_map_t::const_iterator it = mBuddyInfo.begin();
290	buddy_map_t::const_iterator end = mBuddyInfo.end();
291	for(; it != end; ++it)
292	{
293		buddies[(*it).first] = (*it).second;
294	}
295}
296
297void LLAvatarTracker::terminateBuddy(const LLUUID& id)
298{
299	lldebugs << "LLAvatarTracker::terminateBuddy()" << llendl;
300	LLRelationship* buddy = get_ptr_in_map(mBuddyInfo, id);
301	if(!buddy) return;
302	mBuddyInfo.erase(id);
303	LLMessageSystem* msg = gMessageSystem;
304	msg->newMessage("TerminateFriendship");
305	msg->nextBlock("AgentData");
306	msg->addUUID("AgentID", gAgent.getID());
307	msg->addUUID("SessionID", gAgent.getSessionID());
308	msg->nextBlock("ExBlock");
309	msg->addUUID("OtherID", id);
310	gAgent.sendReliableMessage();
311	 
312	addChangedMask(LLFriendObserver::REMOVE, id);
313	delete buddy;
314}
315
316// get all buddy info
317const LLRelationship* LLAvatarTracker::getBuddyInfo(const LLUUID& id) const
318{
319	if(id.isNull()) return NULL;
320	return get_ptr_in_map(mBuddyInfo, id);
321}
322
323bool LLAvatarTracker::isBuddy(const LLUUID& id) const
324{
325	LLRelationship* info = get_ptr_in_map(mBuddyInfo, id);
326	return (info != NULL);
327}
328
329// online status
330void LLAvatarTracker::setBuddyOnline(const LLUUID& id, bool is_online)
331{
332	LLRelationship* info = get_ptr_in_map(mBuddyInfo, id);
333	if(info)
334	{
335		info->online(is_online);
336		addChangedMask(LLFriendObserver::ONLINE, id);
337		lldebugs << "Set buddy " << id << (is_online ? " Online" : " Offline") << llendl;
338	}
339	else
340	{
341		llwarns << "!! No buddy info found for " << id 
342				<< ", setting to " << (is_online ? "Online" : "Offline") << llendl;
343	}
344}
345
346bool LLAvatarTracker::isBuddyOnline(const LLUUID& id) const
347{
348	LLRelationship* info = get_ptr_in_map(mBuddyInfo, id);
349	if(info)
350	{
351		return info->isOnline();
352	}
353	return false;
354}
355
356// empowered status
357void LLAvatarTracker::setBuddyEmpowered(const LLUUID& id, bool is_empowered)
358{
359	LLRelationship* info = get_ptr_in_map(mBuddyInfo, id);
360	if(info)
361	{
362		info->grantRights(LLRelationship::GRANT_MODIFY_OBJECTS, 0);
363		mModifyMask |= LLFriendObserver::POWERS;
364	}
365}
366
367bool LLAvatarTracker::isBuddyEmpowered(const LLUUID& id) const
368{
369	LLRelationship* info = get_ptr_in_map(mBuddyInfo, id);
370	if(info)
371	{
372		return info->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS);
373	}
374	return false;
375}
376
377void LLAvatarTracker::empower(const LLUUID& id, bool grant)
378{
379	// wrapper for ease of use in some situations.
380	buddy_map_t list;
381	/*
382	list.insert(id);
383	empowerList(list, grant);
384	*/
385}
386
387void LLAvatarTracker::empowerList(const buddy_map_t& list, bool grant)
388{
389	llwarns << "LLAvatarTracker::empowerList() not implemented." << llendl;
390/*
391	LLMessageSystem* msg = gMessageSystem;
392	const char* message_name;
393	const char* block_name;
394	const char* field_name;
395	if(grant)
396	{
397		message_name = _PREHASH_GrantModification;
398		block_name = _PREHASH_EmpoweredBlock;
399		field_name = _PREHASH_EmpoweredID;
400	}
401	else
402	{
403		message_name = _PREHASH_RevokeModification;
404		block_name = _PREHASH_RevokedBlock;
405		field_name = _PREHASH_RevokedID;
406	}
407
408	std::string name;
409	gAgent.buildFullnameAndTitle(name);
410
411	bool start_new_message = true;
412	buddy_list_t::const_iterator it = list.begin();
413	buddy_list_t::const_iterator end = list.end();
414	for(; it != end; ++it)
415	{
416		if(NULL == get_ptr_in_map(mBuddyInfo, (*it))) continue;
417		setBuddyEmpowered((*it), grant);
418		if(start_new_message)
419		{
420			start_new_message = false;
421			msg->newMessageFast(message_name);
422			msg->nextBlockFast(_PREHASH_AgentData);
423			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
424			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
425			msg->addStringFast(_PREHASH_GranterName, name);
426		}
427		msg->nextBlockFast(block_name);
428		msg->addUUIDFast(field_name, (*it));
429		if(msg->isSendFullFast(block_name))
430		{
431			start_new_message = true;
432			gAgent.sendReliableMessage();
433		}
434	}
435	if(!start_new_message)
436	{
437		gAgent.sendReliableMessage();
438	}
439*/
440}
441
442void LLAvatarTracker::deleteTrackingData()
443{
444	//make sure mTrackingData never points to freed memory
445	LLTrackingData* tmp = mTrackingData;
446	mTrackingData = NULL;
447	delete tmp;
448}
449
450void LLAvatarTracker::findAgent()
451{
452	if (!mTrackingData) return;
453	if (mTrackingData->mAvatarID.isNull()) return;
454	LLMessageSystem* msg = gMessageSystem;
455	msg->newMessageFast(_PREHASH_FindAgent); // Request
456	msg->nextBlockFast(_PREHASH_AgentBlock);
457	msg->addUUIDFast(_PREHASH_Hunter, gAgentID);
458	msg->addUUIDFast(_PREHASH_Prey, mTrackingData->mAvatarID);
459	msg->addU32Fast(_PREHASH_SpaceIP, 0); // will get filled in by simulator
460	msg->nextBlockFast(_PREHASH_LocationBlock);
461	const F64 NO_LOCATION = 0.0;
462	msg->addF64Fast(_PREHASH_GlobalX, NO_LOCATION);
463	msg->addF64Fast(_PREHASH_GlobalY, NO_LOCATION);
464	gAgent.sendReliableMessage();
465}
466
467void LLAvatarTracker::addObserver(LLFriendObserver* observer)
468{
469	if(observer)
470	{
471		mObservers.push_back(observer);
472	}
473}
474
475void LLAvatarTracker::removeObserver(LLFriendObserver* observer)
476{
477	mObservers.erase(
478		std::remove(mObservers.begin(), mObservers.end(), observer),
479		mObservers.end());
480}
481
482void LLAvatarTracker::notifyObservers()
483{
484	observer_list_t observers(mObservers);
485	observer_list_t::iterator it = observers.begin();
486	observer_list_t::iterator end = observers.end();
487	for(; it != end; ++it)
488	{
489		(*it)->changed(mModifyMask);
490	}
491
492	for (changed_buddy_t::iterator it = mChangedBuddyIDs.begin(); it != mChangedBuddyIDs.end(); it++)
493	{
494		notifyParticularFriendObservers(*it);
495	}
496
497	mModifyMask = LLFriendObserver::NONE;
498	mChangedBuddyIDs.clear();
499}
500
501void LLAvatarTracker::addParticularFriendObserver(const LLUUID& buddy_id, LLFriendObserver* observer)
502{
503	if (buddy_id.notNull() && observer)
504		mParticularFriendObserverMap[buddy_id].insert(observer);
505}
506
507void LLAvatarTracker::removeParticularFriendObserver(const LLUUID& buddy_id, LLFriendObserver* observer)
508{
509	if (buddy_id.isNull() || !observer)
510		return;
511
512    observer_map_t::iterator obs_it = mParticularFriendObserverMap.find(buddy_id);
513    if(obs_it == mParticularFriendObserverMap.end())
514        return;
515
516    obs_it->second.erase(observer);
517
518    // purge empty sets from the map
519    if (obs_it->second.size() == 0)
520    	mParticularFriendObserverMap.erase(obs_it);
521}
522
523void LLAvatarTracker::notifyParticularFriendObservers(const LLUUID& buddy_id)
524{
525    observer_map_t::iterator obs_it = mParticularFriendObserverMap.find(buddy_id);
526    if(obs_it == mParticularFriendObserverMap.end())
527        return;
528
529    // Notify observers interested in buddy_id.
530    observer_set_t& obs = obs_it->second;
531    for (observer_set_t::iterator ob_it = obs.begin(); ob_it != obs.end(); ob_it++)
532    {
533        (*ob_it)->changed(mModifyMask);
534    }
535}
536
537// store flag for change
538// and id of object change applies to
539void LLAvatarTracker::addChangedMask(U32 mask, const LLUUID& referent)
540{ 
541	mModifyMask |= mask; 
542	if (referent.notNull())
543	{
544		mChangedBuddyIDs.insert(referent);
545	}
546}
547
548void LLAvatarTracker::applyFunctor(LLRelationshipFunctor& f)
549{
550	buddy_map_t::iterator it = mBuddyInfo.begin();
551	buddy_map_t::iterator end = mBuddyInfo.end();
552	for(; it != end; ++it)
553	{
554		f((*it).first, (*it).second);
555	}
556}
557
558void LLAvatarTracker::registerCallbacks(LLMessageSystem* msg)
559{
560	msg->setHandlerFuncFast(_PREHASH_FindAgent, processAgentFound);
561	msg->setHandlerFuncFast(_PREHASH_OnlineNotification,
562						processOnlineNotification);
563	msg->setHandlerFuncFast(_PREHASH_OfflineNotification,
564						processOfflineNotification);
565	//msg->setHandlerFuncFast(_PREHASH_GrantedProxies,
566	//					processGrantedProxies);
567	msg->setHandlerFunc("TerminateFriendship", processTerminateFriendship);
568	msg->setHandlerFunc(_PREHASH_ChangeUserRights, processChangeUserRights);
569}
570
571// static
572void LLAvatarTracker::processAgentFound(LLMessageSystem* msg, void**)
573{
574	LLUUID id;
575
576	
577	msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_Hunter, id);
578	msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_Prey, id);
579	// *FIX: should make sure prey id matches.
580	LLVector3d estimated_global_pos;
581	msg->getF64Fast(_PREHASH_LocationBlock, _PREHASH_GlobalX,
582				 estimated_global_pos.mdV[VX]);
583	msg->getF64Fast(_PREHASH_LocationBlock, _PREHASH_GlobalY,
584				 estimated_global_pos.mdV[VY]);
585	LLAvatarTracker::instance().agentFound(id, estimated_global_pos);
586}
587
588void LLAvatarTracker::agentFound(const LLUUID& prey,
589								 const LLVector3d& estimated_global_pos)
590{
591	if(!mTrackingData) return;
592	//if we get a valid reply from the server, that means the agent
593	//is our friend and mappable, so enable interest list based updates
594	LLAvatarTracker::instance().setTrackedAgentValid(true);
595	mTrackingData->agentFound(prey, estimated_global_pos);
596}
597
598// 	static
599void LLAvatarTracker::processOnlineNotification(LLMessageSystem* msg, void**)
600{
601	lldebugs << "LLAvatarTracker::processOnlineNotification()" << llendl;
602	instance().processNotify(msg, true);
603}
604
605// 	static
606void LLAvatarTracker::processOfflineNotification(LLMessageSystem* msg, void**)
607{
608	lldebugs << "LLAvatarTracker::processOfflineNotification()" << llendl;
609	instance().processNotify(msg, false);
610}
611
612void LLAvatarTracker::processChange(LLMessageSystem* msg)
613{
614	S32 count = msg->getNumberOfBlocksFast(_PREHASH_Rights);
615	LLUUID agent_id, agent_related;
616	S32 new_rights;
617	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
618	for(int i = 0; i < count; ++i)
619	{
620		msg->getUUIDFast(_PREHASH_Rights, _PREHASH_AgentRelated, agent_related, i);
621		msg->getS32Fast(_PREHASH_Rights,_PREHASH_RelatedRights, new_rights, i);
622		if(agent_id == gAgent.getID())
623		{
624			if(mBuddyInfo.find(agent_related) != mBuddyInfo.end())
625			{
626				(mBuddyInfo[agent_related])->setRightsTo(new_rights);
627			}
628		}
629		else
630		{
631			if(mBuddyInfo.find(agent_id) != mBuddyInfo.end())
632			{
633				if((mBuddyInfo[agent_id]->getRightsGrantedFrom() ^  new_rights) & LLRelationship::GRANT_MODIFY_OBJECTS)
634				{
635					LLSD args;
636					args["NAME"] = LLSLURL("agent", agent_id, "displayname").getSLURLString();
637					
638					LLSD payload;
639					payload["from_id"] = agent_id;
640					if(LLRelationship::GRANT_MODIFY_OBJECTS & new_rights)
641					{
642						LLNotificationsUtil::add("GrantedModifyRights",args, payload);
643					}
644					else
645					{
646						LLNotificationsUtil::add("RevokedModifyRights",args, payload);
647					}
648				}
649				(mBuddyInfo[agent_id])->setRightsFrom(new_rights);
650			}
651		}
652	}
653
654	addChangedMask(LLFriendObserver::POWERS, agent_id);
655	notifyObservers();
656}
657
658void LLAvatarTracker::processChangeUserRights(LLMessageSystem* msg, void**)
659{
660	lldebugs << "LLAvatarTracker::processChangeUserRights()" << llendl;
661	instance().processChange(msg);
662}
663
664void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
665{
666	S32 count = msg->getNumberOfBlocksFast(_PREHASH_AgentBlock);
667	BOOL chat_notify = gSavedSettings.getBOOL("ChatOnlineNotification");
668
669	lldebugs << "Received " << count << " online notifications **** " << llendl;
670	if(count > 0)
671	{
672		LLUUID agent_id;
673		const LLRelationship* info = NULL;
674		LLUUID tracking_id;
675		if(mTrackingData)
676		{
677			tracking_id = mTrackingData->mAvatarID;
678		}
679		LLSD payload;
680		for(S32 i = 0; i < count; ++i)
681		{
682			msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_AgentID, agent_id, i);
683			payload["FROM_ID"] = agent_id;
684			info = getBuddyInfo(agent_id);
685			if(info)
686			{
687				setBuddyOnline(agent_id,online);
688			}
689			else
690			{
691				llwarns << "Received online notification for unknown buddy: " 
692					<< agent_id << " is " << (online ? "ONLINE" : "OFFLINE") << llendl;
693			}
694
695			if(tracking_id == agent_id)
696			{
697				// we were tracking someone who went offline
698				deleteTrackingData();
699			}
700			// *TODO: get actual inventory id
701			gInventory.addChangedMask(LLInventoryObserver::CALLING_CARD, LLUUID::null);
702		}
703		if(chat_notify)
704		{
705			// Look up the name of this agent for the notification
706			LLAvatarNameCache::get(agent_id,
707				boost::bind(&on_avatar_name_cache_notify,
708					_1, _2, online, payload));
709		}
710
711		mModifyMask |= LLFriendObserver::ONLINE;
712		instance().notifyObservers();
713		gInventory.notifyObservers();
714	}
715}
716
717static void on_avatar_name_cache_notify(const LLUUID& agent_id,
718										const LLAvatarName& av_name,
719										bool online,
720										LLSD payload)
721{
722	// Popup a notify box with online status of this agent
723	// Use display name only because this user is your friend
724	LLSD args;
725	args["NAME"] = av_name.mDisplayName;
726
727	LLNotificationPtr notification;
728	if (online)
729	{
730		notification =
731			LLNotificationsUtil::add("FriendOnline",
732									 args,
733									 payload.with("respond_on_mousedown", TRUE),
734									 boost::bind(&LLAvatarActions::startIM, agent_id));
735	}
736	else
737	{
738		notification =
739			LLNotificationsUtil::add("FriendOffline", args, payload);
740	}
741
742	// If there's an open IM session with this agent, send a notification there too.
743	LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, agent_id);
744	std::string notify_msg = notification->getMessage();
745	LLIMModel::instance().proccessOnlineOfflineNotification(session_id, notify_msg);
746}
747
748void LLAvatarTracker::formFriendship(const LLUUID& id)
749{
750	if(id.notNull())
751	{
752		LLRelationship* buddy_info = get_ptr_in_map(instance().mBuddyInfo, id);
753		if(!buddy_info)
754		{
755			LLAvatarTracker& at = LLAvatarTracker::instance();
756			//The default for relationship establishment is to have both parties
757			//visible online to each other.
758			buddy_info = new LLRelationship(LLRelationship::GRANT_ONLINE_STATUS,LLRelationship::GRANT_ONLINE_STATUS, false);
759			at.mBuddyInfo[id] = buddy_info;
760			at.addChangedMask(LLFriendObserver::ADD, id);
761			at.notifyObservers();
762		}
763	}
764}
765
766void LLAvatarTracker::processTerminateFriendship(LLMessageSystem* msg, void**)
767{
768	LLUUID id;
769	msg->getUUID("ExBlock", "OtherID", id);
770	if(id.notNull())
771	{
772		LLAvatarTracker& at = LLAvatarTracker::instance();
773		LLRelationship* buddy = get_ptr_in_map(at.mBuddyInfo, id);
774		if(!buddy) return;
775		at.mBuddyInfo.erase(id);
776		at.addChangedMask(LLFriendObserver::REMOVE, id);
777		delete buddy;
778		at.notifyObservers();
779	}
780}
781
782///----------------------------------------------------------------------------
783/// Tracking Data
784///----------------------------------------------------------------------------
785
786LLTrackingData::LLTrackingData(const LLUUID& avatar_id, const std::string& name)
787:	mAvatarID(avatar_id),
788	mHaveInfo(false),
789	mHaveCoarseInfo(false)
790{
791	mCoarseLocationTimer.setTimerExpirySec(COARSE_FREQUENCY);
792	mUpdateTimer.setTimerExpirySec(FIND_FREQUENCY);
793	mAgentGone.setTimerExpirySec(OFFLINE_SECONDS);
794	if(!name.empty())
795	{
796		mName = name;
797	}
798}
799
800void LLTrackingData::agentFound(const LLUUID& prey,
801								const LLVector3d& estimated_global_pos)
802{
803	if(prey != mAvatarID)
804	{
805		llwarns << "LLTrackingData::agentFound() - found " << prey
806				<< " but looking for " << mAvatarID << llendl;
807	}
808	mHaveInfo = true;
809	mAgentGone.setTimerExpirySec(OFFLINE_SECONDS);
810	mGlobalPositionEstimate = estimated_global_pos;
811}
812
813bool LLTrackingData::haveTrackingInfo()
814{
815	LLViewerObject* object = gObjectList.findObject(mAvatarID);
816	if(object && !object->isDead())
817	{
818		mCoarseLocationTimer.checkExpirationAndReset(COARSE_FREQUENCY);
819		mUpdateTimer.setTimerExpirySec(FIND_FREQUENCY);
820		mAgentGone.setTimerExpirySec(OFFLINE_SECONDS);
821		mHaveInfo = true;
822		return true;
823	}
824	if(mHaveCoarseInfo &&
825	   !mCoarseLocationTimer.checkExpirationAndReset(COARSE_FREQUENCY))
826	{
827		// if we reach here, then we have a 'recent' coarse update
828		mUpdateTimer.setTimerExpirySec(FIND_FREQUENCY);
829		mAgentGone.setTimerExpirySec(OFFLINE_SECONDS);
830		return true;
831	}
832	if(mUpdateTimer.checkExpirationAndReset(FIND_FREQUENCY))
833	{
834		LLAvatarTracker::instance().findAgent();
835		mHaveCoarseInfo = false;
836	}
837	if(mAgentGone.checkExpirationAndReset(OFFLINE_SECONDS))
838	{
839		mHaveInfo = false;
840		mHaveCoarseInfo = false;
841	}
842	return mHaveInfo;
843}
844
845void LLTrackingData::setTrackedCoarseLocation(const LLVector3d& global_pos)
846{
847	mCoarseLocationTimer.setTimerExpirySec(COARSE_FREQUENCY);
848	mGlobalPositionEstimate = global_pos;
849	mHaveInfo = true;
850	mHaveCoarseInfo = true;
851}
852
853///----------------------------------------------------------------------------
854// various buddy functors
855///----------------------------------------------------------------------------
856
857bool LLCollectProxyBuddies::operator()(const LLUUID& buddy_id, LLRelationship* buddy)
858{
859	if(buddy->isRightGrantedFrom(LLRelationship::GRANT_MODIFY_OBJECTS))
860	{
861		mProxy.insert(buddy_id);
862	}
863	return true;
864}
865
866bool LLCollectMappableBuddies::operator()(const LLUUID& buddy_id, LLRelationship* buddy)
867{
868	LLAvatarName av_name;
869	LLAvatarNameCache::get( buddy_id, &av_name);
870	buddy_map_t::value_type value(av_name.mDisplayName, buddy_id);
871	if(buddy->isOnline() && buddy->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION))
872	{
873		mMappable.insert(value);
874	}
875	return true;
876}
877
878bool LLCollectOnlineBuddies::operator()(const LLUUID& buddy_id, LLRelationship* buddy)
879{
880	gCacheName->getFullName(buddy_id, mFullName);
881	buddy_map_t::value_type value(mFullName, buddy_id);
882	if(buddy->isOnline())
883	{
884		mOnline.insert(value);
885	}
886	return true;
887}
888
889bool LLCollectAllBuddies::operator()(const LLUUID& buddy_id, LLRelationship* buddy)
890{
891	LLAvatarName av_name;
892	LLAvatarNameCache::get(buddy_id, &av_name);
893	mFullName = av_name.mDisplayName;
894	buddy_map_t::value_type value(mFullName, buddy_id);
895	if(buddy->isOnline())
896	{
897		mOnline.insert(value);
898	}
899	else
900	{
901		mOffline.insert(value);
902	}
903	return true;
904}