From eebddcd5e693a4b56af326546d4222bd594286e0 Mon Sep 17 00:00:00 2001 From: Melanie Date: Mon, 28 Dec 2009 01:24:15 +0000 Subject: Change FriendsModule, InstantMessageModule, MessageTransferModule, MuteListModule, OfflineMessageModule, PresenceModule, InventoryTransferModule and LureModule to new style. Reduce FriendsModule and PresenceModule to shells. --- .../CoreModules/Avatar/Friends/FriendsModule.cs | 1064 +------------------- .../Avatar/InstantMessage/InstantMessageModule.cs | 60 +- .../Avatar/InstantMessage/MessageTransferModule.cs | 55 +- .../Avatar/InstantMessage/MuteListModule.cs | 68 +- .../Avatar/InstantMessage/OfflineMessageModule.cs | 78 +- .../Avatar/InstantMessage/PresenceModule.cs | 381 +------ .../Inventory/Transfer/InventoryTransferModule.cs | 56 +- .../Region/CoreModules/Avatar/Lure/LureModule.cs | 64 +- .../Resources/CoreModulePlugin.addin.xml | 8 + .../Region/Framework/Interfaces/IPresenceModule.cs | 10 +- 10 files changed, 286 insertions(+), 1558 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index d6a82ef..f5d30b7 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -44,1088 +44,50 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Region.CoreModules.Avatar.Friends { - /* - This module handles adding/removing friends, and the the presence - notification process for login/logoff of friends. - - The presence notification works as follows: - - After the user initially connects to a region (so we now have a UDP - connection to work with), this module fetches the friends of user - (those are cached), their on-/offline status, and info about the - region they are in from the MessageServer. - - (*) It then informs the user about the on-/offline status of her friends. - - It then informs all online friends currently on this region-server about - user's new online status (this will save some network traffic, as local - messages don't have to be transferred inter-region, and it will be all - that has to be done in Standalone Mode). - - For the rest of the online friends (those not on this region-server), - this module uses the provided region-information to map users to - regions, and sends one notification to every region containing the - friends to inform on that server. - - The region-server will handle that in the following way: - - If it finds the friend, it informs her about the user being online. - - If it doesn't find the friend (maybe she TPed away in the meantime), - it stores that information. - - After it processed all friends, it returns the list of friends it - couldn't find. - - If this list isn't empty, the FriendsModule re-requests information - about those online friends that have been missed and starts at (*) - again until all friends have been found, or until it tried 3 times - (to prevent endless loops due to some uncaught error). - - NOTE: Online/Offline notifications don't need to be sent on region change. - - We implement two XMLRpc handlers here, handling all the inter-region things - we have to handle: - - On-/Offline-Notifications (bulk) - - Terminate Friendship messages (single) - */ - - public class FriendsModule : IRegionModule, IFriendsModule + public class FriendsModule : ISharedRegionModule, IFriendsModule { - private class Transaction + public void Initialise(IConfigSource config) { - public UUID agentID; - public string agentName; - public uint count; - - public Transaction(UUID agentID, string agentName) - { - this.agentID = agentID; - this.agentName = agentName; - this.count = 1; - } - } - - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private Cache m_friendLists = new Cache(CacheFlags.AllowUpdate); - - private Dictionary m_rootAgents = new Dictionary(); - - private Dictionary m_pendingCallingcardRequests = new Dictionary(); - - private Scene m_initialScene; // saves a lookup if we don't have a specific scene - private Dictionary m_scenes = new Dictionary(); - private IMessageTransferModule m_TransferModule = null; - - private IGridService m_gridServices = null; - - #region IRegionModule Members - - public void Initialise(Scene scene, IConfigSource config) - { - lock (m_scenes) - { - if (m_scenes.Count == 0) - { - MainServer.Instance.AddXmlRPCHandler("presence_update_bulk", processPresenceUpdateBulk); - MainServer.Instance.AddXmlRPCHandler("terminate_friend", processTerminateFriend); - m_friendLists.DefaultTTL = new TimeSpan(1, 0, 0); // store entries for one hour max - m_initialScene = scene; - } - - if (!m_scenes.ContainsKey(scene.RegionInfo.RegionHandle)) - m_scenes[scene.RegionInfo.RegionHandle] = scene; - } - - scene.RegisterModuleInterface(this); - - scene.EventManager.OnNewClient += OnNewClient; - scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; - scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel; - scene.EventManager.OnMakeChildAgent += MakeChildAgent; - scene.EventManager.OnClientClosed += ClientClosed; } public void PostInitialise() { - if (m_scenes.Count > 0) - { - m_TransferModule = m_initialScene.RequestModuleInterface(); - m_gridServices = m_initialScene.GridService; - } - if (m_TransferModule == null) - m_log.Error("[FRIENDS]: Unable to find a message transfer module, friendship offers will not work"); - } - - public void Close() - { - } - - public string Name - { - get { return "FriendsModule"; } - } - - public bool IsSharedModule - { - get { return true; } - } - - #endregion - - #region IInterregionFriendsComms - - public List InformFriendsInOtherRegion(UUID agentId, ulong destRegionHandle, List friends, bool online) - { - List tpdAway = new List(); - - // destRegionHandle is a region on another server - uint x = 0, y = 0; - Utils.LongToUInts(destRegionHandle, out x, out y); - GridRegion info = m_gridServices.GetRegionByPosition(m_initialScene.RegionInfo.ScopeID, (int)x, (int)y); - if (info != null) - { - string httpServer = "http://" + info.ExternalEndPoint.Address + ":" + info.HttpPort + "/presence_update_bulk"; - - Hashtable reqParams = new Hashtable(); - reqParams["agentID"] = agentId.ToString(); - reqParams["agentOnline"] = online; - int count = 0; - foreach (UUID uuid in friends) - { - reqParams["friendID_" + count++] = uuid.ToString(); - } - reqParams["friendCount"] = count; - - IList parameters = new ArrayList(); - parameters.Add(reqParams); - try - { - XmlRpcRequest request = new XmlRpcRequest("presence_update_bulk", parameters); - XmlRpcResponse response = request.Send(httpServer, 5000); - Hashtable respData = (Hashtable)response.Value; - - count = (int)respData["friendCount"]; - for (int i = 0; i < count; ++i) - { - UUID uuid; - if (UUID.TryParse((string)respData["friendID_" + i], out uuid)) tpdAway.Add(uuid); - } - } - catch (WebException e) - { - // Ignore connect failures, simulators come and go - // - if (!e.Message.Contains("ConnectFailure")) - { - m_log.Error("[OGS1 GRID SERVICES]: InformFriendsInOtherRegion XMLRPC failure: ", e); - } - } - catch (Exception e) - { - m_log.Error("[OGS1 GRID SERVICES]: InformFriendsInOtherRegion XMLRPC failure: ", e); - } - } - else m_log.WarnFormat("[OGS1 GRID SERVICES]: Couldn't find region {0}???", destRegionHandle); - - return tpdAway; - } - - public bool TriggerTerminateFriend(ulong destRegionHandle, UUID agentID, UUID exFriendID) - { - // destRegionHandle is a region on another server - uint x = 0, y = 0; - Utils.LongToUInts(destRegionHandle, out x, out y); - GridRegion info = m_gridServices.GetRegionByPosition(m_initialScene.RegionInfo.ScopeID, (int)x, (int)y); - if (info == null) - { - m_log.WarnFormat("[OGS1 GRID SERVICES]: Couldn't find region {0}", destRegionHandle); - return false; // region not found??? - } - - string httpServer = "http://" + info.ExternalEndPoint.Address + ":" + info.HttpPort + "/presence_update_bulk"; - - Hashtable reqParams = new Hashtable(); - reqParams["agentID"] = agentID.ToString(); - reqParams["friendID"] = exFriendID.ToString(); - - IList parameters = new ArrayList(); - parameters.Add(reqParams); - try - { - XmlRpcRequest request = new XmlRpcRequest("terminate_friend", parameters); - XmlRpcResponse response = request.Send(httpServer, 5000); - Hashtable respData = (Hashtable)response.Value; - - return (bool)respData["success"]; - } - catch (Exception e) - { - m_log.Error("[OGS1 GRID SERVICES]: InformFriendsInOtherRegion XMLRPC failure: ", e); - return false; - } - } - - #endregion - - #region Incoming XMLRPC messages - /// - /// Receive presence information changes about clients in other regions. - /// - /// - /// - public XmlRpcResponse processPresenceUpdateBulk(XmlRpcRequest req, IPEndPoint remoteClient) - { - Hashtable requestData = (Hashtable)req.Params[0]; - - List friendsNotHere = new List(); - - // this is called with the expectation that all the friends in the request are on this region-server. - // But as some time passed since we checked (on the other region-server, via the MessagingServer), - // some of the friends might have teleported away. - // Actually, even now, between this line and the sending below, some people could TP away. So, - // we'll have to lock the m_rootAgents list for the duration to prevent/delay that. - lock (m_rootAgents) - { - List friendsHere = new List(); - - try - { - UUID agentID = new UUID((string)requestData["agentID"]); - bool agentOnline = (bool)requestData["agentOnline"]; - int count = (int)requestData["friendCount"]; - for (int i = 0; i < count; ++i) - { - UUID uuid; - if (UUID.TryParse((string)requestData["friendID_" + i], out uuid)) - { - if (m_rootAgents.ContainsKey(uuid)) friendsHere.Add(GetRootPresenceFromAgentID(uuid)); - else friendsNotHere.Add(uuid); - } - } - - // now send, as long as they are still here... - UUID[] agentUUID = new UUID[] { agentID }; - if (agentOnline) - { - foreach (ScenePresence agent in friendsHere) - { - agent.ControllingClient.SendAgentOnline(agentUUID); - } - } - else - { - foreach (ScenePresence agent in friendsHere) - { - agent.ControllingClient.SendAgentOffline(agentUUID); - } - } - } - catch(Exception e) - { - m_log.Warn("[FRIENDS]: Got exception while parsing presence_update_bulk request:", e); - } - } - - // no need to lock anymore; if TPs happen now, worst case is that we have an additional agent in this region, - // which should be caught on the next iteration... - Hashtable result = new Hashtable(); - int idx = 0; - foreach (UUID uuid in friendsNotHere) - { - result["friendID_" + idx++] = uuid.ToString(); - } - result["friendCount"] = idx; - - XmlRpcResponse response = new XmlRpcResponse(); - response.Value = result; - - return response; - } - - public XmlRpcResponse processTerminateFriend(XmlRpcRequest req, IPEndPoint remoteClient) - { - Hashtable requestData = (Hashtable)req.Params[0]; - - bool success = false; - - UUID agentID; - UUID friendID; - if (requestData.ContainsKey("agentID") && UUID.TryParse((string)requestData["agentID"], out agentID) && - requestData.ContainsKey("friendID") && UUID.TryParse((string)requestData["friendID"], out friendID)) - { - // try to find it and if it is there, prevent it to vanish before we sent the message - lock (m_rootAgents) - { - if (m_rootAgents.ContainsKey(agentID)) - { - m_log.DebugFormat("[FRIEND]: Sending terminate friend {0} to agent {1}", friendID, agentID); - GetRootPresenceFromAgentID(agentID).ControllingClient.SendTerminateFriend(friendID); - success = true; - } - } - } - - // return whether we were successful - Hashtable result = new Hashtable(); - result["success"] = success; - - XmlRpcResponse response = new XmlRpcResponse(); - response.Value = result; - return response; - } - - #endregion - - #region Scene events - - private void OnNewClient(IClientAPI client) - { - // All friends establishment protocol goes over instant message - // There's no way to send a message from the sim - // to a user to 'add a friend' without causing dialog box spam - - // Subscribe to instant messages - client.OnInstantMessage += OnInstantMessage; - - // Friend list management - client.OnApproveFriendRequest += OnApproveFriendRequest; - client.OnDenyFriendRequest += OnDenyFriendRequest; - client.OnTerminateFriendship += OnTerminateFriendship; - - // ... calling card handling... - client.OnOfferCallingCard += OnOfferCallingCard; - client.OnAcceptCallingCard += OnAcceptCallingCard; - client.OnDeclineCallingCard += OnDeclineCallingCard; - - // we need this one exactly once per agent session (see comments in the handler below) - client.OnEconomyDataRequest += OnEconomyDataRequest; - - // if it leaves, we want to know, too - client.OnLogout += OnLogout; - client.OnGrantUserRights += GrantUserFriendRights; - - } - - private void ClientClosed(UUID AgentId, Scene scene) - { - // agent's client was closed. As we handle logout in OnLogout, this here has only to handle - // TPing away (root agent is closed) or TPing/crossing in a region far enough away (client - // agent is closed). - // NOTE: In general, this doesn't mean that the agent logged out, just that it isn't around - // in one of the regions here anymore. - lock (m_rootAgents) - { - if (m_rootAgents.ContainsKey(AgentId)) - { - m_rootAgents.Remove(AgentId); - } - } - } - - private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID) - { - lock (m_rootAgents) - { - m_rootAgents[avatar.UUID] = avatar.RegionHandle; - // Claim User! my user! Mine mine mine! - } - } - - private void MakeChildAgent(ScenePresence avatar) - { - lock (m_rootAgents) - { - if (m_rootAgents.ContainsKey(avatar.UUID)) - { - // only delete if the region matches. As this is a shared module, the avatar could be - // root agent in another region on this server. - if (m_rootAgents[avatar.UUID] == avatar.RegionHandle) - { - m_rootAgents.Remove(avatar.UUID); -// m_log.Debug("[FRIEND]: Removing " + avatar.Firstname + " " + avatar.Lastname + " as a root agent"); - } - } - } - } - #endregion - - private ScenePresence GetRootPresenceFromAgentID(UUID AgentID) - { - ScenePresence returnAgent = null; - lock (m_scenes) - { - ScenePresence queryagent = null; - foreach (Scene scene in m_scenes.Values) - { - queryagent = scene.GetScenePresence(AgentID); - if (queryagent != null) - { - if (!queryagent.IsChildAgent) - { - returnAgent = queryagent; - break; - } - } - } - } - return returnAgent; - } - - private ScenePresence GetAnyPresenceFromAgentID(UUID AgentID) - { - ScenePresence returnAgent = null; - lock (m_scenes) - { - ScenePresence queryagent = null; - foreach (Scene scene in m_scenes.Values) - { - queryagent = scene.GetScenePresence(AgentID); - if (queryagent != null) - { - returnAgent = queryagent; - break; - } - } - } - return returnAgent; - } - - public void OfferFriendship(UUID fromUserId, IClientAPI toUserClient, string offerMessage) - { - CachedUserInfo userInfo = m_initialScene.CommsManager.UserProfileCacheService.GetUserDetails(fromUserId); - - if (userInfo != null) - { - GridInstantMessage msg = new GridInstantMessage( - toUserClient.Scene, fromUserId, userInfo.UserProfile.Name, toUserClient.AgentId, - (byte)InstantMessageDialog.FriendshipOffered, offerMessage, false, Vector3.Zero); - - FriendshipOffered(msg); - } - else - { - m_log.ErrorFormat("[FRIENDS]: No user found for id {0} in OfferFriendship()", fromUserId); - } - } - - #region FriendRequestHandling - - private void OnInstantMessage(IClientAPI client, GridInstantMessage im) - { - // Friend Requests go by Instant Message.. using the dialog param - // https://wiki.secondlife.com/wiki/ImprovedInstantMessage - - if (im.dialog == (byte)InstantMessageDialog.FriendshipOffered) // 38 - { - // fromAgentName is the *destination* name (the friend we offer friendship to) - ScenePresence initiator = GetAnyPresenceFromAgentID(new UUID(im.fromAgentID)); - im.fromAgentName = initiator != null ? initiator.Name : "(hippo)"; - - FriendshipOffered(im); - } - else if (im.dialog == (byte)InstantMessageDialog.FriendshipAccepted) // 39 - { - FriendshipAccepted(client, im); - } - else if (im.dialog == (byte)InstantMessageDialog.FriendshipDeclined) // 40 - { - FriendshipDeclined(client, im); - } - } - - /// - /// Invoked when a user offers a friendship. - /// - /// - /// - /// - private void FriendshipOffered(GridInstantMessage im) - { - // this is triggered by the initiating agent: - // A local agent offers friendship to some possibly remote friend. - // A IM is triggered, processed here and sent to the friend (possibly in a remote region). - - m_log.DebugFormat("[FRIEND]: Offer(38) - From: {0}, FromName: {1} To: {2}, Session: {3}, Message: {4}, Offline {5}", - im.fromAgentID, im.fromAgentName, im.toAgentID, im.imSessionID, im.message, im.offline); - - // 1.20 protocol sends an UUID in the message field, instead of the friendship offer text. - // For interoperability, we have to clear that - if (Util.isUUID(im.message)) im.message = ""; - - // be sneeky and use the initiator-UUID as transactionID. This means we can be stateless. - // we have to look up the agent name on friendship-approval, though. - im.imSessionID = im.fromAgentID; - - if (m_TransferModule != null) - { - // Send it to whoever is the destination. - // If new friend is local, it will send an IM to the viewer. - // If new friend is remote, it will cause a OnGridInstantMessage on the remote server - m_TransferModule.SendInstantMessage( - im, - delegate(bool success) - { - m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success); - } - ); - } - } - - /// - /// Invoked when a user accepts a friendship offer. - /// - /// - /// - private void FriendshipAccepted(IClientAPI client, GridInstantMessage im) - { - m_log.DebugFormat("[FRIEND]: 39 - from client {0}, agent {2} {3}, imsession {4} to {5}: {6} (dialog {7})", - client.AgentId, im.fromAgentID, im.fromAgentName, im.imSessionID, im.toAgentID, im.message, im.dialog); - } - - /// - /// Invoked when a user declines a friendship offer. - /// - /// May not currently be used - see OnDenyFriendRequest() instead - /// - /// - private void FriendshipDeclined(IClientAPI client, GridInstantMessage im) - { - UUID fromAgentID = new UUID(im.fromAgentID); - UUID toAgentID = new UUID(im.toAgentID); - - // declining the friendship offer causes a type 40 IM being sent to the (possibly remote) initiator - // toAgentID is initiator, fromAgentID declined friendship - m_log.DebugFormat("[FRIEND]: 40 - from client {0}, agent {1} {2}, imsession {3} to {4}: {5} (dialog {6})", - client != null ? client.AgentId.ToString() : "", - fromAgentID, im.fromAgentName, im.imSessionID, im.toAgentID, im.message, im.dialog); - - // Send the decline to whoever is the destination. - GridInstantMessage msg - = new GridInstantMessage( - client.Scene, fromAgentID, client.Name, toAgentID, - im.dialog, im.message, im.offline != 0, im.Position); - - // If new friend is local, it will send an IM to the viewer. - // If new friend is remote, it will cause a OnGridInstantMessage on the remote server - m_TransferModule.SendInstantMessage(msg, - delegate(bool success) { - m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success); - } - ); - } - - private void OnGridInstantMessage(GridInstantMessage msg) - { - // This event won't be raised unless we have that agent, - // so we can depend on the above not trying to send - // via grid again - //m_log.DebugFormat("[FRIEND]: Got GridIM from {0}, to {1}, imSession {2}, message {3}, dialog {4}", - // msg.fromAgentID, msg.toAgentID, msg.imSessionID, msg.message, msg.dialog); - - if (msg.dialog == (byte)InstantMessageDialog.FriendshipOffered || - msg.dialog == (byte)InstantMessageDialog.FriendshipAccepted || - msg.dialog == (byte)InstantMessageDialog.FriendshipDeclined) - { - // this should succeed as we *know* the root agent is here. - m_TransferModule.SendInstantMessage(msg, - delegate(bool success) { - //m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success); - } - ); - } - - if (msg.dialog == (byte)InstantMessageDialog.FriendshipAccepted) - { - // for accept friendship, we have to do a bit more - ApproveFriendship(new UUID(msg.fromAgentID), new UUID(msg.toAgentID), msg.fromAgentName); - } - } - - private void ApproveFriendship(UUID fromAgentID, UUID toAgentID, string fromName) - { - m_log.DebugFormat("[FRIEND]: Approve friendship from {0} (ID: {1}) to {2}", - fromAgentID, fromName, toAgentID); - - // a new friend was added in the initiator's and friend's data, so the cache entries are wrong now. - lock (m_friendLists) - { - m_friendLists.Invalidate(fromAgentID.ToString()); - m_friendLists.Invalidate(toAgentID.ToString()); - } - - // now send presence update and add a calling card for the new friend - - ScenePresence initiator = GetAnyPresenceFromAgentID(toAgentID); - if (initiator == null) - { - // quite wrong. Shouldn't happen. - m_log.WarnFormat("[FRIEND]: Coudn't find initiator of friend request {0}", toAgentID); - return; - } - - m_log.DebugFormat("[FRIEND]: Tell {0} that {1} is online", - initiator.Name, fromName); - // tell initiator that friend is online - initiator.ControllingClient.SendAgentOnline(new UUID[] { fromAgentID }); - - // find the folder for the friend... - //InventoryFolderImpl folder = - // initiator.Scene.CommsManager.UserProfileCacheService.GetUserDetails(toAgentID).FindFolderForType((int)InventoryType.CallingCard); - IInventoryService invService = initiator.Scene.InventoryService; - InventoryFolderBase folder = invService.GetFolderForType(toAgentID, AssetType.CallingCard); - if (folder != null) - { - // ... and add the calling card - CreateCallingCard(initiator.ControllingClient, fromAgentID, folder.ID, fromName); - } } - private void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List callingCardFolders) + public void AddRegion(Scene scene) { - m_log.DebugFormat("[FRIEND]: Got approve friendship from {0} {1}, agentID {2}, tid {3}", - client.Name, client.AgentId, agentID, friendID); - - // store the new friend persistently for both avatars - m_initialScene.StoreAddFriendship(friendID, agentID, (uint) FriendRights.CanSeeOnline); - - // The cache entries aren't valid anymore either, as we just added a friend to both sides. - lock (m_friendLists) - { - m_friendLists.Invalidate(agentID.ToString()); - m_friendLists.Invalidate(friendID.ToString()); - } - - // if it's a local friend, we don't have to do the lookup - ScenePresence friendPresence = GetAnyPresenceFromAgentID(friendID); - - if (friendPresence != null) - { - m_log.Debug("[FRIEND]: Local agent detected."); - - // create calling card - CreateCallingCard(client, friendID, callingCardFolders[0], friendPresence.Name); - - // local message means OnGridInstantMessage won't be triggered, so do the work here. - friendPresence.ControllingClient.SendInstantMessage( - new GridInstantMessage(client.Scene, agentID, - client.Name, friendID, - (byte)InstantMessageDialog.FriendshipAccepted, - agentID.ToString(), false, Vector3.Zero)); - ApproveFriendship(agentID, friendID, client.Name); - } - else - { - m_log.Debug("[FRIEND]: Remote agent detected."); - - // fetch the friend's name for the calling card. - CachedUserInfo info = m_initialScene.CommsManager.UserProfileCacheService.GetUserDetails(friendID); - - // create calling card - CreateCallingCard(client, friendID, callingCardFolders[0], - info.UserProfile.FirstName + " " + info.UserProfile.SurName); - - // Compose (remote) response to friend. - GridInstantMessage msg = new GridInstantMessage(client.Scene, agentID, client.Name, friendID, - (byte)InstantMessageDialog.FriendshipAccepted, - agentID.ToString(), false, Vector3.Zero); - if (m_TransferModule != null) - { - m_TransferModule.SendInstantMessage(msg, - delegate(bool success) { - m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success); - } - ); - } - } - - // tell client that new friend is online - client.SendAgentOnline(new UUID[] { friendID }); } - private void OnDenyFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List callingCardFolders) + public void RegionLoaded(Scene scene) { - m_log.DebugFormat("[FRIEND]: Got deny friendship from {0} {1}, agentID {2}, tid {3}", - client.Name, client.AgentId, agentID, friendID); - - // Compose response to other agent. - GridInstantMessage msg = new GridInstantMessage(client.Scene, agentID, client.Name, friendID, - (byte)InstantMessageDialog.FriendshipDeclined, - agentID.ToString(), false, Vector3.Zero); - // send decline to initiator - if (m_TransferModule != null) - { - m_TransferModule.SendInstantMessage(msg, - delegate(bool success) { - m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success); - } - ); - } } - private void OnTerminateFriendship(IClientAPI client, UUID agentID, UUID exfriendID) + public void RemoveRegion(Scene scene) { - // client.AgentId == agentID! - - // this removes the friends from the stored friendlists. After the next login, they will be gone... - m_initialScene.StoreRemoveFriendship(agentID, exfriendID); - - // ... now tell the two involved clients that they aren't friends anymore. - - // I don't know why we have to tell , as this was caused by her, but that's how it works in SL... - client.SendTerminateFriend(exfriendID); - - // now send the friend, if online - ScenePresence presence = GetAnyPresenceFromAgentID(exfriendID); - if (presence != null) - { - m_log.DebugFormat("[FRIEND]: Sending terminate friend {0} to agent {1}", agentID, exfriendID); - presence.ControllingClient.SendTerminateFriend(agentID); - } - else - { - // retry 3 times, in case the agent TPed from the last known region... - for (int retry = 0; retry < 3; ++retry) - { - // wasn't sent, so ex-friend wasn't around on this region-server. Fetch info and try to send - UserAgentData data = m_initialScene.CommsManager.UserService.GetAgentByUUID(exfriendID); - - if (null == data) - break; - - if (!data.AgentOnline) - { - m_log.DebugFormat("[FRIEND]: {0} is offline, so not sending TerminateFriend", exfriendID); - break; // if ex-friend isn't online, we don't need to send - } - - m_log.DebugFormat("[FRIEND]: Sending remote terminate friend {0} to agent {1}@{2}", - agentID, exfriendID, data.Handle); - - // try to send to foreign region, retry if it fails (friend TPed away, for example) - if (TriggerTerminateFriend(data.Handle, exfriendID, agentID)) break; - } - } - - // clean up cache: FriendList is wrong now... - lock (m_friendLists) - { - m_friendLists.Invalidate(agentID.ToString()); - m_friendLists.Invalidate(exfriendID.ToString()); - } } - #endregion - - #region CallingCards - - private void OnOfferCallingCard(IClientAPI client, UUID destID, UUID transactionID) - { - m_log.DebugFormat("[CALLING CARD]: got offer from {0} for {1}, transaction {2}", - client.AgentId, destID, transactionID); - // This might be slightly wrong. On a multi-region server, we might get the child-agent instead of the root-agent - // (or the root instead of the child) - ScenePresence destAgent = GetAnyPresenceFromAgentID(destID); - if (destAgent == null) - { - client.SendAlertMessage("The person you have offered a card to can't be found anymore."); - return; - } - - lock (m_pendingCallingcardRequests) - { - m_pendingCallingcardRequests[transactionID] = client.AgentId; - } - // inform the destination agent about the offer - destAgent.ControllingClient.SendOfferCallingCard(client.AgentId, transactionID); - } - - private void CreateCallingCard(IClientAPI client, UUID creator, UUID folder, string name) - { - InventoryItemBase item = new InventoryItemBase(); - item.AssetID = UUID.Zero; - item.AssetType = (int)AssetType.CallingCard; - item.BasePermissions = (uint)PermissionMask.Copy; - item.CreationDate = Util.UnixTimeSinceEpoch(); - item.CreatorId = creator.ToString(); - item.CurrentPermissions = item.BasePermissions; - item.Description = ""; - item.EveryOnePermissions = (uint)PermissionMask.None; - item.Flags = 0; - item.Folder = folder; - item.GroupID = UUID.Zero; - item.GroupOwned = false; - item.ID = UUID.Random(); - item.InvType = (int)InventoryType.CallingCard; - item.Name = name; - item.NextPermissions = item.EveryOnePermissions; - item.Owner = client.AgentId; - item.SalePrice = 10; - item.SaleType = (byte)SaleType.Not; - ((Scene)client.Scene).AddInventoryItem(client, item); - } - - private void OnAcceptCallingCard(IClientAPI client, UUID transactionID, UUID folderID) - { - m_log.DebugFormat("[CALLING CARD]: User {0} ({1} {2}) accepted tid {3}, folder {4}", - client.AgentId, - client.FirstName, client.LastName, - transactionID, folderID); - UUID destID; - lock (m_pendingCallingcardRequests) - { - if (!m_pendingCallingcardRequests.TryGetValue(transactionID, out destID)) - { - m_log.WarnFormat("[CALLING CARD]: Got a AcceptCallingCard from {0} without an offer before.", - client.Name); - return; - } - // else found pending calling card request with that transaction. - m_pendingCallingcardRequests.Remove(transactionID); - } - - - ScenePresence destAgent = GetAnyPresenceFromAgentID(destID); - // inform sender of the card that destination declined the offer - if (destAgent != null) destAgent.ControllingClient.SendAcceptCallingCard(transactionID); - - // put a calling card into the inventory of receiver - CreateCallingCard(client, destID, folderID, destAgent.Name); - } - - private void OnDeclineCallingCard(IClientAPI client, UUID transactionID) + public void Close() { - m_log.DebugFormat("[CALLING CARD]: User {0} (ID:{1}) declined card, tid {2}", - client.Name, client.AgentId, transactionID); - UUID destID; - lock (m_pendingCallingcardRequests) - { - if (!m_pendingCallingcardRequests.TryGetValue(transactionID, out destID)) - { - m_log.WarnFormat("[CALLING CARD]: Got a AcceptCallingCard from {0} without an offer before.", - client.Name); - return; - } - // else found pending calling card request with that transaction. - m_pendingCallingcardRequests.Remove(transactionID); - } - - ScenePresence destAgent = GetAnyPresenceFromAgentID(destID); - // inform sender of the card that destination declined the offer - if (destAgent != null) destAgent.ControllingClient.SendDeclineCallingCard(transactionID); } - /// - /// Send presence information about a client to other clients in both this region and others. - /// - /// - /// - /// - private void SendPresenceState(IClientAPI client, List friendList, bool iAmOnline) + public string Name { - //m_log.DebugFormat("[FRIEND]: {0} logged {1}; sending presence updates", client.Name, iAmOnline ? "in" : "out"); - - if (friendList == null || friendList.Count == 0) - { - //m_log.DebugFormat("[FRIEND]: {0} doesn't have friends.", client.Name); - return; // nothing we can do if she doesn't have friends... - } - - // collect sets of friendIDs; to send to (online and offline), and to receive from - // TODO: If we ever switch to .NET >= 3, replace those Lists with HashSets. - // I can't believe that we have Dictionaries, but no Sets, considering Java introduced them years ago... - List friendIDsToSendTo = new List(); - List candidateFriendIDsToReceive = new List(); - - foreach (FriendListItem item in friendList) - { - if (((item.FriendListOwnerPerms | item.FriendPerms) & (uint)FriendRights.CanSeeOnline) != 0) - { - // friend is allowed to see my presence => add - if ((item.FriendListOwnerPerms & (uint)FriendRights.CanSeeOnline) != 0) - friendIDsToSendTo.Add(item.Friend); - - if ((item.FriendPerms & (uint)FriendRights.CanSeeOnline) != 0) - candidateFriendIDsToReceive.Add(item.Friend); - } - } - - // we now have a list of "interesting" friends (which we have to find out on-/offline state for), - // friends we want to send our online state to (if *they* are online, too), and - // friends we want to receive online state for (currently unknown whether online or not) - - // as this processing might take some time and friends might TP away, we try up to three times to - // reach them. Most of the time, we *will* reach them, and this loop won't loop - int retry = 0; - do - { - // build a list of friends to look up region-information and on-/offline-state for - List friendIDsToLookup = new List(friendIDsToSendTo); - foreach (UUID uuid in candidateFriendIDsToReceive) - { - if (!friendIDsToLookup.Contains(uuid)) friendIDsToLookup.Add(uuid); - } - - m_log.DebugFormat( - "[FRIEND]: {0} to lookup, {1} to send to, {2} candidates to receive from for agent {3}", - friendIDsToLookup.Count, friendIDsToSendTo.Count, candidateFriendIDsToReceive.Count, client.Name); - - // we have to fetch FriendRegionInfos, as the (cached) FriendListItems don't - // necessarily contain the correct online state... - Dictionary friendRegions = m_initialScene.GetFriendRegionInfos(friendIDsToLookup); - m_log.DebugFormat( - "[FRIEND]: Found {0} regionInfos for {1} friends of {2}", - friendRegions.Count, friendIDsToLookup.Count, client.Name); - - // argument for SendAgentOn/Offline; we shouldn't generate that repeatedly within loops. - UUID[] agentArr = new UUID[] { client.AgentId }; - - // first, send to friend presence state to me, if I'm online... - if (iAmOnline) - { - List friendIDsToReceive = new List(); - - for (int i = candidateFriendIDsToReceive.Count - 1; i >= 0; --i) - { - UUID uuid = candidateFriendIDsToReceive[i]; - FriendRegionInfo info; - if (friendRegions.TryGetValue(uuid, out info) && info != null && info.isOnline) - { - friendIDsToReceive.Add(uuid); - } - } - - m_log.DebugFormat( - "[FRIEND]: Sending {0} online friends to {1}", friendIDsToReceive.Count, client.Name); - - if (friendIDsToReceive.Count > 0) - client.SendAgentOnline(friendIDsToReceive.ToArray()); - - // clear them for a possible second iteration; we don't have to repeat this - candidateFriendIDsToReceive.Clear(); - } - - // now, send my presence state to my friends - for (int i = friendIDsToSendTo.Count - 1; i >= 0; --i) - { - UUID uuid = friendIDsToSendTo[i]; - FriendRegionInfo info; - if (friendRegions.TryGetValue(uuid, out info) && info != null && info.isOnline) - { - // any client is good enough, root or child... - ScenePresence agent = GetAnyPresenceFromAgentID(uuid); - if (agent != null) - { - //m_log.DebugFormat("[FRIEND]: Found local agent {0}", agent.Name); - - // friend is online and on this server... - if (iAmOnline) agent.ControllingClient.SendAgentOnline(agentArr); - else agent.ControllingClient.SendAgentOffline(agentArr); - - // done, remove it - friendIDsToSendTo.RemoveAt(i); - } - } - else - { - //m_log.DebugFormat("[FRIEND]: Friend {0} ({1}) is offline; not sending.", uuid, i); - - // friend is offline => no need to try sending - friendIDsToSendTo.RemoveAt(i); - } - } - - m_log.DebugFormat("[FRIEND]: Have {0} friends to contact via inter-region comms.", friendIDsToSendTo.Count); - - // we now have all the friends left that are online (we think), but not on this region-server - if (friendIDsToSendTo.Count > 0) - { - // sort them into regions - Dictionary> friendsInRegion = new Dictionary>(); - foreach (UUID uuid in friendIDsToSendTo) - { - ulong handle = friendRegions[uuid].regionHandle; // this can't fail as we filtered above already - List friends; - if (!friendsInRegion.TryGetValue(handle, out friends)) - { - friends = new List(); - friendsInRegion[handle] = friends; - } - friends.Add(uuid); - } - m_log.DebugFormat("[FRIEND]: Found {0} regions to send to.", friendRegions.Count); - - // clear uuids list and collect missed friends in it for the next retry - friendIDsToSendTo.Clear(); - - // send bulk updates to the region - foreach (KeyValuePair> pair in friendsInRegion) - { - //m_log.DebugFormat("[FRIEND]: Inform {0} friends in region {1} that user {2} is {3}line", - // pair.Value.Count, pair.Key, client.Name, iAmOnline ? "on" : "off"); - - friendIDsToSendTo.AddRange(InformFriendsInOtherRegion(client.AgentId, pair.Key, pair.Value, iAmOnline)); - } - } - // now we have in friendIDsToSendTo only the agents left that TPed away while we tried to contact them. - // In most cases, it will be empty, and it won't loop here. But sometimes, we have to work harder and try again... - } - while (++retry < 3 && friendIDsToSendTo.Count > 0); + get { return "FriendsModule"; } } - private void OnEconomyDataRequest(UUID agentID) + public Type ReplaceableInterface { - // KLUDGE: This is the only way I found to get a message (only) after login was completed and the - // client is connected enough to receive UDP packets). - // This packet seems to be sent only once, just after connection was established to the first - // region after login. - // We use it here to trigger a presence update; the old update-on-login was never be heard by - // the freshly logged in viewer, as it wasn't connected to the region at that time. - // TODO: Feel free to replace this by a better solution if you find one. - - // get the agent. This should work every time, as we just got a packet from it - //ScenePresence agent = GetRootPresenceFromAgentID(agentID); - // KLUDGE 2: As this is sent quite early, the avatar isn't here as root agent yet. So, we have to cheat a bit - ScenePresence agent = GetAnyPresenceFromAgentID(agentID); - - // just to be paranoid... - if (agent == null) - { - m_log.ErrorFormat("[FRIEND]: Got a packet from agent {0} who can't be found anymore!?", agentID); - return; - } - - List fl; - lock (m_friendLists) - { - fl = (List)m_friendLists.Get(agent.ControllingClient.AgentId.ToString(), - m_initialScene.GetFriendList); - } - - // tell everyone that we are online - SendPresenceState(agent.ControllingClient, fl, true); + get { return null; } } - private void OnLogout(IClientAPI remoteClient) + public void OfferFriendship(UUID fromUserId, IClientAPI toUserClient, + string offerMessage) { - List fl; - lock (m_friendLists) - { - fl = (List)m_friendLists.Get(remoteClient.AgentId.ToString(), - m_initialScene.GetFriendList); - } - - // tell everyone that we are offline - SendPresenceState(remoteClient, fl, false); - } - private void GrantUserFriendRights(IClientAPI remoteClient, UUID requester, UUID target, int rights) - { - ((Scene)remoteClient.Scene).CommsManager.UpdateUserFriendPerms(requester, target, (uint)rights); } public List GetUserFriends(UUID agentID) { - List fl; - lock (m_friendLists) - { - fl = (List)m_friendLists.Get(agentID.ToString(), - m_initialScene.GetFriendList); - } - - return fl; + return null; } } - #endregion } diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs index 9a68749..ab141eb 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs @@ -24,6 +24,7 @@ * (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.Collections.Generic; using System.Reflection; using log4net; @@ -36,9 +37,10 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.CoreModules.Avatar.InstantMessage { - public class InstantMessageModule : IRegionModule + public class InstantMessageModule : ISharedRegionModule { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); /// /// Is this module enabled? @@ -51,7 +53,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage private IMessageTransferModule m_TransferModule = null; - public void Initialise(Scene scene, IConfigSource config) + public void Initialise(IConfigSource config) { if (config.Configs["Messaging"] != null) { @@ -62,6 +64,12 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage } m_enabled = true; + } + + public void AddRegion(Scene scene) + { + if (!m_enabled) + return; lock (m_scenes) { @@ -74,6 +82,39 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage } } + public void RegionLoaded(Scene scene) + { + if (!m_enabled) + return; + + if (m_TransferModule == null) + { + m_TransferModule = + scene.RequestModuleInterface(); + + if (m_TransferModule == null) + { + m_log.Error("[INSTANT MESSAGE]: No message transfer module, IM will not work!"); + scene.EventManager.OnClientConnect -= OnClientConnect; + scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; + + m_scenes.Clear(); + m_enabled = false; + } + } + } + + public void RemoveRegion(Scene scene) + { + if (!m_enabled) + return; + + lock (m_scenes) + { + m_scenes.Remove(scene); + } + } + void OnClientConnect(IClientCore client) { IClientIM clientIM; @@ -85,15 +126,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage public void PostInitialise() { - if (!m_enabled) - return; - - m_TransferModule = - m_scenes[0].RequestModuleInterface(); - - if (m_TransferModule == null) - m_log.Error("[INSTANT MESSAGE]: No message transfer module, "+ - "IM will not work!"); } public void Close() @@ -105,9 +137,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage get { return "InstantMessageModule"; } } - public bool IsSharedModule + public Type ReplaceableInterface { - get { return true; } + get { return null; } } #endregion diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs index e5159b3..b5019f1 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs @@ -40,18 +40,17 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Region.CoreModules.Avatar.InstantMessage { - public class MessageTransferModule : IRegionModule, IMessageTransferModule + public class MessageTransferModule : ISharedRegionModule, IMessageTransferModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - // private bool m_Enabled = false; - protected bool m_Gridmode = false; + private bool m_Enabled = false; protected List m_Scenes = new List(); protected Dictionary m_UserRegionMap = new Dictionary(); public event UndeliveredMessage OnUndeliveredMessage; - public virtual void Initialise(Scene scene, IConfigSource config) + public virtual void Initialise(IConfigSource config) { IConfig cnf = config.Configs["Messaging"]; if (cnf != null && cnf.GetString( @@ -62,20 +61,19 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage return; } - cnf = config.Configs["Startup"]; - if (cnf != null) - m_Gridmode = cnf.GetBoolean("gridmode", false); + MainServer.Instance.AddXmlRPCHandler( + "grid_instant_message", processXMLRPCGridInstantMessage); - // m_Enabled = true; + m_Enabled = true; + } + + public virtual void AddRegion(Scene scene) + { + if (!m_Enabled) + return; lock (m_Scenes) { - if (m_Scenes.Count == 0) - { - MainServer.Instance.AddXmlRPCHandler( - "grid_instant_message", processXMLRPCGridInstantMessage); - } - m_log.Debug("[MESSAGE TRANSFER]: Message transfer module active"); scene.RegisterModuleInterface(this); m_Scenes.Add(scene); @@ -86,6 +84,21 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage { } + public virtual void RegionLoaded(Scene scene) + { + } + + public virtual void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + + lock(m_Scenes) + { + m_Scenes.Remove(scene); + } + } + public virtual void Close() { } @@ -95,9 +108,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage get { return "MessageTransferModule"; } } - public virtual bool IsSharedModule + public virtual Type ReplaceableInterface { - get { return true; } + get { return null; } } public virtual void SendInstantMessage(GridInstantMessage im, MessageResultNotification result) @@ -148,15 +161,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage } } - if (m_Gridmode) - { - //m_log.DebugFormat("[INSTANT MESSAGE]: Delivering via grid"); - // Still here, try send via Grid - SendGridInstantMessageViaXMLRPC(im, result); - return; - } - - HandleUndeliveredMessage(im, result); + SendGridInstantMessageViaXMLRPC(im, result); return; } diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs index 2d4a635..1ff5865 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs @@ -39,7 +39,7 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.CoreModules.Avatar.MuteList { - public class MuteListModule : IRegionModule + public class MuteListModule : ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -47,11 +47,8 @@ namespace OpenSim.Region.CoreModules.Avatar.MuteList private List m_SceneList = new List(); private string m_RestURL = String.Empty; - public void Initialise(Scene scene, IConfigSource config) + public void Initialise(IConfigSource config) { - if (!enabled) - return; - IConfig cnf = config.Configs["Messaging"]; if (cnf == null) { @@ -59,39 +56,53 @@ namespace OpenSim.Region.CoreModules.Avatar.MuteList return; } - if (cnf != null && cnf.GetString( - "MuteListModule", "None") != + if (cnf != null && cnf.GetString("MuteListModule", "None") != "MuteListModule") { enabled = false; return; } + m_RestURL = cnf.GetString("MuteListURL", ""); + if (m_RestURL == "") + { + m_log.Error("[MUTE LIST] Module was enabled, but no URL is given, disabling"); + enabled = false; + return; + } + } + + public void AddRegion(Scene scene) + { + if (!enabled) + return; + lock (m_SceneList) { - if (m_SceneList.Count == 0) - { - m_RestURL = cnf.GetString("MuteListURL", ""); - if (m_RestURL == "") - { - m_log.Error("[MUTE LIST] Module was enabled, but no URL is given, disabling"); - enabled = false; - return; - } - } - if (!m_SceneList.Contains(scene)) - m_SceneList.Add(scene); + m_SceneList.Add(scene); scene.EventManager.OnNewClient += OnNewClient; } } - public void PostInitialise() + public void RegionLoaded(Scene scene) + { + } + + public void RemoveRegion(Scene scene) { if (!enabled) return; - if (m_SceneList.Count == 0) + lock (m_SceneList) + { + m_SceneList.Remove(scene); + } + } + + public void PostInitialise() + { + if (!enabled) return; m_log.Debug("[MUTE LIST] Mute list enabled"); @@ -102,26 +113,15 @@ namespace OpenSim.Region.CoreModules.Avatar.MuteList get { return "MuteListModule"; } } - public bool IsSharedModule + public Type ReplaceableInterface { - get { return true; } + get { return null; } } public void Close() { } -// private IClientAPI FindClient(UUID agentID) -// { -// foreach (Scene s in m_SceneList) -// { -// ScenePresence presence = s.GetScenePresence(agentID); -// if (presence != null && !presence.IsChildAgent) -// return presence.ControllingClient; -// } -// return null; -// } - private void OnNewClient(IClientAPI client) { client.OnMuteListRequest += OnMuteListRequest; diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs index 1614b70..a835c52 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs @@ -40,78 +40,88 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.CoreModules.Avatar.InstantMessage { - public class OfflineMessageModule : IRegionModule + public class OfflineMessageModule : ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private bool enabled = true; private List m_SceneList = new List(); private string m_RestURL = String.Empty; + IMessageTransferModule m_TransferModule = null; - public void Initialise(Scene scene, IConfigSource config) + public void Initialise(IConfigSource config) { - if (!enabled) - return; - IConfig cnf = config.Configs["Messaging"]; if (cnf == null) { enabled = false; return; } - if (cnf != null && cnf.GetString( - "OfflineMessageModule", "None") != + if (cnf != null && cnf.GetString("OfflineMessageModule", "None") != "OfflineMessageModule") { enabled = false; return; } + m_RestURL = cnf.GetString("OfflineMessageURL", ""); + if (m_RestURL == "") + { + m_log.Error("[OFFLINE MESSAGING] Module was enabled, but no URL is given, disabling"); + enabled = false; + return; + } + } + + public void AddRegion(Scene scene) + { + if (!enabled) + return; + lock (m_SceneList) { - if (m_SceneList.Count == 0) - { - m_RestURL = cnf.GetString("OfflineMessageURL", ""); - if (m_RestURL == "") - { - m_log.Error("[OFFLINE MESSAGING] Module was enabled, but no URL is given, disabling"); - enabled = false; - return; - } - } - if (!m_SceneList.Contains(scene)) - m_SceneList.Add(scene); + m_SceneList.Add(scene); scene.EventManager.OnNewClient += OnNewClient; } } - public void PostInitialise() + public void RegionLoaded(Scene scene) { if (!enabled) return; - if (m_SceneList.Count == 0) - return; - - IMessageTransferModule trans = m_SceneList[0].RequestModuleInterface(); - if (trans == null) + if (m_TransferModule == null) { - enabled = false; - - lock (m_SceneList) + m_TransferModule = scene.RequestModuleInterface(); + if (m_TransferModule == null) { - foreach (Scene s in m_SceneList) - s.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnNewClient -= OnNewClient; + enabled = false; m_SceneList.Clear(); + + m_log.Error("[OFFLINE MESSAGING] No message transfer module is enabled. Diabling offline messages"); } + m_TransferModule.OnUndeliveredMessage += UndeliveredMessage; + } + } - m_log.Error("[OFFLINE MESSAGING] No message transfer module is enabled. Diabling offline messages"); + public void RemoveRegion(Scene scene) + { + if (!enabled) return; + + lock (m_SceneList) + { + m_SceneList.Remove(scene); } + } - trans.OnUndeliveredMessage += UndeliveredMessage; + public void PostInitialise() + { + if (!enabled) + return; m_log.Debug("[OFFLINE MESSAGING] Offline messages enabled"); } @@ -121,9 +131,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage get { return "OfflineMessageModule"; } } - public bool IsSharedModule + public Type ReplaceableInterface { - get { return true; } + get { return null; } } public void Close() diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs index f5ab454..267a90a 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs @@ -24,6 +24,7 @@ * (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.Collections; using System.Collections.Generic; using System.Net; @@ -39,404 +40,54 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Region.CoreModules.Avatar.InstantMessage { - public class PresenceModule : IRegionModule, IPresenceModule + public class PresenceModule : ISharedRegionModule, IPresenceModule { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private bool m_Enabled = false; - private bool m_Gridmode = false; - - // some default scene for doing things that aren't connected to a specific scene. Avoids locking. - private Scene m_initialScene; - - private List m_Scenes = new List(); - - // we currently are only interested in root-agents. If the root isn't here, we don't know the region the - // user is in, so we have to ask the messaging server anyway. - private Dictionary m_RootAgents = - new Dictionary(); + private static readonly ILog m_log = LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); public event PresenceChange OnPresenceChange; public event BulkPresenceData OnBulkPresenceData; - public void Initialise(Scene scene, IConfigSource config) + public void Initialise(IConfigSource config) { - lock (m_Scenes) - { - // This is a shared module; Initialise will be called for every region on this server. - // Only check config once for the first region. - if (m_Scenes.Count == 0) - { - IConfig cnf = config.Configs["Messaging"]; - if (cnf != null && cnf.GetString( - "PresenceModule", "PresenceModule") != - "PresenceModule") - return; - - cnf = config.Configs["Startup"]; - if (cnf != null) - m_Gridmode = cnf.GetBoolean("gridmode", false); - - m_Enabled = true; - - m_initialScene = scene; - } - - if (m_Gridmode) - NotifyMessageServerOfStartup(scene); - - m_Scenes.Add(scene); - } - - scene.RegisterModuleInterface(this); - - scene.EventManager.OnNewClient += OnNewClient; - scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene; - scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; } - public void PostInitialise() + public void AddRegion(Scene scene) { } - public void Close() + public void RegionLoaded(Scene scene) { - if (!m_Gridmode || !m_Enabled) - return; - - if (OnPresenceChange != null) - { - lock (m_RootAgents) - { - // on shutdown, users are kicked, too - foreach (KeyValuePair pair in m_RootAgents) - { - OnPresenceChange(new PresenceInfo(pair.Key, UUID.Zero)); - } - } - } - - lock (m_Scenes) - { - foreach (Scene scene in m_Scenes) - NotifyMessageServerOfShutdown(scene); - } } - public string Name + public void RemoveRegion(Scene scene) { - get { return "PresenceModule"; } - } - - public bool IsSharedModule - { - get { return true; } - } - - public void RequestBulkPresenceData(UUID[] users) - { - if (OnBulkPresenceData != null) - { - PresenceInfo[] result = new PresenceInfo[users.Length]; - if (m_Gridmode) - { - // first check the local information - List uuids = new List(); // the uuids to check remotely - List indices = new List(); // just for performance. - lock (m_RootAgents) - { - for (int i = 0; i < uuids.Count; ++i) - { - Scene scene; - if (m_RootAgents.TryGetValue(users[i], out scene)) - { - result[i] = new PresenceInfo(users[i], scene.RegionInfo.RegionID); - } - else - { - uuids.Add(users[i]); - indices.Add(i); - } - } - } - - // now we have filtered out all the local root agents. The rest we have to request info about - Dictionary infos = m_initialScene.GetFriendRegionInfos(uuids); - for (int i = 0; i < uuids.Count; ++i) - { - FriendRegionInfo info; - if (infos.TryGetValue(uuids[i], out info) && info.isOnline) - { - UUID regionID = info.regionID; - if (regionID == UUID.Zero) - { - // TODO this is the old messaging-server protocol; only the regionHandle is available. - // Fetch region-info to get the id - uint x = 0, y = 0; - Utils.LongToUInts(info.regionHandle, out x, out y); - GridRegion regionInfo = m_initialScene.GridService.GetRegionByPosition(m_initialScene.RegionInfo.ScopeID, - (int)x, (int)y); - regionID = regionInfo.RegionID; - } - result[indices[i]] = new PresenceInfo(uuids[i], regionID); - } - else result[indices[i]] = new PresenceInfo(uuids[i], UUID.Zero); - } - } - else - { - // in standalone mode, we have all the info locally available. - lock (m_RootAgents) - { - for (int i = 0; i < users.Length; ++i) - { - Scene scene; - if (m_RootAgents.TryGetValue(users[i], out scene)) - { - result[i] = new PresenceInfo(users[i], scene.RegionInfo.RegionID); - } - else - { - result[i] = new PresenceInfo(users[i], UUID.Zero); - } - } - } - } - - // tell everyone - OnBulkPresenceData(result); - } - } - - // new client doesn't mean necessarily that user logged in, it just means it entered one of the - // the regions on this server - public void OnNewClient(IClientAPI client) - { - client.OnConnectionClosed += OnConnectionClosed; - client.OnLogout += OnLogout; - - // KLUDGE: See handler for details. - client.OnEconomyDataRequest += OnEconomyDataRequest; } - // connection closed just means *one* client connection has been closed. It doesn't mean that the - // user has logged off; it might have just TPed away. - public void OnConnectionClosed(IClientAPI client) - { - // TODO: Have to think what we have to do here... - // Should we just remove the root from the list (if scene matches)? - if (!(client.Scene is Scene)) - return; - Scene scene = (Scene)client.Scene; - - lock (m_RootAgents) - { - Scene rootScene; - if (!(m_RootAgents.TryGetValue(client.AgentId, out rootScene)) || scene != rootScene) - return; - - m_RootAgents.Remove(client.AgentId); - } - - // Should it have logged off, we'll do the logout part in OnLogout, even if no root is stored - // anymore. It logged off, after all... - } - - // Triggered when the user logs off. - public void OnLogout(IClientAPI client) - { - if (!(client.Scene is Scene)) - return; - Scene scene = (Scene)client.Scene; - - // On logout, we really remove the client from rootAgents, even if the scene doesn't match - lock (m_RootAgents) - { - if (m_RootAgents.ContainsKey(client.AgentId)) m_RootAgents.Remove(client.AgentId); - } - - // now inform the messaging server and anyone who is interested - NotifyMessageServerOfAgentLeaving(client.AgentId, scene.RegionInfo.RegionID, scene.RegionInfo.RegionHandle); - if (OnPresenceChange != null) OnPresenceChange(new PresenceInfo(client.AgentId, UUID.Zero)); - } - - public void OnSetRootAgentScene(UUID agentID, Scene scene) - { - // OnSetRootAgentScene can be called from several threads at once (with different agentID). - // Concurrent access to m_RootAgents is prone to failure on multi-core/-processor systems without - // correct locking). - lock (m_RootAgents) - { - Scene rootScene; - if (m_RootAgents.TryGetValue(agentID, out rootScene) && scene == rootScene) - { - return; - } - m_RootAgents[agentID] = scene; - } - - // inform messaging server that agent changed the region - Util.FireAndForget( - delegate(object o) - { - NotifyMessageServerOfAgentLocation(agentID, scene.RegionInfo.RegionID, scene.RegionInfo.RegionHandle); - } - ); - } - - private void OnEconomyDataRequest(UUID agentID) + public void PostInitialise() { - // KLUDGE: This is the only way I found to get a message (only) after login was completed and the - // client is connected enough to receive UDP packets. - // This packet seems to be sent only once, just after connection was established to the first - // region after login. - // We use it here to trigger a presence update; the old update-on-login was never be heard by - // the freshly logged in viewer, as it wasn't connected to the region at that time. - // TODO: Feel free to replace this by a better solution if you find one. - - // get the agent. This should work every time, as we just got a packet from it - ScenePresence agent = null; - lock (m_Scenes) - { - foreach (Scene scene in m_Scenes) - { - agent = scene.GetScenePresence(agentID); - if (agent != null) break; - } - } - - // just to be paranoid... - if (agent == null) - { - m_log.ErrorFormat("[PRESENCE]: Got a packet from agent {0} who can't be found anymore!?", agentID); - return; - } - - // we are a bit premature here, but the next packet will switch this child agent to root. - if (OnPresenceChange != null) OnPresenceChange(new PresenceInfo(agentID, agent.Scene.RegionInfo.RegionID)); } - public void OnMakeChildAgent(ScenePresence agent) + public void Close() { - // OnMakeChildAgent can be called from several threads at once (with different agent). - // Concurrent access to m_RootAgents is prone to failure on multi-core/-processor systems without - // correct locking). - lock (m_RootAgents) - { - Scene rootScene; - if (m_RootAgents.TryGetValue(agent.UUID, out rootScene) && agent.Scene == rootScene) - { - m_RootAgents.Remove(agent.UUID); - } - } - // don't notify the messaging-server; either this agent just had been downgraded and another one will be upgraded - // to root momentarily (which will notify the messaging-server), or possibly it will be closed in a moment, - // which will update the messaging-server, too. } - private void NotifyMessageServerOfStartup(Scene scene) + public string Name { - Hashtable xmlrpcdata = new Hashtable(); - xmlrpcdata["RegionUUID"] = scene.RegionInfo.RegionID.ToString(); - ArrayList SendParams = new ArrayList(); - SendParams.Add(xmlrpcdata); - try - { - XmlRpcRequest UpRequest = new XmlRpcRequest("region_startup", SendParams); - XmlRpcResponse resp = UpRequest.Send(scene.CommsManager.NetworkServersInfo.MessagingURL, 5000); - - Hashtable responseData = (Hashtable)resp.Value; - if (responseData == null || (!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE") - { - m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region startup for region {0}", scene.RegionInfo.RegionName); - } - } - catch (WebException) - { - m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region startup for region {0}", scene.RegionInfo.RegionName); - } + get { return "PresenceModule"; } } - private void NotifyMessageServerOfShutdown(Scene scene) + public Type ReplaceableInterface { - if (m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL == string.Empty) - return; - - Hashtable xmlrpcdata = new Hashtable(); - xmlrpcdata["RegionUUID"] = scene.RegionInfo.RegionID.ToString(); - ArrayList SendParams = new ArrayList(); - SendParams.Add(xmlrpcdata); - try - { - XmlRpcRequest DownRequest = new XmlRpcRequest("region_shutdown", SendParams); - XmlRpcResponse resp = DownRequest.Send(scene.CommsManager.NetworkServersInfo.MessagingURL, 5000); - - Hashtable responseData = (Hashtable)resp.Value; - if ((!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE") - { - m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region shutdown for region {0}", scene.RegionInfo.RegionName); - } - } - catch (WebException) - { - m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region shutdown for region {0}", scene.RegionInfo.RegionName); - } + get { return null; } } - private void NotifyMessageServerOfAgentLocation(UUID agentID, UUID region, ulong regionHandle) + public void RequestBulkPresenceData(UUID[] users) { - if (m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL == string.Empty) - return; - - Hashtable xmlrpcdata = new Hashtable(); - xmlrpcdata["AgentID"] = agentID.ToString(); - xmlrpcdata["RegionUUID"] = region.ToString(); - xmlrpcdata["RegionHandle"] = regionHandle.ToString(); - ArrayList SendParams = new ArrayList(); - SendParams.Add(xmlrpcdata); - try - { - XmlRpcRequest LocationRequest = new XmlRpcRequest("agent_location", SendParams); - XmlRpcResponse resp = LocationRequest.Send(m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL, 5000); - - Hashtable responseData = (Hashtable)resp.Value; - if ((!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE") - { - m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent location for {0}", agentID.ToString()); - } - } - catch (WebException) - { - m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent location for {0}", agentID.ToString()); - } } - private void NotifyMessageServerOfAgentLeaving(UUID agentID, UUID region, ulong regionHandle) + public void OnNewClient(IClientAPI client) { - if (m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL == string.Empty) - return; - - Hashtable xmlrpcdata = new Hashtable(); - xmlrpcdata["AgentID"] = agentID.ToString(); - xmlrpcdata["RegionUUID"] = region.ToString(); - xmlrpcdata["RegionHandle"] = regionHandle.ToString(); - ArrayList SendParams = new ArrayList(); - SendParams.Add(xmlrpcdata); - try - { - XmlRpcRequest LeavingRequest = new XmlRpcRequest("agent_leaving", SendParams); - XmlRpcResponse resp = LeavingRequest.Send(m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL, 5000); - - Hashtable responseData = (Hashtable)resp.Value; - if ((!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE") - { - m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent leaving for {0}", agentID.ToString()); - } - } - catch (WebException) - { - m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent leaving for {0}", agentID.ToString()); - } } } } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index d9a021f..55d4f14 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs @@ -39,7 +39,7 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer { - public class InventoryTransferModule : IInventoryTransferModule, IRegionModule + public class InventoryTransferModule : IInventoryTransferModule, ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -50,10 +50,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer new Dictionary(); private IMessageTransferModule m_TransferModule = null; + private bool m_Enabled = true; #region IRegionModule Members - public void Initialise(Scene scene, IConfigSource config) + public void Initialise(IConfigSource config) { if (config.Configs["Messaging"] != null) { @@ -62,29 +63,56 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer if (config.Configs["Messaging"].GetString( "InventoryTransferModule", "InventoryTransferModule") != "InventoryTransferModule") + { + m_Enabled = false; return; + } } + } - if (!m_Scenelist.Contains(scene)) - { - m_Scenelist.Add(scene); + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; - scene.RegisterModuleInterface(this); + m_Scenelist.Add(scene); - scene.EventManager.OnNewClient += OnNewClient; - scene.EventManager.OnClientClosed += ClientLoggedOut; - scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; - } + scene.RegisterModuleInterface(this); + + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnClientClosed += ClientLoggedOut; + scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; } - public void PostInitialise() + public void RegionLoaded(Scene scene) { - if (m_Scenelist.Count > 0) + if (m_TransferModule == null) { m_TransferModule = m_Scenelist[0].RequestModuleInterface(); if (m_TransferModule == null) + { m_log.Error("[INVENTORY TRANSFER] No Message transfer module found, transfers will be local only"); + m_Enabled = false; + + m_Scenelist.Clear(); + scene.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnClientClosed -= ClientLoggedOut; + scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; + } } + + } + + public void RemoveRegion(Scene scene) + { + scene.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnClientClosed -= ClientLoggedOut; + scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; + m_Scenelist.Remove(scene); + } + + public void PostInitialise() + { } public void Close() @@ -96,9 +124,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer get { return "InventoryModule"; } } - public bool IsSharedModule + public Type ReplaceableInterface { - get { return true; } + get { return null; } } #endregion diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs index 261bd6c..d1d7df2 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs @@ -37,34 +37,72 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.CoreModules.Avatar.Lure { - public class LureModule : IRegionModule + public class LureModule : ISharedRegionModule { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); private readonly List m_scenes = new List(); private IMessageTransferModule m_TransferModule = null; + private bool m_Enabled = true; - public void Initialise(Scene scene, IConfigSource config) + public void Initialise(IConfigSource config) { if (config.Configs["Messaging"] != null) { if (config.Configs["Messaging"].GetString( "LureModule", "LureModule") != "LureModule") - return; + m_Enabled = false; } + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; lock (m_scenes) { - if (!m_scenes.Contains(scene)) + m_scenes.Add(scene); + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnIncomingInstantMessage += + OnGridInstantMessage; + } + } + + public void RegionLoaded(Scene scene) + { + if (m_TransferModule == null) + { + m_TransferModule = + scene.RequestModuleInterface(); + + if (m_TransferModule == null) { - m_scenes.Add(scene); - scene.EventManager.OnNewClient += OnNewClient; - scene.EventManager.OnIncomingInstantMessage += + m_log.Error("[INSTANT MESSAGE]: No message transfer module, "+ + "lures will not work!"); + + m_Enabled = false; + m_scenes.Clear(); + scene.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; } } + + } + + public void RemoveRegion(Scene scene) + { + lock (m_scenes) + { + m_scenes.Remove(scene); + scene.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnIncomingInstantMessage -= + OnGridInstantMessage; + } } void OnNewClient(IClientAPI client) @@ -76,12 +114,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure public void PostInitialise() { - m_TransferModule = - m_scenes[0].RequestModuleInterface(); - - if (m_TransferModule == null) - m_log.Error("[INSTANT MESSAGE]: No message transfer module, "+ - "lures will not work!"); } public void Close() @@ -93,9 +125,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure get { return "LureModule"; } } - public bool IsSharedModule + public Type ReplaceableInterface { - get { return true; } + get { return null; } } public void OnInstantMessage(IClientAPI client, GridInstantMessage im) diff --git a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml index beb2307..40a13f4 100644 --- a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml +++ b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml @@ -17,6 +17,14 @@ + + + + + + + + diff --git a/OpenSim/Region/Framework/Interfaces/IPresenceModule.cs b/OpenSim/Region/Framework/Interfaces/IPresenceModule.cs index 630c6a3..d44c1e1 100644 --- a/OpenSim/Region/Framework/Interfaces/IPresenceModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IPresenceModule.cs @@ -31,13 +31,13 @@ namespace OpenSim.Region.Framework.Interfaces { public struct PresenceInfo { - public UUID userID; - public UUID regionID; + public string UserID; + public UUID RegionID; - public PresenceInfo(UUID userID, UUID regionID) + public PresenceInfo(string userID, UUID regionID) { - this.userID = userID; - this.regionID = regionID; + UserID = userID; + RegionID = regionID; } } -- cgit v1.1