diff --git a/OpenSim/Framework/GridInstantMessage.cs b/OpenSim/Framework/GridInstantMessage.cs
index 037f110dca..4ca4e67435 100644
--- a/OpenSim/Framework/GridInstantMessage.cs
+++ b/OpenSim/Framework/GridInstantMessage.cs
@@ -33,26 +33,60 @@ namespace OpenSim.Framework
[Serializable]
public class GridInstantMessage
{
- public byte[] binaryBucket;
- public byte dialog;
public Guid fromAgentID;
public string fromAgentName;
public Guid fromAgentSession;
+ public Guid toAgentID;
+ public byte dialog;
public bool fromGroup;
- public Guid imSessionID;
-
public string message;
+ public Guid imSessionID;
public byte offline;
+ public Vector3 Position;
+ public byte[] binaryBucket;
+
public uint ParentEstateID;
-
- public Vector3 Position;
-
public Guid RegionID;
public uint timestamp;
- public Guid toAgentID;
public GridInstantMessage()
+ {
+ binaryBucket = new byte[0];
+ }
+
+ public GridInstantMessage(IScene scene, UUID _fromAgentID,
+ string _fromAgentName, UUID _fromAgentSession, UUID _toAgentID,
+ byte _dialog, bool _fromGroup, string _message,
+ UUID _imSessionID, bool _offline, Vector3 _position,
+ byte[] _binaryBucket)
+ {
+ fromAgentID = _fromAgentID.Guid;
+ fromAgentName = _fromAgentName;
+ fromAgentSession = _fromAgentSession.Guid;
+ toAgentID = _toAgentID.Guid;
+ dialog = _dialog;
+ fromGroup = _fromGroup;
+ message = _message;
+ imSessionID = _imSessionID.Guid;
+ if (_offline)
+ offline = 1;
+ else
+ offline = 0;
+ Position = _position;
+ binaryBucket = _binaryBucket;
+
+ ParentEstateID = scene.RegionInfo.EstateSettings.ParentEstateID;
+ RegionID = scene.RegionInfo.RegionSettings.RegionUUID.Guid;
+ timestamp = (uint)Util.UnixTimeSinceEpoch();
+ }
+
+ public GridInstantMessage(IScene scene, UUID _fromAgentID,
+ string _fromAgentName, UUID _toAgentID, byte _dialog,
+ string _message, bool _offline,
+ Vector3 _position) : this(scene, _fromAgentID, _fromAgentName,
+ UUID.Zero, _toAgentID, _dialog, false, _message,
+ _fromAgentID ^ _toAgentID, _offline, _position, new byte[0])
{
}
}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index ea82a374f6..3aa3fea273 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -4023,6 +4023,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
break;
case PacketType.ImprovedInstantMessage:
ImprovedInstantMessagePacket msgpack = (ImprovedInstantMessagePacket)Pack;
+ Console.WriteLine(msgpack.ToString());
string IMfromName = Util.FieldToString(msgpack.MessageBlock.FromAgentName);
string IMmessage = Utils.BytesToString(msgpack.MessageBlock.Message);
handlerInstantMessage = OnInstantMessage;
@@ -6171,7 +6172,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
case PacketType.ObjectBuy:
ObjectBuyPacket objectBuyPacket = (ObjectBuyPacket)Pack;
handlerObjectBuy = OnObjectBuy;
- Console.WriteLine(objectBuyPacket.ToString());
+
if (handlerObjectBuy != null)
{
foreach (ObjectBuyPacket.ObjectDataBlock d
diff --git a/OpenSim/Region/Environment/InstantMessageReceiver.cs b/OpenSim/Region/Environment/InstantMessageReceiver.cs
deleted file mode 100644
index d82bffcfbd..0000000000
--- a/OpenSim/Region/Environment/InstantMessageReceiver.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * 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.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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;
-
-namespace OpenSim.Region.Environment
-{
- ///
- /// Bit Vector for Which Modules to send an instant message to from the Scene or an Associated Module
- ///
-
- // This prevents the Modules from sending Instant messages to other modules through the scene
- // and then receiving the same messages
-
- // This is mostly here because on LLSL and the SecondLife Client, IMs,Groups and friends are linked
- // inseparably
-
- [Flags]
- public enum InstantMessageReceiver : uint
- {
- /// None of them.. here for posterity and amusement
- None = 0,
- /// The IM Module
- IMModule = 0x00000001,
- /// The Friends Module
- FriendsModule = 0x00000002,
- /// The Groups Module
- GroupsModule = 0x00000004
- }
-}
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs
index 58251cbb4a..72c64add0a 100644
--- a/OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs
@@ -36,6 +36,7 @@ using Nwc.XmlRpc;
using OpenSim.Framework;
using OpenSim.Framework.Communications.Cache;
using OpenSim.Framework.Servers;
+using OpenSim.Region.Interfaces;
using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
@@ -105,6 +106,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Friends
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;
#region IRegionModule Members
@@ -124,7 +126,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Friends
m_scenes[scene.RegionInfo.RegionHandle] = scene;
}
scene.EventManager.OnNewClient += OnNewClient;
- scene.EventManager.OnGridInstantMessage += OnGridInstantMessage;
+ scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
scene.EventManager.OnMakeChildAgent += MakeChildAgent;
scene.EventManager.OnClientClosed += ClientClosed;
@@ -132,6 +134,10 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Friends
public void PostInitialise()
{
+ List scenes = new List(m_scenes.Values);
+ m_TransferModule = scenes[0].RequestModuleInterface();
+ if (m_TransferModule == null)
+ m_log.Error("[FRIENDS]: Unable to find a message transfer module, friendship offers will not work");
}
public void Close()
@@ -434,11 +440,14 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Friends
// we don't want to get that new IM into here if we aren't local, as only on the destination
// should receive it. If we *are* local, *we* are the destination, so we have to receive it.
// As grid-IMs are routed to all modules (in contrast to local IMs), we have to decide here.
- InstantMessageReceiver recv = InstantMessageReceiver.IMModule;
- if (GetAnyPresenceFromAgentID(toAgentID) != null) recv |= InstantMessageReceiver.FriendsModule;
// We don't really care which local scene we pipe it through.
- m_initialScene.TriggerGridInstantMessage(msg, recv);
+ if (m_TransferModule != null)
+ {
+ m_TransferModule.SendInstantMessage(msg,
+ delegate(bool success) {}
+ );
+ }
}
else
{
@@ -531,17 +540,20 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Friends
}
}
- private void OnGridInstantMessage(GridInstantMessage msg, InstantMessageReceiver whichModule)
+ private void OnGridInstantMessage(GridInstantMessage msg)
{
- if ((whichModule & InstantMessageReceiver.FriendsModule) == 0)
- return;
-
- // Trigger the above event handler
- OnInstantMessage(null, new UUID(msg.fromAgentID), new UUID(msg.fromAgentSession),
- new UUID(msg.toAgentID), new UUID(msg.imSessionID), msg.timestamp, msg.fromAgentName,
- msg.message, msg.dialog, msg.fromGroup, msg.offline, msg.ParentEstateID,
- new Vector3(msg.Position.X, msg.Position.Y, msg.Position.Z), new UUID(msg.RegionID),
- msg.binaryBucket);
+ // Just call the IM handler above
+ // 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
+ //
+ OnInstantMessage(null, new UUID(msg.fromAgentID),
+ new UUID(msg.fromAgentSession),
+ new UUID(msg.toAgentID), new UUID(msg.imSessionID),
+ msg.timestamp, msg.fromAgentName, msg.message,
+ msg.dialog, msg.fromGroup, msg.offline,
+ msg.ParentEstateID, msg.Position,
+ new UUID(msg.RegionID), msg.binaryBucket);
}
private void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID transactionID, List callingCardFolders)
@@ -607,12 +619,15 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Friends
// we don't want to get that new IM into here if we aren't local, as only on the destination
// should receive it. If we *are* local, *we* are the destination, so we have to receive it.
// As grid-IMs are routed to all modules (in contrast to local IMs), we have to decide here.
- InstantMessageReceiver recv = InstantMessageReceiver.IMModule;
- if (GetAnyPresenceFromAgentID(friendID) != null) recv |= InstantMessageReceiver.FriendsModule;
// now we have to inform the agent about the friend. For the opposite direction, this happens in the handler
// of the type 39 IM
- SceneAgentIn.TriggerGridInstantMessage(msg, recv);
+ if (m_TransferModule != null)
+ {
+ m_TransferModule.SendInstantMessage(msg,
+ delegate(bool success) {}
+ );
+ }
// tell client that new friend is online
client.SendAgentOnline(new UUID[] { friendID });
@@ -664,12 +679,15 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Friends
// we don't want to get that new IM into here if we aren't local, as only on the destination
// should receive it. If we *are* local, *we* are the destination, so we have to receive it.
// As grid-IMs are routed to all modules (in contrast to local IMs), we have to decide here.
- InstantMessageReceiver recv = InstantMessageReceiver.IMModule;
- if (GetAnyPresenceFromAgentID(friendID) != null) recv |= InstantMessageReceiver.FriendsModule;
// now we have to inform the agent about the friend. For the opposite direction, this happens in the handler
// of the type 39 IM
- SceneAgentIn.TriggerGridInstantMessage(msg, recv);
+ if (m_TransferModule != null)
+ {
+ m_TransferModule.SendInstantMessage(msg,
+ delegate(bool success) {}
+ );
+ }
}
private void OnTerminateFriendship(IClientAPI client, UUID agentID, UUID exfriendID)
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Groups/GroupsModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Groups/GroupsModule.cs
index d9a5393232..c291c169df 100644
--- a/OpenSim/Region/Environment/Modules/Avatar/Groups/GroupsModule.cs
+++ b/OpenSim/Region/Environment/Modules/Avatar/Groups/GroupsModule.cs
@@ -99,7 +99,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Groups
scene.EventManager.OnNewClient += OnNewClient;
scene.EventManager.OnClientClosed += OnClientClosed;
- scene.EventManager.OnGridInstantMessage +=
+ scene.EventManager.OnIncomingInstantMessage +=
OnGridInstantMessage;
}
@@ -187,11 +187,8 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Groups
{
}
- private void OnGridInstantMessage(GridInstantMessage msg, InstantMessageReceiver whichModule)
+ private void OnGridInstantMessage(GridInstantMessage msg)
{
- if ((whichModule & InstantMessageReceiver.GroupsModule) == 0)
- return;
-
// Trigger the above event handler
OnInstantMessage(null, new UUID(msg.fromAgentID),
new UUID(msg.fromAgentSession),
diff --git a/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs b/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs
index 805f7cb8b2..1b7eb97eb5 100644
--- a/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs
+++ b/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs
@@ -36,6 +36,7 @@ using Nini.Config;
using Nwc.XmlRpc;
using OpenSim.Framework;
using OpenSim.Framework.Client;
+using OpenSim.Region.Interfaces;
using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
@@ -46,12 +47,12 @@ namespace OpenSim.Region.Environment.Modules.Avatar.InstantMessage
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private readonly List m_scenes = new List();
- private Dictionary m_userRegionMap = new Dictionary();
#region IRegionModule Members
private bool gridmode = false;
+ private IMessageTransferModule m_TransferModule = null;
public void Initialise(Scene scene, IConfigSource config)
{
@@ -65,18 +66,11 @@ namespace OpenSim.Region.Environment.Modules.Avatar.InstantMessage
lock (m_scenes)
{
- if (m_scenes.Count == 0)
- {
- //scene.AddXmlRPCHandler("avatar_location_update", processPresenceUpdate);
- scene.AddXmlRPCHandler("grid_instant_message", processXMLRPCGridInstantMessage);
- ReadConfig(config);
- }
-
if (!m_scenes.Contains(scene))
{
m_scenes.Add(scene);
scene.EventManager.OnClientConnect += OnClientConnect;
- scene.EventManager.OnGridInstantMessage += OnGridInstantMessage;
+ scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
}
}
}
@@ -90,17 +84,14 @@ namespace OpenSim.Region.Environment.Modules.Avatar.InstantMessage
}
}
- private void ReadConfig(IConfigSource config)
- {
- IConfig cnf = config.Configs["Startup"];
- if (cnf != null)
- {
- gridmode = cnf.GetBoolean("gridmode", false);
- }
- }
-
public void PostInitialise()
{
+ 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()
@@ -120,639 +111,71 @@ namespace OpenSim.Region.Environment.Modules.Avatar.InstantMessage
#endregion
private void OnInstantMessage(IClientAPI client, UUID fromAgentID,
- UUID fromAgentSession, UUID toAgentID,
- UUID imSessionID, uint timestamp, string fromAgentName,
- string message, byte dialog, bool fromGroup, byte offline,
- uint ParentEstateID, Vector3 Position, UUID RegionID,
- byte[] binaryBucket)
+ UUID fromAgentSession, UUID toAgentID,
+ UUID imSessionID, uint timestamp, string fromAgentName,
+ string message, byte dialog, bool fromGroup, byte offline,
+ uint ParentEstateID, Vector3 Position, UUID RegionID,
+ byte[] binaryBucket)
{
- bool dialogHandledElsewhere
- = ( dialog == (byte) InstantMessageDialog.FriendshipOffered
- || dialog == (byte) InstantMessageDialog.FriendshipAccepted
- || dialog == (byte) InstantMessageDialog.FriendshipDeclined
- || dialog == (byte) InstantMessageDialog.InventoryOffered
- || dialog == (byte) InstantMessageDialog.InventoryAccepted
- || dialog == (byte) InstantMessageDialog.InventoryDeclined
- || dialog == (byte) InstantMessageDialog.GroupNoticeInventoryAccepted
- || dialog == (byte) InstantMessageDialog.GroupNoticeInventoryDeclined
- || dialog == (byte) InstantMessageDialog.GroupInvitationAccept
- || dialog == (byte) InstantMessageDialog.GroupInvitationDecline
- || dialog == (byte) InstantMessageDialog.GroupNotice);
-
- // IM dialogs need to be pre-processed and have their sessionID filled by the server
- // so the sim can match the transaction on the return packet.
-
- // Don't process IMs that are handled elsewhere (e.g. friend dialog
- // IMs) with a non-UUID.Zero agent session, as those have been send
- // by a client (either directly or from another region via
- // inter-region communication) and will be processed in another
- // module (e.g. the friends-module).
- // IMs with fromAgentSession == UUID.Zero come from the server, and
- // have to be passed to the matching viewer
- if (!dialogHandledElsewhere || fromAgentSession == UUID.Zero)
+ // This module handles exclusively private text IM from user
+ // to user. All others will be caught in other modules
+ //
+ if ( dialog != (byte)InstantMessageDialog.MessageFromAgent
+ && dialog != (byte)InstantMessageDialog.StartTyping
+ && dialog != (byte)InstantMessageDialog.StopTyping)
{
- // Try root avatar only first
- foreach (Scene scene in m_scenes)
- {
- if (scene.Entities.ContainsKey(toAgentID) && scene.Entities[toAgentID] is ScenePresence)
- {
- // Local message
- ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
- if (!user.IsChildAgent)
- {
- user.ControllingClient.SendInstantMessage(fromAgentID, message,
- toAgentID, fromAgentName, dialog,
- timestamp, imSessionID, fromGroup, binaryBucket);
- // Message sent
- return;
- }
- }
- }
-
- // try child avatar second
- foreach (Scene scene in m_scenes)
- {
- if (scene.Entities.ContainsKey(toAgentID) && scene.Entities[toAgentID] is ScenePresence)
- {
- // Local message
- ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
-
- user.ControllingClient.SendInstantMessage(fromAgentID, message,
- toAgentID, fromAgentName, dialog,
- timestamp, imSessionID, fromGroup, binaryBucket);
- // Message sent
- return;
- }
- }
- if (gridmode)
- {
- // Still here, try send via Grid
-
- // don't send session drop yet, as it's not reliable somehow.
- if (dialog != (byte)InstantMessageDialog.SessionDrop)
- {
- SendGridInstantMessageViaXMLRPC(client, fromAgentID,
- fromAgentSession, toAgentID,
- imSessionID, timestamp, fromAgentName,
- message, dialog, fromGroup, offline,
- ParentEstateID, Position, RegionID,
- binaryBucket, getLocalRegionHandleFromUUID(RegionID), 0);
- }
- }
- else
- {
- if (client != null)
- {
- if (dialog != (byte)InstantMessageDialog.StartTyping && dialog != (byte)InstantMessageDialog.StopTyping && dialog != (byte)InstantMessageDialog.SessionDrop)
- client.SendInstantMessage(toAgentID, "Unable to send instant message. User is not logged in.", fromAgentID, "System", (byte)InstantMessageDialog.BusyAutoResponse, (uint)Util.UnixTimeSinceEpoch());// SendAlertMessage("Unable to send instant message");
- }
- }
+ return;
}
+ GridInstantMessage im = new GridInstantMessage(client.Scene,
+ fromAgentID, fromAgentName, fromAgentSession, toAgentID,
+ dialog, fromGroup, message, imSessionID,
+ offline != 0 ? true : false, Position,
+ binaryBucket);
+ if (m_TransferModule != null)
+ {
+ m_TransferModule.SendInstantMessage(im,
+ delegate(bool success)
+ {
+ if (dialog == (uint)InstantMessageDialog.StartTyping ||
+ dialog == (uint)InstantMessageDialog.StopTyping)
+ {
+ return;
+ }
+
+ if ((client != null) && !success)
+ {
+ client.SendInstantMessage(toAgentID,
+ "Unable to send instant message. "+
+ "User is not logged in.",
+ fromAgentID, "System",
+ (byte)InstantMessageDialog.BusyAutoResponse,
+ (uint)Util.UnixTimeSinceEpoch());
+ }
+ }
+ );
+ }
}
- // Trusty OSG1 called method. This method also gets called from the FriendsModule
- // Turns out the sim has to send an instant message to the user to get it to show an accepted friend.
///
///
///
///
- private void OnGridInstantMessage(GridInstantMessage msg, InstantMessageReceiver which)
+ private void OnGridInstantMessage(GridInstantMessage msg)
{
- if ((which & InstantMessageReceiver.IMModule) == 0)
- return;
-
- // Trigger the above event handler
- OnInstantMessage(null, new UUID(msg.fromAgentID), new UUID(msg.fromAgentSession),
- new UUID(msg.toAgentID), new UUID(msg.imSessionID), msg.timestamp, msg.fromAgentName,
- msg.message, msg.dialog, msg.fromGroup, msg.offline, msg.ParentEstateID,
- new Vector3(msg.Position.X, msg.Position.Y, msg.Position.Z), new UUID(msg.RegionID),
- msg.binaryBucket);
+ // Just call the Text IM handler above
+ // 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
+ //
+ OnInstantMessage(null, new UUID(msg.fromAgentID),
+ new UUID(msg.fromAgentSession),
+ new UUID(msg.toAgentID), new UUID(msg.imSessionID),
+ msg.timestamp, msg.fromAgentName, msg.message,
+ msg.dialog, msg.fromGroup, msg.offline,
+ msg.ParentEstateID, msg.Position,
+ new UUID(msg.RegionID), msg.binaryBucket);
}
-
-
- ///
- /// Process a XMLRPC Grid Instant Message
- ///
- /// XMLRPC parameters from_agent_id from_agent_session to_agent_id im_session_id timestamp
- /// from_agent_name message dialog from_group offline parent_estate_id position_x position_y position_z region_id
- /// binary_bucket region_handle
- /// Nothing much
- protected virtual XmlRpcResponse processXMLRPCGridInstantMessage(XmlRpcRequest request)
- {
- bool successful = false;
- // various rational defaults
- UUID fromAgentID = UUID.Zero;
- UUID fromAgentSession = UUID.Zero;
- UUID toAgentID = UUID.Zero;
- UUID imSessionID = UUID.Zero;
- uint timestamp = 0;
- string fromAgentName = "";
- string message = "";
- byte dialog = (byte)0;
- bool fromGroup = false;
- byte offline = (byte)0;
- uint ParentEstateID=0;
- Vector3 Position = Vector3.Zero;
- UUID RegionID = UUID.Zero ;
- byte[] binaryBucket = new byte[0];
-
- float pos_x = 0;
- float pos_y = 0;
- float pos_z = 0;
- //m_log.Info("Processing IM");
-
-
- Hashtable requestData = (Hashtable)request.Params[0];
- // Check if it's got all the data
- if (requestData.ContainsKey("from_agent_id") && requestData.ContainsKey("from_agent_session")
- && requestData.ContainsKey("to_agent_id") && requestData.ContainsKey("im_session_id")
- && requestData.ContainsKey("timestamp") && requestData.ContainsKey("from_agent_name")
- && requestData.ContainsKey("message") && requestData.ContainsKey("dialog")
- && requestData.ContainsKey("from_group")
- && requestData.ContainsKey("offline") && requestData.ContainsKey("parent_estate_id")
- && requestData.ContainsKey("position_x") && requestData.ContainsKey("position_y")
- && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id")
- && requestData.ContainsKey("binary_bucket") && requestData.ContainsKey("region_handle"))
- {
- // Do the easy way of validating the UUIDs
- UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID);
- UUID.TryParse((string)requestData["from_agent_session"], out fromAgentSession);
- UUID.TryParse((string)requestData["to_agent_id"], out toAgentID);
- UUID.TryParse((string)requestData["im_session_id"], out imSessionID);
- UUID.TryParse((string)requestData["region_id"], out RegionID);
-
- # region timestamp
- try
- {
- timestamp = (uint)Convert.ToInt32((string)requestData["timestamp"]);
- }
- catch (ArgumentException)
- {
- }
- catch (FormatException)
- {
- }
- catch (OverflowException)
- {
- }
- # endregion
-
- fromAgentName = (string)requestData["from_agent_name"];
- message = (string)requestData["message"];
-
- // Bytes don't transfer well over XMLRPC, so, we Base64 Encode them.
- string requestData1 = (string)requestData["dialog"];
- if (string.IsNullOrEmpty(requestData1))
- {
- dialog = 0;
- }
- else
- {
- byte[] dialogdata = Convert.FromBase64String(requestData1);
- dialog = dialogdata[0];
- }
-
- if ((string)requestData["from_group"] == "TRUE")
- fromGroup = true;
-
- string requestData2 = (string)requestData["offline"];
- if (String.IsNullOrEmpty(requestData2))
- {
- offline = 0;
- }
- else
- {
- byte[] offlinedata = Convert.FromBase64String(requestData2);
- offline = offlinedata[0];
- }
-
- # region ParentEstateID
- try
- {
- ParentEstateID = (uint)Convert.ToInt32((string)requestData["parent_estate_id"]);
- }
- catch (ArgumentException)
- {
- }
- catch (FormatException)
- {
- }
- catch (OverflowException)
- {
- }
- # endregion
-
- # region pos_x
- try
- {
- pos_x = (uint)Convert.ToInt32((string)requestData["position_x"]);
- }
- catch (ArgumentException)
- {
- }
- catch (FormatException)
- {
- }
- catch (OverflowException)
- {
- }
- # endregion
- # region pos_y
- try
- {
- pos_y = (uint)Convert.ToInt32((string)requestData["position_y"]);
- }
- catch (ArgumentException)
- {
- }
- catch (FormatException)
- {
- }
- catch (OverflowException)
- {
- }
- # endregion
- # region pos_z
- try
- {
- pos_z = (uint)Convert.ToInt32((string)requestData["position_z"]);
- }
- catch (ArgumentException)
- {
- }
- catch (FormatException)
- {
- }
- catch (OverflowException)
- {
- }
- # endregion
-
- Position = new Vector3(pos_x, pos_y, pos_z);
-
- string requestData3 = (string)requestData["binary_bucket"];
- if (string.IsNullOrEmpty(requestData3))
- {
- binaryBucket = new byte[0];
- }
- else
- {
- binaryBucket = Convert.FromBase64String(requestData3);
- }
-
- // Create a New GridInstantMessageObject the the data
- GridInstantMessage gim = new GridInstantMessage();
- gim.fromAgentID = fromAgentID.Guid;
- gim.fromAgentName = fromAgentName;
- gim.fromAgentSession = fromAgentSession.Guid;
- gim.fromGroup = fromGroup;
- gim.imSessionID = imSessionID.Guid;
- gim.RegionID = RegionID.Guid;
- gim.timestamp = timestamp;
- gim.toAgentID = toAgentID.Guid;
- gim.message = message;
- gim.dialog = dialog;
- gim.offline = offline;
- gim.ParentEstateID = ParentEstateID;
- gim.Position = Position;
- gim.binaryBucket = binaryBucket;
-
-
- // Trigger the Instant message in the scene.
- foreach (Scene scene in m_scenes)
- {
- if (scene.Entities.ContainsKey(toAgentID) && scene.Entities[toAgentID] is ScenePresence)
- {
- // Local message
- ScenePresence user = (ScenePresence)scene.Entities[toAgentID];
- if (!user.IsChildAgent)
- {
- scene.EventManager.TriggerGridInstantMessage(gim, InstantMessageReceiver.FriendsModule | InstantMessageReceiver.GroupsModule | InstantMessageReceiver.IMModule);
- successful = true;
- }
- }
- }
- //OnGridInstantMessage(gim);
-
- }
-
- //Send response back to region calling if it was successful
- // calling region uses this to know when to look up a user's location again.
- XmlRpcResponse resp = new XmlRpcResponse();
- Hashtable respdata = new Hashtable();
- if (successful)
- respdata["success"] = "TRUE";
- else
- respdata["success"] = "FALSE";
- resp.Value = respdata;
-
- return resp;
- }
-
- #region Asynchronous setup
- ///
- /// delegate for sending a grid instant message asynchronously
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public delegate void GridInstantMessageDelegate(IClientAPI client, UUID fromAgentID,
- UUID fromAgentSession, UUID toAgentID,
- UUID imSessionID, uint timestamp, string fromAgentName,
- string message, byte dialog, bool fromGroup, byte offline,
- uint ParentEstateID, Vector3 Position, UUID RegionID,
- byte[] binaryBucket, ulong regionhandle, ulong prevRegionHandle);
-
- private void GridInstantMessageCompleted(IAsyncResult iar)
- {
- GridInstantMessageDelegate icon = (GridInstantMessageDelegate)iar.AsyncState;
- icon.EndInvoke(iar);
- }
-
-
- protected virtual void SendGridInstantMessageViaXMLRPC(IClientAPI client, UUID fromAgentID,
- UUID fromAgentSession, UUID toAgentID,
- UUID imSessionID, uint timestamp, string fromAgentName,
- string message, byte dialog, bool fromGroup, byte offline,
- uint ParentEstateID, Vector3 Position, UUID RegionID,
- byte[] binaryBucket, ulong regionhandle, ulong prevRegionHandle)
- {
- GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync;
-
- d.BeginInvoke(client,fromAgentID,
- fromAgentSession,toAgentID,
- imSessionID,timestamp, fromAgentName,
- message, dialog, fromGroup, offline,
- ParentEstateID, Position, RegionID,
- binaryBucket, regionhandle, prevRegionHandle,
- GridInstantMessageCompleted,
- d);
- }
-
- #endregion
-
-
- ///
- /// Recursive SendGridInstantMessage over XMLRPC method. The prevRegionHandle contains the last regionhandle tried
- /// if it's the same as the user's looked up region handle, then we end the recursive loop
- ///
- ///
- protected virtual void SendGridInstantMessageViaXMLRPCAsync(IClientAPI client, UUID fromAgentID,
- UUID fromAgentSession, UUID toAgentID,
- UUID imSessionID, uint timestamp, string fromAgentName,
- string message, byte dialog, bool fromGroup, byte offline,
- uint ParentEstateID, Vector3 Position, UUID RegionID,
- byte[] binaryBucket, ulong regionhandle, ulong prevRegionHandle)
- {
- UserAgentData upd = null;
-
- bool lookupAgent = false;
-
- lock (m_userRegionMap)
- {
- if (m_userRegionMap.ContainsKey(toAgentID) && prevRegionHandle == 0)
- {
- upd = new UserAgentData();
- upd.AgentOnline = true;
- upd.Handle = m_userRegionMap[toAgentID];
-
- }
- else
- {
- lookupAgent = true;
-
-
- }
- }
-
- // Are we needing to look-up an agent?
- if (lookupAgent)
- {
- // Non-cached user agent lookup.
- upd = m_scenes[0].CommsManager.UserService.GetAgentByUUID(toAgentID);
-
- if (upd != null)
- {
- // check if we've tried this before.. This is one way to end the recursive loop
- if (upd.Handle == prevRegionHandle)
- {
- m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
- if (client != null)
- {
- if (dialog != (byte)InstantMessageDialog.StartTyping && dialog != (byte)InstantMessageDialog.StopTyping && dialog != (byte)InstantMessageDialog.SessionDrop)
- client.SendInstantMessage(toAgentID, "Unable to send instant message", fromAgentID, "System", (byte)InstantMessageDialog.BusyAutoResponse, (uint)Util.UnixTimeSinceEpoch());
- }
- return;
- }
- }
- else
- {
- m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
- if (client != null)
- {
- if (dialog != (byte)InstantMessageDialog.StartTyping && dialog != (byte)InstantMessageDialog.StopTyping && dialog != (byte)InstantMessageDialog.SessionDrop)
- client.SendInstantMessage(toAgentID, "Unable to send instant message", fromAgentID, "System", (byte)InstantMessageDialog.BusyAutoResponse, (uint)Util.UnixTimeSinceEpoch());
- }
- return;
- }
- }
-
- if (upd != null)
- {
- if (upd.AgentOnline)
- {
- RegionInfo reginfo = m_scenes[0].SceneGridService.RequestNeighbouringRegionInfo(upd.Handle);
- if (reginfo != null)
- {
- GridInstantMessage msg = new GridInstantMessage();
- msg.fromAgentID = fromAgentID.Guid;
- msg.fromAgentSession = fromAgentSession.Guid;
- msg.toAgentID = toAgentID.Guid;
- msg.imSessionID = imSessionID.Guid;
- msg.timestamp = timestamp;
- msg.fromAgentName = fromAgentName;
- msg.message = message;
- msg.dialog = dialog;
- msg.fromGroup = fromGroup;
- msg.offline = offline;
- msg.ParentEstateID = ParentEstateID;
- msg.Position = Position;
- msg.RegionID = RegionID.Guid;
- msg.binaryBucket = binaryBucket;
-
- Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(msg);
- msgdata["region_handle"] = getLocalRegionHandleFromUUID(RegionID);
- bool imresult = doIMSending(reginfo, msgdata);
- if (imresult)
- {
- // IM delivery successful, so store the Agent's location in our local cache.
- lock (m_userRegionMap)
- {
- if (m_userRegionMap.ContainsKey(toAgentID))
- {
- m_userRegionMap[toAgentID] = upd.Handle;
- }
- else
- {
- m_userRegionMap.Add(toAgentID, upd.Handle);
- }
- }
- //m_log.Info("[GRID INSTANT MESSAGE]: Successfully sent a message");
- }
- else
- {
- // try again, but lookup user this time.
- // Warning, this must call the Async version
- // of this method or we'll be making thousands of threads
- // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync
- // The version that spawns the thread is SendGridInstantMessageViaXMLRPC
-
- // This is recursive!!!!!
- SendGridInstantMessageViaXMLRPCAsync(client, fromAgentID,
- fromAgentSession, toAgentID,
- imSessionID, timestamp, fromAgentName,
- message, dialog, fromGroup, offline,
- ParentEstateID, Position, RegionID,
- binaryBucket, regionhandle, upd.Handle);
- }
-
- }
- }
- else
- {
- // send Agent Offline message
- if (client != null)
- {
- if (dialog != (byte)InstantMessageDialog.StartTyping && dialog != (byte)InstantMessageDialog.StopTyping && dialog != (byte)InstantMessageDialog.SessionDrop)
- client.SendInstantMessage(toAgentID, "Unable to send instant message: Agent Offline", fromAgentID, "System", (byte)InstantMessageDialog.BusyAutoResponse, (uint)Util.UnixTimeSinceEpoch());// SendAlertMessage("Unable to send instant message");
- }
- }
- }
- else
- {
- // send Agent doesn't exist message
- if (client != null)
- client.SendInstantMessage(toAgentID, "Unable to send instant message: Are you sure this agent exists anymore?", fromAgentID, "System", (byte)InstantMessageDialog.MessageFromObject, (uint)Util.UnixTimeSinceEpoch());// SendAlertMessage("Unable to send instant message");
- }
-
- }
-
- ///
- /// This actually does the XMLRPC Request
- ///
- /// RegionInfo we pull the data out of to send the request to
- /// The Instant Message data Hashtable
- /// Bool if the message was successfully delivered at the other side.
- private bool doIMSending(RegionInfo reginfo, Hashtable xmlrpcdata)
- {
-
- ArrayList SendParams = new ArrayList();
- SendParams.Add(xmlrpcdata);
- XmlRpcRequest GridReq = new XmlRpcRequest("grid_instant_message", SendParams);
- try
- {
-
- XmlRpcResponse GridResp = GridReq.Send("http://" + reginfo.ExternalHostName + ":" + reginfo.HttpPort, 3000);
-
- Hashtable responseData = (Hashtable)GridResp.Value;
-
- if (responseData.ContainsKey("success"))
- {
- if ((string)responseData["success"] == "TRUE")
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- catch (WebException e)
- {
- m_log.ErrorFormat("[GRID INSTANT MESSAGE]: Error sending message to http://{0}:{1} the host didn't respond ({2})",
- reginfo.ExternalHostName, reginfo.HttpPort, e.Message);
- }
-
- return false;
- }
-
- ///
- /// Get ulong region handle for region by it's Region UUID.
- /// We use region handles over grid comms because there's all sorts of free and cool caching.
- ///
- /// UUID of region to get the region handle for
- ///
- private ulong getLocalRegionHandleFromUUID(UUID regionID)
- {
- ulong returnhandle = 0;
-
- lock (m_scenes)
- {
- foreach (Scene sn in m_scenes)
- {
- if (sn.RegionInfo.RegionID == regionID)
- {
- returnhandle = sn.RegionInfo.RegionHandle;
- break;
- }
- }
- }
- return returnhandle;
- }
-
- ///
- /// Takes a GridInstantMessage and converts it into a Hashtable for XMLRPC
- ///
- /// The GridInstantMessage object
- /// Hashtable containing the XMLRPC request
- private Hashtable ConvertGridInstantMessageToXMLRPC(GridInstantMessage msg)
- {
- Hashtable gim = new Hashtable();
- gim["from_agent_id"] = msg.fromAgentID.ToString();
- gim["from_agent_session"] = msg.fromAgentSession.ToString();
- gim["to_agent_id"] = msg.toAgentID.ToString();
- gim["im_session_id"] = msg.imSessionID.ToString();
- gim["timestamp"] = msg.timestamp.ToString();
- gim["from_agent_name"] = msg.fromAgentName;
- gim["message"] = msg.message;
- byte[] dialogdata = new byte[1];dialogdata[0] = msg.dialog;
- gim["dialog"] = Convert.ToBase64String(dialogdata,Base64FormattingOptions.None);
-
- if (msg.fromGroup)
- gim["from_group"] = "TRUE";
- else
- gim["from_group"] = "FALSE";
- byte[] offlinedata = new byte[1]; offlinedata[0] = msg.offline;
- gim["offline"] = Convert.ToBase64String(offlinedata, Base64FormattingOptions.None);
- gim["parent_estate_id"] = msg.ParentEstateID.ToString();
- gim["position_x"] = msg.Position.X.ToString();
- gim["position_y"] = msg.Position.Y.ToString();
- gim["position_z"] = msg.Position.Z.ToString();
- gim["region_id"] = msg.RegionID.ToString();
- gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None);
- return gim;
- }
-
}
}
diff --git a/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/MessageTransferModule.cs
new file mode 100644
index 0000000000..d1543a0872
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/MessageTransferModule.cs
@@ -0,0 +1,626 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * 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.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Net;
+using System.Threading;
+using OpenMetaverse;
+using log4net;
+using Nini.Config;
+using Nwc.XmlRpc;
+using OpenSim.Framework;
+using OpenSim.Framework.Client;
+using OpenSim.Region.Interfaces;
+using OpenSim.Region.Environment.Interfaces;
+using OpenSim.Region.Environment.Scenes;
+
+namespace OpenSim.Region.Environment.Modules.Avatar.InstantMessage
+{
+ public class MessageTransferModule : IRegionModule, IMessageTransferModule
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ private bool m_Enabled = false;
+ private bool m_Gridmode = false;
+ private List m_Scenes = new List();
+ private Dictionary m_UserRegionMap = new Dictionary();
+
+ public void Initialise(Scene scene, IConfigSource config)
+ {
+ if (config.Configs["Messaging"] != null)
+ {
+ IConfig cnf = config.Configs["Messaging"];
+ if (cnf == null || cnf.GetString(
+ "MessageTransferModule", "MessageTransferModule") !=
+ "MessageTransferModule")
+ return;
+
+ cnf = config.Configs["Startup"];
+ if (cnf != null)
+ m_Gridmode = cnf.GetBoolean("m_Gridmode", false);
+
+ m_Enabled = true;
+ }
+
+ lock (m_Scenes)
+ {
+ if (m_Scenes.Count == 0)
+ {
+ scene.AddXmlRPCHandler("grid_instant_message", processXMLRPCGridInstantMessage);
+ scene.RegisterModuleInterface(this);
+ }
+
+ m_Scenes.Add(scene);
+ }
+ }
+
+ public void PostInitialise()
+ {
+ }
+
+ public void Close()
+ {
+ }
+
+ public string Name
+ {
+ get { return "MessageTransferModule"; }
+ }
+
+ public bool IsSharedModule
+ {
+ get { return true; }
+ }
+
+ public void SendInstantMessage(GridInstantMessage im, MessageResultNotification result)
+ {
+ UUID toAgentID = new UUID(im.toAgentID);
+
+ m_log.DebugFormat("[INSTANT MESSAGE]: Attempting delivery of IM fromn {0} to {1}", im.fromAgentName, toAgentID.ToString());
+
+ // Try root avatar only first
+ foreach (Scene scene in m_Scenes)
+ {
+ if (scene.Entities.ContainsKey(toAgentID) &&
+ scene.Entities[toAgentID] is ScenePresence)
+ {
+ m_log.DebugFormat("[INSTANT MESSAGE]: Looking for {0} in {1}", toAgentID.ToString(), scene.RegionInfo.RegionName);
+ // Local message
+ ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
+ if (!user.IsChildAgent)
+ {
+ m_log.DebugFormat("[INSTANT MESSAGE]: Delivering to client");
+ user.ControllingClient.SendInstantMessage(
+ new UUID(im.fromAgentID),
+ im.message,
+ new UUID(im.toAgentID),
+ im.fromAgentName,
+ im.dialog,
+ im.timestamp,
+ new UUID(im.imSessionID),
+ im.fromGroup,
+ im.binaryBucket);
+ // Message sent
+ result(true);
+ return;
+ }
+ }
+ }
+
+ // try child avatar second
+ foreach (Scene scene in m_Scenes)
+ {
+ m_log.DebugFormat("[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID.ToString(), scene.RegionInfo.RegionName);
+
+ if (scene.Entities.ContainsKey(toAgentID) &&
+ scene.Entities[toAgentID] is ScenePresence)
+ {
+ // Local message
+ ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
+
+ m_log.DebugFormat("[INSTANT MESSAGE]: Delivering to client");
+ user.ControllingClient.SendInstantMessage(
+ new UUID(im.fromAgentID),
+ im.message,
+ new UUID(im.toAgentID),
+ im.fromAgentName,
+ im.dialog,
+ im.timestamp,
+ new UUID(im.imSessionID),
+ im.fromGroup,
+ im.binaryBucket);
+ // Message sent
+ result(true);
+ return;
+ }
+ }
+
+ if (m_Gridmode)
+ {
+ m_log.DebugFormat("[INSTANT MESSAGE]: Delivering via grid");
+ // Still here, try send via Grid
+ SendGridInstantMessageViaXMLRPC(im, result);
+ return;
+ }
+
+ m_log.DebugFormat("[INSTANT MESSAGE]: Undeliverable");
+ result(false);
+ return;
+ }
+
+ ///
+ /// Process a XMLRPC Grid Instant Message
+ ///
+ /// XMLRPC parameters
+ ///
+ /// Nothing much
+ protected virtual XmlRpcResponse processXMLRPCGridInstantMessage(XmlRpcRequest request)
+ {
+ bool successful = false;
+ // various rational defaults
+ UUID fromAgentID = UUID.Zero;
+ UUID fromAgentSession = UUID.Zero;
+ UUID toAgentID = UUID.Zero;
+ UUID imSessionID = UUID.Zero;
+ uint timestamp = 0;
+ string fromAgentName = "";
+ string message = "";
+ byte dialog = (byte)0;
+ bool fromGroup = false;
+ byte offline = (byte)0;
+ uint ParentEstateID=0;
+ Vector3 Position = Vector3.Zero;
+ UUID RegionID = UUID.Zero ;
+ byte[] binaryBucket = new byte[0];
+
+ float pos_x = 0;
+ float pos_y = 0;
+ float pos_z = 0;
+ //m_log.Info("Processing IM");
+
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ // Check if it's got all the data
+ if (requestData.ContainsKey("from_agent_id") && requestData.ContainsKey("from_agent_session")
+ && requestData.ContainsKey("to_agent_id") && requestData.ContainsKey("im_session_id")
+ && requestData.ContainsKey("timestamp") && requestData.ContainsKey("from_agent_name")
+ && requestData.ContainsKey("message") && requestData.ContainsKey("dialog")
+ && requestData.ContainsKey("from_group")
+ && requestData.ContainsKey("offline") && requestData.ContainsKey("parent_estate_id")
+ && requestData.ContainsKey("position_x") && requestData.ContainsKey("position_y")
+ && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id")
+ && requestData.ContainsKey("binary_bucket"))
+ {
+ // Do the easy way of validating the UUIDs
+ UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID);
+ UUID.TryParse((string)requestData["from_agent_session"], out fromAgentSession);
+ UUID.TryParse((string)requestData["to_agent_id"], out toAgentID);
+ UUID.TryParse((string)requestData["im_session_id"], out imSessionID);
+ UUID.TryParse((string)requestData["region_id"], out RegionID);
+
+ try
+ {
+ timestamp = (uint)Convert.ToInt32((string)requestData["timestamp"]);
+ }
+ catch (ArgumentException)
+ {
+ }
+ catch (FormatException)
+ {
+ }
+ catch (OverflowException)
+ {
+ }
+
+ fromAgentName = (string)requestData["from_agent_name"];
+ message = (string)requestData["message"];
+
+ // Bytes don't transfer well over XMLRPC, so, we Base64 Encode them.
+ string requestData1 = (string)requestData["dialog"];
+ if (string.IsNullOrEmpty(requestData1))
+ {
+ dialog = 0;
+ }
+ else
+ {
+ byte[] dialogdata = Convert.FromBase64String(requestData1);
+ dialog = dialogdata[0];
+ }
+
+ if ((string)requestData["from_group"] == "TRUE")
+ fromGroup = true;
+
+ string requestData2 = (string)requestData["offline"];
+ if (String.IsNullOrEmpty(requestData2))
+ {
+ offline = 0;
+ }
+ else
+ {
+ byte[] offlinedata = Convert.FromBase64String(requestData2);
+ offline = offlinedata[0];
+ }
+
+ try
+ {
+ ParentEstateID = (uint)Convert.ToInt32((string)requestData["parent_estate_id"]);
+ }
+ catch (ArgumentException)
+ {
+ }
+ catch (FormatException)
+ {
+ }
+ catch (OverflowException)
+ {
+ }
+
+ try
+ {
+ pos_x = (uint)Convert.ToInt32((string)requestData["position_x"]);
+ }
+ catch (ArgumentException)
+ {
+ }
+ catch (FormatException)
+ {
+ }
+ catch (OverflowException)
+ {
+ }
+ try
+ {
+ pos_y = (uint)Convert.ToInt32((string)requestData["position_y"]);
+ }
+ catch (ArgumentException)
+ {
+ }
+ catch (FormatException)
+ {
+ }
+ catch (OverflowException)
+ {
+ }
+ try
+ {
+ pos_z = (uint)Convert.ToInt32((string)requestData["position_z"]);
+ }
+ catch (ArgumentException)
+ {
+ }
+ catch (FormatException)
+ {
+ }
+ catch (OverflowException)
+ {
+ }
+
+ Position = new Vector3(pos_x, pos_y, pos_z);
+
+ string requestData3 = (string)requestData["binary_bucket"];
+ if (string.IsNullOrEmpty(requestData3))
+ {
+ binaryBucket = new byte[0];
+ }
+ else
+ {
+ binaryBucket = Convert.FromBase64String(requestData3);
+ }
+
+ // Create a New GridInstantMessageObject the the data
+ GridInstantMessage gim = new GridInstantMessage();
+ gim.fromAgentID = fromAgentID.Guid;
+ gim.fromAgentName = fromAgentName;
+ gim.fromAgentSession = fromAgentSession.Guid;
+ gim.fromGroup = fromGroup;
+ gim.imSessionID = imSessionID.Guid;
+ gim.RegionID = RegionID.Guid;
+ gim.timestamp = timestamp;
+ gim.toAgentID = toAgentID.Guid;
+ gim.message = message;
+ gim.dialog = dialog;
+ gim.offline = offline;
+ gim.ParentEstateID = ParentEstateID;
+ gim.Position = Position;
+ gim.binaryBucket = binaryBucket;
+
+
+ // Trigger the Instant message in the scene.
+ foreach (Scene scene in m_Scenes)
+ {
+ if (scene.Entities.ContainsKey(toAgentID) &&
+ scene.Entities[toAgentID] is ScenePresence)
+ {
+ ScenePresence user =
+ (ScenePresence)scene.Entities[toAgentID];
+
+ if (!user.IsChildAgent)
+ {
+ scene.EventManager.TriggerIncomingInstantMessage(gim);
+ successful = true;
+ }
+ }
+ }
+ if (!successful)
+ {
+ // If the message can't be delivered to an agent, it
+ // is likely to be a group IM. On a group IM, the
+ // imSessionID = toAgentID = group id. Raise the
+ // unhandled IM event to give the groups module
+ // a chance to pick it up. We raise that in a random
+ // scene, since the groups module is shared.
+ //
+ m_Scenes[0].EventManager.TriggerUnhandledInstantMessage(gim);
+ }
+ }
+
+ //Send response back to region calling if it was successful
+ // calling region uses this to know when to look up a user's location again.
+ XmlRpcResponse resp = new XmlRpcResponse();
+ Hashtable respdata = new Hashtable();
+ if (successful)
+ respdata["success"] = "TRUE";
+ else
+ respdata["success"] = "FALSE";
+ resp.Value = respdata;
+
+ return resp;
+ }
+
+ ///
+ /// delegate for sending a grid instant message asynchronously
+ ///
+ public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result, ulong prevRegionHandle);
+
+ private void GridInstantMessageCompleted(IAsyncResult iar)
+ {
+ GridInstantMessageDelegate icon =
+ (GridInstantMessageDelegate)iar.AsyncState;
+ icon.EndInvoke(iar);
+ }
+
+
+ protected virtual void SendGridInstantMessageViaXMLRPC(GridInstantMessage im, MessageResultNotification result)
+ {
+ GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync;
+
+ d.BeginInvoke(im, result, 0, GridInstantMessageCompleted, d);
+ }
+
+ ///
+ /// Recursive SendGridInstantMessage over XMLRPC method.
+ ///
+ ///
+ protected virtual void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, ulong prevRegionHandle)
+ {
+ UUID toAgentID = new UUID(im.toAgentID);
+
+ UserAgentData upd = null;
+
+ bool lookupAgent = false;
+
+ lock (m_UserRegionMap)
+ {
+ if (m_UserRegionMap.ContainsKey(toAgentID))
+ {
+ upd = new UserAgentData();
+ upd.AgentOnline = true;
+ upd.Handle = m_UserRegionMap[toAgentID];
+ }
+ else
+ {
+ lookupAgent = true;
+ }
+ }
+
+ // Are we needing to look-up an agent?
+ if (lookupAgent)
+ {
+ // Non-cached user agent lookup.
+ upd = m_Scenes[0].CommsManager.UserService.GetAgentByUUID(toAgentID);
+
+ if (upd != null)
+ {
+ // check if we've tried this before..
+ // This is one way to end the recursive loop
+ //
+ if (upd.Handle == prevRegionHandle)
+ {
+ m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
+ result(false);
+ return;
+ }
+ }
+ else
+ {
+ m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
+ result(false);
+ return;
+ }
+ }
+
+ if (upd != null)
+ {
+ if (upd.AgentOnline)
+ {
+ RegionInfo reginfo = m_Scenes[0].SceneGridService.RequestNeighbouringRegionInfo(upd.Handle);
+ if (reginfo != null)
+ {
+ Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im);
+ // Not actually used anymore, left in for compatibility
+ // Remove at next interface change
+ //
+ msgdata["region_handle"] = 0;
+ bool imresult = doIMSending(reginfo, msgdata);
+ if (imresult)
+ {
+ // IM delivery successful, so store the Agent's location in our local cache.
+ lock (m_UserRegionMap)
+ {
+ if (m_UserRegionMap.ContainsKey(toAgentID))
+ {
+ m_UserRegionMap[toAgentID] = upd.Handle;
+ }
+ else
+ {
+ m_UserRegionMap.Add(toAgentID, upd.Handle);
+ }
+ }
+ result(true);
+ }
+ else
+ {
+ // try again, but lookup user this time.
+ // Warning, this must call the Async version
+ // of this method or we'll be making thousands of threads
+ // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync
+ // The version that spawns the thread is SendGridInstantMessageViaXMLRPC
+
+ // This is recursive!!!!!
+ SendGridInstantMessageViaXMLRPCAsync(im, result,
+ upd.Handle);
+ }
+
+ }
+ }
+ else
+ {
+ result(false);
+ }
+ }
+ else
+ {
+ result(false);
+ }
+
+ }
+
+ ///
+ /// This actually does the XMLRPC Request
+ ///
+ /// RegionInfo we pull the data out of to send the request to
+ /// The Instant Message data Hashtable
+ /// Bool if the message was successfully delivered at the other side.
+ private bool doIMSending(RegionInfo reginfo, Hashtable xmlrpcdata)
+ {
+
+ ArrayList SendParams = new ArrayList();
+ SendParams.Add(xmlrpcdata);
+ XmlRpcRequest GridReq = new XmlRpcRequest("grid_instant_message", SendParams);
+ try
+ {
+
+ XmlRpcResponse GridResp = GridReq.Send("http://" + reginfo.ExternalHostName + ":" + reginfo.HttpPort, 3000);
+
+ Hashtable responseData = (Hashtable)GridResp.Value;
+
+ if (responseData.ContainsKey("success"))
+ {
+ if ((string)responseData["success"] == "TRUE")
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ catch (WebException e)
+ {
+ m_log.ErrorFormat("[GRID INSTANT MESSAGE]: Error sending message to http://{0}:{1} the host didn't respond ({2})",
+ reginfo.ExternalHostName, reginfo.HttpPort, e.Message);
+ }
+
+ return false;
+ }
+
+ ///
+ /// Get ulong region handle for region by it's Region UUID.
+ /// We use region handles over grid comms because there's all sorts of free and cool caching.
+ ///
+ /// UUID of region to get the region handle for
+ ///
+ private ulong getLocalRegionHandleFromUUID(UUID regionID)
+ {
+ ulong returnhandle = 0;
+
+ lock (m_Scenes)
+ {
+ foreach (Scene sn in m_Scenes)
+ {
+ if (sn.RegionInfo.RegionID == regionID)
+ {
+ returnhandle = sn.RegionInfo.RegionHandle;
+ break;
+ }
+ }
+ }
+ return returnhandle;
+ }
+
+ ///
+ /// Takes a GridInstantMessage and converts it into a Hashtable for XMLRPC
+ ///
+ /// The GridInstantMessage object
+ /// Hashtable containing the XMLRPC request
+ private Hashtable ConvertGridInstantMessageToXMLRPC(GridInstantMessage msg)
+ {
+ Hashtable gim = new Hashtable();
+ gim["from_agent_id"] = msg.fromAgentID.ToString();
+ gim["from_agent_session"] = msg.fromAgentSession.ToString();
+ gim["to_agent_id"] = msg.toAgentID.ToString();
+ gim["im_session_id"] = msg.imSessionID.ToString();
+ gim["timestamp"] = msg.timestamp.ToString();
+ gim["from_agent_name"] = msg.fromAgentName;
+ gim["message"] = msg.message;
+ byte[] dialogdata = new byte[1];dialogdata[0] = msg.dialog;
+ gim["dialog"] = Convert.ToBase64String(dialogdata,Base64FormattingOptions.None);
+
+ if (msg.fromGroup)
+ gim["from_group"] = "TRUE";
+ else
+ gim["from_group"] = "FALSE";
+ byte[] offlinedata = new byte[1]; offlinedata[0] = msg.offline;
+ gim["offline"] = Convert.ToBase64String(offlinedata, Base64FormattingOptions.None);
+ gim["parent_estate_id"] = msg.ParentEstateID.ToString();
+ gim["position_x"] = msg.Position.X.ToString();
+ gim["position_y"] = msg.Position.Y.ToString();
+ gim["position_z"] = msg.Position.Z.ToString();
+ gim["region_id"] = msg.RegionID.ToString();
+ gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None);
+ return gim;
+ }
+
+ }
+}
diff --git a/OpenSim/Region/Environment/Scenes/EventManager.cs b/OpenSim/Region/Environment/Scenes/EventManager.cs
index 5d21dc5f2f..bcefe375f5 100644
--- a/OpenSim/Region/Environment/Scenes/EventManager.cs
+++ b/OpenSim/Region/Environment/Scenes/EventManager.cs
@@ -144,9 +144,11 @@ namespace OpenSim.Region.Environment.Scenes
public event SignificantClientMovement OnSignificantClientMovement;
- public delegate void NewGridInstantMessage(GridInstantMessage message, InstantMessageReceiver whichModule);
+ public delegate void IncomingInstantMessage(GridInstantMessage message);
- public event NewGridInstantMessage OnGridInstantMessage;
+ public event IncomingInstantMessage OnIncomingInstantMessage;
+
+ public event IncomingInstantMessage OnUnhandledInstantMessage;
public delegate void ClientClosed(UUID clientID);
@@ -352,7 +354,8 @@ namespace OpenSim.Region.Environment.Scenes
private LandObjectAdded handlerLandObjectAdded = null; //OnLandObjectAdded;
private LandObjectRemoved handlerLandObjectRemoved = null; //OnLandObjectRemoved;
private AvatarEnteringNewParcel handlerAvatarEnteringNewParcel = null; //OnAvatarEnteringNewParcel;
- private NewGridInstantMessage handlerGridInstantMessage = null; //OnGridInstantMessage;
+ private IncomingInstantMessage handlerIncomingInstantMessage = null; //OnIncomingInstantMessage;
+ private IncomingInstantMessage handlerUnhandledInstantMessage = null; //OnUnhandledInstantMessage;
private ClientClosed handlerClientClosed = null; //OnClientClosed;
private OnMakeChildAgentDelegate handlerMakeChildAgent = null; //OnMakeChildAgent;
private OnMakeRootAgentDelegate handlerMakeRootAgent = null; //OnMakeRootAgent;
@@ -641,15 +644,21 @@ namespace OpenSim.Region.Environment.Scenes
}
}
- ///Used to pass instnat messages around between the Scene, the Friends Module and the Instant Messsage Module
- ///Object containing the Instant Message Data
- ///A bit vector containing the modules to send the message to
- public void TriggerGridInstantMessage(GridInstantMessage message, InstantMessageReceiver whichModule)
+ public void TriggerIncomingInstantMessage(GridInstantMessage message)
{
- handlerGridInstantMessage = OnGridInstantMessage;
- if (handlerGridInstantMessage != null)
+ handlerIncomingInstantMessage = OnIncomingInstantMessage;
+ if (handlerIncomingInstantMessage != null)
{
- handlerGridInstantMessage(message, whichModule);
+ handlerIncomingInstantMessage(message);
+ }
+ }
+
+ public void TriggerUnhandledInstantMessage(GridInstantMessage message)
+ {
+ handlerUnhandledInstantMessage = OnUnhandledInstantMessage;
+ if (handlerUnhandledInstantMessage != null)
+ {
+ handlerUnhandledInstantMessage(message);
}
}
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs
index 08b7bdb377..7485134590 100644
--- a/OpenSim/Region/Environment/Scenes/Scene.cs
+++ b/OpenSim/Region/Environment/Scenes/Scene.cs
@@ -993,7 +993,8 @@ namespace OpenSim.Region.Environment.Scenes
else
msg.message = string.Format("Your object {0} was returned from {1} in region {2} due to parcel auto return", ret.Value.objectName, ret.Value.location.ToString(), RegionInfo.RegionName);
- TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule);
+// TODO: Send IM
+// TriggerGridInstantMessage(msg);
}
}
@@ -3304,21 +3305,6 @@ namespace OpenSim.Region.Environment.Scenes
return UUID.Zero;
}
- ///
- /// This method is a way for the Friends Module to create an instant
- /// message to the avatar and for Instant Messages that travel across
- /// gridcomms to make it to the Instant Message Module.
- ///
- /// Friendship establishment and groups are unfortunately tied with instant messaging and
- /// there's no way to separate them completely.
- ///
- /// object containing the instant message data
- /// void
- public void TriggerGridInstantMessage(GridInstantMessage message, InstantMessageReceiver options)
- {
- m_eventManager.TriggerGridInstantMessage(message, options);
- }
-
public virtual void StoreAddFriendship(UUID ownerID, UUID friendID, uint perms)
{
// TODO: m_sceneGridService.DoStuff;
diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs
index d929be228d..acb6888c30 100644
--- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs
@@ -1211,6 +1211,9 @@ namespace OpenSim.Region.Environment.Scenes
///
public void ProcessBackup(IRegionDataStore datastore)
{
+ if (!m_isBackedUp)
+ return;
+
// Since this is the top of the section of call stack for backing up a particular scene object, don't let
// any exception propogate upwards.
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 0720f363fc..cce7e7ab21 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -2645,7 +2645,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
msg.Position = Vector3.Zero;// new Vector3(m_host.AbsolutePosition);
msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
msg.binaryBucket = new byte[0];// binaryBucket;
- World.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule);
+// TODO: Send IM
+// World.TriggerGridInstantMessage(msg);
// ScriptSleep(2000);
}