/*
* Copyright (c) 2006-2014, openmetaverse.org
* All rights reserved.
*
* - Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Neither the name of the openmetaverse.org nor the names
* of its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Text;
using System.Collections.Generic;
using OpenMetaverse.Packets;
namespace OpenMetaverse
{
///
///
///
[Flags]
public enum FriendRights : int
{
/// The avatar has no rights
None = 0,
/// The avatar can see the online status of the target avatar
CanSeeOnline = 1,
/// The avatar can see the location of the target avatar on the map
CanSeeOnMap = 2,
/// The avatar can modify the ojects of the target avatar
CanModifyObjects = 4
}
///
/// This class holds information about an avatar in the friends list. There are two ways
/// to interface to this class. The first is through the set of boolean properties. This is the typical
/// way clients of this class will use it. The second interface is through two bitflag properties,
/// TheirFriendsRights and MyFriendsRights
///
public class FriendInfo
{
private UUID m_id;
private string m_name;
private bool m_isOnline;
private bool m_canSeeMeOnline;
private bool m_canSeeMeOnMap;
private bool m_canModifyMyObjects;
private bool m_canSeeThemOnline;
private bool m_canSeeThemOnMap;
private bool m_canModifyTheirObjects;
#region Properties
///
/// System ID of the avatar
///
public UUID UUID { get { return m_id; } }
///
/// full name of the avatar
///
public string Name
{
get { return m_name; }
set { m_name = value; }
}
///
/// True if the avatar is online
///
public bool IsOnline
{
get { return m_isOnline; }
set { m_isOnline = value; }
}
///
/// True if the friend can see if I am online
///
public bool CanSeeMeOnline
{
get { return m_canSeeMeOnline; }
set
{
m_canSeeMeOnline = value;
// if I can't see them online, then I can't see them on the map
if (!m_canSeeMeOnline)
m_canSeeMeOnMap = false;
}
}
///
/// True if the friend can see me on the map
///
public bool CanSeeMeOnMap
{
get { return m_canSeeMeOnMap; }
set
{
// if I can't see them online, then I can't see them on the map
if (m_canSeeMeOnline)
m_canSeeMeOnMap = value;
}
}
///
/// True if the freind can modify my objects
///
public bool CanModifyMyObjects
{
get { return m_canModifyMyObjects; }
set { m_canModifyMyObjects = value; }
}
///
/// True if I can see if my friend is online
///
public bool CanSeeThemOnline { get { return m_canSeeThemOnline; } }
///
/// True if I can see if my friend is on the map
///
public bool CanSeeThemOnMap { get { return m_canSeeThemOnMap; } }
///
/// True if I can modify my friend's objects
///
public bool CanModifyTheirObjects { get { return m_canModifyTheirObjects; } }
///
/// My friend's rights represented as bitmapped flags
///
public FriendRights TheirFriendRights
{
get
{
FriendRights results = FriendRights.None;
if (m_canSeeMeOnline)
results |= FriendRights.CanSeeOnline;
if (m_canSeeMeOnMap)
results |= FriendRights.CanSeeOnMap;
if (m_canModifyMyObjects)
results |= FriendRights.CanModifyObjects;
return results;
}
set
{
m_canSeeMeOnline = (value & FriendRights.CanSeeOnline) != 0;
m_canSeeMeOnMap = (value & FriendRights.CanSeeOnMap) != 0;
m_canModifyMyObjects = (value & FriendRights.CanModifyObjects) != 0;
}
}
///
/// My rights represented as bitmapped flags
///
public FriendRights MyFriendRights
{
get
{
FriendRights results = FriendRights.None;
if (m_canSeeThemOnline)
results |= FriendRights.CanSeeOnline;
if (m_canSeeThemOnMap)
results |= FriendRights.CanSeeOnMap;
if (m_canModifyTheirObjects)
results |= FriendRights.CanModifyObjects;
return results;
}
set
{
m_canSeeThemOnline = (value & FriendRights.CanSeeOnline) != 0;
m_canSeeThemOnMap = (value & FriendRights.CanSeeOnMap) != 0;
m_canModifyTheirObjects = (value & FriendRights.CanModifyObjects) != 0;
}
}
#endregion Properties
///
/// Used internally when building the initial list of friends at login time
///
/// System ID of the avatar being prepesented
/// Rights the friend has to see you online and to modify your objects
/// Rights you have to see your friend online and to modify their objects
internal FriendInfo(UUID id, FriendRights theirRights, FriendRights myRights)
{
m_id = id;
m_canSeeMeOnline = (theirRights & FriendRights.CanSeeOnline) != 0;
m_canSeeMeOnMap = (theirRights & FriendRights.CanSeeOnMap) != 0;
m_canModifyMyObjects = (theirRights & FriendRights.CanModifyObjects) != 0;
m_canSeeThemOnline = (myRights & FriendRights.CanSeeOnline) != 0;
m_canSeeThemOnMap = (myRights & FriendRights.CanSeeOnMap) != 0;
m_canModifyTheirObjects = (myRights & FriendRights.CanModifyObjects) != 0;
}
///
/// FriendInfo represented as a string
///
/// A string reprentation of both my rights and my friends rights
public override string ToString()
{
if (!String.IsNullOrEmpty(m_name))
return String.Format("{0} (Their Rights: {1}, My Rights: {2})", m_name, TheirFriendRights,
MyFriendRights);
else
return String.Format("{0} (Their Rights: {1}, My Rights: {2})", m_id, TheirFriendRights,
MyFriendRights);
}
}
///
/// This class is used to add and remove avatars from your friends list and to manage their permission.
///
public class FriendsManager
{
#region Delegates
/// The event subscribers. null if no subcribers
private EventHandler m_FriendOnline;
/// Raises the FriendOnline event
/// A FriendInfoEventArgs object containing the
/// data returned from the data server
protected virtual void OnFriendOnline(FriendInfoEventArgs e)
{
EventHandler handler = m_FriendOnline;
if (handler != null)
handler(this, e);
}
/// Thread sync lock object
private readonly object m_FriendOnlineLock = new object();
/// Raised when the simulator sends notification one of the members in our friends list comes online
public event EventHandler FriendOnline
{
add { lock (m_FriendOnlineLock) { m_FriendOnline += value; } }
remove { lock (m_FriendOnlineLock) { m_FriendOnline -= value; } }
}
/// The event subscribers. null if no subcribers
private EventHandler m_FriendOffline;
/// Raises the FriendOffline event
/// A FriendInfoEventArgs object containing the
/// data returned from the data server
protected virtual void OnFriendOffline(FriendInfoEventArgs e)
{
EventHandler handler = m_FriendOffline;
if (handler != null)
handler(this, e);
}
/// Thread sync lock object
private readonly object m_FriendOfflineLock = new object();
/// Raised when the simulator sends notification one of the members in our friends list goes offline
public event EventHandler FriendOffline
{
add { lock (m_FriendOfflineLock) { m_FriendOffline += value; } }
remove { lock (m_FriendOfflineLock) { m_FriendOffline -= value; } }
}
/// The event subscribers. null if no subcribers
private EventHandler m_FriendRights;
/// Raises the FriendRightsUpdate event
/// A FriendInfoEventArgs object containing the
/// data returned from the data server
protected virtual void OnFriendRights(FriendInfoEventArgs e)
{
EventHandler handler = m_FriendRights;
if (handler != null)
handler(this, e);
}
/// Thread sync lock object
private readonly object m_FriendRightsLock = new object();
/// Raised when the simulator sends notification one of the members in our friends list grants or revokes permissions
public event EventHandler FriendRightsUpdate
{
add { lock (m_FriendRightsLock) { m_FriendRights += value; } }
remove { lock (m_FriendRightsLock) { m_FriendRights -= value; } }
}
/// The event subscribers. null if no subcribers
private EventHandler m_FriendNames;
/// Raises the FriendNames event
/// A FriendNamesEventArgs object containing the
/// data returned from the data server
protected virtual void OnFriendNames(FriendNamesEventArgs e)
{
EventHandler handler = m_FriendNames;
if (handler != null)
handler(this, e);
}
/// Thread sync lock object
private readonly object m_FriendNamesLock = new object();
/// Raised when the simulator sends us the names on our friends list
public event EventHandler FriendNames
{
add { lock (m_FriendNamesLock) { m_FriendNames += value; } }
remove { lock (m_FriendNamesLock) { m_FriendNames -= value; } }
}
/// The event subscribers. null if no subcribers
private EventHandler m_FriendshipOffered;
/// Raises the FriendshipOffered event
/// A FriendshipOfferedEventArgs object containing the
/// data returned from the data server
protected virtual void OnFriendshipOffered(FriendshipOfferedEventArgs e)
{
EventHandler handler = m_FriendshipOffered;
if (handler != null)
handler(this, e);
}
/// Thread sync lock object
private readonly object m_FriendshipOfferedLock = new object();
/// Raised when the simulator sends notification another agent is offering us friendship
public event EventHandler FriendshipOffered
{
add { lock (m_FriendshipOfferedLock) { m_FriendshipOffered += value; } }
remove { lock (m_FriendshipOfferedLock) { m_FriendshipOffered -= value; } }
}
/// The event subscribers. null if no subcribers
private EventHandler m_FriendshipResponse;
/// Raises the FriendshipResponse event
/// A FriendshipResponseEventArgs object containing the
/// data returned from the data server
protected virtual void OnFriendshipResponse(FriendshipResponseEventArgs e)
{
EventHandler handler = m_FriendshipResponse;
if (handler != null)
handler(this, e);
}
/// Thread sync lock object
private readonly object m_FriendshipResponseLock = new object();
/// Raised when a request we sent to friend another agent is accepted or declined
public event EventHandler FriendshipResponse
{
add { lock (m_FriendshipResponseLock) { m_FriendshipResponse += value; } }
remove { lock (m_FriendshipResponseLock) { m_FriendshipResponse -= value; } }
}
/// The event subscribers. null if no subcribers
private EventHandler m_FriendshipTerminated;
/// Raises the FriendshipTerminated event
/// A FriendshipTerminatedEventArgs object containing the
/// data returned from the data server
protected virtual void OnFriendshipTerminated(FriendshipTerminatedEventArgs e)
{
EventHandler handler = m_FriendshipTerminated;
if (handler != null)
handler(this, e);
}
/// Thread sync lock object
private readonly object m_FriendshipTerminatedLock = new object();
/// Raised when the simulator sends notification one of the members in our friends list has terminated
/// our friendship
public event EventHandler FriendshipTerminated
{
add { lock (m_FriendshipTerminatedLock) { m_FriendshipTerminated += value; } }
remove { lock (m_FriendshipTerminatedLock) { m_FriendshipTerminated -= value; } }
}
/// The event subscribers. null if no subcribers
private EventHandler m_FriendFound;
/// Raises the FriendFoundReply event
/// A FriendFoundReplyEventArgs object containing the
/// data returned from the data server
protected virtual void OnFriendFoundReply(FriendFoundReplyEventArgs e)
{
EventHandler handler = m_FriendFound;
if (handler != null)
handler(this, e);
}
/// Thread sync lock object
private readonly object m_FriendFoundLock = new object();
/// Raised when the simulator sends the location of a friend we have
/// requested map location info for
public event EventHandler FriendFoundReply
{
add { lock (m_FriendFoundLock) { m_FriendFound += value; } }
remove { lock (m_FriendFoundLock) { m_FriendFound -= value; } }
}
#endregion Delegates
#region Events
#endregion Events
private GridClient Client;
///
/// A dictionary of key/value pairs containing known friends of this avatar.
///
/// The Key is the of the friend, the value is a
/// object that contains detailed information including permissions you have and have given to the friend
///
public InternalDictionary FriendList = new InternalDictionary();
///
/// A Dictionary of key/value pairs containing current pending frienship offers.
///
/// The key is the of the avatar making the request,
/// the value is the of the request which is used to accept
/// or decline the friendship offer
///
public InternalDictionary FriendRequests = new InternalDictionary();
///
/// Internal constructor
///
/// A reference to the GridClient Object
internal FriendsManager(GridClient client)
{
Client = client;
Client.Network.LoginProgress += Network_OnConnect;
Client.Avatars.UUIDNameReply += new EventHandler(Avatars_OnAvatarNames);
Client.Self.IM += Self_IM;
Client.Network.RegisterCallback(PacketType.OnlineNotification, OnlineNotificationHandler);
Client.Network.RegisterCallback(PacketType.OfflineNotification, OfflineNotificationHandler);
Client.Network.RegisterCallback(PacketType.ChangeUserRights, ChangeUserRightsHandler);
Client.Network.RegisterCallback(PacketType.TerminateFriendship, TerminateFriendshipHandler);
Client.Network.RegisterCallback(PacketType.FindAgent, OnFindAgentReplyHandler);
Client.Network.RegisterLoginResponseCallback(new NetworkManager.LoginResponseCallback(Network_OnLoginResponse),
new string[] { "buddy-list" });
}
#region Public Methods
///
/// Accept a friendship request
///
/// agentID of avatatar to form friendship with
/// imSessionID of the friendship request message
public void AcceptFriendship(UUID fromAgentID, UUID imSessionID)
{
UUID callingCardFolder = Client.Inventory.FindFolderForType(AssetType.CallingCard);
AcceptFriendshipPacket request = new AcceptFriendshipPacket();
request.AgentData.AgentID = Client.Self.AgentID;
request.AgentData.SessionID = Client.Self.SessionID;
request.TransactionBlock.TransactionID = imSessionID;
request.FolderData = new AcceptFriendshipPacket.FolderDataBlock[1];
request.FolderData[0] = new AcceptFriendshipPacket.FolderDataBlock();
request.FolderData[0].FolderID = callingCardFolder;
Client.Network.SendPacket(request);
FriendInfo friend = new FriendInfo(fromAgentID, FriendRights.CanSeeOnline,
FriendRights.CanSeeOnline);
if (!FriendList.ContainsKey(fromAgentID))
FriendList.Add(friend.UUID, friend);
if (FriendRequests.ContainsKey(fromAgentID))
FriendRequests.Remove(fromAgentID);
Client.Avatars.RequestAvatarName(fromAgentID);
}
///
/// Decline a friendship request
///
/// of friend
/// imSessionID of the friendship request message
public void DeclineFriendship(UUID fromAgentID, UUID imSessionID)
{
DeclineFriendshipPacket request = new DeclineFriendshipPacket();
request.AgentData.AgentID = Client.Self.AgentID;
request.AgentData.SessionID = Client.Self.SessionID;
request.TransactionBlock.TransactionID = imSessionID;
Client.Network.SendPacket(request);
if (FriendRequests.ContainsKey(fromAgentID))
FriendRequests.Remove(fromAgentID);
}
///
/// Overload: Offer friendship to an avatar.
///
/// System ID of the avatar you are offering friendship to
public void OfferFriendship(UUID agentID)
{
OfferFriendship(agentID, "Do ya wanna be my buddy?");
}
///
/// Offer friendship to an avatar.
///
/// System ID of the avatar you are offering friendship to
/// A message to send with the request
public void OfferFriendship(UUID agentID, string message)
{
Client.Self.InstantMessage(Client.Self.Name,
agentID,
message,
UUID.Random(),
InstantMessageDialog.FriendshipOffered,
InstantMessageOnline.Offline,
Client.Self.SimPosition,
Client.Network.CurrentSim.ID,
null);
}
///
/// Terminate a friendship with an avatar
///
/// System ID of the avatar you are terminating the friendship with
public void TerminateFriendship(UUID agentID)
{
if (FriendList.ContainsKey(agentID))
{
TerminateFriendshipPacket request = new TerminateFriendshipPacket();
request.AgentData.AgentID = Client.Self.AgentID;
request.AgentData.SessionID = Client.Self.SessionID;
request.ExBlock.OtherID = agentID;
Client.Network.SendPacket(request);
if (FriendList.ContainsKey(agentID))
FriendList.Remove(agentID);
}
}
/// Process an incoming packet and raise the appropriate events
/// The sender
/// The EventArgs object containing the packet data
private void TerminateFriendshipHandler(object sender, PacketReceivedEventArgs e)
{
Packet packet = e.Packet;
TerminateFriendshipPacket itsOver = (TerminateFriendshipPacket)packet;
string name = String.Empty;
if (FriendList.ContainsKey(itsOver.ExBlock.OtherID))
{
name = FriendList[itsOver.ExBlock.OtherID].Name;
FriendList.Remove(itsOver.ExBlock.OtherID);
}
if (m_FriendshipTerminated != null)
{
OnFriendshipTerminated(new FriendshipTerminatedEventArgs(itsOver.ExBlock.OtherID, name));
}
}
///
/// Change the rights of a friend avatar.
///
/// the of the friend
/// the new rights to give the friend
/// This method will implicitly set the rights to those passed in the rights parameter.
public void GrantRights(UUID friendID, FriendRights rights)
{
GrantUserRightsPacket request = new GrantUserRightsPacket();
request.AgentData.AgentID = Client.Self.AgentID;
request.AgentData.SessionID = Client.Self.SessionID;
request.Rights = new GrantUserRightsPacket.RightsBlock[1];
request.Rights[0] = new GrantUserRightsPacket.RightsBlock();
request.Rights[0].AgentRelated = friendID;
request.Rights[0].RelatedRights = (int)rights;
Client.Network.SendPacket(request);
}
///
/// Use to map a friends location on the grid.
///
/// Friends UUID to find
///
public void MapFriend(UUID friendID)
{
FindAgentPacket stalk = new FindAgentPacket();
stalk.AgentBlock.Hunter = Client.Self.AgentID;
stalk.AgentBlock.Prey = friendID;
stalk.AgentBlock.SpaceIP = 0; // Will be filled in by the simulator
stalk.LocationBlock = new FindAgentPacket.LocationBlockBlock[1];
stalk.LocationBlock[0] = new FindAgentPacket.LocationBlockBlock();
stalk.LocationBlock[0].GlobalX = 0.0; // Filled in by the simulator
stalk.LocationBlock[0].GlobalY = 0.0;
Client.Network.SendPacket(stalk);
}
///
/// Use to track a friends movement on the grid
///
/// Friends Key
public void TrackFriend(UUID friendID)
{
TrackAgentPacket stalk = new TrackAgentPacket();
stalk.AgentData.AgentID = Client.Self.AgentID;
stalk.AgentData.SessionID = Client.Self.SessionID;
stalk.TargetData.PreyID = friendID;
Client.Network.SendPacket(stalk);
}
///
/// Ask for a notification of friend's online status
///
/// Friend's UUID
public void RequestOnlineNotification(UUID friendID)
{
GenericMessagePacket gmp = new GenericMessagePacket();
gmp.AgentData.AgentID = Client.Self.AgentID;
gmp.AgentData.SessionID = Client.Self.SessionID;
gmp.AgentData.TransactionID = UUID.Zero;
gmp.MethodData.Method = Utils.StringToBytes("requestonlinenotification");
gmp.MethodData.Invoice = UUID.Zero;
gmp.ParamList = new GenericMessagePacket.ParamListBlock[1];
gmp.ParamList[0] = new GenericMessagePacket.ParamListBlock();
gmp.ParamList[0].Parameter = Utils.StringToBytes(friendID.ToString());
Client.Network.SendPacket(gmp);
}
#endregion
#region Internal events
private void Network_OnConnect(object sender, LoginProgressEventArgs e)
{
if (e.Status != LoginStatus.Success)
{
return;
}
List names = new List();
if (FriendList.Count > 0)
{
FriendList.ForEach(
delegate(KeyValuePair kvp)
{
if (String.IsNullOrEmpty(kvp.Value.Name))
names.Add(kvp.Key);
}
);
Client.Avatars.RequestAvatarNames(names);
}
}
///
/// This handles the asynchronous response of a RequestAvatarNames call.
///
///
/// names cooresponding to the the list of IDs sent the the RequestAvatarNames call.
private void Avatars_OnAvatarNames(object sender, UUIDNameReplyEventArgs e)
{
Dictionary newNames = new Dictionary();
foreach (KeyValuePair kvp in e.Names)
{
FriendInfo friend;
lock (FriendList.Dictionary)
{
if (FriendList.TryGetValue(kvp.Key, out friend))
{
if (friend.Name == null)
newNames.Add(kvp.Key, e.Names[kvp.Key]);
friend.Name = e.Names[kvp.Key];
FriendList[kvp.Key] = friend;
}
}
}
if (newNames.Count > 0 && m_FriendNames != null)
{
OnFriendNames(new FriendNamesEventArgs(newNames));
}
}
#endregion
#region Packet Handlers
/// Process an incoming packet and raise the appropriate events
/// The sender
/// The EventArgs object containing the packet data
protected void OnlineNotificationHandler(object sender, PacketReceivedEventArgs e)
{
Packet packet = e.Packet;
if (packet.Type == PacketType.OnlineNotification)
{
OnlineNotificationPacket notification = ((OnlineNotificationPacket)packet);
foreach (OnlineNotificationPacket.AgentBlockBlock block in notification.AgentBlock)
{
FriendInfo friend;
lock (FriendList.Dictionary)
{
if (!FriendList.ContainsKey(block.AgentID))
{
friend = new FriendInfo(block.AgentID, FriendRights.CanSeeOnline,
FriendRights.CanSeeOnline);
FriendList.Add(block.AgentID, friend);
}
else
{
friend = FriendList[block.AgentID];
}
}
bool doNotify = !friend.IsOnline;
friend.IsOnline = true;
if (m_FriendOnline != null && doNotify)
{
OnFriendOnline(new FriendInfoEventArgs(friend));
}
}
}
}
/// Process an incoming packet and raise the appropriate events
/// The sender
/// The EventArgs object containing the packet data
protected void OfflineNotificationHandler(object sender, PacketReceivedEventArgs e)
{
Packet packet = e.Packet;
if (packet.Type == PacketType.OfflineNotification)
{
OfflineNotificationPacket notification = (OfflineNotificationPacket)packet;
foreach (OfflineNotificationPacket.AgentBlockBlock block in notification.AgentBlock)
{
FriendInfo friend = new FriendInfo(block.AgentID, FriendRights.CanSeeOnline, FriendRights.CanSeeOnline);
lock (FriendList.Dictionary)
{
if (!FriendList.Dictionary.ContainsKey(block.AgentID))
FriendList.Dictionary[block.AgentID] = friend;
friend = FriendList.Dictionary[block.AgentID];
}
friend.IsOnline = false;
if (m_FriendOffline != null)
{
OnFriendOffline(new FriendInfoEventArgs(friend));
}
}
}
}
/// Process an incoming packet and raise the appropriate events
/// The sender
/// The EventArgs object containing the packet data
private void ChangeUserRightsHandler(object sender, PacketReceivedEventArgs e)
{
Packet packet = e.Packet;
if (packet.Type == PacketType.ChangeUserRights)
{
FriendInfo friend;
ChangeUserRightsPacket rights = (ChangeUserRightsPacket)packet;
foreach (ChangeUserRightsPacket.RightsBlock block in rights.Rights)
{
FriendRights newRights = (FriendRights)block.RelatedRights;
if (FriendList.TryGetValue(block.AgentRelated, out friend))
{
friend.TheirFriendRights = newRights;
if (m_FriendRights != null)
{
OnFriendRights(new FriendInfoEventArgs(friend));
}
}
else if (block.AgentRelated == Client.Self.AgentID)
{
if (FriendList.TryGetValue(rights.AgentData.AgentID, out friend))
{
friend.MyFriendRights = newRights;
if (m_FriendRights != null)
{
OnFriendRights(new FriendInfoEventArgs(friend));
}
}
}
}
}
}
/// Process an incoming packet and raise the appropriate events
/// The sender
/// The EventArgs object containing the packet data
public void OnFindAgentReplyHandler(object sender, PacketReceivedEventArgs e)
{
if (m_FriendFound != null)
{
Packet packet = e.Packet;
FindAgentPacket reply = (FindAgentPacket)packet;
float x, y;
UUID prey = reply.AgentBlock.Prey;
ulong regionHandle = Helpers.GlobalPosToRegionHandle((float)reply.LocationBlock[0].GlobalX,
(float)reply.LocationBlock[0].GlobalY, out x, out y);
Vector3 xyz = new Vector3(x, y, 0f);
OnFriendFoundReply(new FriendFoundReplyEventArgs(prey, regionHandle, xyz));
}
}
#endregion
private void Self_IM(object sender, InstantMessageEventArgs e)
{
if (e.IM.Dialog == InstantMessageDialog.FriendshipOffered)
{
if (m_FriendshipOffered != null)
{
if (FriendRequests.ContainsKey(e.IM.FromAgentID))
FriendRequests[e.IM.FromAgentID] = e.IM.IMSessionID;
else
FriendRequests.Add(e.IM.FromAgentID, e.IM.IMSessionID);
OnFriendshipOffered(new FriendshipOfferedEventArgs(e.IM.FromAgentID, e.IM.FromAgentName, e.IM.IMSessionID));
}
}
else if (e.IM.Dialog == InstantMessageDialog.FriendshipAccepted)
{
FriendInfo friend = new FriendInfo(e.IM.FromAgentID, FriendRights.CanSeeOnline,
FriendRights.CanSeeOnline);
friend.Name = e.IM.FromAgentName;
lock (FriendList.Dictionary) FriendList[friend.UUID] = friend;
if (m_FriendshipResponse != null)
{
OnFriendshipResponse(new FriendshipResponseEventArgs(e.IM.FromAgentID, e.IM.FromAgentName, true));
}
RequestOnlineNotification(e.IM.FromAgentID);
}
else if (e.IM.Dialog == InstantMessageDialog.FriendshipDeclined)
{
if (m_FriendshipResponse != null)
{
OnFriendshipResponse(new FriendshipResponseEventArgs(e.IM.FromAgentID, e.IM.FromAgentName, false));
}
}
}
///
/// Populate FriendList with data from the login reply
///
/// true if login was successful
/// true if login request is requiring a redirect
/// A string containing the response to the login request
/// A string containing the reason for the request
/// A object containing the decoded
/// reply from the login server
private void Network_OnLoginResponse(bool loginSuccess, bool redirect, string message, string reason,
LoginResponseData replyData)
{
int uuidLength = UUID.Zero.ToString().Length;
if (loginSuccess && replyData.BuddyList != null)
{
foreach (BuddyListEntry buddy in replyData.BuddyList)
{
UUID bubid;
string id = buddy.buddy_id.Length > uuidLength ? buddy.buddy_id.Substring(0, uuidLength) : buddy.buddy_id;
if (UUID.TryParse(id, out bubid))
{
lock (FriendList.Dictionary)
{
if (!FriendList.ContainsKey(bubid))
{
FriendList[bubid] = new FriendInfo(bubid,
(FriendRights)buddy.buddy_rights_given,
(FriendRights)buddy.buddy_rights_has);
}
}
}
}
}
}
}
#region EventArgs
/// Contains information on a member of our friends list
public class FriendInfoEventArgs : EventArgs
{
private readonly FriendInfo m_Friend;
/// Get the FriendInfo
public FriendInfo Friend { get { return m_Friend; } }
///
/// Construct a new instance of the FriendInfoEventArgs class
///
/// The FriendInfo
public FriendInfoEventArgs(FriendInfo friend)
{
this.m_Friend = friend;
}
}
/// Contains Friend Names
public class FriendNamesEventArgs : EventArgs
{
private readonly Dictionary m_Names;
/// A dictionary where the Key is the ID of the Agent,
/// and the Value is a string containing their name
public Dictionary Names { get { return m_Names; } }
///
/// Construct a new instance of the FriendNamesEventArgs class
///
/// A dictionary where the Key is the ID of the Agent,
/// and the Value is a string containing their name
public FriendNamesEventArgs(Dictionary names)
{
this.m_Names = names;
}
}
/// Sent when another agent requests a friendship with our agent
public class FriendshipOfferedEventArgs : EventArgs
{
private readonly UUID m_AgentID;
private readonly string m_AgentName;
private readonly UUID m_SessionID;
/// Get the ID of the agent requesting friendship
public UUID AgentID { get { return m_AgentID; } }
/// Get the name of the agent requesting friendship
public string AgentName { get { return m_AgentName; } }
/// Get the ID of the session, used in accepting or declining the
/// friendship offer
public UUID SessionID { get { return m_SessionID; } }
///
/// Construct a new instance of the FriendshipOfferedEventArgs class
///
/// The ID of the agent requesting friendship
/// The name of the agent requesting friendship
/// The ID of the session, used in accepting or declining the
/// friendship offer
public FriendshipOfferedEventArgs(UUID agentID, string agentName, UUID imSessionID)
{
this.m_AgentID = agentID;
this.m_AgentName = agentName;
this.m_SessionID = imSessionID;
}
}
/// A response containing the results of our request to form a friendship with another agent
public class FriendshipResponseEventArgs : EventArgs
{
private readonly UUID m_AgentID;
private readonly string m_AgentName;
private readonly bool m_Accepted;
/// Get the ID of the agent we requested a friendship with
public UUID AgentID { get { return m_AgentID; } }
/// Get the name of the agent we requested a friendship with
public string AgentName { get { return m_AgentName; } }
/// true if the agent accepted our friendship offer
public bool Accepted { get { return m_Accepted; } }
///
/// Construct a new instance of the FriendShipResponseEventArgs class
///
/// The ID of the agent we requested a friendship with
/// The name of the agent we requested a friendship with
/// true if the agent accepted our friendship offer
public FriendshipResponseEventArgs(UUID agentID, string agentName, bool accepted)
{
this.m_AgentID = agentID;
this.m_AgentName = agentName;
this.m_Accepted = accepted;
}
}
/// Contains data sent when a friend terminates a friendship with us
public class FriendshipTerminatedEventArgs : EventArgs
{
private readonly UUID m_AgentID;
private readonly string m_AgentName;
/// Get the ID of the agent that terminated the friendship with us
public UUID AgentID { get { return m_AgentID; } }
/// Get the name of the agent that terminated the friendship with us
public string AgentName { get { return m_AgentName; } }
///
/// Construct a new instance of the FrindshipTerminatedEventArgs class
///
/// The ID of the friend who terminated the friendship with us
/// The name of the friend who terminated the friendship with us
public FriendshipTerminatedEventArgs(UUID agentID, string agentName)
{
this.m_AgentID = agentID;
this.m_AgentName = agentName;
}
}
///
/// Data sent in response to a request which contains the information to allow us to map the friends location
///
public class FriendFoundReplyEventArgs : EventArgs
{
private readonly UUID m_AgentID;
private readonly ulong m_RegionHandle;
private readonly Vector3 m_Location;
/// Get the ID of the agent we have received location information for
public UUID AgentID { get { return m_AgentID; } }
/// Get the region handle where our mapped friend is located
public ulong RegionHandle { get { return m_RegionHandle; } }
/// Get the simulator local position where our friend is located
public Vector3 Location { get { return m_Location; } }
///
/// Construct a new instance of the FriendFoundReplyEventArgs class
///
/// The ID of the agent we have requested location information for
/// The region handle where our friend is located
/// The simulator local position our friend is located
public FriendFoundReplyEventArgs(UUID agentID, ulong regionHandle, Vector3 location)
{
this.m_AgentID = agentID;
this.m_RegionHandle = regionHandle;
this.m_Location = location;
}
}
#endregion
}