diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs index 5ec64d5141..9fd331857a 100644 --- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs @@ -31,16 +31,40 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; +using System; +using System.Reflection; +using System.Collections; +using System.Collections.Specialized; +using System.Reflection; +using System.IO; +using System.Web; +using System.Xml; +using log4net; +using Mono.Addins; +using OpenMetaverse.Messages.Linden; +using OpenMetaverse.StructuredData; +using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using Caps = OpenSim.Framework.Capabilities.Caps; +using OSDArray = OpenMetaverse.StructuredData.OSDArray; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; namespace OpenSim.Region.CoreModules.Avatar.Gods { public class GodsModule : IRegionModule, IGodsModule { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// Special UUID for actions that apply to all agents private static readonly UUID ALL_AGENTS = new UUID("44e87126-e794-4ded-05b3-7c42da3d5cdb"); protected Scene m_scene; protected IDialogModule m_dialogModule; + + protected Dictionary m_capsDict = + new Dictionary(); public void Initialise(Scene scene, IConfigSource source) { @@ -48,6 +72,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods m_dialogModule = m_scene.RequestModuleInterface(); m_scene.RegisterModuleInterface(this); m_scene.EventManager.OnNewClient += SubscribeToClientEvents; + m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; + m_scene.EventManager.OnClientClosed += OnClientClosed; } public void PostInitialise() {} @@ -67,6 +93,50 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods client.OnRequestGodlikePowers -= RequestGodlikePowers; } + private void OnClientClosed(UUID agentID, Scene scene) + { + m_capsDict.Remove(agentID); + } + + private void OnRegisterCaps(UUID agentID, Caps caps) + { + string uri = "/CAPS/" + UUID.Random(); + m_capsDict[agentID] = uri; + + caps.RegisterHandler("UntrustedSimulatorMessage", + new RestStreamHandler("POST", uri, + HandleUntrustedSimulatorMessage)); + } + + private string HandleUntrustedSimulatorMessage(string request, + string path, string param, OSHttpRequest httpRequest, + OSHttpResponse httpResponse) + { + OSDMap osd = (OSDMap)OSDParser.DeserializeLLSDXml(request); + + string message = osd["message"].AsString(); + + if (message == "GodKickUser") + { + OSDMap body = (OSDMap)osd["body"]; + OSDArray userInfo = (OSDArray)body["UserInfo"]; + OSDMap userData = (OSDMap)userInfo[0]; + + UUID agentID = userData["AgentID"].AsUUID(); + UUID godID = userData["GodID"].AsUUID(); + UUID godSessionID = userData["GodSessionID"].AsUUID(); + uint kickFlags = userData["KickFlags"].AsUInteger(); + string reason = userData["Reason"].AsString(); + + KickUser(godID, godSessionID, agentID, kickFlags, Util.StringToBytes1024(reason)); + } + else + { + m_log.ErrorFormat("[GOD]: Unhandled UntrustedSimulatorMessage: {0}", message); + } + return String.Empty; + } + public void RequestGodlikePowers( UUID agentID, UUID sessionID, UUID token, bool godLike, IClientAPI controllingClient) { @@ -115,71 +185,60 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods /// The message to send to the user after it's been turned into a field public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason) { - UUID kickUserID = ALL_AGENTS; - + if (!m_scene.Permissions.IsGod(godID)) + return; + + ScenePresence god = m_scene.GetScenePresence(godID); + if (god == null || god.ControllingClient.SessionId != sessionID) + return; + ScenePresence sp = m_scene.GetScenePresence(agentID); - if (sp != null || agentID == kickUserID) + switch (kickflags) { - if (m_scene.Permissions.IsGod(godID)) + case 0: + if (sp != null) { - if (kickflags == 0) - { - if (agentID == kickUserID) - { - string reasonStr = Utils.BytesToString(reason); - - m_scene.ForEachClient( - delegate(IClientAPI controller) - { - if (controller.AgentId != godID) - controller.Kick(reasonStr); - } - ); - - // This is a bit crude. It seems the client will be null before it actually stops the thread - // The thread will kill itself eventually :/ - // Is there another way to make sure *all* clients get this 'inter region' message? - m_scene.ForEachScenePresence( - delegate(ScenePresence p) - { - if (p.UUID != godID && !p.IsChildAgent) - { - // Possibly this should really be p.Close() though that method doesn't send a close - // to the client - p.ControllingClient.Close(); - } - } - ); - } - else - { - m_scene.SceneGraph.removeUserCount(!sp.IsChildAgent); - - sp.ControllingClient.Kick(Utils.BytesToString(reason)); - sp.ControllingClient.Close(); - } - } - - if (kickflags == 1) - { - sp.AllowMovement = false; - m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason)); - m_dialogModule.SendAlertToUser(godID, "User Frozen"); - } - - if (kickflags == 2) - { - sp.AllowMovement = true; - m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason)); - m_dialogModule.SendAlertToUser(godID, "User Unfrozen"); - } + KickPresence(sp, Utils.BytesToString(reason)); } - else + else if (agentID == ALL_AGENTS) { - m_dialogModule.SendAlertToUser(godID, "Kick request denied"); + m_scene.ForEachScenePresence( + delegate(ScenePresence p) + { + if (p.UUID != godID && (!m_scene.Permissions.IsGod(p.UUID))) + KickPresence(p, Utils.BytesToString(reason)); + } + ); } + break; + case 1: + if (sp != null) + { + sp.AllowMovement = false; + m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason)); + m_dialogModule.SendAlertToUser(godID, "User Frozen"); + } + break; + case 2: + if (sp != null) + { + sp.AllowMovement = true; + m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason)); + m_dialogModule.SendAlertToUser(godID, "User Unfrozen"); + } + break; + default: + break; } } + + private void KickPresence(ScenePresence sp, string reason) + { + if (sp.IsChildAgent) + return; + sp.ControllingClient.Kick(reason); + sp.Scene.IncomingCloseAgent(sp.UUID); + } } -} \ No newline at end of file +}