diff options
author | UbitUmarov | 2015-09-01 11:43:07 +0100 |
---|---|---|
committer | UbitUmarov | 2015-09-01 11:43:07 +0100 |
commit | fb78b182520fc9bb0f971afd0322029c70278ea6 (patch) | |
tree | b4e30d383938fdeef8c92d1d1c2f44bb61d329bd /OpenSim/Region/ClientStack/Linden/Caps | |
parent | lixo (diff) | |
parent | Mantis #7713: fixed bug introduced by 1st MOSES patch. (diff) | |
download | opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.zip opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.gz opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.bz2 opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.xz |
Merge remote-tracking branch 'os/master'
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps')
21 files changed, 6480 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs new file mode 100644 index 0000000..aabdb51 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs | |||
@@ -0,0 +1,182 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.IO; | ||
32 | using log4net; | ||
33 | using Mono.Addins; | ||
34 | using Nini.Config; | ||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | using OpenSim.Framework.Console; | ||
38 | using OpenSim.Framework.Servers; | ||
39 | using OpenSim.Framework.Servers.HttpServer; | ||
40 | using OpenSim.Region.Framework.Interfaces; | ||
41 | using OpenSim.Region.Framework.Scenes; | ||
42 | using OpenSim.Services.Interfaces; | ||
43 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
44 | using OpenSim.Capabilities.Handlers; | ||
45 | |||
46 | namespace OpenSim.Region.ClientStack.LindenCaps | ||
47 | { | ||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AgentPreferencesModule")] | ||
49 | public class AgentPreferencesModule : ISharedRegionModule | ||
50 | { | ||
51 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
52 | |||
53 | private List<Scene> m_scenes = new List<Scene>(); | ||
54 | |||
55 | public void Initialise(IConfigSource source) | ||
56 | { | ||
57 | |||
58 | } | ||
59 | |||
60 | #region Region module | ||
61 | |||
62 | public void AddRegion(Scene scene) | ||
63 | { | ||
64 | lock (m_scenes) m_scenes.Add(scene); | ||
65 | } | ||
66 | |||
67 | public void RemoveRegion(Scene scene) | ||
68 | { | ||
69 | lock (m_scenes) m_scenes.Remove(scene); | ||
70 | scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
71 | scene = null; | ||
72 | } | ||
73 | |||
74 | public void RegionLoaded(Scene scene) | ||
75 | { | ||
76 | scene.EventManager.OnRegisterCaps += delegate(UUID agentID, OpenSim.Framework.Capabilities.Caps caps) | ||
77 | { | ||
78 | RegisterCaps(agentID, caps); | ||
79 | }; | ||
80 | } | ||
81 | |||
82 | public void PostInitialise() {} | ||
83 | |||
84 | public void Close() {} | ||
85 | |||
86 | public string Name { get { return "AgentPreferencesModule"; } } | ||
87 | |||
88 | public Type ReplaceableInterface | ||
89 | { | ||
90 | get { return null; } | ||
91 | } | ||
92 | |||
93 | public void RegisterCaps(UUID agent, Caps caps) | ||
94 | { | ||
95 | UUID capId = UUID.Random(); | ||
96 | caps.RegisterHandler("AgentPreferences", | ||
97 | new RestStreamHandler("POST", "/CAPS/" + capId, | ||
98 | delegate(string request, string path, string param, | ||
99 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
100 | { | ||
101 | return UpdateAgentPreferences(request, path, param, agent); | ||
102 | })); | ||
103 | caps.RegisterHandler("UpdateAgentLanguage", | ||
104 | new RestStreamHandler("POST", "/CAPS/" + capId, | ||
105 | delegate(string request, string path, string param, | ||
106 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
107 | { | ||
108 | return UpdateAgentPreferences(request, path, param, agent); | ||
109 | })); | ||
110 | caps.RegisterHandler("UpdateAgentInformation", | ||
111 | new RestStreamHandler("POST", "/CAPS/" + capId, | ||
112 | delegate(string request, string path, string param, | ||
113 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
114 | { | ||
115 | return UpdateAgentPreferences(request, path, param, agent); | ||
116 | })); | ||
117 | } | ||
118 | |||
119 | public string UpdateAgentPreferences(string request, string path, string param, UUID agent) | ||
120 | { | ||
121 | OSDMap resp = new OSDMap(); | ||
122 | // The viewer doesn't do much with the return value, so for now, if there is no preference service, | ||
123 | // we'll return a null llsd block for debugging purposes. This may change if someone knows what the | ||
124 | // correct server response would be here. | ||
125 | if (m_scenes[0].AgentPreferencesService == null) | ||
126 | { | ||
127 | return OSDParser.SerializeLLSDXmlString(resp); | ||
128 | } | ||
129 | m_log.DebugFormat("[AgentPrefs]: UpdateAgentPreferences for {0}", agent.ToString()); | ||
130 | OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); | ||
131 | AgentPrefs data = m_scenes[0].AgentPreferencesService.GetAgentPreferences(agent); | ||
132 | if (data == null) | ||
133 | { | ||
134 | data = new AgentPrefs(agent); | ||
135 | } | ||
136 | |||
137 | if (req.ContainsKey("access_prefs")) | ||
138 | { | ||
139 | OSDMap accessPrefs = (OSDMap)req["access_prefs"]; // We could check with ContainsKey... | ||
140 | data.AccessPrefs = accessPrefs["max"].AsString(); | ||
141 | } | ||
142 | if (req.ContainsKey("default_object_perm_masks")) | ||
143 | { | ||
144 | OSDMap permsMap = (OSDMap)req["default_object_perm_masks"]; | ||
145 | data.PermEveryone = permsMap["Everyone"].AsInteger(); | ||
146 | data.PermGroup = permsMap["Group"].AsInteger(); | ||
147 | data.PermNextOwner = permsMap["NextOwner"].AsInteger(); | ||
148 | } | ||
149 | if (req.ContainsKey("hover_height")) | ||
150 | { | ||
151 | data.HoverHeight = req["hover_height"].AsReal(); | ||
152 | } | ||
153 | if (req.ContainsKey("language")) | ||
154 | { | ||
155 | data.Language = req["language"].AsString(); | ||
156 | } | ||
157 | if (req.ContainsKey("language_is_public")) | ||
158 | { | ||
159 | data.LanguageIsPublic = req["language_is_public"].AsBoolean(); | ||
160 | } | ||
161 | m_scenes[0].AgentPreferencesService.StoreAgentPreferences(data); | ||
162 | OSDMap respAccessPrefs = new OSDMap(); | ||
163 | respAccessPrefs["max"] = data.AccessPrefs; | ||
164 | resp["access_prefs"] = respAccessPrefs; | ||
165 | OSDMap respDefaultPerms = new OSDMap(); | ||
166 | respDefaultPerms["Everyone"] = data.PermEveryone; | ||
167 | respDefaultPerms["Group"] = data.PermGroup; | ||
168 | respDefaultPerms["NextOwner"] = data.PermNextOwner; | ||
169 | resp["default_object_perm_masks"] = respDefaultPerms; | ||
170 | resp["god_level"] = 0; // *TODO: Add this | ||
171 | resp["hover_height"] = data.HoverHeight; | ||
172 | resp["language"] = data.Language; | ||
173 | resp["language_is_public"] = data.LanguageIsPublic; | ||
174 | |||
175 | string response = OSDParser.SerializeLLSDXmlString(resp); | ||
176 | return response; | ||
177 | } | ||
178 | |||
179 | #endregion Region module | ||
180 | } | ||
181 | } | ||
182 | |||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs new file mode 100644 index 0000000..bbadc55 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Drawing; | ||
32 | using System.Drawing.Imaging; | ||
33 | using System.Reflection; | ||
34 | using System.IO; | ||
35 | using System.Web; | ||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using Mono.Addins; | ||
39 | using OpenMetaverse; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenSim.Framework; | ||
42 | using OpenSim.Framework.Servers; | ||
43 | using OpenSim.Framework.Servers.HttpServer; | ||
44 | using OpenSim.Region.Framework.Interfaces; | ||
45 | using OpenSim.Region.Framework.Scenes; | ||
46 | using OpenSim.Services.Interfaces; | ||
47 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
48 | using OpenSim.Capabilities.Handlers; | ||
49 | |||
50 | namespace OpenSim.Region.ClientStack.Linden | ||
51 | { | ||
52 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AvatarPickerSearchModule")] | ||
53 | public class AvatarPickerSearchModule : INonSharedRegionModule | ||
54 | { | ||
55 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
56 | |||
57 | private Scene m_scene; | ||
58 | private IPeople m_People; | ||
59 | private bool m_Enabled = false; | ||
60 | |||
61 | private string m_URL; | ||
62 | |||
63 | #region ISharedRegionModule Members | ||
64 | |||
65 | public void Initialise(IConfigSource source) | ||
66 | { | ||
67 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
68 | if (config == null) | ||
69 | return; | ||
70 | |||
71 | m_URL = config.GetString("Cap_AvatarPickerSearch", string.Empty); | ||
72 | // Cap doesn't exist | ||
73 | if (m_URL != string.Empty) | ||
74 | m_Enabled = true; | ||
75 | } | ||
76 | |||
77 | public void AddRegion(Scene s) | ||
78 | { | ||
79 | if (!m_Enabled) | ||
80 | return; | ||
81 | |||
82 | m_scene = s; | ||
83 | } | ||
84 | |||
85 | public void RemoveRegion(Scene s) | ||
86 | { | ||
87 | if (!m_Enabled) | ||
88 | return; | ||
89 | |||
90 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
91 | m_scene = null; | ||
92 | } | ||
93 | |||
94 | public void RegionLoaded(Scene s) | ||
95 | { | ||
96 | if (!m_Enabled) | ||
97 | return; | ||
98 | |||
99 | m_People = m_scene.RequestModuleInterface<IPeople>(); | ||
100 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
101 | } | ||
102 | |||
103 | public void PostInitialise() | ||
104 | { | ||
105 | } | ||
106 | |||
107 | public void Close() { } | ||
108 | |||
109 | public string Name { get { return "AvatarPickerSearchModule"; } } | ||
110 | |||
111 | public Type ReplaceableInterface | ||
112 | { | ||
113 | get { return null; } | ||
114 | } | ||
115 | |||
116 | #endregion | ||
117 | |||
118 | public void RegisterCaps(UUID agentID, Caps caps) | ||
119 | { | ||
120 | UUID capID = UUID.Random(); | ||
121 | |||
122 | if (m_URL == "localhost") | ||
123 | { | ||
124 | // m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | ||
125 | caps.RegisterHandler( | ||
126 | "AvatarPickerSearch", | ||
127 | new AvatarPickerSearchHandler("/CAPS/" + capID + "/", m_People, "AvatarPickerSearch", "Search for avatars by name")); | ||
128 | } | ||
129 | else | ||
130 | { | ||
131 | // m_log.DebugFormat("[AVATAR PICKER SEARCH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); | ||
132 | caps.RegisterHandler("AvatarPickerSearch", m_URL); | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs new file mode 100644 index 0000000..774202e --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs | |||
@@ -0,0 +1,1309 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using System.Text; | ||
34 | |||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | using Nini.Config; | ||
38 | using log4net; | ||
39 | |||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Capabilities; | ||
42 | using OpenSim.Region.Framework; | ||
43 | using OpenSim.Region.Framework.Scenes; | ||
44 | using OpenSim.Region.Framework.Scenes.Serialization; | ||
45 | using OpenSim.Framework.Servers; | ||
46 | using OpenSim.Framework.Servers.HttpServer; | ||
47 | using OpenSim.Framework.Client; | ||
48 | using OpenSim.Services.Interfaces; | ||
49 | |||
50 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
51 | using OSDArray = OpenMetaverse.StructuredData.OSDArray; | ||
52 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||
53 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
54 | |||
55 | namespace OpenSim.Region.ClientStack.Linden | ||
56 | { | ||
57 | public delegate void UpLoadedAsset( | ||
58 | string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, | ||
59 | byte[] data, string inventoryType, string assetType); | ||
60 | |||
61 | public delegate UUID UpdateItem(UUID itemID, byte[] data); | ||
62 | |||
63 | public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); | ||
64 | |||
65 | public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); | ||
66 | |||
67 | public delegate void NewAsset(AssetBase asset); | ||
68 | |||
69 | public delegate UUID ItemUpdatedCallback(UUID userID, UUID itemID, byte[] data); | ||
70 | |||
71 | public delegate ArrayList TaskScriptUpdatedCallback(UUID userID, UUID itemID, UUID primID, | ||
72 | bool isScriptRunning, byte[] data); | ||
73 | |||
74 | public delegate InventoryCollection FetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID, | ||
75 | bool fetchFolders, bool fetchItems, int sortOrder, out int version); | ||
76 | |||
77 | /// <summary> | ||
78 | /// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that | ||
79 | /// we can popup a message on the user's client if the inventory service has permanently failed). But I didn't want | ||
80 | /// to just pass the whole Scene into CAPS. | ||
81 | /// </summary> | ||
82 | public delegate IClientAPI GetClientDelegate(UUID agentID); | ||
83 | |||
84 | public class BunchOfCaps | ||
85 | { | ||
86 | private static readonly ILog m_log = | ||
87 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
88 | |||
89 | private Scene m_Scene; | ||
90 | private Caps m_HostCapsObj; | ||
91 | |||
92 | private static readonly string m_requestPath = "0000/"; | ||
93 | // private static readonly string m_mapLayerPath = "0001/"; | ||
94 | private static readonly string m_newInventory = "0002/"; | ||
95 | //private static readonly string m_requestTexture = "0003/"; | ||
96 | private static readonly string m_notecardUpdatePath = "0004/"; | ||
97 | private static readonly string m_notecardTaskUpdatePath = "0005/"; | ||
98 | // private static readonly string m_fetchInventoryPath = "0006/"; | ||
99 | private static readonly string m_copyFromNotecardPath = "0007/"; | ||
100 | // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. | ||
101 | private static readonly string m_getObjectPhysicsDataPath = "0101/"; | ||
102 | /* 0102 - 0103 RESERVED */ | ||
103 | private static readonly string m_UpdateAgentInformationPath = "0500/"; | ||
104 | |||
105 | // These are callbacks which will be setup by the scene so that we can update scene data when we | ||
106 | // receive capability calls | ||
107 | public NewInventoryItem AddNewInventoryItem = null; | ||
108 | public NewAsset AddNewAsset = null; | ||
109 | public ItemUpdatedCallback ItemUpdatedCall = null; | ||
110 | public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null; | ||
111 | public FetchInventoryDescendentsCAPS CAPSFetchInventoryDescendents = null; | ||
112 | public GetClientDelegate GetClient = null; | ||
113 | |||
114 | private bool m_persistBakedTextures = false; | ||
115 | private IAssetService m_assetService; | ||
116 | private bool m_dumpAssetsToFile = false; | ||
117 | private string m_regionName; | ||
118 | private int m_levelUpload = 0; | ||
119 | |||
120 | public BunchOfCaps(Scene scene, Caps caps) | ||
121 | { | ||
122 | m_Scene = scene; | ||
123 | m_HostCapsObj = caps; | ||
124 | IConfigSource config = m_Scene.Config; | ||
125 | if (config != null) | ||
126 | { | ||
127 | IConfig sconfig = config.Configs["Startup"]; | ||
128 | if (sconfig != null) | ||
129 | { | ||
130 | m_levelUpload = sconfig.GetInt("LevelUpload", 0); | ||
131 | } | ||
132 | |||
133 | IConfig appearanceConfig = config.Configs["Appearance"]; | ||
134 | if (appearanceConfig != null) | ||
135 | { | ||
136 | m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | m_assetService = m_Scene.AssetService; | ||
141 | m_regionName = m_Scene.RegionInfo.RegionName; | ||
142 | |||
143 | RegisterHandlers(); | ||
144 | |||
145 | AddNewInventoryItem = m_Scene.AddUploadedInventoryItem; | ||
146 | ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; | ||
147 | TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; | ||
148 | GetClient = m_Scene.SceneGraph.GetControllingClient; | ||
149 | } | ||
150 | |||
151 | /// <summary> | ||
152 | /// Register a bunch of CAPS http service handlers | ||
153 | /// </summary> | ||
154 | public void RegisterHandlers() | ||
155 | { | ||
156 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | ||
157 | |||
158 | RegisterRegionServiceHandlers(capsBase); | ||
159 | RegisterInventoryServiceHandlers(capsBase); | ||
160 | } | ||
161 | |||
162 | public void RegisterRegionServiceHandlers(string capsBase) | ||
163 | { | ||
164 | try | ||
165 | { | ||
166 | // the root of all evil | ||
167 | m_HostCapsObj.RegisterHandler( | ||
168 | "SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null)); | ||
169 | |||
170 | // m_log.DebugFormat( | ||
171 | // "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID); | ||
172 | |||
173 | //m_capsHandlers["MapLayer"] = | ||
174 | // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", | ||
175 | // capsBase + m_mapLayerPath, | ||
176 | // GetMapLayer); | ||
177 | IRequestHandler req | ||
178 | = new RestStreamHandler( | ||
179 | "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null); | ||
180 | |||
181 | m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req); | ||
182 | m_HostCapsObj.RegisterHandler("UpdateScriptTask", req); | ||
183 | } | ||
184 | catch (Exception e) | ||
185 | { | ||
186 | m_log.Error("[CAPS]: " + e.ToString()); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | public void RegisterInventoryServiceHandlers(string capsBase) | ||
191 | { | ||
192 | try | ||
193 | { | ||
194 | // I don't think this one works... | ||
195 | m_HostCapsObj.RegisterHandler( | ||
196 | "NewFileAgentInventory", | ||
197 | new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>( | ||
198 | "POST", | ||
199 | capsBase + m_newInventory, | ||
200 | NewAgentInventoryRequest, | ||
201 | "NewFileAgentInventory", | ||
202 | null)); | ||
203 | |||
204 | IRequestHandler req | ||
205 | = new RestStreamHandler( | ||
206 | "POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory, "Update*", null); | ||
207 | |||
208 | m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); | ||
209 | m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); | ||
210 | m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); | ||
211 | |||
212 | IRequestHandler getObjectPhysicsDataHandler | ||
213 | = new RestStreamHandler( | ||
214 | "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null); | ||
215 | m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); | ||
216 | |||
217 | IRequestHandler UpdateAgentInformationHandler | ||
218 | = new RestStreamHandler( | ||
219 | "POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation, "UpdateAgentInformation", null); | ||
220 | m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); | ||
221 | |||
222 | m_HostCapsObj.RegisterHandler( | ||
223 | "CopyInventoryFromNotecard", | ||
224 | new RestStreamHandler( | ||
225 | "POST", capsBase + m_copyFromNotecardPath, CopyInventoryFromNotecard, "CopyInventoryFromNotecard", null)); | ||
226 | |||
227 | // As of RC 1.22.9 of the Linden client this is | ||
228 | // supported | ||
229 | |||
230 | //m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest); | ||
231 | |||
232 | // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and | ||
233 | // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires | ||
234 | // enhancements (probably filling out the folder part of the LLSD reply) to our CAPS service, | ||
235 | // but when I went on the Linden grid, the | ||
236 | // simulators I visited (version 1.21) were, surprisingly, no longer supplying this capability. Instead, | ||
237 | // the 1.19.1.4 client appeared to be happily flowing inventory data over UDP | ||
238 | // | ||
239 | // This is very probably just a temporary measure - once the CAPS service appears again on the Linden grid | ||
240 | // we will be | ||
241 | // able to get the data we need to implement the necessary part of the protocol to fix the issue above. | ||
242 | // m_capsHandlers["FetchInventoryDescendents"] = | ||
243 | // new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest); | ||
244 | |||
245 | // m_capsHandlers["FetchInventoryDescendents"] = | ||
246 | // new LLSDStreamhandler<LLSDFetchInventoryDescendents, LLSDInventoryDescendents>("POST", | ||
247 | // capsBase + m_fetchInventory, | ||
248 | // FetchInventory)); | ||
249 | // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST", | ||
250 | // capsBase + m_requestTexture, | ||
251 | // RequestTexture); | ||
252 | } | ||
253 | catch (Exception e) | ||
254 | { | ||
255 | m_log.Error("[CAPS]: " + e.ToString()); | ||
256 | } | ||
257 | } | ||
258 | |||
259 | /// <summary> | ||
260 | /// Construct a client response detailing all the capabilities this server can provide. | ||
261 | /// </summary> | ||
262 | /// <param name="request"></param> | ||
263 | /// <param name="path"></param> | ||
264 | /// <param name="param"></param> | ||
265 | /// <param name="httpRequest">HTTP request header object</param> | ||
266 | /// <param name="httpResponse">HTTP response header object</param> | ||
267 | /// <returns></returns> | ||
268 | public string SeedCapRequest(string request, string path, string param, | ||
269 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
270 | { | ||
271 | // m_log.DebugFormat( | ||
272 | // "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); | ||
273 | |||
274 | if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) | ||
275 | { | ||
276 | m_log.WarnFormat( | ||
277 | "[CAPS]: Unauthorized CAPS client {0} from {1}", | ||
278 | m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint); | ||
279 | |||
280 | return string.Empty; | ||
281 | } | ||
282 | |||
283 | OSDArray capsRequested = (OSDArray)OSDParser.DeserializeLLSDXml(request); | ||
284 | List<string> validCaps = new List<string>(); | ||
285 | |||
286 | foreach (OSD c in capsRequested) | ||
287 | validCaps.Add(c.AsString()); | ||
288 | |||
289 | string result = LLSDHelpers.SerialiseLLSDReply(m_HostCapsObj.GetCapsDetails(true, validCaps)); | ||
290 | |||
291 | //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); | ||
292 | |||
293 | return result; | ||
294 | } | ||
295 | |||
296 | /// <summary> | ||
297 | /// Called by the script task update handler. Provides a URL to which the client can upload a new asset. | ||
298 | /// </summary> | ||
299 | /// <param name="request"></param> | ||
300 | /// <param name="path"></param> | ||
301 | /// <param name="param"></param> | ||
302 | /// <param name="httpRequest">HTTP request header object</param> | ||
303 | /// <param name="httpResponse">HTTP response header object</param> | ||
304 | /// <returns></returns> | ||
305 | public string ScriptTaskInventory(string request, string path, string param, | ||
306 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
307 | { | ||
308 | try | ||
309 | { | ||
310 | // m_log.Debug("[CAPS]: ScriptTaskInventory Request in region: " + m_regionName); | ||
311 | //m_log.DebugFormat("[CAPS]: request: {0}, path: {1}, param: {2}", request, path, param); | ||
312 | |||
313 | Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); | ||
314 | LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate(); | ||
315 | LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest); | ||
316 | |||
317 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | ||
318 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | ||
319 | |||
320 | TaskInventoryScriptUpdater uploader = | ||
321 | new TaskInventoryScriptUpdater( | ||
322 | llsdUpdateRequest.item_id, | ||
323 | llsdUpdateRequest.task_id, | ||
324 | llsdUpdateRequest.is_script_running, | ||
325 | capsBase + uploaderPath, | ||
326 | m_HostCapsObj.HttpListener, | ||
327 | m_dumpAssetsToFile); | ||
328 | uploader.OnUpLoad += TaskScriptUpdated; | ||
329 | |||
330 | m_HostCapsObj.HttpListener.AddStreamHandler( | ||
331 | new BinaryStreamHandler( | ||
332 | "POST", capsBase + uploaderPath, uploader.uploaderCaps, "TaskInventoryScriptUpdater", null)); | ||
333 | |||
334 | string protocol = "http://"; | ||
335 | |||
336 | if (m_HostCapsObj.SSLCaps) | ||
337 | protocol = "https://"; | ||
338 | |||
339 | string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + | ||
340 | uploaderPath; | ||
341 | |||
342 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); | ||
343 | uploadResponse.uploader = uploaderURL; | ||
344 | uploadResponse.state = "upload"; | ||
345 | |||
346 | // m_log.InfoFormat("[CAPS]: " + | ||
347 | // "ScriptTaskInventory response: {0}", | ||
348 | // LLSDHelpers.SerialiseLLSDReply(uploadResponse))); | ||
349 | |||
350 | return LLSDHelpers.SerialiseLLSDReply(uploadResponse); | ||
351 | } | ||
352 | catch (Exception e) | ||
353 | { | ||
354 | m_log.Error("[CAPS]: " + e.ToString()); | ||
355 | } | ||
356 | |||
357 | return null; | ||
358 | } | ||
359 | |||
360 | /// <summary> | ||
361 | /// Called when new asset data for an agent inventory item update has been uploaded. | ||
362 | /// </summary> | ||
363 | /// <param name="itemID">Item to update</param> | ||
364 | /// <param name="primID">Prim containing item to update</param> | ||
365 | /// <param name="isScriptRunning">Signals whether the script to update is currently running</param> | ||
366 | /// <param name="data">New asset data</param> | ||
367 | public void TaskScriptUpdated(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors) | ||
368 | { | ||
369 | if (TaskScriptUpdatedCall != null) | ||
370 | { | ||
371 | ArrayList e = TaskScriptUpdatedCall(m_HostCapsObj.AgentID, itemID, primID, isScriptRunning, data); | ||
372 | foreach (Object item in e) | ||
373 | errors.Add(item); | ||
374 | } | ||
375 | } | ||
376 | |||
377 | /// <summary> | ||
378 | /// Called when new asset data for an agent inventory item update has been uploaded. | ||
379 | /// </summary> | ||
380 | /// <param name="itemID">Item to update</param> | ||
381 | /// <param name="data">New asset data</param> | ||
382 | /// <returns></returns> | ||
383 | public UUID ItemUpdated(UUID itemID, byte[] data) | ||
384 | { | ||
385 | if (ItemUpdatedCall != null) | ||
386 | { | ||
387 | return ItemUpdatedCall(m_HostCapsObj.AgentID, itemID, data); | ||
388 | } | ||
389 | |||
390 | return UUID.Zero; | ||
391 | } | ||
392 | |||
393 | /// <summary> | ||
394 | /// | ||
395 | /// </summary> | ||
396 | /// <param name="llsdRequest"></param> | ||
397 | /// <returns></returns> | ||
398 | public LLSDAssetUploadResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest) | ||
399 | { | ||
400 | //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); | ||
401 | //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); | ||
402 | |||
403 | if (llsdRequest.asset_type == "texture" || | ||
404 | llsdRequest.asset_type == "animation" || | ||
405 | llsdRequest.asset_type == "sound") | ||
406 | { | ||
407 | ScenePresence avatar = null; | ||
408 | IClientAPI client = null; | ||
409 | m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); | ||
410 | |||
411 | // check user level | ||
412 | if (avatar != null) | ||
413 | { | ||
414 | client = avatar.ControllingClient; | ||
415 | |||
416 | if (avatar.UserLevel < m_levelUpload) | ||
417 | { | ||
418 | if (client != null) | ||
419 | client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); | ||
420 | |||
421 | LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); | ||
422 | errorResponse.uploader = ""; | ||
423 | errorResponse.state = "error"; | ||
424 | return errorResponse; | ||
425 | } | ||
426 | } | ||
427 | |||
428 | // check funds | ||
429 | if (client != null) | ||
430 | { | ||
431 | IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); | ||
432 | |||
433 | if (mm != null) | ||
434 | { | ||
435 | if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) | ||
436 | { | ||
437 | client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); | ||
438 | |||
439 | LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); | ||
440 | errorResponse.uploader = ""; | ||
441 | errorResponse.state = "error"; | ||
442 | return errorResponse; | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | |||
448 | string assetName = llsdRequest.name; | ||
449 | string assetDes = llsdRequest.description; | ||
450 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | ||
451 | UUID newAsset = UUID.Random(); | ||
452 | UUID newInvItem = UUID.Random(); | ||
453 | UUID parentFolder = llsdRequest.folder_id; | ||
454 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | ||
455 | |||
456 | AssetUploader uploader = | ||
457 | new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, | ||
458 | llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); | ||
459 | |||
460 | m_HostCapsObj.HttpListener.AddStreamHandler( | ||
461 | new BinaryStreamHandler( | ||
462 | "POST", | ||
463 | capsBase + uploaderPath, | ||
464 | uploader.uploaderCaps, | ||
465 | "NewAgentInventoryRequest", | ||
466 | m_HostCapsObj.AgentID.ToString())); | ||
467 | |||
468 | string protocol = "http://"; | ||
469 | |||
470 | if (m_HostCapsObj.SSLCaps) | ||
471 | protocol = "https://"; | ||
472 | |||
473 | string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + | ||
474 | uploaderPath; | ||
475 | |||
476 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); | ||
477 | uploadResponse.uploader = uploaderURL; | ||
478 | uploadResponse.state = "upload"; | ||
479 | uploader.OnUpLoad += UploadCompleteHandler; | ||
480 | return uploadResponse; | ||
481 | } | ||
482 | |||
483 | /// <summary> | ||
484 | /// Convert raw uploaded data into the appropriate asset and item. | ||
485 | /// </summary> | ||
486 | /// <param name="assetID"></param> | ||
487 | /// <param name="inventoryItem"></param> | ||
488 | /// <param name="data"></param> | ||
489 | public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, | ||
490 | UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, | ||
491 | string assetType) | ||
492 | { | ||
493 | m_log.DebugFormat( | ||
494 | "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", | ||
495 | assetID, inventoryItem, inventoryType, assetType); | ||
496 | |||
497 | sbyte assType = 0; | ||
498 | sbyte inType = 0; | ||
499 | |||
500 | if (inventoryType == "sound") | ||
501 | { | ||
502 | inType = (sbyte)InventoryType.Sound; | ||
503 | assType = (sbyte)AssetType.Sound; | ||
504 | } | ||
505 | else if (inventoryType == "snapshot") | ||
506 | { | ||
507 | inType = (sbyte)InventoryType.Snapshot; | ||
508 | } | ||
509 | else if (inventoryType == "animation") | ||
510 | { | ||
511 | inType = (sbyte)InventoryType.Animation; | ||
512 | assType = (sbyte)AssetType.Animation; | ||
513 | } | ||
514 | else if (inventoryType == "wearable") | ||
515 | { | ||
516 | inType = (sbyte)InventoryType.Wearable; | ||
517 | switch (assetType) | ||
518 | { | ||
519 | case "bodypart": | ||
520 | assType = (sbyte)AssetType.Bodypart; | ||
521 | break; | ||
522 | case "clothing": | ||
523 | assType = (sbyte)AssetType.Clothing; | ||
524 | break; | ||
525 | } | ||
526 | } | ||
527 | else if (inventoryType == "object") | ||
528 | { | ||
529 | inType = (sbyte)InventoryType.Object; | ||
530 | assType = (sbyte)AssetType.Object; | ||
531 | |||
532 | List<Vector3> positions = new List<Vector3>(); | ||
533 | List<Quaternion> rotations = new List<Quaternion>(); | ||
534 | OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data); | ||
535 | OSDArray instance_list = (OSDArray)request["instance_list"]; | ||
536 | OSDArray mesh_list = (OSDArray)request["mesh_list"]; | ||
537 | OSDArray texture_list = (OSDArray)request["texture_list"]; | ||
538 | SceneObjectGroup grp = null; | ||
539 | |||
540 | InventoryFolderBase textureUploadFolder = null; | ||
541 | |||
542 | List<InventoryFolderBase> foldersToUpdate = new List<InventoryFolderBase>(); | ||
543 | List<InventoryItemBase> itemsToUpdate = new List<InventoryItemBase>(); | ||
544 | IClientInventory clientInv = null; | ||
545 | |||
546 | if (texture_list.Count > 0) | ||
547 | { | ||
548 | ScenePresence avatar = null; | ||
549 | m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); | ||
550 | |||
551 | if (avatar != null) | ||
552 | { | ||
553 | IClientCore core = (IClientCore)avatar.ControllingClient; | ||
554 | |||
555 | if (core.TryGet<IClientInventory>(out clientInv)) | ||
556 | { | ||
557 | var systemTextureFolder = m_Scene.InventoryService.GetFolderForType(m_HostCapsObj.AgentID, FolderType.Texture); | ||
558 | textureUploadFolder = new InventoryFolderBase(UUID.Random(), assetName, m_HostCapsObj.AgentID, (short)FolderType.None, systemTextureFolder.ID, 1); | ||
559 | if (m_Scene.InventoryService.AddFolder(textureUploadFolder)) | ||
560 | { | ||
561 | foldersToUpdate.Add(textureUploadFolder); | ||
562 | |||
563 | m_log.DebugFormat( | ||
564 | "[BUNCH OF CAPS]: Created new folder '{0}' ({1}) for textures uploaded with mesh object {2}", | ||
565 | textureUploadFolder.Name, textureUploadFolder.ID, assetName); | ||
566 | } | ||
567 | else | ||
568 | { | ||
569 | textureUploadFolder = null; | ||
570 | } | ||
571 | } | ||
572 | } | ||
573 | } | ||
574 | |||
575 | List<UUID> textures = new List<UUID>(); | ||
576 | for (int i = 0; i < texture_list.Count; i++) | ||
577 | { | ||
578 | AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); | ||
579 | textureAsset.Data = texture_list[i].AsBinary(); | ||
580 | m_assetService.Store(textureAsset); | ||
581 | textures.Add(textureAsset.FullID); | ||
582 | |||
583 | if (textureUploadFolder != null) | ||
584 | { | ||
585 | InventoryItemBase textureItem = new InventoryItemBase(); | ||
586 | textureItem.Owner = m_HostCapsObj.AgentID; | ||
587 | textureItem.CreatorId = m_HostCapsObj.AgentID.ToString(); | ||
588 | textureItem.CreatorData = String.Empty; | ||
589 | textureItem.ID = UUID.Random(); | ||
590 | textureItem.AssetID = textureAsset.FullID; | ||
591 | textureItem.Description = assetDescription; | ||
592 | textureItem.Name = assetName + " - Texture " + (i + 1).ToString(); | ||
593 | textureItem.AssetType = (int)AssetType.Texture; | ||
594 | textureItem.InvType = (int)InventoryType.Texture; | ||
595 | textureItem.Folder = textureUploadFolder.ID; | ||
596 | textureItem.CurrentPermissions | ||
597 | = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export); | ||
598 | textureItem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; | ||
599 | textureItem.EveryOnePermissions = 0; | ||
600 | textureItem.NextPermissions = (uint)PermissionMask.All; | ||
601 | textureItem.CreationDate = Util.UnixTimeSinceEpoch(); | ||
602 | m_Scene.InventoryService.AddItem(textureItem); | ||
603 | itemsToUpdate.Add(textureItem); | ||
604 | |||
605 | m_log.DebugFormat( | ||
606 | "[BUNCH OF CAPS]: Created new inventory item '{0}' ({1}) for texture uploaded with mesh object {2}", | ||
607 | textureItem.Name, textureItem.ID, assetName); | ||
608 | } | ||
609 | } | ||
610 | |||
611 | if (clientInv != null && (foldersToUpdate.Count > 0 || itemsToUpdate.Count > 0)) | ||
612 | { | ||
613 | clientInv.SendBulkUpdateInventory(foldersToUpdate.ToArray(), itemsToUpdate.ToArray()); | ||
614 | } | ||
615 | |||
616 | for (int i = 0; i < mesh_list.Count; i++) | ||
617 | { | ||
618 | PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); | ||
619 | |||
620 | Primitive.TextureEntry textureEntry | ||
621 | = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE); | ||
622 | OSDMap inner_instance_list = (OSDMap)instance_list[i]; | ||
623 | |||
624 | OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; | ||
625 | for (uint face = 0; face < face_list.Count; face++) | ||
626 | { | ||
627 | OSDMap faceMap = (OSDMap)face_list[(int)face]; | ||
628 | Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); | ||
629 | if(faceMap.ContainsKey("fullbright")) | ||
630 | f.Fullbright = faceMap["fullbright"].AsBoolean(); | ||
631 | if (faceMap.ContainsKey ("diffuse_color")) | ||
632 | f.RGBA = faceMap["diffuse_color"].AsColor4(); | ||
633 | |||
634 | int textureNum = faceMap["image"].AsInteger(); | ||
635 | float imagerot = faceMap["imagerot"].AsInteger(); | ||
636 | float offsets = (float)faceMap["offsets"].AsReal(); | ||
637 | float offsett = (float)faceMap["offsett"].AsReal(); | ||
638 | float scales = (float)faceMap["scales"].AsReal(); | ||
639 | float scalet = (float)faceMap["scalet"].AsReal(); | ||
640 | |||
641 | if(imagerot != 0) | ||
642 | f.Rotation = imagerot; | ||
643 | |||
644 | if(offsets != 0) | ||
645 | f.OffsetU = offsets; | ||
646 | |||
647 | if (offsett != 0) | ||
648 | f.OffsetV = offsett; | ||
649 | |||
650 | if (scales != 0) | ||
651 | f.RepeatU = scales; | ||
652 | |||
653 | if (scalet != 0) | ||
654 | f.RepeatV = scalet; | ||
655 | |||
656 | if (textures.Count > textureNum) | ||
657 | f.TextureID = textures[textureNum]; | ||
658 | else | ||
659 | f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE; | ||
660 | |||
661 | textureEntry.FaceTextures[face] = f; | ||
662 | } | ||
663 | |||
664 | pbs.TextureEntry = textureEntry.GetBytes(); | ||
665 | |||
666 | AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); | ||
667 | meshAsset.Data = mesh_list[i].AsBinary(); | ||
668 | m_assetService.Store(meshAsset); | ||
669 | |||
670 | pbs.SculptEntry = true; | ||
671 | pbs.SculptTexture = meshAsset.FullID; | ||
672 | pbs.SculptType = (byte)SculptType.Mesh; | ||
673 | pbs.SculptData = meshAsset.Data; | ||
674 | |||
675 | Vector3 position = inner_instance_list["position"].AsVector3(); | ||
676 | Vector3 scale = inner_instance_list["scale"].AsVector3(); | ||
677 | Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); | ||
678 | |||
679 | // no longer used - begin ------------------------ | ||
680 | // int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger(); | ||
681 | // int material = inner_instance_list["material"].AsInteger(); | ||
682 | // int mesh = inner_instance_list["mesh"].AsInteger(); | ||
683 | |||
684 | // OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; | ||
685 | // int base_mask = permissions["base_mask"].AsInteger(); | ||
686 | // int everyone_mask = permissions["everyone_mask"].AsInteger(); | ||
687 | // UUID creator_id = permissions["creator_id"].AsUUID(); | ||
688 | // UUID group_id = permissions["group_id"].AsUUID(); | ||
689 | // int group_mask = permissions["group_mask"].AsInteger(); | ||
690 | // bool is_owner_group = permissions["is_owner_group"].AsBoolean(); | ||
691 | // UUID last_owner_id = permissions["last_owner_id"].AsUUID(); | ||
692 | // int next_owner_mask = permissions["next_owner_mask"].AsInteger(); | ||
693 | // UUID owner_id = permissions["owner_id"].AsUUID(); | ||
694 | // int owner_mask = permissions["owner_mask"].AsInteger(); | ||
695 | // no longer used - end ------------------------ | ||
696 | |||
697 | UUID owner_id = m_HostCapsObj.AgentID; | ||
698 | |||
699 | SceneObjectPart prim | ||
700 | = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); | ||
701 | |||
702 | prim.Scale = scale; | ||
703 | //prim.OffsetPosition = position; | ||
704 | rotations.Add(rotation); | ||
705 | positions.Add(position); | ||
706 | prim.UUID = UUID.Random(); | ||
707 | prim.CreatorID = owner_id; | ||
708 | prim.OwnerID = owner_id; | ||
709 | prim.GroupID = UUID.Zero; | ||
710 | prim.LastOwnerID = prim.OwnerID; | ||
711 | prim.CreationDate = Util.UnixTimeSinceEpoch(); | ||
712 | prim.Name = assetName; | ||
713 | prim.Description = ""; | ||
714 | |||
715 | // prim.BaseMask = (uint)base_mask; | ||
716 | // prim.EveryoneMask = (uint)everyone_mask; | ||
717 | // prim.GroupMask = (uint)group_mask; | ||
718 | // prim.NextOwnerMask = (uint)next_owner_mask; | ||
719 | // prim.OwnerMask = (uint)owner_mask; | ||
720 | |||
721 | if (grp == null) | ||
722 | grp = new SceneObjectGroup(prim); | ||
723 | else | ||
724 | grp.AddPart(prim); | ||
725 | } | ||
726 | |||
727 | Vector3 rootPos = positions[0]; | ||
728 | |||
729 | if (grp.Parts.Length > 1) | ||
730 | { | ||
731 | // Fix first link number | ||
732 | grp.RootPart.LinkNum++; | ||
733 | |||
734 | Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); | ||
735 | Quaternion tmprot; | ||
736 | Vector3 offset; | ||
737 | |||
738 | // fix children rotations and positions | ||
739 | for (int i = 1; i < rotations.Count; i++) | ||
740 | { | ||
741 | tmprot = rotations[i]; | ||
742 | tmprot = rootRotConj * tmprot; | ||
743 | |||
744 | grp.Parts[i].RotationOffset = tmprot; | ||
745 | |||
746 | offset = positions[i] - rootPos; | ||
747 | |||
748 | offset *= rootRotConj; | ||
749 | grp.Parts[i].OffsetPosition = offset; | ||
750 | } | ||
751 | |||
752 | grp.AbsolutePosition = rootPos; | ||
753 | grp.UpdateGroupRotationR(rotations[0]); | ||
754 | } | ||
755 | else | ||
756 | { | ||
757 | grp.AbsolutePosition = rootPos; | ||
758 | grp.UpdateGroupRotationR(rotations[0]); | ||
759 | } | ||
760 | |||
761 | data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp)); | ||
762 | } | ||
763 | |||
764 | AssetBase asset; | ||
765 | asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); | ||
766 | asset.Data = data; | ||
767 | if (AddNewAsset != null) | ||
768 | AddNewAsset(asset); | ||
769 | else if (m_assetService != null) | ||
770 | m_assetService.Store(asset); | ||
771 | |||
772 | InventoryItemBase item = new InventoryItemBase(); | ||
773 | item.Owner = m_HostCapsObj.AgentID; | ||
774 | item.CreatorId = m_HostCapsObj.AgentID.ToString(); | ||
775 | item.CreatorData = String.Empty; | ||
776 | item.ID = inventoryItem; | ||
777 | item.AssetID = asset.FullID; | ||
778 | item.Description = assetDescription; | ||
779 | item.Name = assetName; | ||
780 | item.AssetType = assType; | ||
781 | item.InvType = inType; | ||
782 | item.Folder = parentFolder; | ||
783 | |||
784 | // If we set PermissionMask.All then when we rez the item the next permissions will replace the current | ||
785 | // (owner) permissions. This becomes a problem if next permissions are changed. | ||
786 | item.CurrentPermissions | ||
787 | = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export); | ||
788 | |||
789 | item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; | ||
790 | item.EveryOnePermissions = 0; | ||
791 | item.NextPermissions = (uint)PermissionMask.All; | ||
792 | item.CreationDate = Util.UnixTimeSinceEpoch(); | ||
793 | |||
794 | if (AddNewInventoryItem != null) | ||
795 | { | ||
796 | AddNewInventoryItem(m_HostCapsObj.AgentID, item); | ||
797 | } | ||
798 | } | ||
799 | |||
800 | /// <summary> | ||
801 | /// | ||
802 | /// </summary> | ||
803 | /// <param name="mapReq"></param> | ||
804 | /// <returns></returns> | ||
805 | public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq) | ||
806 | { | ||
807 | m_log.Debug("[CAPS]: MapLayer Request in region: " + m_regionName); | ||
808 | LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); | ||
809 | mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); | ||
810 | return mapResponse; | ||
811 | } | ||
812 | |||
813 | /// <summary> | ||
814 | /// | ||
815 | /// </summary> | ||
816 | /// <returns></returns> | ||
817 | protected static OSDMapLayer GetOSDMapLayerResponse() | ||
818 | { | ||
819 | OSDMapLayer mapLayer = new OSDMapLayer(); | ||
820 | mapLayer.Right = 5000; | ||
821 | mapLayer.Top = 5000; | ||
822 | mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006"); | ||
823 | |||
824 | return mapLayer; | ||
825 | } | ||
826 | |||
827 | /// <summary> | ||
828 | /// | ||
829 | /// </summary> | ||
830 | /// <param name="request"></param> | ||
831 | /// <param name="path"></param> | ||
832 | /// <param name="param"></param> | ||
833 | /// <returns></returns> | ||
834 | public string RequestTexture(string request, string path, string param) | ||
835 | { | ||
836 | m_log.Debug("texture request " + request); | ||
837 | // Needs implementing (added to remove compiler warning) | ||
838 | return String.Empty; | ||
839 | } | ||
840 | |||
841 | |||
842 | /// <summary> | ||
843 | /// Called by the notecard update handler. Provides a URL to which the client can upload a new asset. | ||
844 | /// </summary> | ||
845 | /// <param name="request"></param> | ||
846 | /// <param name="path"></param> | ||
847 | /// <param name="param"></param> | ||
848 | /// <returns></returns> | ||
849 | public string NoteCardAgentInventory(string request, string path, string param, | ||
850 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
851 | { | ||
852 | //m_log.Debug("[CAPS]: NoteCardAgentInventory Request in region: " + m_regionName + "\n" + request); | ||
853 | //m_log.Debug("[CAPS]: NoteCardAgentInventory Request is: " + request); | ||
854 | |||
855 | //OpenMetaverse.StructuredData.OSDMap hash = (OpenMetaverse.StructuredData.OSDMap)OpenMetaverse.StructuredData.LLSDParser.DeserializeBinary(Utils.StringToBytes(request)); | ||
856 | Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); | ||
857 | LLSDItemUpdate llsdRequest = new LLSDItemUpdate(); | ||
858 | LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest); | ||
859 | |||
860 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | ||
861 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | ||
862 | |||
863 | ItemUpdater uploader = | ||
864 | new ItemUpdater(llsdRequest.item_id, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); | ||
865 | uploader.OnUpLoad += ItemUpdated; | ||
866 | |||
867 | m_HostCapsObj.HttpListener.AddStreamHandler( | ||
868 | new BinaryStreamHandler( | ||
869 | "POST", capsBase + uploaderPath, uploader.uploaderCaps, "NoteCardAgentInventory", null)); | ||
870 | |||
871 | string protocol = "http://"; | ||
872 | |||
873 | if (m_HostCapsObj.SSLCaps) | ||
874 | protocol = "https://"; | ||
875 | |||
876 | string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + | ||
877 | uploaderPath; | ||
878 | |||
879 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); | ||
880 | uploadResponse.uploader = uploaderURL; | ||
881 | uploadResponse.state = "upload"; | ||
882 | |||
883 | // m_log.InfoFormat("[CAPS]: " + | ||
884 | // "NoteCardAgentInventory response: {0}", | ||
885 | // LLSDHelpers.SerialiseLLSDReply(uploadResponse))); | ||
886 | |||
887 | return LLSDHelpers.SerialiseLLSDReply(uploadResponse); | ||
888 | } | ||
889 | |||
890 | /// <summary> | ||
891 | /// Called by the CopyInventoryFromNotecard caps handler. | ||
892 | /// </summary> | ||
893 | /// <param name="request"></param> | ||
894 | /// <param name="path"></param> | ||
895 | /// <param name="param"></param> | ||
896 | public string CopyInventoryFromNotecard(string request, string path, string param, | ||
897 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
898 | { | ||
899 | Hashtable response = new Hashtable(); | ||
900 | response["int_response_code"] = 404; | ||
901 | response["content_type"] = "text/plain"; | ||
902 | response["keepalive"] = false; | ||
903 | response["str_response_string"] = ""; | ||
904 | |||
905 | try | ||
906 | { | ||
907 | OSDMap content = (OSDMap)OSDParser.DeserializeLLSDXml(request); | ||
908 | UUID objectID = content["object-id"].AsUUID(); | ||
909 | UUID notecardID = content["notecard-id"].AsUUID(); | ||
910 | UUID folderID = content["folder-id"].AsUUID(); | ||
911 | UUID itemID = content["item-id"].AsUUID(); | ||
912 | |||
913 | // m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, FolderID:{0}, ItemID:{1}, NotecardID:{2}, ObjectID:{3}", folderID, itemID, notecardID, objectID); | ||
914 | |||
915 | if (objectID != UUID.Zero) | ||
916 | { | ||
917 | SceneObjectPart part = m_Scene.GetSceneObjectPart(objectID); | ||
918 | if (part != null) | ||
919 | { | ||
920 | // TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(notecardID); | ||
921 | if (!m_Scene.Permissions.CanCopyObjectInventory(notecardID, objectID, m_HostCapsObj.AgentID)) | ||
922 | { | ||
923 | return LLSDHelpers.SerialiseLLSDReply(response); | ||
924 | } | ||
925 | } | ||
926 | } | ||
927 | |||
928 | InventoryItemBase item = null; | ||
929 | InventoryItemBase copyItem = null; | ||
930 | IClientAPI client = null; | ||
931 | |||
932 | m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); | ||
933 | item = m_Scene.InventoryService.GetItem(new InventoryItemBase(itemID)); | ||
934 | if (item != null) | ||
935 | { | ||
936 | string message; | ||
937 | copyItem = m_Scene.GiveInventoryItem(m_HostCapsObj.AgentID, item.Owner, itemID, folderID, out message); | ||
938 | if (client != null) | ||
939 | { | ||
940 | if (copyItem != null) | ||
941 | { | ||
942 | m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, ItemID:{0}, FolderID:{1}", copyItem.ID, copyItem.Folder); | ||
943 | client.SendBulkUpdateInventory(copyItem); | ||
944 | } | ||
945 | else | ||
946 | { | ||
947 | client.SendAgentAlertMessage(message, false); | ||
948 | } | ||
949 | } | ||
950 | } | ||
951 | else | ||
952 | { | ||
953 | m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard - Failed to retrieve item {0} from notecard {1}", itemID, notecardID); | ||
954 | if (client != null) | ||
955 | client.SendAgentAlertMessage("Failed to retrieve item", false); | ||
956 | } | ||
957 | } | ||
958 | catch (Exception e) | ||
959 | { | ||
960 | m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard : {0}", e.ToString()); | ||
961 | } | ||
962 | |||
963 | response["int_response_code"] = 200; | ||
964 | return LLSDHelpers.SerialiseLLSDReply(response); | ||
965 | } | ||
966 | |||
967 | public string GetObjectPhysicsData(string request, string path, | ||
968 | string param, IOSHttpRequest httpRequest, | ||
969 | IOSHttpResponse httpResponse) | ||
970 | { | ||
971 | OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); | ||
972 | OSDMap resp = new OSDMap(); | ||
973 | OSDArray object_ids = (OSDArray)req["object_ids"]; | ||
974 | |||
975 | for (int i = 0 ; i < object_ids.Count ; i++) | ||
976 | { | ||
977 | UUID uuid = object_ids[i].AsUUID(); | ||
978 | |||
979 | SceneObjectPart obj = m_Scene.GetSceneObjectPart(uuid); | ||
980 | if (obj != null) | ||
981 | { | ||
982 | OSDMap object_data = new OSDMap(); | ||
983 | |||
984 | object_data["PhysicsShapeType"] = obj.PhysicsShapeType; | ||
985 | object_data["Density"] = obj.Density; | ||
986 | object_data["Friction"] = obj.Friction; | ||
987 | object_data["Restitution"] = obj.Restitution; | ||
988 | object_data["GravityMultiplier"] = obj.GravityModifier; | ||
989 | |||
990 | resp[uuid.ToString()] = object_data; | ||
991 | } | ||
992 | } | ||
993 | |||
994 | string response = OSDParser.SerializeLLSDXmlString(resp); | ||
995 | return response; | ||
996 | } | ||
997 | |||
998 | public string UpdateAgentInformation(string request, string path, | ||
999 | string param, IOSHttpRequest httpRequest, | ||
1000 | IOSHttpResponse httpResponse) | ||
1001 | { | ||
1002 | OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); | ||
1003 | OSDMap accessPrefs = (OSDMap)req["access_prefs"]; | ||
1004 | string desiredMaturity = accessPrefs["max"]; | ||
1005 | |||
1006 | OSDMap resp = new OSDMap(); | ||
1007 | OSDMap respAccessPrefs = new OSDMap(); | ||
1008 | respAccessPrefs["max"] = desiredMaturity; // echoing the maturity back means success | ||
1009 | resp["access_prefs"] = respAccessPrefs; | ||
1010 | |||
1011 | string response = OSDParser.SerializeLLSDXmlString(resp); | ||
1012 | return response; | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | public class AssetUploader | ||
1017 | { | ||
1018 | public event UpLoadedAsset OnUpLoad; | ||
1019 | private UpLoadedAsset handlerUpLoad = null; | ||
1020 | |||
1021 | private string uploaderPath = String.Empty; | ||
1022 | private UUID newAssetID; | ||
1023 | private UUID inventoryItemID; | ||
1024 | private UUID parentFolder; | ||
1025 | private IHttpServer httpListener; | ||
1026 | private bool m_dumpAssetsToFile; | ||
1027 | private string m_assetName = String.Empty; | ||
1028 | private string m_assetDes = String.Empty; | ||
1029 | |||
1030 | private string m_invType = String.Empty; | ||
1031 | private string m_assetType = String.Empty; | ||
1032 | |||
1033 | public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, | ||
1034 | UUID parentFolderID, string invType, string assetType, string path, | ||
1035 | IHttpServer httpServer, bool dumpAssetsToFile) | ||
1036 | { | ||
1037 | m_assetName = assetName; | ||
1038 | m_assetDes = description; | ||
1039 | newAssetID = assetID; | ||
1040 | inventoryItemID = inventoryItem; | ||
1041 | uploaderPath = path; | ||
1042 | httpListener = httpServer; | ||
1043 | parentFolder = parentFolderID; | ||
1044 | m_assetType = assetType; | ||
1045 | m_invType = invType; | ||
1046 | m_dumpAssetsToFile = dumpAssetsToFile; | ||
1047 | } | ||
1048 | |||
1049 | /// <summary> | ||
1050 | /// Handle raw asset upload data via the capability. | ||
1051 | /// </summary> | ||
1052 | /// <param name="data"></param> | ||
1053 | /// <param name="path"></param> | ||
1054 | /// <param name="param"></param> | ||
1055 | /// <returns></returns> | ||
1056 | public string uploaderCaps(byte[] data, string path, string param) | ||
1057 | { | ||
1058 | UUID inv = inventoryItemID; | ||
1059 | string res = String.Empty; | ||
1060 | LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); | ||
1061 | uploadComplete.new_asset = newAssetID.ToString(); | ||
1062 | uploadComplete.new_inventory_item = inv; | ||
1063 | uploadComplete.state = "complete"; | ||
1064 | |||
1065 | res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); | ||
1066 | |||
1067 | httpListener.RemoveStreamHandler("POST", uploaderPath); | ||
1068 | |||
1069 | // TODO: probably make this a better set of extensions here | ||
1070 | string extension = ".jp2"; | ||
1071 | if (m_invType != "image") | ||
1072 | { | ||
1073 | extension = ".dat"; | ||
1074 | } | ||
1075 | |||
1076 | if (m_dumpAssetsToFile) | ||
1077 | { | ||
1078 | SaveAssetToFile(m_assetName + extension, data); | ||
1079 | } | ||
1080 | handlerUpLoad = OnUpLoad; | ||
1081 | if (handlerUpLoad != null) | ||
1082 | { | ||
1083 | handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); | ||
1084 | } | ||
1085 | |||
1086 | return res; | ||
1087 | } | ||
1088 | |||
1089 | ///Left this in and commented in case there are unforseen issues | ||
1090 | //private void SaveAssetToFile(string filename, byte[] data) | ||
1091 | //{ | ||
1092 | // FileStream fs = File.Create(filename); | ||
1093 | // BinaryWriter bw = new BinaryWriter(fs); | ||
1094 | // bw.Write(data); | ||
1095 | // bw.Close(); | ||
1096 | // fs.Close(); | ||
1097 | //} | ||
1098 | |||
1099 | private static void SaveAssetToFile(string filename, byte[] data) | ||
1100 | { | ||
1101 | string assetPath = "UserAssets"; | ||
1102 | if (!Directory.Exists(assetPath)) | ||
1103 | { | ||
1104 | Directory.CreateDirectory(assetPath); | ||
1105 | } | ||
1106 | FileStream fs = File.Create(Path.Combine(assetPath, Util.safeFileName(filename))); | ||
1107 | BinaryWriter bw = new BinaryWriter(fs); | ||
1108 | bw.Write(data); | ||
1109 | bw.Close(); | ||
1110 | fs.Close(); | ||
1111 | } | ||
1112 | } | ||
1113 | |||
1114 | /// <summary> | ||
1115 | /// This class is a callback invoked when a client sends asset data to | ||
1116 | /// an agent inventory notecard update url | ||
1117 | /// </summary> | ||
1118 | public class ItemUpdater | ||
1119 | { | ||
1120 | public event UpdateItem OnUpLoad; | ||
1121 | |||
1122 | private UpdateItem handlerUpdateItem = null; | ||
1123 | |||
1124 | private string uploaderPath = String.Empty; | ||
1125 | private UUID inventoryItemID; | ||
1126 | private IHttpServer httpListener; | ||
1127 | private bool m_dumpAssetToFile; | ||
1128 | |||
1129 | public ItemUpdater(UUID inventoryItem, string path, IHttpServer httpServer, bool dumpAssetToFile) | ||
1130 | { | ||
1131 | m_dumpAssetToFile = dumpAssetToFile; | ||
1132 | |||
1133 | inventoryItemID = inventoryItem; | ||
1134 | uploaderPath = path; | ||
1135 | httpListener = httpServer; | ||
1136 | } | ||
1137 | |||
1138 | /// <summary> | ||
1139 | /// Handle raw uploaded asset data. | ||
1140 | /// </summary> | ||
1141 | /// <param name="data"></param> | ||
1142 | /// <param name="path"></param> | ||
1143 | /// <param name="param"></param> | ||
1144 | /// <returns></returns> | ||
1145 | public string uploaderCaps(byte[] data, string path, string param) | ||
1146 | { | ||
1147 | UUID inv = inventoryItemID; | ||
1148 | string res = String.Empty; | ||
1149 | LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); | ||
1150 | UUID assetID = UUID.Zero; | ||
1151 | handlerUpdateItem = OnUpLoad; | ||
1152 | if (handlerUpdateItem != null) | ||
1153 | { | ||
1154 | assetID = handlerUpdateItem(inv, data); | ||
1155 | } | ||
1156 | |||
1157 | uploadComplete.new_asset = assetID.ToString(); | ||
1158 | uploadComplete.new_inventory_item = inv; | ||
1159 | uploadComplete.state = "complete"; | ||
1160 | |||
1161 | res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); | ||
1162 | |||
1163 | httpListener.RemoveStreamHandler("POST", uploaderPath); | ||
1164 | |||
1165 | if (m_dumpAssetToFile) | ||
1166 | { | ||
1167 | SaveAssetToFile("updateditem" + Util.RandomClass.Next(1, 1000) + ".dat", data); | ||
1168 | } | ||
1169 | |||
1170 | return res; | ||
1171 | } | ||
1172 | |||
1173 | ///Left this in and commented in case there are unforseen issues | ||
1174 | //private void SaveAssetToFile(string filename, byte[] data) | ||
1175 | //{ | ||
1176 | // FileStream fs = File.Create(filename); | ||
1177 | // BinaryWriter bw = new BinaryWriter(fs); | ||
1178 | // bw.Write(data); | ||
1179 | // bw.Close(); | ||
1180 | // fs.Close(); | ||
1181 | //} | ||
1182 | |||
1183 | private static void SaveAssetToFile(string filename, byte[] data) | ||
1184 | { | ||
1185 | string assetPath = "UserAssets"; | ||
1186 | if (!Directory.Exists(assetPath)) | ||
1187 | { | ||
1188 | Directory.CreateDirectory(assetPath); | ||
1189 | } | ||
1190 | FileStream fs = File.Create(Path.Combine(assetPath, filename)); | ||
1191 | BinaryWriter bw = new BinaryWriter(fs); | ||
1192 | bw.Write(data); | ||
1193 | bw.Close(); | ||
1194 | fs.Close(); | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | /// <summary> | ||
1199 | /// This class is a callback invoked when a client sends asset data to | ||
1200 | /// a task inventory script update url | ||
1201 | /// </summary> | ||
1202 | public class TaskInventoryScriptUpdater | ||
1203 | { | ||
1204 | private static readonly ILog m_log = | ||
1205 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
1206 | |||
1207 | public event UpdateTaskScript OnUpLoad; | ||
1208 | |||
1209 | private UpdateTaskScript handlerUpdateTaskScript = null; | ||
1210 | |||
1211 | private string uploaderPath = String.Empty; | ||
1212 | private UUID inventoryItemID; | ||
1213 | private UUID primID; | ||
1214 | private bool isScriptRunning; | ||
1215 | private IHttpServer httpListener; | ||
1216 | private bool m_dumpAssetToFile; | ||
1217 | |||
1218 | public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, int isScriptRunning, | ||
1219 | string path, IHttpServer httpServer, bool dumpAssetToFile) | ||
1220 | { | ||
1221 | m_dumpAssetToFile = dumpAssetToFile; | ||
1222 | |||
1223 | this.inventoryItemID = inventoryItemID; | ||
1224 | this.primID = primID; | ||
1225 | |||
1226 | // This comes in over the packet as an integer, but actually appears to be treated as a bool | ||
1227 | this.isScriptRunning = (0 == isScriptRunning ? false : true); | ||
1228 | |||
1229 | uploaderPath = path; | ||
1230 | httpListener = httpServer; | ||
1231 | } | ||
1232 | |||
1233 | /// <summary> | ||
1234 | /// | ||
1235 | /// </summary> | ||
1236 | /// <param name="data"></param> | ||
1237 | /// <param name="path"></param> | ||
1238 | /// <param name="param"></param> | ||
1239 | /// <returns></returns> | ||
1240 | public string uploaderCaps(byte[] data, string path, string param) | ||
1241 | { | ||
1242 | try | ||
1243 | { | ||
1244 | // m_log.InfoFormat("[CAPS]: " + | ||
1245 | // "TaskInventoryScriptUpdater received data: {0}, path: {1}, param: {2}", | ||
1246 | // data, path, param)); | ||
1247 | |||
1248 | string res = String.Empty; | ||
1249 | LLSDTaskScriptUploadComplete uploadComplete = new LLSDTaskScriptUploadComplete(); | ||
1250 | |||
1251 | ArrayList errors = new ArrayList(); | ||
1252 | handlerUpdateTaskScript = OnUpLoad; | ||
1253 | if (handlerUpdateTaskScript != null) | ||
1254 | { | ||
1255 | handlerUpdateTaskScript(inventoryItemID, primID, isScriptRunning, data, ref errors); | ||
1256 | } | ||
1257 | |||
1258 | uploadComplete.new_asset = inventoryItemID; | ||
1259 | uploadComplete.compiled = errors.Count > 0 ? false : true; | ||
1260 | uploadComplete.state = "complete"; | ||
1261 | uploadComplete.errors = new OpenSim.Framework.Capabilities.OSDArray(); | ||
1262 | uploadComplete.errors.Array = errors; | ||
1263 | |||
1264 | res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); | ||
1265 | |||
1266 | httpListener.RemoveStreamHandler("POST", uploaderPath); | ||
1267 | |||
1268 | if (m_dumpAssetToFile) | ||
1269 | { | ||
1270 | SaveAssetToFile("updatedtaskscript" + Util.RandomClass.Next(1, 1000) + ".dat", data); | ||
1271 | } | ||
1272 | |||
1273 | // m_log.InfoFormat("[CAPS]: TaskInventoryScriptUpdater.uploaderCaps res: {0}", res); | ||
1274 | |||
1275 | return res; | ||
1276 | } | ||
1277 | catch (Exception e) | ||
1278 | { | ||
1279 | m_log.Error("[CAPS]: " + e.ToString()); | ||
1280 | } | ||
1281 | |||
1282 | // XXX Maybe this should be some meaningful error packet | ||
1283 | return null; | ||
1284 | } | ||
1285 | |||
1286 | ///Left this in and commented in case there are unforseen issues | ||
1287 | //private void SaveAssetToFile(string filename, byte[] data) | ||
1288 | //{ | ||
1289 | // FileStream fs = File.Create(filename); | ||
1290 | // BinaryWriter bw = new BinaryWriter(fs); | ||
1291 | // bw.Write(data); | ||
1292 | // bw.Close(); | ||
1293 | // fs.Close(); | ||
1294 | //} | ||
1295 | private static void SaveAssetToFile(string filename, byte[] data) | ||
1296 | { | ||
1297 | string assetPath = "UserAssets"; | ||
1298 | if (!Directory.Exists(assetPath)) | ||
1299 | { | ||
1300 | Directory.CreateDirectory(assetPath); | ||
1301 | } | ||
1302 | FileStream fs = File.Create(Path.Combine(assetPath, filename)); | ||
1303 | BinaryWriter bw = new BinaryWriter(fs); | ||
1304 | bw.Write(data); | ||
1305 | bw.Close(); | ||
1306 | fs.Close(); | ||
1307 | } | ||
1308 | } | ||
1309 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs new file mode 100644 index 0000000..c241075 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | |||
32 | using log4net; | ||
33 | using Nini.Config; | ||
34 | using OpenMetaverse; | ||
35 | using Mono.Addins; | ||
36 | |||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Framework; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
42 | |||
43 | [assembly: Addin("LindenCaps", OpenSim.VersionInfo.VersionNumber)] | ||
44 | [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] | ||
45 | namespace OpenSim.Region.ClientStack.Linden | ||
46 | { | ||
47 | |||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BunchOfCapsModule")] | ||
49 | public class BunchOfCapsModule : INonSharedRegionModule | ||
50 | { | ||
51 | // private static readonly ILog m_log = | ||
52 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
53 | |||
54 | private Scene m_Scene; | ||
55 | |||
56 | #region INonSharedRegionModule | ||
57 | |||
58 | public string Name { get { return "BunchOfCapsModule"; } } | ||
59 | |||
60 | public Type ReplaceableInterface { get { return null; } } | ||
61 | |||
62 | public void Initialise(IConfigSource source) | ||
63 | { | ||
64 | } | ||
65 | |||
66 | public void Close() { } | ||
67 | |||
68 | public void AddRegion(Scene scene) | ||
69 | { | ||
70 | m_Scene = scene; | ||
71 | m_Scene.EventManager.OnRegisterCaps += OnRegisterCaps; | ||
72 | } | ||
73 | |||
74 | public void RemoveRegion(Scene scene) | ||
75 | { | ||
76 | } | ||
77 | |||
78 | public void RegionLoaded(Scene scene) | ||
79 | { | ||
80 | } | ||
81 | |||
82 | public void PostInitialise() { } | ||
83 | #endregion | ||
84 | |||
85 | private void OnRegisterCaps(UUID agentID, Caps caps) | ||
86 | { | ||
87 | new BunchOfCaps(m_Scene, caps); | ||
88 | } | ||
89 | |||
90 | } | ||
91 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs new file mode 100644 index 0000000..9b9f6a7 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | |||
@@ -0,0 +1,830 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using System.Threading; | ||
34 | using log4net; | ||
35 | using Nini.Config; | ||
36 | using Mono.Addins; | ||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.Messages.Linden; | ||
39 | using OpenMetaverse.Packets; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenSim.Framework; | ||
42 | using OpenSim.Framework.Console; | ||
43 | using OpenSim.Framework.Servers; | ||
44 | using OpenSim.Framework.Servers.HttpServer; | ||
45 | using OpenSim.Region.Framework.Interfaces; | ||
46 | using OpenSim.Region.Framework.Scenes; | ||
47 | using BlockingLLSDQueue = OpenSim.Framework.BlockingQueue<OpenMetaverse.StructuredData.OSD>; | ||
48 | using Caps=OpenSim.Framework.Capabilities.Caps; | ||
49 | |||
50 | namespace OpenSim.Region.ClientStack.Linden | ||
51 | { | ||
52 | public struct QueueItem | ||
53 | { | ||
54 | public int id; | ||
55 | public OSDMap body; | ||
56 | } | ||
57 | |||
58 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EventQueueGetModule")] | ||
59 | public class EventQueueGetModule : IEventQueue, INonSharedRegionModule | ||
60 | { | ||
61 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
62 | private static string LogHeader = "[EVENT QUEUE GET MODULE]"; | ||
63 | |||
64 | /// <value> | ||
65 | /// Debug level. | ||
66 | /// </value> | ||
67 | public int DebugLevel { get; set; } | ||
68 | |||
69 | // Viewer post requests timeout in 60 secs | ||
70 | // https://bitbucket.org/lindenlab/viewer-release/src/421c20423df93d650cc305dc115922bb30040999/indra/llmessage/llhttpclient.cpp?at=default#cl-44 | ||
71 | // | ||
72 | private const int VIEWER_TIMEOUT = 60 * 1000; | ||
73 | // Just to be safe, we work on a 10 sec shorter cycle | ||
74 | private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000); | ||
75 | |||
76 | protected Scene m_scene; | ||
77 | |||
78 | private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); | ||
79 | |||
80 | private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); | ||
81 | private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>(); | ||
82 | private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); | ||
83 | |||
84 | #region INonSharedRegionModule methods | ||
85 | public virtual void Initialise(IConfigSource config) | ||
86 | { | ||
87 | } | ||
88 | |||
89 | public void AddRegion(Scene scene) | ||
90 | { | ||
91 | m_scene = scene; | ||
92 | scene.RegisterModuleInterface<IEventQueue>(this); | ||
93 | |||
94 | scene.EventManager.OnClientClosed += ClientClosed; | ||
95 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | ||
96 | |||
97 | MainConsole.Instance.Commands.AddCommand( | ||
98 | "Debug", | ||
99 | false, | ||
100 | "debug eq", | ||
101 | "debug eq [0|1|2]", | ||
102 | "Turn on event queue debugging\n" | ||
103 | + " <= 0 - turns off all event queue logging\n" | ||
104 | + " >= 1 - turns on event queue setup and outgoing event logging\n" | ||
105 | + " >= 2 - turns on poll notification", | ||
106 | HandleDebugEq); | ||
107 | |||
108 | MainConsole.Instance.Commands.AddCommand( | ||
109 | "Debug", | ||
110 | false, | ||
111 | "show eq", | ||
112 | "show eq", | ||
113 | "Show contents of event queues for logged in avatars. Used for debugging.", | ||
114 | HandleShowEq); | ||
115 | } | ||
116 | |||
117 | public void RemoveRegion(Scene scene) | ||
118 | { | ||
119 | if (m_scene != scene) | ||
120 | return; | ||
121 | |||
122 | scene.EventManager.OnClientClosed -= ClientClosed; | ||
123 | scene.EventManager.OnRegisterCaps -= OnRegisterCaps; | ||
124 | |||
125 | scene.UnregisterModuleInterface<IEventQueue>(this); | ||
126 | m_scene = null; | ||
127 | } | ||
128 | |||
129 | public void RegionLoaded(Scene scene) | ||
130 | { | ||
131 | } | ||
132 | |||
133 | public virtual void Close() | ||
134 | { | ||
135 | } | ||
136 | |||
137 | public virtual string Name | ||
138 | { | ||
139 | get { return "EventQueueGetModule"; } | ||
140 | } | ||
141 | |||
142 | public Type ReplaceableInterface | ||
143 | { | ||
144 | get { return null; } | ||
145 | } | ||
146 | |||
147 | #endregion | ||
148 | |||
149 | protected void HandleDebugEq(string module, string[] args) | ||
150 | { | ||
151 | int debugLevel; | ||
152 | |||
153 | if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel))) | ||
154 | { | ||
155 | MainConsole.Instance.OutputFormat("Usage: debug eq [0|1|2]"); | ||
156 | } | ||
157 | else | ||
158 | { | ||
159 | DebugLevel = debugLevel; | ||
160 | MainConsole.Instance.OutputFormat( | ||
161 | "Set event queue debug level to {0} in {1}", DebugLevel, m_scene.RegionInfo.RegionName); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | protected void HandleShowEq(string module, string[] args) | ||
166 | { | ||
167 | MainConsole.Instance.OutputFormat("For scene {0}", m_scene.Name); | ||
168 | |||
169 | lock (queues) | ||
170 | { | ||
171 | foreach (KeyValuePair<UUID, Queue<OSD>> kvp in queues) | ||
172 | { | ||
173 | MainConsole.Instance.OutputFormat( | ||
174 | "For agent {0} there are {1} messages queued for send.", | ||
175 | kvp.Key, kvp.Value.Count); | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /// <summary> | ||
181 | /// Always returns a valid queue | ||
182 | /// </summary> | ||
183 | /// <param name="agentId"></param> | ||
184 | /// <returns></returns> | ||
185 | private Queue<OSD> TryGetQueue(UUID agentId) | ||
186 | { | ||
187 | lock (queues) | ||
188 | { | ||
189 | if (!queues.ContainsKey(agentId)) | ||
190 | { | ||
191 | if (DebugLevel > 0) | ||
192 | m_log.DebugFormat( | ||
193 | "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", | ||
194 | agentId, m_scene.RegionInfo.RegionName); | ||
195 | |||
196 | queues[agentId] = new Queue<OSD>(); | ||
197 | } | ||
198 | |||
199 | return queues[agentId]; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | /// <summary> | ||
204 | /// May return a null queue | ||
205 | /// </summary> | ||
206 | /// <param name="agentId"></param> | ||
207 | /// <returns></returns> | ||
208 | private Queue<OSD> GetQueue(UUID agentId) | ||
209 | { | ||
210 | lock (queues) | ||
211 | { | ||
212 | if (queues.ContainsKey(agentId)) | ||
213 | { | ||
214 | return queues[agentId]; | ||
215 | } | ||
216 | else | ||
217 | return null; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | #region IEventQueue Members | ||
222 | |||
223 | public bool Enqueue(OSD ev, UUID avatarID) | ||
224 | { | ||
225 | //m_log.DebugFormat("[EVENTQUEUE]: Enqueuing event for {0} in region {1}", avatarID, m_scene.RegionInfo.RegionName); | ||
226 | try | ||
227 | { | ||
228 | Queue<OSD> queue = GetQueue(avatarID); | ||
229 | if (queue != null) | ||
230 | { | ||
231 | lock (queue) | ||
232 | queue.Enqueue(ev); | ||
233 | } | ||
234 | else if (DebugLevel > 0) | ||
235 | { | ||
236 | ScenePresence sp = m_scene.GetScenePresence(avatarID); | ||
237 | |||
238 | // This assumes that an NPC should never have a queue. | ||
239 | if (sp != null && sp.PresenceType != PresenceType.Npc) | ||
240 | { | ||
241 | OSDMap evMap = (OSDMap)ev; | ||
242 | m_log.WarnFormat( | ||
243 | "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} {1} when placing message {2} in region {3}", | ||
244 | sp.Name, sp.UUID, evMap["message"], m_scene.Name); | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | catch (NullReferenceException e) | ||
249 | { | ||
250 | m_log.Error("[EVENTQUEUE] Caught exception: " + e); | ||
251 | return false; | ||
252 | } | ||
253 | |||
254 | return true; | ||
255 | } | ||
256 | |||
257 | #endregion | ||
258 | |||
259 | private void ClientClosed(UUID agentID, Scene scene) | ||
260 | { | ||
261 | //m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | ||
262 | |||
263 | lock (queues) | ||
264 | queues.Remove(agentID); | ||
265 | |||
266 | List<UUID> removeitems = new List<UUID>(); | ||
267 | lock (m_AvatarQueueUUIDMapping) | ||
268 | m_AvatarQueueUUIDMapping.Remove(agentID); | ||
269 | |||
270 | UUID searchval = UUID.Zero; | ||
271 | |||
272 | removeitems.Clear(); | ||
273 | |||
274 | lock (m_QueueUUIDAvatarMapping) | ||
275 | { | ||
276 | foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys) | ||
277 | { | ||
278 | searchval = m_QueueUUIDAvatarMapping[ky]; | ||
279 | |||
280 | if (searchval == agentID) | ||
281 | { | ||
282 | removeitems.Add(ky); | ||
283 | } | ||
284 | } | ||
285 | |||
286 | foreach (UUID ky in removeitems) | ||
287 | m_QueueUUIDAvatarMapping.Remove(ky); | ||
288 | } | ||
289 | |||
290 | // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | ||
291 | |||
292 | } | ||
293 | |||
294 | /// <summary> | ||
295 | /// Generate an Event Queue Get handler path for the given eqg uuid. | ||
296 | /// </summary> | ||
297 | /// <param name='eqgUuid'></param> | ||
298 | private string GenerateEqgCapPath(UUID eqgUuid) | ||
299 | { | ||
300 | return string.Format("/CAPS/EQG/{0}/", eqgUuid); | ||
301 | } | ||
302 | |||
303 | public void OnRegisterCaps(UUID agentID, Caps caps) | ||
304 | { | ||
305 | // Register an event queue for the client | ||
306 | |||
307 | if (DebugLevel > 0) | ||
308 | m_log.DebugFormat( | ||
309 | "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", | ||
310 | agentID, caps, m_scene.RegionInfo.RegionName); | ||
311 | |||
312 | // Let's instantiate a Queue for this agent right now | ||
313 | TryGetQueue(agentID); | ||
314 | |||
315 | UUID eventQueueGetUUID; | ||
316 | |||
317 | lock (m_AvatarQueueUUIDMapping) | ||
318 | { | ||
319 | // Reuse open queues. The client does! | ||
320 | if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
321 | { | ||
322 | //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); | ||
323 | eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; | ||
324 | } | ||
325 | else | ||
326 | { | ||
327 | eventQueueGetUUID = UUID.Random(); | ||
328 | //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); | ||
329 | } | ||
330 | } | ||
331 | |||
332 | lock (m_QueueUUIDAvatarMapping) | ||
333 | { | ||
334 | if (!m_QueueUUIDAvatarMapping.ContainsKey(eventQueueGetUUID)) | ||
335 | m_QueueUUIDAvatarMapping.Add(eventQueueGetUUID, agentID); | ||
336 | } | ||
337 | |||
338 | lock (m_AvatarQueueUUIDMapping) | ||
339 | { | ||
340 | if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
341 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); | ||
342 | } | ||
343 | |||
344 | caps.RegisterPollHandler( | ||
345 | "EventQueueGet", | ||
346 | new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS)); | ||
347 | |||
348 | Random rnd = new Random(Environment.TickCount); | ||
349 | lock (m_ids) | ||
350 | { | ||
351 | if (!m_ids.ContainsKey(agentID)) | ||
352 | m_ids.Add(agentID, rnd.Next(30000000)); | ||
353 | } | ||
354 | } | ||
355 | |||
356 | public bool HasEvents(UUID requestID, UUID agentID) | ||
357 | { | ||
358 | // Don't use this, because of race conditions at agent closing time | ||
359 | //Queue<OSD> queue = TryGetQueue(agentID); | ||
360 | |||
361 | Queue<OSD> queue = GetQueue(agentID); | ||
362 | if (queue != null) | ||
363 | lock (queue) | ||
364 | { | ||
365 | //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count); | ||
366 | return queue.Count > 0; | ||
367 | } | ||
368 | |||
369 | return false; | ||
370 | } | ||
371 | |||
372 | /// <summary> | ||
373 | /// Logs a debug line for an outbound event queue message if appropriate. | ||
374 | /// </summary> | ||
375 | /// <param name='element'>Element containing message</param> | ||
376 | private void LogOutboundDebugMessage(OSD element, UUID agentId) | ||
377 | { | ||
378 | if (element is OSDMap) | ||
379 | { | ||
380 | OSDMap ev = (OSDMap)element; | ||
381 | m_log.DebugFormat( | ||
382 | "Eq OUT {0,-30} to {1,-20} {2,-20}", | ||
383 | ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | public Hashtable GetEvents(UUID requestID, UUID pAgentId) | ||
388 | { | ||
389 | if (DebugLevel >= 2) | ||
390 | m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.Name); | ||
391 | |||
392 | Queue<OSD> queue = GetQueue(pAgentId); | ||
393 | if (queue == null) | ||
394 | { | ||
395 | return NoEvents(requestID, pAgentId); | ||
396 | } | ||
397 | |||
398 | OSD element; | ||
399 | lock (queue) | ||
400 | { | ||
401 | if (queue.Count == 0) | ||
402 | return NoEvents(requestID, pAgentId); | ||
403 | element = queue.Dequeue(); // 15s timeout | ||
404 | } | ||
405 | |||
406 | int thisID = 0; | ||
407 | lock (m_ids) | ||
408 | thisID = m_ids[pAgentId]; | ||
409 | |||
410 | OSDArray array = new OSDArray(); | ||
411 | if (element == null) // didn't have an event in 15s | ||
412 | { | ||
413 | // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! | ||
414 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
415 | //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName); | ||
416 | } | ||
417 | else | ||
418 | { | ||
419 | if (DebugLevel > 0) | ||
420 | LogOutboundDebugMessage(element, pAgentId); | ||
421 | |||
422 | array.Add(element); | ||
423 | |||
424 | lock (queue) | ||
425 | { | ||
426 | while (queue.Count > 0) | ||
427 | { | ||
428 | element = queue.Dequeue(); | ||
429 | |||
430 | if (DebugLevel > 0) | ||
431 | LogOutboundDebugMessage(element, pAgentId); | ||
432 | |||
433 | array.Add(element); | ||
434 | thisID++; | ||
435 | } | ||
436 | } | ||
437 | } | ||
438 | |||
439 | OSDMap events = new OSDMap(); | ||
440 | events.Add("events", array); | ||
441 | |||
442 | events.Add("id", new OSDInteger(thisID)); | ||
443 | lock (m_ids) | ||
444 | { | ||
445 | m_ids[pAgentId] = thisID + 1; | ||
446 | } | ||
447 | Hashtable responsedata = new Hashtable(); | ||
448 | responsedata["int_response_code"] = 200; | ||
449 | responsedata["content_type"] = "application/xml"; | ||
450 | responsedata["keepalive"] = false; | ||
451 | responsedata["reusecontext"] = false; | ||
452 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events); | ||
453 | //m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", pAgentId, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]); | ||
454 | return responsedata; | ||
455 | } | ||
456 | |||
457 | public Hashtable NoEvents(UUID requestID, UUID agentID) | ||
458 | { | ||
459 | Hashtable responsedata = new Hashtable(); | ||
460 | responsedata["int_response_code"] = 502; | ||
461 | responsedata["content_type"] = "text/plain"; | ||
462 | responsedata["keepalive"] = false; | ||
463 | responsedata["reusecontext"] = false; | ||
464 | responsedata["str_response_string"] = "Upstream error: "; | ||
465 | responsedata["error_status_text"] = "Upstream error:"; | ||
466 | responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
467 | return responsedata; | ||
468 | } | ||
469 | |||
470 | // public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps) | ||
471 | // { | ||
472 | // // TODO: this has to be redone to not busy-wait (and block the thread), | ||
473 | // // TODO: as soon as we have a non-blocking way to handle HTTP-requests. | ||
474 | // | ||
475 | //// if (m_log.IsDebugEnabled) | ||
476 | //// { | ||
477 | //// String debug = "[EVENTQUEUE]: Got request for agent {0} in region {1} from thread {2}: [ "; | ||
478 | //// foreach (object key in request.Keys) | ||
479 | //// { | ||
480 | //// debug += key.ToString() + "=" + request[key].ToString() + " "; | ||
481 | //// } | ||
482 | //// m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name); | ||
483 | //// } | ||
484 | // | ||
485 | // Queue<OSD> queue = TryGetQueue(agentID); | ||
486 | // OSD element; | ||
487 | // | ||
488 | // lock (queue) | ||
489 | // element = queue.Dequeue(); // 15s timeout | ||
490 | // | ||
491 | // Hashtable responsedata = new Hashtable(); | ||
492 | // | ||
493 | // int thisID = 0; | ||
494 | // lock (m_ids) | ||
495 | // thisID = m_ids[agentID]; | ||
496 | // | ||
497 | // if (element == null) | ||
498 | // { | ||
499 | // //m_log.ErrorFormat("[EVENTQUEUE]: Nothing to process in " + m_scene.RegionInfo.RegionName); | ||
500 | // if (thisID == -1) // close-request | ||
501 | // { | ||
502 | // m_log.ErrorFormat("[EVENTQUEUE]: 404 in " + m_scene.RegionInfo.RegionName); | ||
503 | // responsedata["int_response_code"] = 404; //501; //410; //404; | ||
504 | // responsedata["content_type"] = "text/plain"; | ||
505 | // responsedata["keepalive"] = false; | ||
506 | // responsedata["str_response_string"] = "Closed EQG"; | ||
507 | // return responsedata; | ||
508 | // } | ||
509 | // responsedata["int_response_code"] = 502; | ||
510 | // responsedata["content_type"] = "text/plain"; | ||
511 | // responsedata["keepalive"] = false; | ||
512 | // responsedata["str_response_string"] = "Upstream error: "; | ||
513 | // responsedata["error_status_text"] = "Upstream error:"; | ||
514 | // responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
515 | // return responsedata; | ||
516 | // } | ||
517 | // | ||
518 | // OSDArray array = new OSDArray(); | ||
519 | // if (element == null) // didn't have an event in 15s | ||
520 | // { | ||
521 | // // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! | ||
522 | // array.Add(EventQueueHelper.KeepAliveEvent()); | ||
523 | // //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | ||
524 | // } | ||
525 | // else | ||
526 | // { | ||
527 | // array.Add(element); | ||
528 | // | ||
529 | // if (element is OSDMap) | ||
530 | // { | ||
531 | // OSDMap ev = (OSDMap)element; | ||
532 | // m_log.DebugFormat( | ||
533 | // "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}", | ||
534 | // ev["message"], m_scene.GetScenePresence(agentID).Name); | ||
535 | // } | ||
536 | // | ||
537 | // lock (queue) | ||
538 | // { | ||
539 | // while (queue.Count > 0) | ||
540 | // { | ||
541 | // element = queue.Dequeue(); | ||
542 | // | ||
543 | // if (element is OSDMap) | ||
544 | // { | ||
545 | // OSDMap ev = (OSDMap)element; | ||
546 | // m_log.DebugFormat( | ||
547 | // "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}", | ||
548 | // ev["message"], m_scene.GetScenePresence(agentID).Name); | ||
549 | // } | ||
550 | // | ||
551 | // array.Add(element); | ||
552 | // thisID++; | ||
553 | // } | ||
554 | // } | ||
555 | // } | ||
556 | // | ||
557 | // OSDMap events = new OSDMap(); | ||
558 | // events.Add("events", array); | ||
559 | // | ||
560 | // events.Add("id", new OSDInteger(thisID)); | ||
561 | // lock (m_ids) | ||
562 | // { | ||
563 | // m_ids[agentID] = thisID + 1; | ||
564 | // } | ||
565 | // | ||
566 | // responsedata["int_response_code"] = 200; | ||
567 | // responsedata["content_type"] = "application/xml"; | ||
568 | // responsedata["keepalive"] = false; | ||
569 | // responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events); | ||
570 | // | ||
571 | // m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]); | ||
572 | // | ||
573 | // return responsedata; | ||
574 | // } | ||
575 | |||
576 | // public Hashtable EventQueuePath2(Hashtable request) | ||
577 | // { | ||
578 | // string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/",""); | ||
579 | // // pull off the last "/" in the path. | ||
580 | // Hashtable responsedata = new Hashtable(); | ||
581 | // capuuid = capuuid.Substring(0, capuuid.Length - 1); | ||
582 | // capuuid = capuuid.Replace("/CAPS/EQG/", ""); | ||
583 | // UUID AvatarID = UUID.Zero; | ||
584 | // UUID capUUID = UUID.Zero; | ||
585 | // | ||
586 | // // parse the path and search for the avatar with it registered | ||
587 | // if (UUID.TryParse(capuuid, out capUUID)) | ||
588 | // { | ||
589 | // lock (m_QueueUUIDAvatarMapping) | ||
590 | // { | ||
591 | // if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) | ||
592 | // { | ||
593 | // AvatarID = m_QueueUUIDAvatarMapping[capUUID]; | ||
594 | // } | ||
595 | // } | ||
596 | // | ||
597 | // if (AvatarID != UUID.Zero) | ||
598 | // { | ||
599 | // return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID)); | ||
600 | // } | ||
601 | // else | ||
602 | // { | ||
603 | // responsedata["int_response_code"] = 404; | ||
604 | // responsedata["content_type"] = "text/plain"; | ||
605 | // responsedata["keepalive"] = false; | ||
606 | // responsedata["str_response_string"] = "Not Found"; | ||
607 | // responsedata["error_status_text"] = "Not Found"; | ||
608 | // responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
609 | // return responsedata; | ||
610 | // // return 404 | ||
611 | // } | ||
612 | // } | ||
613 | // else | ||
614 | // { | ||
615 | // responsedata["int_response_code"] = 404; | ||
616 | // responsedata["content_type"] = "text/plain"; | ||
617 | // responsedata["keepalive"] = false; | ||
618 | // responsedata["str_response_string"] = "Not Found"; | ||
619 | // responsedata["error_status_text"] = "Not Found"; | ||
620 | // responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
621 | // return responsedata; | ||
622 | // // return 404 | ||
623 | // } | ||
624 | // } | ||
625 | |||
626 | public OSD EventQueueFallBack(string path, OSD request, string endpoint) | ||
627 | { | ||
628 | // This is a fallback element to keep the client from loosing EventQueueGet | ||
629 | // Why does CAPS fail sometimes!? | ||
630 | m_log.Warn("[EVENTQUEUE]: In the Fallback handler! We lost the Queue in the rest handler!"); | ||
631 | string capuuid = path.Replace("/CAPS/EQG/",""); | ||
632 | capuuid = capuuid.Substring(0, capuuid.Length - 1); | ||
633 | |||
634 | // UUID AvatarID = UUID.Zero; | ||
635 | UUID capUUID = UUID.Zero; | ||
636 | if (UUID.TryParse(capuuid, out capUUID)) | ||
637 | { | ||
638 | /* Don't remove this yet code cleaners! | ||
639 | * Still testing this! | ||
640 | * | ||
641 | lock (m_QueueUUIDAvatarMapping) | ||
642 | { | ||
643 | if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) | ||
644 | { | ||
645 | AvatarID = m_QueueUUIDAvatarMapping[capUUID]; | ||
646 | } | ||
647 | } | ||
648 | |||
649 | |||
650 | if (AvatarID != UUID.Zero) | ||
651 | { | ||
652 | // Repair the CAP! | ||
653 | //OpenSim.Framework.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID); | ||
654 | //string capsBase = "/CAPS/EQG/"; | ||
655 | //caps.RegisterHandler("EventQueueGet", | ||
656 | //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/", | ||
657 | //delegate(Hashtable m_dhttpMethod) | ||
658 | //{ | ||
659 | // return ProcessQueue(m_dhttpMethod, AvatarID, caps); | ||
660 | //})); | ||
661 | // start new ID sequence. | ||
662 | Random rnd = new Random(System.Environment.TickCount); | ||
663 | lock (m_ids) | ||
664 | { | ||
665 | if (!m_ids.ContainsKey(AvatarID)) | ||
666 | m_ids.Add(AvatarID, rnd.Next(30000000)); | ||
667 | } | ||
668 | |||
669 | |||
670 | int thisID = 0; | ||
671 | lock (m_ids) | ||
672 | thisID = m_ids[AvatarID]; | ||
673 | |||
674 | BlockingLLSDQueue queue = GetQueue(AvatarID); | ||
675 | OSDArray array = new OSDArray(); | ||
676 | LLSD element = queue.Dequeue(15000); // 15s timeout | ||
677 | if (element == null) | ||
678 | { | ||
679 | |||
680 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
681 | } | ||
682 | else | ||
683 | { | ||
684 | array.Add(element); | ||
685 | while (queue.Count() > 0) | ||
686 | { | ||
687 | array.Add(queue.Dequeue(1)); | ||
688 | thisID++; | ||
689 | } | ||
690 | } | ||
691 | OSDMap events = new OSDMap(); | ||
692 | events.Add("events", array); | ||
693 | |||
694 | events.Add("id", new LLSDInteger(thisID)); | ||
695 | |||
696 | lock (m_ids) | ||
697 | { | ||
698 | m_ids[AvatarID] = thisID + 1; | ||
699 | } | ||
700 | |||
701 | return events; | ||
702 | } | ||
703 | else | ||
704 | { | ||
705 | return new LLSD(); | ||
706 | } | ||
707 | * | ||
708 | */ | ||
709 | } | ||
710 | else | ||
711 | { | ||
712 | //return new LLSD(); | ||
713 | } | ||
714 | |||
715 | return new OSDString("shutdown404!"); | ||
716 | } | ||
717 | |||
718 | public void DisableSimulator(ulong handle, UUID avatarID) | ||
719 | { | ||
720 | OSD item = EventQueueHelper.DisableSimulator(handle); | ||
721 | Enqueue(item, avatarID); | ||
722 | } | ||
723 | |||
724 | public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY) | ||
725 | { | ||
726 | if (DebugLevel > 0) | ||
727 | m_log.DebugFormat("{0} EnableSimulator. handle={1}, endPoint={2}, avatarID={3}", | ||
728 | LogHeader, handle, endPoint, avatarID, regionSizeX, regionSizeY); | ||
729 | |||
730 | OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY); | ||
731 | Enqueue(item, avatarID); | ||
732 | } | ||
733 | |||
734 | public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath, | ||
735 | ulong regionHandle, int regionSizeX, int regionSizeY) | ||
736 | { | ||
737 | if (DebugLevel > 0) | ||
738 | m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, endPoint={2}, avatarID={3}", | ||
739 | LogHeader, regionHandle, endPoint, avatarID, regionSizeX, regionSizeY); | ||
740 | |||
741 | OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY); | ||
742 | Enqueue(item, avatarID); | ||
743 | } | ||
744 | |||
745 | public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, | ||
746 | IPEndPoint regionExternalEndPoint, | ||
747 | uint locationID, uint flags, string capsURL, | ||
748 | UUID avatarID, int regionSizeX, int regionSizeY) | ||
749 | { | ||
750 | if (DebugLevel > 0) | ||
751 | m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, endPoint={2}, avatarID={3}", | ||
752 | LogHeader, regionHandle, regionExternalEndPoint, avatarID, regionSizeX, regionSizeY); | ||
753 | |||
754 | OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, | ||
755 | locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY); | ||
756 | Enqueue(item, avatarID); | ||
757 | } | ||
758 | |||
759 | public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, | ||
760 | IPEndPoint newRegionExternalEndPoint, | ||
761 | string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY) | ||
762 | { | ||
763 | if (DebugLevel > 0) | ||
764 | m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>", | ||
765 | LogHeader, handle, avatarID, regionSizeX, regionSizeY); | ||
766 | |||
767 | OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, | ||
768 | capsURL, avatarID, sessionID, regionSizeX, regionSizeY); | ||
769 | Enqueue(item, avatarID); | ||
770 | } | ||
771 | |||
772 | public void ChatterboxInvitation(UUID sessionID, string sessionName, | ||
773 | UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog, | ||
774 | uint timeStamp, bool offline, int parentEstateID, Vector3 position, | ||
775 | uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket) | ||
776 | { | ||
777 | OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog, | ||
778 | timeStamp, offline, parentEstateID, position, ttl, transactionID, | ||
779 | fromGroup, binaryBucket); | ||
780 | Enqueue(item, toAgent); | ||
781 | //m_log.InfoFormat("########### eq ChatterboxInvitation #############\n{0}", item); | ||
782 | |||
783 | } | ||
784 | |||
785 | public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat, | ||
786 | bool isModerator, bool textMute) | ||
787 | { | ||
788 | OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, | ||
789 | isModerator, textMute); | ||
790 | Enqueue(item, fromAgent); | ||
791 | //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); | ||
792 | } | ||
793 | |||
794 | public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID) | ||
795 | { | ||
796 | OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage); | ||
797 | Enqueue(item, avatarID); | ||
798 | } | ||
799 | |||
800 | public void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID) | ||
801 | { | ||
802 | OSD item = EventQueueHelper.GroupMembership(groupUpdate); | ||
803 | Enqueue(item, avatarID); | ||
804 | } | ||
805 | |||
806 | public void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID) | ||
807 | { | ||
808 | OSD item = EventQueueHelper.PlacesQuery(groupUpdate); | ||
809 | Enqueue(item, avatarID); | ||
810 | } | ||
811 | |||
812 | public OSD ScriptRunningEvent(UUID objectID, UUID itemID, bool running, bool mono) | ||
813 | { | ||
814 | return EventQueueHelper.ScriptRunningReplyEvent(objectID, itemID, running, mono); | ||
815 | } | ||
816 | |||
817 | public OSD BuildEvent(string eventName, OSD eventBody) | ||
818 | { | ||
819 | return EventQueueHelper.BuildEvent(eventName, eventBody); | ||
820 | } | ||
821 | |||
822 | public void partPhysicsProperties(uint localID, byte physhapetype, | ||
823 | float density, float friction, float bounce, float gravmod,UUID avatarID) | ||
824 | { | ||
825 | OSD item = EventQueueHelper.partPhysicsProperties(localID, physhapetype, | ||
826 | density, friction, bounce, gravmod); | ||
827 | Enqueue(item, avatarID); | ||
828 | } | ||
829 | } | ||
830 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs new file mode 100644 index 0000000..384af74 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs | |||
@@ -0,0 +1,433 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Net; | ||
30 | using OpenMetaverse; | ||
31 | using OpenMetaverse.Packets; | ||
32 | using OpenMetaverse.StructuredData; | ||
33 | using OpenMetaverse.Messages.Linden; | ||
34 | |||
35 | namespace OpenSim.Region.ClientStack.Linden | ||
36 | { | ||
37 | public class EventQueueHelper | ||
38 | { | ||
39 | private EventQueueHelper() {} // no construction possible, it's an utility class | ||
40 | |||
41 | private static byte[] ulongToByteArray(ulong uLongValue) | ||
42 | { | ||
43 | // Reverse endianness of RegionHandle | ||
44 | return new byte[] | ||
45 | { | ||
46 | (byte)((uLongValue >> 56) % 256), | ||
47 | (byte)((uLongValue >> 48) % 256), | ||
48 | (byte)((uLongValue >> 40) % 256), | ||
49 | (byte)((uLongValue >> 32) % 256), | ||
50 | (byte)((uLongValue >> 24) % 256), | ||
51 | (byte)((uLongValue >> 16) % 256), | ||
52 | (byte)((uLongValue >> 8) % 256), | ||
53 | (byte)(uLongValue % 256) | ||
54 | }; | ||
55 | } | ||
56 | |||
57 | // private static byte[] uintToByteArray(uint uIntValue) | ||
58 | // { | ||
59 | // byte[] result = new byte[4]; | ||
60 | // Utils.UIntToBytesBig(uIntValue, result, 0); | ||
61 | // return result; | ||
62 | // } | ||
63 | |||
64 | public static OSD BuildEvent(string eventName, OSD eventBody) | ||
65 | { | ||
66 | OSDMap llsdEvent = new OSDMap(2); | ||
67 | llsdEvent.Add("message", new OSDString(eventName)); | ||
68 | llsdEvent.Add("body", eventBody); | ||
69 | |||
70 | return llsdEvent; | ||
71 | } | ||
72 | |||
73 | public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint, int regionSizeX, int regionSizeY) | ||
74 | { | ||
75 | OSDMap llsdSimInfo = new OSDMap(5); | ||
76 | |||
77 | llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle))); | ||
78 | llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes())); | ||
79 | llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port)); | ||
80 | llsdSimInfo.Add("RegionSizeX", OSD.FromUInteger((uint) regionSizeX)); | ||
81 | llsdSimInfo.Add("RegionSizeY", OSD.FromUInteger((uint) regionSizeY)); | ||
82 | |||
83 | OSDArray arr = new OSDArray(1); | ||
84 | arr.Add(llsdSimInfo); | ||
85 | |||
86 | OSDMap llsdBody = new OSDMap(1); | ||
87 | llsdBody.Add("SimulatorInfo", arr); | ||
88 | |||
89 | return BuildEvent("EnableSimulator", llsdBody); | ||
90 | } | ||
91 | |||
92 | public static OSD DisableSimulator(ulong handle) | ||
93 | { | ||
94 | //OSDMap llsdSimInfo = new OSDMap(1); | ||
95 | |||
96 | //llsdSimInfo.Add("Handle", new OSDBinary(regionHandleToByteArray(handle))); | ||
97 | |||
98 | //OSDArray arr = new OSDArray(1); | ||
99 | //arr.Add(llsdSimInfo); | ||
100 | |||
101 | OSDMap llsdBody = new OSDMap(0); | ||
102 | //llsdBody.Add("SimulatorInfo", arr); | ||
103 | |||
104 | return BuildEvent("DisableSimulator", llsdBody); | ||
105 | } | ||
106 | |||
107 | public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, | ||
108 | IPEndPoint newRegionExternalEndPoint, | ||
109 | string capsURL, UUID agentID, UUID sessionID, | ||
110 | int regionSizeX, int regionSizeY) | ||
111 | { | ||
112 | OSDArray lookAtArr = new OSDArray(3); | ||
113 | lookAtArr.Add(OSD.FromReal(lookAt.X)); | ||
114 | lookAtArr.Add(OSD.FromReal(lookAt.Y)); | ||
115 | lookAtArr.Add(OSD.FromReal(lookAt.Z)); | ||
116 | |||
117 | OSDArray positionArr = new OSDArray(3); | ||
118 | positionArr.Add(OSD.FromReal(pos.X)); | ||
119 | positionArr.Add(OSD.FromReal(pos.Y)); | ||
120 | positionArr.Add(OSD.FromReal(pos.Z)); | ||
121 | |||
122 | OSDMap infoMap = new OSDMap(2); | ||
123 | infoMap.Add("LookAt", lookAtArr); | ||
124 | infoMap.Add("Position", positionArr); | ||
125 | |||
126 | OSDArray infoArr = new OSDArray(1); | ||
127 | infoArr.Add(infoMap); | ||
128 | |||
129 | OSDMap agentDataMap = new OSDMap(2); | ||
130 | agentDataMap.Add("AgentID", OSD.FromUUID(agentID)); | ||
131 | agentDataMap.Add("SessionID", OSD.FromUUID(sessionID)); | ||
132 | |||
133 | OSDArray agentDataArr = new OSDArray(1); | ||
134 | agentDataArr.Add(agentDataMap); | ||
135 | |||
136 | OSDMap regionDataMap = new OSDMap(6); | ||
137 | regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle))); | ||
138 | regionDataMap.Add("SeedCapability", OSD.FromString(capsURL)); | ||
139 | regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes())); | ||
140 | regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port)); | ||
141 | regionDataMap.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX)); | ||
142 | regionDataMap.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY)); | ||
143 | |||
144 | OSDArray regionDataArr = new OSDArray(1); | ||
145 | regionDataArr.Add(regionDataMap); | ||
146 | |||
147 | OSDMap llsdBody = new OSDMap(3); | ||
148 | llsdBody.Add("Info", infoArr); | ||
149 | llsdBody.Add("AgentData", agentDataArr); | ||
150 | llsdBody.Add("RegionData", regionDataArr); | ||
151 | |||
152 | return BuildEvent("CrossedRegion", llsdBody); | ||
153 | } | ||
154 | |||
155 | public static OSD TeleportFinishEvent( | ||
156 | ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, | ||
157 | uint locationID, uint flags, string capsURL, UUID agentID, | ||
158 | int regionSizeX, int regionSizeY) | ||
159 | { | ||
160 | OSDMap info = new OSDMap(); | ||
161 | info.Add("AgentID", OSD.FromUUID(agentID)); | ||
162 | info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this? | ||
163 | info.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(regionHandle))); | ||
164 | info.Add("SeedCapability", OSD.FromString(capsURL)); | ||
165 | info.Add("SimAccess", OSD.FromInteger(simAccess)); | ||
166 | info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes())); | ||
167 | info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); | ||
168 | info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation | ||
169 | info.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX)); | ||
170 | info.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY)); | ||
171 | |||
172 | OSDArray infoArr = new OSDArray(); | ||
173 | infoArr.Add(info); | ||
174 | |||
175 | OSDMap body = new OSDMap(); | ||
176 | body.Add("Info", infoArr); | ||
177 | |||
178 | return BuildEvent("TeleportFinish", body); | ||
179 | } | ||
180 | |||
181 | public static OSD ScriptRunningReplyEvent(UUID objectID, UUID itemID, bool running, bool mono) | ||
182 | { | ||
183 | OSDMap script = new OSDMap(); | ||
184 | script.Add("ObjectID", OSD.FromUUID(objectID)); | ||
185 | script.Add("ItemID", OSD.FromUUID(itemID)); | ||
186 | script.Add("Running", OSD.FromBoolean(running)); | ||
187 | script.Add("Mono", OSD.FromBoolean(mono)); | ||
188 | |||
189 | OSDArray scriptArr = new OSDArray(); | ||
190 | scriptArr.Add(script); | ||
191 | |||
192 | OSDMap body = new OSDMap(); | ||
193 | body.Add("Script", scriptArr); | ||
194 | |||
195 | return BuildEvent("ScriptRunningReply", body); | ||
196 | } | ||
197 | |||
198 | public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap, | ||
199 | ulong regionHandle, int regionSizeX, int regionSizeY) | ||
200 | { | ||
201 | OSDMap body = new OSDMap(6) | ||
202 | { | ||
203 | {"agent-id", new OSDUUID(agentID)}, | ||
204 | {"sim-ip-and-port", new OSDString(simIpAndPort)}, | ||
205 | {"seed-capability", new OSDString(seedcap)}, | ||
206 | {"region-handle", OSD.FromULong(regionHandle)}, | ||
207 | {"region-size-x", OSD.FromInteger(regionSizeX)}, | ||
208 | {"region-size-y", OSD.FromInteger(regionSizeY)} | ||
209 | }; | ||
210 | |||
211 | return BuildEvent("EstablishAgentCommunication", body); | ||
212 | } | ||
213 | |||
214 | public static OSD KeepAliveEvent() | ||
215 | { | ||
216 | return BuildEvent("FAKEEVENT", new OSDMap()); | ||
217 | } | ||
218 | |||
219 | public static OSD AgentParams(UUID agentID, bool checkEstate, int godLevel, bool limitedToEstate) | ||
220 | { | ||
221 | OSDMap body = new OSDMap(4); | ||
222 | |||
223 | body.Add("agent_id", new OSDUUID(agentID)); | ||
224 | body.Add("check_estate", new OSDInteger(checkEstate ? 1 : 0)); | ||
225 | body.Add("god_level", new OSDInteger(godLevel)); | ||
226 | body.Add("limited_to_estate", new OSDInteger(limitedToEstate ? 1 : 0)); | ||
227 | |||
228 | return body; | ||
229 | } | ||
230 | |||
231 | public static OSD InstantMessageParams(UUID fromAgent, string message, UUID toAgent, | ||
232 | string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID, | ||
233 | Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket) | ||
234 | { | ||
235 | OSDMap messageParams = new OSDMap(15); | ||
236 | messageParams.Add("type", new OSDInteger((int)dialog)); | ||
237 | |||
238 | OSDArray positionArray = new OSDArray(3); | ||
239 | positionArray.Add(OSD.FromReal(position.X)); | ||
240 | positionArray.Add(OSD.FromReal(position.Y)); | ||
241 | positionArray.Add(OSD.FromReal(position.Z)); | ||
242 | messageParams.Add("position", positionArray); | ||
243 | |||
244 | messageParams.Add("region_id", new OSDUUID(UUID.Zero)); | ||
245 | messageParams.Add("to_id", new OSDUUID(toAgent)); | ||
246 | messageParams.Add("source", new OSDInteger(0)); | ||
247 | |||
248 | OSDMap data = new OSDMap(1); | ||
249 | data.Add("binary_bucket", OSD.FromBinary(binaryBucket)); | ||
250 | messageParams.Add("data", data); | ||
251 | messageParams.Add("message", new OSDString(message)); | ||
252 | messageParams.Add("id", new OSDUUID(transactionID)); | ||
253 | messageParams.Add("from_name", new OSDString(fromName)); | ||
254 | messageParams.Add("timestamp", new OSDInteger((int)timeStamp)); | ||
255 | messageParams.Add("offline", new OSDInteger(offline ? 1 : 0)); | ||
256 | messageParams.Add("parent_estate_id", new OSDInteger(parentEstateID)); | ||
257 | messageParams.Add("ttl", new OSDInteger((int)ttl)); | ||
258 | messageParams.Add("from_id", new OSDUUID(fromAgent)); | ||
259 | messageParams.Add("from_group", new OSDInteger(fromGroup ? 1 : 0)); | ||
260 | |||
261 | return messageParams; | ||
262 | } | ||
263 | |||
264 | public static OSD InstantMessage(UUID fromAgent, string message, UUID toAgent, | ||
265 | string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID, | ||
266 | Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket, | ||
267 | bool checkEstate, int godLevel, bool limitedToEstate) | ||
268 | { | ||
269 | OSDMap im = new OSDMap(2); | ||
270 | im.Add("message_params", InstantMessageParams(fromAgent, message, toAgent, | ||
271 | fromName, dialog, timeStamp, offline, parentEstateID, | ||
272 | position, ttl, transactionID, fromGroup, binaryBucket)); | ||
273 | |||
274 | im.Add("agent_params", AgentParams(fromAgent, checkEstate, godLevel, limitedToEstate)); | ||
275 | |||
276 | return im; | ||
277 | } | ||
278 | |||
279 | |||
280 | public static OSD ChatterboxInvitation(UUID sessionID, string sessionName, | ||
281 | UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog, | ||
282 | uint timeStamp, bool offline, int parentEstateID, Vector3 position, | ||
283 | uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket) | ||
284 | { | ||
285 | OSDMap body = new OSDMap(5); | ||
286 | body.Add("session_id", new OSDUUID(sessionID)); | ||
287 | body.Add("from_name", new OSDString(fromName)); | ||
288 | body.Add("session_name", new OSDString(sessionName)); | ||
289 | body.Add("from_id", new OSDUUID(fromAgent)); | ||
290 | |||
291 | body.Add("instantmessage", InstantMessage(fromAgent, message, toAgent, | ||
292 | fromName, dialog, timeStamp, offline, parentEstateID, position, | ||
293 | ttl, transactionID, fromGroup, binaryBucket, true, 0, true)); | ||
294 | |||
295 | OSDMap chatterboxInvitation = new OSDMap(2); | ||
296 | chatterboxInvitation.Add("message", new OSDString("ChatterBoxInvitation")); | ||
297 | chatterboxInvitation.Add("body", body); | ||
298 | return chatterboxInvitation; | ||
299 | } | ||
300 | |||
301 | public static OSD ChatterBoxSessionAgentListUpdates(UUID sessionID, | ||
302 | UUID agentID, bool canVoiceChat, bool isModerator, bool textMute) | ||
303 | { | ||
304 | OSDMap body = new OSDMap(); | ||
305 | OSDMap agentUpdates = new OSDMap(); | ||
306 | OSDMap infoDetail = new OSDMap(); | ||
307 | OSDMap mutes = new OSDMap(); | ||
308 | |||
309 | mutes.Add("text", OSD.FromBoolean(textMute)); | ||
310 | infoDetail.Add("can_voice_chat", OSD.FromBoolean(canVoiceChat)); | ||
311 | infoDetail.Add("is_moderator", OSD.FromBoolean(isModerator)); | ||
312 | infoDetail.Add("mutes", mutes); | ||
313 | OSDMap info = new OSDMap(); | ||
314 | info.Add("info", infoDetail); | ||
315 | agentUpdates.Add(agentID.ToString(), info); | ||
316 | body.Add("agent_updates", agentUpdates); | ||
317 | body.Add("session_id", OSD.FromUUID(sessionID)); | ||
318 | body.Add("updates", new OSD()); | ||
319 | |||
320 | OSDMap chatterBoxSessionAgentListUpdates = new OSDMap(); | ||
321 | chatterBoxSessionAgentListUpdates.Add("message", OSD.FromString("ChatterBoxSessionAgentListUpdates")); | ||
322 | chatterBoxSessionAgentListUpdates.Add("body", body); | ||
323 | |||
324 | return chatterBoxSessionAgentListUpdates; | ||
325 | } | ||
326 | |||
327 | public static OSD GroupMembership(AgentGroupDataUpdatePacket groupUpdatePacket) | ||
328 | { | ||
329 | OSDMap groupUpdate = new OSDMap(); | ||
330 | groupUpdate.Add("message", OSD.FromString("AgentGroupDataUpdate")); | ||
331 | |||
332 | OSDMap body = new OSDMap(); | ||
333 | OSDArray agentData = new OSDArray(); | ||
334 | OSDMap agentDataMap = new OSDMap(); | ||
335 | agentDataMap.Add("AgentID", OSD.FromUUID(groupUpdatePacket.AgentData.AgentID)); | ||
336 | agentData.Add(agentDataMap); | ||
337 | body.Add("AgentData", agentData); | ||
338 | |||
339 | OSDArray groupData = new OSDArray(); | ||
340 | |||
341 | foreach (AgentGroupDataUpdatePacket.GroupDataBlock groupDataBlock in groupUpdatePacket.GroupData) | ||
342 | { | ||
343 | OSDMap groupDataMap = new OSDMap(); | ||
344 | groupDataMap.Add("ListInProfile", OSD.FromBoolean(false)); | ||
345 | groupDataMap.Add("GroupID", OSD.FromUUID(groupDataBlock.GroupID)); | ||
346 | groupDataMap.Add("GroupInsigniaID", OSD.FromUUID(groupDataBlock.GroupInsigniaID)); | ||
347 | groupDataMap.Add("Contribution", OSD.FromInteger(groupDataBlock.Contribution)); | ||
348 | groupDataMap.Add("GroupPowers", OSD.FromBinary(ulongToByteArray(groupDataBlock.GroupPowers))); | ||
349 | groupDataMap.Add("GroupName", OSD.FromString(Utils.BytesToString(groupDataBlock.GroupName))); | ||
350 | groupDataMap.Add("AcceptNotices", OSD.FromBoolean(groupDataBlock.AcceptNotices)); | ||
351 | |||
352 | groupData.Add(groupDataMap); | ||
353 | |||
354 | } | ||
355 | body.Add("GroupData", groupData); | ||
356 | groupUpdate.Add("body", body); | ||
357 | |||
358 | return groupUpdate; | ||
359 | } | ||
360 | |||
361 | public static OSD PlacesQuery(PlacesReplyPacket PlacesReply) | ||
362 | { | ||
363 | OSDMap placesReply = new OSDMap(); | ||
364 | placesReply.Add("message", OSD.FromString("PlacesReplyMessage")); | ||
365 | |||
366 | OSDMap body = new OSDMap(); | ||
367 | OSDArray agentData = new OSDArray(); | ||
368 | OSDMap agentDataMap = new OSDMap(); | ||
369 | agentDataMap.Add("AgentID", OSD.FromUUID(PlacesReply.AgentData.AgentID)); | ||
370 | agentDataMap.Add("QueryID", OSD.FromUUID(PlacesReply.AgentData.QueryID)); | ||
371 | agentDataMap.Add("TransactionID", OSD.FromUUID(PlacesReply.TransactionData.TransactionID)); | ||
372 | agentData.Add(agentDataMap); | ||
373 | body.Add("AgentData", agentData); | ||
374 | |||
375 | OSDArray QueryData = new OSDArray(); | ||
376 | |||
377 | foreach (PlacesReplyPacket.QueryDataBlock groupDataBlock in PlacesReply.QueryData) | ||
378 | { | ||
379 | OSDMap QueryDataMap = new OSDMap(); | ||
380 | QueryDataMap.Add("ActualArea", OSD.FromInteger(groupDataBlock.ActualArea)); | ||
381 | QueryDataMap.Add("BillableArea", OSD.FromInteger(groupDataBlock.BillableArea)); | ||
382 | QueryDataMap.Add("Description", OSD.FromBinary(groupDataBlock.Desc)); | ||
383 | QueryDataMap.Add("Dwell", OSD.FromInteger((int)groupDataBlock.Dwell)); | ||
384 | QueryDataMap.Add("Flags", OSD.FromString(Convert.ToString(groupDataBlock.Flags))); | ||
385 | QueryDataMap.Add("GlobalX", OSD.FromInteger((int)groupDataBlock.GlobalX)); | ||
386 | QueryDataMap.Add("GlobalY", OSD.FromInteger((int)groupDataBlock.GlobalY)); | ||
387 | QueryDataMap.Add("GlobalZ", OSD.FromInteger((int)groupDataBlock.GlobalZ)); | ||
388 | QueryDataMap.Add("Name", OSD.FromBinary(groupDataBlock.Name)); | ||
389 | QueryDataMap.Add("OwnerID", OSD.FromUUID(groupDataBlock.OwnerID)); | ||
390 | QueryDataMap.Add("SimName", OSD.FromBinary(groupDataBlock.SimName)); | ||
391 | QueryDataMap.Add("SnapShotID", OSD.FromUUID(groupDataBlock.SnapshotID)); | ||
392 | QueryDataMap.Add("ProductSku", OSD.FromInteger(0)); | ||
393 | QueryDataMap.Add("Price", OSD.FromInteger(groupDataBlock.Price)); | ||
394 | |||
395 | QueryData.Add(QueryDataMap); | ||
396 | } | ||
397 | body.Add("QueryData", QueryData); | ||
398 | placesReply.Add("QueryData[]", body); | ||
399 | |||
400 | return placesReply; | ||
401 | } | ||
402 | |||
403 | public static OSD ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage) | ||
404 | { | ||
405 | OSDMap message = new OSDMap(); | ||
406 | message.Add("message", OSD.FromString("ParcelProperties")); | ||
407 | OSD message_body = parcelPropertiesMessage.Serialize(); | ||
408 | message.Add("body", message_body); | ||
409 | return message; | ||
410 | } | ||
411 | |||
412 | public static OSD partPhysicsProperties(uint localID, byte physhapetype, | ||
413 | float density, float friction, float bounce, float gravmod) | ||
414 | { | ||
415 | |||
416 | OSDMap physinfo = new OSDMap(6); | ||
417 | physinfo["LocalID"] = localID; | ||
418 | physinfo["Density"] = density; | ||
419 | physinfo["Friction"] = friction; | ||
420 | physinfo["GravityMultiplier"] = gravmod; | ||
421 | physinfo["Restitution"] = bounce; | ||
422 | physinfo["PhysicsShapeType"] = (int)physhapetype; | ||
423 | |||
424 | OSDArray array = new OSDArray(1); | ||
425 | array.Add(physinfo); | ||
426 | |||
427 | OSDMap llsdBody = new OSDMap(1); | ||
428 | llsdBody.Add("ObjectData", array); | ||
429 | |||
430 | return BuildEvent("ObjectPhysicsProperties", llsdBody); | ||
431 | } | ||
432 | } | ||
433 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs new file mode 100644 index 0000000..16a902d --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Net; | ||
32 | using log4net.Config; | ||
33 | using Nini.Config; | ||
34 | using NUnit.Framework; | ||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.Packets; | ||
37 | using OpenMetaverse.StructuredData; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Framework.Servers; | ||
40 | using OpenSim.Framework.Servers.HttpServer; | ||
41 | using OpenSim.Region.ClientStack.Linden; | ||
42 | using OpenSim.Region.CoreModules.Framework; | ||
43 | using OpenSim.Region.Framework.Scenes; | ||
44 | using OpenSim.Region.OptionalModules.World.NPC; | ||
45 | using OpenSim.Tests.Common; | ||
46 | |||
47 | namespace OpenSim.Region.ClientStack.Linden.Tests | ||
48 | { | ||
49 | [TestFixture] | ||
50 | public class EventQueueTests : OpenSimTestCase | ||
51 | { | ||
52 | private TestScene m_scene; | ||
53 | private EventQueueGetModule m_eqgMod; | ||
54 | private NPCModule m_npcMod; | ||
55 | |||
56 | [SetUp] | ||
57 | public override void SetUp() | ||
58 | { | ||
59 | base.SetUp(); | ||
60 | |||
61 | uint port = 9999; | ||
62 | uint sslPort = 9998; | ||
63 | |||
64 | // This is an unfortunate bit of clean up we have to do because MainServer manages things through static | ||
65 | // variables and the VM is not restarted between tests. | ||
66 | MainServer.RemoveHttpServer(port); | ||
67 | |||
68 | BaseHttpServer server = new BaseHttpServer(port, false, sslPort, ""); | ||
69 | MainServer.AddHttpServer(server); | ||
70 | MainServer.Instance = server; | ||
71 | |||
72 | IConfigSource config = new IniConfigSource(); | ||
73 | config.AddConfig("Startup"); | ||
74 | config.Configs["Startup"].Set("EventQueue", "true"); | ||
75 | |||
76 | CapabilitiesModule capsModule = new CapabilitiesModule(); | ||
77 | m_eqgMod = new EventQueueGetModule(); | ||
78 | |||
79 | // For NPC test support | ||
80 | config.AddConfig("NPC"); | ||
81 | config.Configs["NPC"].Set("Enabled", "true"); | ||
82 | m_npcMod = new NPCModule(); | ||
83 | |||
84 | m_scene = new SceneHelpers().SetupScene(); | ||
85 | SceneHelpers.SetupSceneModules(m_scene, config, capsModule, m_eqgMod, m_npcMod); | ||
86 | } | ||
87 | |||
88 | [Test] | ||
89 | public void TestAddForClient() | ||
90 | { | ||
91 | TestHelpers.InMethod(); | ||
92 | // log4net.Config.XmlConfigurator.Configure(); | ||
93 | |||
94 | SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); | ||
95 | |||
96 | // TODO: Add more assertions for the other aspects of event queues | ||
97 | Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(1)); | ||
98 | } | ||
99 | |||
100 | [Test] | ||
101 | public void TestRemoveForClient() | ||
102 | { | ||
103 | TestHelpers.InMethod(); | ||
104 | // TestHelpers.EnableLogging(); | ||
105 | |||
106 | UUID spId = TestHelpers.ParseTail(0x1); | ||
107 | |||
108 | SceneHelpers.AddScenePresence(m_scene, spId); | ||
109 | m_scene.CloseAgent(spId, false); | ||
110 | |||
111 | // TODO: Add more assertions for the other aspects of event queues | ||
112 | Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0)); | ||
113 | } | ||
114 | |||
115 | [Test] | ||
116 | public void TestEnqueueMessage() | ||
117 | { | ||
118 | TestHelpers.InMethod(); | ||
119 | // log4net.Config.XmlConfigurator.Configure(); | ||
120 | |||
121 | ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); | ||
122 | |||
123 | string messageName = "TestMessage"; | ||
124 | |||
125 | m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), sp.UUID); | ||
126 | |||
127 | Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); | ||
128 | |||
129 | Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK)); | ||
130 | |||
131 | // Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]); | ||
132 | |||
133 | OSDMap rawOsd = (OSDMap)OSDParser.DeserializeLLSDXml((string)eventsResponse["str_response_string"]); | ||
134 | OSDArray eventsOsd = (OSDArray)rawOsd["events"]; | ||
135 | |||
136 | bool foundUpdate = false; | ||
137 | foreach (OSD osd in eventsOsd) | ||
138 | { | ||
139 | OSDMap eventOsd = (OSDMap)osd; | ||
140 | |||
141 | if (eventOsd["message"] == messageName) | ||
142 | foundUpdate = true; | ||
143 | } | ||
144 | |||
145 | Assert.That(foundUpdate, Is.True, string.Format("Did not find {0} in response", messageName)); | ||
146 | } | ||
147 | |||
148 | /// <summary> | ||
149 | /// Test an attempt to put a message on the queue of a user that is not in the region. | ||
150 | /// </summary> | ||
151 | [Test] | ||
152 | public void TestEnqueueMessageNoUser() | ||
153 | { | ||
154 | TestHelpers.InMethod(); | ||
155 | TestHelpers.EnableLogging(); | ||
156 | |||
157 | string messageName = "TestMessage"; | ||
158 | |||
159 | m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), TestHelpers.ParseTail(0x1)); | ||
160 | |||
161 | Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, TestHelpers.ParseTail(0x1)); | ||
162 | |||
163 | Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway)); | ||
164 | } | ||
165 | |||
166 | /// <summary> | ||
167 | /// NPCs do not currently have an event queue but a caller may try to send a message anyway, so check behaviour. | ||
168 | /// </summary> | ||
169 | [Test] | ||
170 | public void TestEnqueueMessageToNpc() | ||
171 | { | ||
172 | TestHelpers.InMethod(); | ||
173 | // TestHelpers.EnableLogging(); | ||
174 | |||
175 | UUID npcId | ||
176 | = m_npcMod.CreateNPC( | ||
177 | "John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, new AvatarAppearance()); | ||
178 | |||
179 | ScenePresence npc = m_scene.GetScenePresence(npcId); | ||
180 | |||
181 | string messageName = "TestMessage"; | ||
182 | |||
183 | m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), npc.UUID); | ||
184 | |||
185 | Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, npc.UUID); | ||
186 | |||
187 | Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway)); | ||
188 | } | ||
189 | } | ||
190 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs b/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs new file mode 100644 index 0000000..e0a11cc --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using Mono.Addins; | ||
29 | using Nini.Config; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Capabilities.Handlers; | ||
32 | using OpenSim.Framework.Servers.HttpServer; | ||
33 | using OpenSim.Region.Framework.Interfaces; | ||
34 | using OpenSim.Region.Framework.Scenes; | ||
35 | using OpenSim.Services.Interfaces; | ||
36 | using System; | ||
37 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
38 | |||
39 | namespace OpenSim.Region.ClientStack.Linden | ||
40 | { | ||
41 | /// <summary> | ||
42 | /// This module implements both WebFetchInventoryDescendents and FetchInventoryDescendents2 capabilities. | ||
43 | /// </summary> | ||
44 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "FetchInventory2Module")] | ||
45 | public class FetchInventory2Module : INonSharedRegionModule | ||
46 | { | ||
47 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
48 | |||
49 | public bool Enabled { get; private set; } | ||
50 | |||
51 | private Scene m_scene; | ||
52 | |||
53 | private IInventoryService m_inventoryService; | ||
54 | |||
55 | private string m_fetchInventory2Url; | ||
56 | |||
57 | #region ISharedRegionModule Members | ||
58 | |||
59 | public void Initialise(IConfigSource source) | ||
60 | { | ||
61 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
62 | if (config == null) | ||
63 | return; | ||
64 | |||
65 | m_fetchInventory2Url = config.GetString("Cap_FetchInventory2", string.Empty); | ||
66 | |||
67 | if (m_fetchInventory2Url != string.Empty) | ||
68 | Enabled = true; | ||
69 | } | ||
70 | |||
71 | public void AddRegion(Scene s) | ||
72 | { | ||
73 | if (!Enabled) | ||
74 | return; | ||
75 | |||
76 | m_scene = s; | ||
77 | } | ||
78 | |||
79 | public void RemoveRegion(Scene s) | ||
80 | { | ||
81 | if (!Enabled) | ||
82 | return; | ||
83 | |||
84 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
85 | m_scene = null; | ||
86 | } | ||
87 | |||
88 | public void RegionLoaded(Scene s) | ||
89 | { | ||
90 | if (!Enabled) | ||
91 | return; | ||
92 | |||
93 | m_inventoryService = m_scene.InventoryService; | ||
94 | |||
95 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
96 | } | ||
97 | |||
98 | public void PostInitialise() {} | ||
99 | |||
100 | public void Close() {} | ||
101 | |||
102 | public string Name { get { return "FetchInventory2Module"; } } | ||
103 | |||
104 | public Type ReplaceableInterface | ||
105 | { | ||
106 | get { return null; } | ||
107 | } | ||
108 | |||
109 | #endregion | ||
110 | |||
111 | private void RegisterCaps(UUID agentID, Caps caps) | ||
112 | { | ||
113 | RegisterFetchCap(agentID, caps, "FetchInventory2", m_fetchInventory2Url); | ||
114 | } | ||
115 | |||
116 | private void RegisterFetchCap(UUID agentID, Caps caps, string capName, string url) | ||
117 | { | ||
118 | string capUrl; | ||
119 | |||
120 | if (url == "localhost") | ||
121 | { | ||
122 | capUrl = "/CAPS/" + UUID.Random(); | ||
123 | |||
124 | FetchInventory2Handler fetchHandler = new FetchInventory2Handler(m_inventoryService, agentID); | ||
125 | |||
126 | IRequestHandler reqHandler | ||
127 | = new RestStreamHandler( | ||
128 | "POST", capUrl, fetchHandler.FetchInventoryRequest, capName, agentID.ToString()); | ||
129 | |||
130 | caps.RegisterHandler(capName, reqHandler); | ||
131 | } | ||
132 | else | ||
133 | { | ||
134 | capUrl = url; | ||
135 | |||
136 | caps.RegisterHandler(capName, capUrl); | ||
137 | } | ||
138 | |||
139 | // m_log.DebugFormat( | ||
140 | // "[FETCH INVENTORY2 MODULE]: Registered capability {0} at {1} in region {2} for {3}", | ||
141 | // capName, capUrl, m_scene.RegionInfo.RegionName, agentID); | ||
142 | } | ||
143 | } | ||
144 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs new file mode 100644 index 0000000..6617bbc --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Drawing; | ||
32 | using System.Drawing.Imaging; | ||
33 | using System.Reflection; | ||
34 | using System.IO; | ||
35 | using System.Web; | ||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using Mono.Addins; | ||
39 | using OpenMetaverse; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenMetaverse.Imaging; | ||
42 | using OpenSim.Framework; | ||
43 | using OpenSim.Framework.Servers; | ||
44 | using OpenSim.Framework.Servers.HttpServer; | ||
45 | using OpenSim.Region.Framework.Interfaces; | ||
46 | using OpenSim.Region.Framework.Scenes; | ||
47 | using OpenSim.Services.Interfaces; | ||
48 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
49 | using OpenSim.Capabilities.Handlers; | ||
50 | |||
51 | namespace OpenSim.Region.ClientStack.Linden | ||
52 | { | ||
53 | |||
54 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetDisplayNamesModule")] | ||
55 | public class GetDisplayNamesModule : INonSharedRegionModule | ||
56 | { | ||
57 | private static readonly ILog m_log = | ||
58 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
59 | |||
60 | private Scene m_scene; | ||
61 | private IUserManagement m_UserManager; | ||
62 | |||
63 | private bool m_Enabled = false; | ||
64 | |||
65 | private string m_URL; | ||
66 | |||
67 | #region ISharedRegionModule Members | ||
68 | |||
69 | public void Initialise(IConfigSource source) | ||
70 | { | ||
71 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
72 | if (config == null) | ||
73 | return; | ||
74 | |||
75 | m_URL = config.GetString("Cap_GetDisplayNames", string.Empty); | ||
76 | if (m_URL != string.Empty) | ||
77 | m_Enabled = true; | ||
78 | } | ||
79 | |||
80 | public void AddRegion(Scene s) | ||
81 | { | ||
82 | if (!m_Enabled) | ||
83 | return; | ||
84 | |||
85 | m_scene = s; | ||
86 | } | ||
87 | |||
88 | public void RemoveRegion(Scene s) | ||
89 | { | ||
90 | if (!m_Enabled) | ||
91 | return; | ||
92 | |||
93 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
94 | m_scene = null; | ||
95 | } | ||
96 | |||
97 | public void RegionLoaded(Scene s) | ||
98 | { | ||
99 | if (!m_Enabled) | ||
100 | return; | ||
101 | |||
102 | m_UserManager = m_scene.RequestModuleInterface<IUserManagement>(); | ||
103 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
104 | } | ||
105 | |||
106 | public void PostInitialise() | ||
107 | { | ||
108 | } | ||
109 | |||
110 | public void Close() { } | ||
111 | |||
112 | public string Name { get { return "GetDisplayNamesModule"; } } | ||
113 | |||
114 | public Type ReplaceableInterface | ||
115 | { | ||
116 | get { return null; } | ||
117 | } | ||
118 | |||
119 | #endregion | ||
120 | |||
121 | public void RegisterCaps(UUID agentID, Caps caps) | ||
122 | { | ||
123 | UUID capID = UUID.Random(); | ||
124 | |||
125 | if (m_URL == "localhost") | ||
126 | { | ||
127 | m_log.DebugFormat("[GET_DISPLAY_NAMES]: /CAPS/agents/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | ||
128 | caps.RegisterHandler( | ||
129 | "GetDisplayNames", | ||
130 | new GetDisplayNamesHandler("/CAPS/agents" + capID + "/", m_UserManager, "GetDisplayNames", agentID.ToString())); | ||
131 | } | ||
132 | else | ||
133 | { | ||
134 | // m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); | ||
135 | IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>(); | ||
136 | if (handler != null) | ||
137 | handler.RegisterExternalUserCapsHandler(agentID,caps,"GetDisplayNames", m_URL); | ||
138 | else | ||
139 | caps.RegisterHandler("GetDisplayNames", m_URL); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | } | ||
144 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs new file mode 100644 index 0000000..f57d857 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using System.IO; | ||
33 | using System.Web; | ||
34 | using Mono.Addins; | ||
35 | using log4net; | ||
36 | using Nini.Config; | ||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.StructuredData; | ||
39 | using OpenSim.Capabilities.Handlers; | ||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
43 | using OpenSim.Region.Framework.Interfaces; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | using OpenSim.Services.Interfaces; | ||
46 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
47 | |||
48 | namespace OpenSim.Region.ClientStack.Linden | ||
49 | { | ||
50 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetMeshModule")] | ||
51 | public class GetMeshModule : INonSharedRegionModule | ||
52 | { | ||
53 | // private static readonly ILog m_log = | ||
54 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | |||
56 | private Scene m_scene; | ||
57 | private IAssetService m_AssetService; | ||
58 | private bool m_Enabled = true; | ||
59 | private string m_URL; | ||
60 | private string m_URL2; | ||
61 | private string m_RedirectURL = null; | ||
62 | private string m_RedirectURL2 = null; | ||
63 | |||
64 | #region Region Module interfaceBase Members | ||
65 | |||
66 | public Type ReplaceableInterface | ||
67 | { | ||
68 | get { return null; } | ||
69 | } | ||
70 | |||
71 | public void Initialise(IConfigSource source) | ||
72 | { | ||
73 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
74 | if (config == null) | ||
75 | return; | ||
76 | |||
77 | m_URL = config.GetString("Cap_GetMesh", string.Empty); | ||
78 | // Cap doesn't exist | ||
79 | if (m_URL != string.Empty) | ||
80 | { | ||
81 | m_Enabled = true; | ||
82 | m_RedirectURL = config.GetString("GetMeshRedirectURL"); | ||
83 | } | ||
84 | |||
85 | m_URL2 = config.GetString("Cap_GetMesh2", string.Empty); | ||
86 | // Cap doesn't exist | ||
87 | if (m_URL2 != string.Empty) | ||
88 | { | ||
89 | m_Enabled = true; | ||
90 | m_RedirectURL2 = config.GetString("GetMesh2RedirectURL"); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | public void AddRegion(Scene pScene) | ||
95 | { | ||
96 | if (!m_Enabled) | ||
97 | return; | ||
98 | |||
99 | m_scene = pScene; | ||
100 | } | ||
101 | |||
102 | public void RemoveRegion(Scene scene) | ||
103 | { | ||
104 | if (!m_Enabled) | ||
105 | return; | ||
106 | |||
107 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
108 | m_scene = null; | ||
109 | } | ||
110 | |||
111 | public void RegionLoaded(Scene scene) | ||
112 | { | ||
113 | if (!m_Enabled) | ||
114 | return; | ||
115 | |||
116 | m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); | ||
117 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
118 | } | ||
119 | |||
120 | |||
121 | public void Close() { } | ||
122 | |||
123 | public string Name { get { return "GetMeshModule"; } } | ||
124 | |||
125 | #endregion | ||
126 | |||
127 | |||
128 | public void RegisterCaps(UUID agentID, Caps caps) | ||
129 | { | ||
130 | UUID capID = UUID.Random(); | ||
131 | bool getMeshRegistered = false; | ||
132 | |||
133 | if (m_URL == string.Empty) | ||
134 | { | ||
135 | |||
136 | } | ||
137 | else if (m_URL == "localhost") | ||
138 | { | ||
139 | getMeshRegistered = true; | ||
140 | caps.RegisterHandler( | ||
141 | "GetMesh", | ||
142 | new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh", agentID.ToString(), m_RedirectURL)); | ||
143 | } | ||
144 | else | ||
145 | { | ||
146 | caps.RegisterHandler("GetMesh", m_URL); | ||
147 | } | ||
148 | |||
149 | if(m_URL2 == string.Empty) | ||
150 | { | ||
151 | |||
152 | } | ||
153 | else if (m_URL2 == "localhost") | ||
154 | { | ||
155 | if (!getMeshRegistered) | ||
156 | { | ||
157 | caps.RegisterHandler( | ||
158 | "GetMesh2", | ||
159 | new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh2", agentID.ToString(), m_RedirectURL2)); | ||
160 | } | ||
161 | } | ||
162 | else | ||
163 | { | ||
164 | caps.RegisterHandler("GetMesh2", m_URL2); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | } | ||
169 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs new file mode 100644 index 0000000..bb932f2 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs | |||
@@ -0,0 +1,152 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Drawing; | ||
32 | using System.Drawing.Imaging; | ||
33 | using System.Reflection; | ||
34 | using System.IO; | ||
35 | using System.Web; | ||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using Mono.Addins; | ||
39 | using OpenMetaverse; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenMetaverse.Imaging; | ||
42 | using OpenSim.Framework; | ||
43 | using OpenSim.Framework.Servers; | ||
44 | using OpenSim.Framework.Servers.HttpServer; | ||
45 | using OpenSim.Region.Framework.Interfaces; | ||
46 | using OpenSim.Region.Framework.Scenes; | ||
47 | using OpenSim.Services.Interfaces; | ||
48 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
49 | using OpenSim.Capabilities.Handlers; | ||
50 | |||
51 | namespace OpenSim.Region.ClientStack.Linden | ||
52 | { | ||
53 | |||
54 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")] | ||
55 | public class GetTextureModule : INonSharedRegionModule | ||
56 | { | ||
57 | // private static readonly ILog m_log = | ||
58 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
59 | |||
60 | private Scene m_scene; | ||
61 | private IAssetService m_assetService; | ||
62 | |||
63 | private bool m_Enabled = false; | ||
64 | |||
65 | // TODO: Change this to a config option | ||
66 | private string m_RedirectURL = null; | ||
67 | |||
68 | private string m_URL; | ||
69 | |||
70 | #region ISharedRegionModule Members | ||
71 | |||
72 | public void Initialise(IConfigSource source) | ||
73 | { | ||
74 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
75 | if (config == null) | ||
76 | return; | ||
77 | |||
78 | m_URL = config.GetString("Cap_GetTexture", string.Empty); | ||
79 | // Cap doesn't exist | ||
80 | if (m_URL != string.Empty) | ||
81 | { | ||
82 | m_Enabled = true; | ||
83 | m_RedirectURL = config.GetString("GetTextureRedirectURL"); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | public void AddRegion(Scene s) | ||
88 | { | ||
89 | if (!m_Enabled) | ||
90 | return; | ||
91 | |||
92 | m_scene = s; | ||
93 | } | ||
94 | |||
95 | public void RemoveRegion(Scene s) | ||
96 | { | ||
97 | if (!m_Enabled) | ||
98 | return; | ||
99 | |||
100 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
101 | m_scene = null; | ||
102 | } | ||
103 | |||
104 | public void RegionLoaded(Scene s) | ||
105 | { | ||
106 | if (!m_Enabled) | ||
107 | return; | ||
108 | |||
109 | m_assetService = m_scene.RequestModuleInterface<IAssetService>(); | ||
110 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
111 | } | ||
112 | |||
113 | public void PostInitialise() | ||
114 | { | ||
115 | } | ||
116 | |||
117 | public void Close() { } | ||
118 | |||
119 | public string Name { get { return "GetTextureModule"; } } | ||
120 | |||
121 | public Type ReplaceableInterface | ||
122 | { | ||
123 | get { return null; } | ||
124 | } | ||
125 | |||
126 | #endregion | ||
127 | |||
128 | public void RegisterCaps(UUID agentID, Caps caps) | ||
129 | { | ||
130 | UUID capID = UUID.Random(); | ||
131 | |||
132 | //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); | ||
133 | if (m_URL == "localhost") | ||
134 | { | ||
135 | // m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | ||
136 | caps.RegisterHandler( | ||
137 | "GetTexture", | ||
138 | new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString(), m_RedirectURL)); | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | // m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); | ||
143 | IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>(); | ||
144 | if (handler != null) | ||
145 | handler.RegisterExternalUserCapsHandler(agentID,caps,"GetTexture", m_URL); | ||
146 | else | ||
147 | caps.RegisterHandler("GetTexture", m_URL); | ||
148 | } | ||
149 | } | ||
150 | |||
151 | } | ||
152 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs new file mode 100644 index 0000000..45d33cd --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using Mono.Addins; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Framework.Servers.HttpServer; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
42 | |||
43 | namespace OpenSim.Region.ClientStack.Linden | ||
44 | { | ||
45 | /// <summary> | ||
46 | /// MeshUploadFlag capability. This is required for uploading Mesh. | ||
47 | /// </summary> | ||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MeshUploadFlagModule")] | ||
49 | public class MeshUploadFlagModule : INonSharedRegionModule | ||
50 | { | ||
51 | // private static readonly ILog m_log = | ||
52 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
53 | |||
54 | /// <summary> | ||
55 | /// Is this module enabled? | ||
56 | /// </summary> | ||
57 | public bool Enabled { get; private set; } | ||
58 | |||
59 | private Scene m_scene; | ||
60 | |||
61 | #region ISharedRegionModule Members | ||
62 | |||
63 | public MeshUploadFlagModule() | ||
64 | { | ||
65 | Enabled = true; | ||
66 | } | ||
67 | |||
68 | public void Initialise(IConfigSource source) | ||
69 | { | ||
70 | IConfig config = source.Configs["Mesh"]; | ||
71 | if (config == null) | ||
72 | { | ||
73 | return; | ||
74 | } | ||
75 | else | ||
76 | { | ||
77 | Enabled = config.GetBoolean("AllowMeshUpload", Enabled); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | public void AddRegion(Scene s) | ||
82 | { | ||
83 | if (!Enabled) | ||
84 | return; | ||
85 | |||
86 | m_scene = s; | ||
87 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
88 | } | ||
89 | |||
90 | public void RemoveRegion(Scene s) | ||
91 | { | ||
92 | if (!Enabled) | ||
93 | return; | ||
94 | |||
95 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
96 | } | ||
97 | |||
98 | public void RegionLoaded(Scene s) | ||
99 | { | ||
100 | } | ||
101 | |||
102 | public void PostInitialise() | ||
103 | { | ||
104 | } | ||
105 | |||
106 | public void Close() { } | ||
107 | |||
108 | public string Name { get { return "MeshUploadFlagModule"; } } | ||
109 | |||
110 | public Type ReplaceableInterface | ||
111 | { | ||
112 | get { return null; } | ||
113 | } | ||
114 | |||
115 | #endregion | ||
116 | |||
117 | public void RegisterCaps(UUID agentID, Caps caps) | ||
118 | { | ||
119 | IRequestHandler reqHandler | ||
120 | = new RestHTTPHandler( | ||
121 | "GET", "/CAPS/" + UUID.Random(), ht => MeshUploadFlag(ht, agentID), "MeshUploadFlag", agentID.ToString()); | ||
122 | |||
123 | caps.RegisterHandler("MeshUploadFlag", reqHandler); | ||
124 | |||
125 | } | ||
126 | |||
127 | private Hashtable MeshUploadFlag(Hashtable mDhttpMethod, UUID agentID) | ||
128 | { | ||
129 | // m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); | ||
130 | |||
131 | OSDMap data = new OSDMap(); | ||
132 | ScenePresence sp = m_scene.GetScenePresence(agentID); | ||
133 | data["username"] = sp.Firstname + "." + sp.Lastname; | ||
134 | data["display_name_next_update"] = new OSDDate(DateTime.Now); | ||
135 | data["legacy_first_name"] = sp.Firstname; | ||
136 | data["mesh_upload_status"] = "valid"; | ||
137 | data["display_name"] = sp.Firstname + " " + sp.Lastname; | ||
138 | data["legacy_last_name"] = sp.Lastname; | ||
139 | data["id"] = agentID; | ||
140 | data["is_display_name_default"] = true; | ||
141 | |||
142 | //Send back data | ||
143 | Hashtable responsedata = new Hashtable(); | ||
144 | responsedata["int_response_code"] = 200; | ||
145 | responsedata["content_type"] = "text/plain"; | ||
146 | responsedata["keepalive"] = false; | ||
147 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(data); | ||
148 | return responsedata; | ||
149 | } | ||
150 | } | ||
151 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs new file mode 100644 index 0000000..f69a0bb --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs | |||
@@ -0,0 +1,297 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using System.IO; | ||
33 | using System.Web; | ||
34 | using Mono.Addins; | ||
35 | using log4net; | ||
36 | using Nini.Config; | ||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.StructuredData; | ||
39 | using OpenSim.Framework; | ||
40 | using OpenSim.Framework.Servers; | ||
41 | using OpenSim.Framework.Servers.HttpServer; | ||
42 | using OpenSim.Region.Framework.Interfaces; | ||
43 | using OpenSim.Region.Framework.Scenes; | ||
44 | using OpenSim.Services.Interfaces; | ||
45 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
46 | using OpenSim.Framework.Capabilities; | ||
47 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
48 | |||
49 | namespace OpenSim.Region.ClientStack.Linden | ||
50 | { | ||
51 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "NewFileAgentInventoryVariablePriceModule")] | ||
52 | public class NewFileAgentInventoryVariablePriceModule : INonSharedRegionModule | ||
53 | { | ||
54 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | |||
56 | private Scene m_scene; | ||
57 | // private IAssetService m_assetService; | ||
58 | private bool m_dumpAssetsToFile = false; | ||
59 | private bool m_enabled = true; | ||
60 | private int m_levelUpload = 0; | ||
61 | |||
62 | #region Region Module interfaceBase Members | ||
63 | |||
64 | |||
65 | public Type ReplaceableInterface | ||
66 | { | ||
67 | get { return null; } | ||
68 | } | ||
69 | |||
70 | public void Initialise(IConfigSource source) | ||
71 | { | ||
72 | IConfig meshConfig = source.Configs["Mesh"]; | ||
73 | if (meshConfig == null) | ||
74 | return; | ||
75 | |||
76 | m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true); | ||
77 | m_levelUpload = meshConfig.GetInt("LevelUpload", 0); | ||
78 | } | ||
79 | |||
80 | public void AddRegion(Scene pScene) | ||
81 | { | ||
82 | m_scene = pScene; | ||
83 | } | ||
84 | |||
85 | public void RemoveRegion(Scene scene) | ||
86 | { | ||
87 | |||
88 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
89 | m_scene = null; | ||
90 | } | ||
91 | |||
92 | public void RegionLoaded(Scene scene) | ||
93 | { | ||
94 | |||
95 | // m_assetService = m_scene.RequestModuleInterface<IAssetService>(); | ||
96 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
97 | } | ||
98 | |||
99 | #endregion | ||
100 | |||
101 | |||
102 | #region Region Module interface | ||
103 | |||
104 | |||
105 | |||
106 | public void Close() { } | ||
107 | |||
108 | public string Name { get { return "NewFileAgentInventoryVariablePriceModule"; } } | ||
109 | |||
110 | |||
111 | public void RegisterCaps(UUID agentID, Caps caps) | ||
112 | { | ||
113 | if(!m_enabled) | ||
114 | return; | ||
115 | |||
116 | UUID capID = UUID.Random(); | ||
117 | |||
118 | // m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID); | ||
119 | caps.RegisterHandler( | ||
120 | "NewFileAgentInventoryVariablePrice", | ||
121 | new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>( | ||
122 | "POST", | ||
123 | "/CAPS/" + capID.ToString(), | ||
124 | req => NewAgentInventoryRequest(req, agentID), | ||
125 | "NewFileAgentInventoryVariablePrice", | ||
126 | agentID.ToString())); | ||
127 | } | ||
128 | |||
129 | #endregion | ||
130 | |||
131 | public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID) | ||
132 | { | ||
133 | //TODO: The Mesh uploader uploads many types of content. If you're going to implement a Money based limit | ||
134 | // you need to be aware of this | ||
135 | |||
136 | //if (llsdRequest.asset_type == "texture" || | ||
137 | // llsdRequest.asset_type == "animation" || | ||
138 | // llsdRequest.asset_type == "sound") | ||
139 | // { | ||
140 | // check user level | ||
141 | |||
142 | ScenePresence avatar = null; | ||
143 | IClientAPI client = null; | ||
144 | m_scene.TryGetScenePresence(agentID, out avatar); | ||
145 | |||
146 | if (avatar != null) | ||
147 | { | ||
148 | client = avatar.ControllingClient; | ||
149 | |||
150 | if (avatar.UserLevel < m_levelUpload) | ||
151 | { | ||
152 | if (client != null) | ||
153 | client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); | ||
154 | |||
155 | LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse(); | ||
156 | errorResponse.rsvp = ""; | ||
157 | errorResponse.state = "error"; | ||
158 | return errorResponse; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | // check funds | ||
163 | IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>(); | ||
164 | |||
165 | if (mm != null) | ||
166 | { | ||
167 | if (!mm.UploadCovered(agentID, mm.UploadCharge)) | ||
168 | { | ||
169 | if (client != null) | ||
170 | client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); | ||
171 | |||
172 | LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse(); | ||
173 | errorResponse.rsvp = ""; | ||
174 | errorResponse.state = "error"; | ||
175 | return errorResponse; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | // } | ||
180 | |||
181 | string assetName = llsdRequest.name; | ||
182 | string assetDes = llsdRequest.description; | ||
183 | string capsBase = "/CAPS/NewFileAgentInventoryVariablePrice/"; | ||
184 | UUID newAsset = UUID.Random(); | ||
185 | UUID newInvItem = UUID.Random(); | ||
186 | UUID parentFolder = llsdRequest.folder_id; | ||
187 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/"; | ||
188 | |||
189 | AssetUploader uploader = | ||
190 | new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, | ||
191 | llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile); | ||
192 | |||
193 | MainServer.Instance.AddStreamHandler( | ||
194 | new BinaryStreamHandler( | ||
195 | "POST", | ||
196 | capsBase + uploaderPath, | ||
197 | uploader.uploaderCaps, | ||
198 | "NewFileAgentInventoryVariablePrice", | ||
199 | agentID.ToString())); | ||
200 | |||
201 | string protocol = "http://"; | ||
202 | |||
203 | if (MainServer.Instance.UseSSL) | ||
204 | protocol = "https://"; | ||
205 | |||
206 | string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase + | ||
207 | uploaderPath; | ||
208 | |||
209 | |||
210 | LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse(); | ||
211 | |||
212 | uploadResponse.rsvp = uploaderURL; | ||
213 | uploadResponse.state = "upload"; | ||
214 | uploadResponse.resource_cost = 0; | ||
215 | uploadResponse.upload_price = 0; | ||
216 | |||
217 | uploader.OnUpLoad += //UploadCompleteHandler; | ||
218 | |||
219 | delegate( | ||
220 | string passetName, string passetDescription, UUID passetID, | ||
221 | UUID pinventoryItem, UUID pparentFolder, byte[] pdata, string pinventoryType, | ||
222 | string passetType) | ||
223 | { | ||
224 | UploadCompleteHandler(passetName, passetDescription, passetID, | ||
225 | pinventoryItem, pparentFolder, pdata, pinventoryType, | ||
226 | passetType,agentID); | ||
227 | }; | ||
228 | |||
229 | return uploadResponse; | ||
230 | } | ||
231 | |||
232 | public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, | ||
233 | UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, | ||
234 | string assetType,UUID AgentID) | ||
235 | { | ||
236 | // m_log.DebugFormat( | ||
237 | // "[NEW FILE AGENT INVENTORY VARIABLE PRICE MODULE]: Upload complete for {0}", inventoryItem); | ||
238 | |||
239 | sbyte assType = 0; | ||
240 | sbyte inType = 0; | ||
241 | |||
242 | if (inventoryType == "sound") | ||
243 | { | ||
244 | inType = 1; | ||
245 | assType = 1; | ||
246 | } | ||
247 | else if (inventoryType == "animation") | ||
248 | { | ||
249 | inType = 19; | ||
250 | assType = 20; | ||
251 | } | ||
252 | else if (inventoryType == "wearable") | ||
253 | { | ||
254 | inType = 18; | ||
255 | switch (assetType) | ||
256 | { | ||
257 | case "bodypart": | ||
258 | assType = 13; | ||
259 | break; | ||
260 | case "clothing": | ||
261 | assType = 5; | ||
262 | break; | ||
263 | } | ||
264 | } | ||
265 | else if (inventoryType == "mesh") | ||
266 | { | ||
267 | inType = (sbyte)InventoryType.Mesh; | ||
268 | assType = (sbyte)AssetType.Mesh; | ||
269 | } | ||
270 | |||
271 | AssetBase asset; | ||
272 | asset = new AssetBase(assetID, assetName, assType, AgentID.ToString()); | ||
273 | asset.Data = data; | ||
274 | |||
275 | if (m_scene.AssetService != null) | ||
276 | m_scene.AssetService.Store(asset); | ||
277 | |||
278 | InventoryItemBase item = new InventoryItemBase(); | ||
279 | item.Owner = AgentID; | ||
280 | item.CreatorId = AgentID.ToString(); | ||
281 | item.ID = inventoryItem; | ||
282 | item.AssetID = asset.FullID; | ||
283 | item.Description = assetDescription; | ||
284 | item.Name = assetName; | ||
285 | item.AssetType = assType; | ||
286 | item.InvType = inType; | ||
287 | item.Folder = parentFolder; | ||
288 | item.CurrentPermissions | ||
289 | = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer); | ||
290 | item.BasePermissions = (uint)PermissionMask.All; | ||
291 | item.EveryOnePermissions = 0; | ||
292 | item.NextPermissions = (uint)PermissionMask.All; | ||
293 | item.CreationDate = Util.UnixTimeSinceEpoch(); | ||
294 | m_scene.AddInventoryItem(item); | ||
295 | } | ||
296 | } | ||
297 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs new file mode 100644 index 0000000..94f8bc1 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs | |||
@@ -0,0 +1,389 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using OpenMetaverse; | ||
34 | using OpenMetaverse.StructuredData; | ||
35 | using Mono.Addins; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Framework.Servers; | ||
38 | using OpenSim.Framework.Servers.HttpServer; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | using Caps=OpenSim.Framework.Capabilities.Caps; | ||
42 | |||
43 | namespace OpenSim.Region.ClientStack.Linden | ||
44 | { | ||
45 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ObjectAdd")] | ||
46 | public class ObjectAdd : INonSharedRegionModule | ||
47 | { | ||
48 | // private static readonly ILog m_log = | ||
49 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
50 | |||
51 | private Scene m_scene; | ||
52 | |||
53 | #region INonSharedRegionModule Members | ||
54 | |||
55 | public void Initialise(IConfigSource pSource) | ||
56 | { | ||
57 | } | ||
58 | |||
59 | public void AddRegion(Scene scene) | ||
60 | { | ||
61 | m_scene = scene; | ||
62 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
63 | } | ||
64 | |||
65 | public void RemoveRegion(Scene scene) | ||
66 | { | ||
67 | if (m_scene == scene) | ||
68 | { | ||
69 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
70 | m_scene = null; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | public void RegionLoaded(Scene scene) | ||
75 | { | ||
76 | } | ||
77 | |||
78 | public void Close() | ||
79 | { | ||
80 | } | ||
81 | |||
82 | public string Name | ||
83 | { | ||
84 | get { return "ObjectAddModule"; } | ||
85 | } | ||
86 | |||
87 | public Type ReplaceableInterface | ||
88 | { | ||
89 | get { return null; } | ||
90 | } | ||
91 | |||
92 | #endregion | ||
93 | |||
94 | public void RegisterCaps(UUID agentID, Caps caps) | ||
95 | { | ||
96 | UUID capuuid = UUID.Random(); | ||
97 | |||
98 | // m_log.InfoFormat("[OBJECTADD]: {0}", "/CAPS/OA/" + capuuid + "/"); | ||
99 | |||
100 | caps.RegisterHandler( | ||
101 | "ObjectAdd", | ||
102 | new RestHTTPHandler( | ||
103 | "POST", | ||
104 | "/CAPS/OA/" + capuuid + "/", | ||
105 | httpMethod => ProcessAdd(httpMethod, agentID, caps), | ||
106 | "ObjectAdd", | ||
107 | agentID.ToString())); ; | ||
108 | } | ||
109 | |||
110 | public Hashtable ProcessAdd(Hashtable request, UUID AgentId, Caps cap) | ||
111 | { | ||
112 | Hashtable responsedata = new Hashtable(); | ||
113 | responsedata["int_response_code"] = 400; //501; //410; //404; | ||
114 | responsedata["content_type"] = "text/plain"; | ||
115 | responsedata["keepalive"] = false; | ||
116 | responsedata["str_response_string"] = "Request wasn't what was expected"; | ||
117 | ScenePresence avatar; | ||
118 | |||
119 | if (!m_scene.TryGetScenePresence(AgentId, out avatar)) | ||
120 | return responsedata; | ||
121 | |||
122 | |||
123 | OSD r = OSDParser.DeserializeLLSDXml((string)request["requestbody"]); | ||
124 | //UUID session_id = UUID.Zero; | ||
125 | bool bypass_raycast = false; | ||
126 | uint everyone_mask = 0; | ||
127 | uint group_mask = 0; | ||
128 | uint next_owner_mask = 0; | ||
129 | uint flags = 0; | ||
130 | UUID group_id = UUID.Zero; | ||
131 | int hollow = 0; | ||
132 | int material = 0; | ||
133 | int p_code = 0; | ||
134 | int path_begin = 0; | ||
135 | int path_curve = 0; | ||
136 | int path_end = 0; | ||
137 | int path_radius_offset = 0; | ||
138 | int path_revolutions = 0; | ||
139 | int path_scale_x = 0; | ||
140 | int path_scale_y = 0; | ||
141 | int path_shear_x = 0; | ||
142 | int path_shear_y = 0; | ||
143 | int path_skew = 0; | ||
144 | int path_taper_x = 0; | ||
145 | int path_taper_y = 0; | ||
146 | int path_twist = 0; | ||
147 | int path_twist_begin = 0; | ||
148 | int profile_begin = 0; | ||
149 | int profile_curve = 0; | ||
150 | int profile_end = 0; | ||
151 | Vector3 ray_end = Vector3.Zero; | ||
152 | bool ray_end_is_intersection = false; | ||
153 | Vector3 ray_start = Vector3.Zero; | ||
154 | UUID ray_target_id = UUID.Zero; | ||
155 | Quaternion rotation = Quaternion.Identity; | ||
156 | Vector3 scale = Vector3.Zero; | ||
157 | int state = 0; | ||
158 | int lastattach = 0; | ||
159 | |||
160 | if (r.Type != OSDType.Map) // not a proper req | ||
161 | return responsedata; | ||
162 | |||
163 | OSDMap rm = (OSDMap)r; | ||
164 | |||
165 | if (rm.ContainsKey("ObjectData")) //v2 | ||
166 | { | ||
167 | if (rm["ObjectData"].Type != OSDType.Map) | ||
168 | { | ||
169 | responsedata["str_response_string"] = "Has ObjectData key, but data not in expected format"; | ||
170 | return responsedata; | ||
171 | } | ||
172 | |||
173 | OSDMap ObjMap = (OSDMap)rm["ObjectData"]; | ||
174 | |||
175 | bypass_raycast = ObjMap["BypassRaycast"].AsBoolean(); | ||
176 | everyone_mask = readuintval(ObjMap["EveryoneMask"]); | ||
177 | flags = readuintval(ObjMap["Flags"]); | ||
178 | group_mask = readuintval(ObjMap["GroupMask"]); | ||
179 | material = ObjMap["Material"].AsInteger(); | ||
180 | next_owner_mask = readuintval(ObjMap["NextOwnerMask"]); | ||
181 | p_code = ObjMap["PCode"].AsInteger(); | ||
182 | |||
183 | if (ObjMap.ContainsKey("Path")) | ||
184 | { | ||
185 | if (ObjMap["Path"].Type != OSDType.Map) | ||
186 | { | ||
187 | responsedata["str_response_string"] = "Has Path key, but data not in expected format"; | ||
188 | return responsedata; | ||
189 | } | ||
190 | |||
191 | OSDMap PathMap = (OSDMap)ObjMap["Path"]; | ||
192 | path_begin = PathMap["Begin"].AsInteger(); | ||
193 | path_curve = PathMap["Curve"].AsInteger(); | ||
194 | path_end = PathMap["End"].AsInteger(); | ||
195 | path_radius_offset = PathMap["RadiusOffset"].AsInteger(); | ||
196 | path_revolutions = PathMap["Revolutions"].AsInteger(); | ||
197 | path_scale_x = PathMap["ScaleX"].AsInteger(); | ||
198 | path_scale_y = PathMap["ScaleY"].AsInteger(); | ||
199 | path_shear_x = PathMap["ShearX"].AsInteger(); | ||
200 | path_shear_y = PathMap["ShearY"].AsInteger(); | ||
201 | path_skew = PathMap["Skew"].AsInteger(); | ||
202 | path_taper_x = PathMap["TaperX"].AsInteger(); | ||
203 | path_taper_y = PathMap["TaperY"].AsInteger(); | ||
204 | path_twist = PathMap["Twist"].AsInteger(); | ||
205 | path_twist_begin = PathMap["TwistBegin"].AsInteger(); | ||
206 | |||
207 | } | ||
208 | |||
209 | if (ObjMap.ContainsKey("Profile")) | ||
210 | { | ||
211 | if (ObjMap["Profile"].Type != OSDType.Map) | ||
212 | { | ||
213 | responsedata["str_response_string"] = "Has Profile key, but data not in expected format"; | ||
214 | return responsedata; | ||
215 | } | ||
216 | |||
217 | OSDMap ProfileMap = (OSDMap)ObjMap["Profile"]; | ||
218 | |||
219 | profile_begin = ProfileMap["Begin"].AsInteger(); | ||
220 | profile_curve = ProfileMap["Curve"].AsInteger(); | ||
221 | profile_end = ProfileMap["End"].AsInteger(); | ||
222 | hollow = ProfileMap["Hollow"].AsInteger(); | ||
223 | } | ||
224 | ray_end_is_intersection = ObjMap["RayEndIsIntersection"].AsBoolean(); | ||
225 | |||
226 | ray_target_id = ObjMap["RayTargetId"].AsUUID(); | ||
227 | state = ObjMap["State"].AsInteger(); | ||
228 | lastattach = ObjMap["LastAttachPoint"].AsInteger(); | ||
229 | try | ||
230 | { | ||
231 | ray_end = ((OSDArray)ObjMap["RayEnd"]).AsVector3(); | ||
232 | ray_start = ((OSDArray)ObjMap["RayStart"]).AsVector3(); | ||
233 | scale = ((OSDArray)ObjMap["Scale"]).AsVector3(); | ||
234 | rotation = ((OSDArray)ObjMap["Rotation"]).AsQuaternion(); | ||
235 | } | ||
236 | catch (Exception) | ||
237 | { | ||
238 | responsedata["str_response_string"] = "RayEnd, RayStart, Scale or Rotation wasn't in the expected format"; | ||
239 | return responsedata; | ||
240 | } | ||
241 | |||
242 | if (rm.ContainsKey("AgentData")) | ||
243 | { | ||
244 | if (rm["AgentData"].Type != OSDType.Map) | ||
245 | { | ||
246 | responsedata["str_response_string"] = "Has AgentData key, but data not in expected format"; | ||
247 | return responsedata; | ||
248 | } | ||
249 | |||
250 | OSDMap AgentDataMap = (OSDMap)rm["AgentData"]; | ||
251 | |||
252 | //session_id = AgentDataMap["SessionId"].AsUUID(); | ||
253 | group_id = AgentDataMap["GroupId"].AsUUID(); | ||
254 | } | ||
255 | |||
256 | } | ||
257 | else | ||
258 | { //v1 | ||
259 | bypass_raycast = rm["bypass_raycast"].AsBoolean(); | ||
260 | |||
261 | everyone_mask = readuintval(rm["everyone_mask"]); | ||
262 | flags = readuintval(rm["flags"]); | ||
263 | group_id = rm["group_id"].AsUUID(); | ||
264 | group_mask = readuintval(rm["group_mask"]); | ||
265 | hollow = rm["hollow"].AsInteger(); | ||
266 | material = rm["material"].AsInteger(); | ||
267 | next_owner_mask = readuintval(rm["next_owner_mask"]); | ||
268 | hollow = rm["hollow"].AsInteger(); | ||
269 | p_code = rm["p_code"].AsInteger(); | ||
270 | path_begin = rm["path_begin"].AsInteger(); | ||
271 | path_curve = rm["path_curve"].AsInteger(); | ||
272 | path_end = rm["path_end"].AsInteger(); | ||
273 | path_radius_offset = rm["path_radius_offset"].AsInteger(); | ||
274 | path_revolutions = rm["path_revolutions"].AsInteger(); | ||
275 | path_scale_x = rm["path_scale_x"].AsInteger(); | ||
276 | path_scale_y = rm["path_scale_y"].AsInteger(); | ||
277 | path_shear_x = rm["path_shear_x"].AsInteger(); | ||
278 | path_shear_y = rm["path_shear_y"].AsInteger(); | ||
279 | path_skew = rm["path_skew"].AsInteger(); | ||
280 | path_taper_x = rm["path_taper_x"].AsInteger(); | ||
281 | path_taper_y = rm["path_taper_y"].AsInteger(); | ||
282 | path_twist = rm["path_twist"].AsInteger(); | ||
283 | path_twist_begin = rm["path_twist_begin"].AsInteger(); | ||
284 | profile_begin = rm["profile_begin"].AsInteger(); | ||
285 | profile_curve = rm["profile_curve"].AsInteger(); | ||
286 | profile_end = rm["profile_end"].AsInteger(); | ||
287 | |||
288 | ray_end_is_intersection = rm["ray_end_is_intersection"].AsBoolean(); | ||
289 | |||
290 | ray_target_id = rm["ray_target_id"].AsUUID(); | ||
291 | |||
292 | |||
293 | //session_id = rm["session_id"].AsUUID(); | ||
294 | state = rm["state"].AsInteger(); | ||
295 | lastattach = rm["last_attach_point"].AsInteger(); | ||
296 | try | ||
297 | { | ||
298 | ray_end = ((OSDArray)rm["ray_end"]).AsVector3(); | ||
299 | ray_start = ((OSDArray)rm["ray_start"]).AsVector3(); | ||
300 | rotation = ((OSDArray)rm["rotation"]).AsQuaternion(); | ||
301 | scale = ((OSDArray)rm["scale"]).AsVector3(); | ||
302 | } | ||
303 | catch (Exception) | ||
304 | { | ||
305 | responsedata["str_response_string"] = "RayEnd, RayStart, Scale or Rotation wasn't in the expected format"; | ||
306 | return responsedata; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | |||
311 | |||
312 | Vector3 pos = m_scene.GetNewRezLocation(ray_start, ray_end, ray_target_id, rotation, (bypass_raycast) ? (byte)1 : (byte)0, (ray_end_is_intersection) ? (byte)1 : (byte)0, true, scale, false); | ||
313 | |||
314 | PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); | ||
315 | |||
316 | pbs.PathBegin = (ushort)path_begin; | ||
317 | pbs.PathCurve = (byte)path_curve; | ||
318 | pbs.PathEnd = (ushort)path_end; | ||
319 | pbs.PathRadiusOffset = (sbyte)path_radius_offset; | ||
320 | pbs.PathRevolutions = (byte)path_revolutions; | ||
321 | pbs.PathScaleX = (byte)path_scale_x; | ||
322 | pbs.PathScaleY = (byte)path_scale_y; | ||
323 | pbs.PathShearX = (byte)path_shear_x; | ||
324 | pbs.PathShearY = (byte)path_shear_y; | ||
325 | pbs.PathSkew = (sbyte)path_skew; | ||
326 | pbs.PathTaperX = (sbyte)path_taper_x; | ||
327 | pbs.PathTaperY = (sbyte)path_taper_y; | ||
328 | pbs.PathTwist = (sbyte)path_twist; | ||
329 | pbs.PathTwistBegin = (sbyte)path_twist_begin; | ||
330 | pbs.HollowShape = (HollowShape)hollow; | ||
331 | pbs.PCode = (byte)p_code; | ||
332 | pbs.ProfileBegin = (ushort)profile_begin; | ||
333 | pbs.ProfileCurve = (byte)profile_curve; | ||
334 | pbs.ProfileEnd = (ushort)profile_end; | ||
335 | pbs.Scale = scale; | ||
336 | pbs.State = (byte)state; | ||
337 | pbs.LastAttachPoint = (byte)lastattach; | ||
338 | |||
339 | SceneObjectGroup obj = null; ; | ||
340 | |||
341 | if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos)) | ||
342 | { | ||
343 | // rez ON the ground, not IN the ground | ||
344 | // pos.Z += 0.25F; | ||
345 | |||
346 | obj = m_scene.AddNewPrim(avatar.UUID, group_id, pos, rotation, pbs); | ||
347 | } | ||
348 | |||
349 | |||
350 | if (obj == null) | ||
351 | return responsedata; | ||
352 | |||
353 | SceneObjectPart rootpart = obj.RootPart; | ||
354 | rootpart.Shape = pbs; | ||
355 | rootpart.Flags |= (PrimFlags)flags; | ||
356 | rootpart.EveryoneMask = everyone_mask; | ||
357 | rootpart.GroupID = group_id; | ||
358 | rootpart.GroupMask = group_mask; | ||
359 | rootpart.NextOwnerMask = next_owner_mask; | ||
360 | rootpart.Material = (byte)material; | ||
361 | |||
362 | m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor); | ||
363 | |||
364 | responsedata["int_response_code"] = 200; //501; //410; //404; | ||
365 | responsedata["content_type"] = "text/plain"; | ||
366 | responsedata["keepalive"] = false; | ||
367 | responsedata["str_response_string"] = String.Format("<llsd><map><key>local_id</key>{0}</map></llsd>", ConvertUintToBytes(obj.LocalId)); | ||
368 | |||
369 | return responsedata; | ||
370 | } | ||
371 | |||
372 | private uint readuintval(OSD obj) | ||
373 | { | ||
374 | byte[] tmp = obj.AsBinary(); | ||
375 | if (BitConverter.IsLittleEndian) | ||
376 | Array.Reverse(tmp); | ||
377 | return Utils.BytesToUInt(tmp); | ||
378 | |||
379 | } | ||
380 | private string ConvertUintToBytes(uint val) | ||
381 | { | ||
382 | byte[] resultbytes = Utils.UIntToBytes(val); | ||
383 | if (BitConverter.IsLittleEndian) | ||
384 | Array.Reverse(resultbytes); | ||
385 | return String.Format("<binary encoding=\"base64\">{0}</binary>", Convert.ToBase64String(resultbytes)); | ||
386 | } | ||
387 | |||
388 | } | ||
389 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs new file mode 100644 index 0000000..769fe28 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs | |||
@@ -0,0 +1,378 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using System.IO; | ||
33 | using System.Web; | ||
34 | using Mono.Addins; | ||
35 | using log4net; | ||
36 | using Nini.Config; | ||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.StructuredData; | ||
39 | using OpenMetaverse.Messages.Linden; | ||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
43 | using OpenSim.Region.Framework.Interfaces; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | using OpenSim.Services.Interfaces; | ||
46 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
47 | using OSD = OpenMetaverse.StructuredData.OSD; | ||
48 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||
49 | using OpenSim.Framework.Capabilities; | ||
50 | using ExtraParamType = OpenMetaverse.ExtraParamType; | ||
51 | |||
52 | namespace OpenSim.Region.ClientStack.Linden | ||
53 | { | ||
54 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadObjectAssetModule")] | ||
55 | public class UploadObjectAssetModule : INonSharedRegionModule | ||
56 | { | ||
57 | private static readonly ILog m_log = | ||
58 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
59 | private Scene m_scene; | ||
60 | |||
61 | #region Region Module interfaceBase Members | ||
62 | |||
63 | |||
64 | public Type ReplaceableInterface | ||
65 | { | ||
66 | get { return null; } | ||
67 | } | ||
68 | |||
69 | public void Initialise(IConfigSource source) | ||
70 | { | ||
71 | |||
72 | } | ||
73 | |||
74 | public void AddRegion(Scene pScene) | ||
75 | { | ||
76 | m_scene = pScene; | ||
77 | } | ||
78 | |||
79 | public void RemoveRegion(Scene scene) | ||
80 | { | ||
81 | |||
82 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
83 | m_scene = null; | ||
84 | } | ||
85 | |||
86 | public void RegionLoaded(Scene scene) | ||
87 | { | ||
88 | |||
89 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
90 | } | ||
91 | |||
92 | #endregion | ||
93 | |||
94 | |||
95 | #region Region Module interface | ||
96 | |||
97 | |||
98 | |||
99 | public void Close() { } | ||
100 | |||
101 | public string Name { get { return "UploadObjectAssetModuleModule"; } } | ||
102 | |||
103 | |||
104 | public void RegisterCaps(UUID agentID, Caps caps) | ||
105 | { | ||
106 | UUID capID = UUID.Random(); | ||
107 | |||
108 | // m_log.Debug("[UPLOAD OBJECT ASSET MODULE]: /CAPS/" + capID); | ||
109 | caps.RegisterHandler( | ||
110 | "UploadObjectAsset", | ||
111 | new RestHTTPHandler( | ||
112 | "POST", | ||
113 | "/CAPS/OA/" + capID + "/", | ||
114 | httpMethod => ProcessAdd(httpMethod, agentID, caps), | ||
115 | "UploadObjectAsset", | ||
116 | agentID.ToString())); | ||
117 | |||
118 | /* | ||
119 | caps.RegisterHandler("NewFileAgentInventoryVariablePrice", | ||
120 | |||
121 | new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>("POST", | ||
122 | "/CAPS/" + capID.ToString(), | ||
123 | delegate(LLSDAssetUploadRequest req) | ||
124 | { | ||
125 | return NewAgentInventoryRequest(req,agentID); | ||
126 | })); | ||
127 | */ | ||
128 | |||
129 | } | ||
130 | |||
131 | #endregion | ||
132 | |||
133 | |||
134 | /// <summary> | ||
135 | /// Parses add request | ||
136 | /// </summary> | ||
137 | /// <param name="request"></param> | ||
138 | /// <param name="AgentId"></param> | ||
139 | /// <param name="cap"></param> | ||
140 | /// <returns></returns> | ||
141 | public Hashtable ProcessAdd(Hashtable request, UUID AgentId, Caps cap) | ||
142 | { | ||
143 | Hashtable responsedata = new Hashtable(); | ||
144 | responsedata["int_response_code"] = 400; //501; //410; //404; | ||
145 | responsedata["content_type"] = "text/plain"; | ||
146 | responsedata["keepalive"] = false; | ||
147 | responsedata["str_response_string"] = "Request wasn't what was expected"; | ||
148 | ScenePresence avatar; | ||
149 | |||
150 | if (!m_scene.TryGetScenePresence(AgentId, out avatar)) | ||
151 | return responsedata; | ||
152 | |||
153 | OSDMap r = (OSDMap)OSDParser.Deserialize((string)request["requestbody"]); | ||
154 | UploadObjectAssetMessage message = new UploadObjectAssetMessage(); | ||
155 | try | ||
156 | { | ||
157 | message.Deserialize(r); | ||
158 | |||
159 | } | ||
160 | catch (Exception ex) | ||
161 | { | ||
162 | m_log.Error("[UPLOAD OBJECT ASSET MODULE]: Error deserializing message " + ex.ToString()); | ||
163 | message = null; | ||
164 | } | ||
165 | |||
166 | if (message == null) | ||
167 | { | ||
168 | responsedata["int_response_code"] = 400; //501; //410; //404; | ||
169 | responsedata["content_type"] = "text/plain"; | ||
170 | responsedata["keepalive"] = false; | ||
171 | responsedata["str_response_string"] = | ||
172 | "<llsd><map><key>error</key><string>Error parsing Object</string></map></llsd>"; | ||
173 | |||
174 | return responsedata; | ||
175 | } | ||
176 | |||
177 | Vector3 pos = avatar.AbsolutePosition + (Vector3.UnitX * avatar.Rotation); | ||
178 | Quaternion rot = Quaternion.Identity; | ||
179 | Vector3 rootpos = Vector3.Zero; | ||
180 | // Quaternion rootrot = Quaternion.Identity; | ||
181 | |||
182 | SceneObjectGroup rootGroup = null; | ||
183 | SceneObjectGroup[] allparts = new SceneObjectGroup[message.Objects.Length]; | ||
184 | for (int i = 0; i < message.Objects.Length; i++) | ||
185 | { | ||
186 | UploadObjectAssetMessage.Object obj = message.Objects[i]; | ||
187 | PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); | ||
188 | |||
189 | if (i == 0) | ||
190 | { | ||
191 | rootpos = obj.Position; | ||
192 | // rootrot = obj.Rotation; | ||
193 | } | ||
194 | |||
195 | // Combine the extraparams data into it's ugly blob again.... | ||
196 | //int bytelength = 0; | ||
197 | //for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++) | ||
198 | //{ | ||
199 | // bytelength += obj.ExtraParams[extparams].ExtraParamData.Length; | ||
200 | //} | ||
201 | //byte[] extraparams = new byte[bytelength]; | ||
202 | //int position = 0; | ||
203 | |||
204 | |||
205 | |||
206 | //for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++) | ||
207 | //{ | ||
208 | // Buffer.BlockCopy(obj.ExtraParams[extparams].ExtraParamData, 0, extraparams, position, | ||
209 | // obj.ExtraParams[extparams].ExtraParamData.Length); | ||
210 | // | ||
211 | // position += obj.ExtraParams[extparams].ExtraParamData.Length; | ||
212 | // } | ||
213 | |||
214 | //pbs.ExtraParams = extraparams; | ||
215 | for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++) | ||
216 | { | ||
217 | UploadObjectAssetMessage.Object.ExtraParam extraParam = obj.ExtraParams[extparams]; | ||
218 | switch ((ushort)extraParam.Type) | ||
219 | { | ||
220 | case (ushort)ExtraParamType.Sculpt: | ||
221 | Primitive.SculptData sculpt = new Primitive.SculptData(extraParam.ExtraParamData, 0); | ||
222 | |||
223 | pbs.SculptEntry = true; | ||
224 | |||
225 | pbs.SculptTexture = obj.SculptID; | ||
226 | pbs.SculptType = (byte)sculpt.Type; | ||
227 | |||
228 | break; | ||
229 | case (ushort)ExtraParamType.Flexible: | ||
230 | Primitive.FlexibleData flex = new Primitive.FlexibleData(extraParam.ExtraParamData, 0); | ||
231 | pbs.FlexiEntry = true; | ||
232 | pbs.FlexiDrag = flex.Drag; | ||
233 | pbs.FlexiForceX = flex.Force.X; | ||
234 | pbs.FlexiForceY = flex.Force.Y; | ||
235 | pbs.FlexiForceZ = flex.Force.Z; | ||
236 | pbs.FlexiGravity = flex.Gravity; | ||
237 | pbs.FlexiSoftness = flex.Softness; | ||
238 | pbs.FlexiTension = flex.Tension; | ||
239 | pbs.FlexiWind = flex.Wind; | ||
240 | break; | ||
241 | case (ushort)ExtraParamType.Light: | ||
242 | Primitive.LightData light = new Primitive.LightData(extraParam.ExtraParamData, 0); | ||
243 | pbs.LightColorA = light.Color.A; | ||
244 | pbs.LightColorB = light.Color.B; | ||
245 | pbs.LightColorG = light.Color.G; | ||
246 | pbs.LightColorR = light.Color.R; | ||
247 | pbs.LightCutoff = light.Cutoff; | ||
248 | pbs.LightEntry = true; | ||
249 | pbs.LightFalloff = light.Falloff; | ||
250 | pbs.LightIntensity = light.Intensity; | ||
251 | pbs.LightRadius = light.Radius; | ||
252 | break; | ||
253 | case 0x40: | ||
254 | pbs.ReadProjectionData(extraParam.ExtraParamData, 0); | ||
255 | break; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | pbs.PathBegin = (ushort) obj.PathBegin; | ||
260 | pbs.PathCurve = (byte) obj.PathCurve; | ||
261 | pbs.PathEnd = (ushort) obj.PathEnd; | ||
262 | pbs.PathRadiusOffset = (sbyte) obj.RadiusOffset; | ||
263 | pbs.PathRevolutions = (byte) obj.Revolutions; | ||
264 | pbs.PathScaleX = (byte) obj.ScaleX; | ||
265 | pbs.PathScaleY = (byte) obj.ScaleY; | ||
266 | pbs.PathShearX = (byte) obj.ShearX; | ||
267 | pbs.PathShearY = (byte) obj.ShearY; | ||
268 | pbs.PathSkew = (sbyte) obj.Skew; | ||
269 | pbs.PathTaperX = (sbyte) obj.TaperX; | ||
270 | pbs.PathTaperY = (sbyte) obj.TaperY; | ||
271 | pbs.PathTwist = (sbyte) obj.Twist; | ||
272 | pbs.PathTwistBegin = (sbyte) obj.TwistBegin; | ||
273 | pbs.HollowShape = (HollowShape) obj.ProfileHollow; | ||
274 | pbs.PCode = (byte) PCode.Prim; | ||
275 | pbs.ProfileBegin = (ushort) obj.ProfileBegin; | ||
276 | pbs.ProfileCurve = (byte) obj.ProfileCurve; | ||
277 | pbs.ProfileEnd = (ushort) obj.ProfileEnd; | ||
278 | pbs.Scale = obj.Scale; | ||
279 | pbs.State = (byte) 0; | ||
280 | pbs.LastAttachPoint = (byte) 0; | ||
281 | SceneObjectPart prim = new SceneObjectPart(); | ||
282 | prim.UUID = UUID.Random(); | ||
283 | prim.CreatorID = AgentId; | ||
284 | prim.OwnerID = AgentId; | ||
285 | prim.GroupID = obj.GroupID; | ||
286 | prim.LastOwnerID = prim.OwnerID; | ||
287 | prim.CreationDate = Util.UnixTimeSinceEpoch(); | ||
288 | prim.Name = obj.Name; | ||
289 | prim.Description = ""; | ||
290 | |||
291 | prim.PayPrice[0] = -2; | ||
292 | prim.PayPrice[1] = -2; | ||
293 | prim.PayPrice[2] = -2; | ||
294 | prim.PayPrice[3] = -2; | ||
295 | prim.PayPrice[4] = -2; | ||
296 | Primitive.TextureEntry tmp = | ||
297 | new Primitive.TextureEntry(UUID.Parse("89556747-24cb-43ed-920b-47caed15465f")); | ||
298 | |||
299 | for (int j = 0; j < obj.Faces.Length; j++) | ||
300 | { | ||
301 | UploadObjectAssetMessage.Object.Face face = obj.Faces[j]; | ||
302 | |||
303 | Primitive.TextureEntryFace primFace = tmp.CreateFace((uint) j); | ||
304 | |||
305 | primFace.Bump = face.Bump; | ||
306 | primFace.RGBA = face.Color; | ||
307 | primFace.Fullbright = face.Fullbright; | ||
308 | primFace.Glow = face.Glow; | ||
309 | primFace.TextureID = face.ImageID; | ||
310 | primFace.Rotation = face.ImageRot; | ||
311 | primFace.MediaFlags = ((face.MediaFlags & 1) != 0); | ||
312 | |||
313 | primFace.OffsetU = face.OffsetS; | ||
314 | primFace.OffsetV = face.OffsetT; | ||
315 | primFace.RepeatU = face.ScaleS; | ||
316 | primFace.RepeatV = face.ScaleT; | ||
317 | primFace.TexMapType = (MappingType) (face.MediaFlags & 6); | ||
318 | } | ||
319 | |||
320 | pbs.TextureEntry = tmp.GetBytes(); | ||
321 | prim.Shape = pbs; | ||
322 | prim.Scale = obj.Scale; | ||
323 | |||
324 | SceneObjectGroup grp = new SceneObjectGroup(); | ||
325 | |||
326 | grp.SetRootPart(prim); | ||
327 | prim.ParentID = 0; | ||
328 | if (i == 0) | ||
329 | { | ||
330 | rootGroup = grp; | ||
331 | |||
332 | } | ||
333 | grp.AttachToScene(m_scene); | ||
334 | grp.AbsolutePosition = obj.Position; | ||
335 | prim.RotationOffset = obj.Rotation; | ||
336 | |||
337 | // Required for linking | ||
338 | grp.RootPart.ClearUpdateSchedule(); | ||
339 | |||
340 | if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos)) | ||
341 | { | ||
342 | m_scene.AddSceneObject(grp); | ||
343 | grp.AbsolutePosition = obj.Position; | ||
344 | } | ||
345 | |||
346 | allparts[i] = grp; | ||
347 | } | ||
348 | |||
349 | for (int j = 1; j < allparts.Length; j++) | ||
350 | { | ||
351 | // Required for linking | ||
352 | rootGroup.RootPart.ClearUpdateSchedule(); | ||
353 | allparts[j].RootPart.ClearUpdateSchedule(); | ||
354 | rootGroup.LinkToGroup(allparts[j]); | ||
355 | } | ||
356 | |||
357 | rootGroup.ScheduleGroupForFullUpdate(); | ||
358 | pos | ||
359 | = m_scene.GetNewRezLocation( | ||
360 | Vector3.Zero, rootpos, UUID.Zero, rot, (byte)1, 1, true, allparts[0].GroupScale, false); | ||
361 | |||
362 | responsedata["int_response_code"] = 200; //501; //410; //404; | ||
363 | responsedata["content_type"] = "text/plain"; | ||
364 | responsedata["keepalive"] = false; | ||
365 | responsedata["str_response_string"] = String.Format("<llsd><map><key>local_id</key>{0}</map></llsd>", ConvertUintToBytes(allparts[0].LocalId)); | ||
366 | |||
367 | return responsedata; | ||
368 | } | ||
369 | |||
370 | private string ConvertUintToBytes(uint val) | ||
371 | { | ||
372 | byte[] resultbytes = Utils.UIntToBytes(val); | ||
373 | if (BitConverter.IsLittleEndian) | ||
374 | Array.Reverse(resultbytes); | ||
375 | return String.Format("<binary encoding=\"base64\">{0}</binary>", Convert.ToBase64String(resultbytes)); | ||
376 | } | ||
377 | } | ||
378 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..264eaa3 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs | |||
@@ -0,0 +1,33 @@ | |||
1 | using System.Reflection; | ||
2 | using System.Runtime.CompilerServices; | ||
3 | using System.Runtime.InteropServices; | ||
4 | |||
5 | // General Information about an assembly is controlled through the following | ||
6 | // set of attributes. Change these attribute values to modify the information | ||
7 | // associated with an assembly. | ||
8 | [assembly: AssemblyTitle("OpenSim.Region.ClientStack.LindenCaps")] | ||
9 | [assembly: AssemblyDescription("")] | ||
10 | [assembly: AssemblyConfiguration("")] | ||
11 | [assembly: AssemblyCompany("http://opensimulator.org")] | ||
12 | [assembly: AssemblyProduct("OpenSim")] | ||
13 | [assembly: AssemblyCopyright("OpenSimulator developers")] | ||
14 | [assembly: AssemblyTrademark("")] | ||
15 | [assembly: AssemblyCulture("")] | ||
16 | |||
17 | // Setting ComVisible to false makes the types in this assembly not visible | ||
18 | // to COM components. If you need to access a type in this assembly from | ||
19 | // COM, set the ComVisible attribute to true on that type. | ||
20 | [assembly: ComVisible(false)] | ||
21 | |||
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM | ||
23 | [assembly: Guid("1ae76353-f37f-4fe3-b6df-d11cedf01f2c")] | ||
24 | |||
25 | // Version information for an assembly consists of the following four values: | ||
26 | // | ||
27 | // Major Version | ||
28 | // Minor Version | ||
29 | // Build Number | ||
30 | // Revision | ||
31 | // | ||
32 | [assembly: AssemblyVersion("0.8.2.*")] | ||
33 | |||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs new file mode 100644 index 0000000..a133a69 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs | |||
@@ -0,0 +1,234 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Collections.Specialized; | ||
32 | using System.Drawing; | ||
33 | using System.Drawing.Imaging; | ||
34 | using System.Reflection; | ||
35 | using System.IO; | ||
36 | using System.Web; | ||
37 | using log4net; | ||
38 | using Nini.Config; | ||
39 | using Mono.Addins; | ||
40 | using OpenMetaverse; | ||
41 | using OpenMetaverse.StructuredData; | ||
42 | using OpenMetaverse.Imaging; | ||
43 | using OpenSim.Framework; | ||
44 | using OpenSim.Framework.Console; | ||
45 | using OpenSim.Framework.Servers; | ||
46 | using OpenSim.Framework.Servers.HttpServer; | ||
47 | using OpenSim.Region.Framework.Interfaces; | ||
48 | using OpenSim.Region.Framework.Scenes; | ||
49 | using OpenSim.Services.Interfaces; | ||
50 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
51 | using OpenSim.Capabilities.Handlers; | ||
52 | |||
53 | namespace OpenSim.Region.ClientStack.Linden | ||
54 | { | ||
55 | |||
56 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RegionConsoleModule")] | ||
57 | public class RegionConsoleModule : INonSharedRegionModule, IRegionConsole | ||
58 | { | ||
59 | // private static readonly ILog m_log = | ||
60 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
61 | |||
62 | private Scene m_scene; | ||
63 | private IEventQueue m_eventQueue; | ||
64 | private Commands m_commands = new Commands(); | ||
65 | public ICommands Commands { get { return m_commands; } } | ||
66 | |||
67 | public void Initialise(IConfigSource source) | ||
68 | { | ||
69 | m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help); | ||
70 | } | ||
71 | |||
72 | public void AddRegion(Scene s) | ||
73 | { | ||
74 | m_scene = s; | ||
75 | m_scene.RegisterModuleInterface<IRegionConsole>(this); | ||
76 | } | ||
77 | |||
78 | public void RemoveRegion(Scene s) | ||
79 | { | ||
80 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
81 | m_scene = null; | ||
82 | } | ||
83 | |||
84 | public void RegionLoaded(Scene s) | ||
85 | { | ||
86 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
87 | m_eventQueue = m_scene.RequestModuleInterface<IEventQueue>(); | ||
88 | } | ||
89 | |||
90 | public void PostInitialise() | ||
91 | { | ||
92 | } | ||
93 | |||
94 | public void Close() { } | ||
95 | |||
96 | public string Name { get { return "RegionConsoleModule"; } } | ||
97 | |||
98 | public Type ReplaceableInterface | ||
99 | { | ||
100 | get { return null; } | ||
101 | } | ||
102 | |||
103 | public void RegisterCaps(UUID agentID, Caps caps) | ||
104 | { | ||
105 | if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID)) | ||
106 | return; | ||
107 | |||
108 | UUID capID = UUID.Random(); | ||
109 | |||
110 | // m_log.DebugFormat("[REGION CONSOLE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | ||
111 | caps.RegisterHandler( | ||
112 | "SimConsoleAsync", | ||
113 | new ConsoleHandler("/CAPS/" + capID + "/", "SimConsoleAsync", agentID, this, m_scene)); | ||
114 | } | ||
115 | |||
116 | public void SendConsoleOutput(UUID agentID, string message) | ||
117 | { | ||
118 | OSD osd = OSD.FromString(message); | ||
119 | |||
120 | m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID); | ||
121 | } | ||
122 | |||
123 | public bool RunCommand(string command, UUID invokerID) | ||
124 | { | ||
125 | string[] parts = Parser.Parse(command); | ||
126 | Array.Resize(ref parts, parts.Length + 1); | ||
127 | parts[parts.Length - 1] = invokerID.ToString(); | ||
128 | |||
129 | if (m_commands.Resolve(parts).Length == 0) | ||
130 | return false; | ||
131 | |||
132 | return true; | ||
133 | } | ||
134 | |||
135 | private void Help(string module, string[] cmd) | ||
136 | { | ||
137 | UUID agentID = new UUID(cmd[cmd.Length - 1]); | ||
138 | Array.Resize(ref cmd, cmd.Length - 1); | ||
139 | |||
140 | List<string> help = Commands.GetHelp(cmd); | ||
141 | |||
142 | string reply = String.Empty; | ||
143 | |||
144 | foreach (string s in help) | ||
145 | { | ||
146 | reply += s + "\n"; | ||
147 | } | ||
148 | |||
149 | SendConsoleOutput(agentID, reply); | ||
150 | } | ||
151 | |||
152 | public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn) | ||
153 | { | ||
154 | m_commands.AddCommand(module, shared, command, help, longhelp, fn); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | public class ConsoleHandler : BaseStreamHandler | ||
159 | { | ||
160 | // private static readonly ILog m_log = | ||
161 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
162 | |||
163 | private RegionConsoleModule m_consoleModule; | ||
164 | private UUID m_agentID; | ||
165 | private bool m_isGod; | ||
166 | private Scene m_scene; | ||
167 | private bool m_consoleIsOn = false; | ||
168 | |||
169 | public ConsoleHandler(string path, string name, UUID agentID, RegionConsoleModule module, Scene scene) | ||
170 | :base("POST", path, name, agentID.ToString()) | ||
171 | { | ||
172 | m_agentID = agentID; | ||
173 | m_consoleModule = module; | ||
174 | m_scene = scene; | ||
175 | |||
176 | m_isGod = m_scene.Permissions.IsGod(agentID); | ||
177 | } | ||
178 | |||
179 | protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
180 | { | ||
181 | StreamReader reader = new StreamReader(request); | ||
182 | string message = reader.ReadToEnd(); | ||
183 | |||
184 | OSD osd = OSDParser.DeserializeLLSDXml(message); | ||
185 | |||
186 | string cmd = osd.AsString(); | ||
187 | if (cmd == "set console on") | ||
188 | { | ||
189 | if (m_isGod) | ||
190 | { | ||
191 | MainConsole.Instance.OnOutput += ConsoleSender; | ||
192 | m_consoleIsOn = true; | ||
193 | m_consoleModule.SendConsoleOutput(m_agentID, "Console is now on"); | ||
194 | } | ||
195 | return new byte[0]; | ||
196 | } | ||
197 | else if (cmd == "set console off") | ||
198 | { | ||
199 | MainConsole.Instance.OnOutput -= ConsoleSender; | ||
200 | m_consoleIsOn = false; | ||
201 | m_consoleModule.SendConsoleOutput(m_agentID, "Console is now off"); | ||
202 | return new byte[0]; | ||
203 | } | ||
204 | |||
205 | if (m_consoleIsOn == false && m_consoleModule.RunCommand(osd.AsString().Trim(), m_agentID)) | ||
206 | return new byte[0]; | ||
207 | |||
208 | if (m_isGod && m_consoleIsOn) | ||
209 | { | ||
210 | MainConsole.Instance.RunCommand(osd.AsString().Trim()); | ||
211 | } | ||
212 | else | ||
213 | { | ||
214 | m_consoleModule.SendConsoleOutput(m_agentID, "Unknown command"); | ||
215 | } | ||
216 | |||
217 | return new byte[0]; | ||
218 | } | ||
219 | |||
220 | private void ConsoleSender(string text) | ||
221 | { | ||
222 | m_consoleModule.SendConsoleOutput(m_agentID, text); | ||
223 | } | ||
224 | |||
225 | private void OnMakeChildAgent(ScenePresence presence) | ||
226 | { | ||
227 | if (presence.UUID == m_agentID) | ||
228 | { | ||
229 | MainConsole.Instance.OnOutput -= ConsoleSender; | ||
230 | m_consoleIsOn = false; | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs new file mode 100644 index 0000000..e258bcb --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs | |||
@@ -0,0 +1,303 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
33 | using Nini.Config; | ||
34 | using Mono.Addins; | ||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Framework.Servers.HttpServer; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | // using OpenSim.Services.Interfaces; | ||
42 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
43 | |||
44 | namespace OpenSim.Region.ClientStack.Linden | ||
45 | { | ||
46 | /// <summary> | ||
47 | /// SimulatorFeatures capability. | ||
48 | /// </summary> | ||
49 | /// <remarks> | ||
50 | /// This is required for uploading Mesh. | ||
51 | /// Since is accepts an open-ended response, we also send more information | ||
52 | /// for viewers that care to interpret it. | ||
53 | /// | ||
54 | /// NOTE: Part of this code was adapted from the Aurora project, specifically | ||
55 | /// the normal part of the response in the capability handler. | ||
56 | /// </remarks> | ||
57 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimulatorFeaturesModule")] | ||
58 | public class SimulatorFeaturesModule : ISharedRegionModule, ISimulatorFeaturesModule | ||
59 | { | ||
60 | private static readonly ILog m_log = | ||
61 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
62 | |||
63 | public event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest; | ||
64 | |||
65 | private Scene m_scene; | ||
66 | |||
67 | /// <summary> | ||
68 | /// Simulator features | ||
69 | /// </summary> | ||
70 | private OSDMap m_features = new OSDMap(); | ||
71 | |||
72 | private string m_SearchURL = string.Empty; | ||
73 | private string m_DestinationGuideURL = string.Empty; | ||
74 | private bool m_ExportSupported = false; | ||
75 | private string m_GridName = string.Empty; | ||
76 | private string m_GridURL = string.Empty; | ||
77 | |||
78 | #region ISharedRegionModule Members | ||
79 | |||
80 | public void Initialise(IConfigSource source) | ||
81 | { | ||
82 | IConfig config = source.Configs["SimulatorFeatures"]; | ||
83 | |||
84 | if (config != null) | ||
85 | { | ||
86 | // | ||
87 | // All this is obsolete since getting these features from the grid service!! | ||
88 | // Will be removed after the next release | ||
89 | // | ||
90 | m_SearchURL = config.GetString("SearchServerURI", m_SearchURL); | ||
91 | |||
92 | m_DestinationGuideURL = config.GetString ("DestinationGuideURI", m_DestinationGuideURL); | ||
93 | |||
94 | if (m_DestinationGuideURL == string.Empty) // Make this consistent with the variable in the LoginService config | ||
95 | m_DestinationGuideURL = config.GetString("DestinationGuide", m_DestinationGuideURL); | ||
96 | |||
97 | m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported); | ||
98 | |||
99 | m_GridURL = Util.GetConfigVarFromSections<string>( | ||
100 | source, "GatekeeperURI", new string[] { "Startup", "Hypergrid", "SimulatorFeatures" }, String.Empty); | ||
101 | |||
102 | m_GridName = config.GetString("GridName", string.Empty); | ||
103 | if (m_GridName == string.Empty) | ||
104 | m_GridName = Util.GetConfigVarFromSections<string>( | ||
105 | source, "gridname", new string[] { "GridInfo", "SimulatorFeatures" }, String.Empty); | ||
106 | } | ||
107 | |||
108 | AddDefaultFeatures(); | ||
109 | } | ||
110 | |||
111 | public void AddRegion(Scene s) | ||
112 | { | ||
113 | m_scene = s; | ||
114 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
115 | |||
116 | m_scene.RegisterModuleInterface<ISimulatorFeaturesModule>(this); | ||
117 | } | ||
118 | |||
119 | public void RemoveRegion(Scene s) | ||
120 | { | ||
121 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
122 | } | ||
123 | |||
124 | public void RegionLoaded(Scene s) | ||
125 | { | ||
126 | GetGridExtraFeatures(s); | ||
127 | } | ||
128 | |||
129 | public void PostInitialise() | ||
130 | { | ||
131 | } | ||
132 | |||
133 | public void Close() { } | ||
134 | |||
135 | public string Name { get { return "SimulatorFeaturesModule"; } } | ||
136 | |||
137 | public Type ReplaceableInterface | ||
138 | { | ||
139 | get { return null; } | ||
140 | } | ||
141 | |||
142 | #endregion | ||
143 | |||
144 | /// <summary> | ||
145 | /// Add default features | ||
146 | /// </summary> | ||
147 | /// <remarks> | ||
148 | /// TODO: These should be added from other modules rather than hardcoded. | ||
149 | /// </remarks> | ||
150 | private void AddDefaultFeatures() | ||
151 | { | ||
152 | |||
153 | lock (m_features) | ||
154 | { | ||
155 | m_features["MeshRezEnabled"] = true; | ||
156 | m_features["MeshUploadEnabled"] = true; | ||
157 | m_features["MeshXferEnabled"] = true; | ||
158 | m_features["PhysicsMaterialsEnabled"] = true; | ||
159 | |||
160 | OSDMap typesMap = new OSDMap(); | ||
161 | typesMap["convex"] = true; | ||
162 | typesMap["none"] = true; | ||
163 | typesMap["prim"] = true; | ||
164 | m_features["PhysicsShapeTypes"] = typesMap; | ||
165 | |||
166 | // Extra information for viewers that want to use it | ||
167 | // TODO: Take these out of here into their respective modules, like map-server-url | ||
168 | OSDMap extrasMap; | ||
169 | if(m_features.ContainsKey("OpenSimExtras")) | ||
170 | { | ||
171 | extrasMap = (OSDMap)m_features["OpenSimExtras"]; | ||
172 | } | ||
173 | else | ||
174 | extrasMap = new OSDMap(); | ||
175 | |||
176 | if (m_SearchURL != string.Empty) | ||
177 | extrasMap["search-server-url"] = m_SearchURL; | ||
178 | if (!string.IsNullOrEmpty(m_DestinationGuideURL)) | ||
179 | extrasMap["destination-guide-url"] = m_DestinationGuideURL; | ||
180 | if (m_ExportSupported) | ||
181 | extrasMap["ExportSupported"] = true; | ||
182 | if (m_GridURL != string.Empty) | ||
183 | extrasMap["GridURL"] = m_GridURL; | ||
184 | if (m_GridName != string.Empty) | ||
185 | extrasMap["GridName"] = m_GridName; | ||
186 | |||
187 | if (extrasMap.Count > 0) | ||
188 | m_features["OpenSimExtras"] = extrasMap; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | public void RegisterCaps(UUID agentID, Caps caps) | ||
193 | { | ||
194 | IRequestHandler reqHandler | ||
195 | = new RestHTTPHandler( | ||
196 | "GET", "/CAPS/" + UUID.Random(), | ||
197 | x => { return HandleSimulatorFeaturesRequest(x, agentID); }, "SimulatorFeatures", agentID.ToString()); | ||
198 | |||
199 | caps.RegisterHandler("SimulatorFeatures", reqHandler); | ||
200 | } | ||
201 | |||
202 | public void AddFeature(string name, OSD value) | ||
203 | { | ||
204 | lock (m_features) | ||
205 | m_features[name] = value; | ||
206 | } | ||
207 | |||
208 | public bool RemoveFeature(string name) | ||
209 | { | ||
210 | lock (m_features) | ||
211 | return m_features.Remove(name); | ||
212 | } | ||
213 | |||
214 | public bool TryGetFeature(string name, out OSD value) | ||
215 | { | ||
216 | lock (m_features) | ||
217 | return m_features.TryGetValue(name, out value); | ||
218 | } | ||
219 | |||
220 | public OSDMap GetFeatures() | ||
221 | { | ||
222 | lock (m_features) | ||
223 | return new OSDMap(m_features); | ||
224 | } | ||
225 | |||
226 | private OSDMap DeepCopy() | ||
227 | { | ||
228 | // This isn't the cheapest way of doing this but the rate | ||
229 | // of occurrence is low (on sim entry only) and it's a sure | ||
230 | // way to get a true deep copy. | ||
231 | OSD copy = OSDParser.DeserializeLLSDXml(OSDParser.SerializeLLSDXmlString(m_features)); | ||
232 | |||
233 | return (OSDMap)copy; | ||
234 | } | ||
235 | |||
236 | private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod, UUID agentID) | ||
237 | { | ||
238 | // m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request"); | ||
239 | |||
240 | OSDMap copy = DeepCopy(); | ||
241 | |||
242 | // Let's add the agentID to the destination guide, if it is expecting that. | ||
243 | if (copy.ContainsKey("OpenSimExtras") && ((OSDMap)(copy["OpenSimExtras"])).ContainsKey("destination-guide-url")) | ||
244 | ((OSDMap)copy["OpenSimExtras"])["destination-guide-url"] = Replace(((OSDMap)copy["OpenSimExtras"])["destination-guide-url"], "[USERID]", agentID.ToString()); | ||
245 | |||
246 | SimulatorFeaturesRequestDelegate handlerOnSimulatorFeaturesRequest = OnSimulatorFeaturesRequest; | ||
247 | |||
248 | if (handlerOnSimulatorFeaturesRequest != null) | ||
249 | handlerOnSimulatorFeaturesRequest(agentID, ref copy); | ||
250 | |||
251 | //Send back data | ||
252 | Hashtable responsedata = new Hashtable(); | ||
253 | responsedata["int_response_code"] = 200; | ||
254 | responsedata["content_type"] = "text/plain"; | ||
255 | responsedata["keepalive"] = false; | ||
256 | |||
257 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(copy); | ||
258 | |||
259 | return responsedata; | ||
260 | } | ||
261 | |||
262 | /// <summary> | ||
263 | /// Gets the grid extra features. | ||
264 | /// </summary> | ||
265 | /// <param name='featuresURI'> | ||
266 | /// The URI Robust uses to handle the get_extra_features request | ||
267 | /// </param> | ||
268 | private void GetGridExtraFeatures(Scene scene) | ||
269 | { | ||
270 | Dictionary<string, object> extraFeatures = scene.GridService.GetExtraFeatures(); | ||
271 | if (extraFeatures.ContainsKey("Result") && extraFeatures["Result"] != null && extraFeatures["Result"].ToString() == "Failure") | ||
272 | { | ||
273 | m_log.WarnFormat("[SIMULATOR FEATURES MODULE]: Unable to retrieve grid-wide features"); | ||
274 | return; | ||
275 | } | ||
276 | |||
277 | lock (m_features) | ||
278 | { | ||
279 | OSDMap extrasMap = new OSDMap(); | ||
280 | |||
281 | foreach(string key in extraFeatures.Keys) | ||
282 | { | ||
283 | extrasMap[key] = (string)extraFeatures[key]; | ||
284 | |||
285 | if (key == "ExportSupported") | ||
286 | { | ||
287 | bool.TryParse(extraFeatures[key].ToString(), out m_ExportSupported); | ||
288 | } | ||
289 | } | ||
290 | m_features["OpenSimExtras"] = extrasMap; | ||
291 | |||
292 | } | ||
293 | } | ||
294 | |||
295 | private string Replace(string url, string substring, string replacement) | ||
296 | { | ||
297 | if (!String.IsNullOrEmpty(url) && url.Contains(substring)) | ||
298 | return url.Replace(substring, replacement); | ||
299 | |||
300 | return url; | ||
301 | } | ||
302 | } | ||
303 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs new file mode 100644 index 0000000..dd4a691 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Net; | ||
33 | using System.Text; | ||
34 | using HttpServer; | ||
35 | using log4net.Config; | ||
36 | using Nini.Config; | ||
37 | using NUnit.Framework; | ||
38 | using OpenMetaverse; | ||
39 | using OpenMetaverse.Packets; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenSim.Framework; | ||
42 | using OpenSim.Framework.Capabilities; | ||
43 | using OpenSim.Framework.Servers; | ||
44 | using OpenSim.Framework.Servers.HttpServer; | ||
45 | using OpenSim.Region.ClientStack.Linden; | ||
46 | using OpenSim.Region.CoreModules.Framework; | ||
47 | using OpenSim.Region.Framework.Scenes; | ||
48 | using OpenSim.Services.Interfaces; | ||
49 | using OpenSim.Tests.Common; | ||
50 | using OSDArray = OpenMetaverse.StructuredData.OSDArray; | ||
51 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||
52 | |||
53 | namespace OpenSim.Region.ClientStack.Linden.Caps.Tests | ||
54 | { | ||
55 | [TestFixture] | ||
56 | public class WebFetchInvDescModuleTests : OpenSimTestCase | ||
57 | { | ||
58 | [TestFixtureSetUp] | ||
59 | public void TestFixtureSetUp() | ||
60 | { | ||
61 | // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. | ||
62 | Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; | ||
63 | } | ||
64 | |||
65 | [TestFixtureTearDown] | ||
66 | public void TestFixureTearDown() | ||
67 | { | ||
68 | // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple | ||
69 | // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression | ||
70 | // tests really shouldn't). | ||
71 | Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; | ||
72 | } | ||
73 | |||
74 | [SetUp] | ||
75 | public override void SetUp() | ||
76 | { | ||
77 | base.SetUp(); | ||
78 | |||
79 | // This is an unfortunate bit of clean up we have to do because MainServer manages things through static | ||
80 | // variables and the VM is not restarted between tests. | ||
81 | uint port = 9999; | ||
82 | MainServer.RemoveHttpServer(port); | ||
83 | |||
84 | BaseHttpServer server = new BaseHttpServer(port, false, 0, ""); | ||
85 | MainServer.AddHttpServer(server); | ||
86 | MainServer.Instance = server; | ||
87 | |||
88 | server.Start(false); | ||
89 | } | ||
90 | |||
91 | [Test] | ||
92 | public void TestInventoryDescendentsFetch() | ||
93 | { | ||
94 | TestHelpers.InMethod(); | ||
95 | TestHelpers.EnableLogging(); | ||
96 | |||
97 | BaseHttpServer httpServer = MainServer.Instance; | ||
98 | Scene scene = new SceneHelpers().SetupScene(); | ||
99 | |||
100 | CapabilitiesModule capsModule = new CapabilitiesModule(); | ||
101 | WebFetchInvDescModule wfidModule = new WebFetchInvDescModule(false); | ||
102 | |||
103 | IConfigSource config = new IniConfigSource(); | ||
104 | config.AddConfig("ClientStack.LindenCaps"); | ||
105 | config.Configs["ClientStack.LindenCaps"].Set("Cap_FetchInventoryDescendents2", "localhost"); | ||
106 | |||
107 | SceneHelpers.SetupSceneModules(scene, config, capsModule, wfidModule); | ||
108 | |||
109 | UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1)); | ||
110 | |||
111 | // We need a user present to have any capabilities set up | ||
112 | SceneHelpers.AddScenePresence(scene, ua.PrincipalID); | ||
113 | |||
114 | TestHttpRequest req = new TestHttpRequest(); | ||
115 | OpenSim.Framework.Capabilities.Caps userCaps = capsModule.GetCapsForUser(ua.PrincipalID); | ||
116 | PollServiceEventArgs pseArgs; | ||
117 | userCaps.TryGetPollHandler("FetchInventoryDescendents2", out pseArgs); | ||
118 | req.UriPath = pseArgs.Url; | ||
119 | req.Uri = new Uri("file://" + req.UriPath); | ||
120 | |||
121 | // Retrieve root folder details directly so that we can request | ||
122 | InventoryFolderBase folder = scene.InventoryService.GetRootFolder(ua.PrincipalID); | ||
123 | |||
124 | OSDMap osdFolder = new OSDMap(); | ||
125 | osdFolder["folder_id"] = folder.ID; | ||
126 | osdFolder["owner_id"] = ua.PrincipalID; | ||
127 | osdFolder["fetch_folders"] = true; | ||
128 | osdFolder["fetch_items"] = true; | ||
129 | osdFolder["sort_order"] = 0; | ||
130 | |||
131 | OSDArray osdFoldersArray = new OSDArray(); | ||
132 | osdFoldersArray.Add(osdFolder); | ||
133 | |||
134 | OSDMap osdReqMap = new OSDMap(); | ||
135 | osdReqMap["folders"] = osdFoldersArray; | ||
136 | |||
137 | req.Body = new MemoryStream(OSDParser.SerializeLLSDXmlBytes(osdReqMap)); | ||
138 | |||
139 | TestHttpClientContext context = new TestHttpClientContext(false); | ||
140 | |||
141 | // WARNING: This results in a caught exception, because queryString is null | ||
142 | MainServer.Instance.OnRequest(context, new RequestEventArgs(req)); | ||
143 | |||
144 | // Drive processing of the queued inventory request synchronously. | ||
145 | wfidModule.WaitProcessQueuedInventoryRequest(); | ||
146 | MainServer.Instance.PollServiceRequestManager.WaitPerformResponse(); | ||
147 | |||
148 | // System.Threading.Thread.Sleep(10000); | ||
149 | |||
150 | OSDMap responseOsd = (OSDMap)OSDParser.DeserializeLLSDXml(context.ResponseBody); | ||
151 | OSDArray foldersOsd = (OSDArray)responseOsd["folders"]; | ||
152 | OSDMap folderOsd = (OSDMap)foldersOsd[0]; | ||
153 | |||
154 | // A sanity check that the response has the expected number of descendents for a default inventory | ||
155 | // TODO: Need a more thorough check. | ||
156 | Assert.That((int)folderOsd["descendents"], Is.EqualTo(16)); | ||
157 | } | ||
158 | } | ||
159 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs new file mode 100644 index 0000000..8cdebcd --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs | |||
@@ -0,0 +1,302 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Collections.Specialized; | ||
32 | using System.Drawing; | ||
33 | using System.Drawing.Imaging; | ||
34 | using System.Reflection; | ||
35 | using System.IO; | ||
36 | using System.Web; | ||
37 | using log4net; | ||
38 | using Nini.Config; | ||
39 | using Mono.Addins; | ||
40 | using OpenMetaverse; | ||
41 | using OpenMetaverse.StructuredData; | ||
42 | using OpenMetaverse.Imaging; | ||
43 | using OpenSim.Framework; | ||
44 | using OpenSim.Framework.Servers; | ||
45 | using OpenSim.Framework.Servers.HttpServer; | ||
46 | using OpenSim.Region.Framework.Interfaces; | ||
47 | using OpenSim.Region.Framework.Scenes; | ||
48 | using OpenSim.Services.Interfaces; | ||
49 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
50 | using OpenSim.Capabilities.Handlers; | ||
51 | |||
52 | namespace OpenSim.Region.ClientStack.Linden | ||
53 | { | ||
54 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadBakedTextureModule")] | ||
55 | public class UploadBakedTextureModule : INonSharedRegionModule | ||
56 | { | ||
57 | private static readonly ILog m_log = | ||
58 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
59 | |||
60 | /// <summary> | ||
61 | /// For historical reasons this is fixed, but there | ||
62 | /// </summary> | ||
63 | private static readonly string m_uploadBakedTexturePath = "0010/";// This is in the LandManagementModule. | ||
64 | |||
65 | private Scene m_scene; | ||
66 | private bool m_persistBakedTextures; | ||
67 | |||
68 | private IBakedTextureModule m_BakedTextureModule; | ||
69 | |||
70 | public void Initialise(IConfigSource source) | ||
71 | { | ||
72 | IConfig appearanceConfig = source.Configs["Appearance"]; | ||
73 | if (appearanceConfig != null) | ||
74 | m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); | ||
75 | |||
76 | |||
77 | } | ||
78 | |||
79 | public void AddRegion(Scene s) | ||
80 | { | ||
81 | m_scene = s; | ||
82 | |||
83 | } | ||
84 | |||
85 | public void RemoveRegion(Scene s) | ||
86 | { | ||
87 | s.EventManager.OnRegisterCaps -= RegisterCaps; | ||
88 | s.EventManager.OnNewPresence -= RegisterNewPresence; | ||
89 | s.EventManager.OnRemovePresence -= DeRegisterPresence; | ||
90 | m_BakedTextureModule = null; | ||
91 | m_scene = null; | ||
92 | } | ||
93 | |||
94 | |||
95 | |||
96 | public void RegionLoaded(Scene s) | ||
97 | { | ||
98 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
99 | m_scene.EventManager.OnNewPresence += RegisterNewPresence; | ||
100 | m_scene.EventManager.OnRemovePresence += DeRegisterPresence; | ||
101 | |||
102 | } | ||
103 | |||
104 | private void DeRegisterPresence(UUID agentId) | ||
105 | { | ||
106 | ScenePresence presence = null; | ||
107 | if (m_scene.TryGetScenePresence(agentId, out presence)) | ||
108 | { | ||
109 | presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings; | ||
110 | } | ||
111 | |||
112 | } | ||
113 | |||
114 | private void RegisterNewPresence(ScenePresence presence) | ||
115 | { | ||
116 | presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings; | ||
117 | |||
118 | } | ||
119 | |||
120 | private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems) | ||
121 | { | ||
122 | int maxCacheitemsLoop = cacheItems.Length; | ||
123 | if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES) | ||
124 | { | ||
125 | maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES; | ||
126 | m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES); | ||
127 | } | ||
128 | |||
129 | m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>(); | ||
130 | if (cacheItems.Length > 0) | ||
131 | { | ||
132 | // m_log.Debug("[Cacheitems]: " + cacheItems.Length); | ||
133 | // for (int iter = 0; iter < maxCacheitemsLoop; iter++) | ||
134 | // { | ||
135 | // m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" + | ||
136 | // cacheItems[iter].TextureID); | ||
137 | // } | ||
138 | |||
139 | ScenePresence p = null; | ||
140 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p)) | ||
141 | { | ||
142 | |||
143 | WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems; | ||
144 | if (existingitems == null) | ||
145 | { | ||
146 | if (m_BakedTextureModule != null) | ||
147 | { | ||
148 | WearableCacheItem[] savedcache = null; | ||
149 | try | ||
150 | { | ||
151 | if (p.Appearance.WearableCacheItemsDirty) | ||
152 | { | ||
153 | savedcache = m_BakedTextureModule.Get(p.UUID); | ||
154 | p.Appearance.WearableCacheItems = savedcache; | ||
155 | p.Appearance.WearableCacheItemsDirty = false; | ||
156 | } | ||
157 | |||
158 | } | ||
159 | /* | ||
160 | * The following Catch types DO NOT WORK with m_BakedTextureModule.Get | ||
161 | * it jumps to the General Packet Exception Handler if you don't catch Exception! | ||
162 | * | ||
163 | catch (System.Net.Sockets.SocketException) | ||
164 | { | ||
165 | cacheItems = null; | ||
166 | } | ||
167 | catch (WebException) | ||
168 | { | ||
169 | cacheItems = null; | ||
170 | } | ||
171 | catch (InvalidOperationException) | ||
172 | { | ||
173 | cacheItems = null; | ||
174 | } */ | ||
175 | catch (Exception) | ||
176 | { | ||
177 | // The service logs a sufficient error message. | ||
178 | } | ||
179 | |||
180 | |||
181 | if (savedcache != null) | ||
182 | existingitems = savedcache; | ||
183 | } | ||
184 | } | ||
185 | // Existing items null means it's a fully new appearance | ||
186 | if (existingitems == null) | ||
187 | { | ||
188 | |||
189 | for (int i = 0; i < maxCacheitemsLoop; i++) | ||
190 | { | ||
191 | if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) | ||
192 | { | ||
193 | Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex]; | ||
194 | if (face == null) | ||
195 | { | ||
196 | textureEntry.CreateFace(cacheItems[i].TextureIndex); | ||
197 | textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID = | ||
198 | AppearanceManager.DEFAULT_AVATAR_TEXTURE; | ||
199 | continue; | ||
200 | } | ||
201 | cacheItems[i].TextureID =face.TextureID; | ||
202 | if (m_scene.AssetService != null) | ||
203 | cacheItems[i].TextureAsset = | ||
204 | m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); | ||
205 | } | ||
206 | else | ||
207 | { | ||
208 | m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length); | ||
209 | } | ||
210 | |||
211 | |||
212 | } | ||
213 | } | ||
214 | else | ||
215 | |||
216 | |||
217 | { | ||
218 | // for each uploaded baked texture | ||
219 | for (int i = 0; i < maxCacheitemsLoop; i++) | ||
220 | { | ||
221 | if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) | ||
222 | { | ||
223 | Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex]; | ||
224 | if (face == null) | ||
225 | { | ||
226 | textureEntry.CreateFace(cacheItems[i].TextureIndex); | ||
227 | textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID = | ||
228 | AppearanceManager.DEFAULT_AVATAR_TEXTURE; | ||
229 | continue; | ||
230 | } | ||
231 | cacheItems[i].TextureID = | ||
232 | face.TextureID; | ||
233 | } | ||
234 | else | ||
235 | { | ||
236 | m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | for (int i = 0; i < maxCacheitemsLoop; i++) | ||
241 | { | ||
242 | if (cacheItems[i].TextureAsset == null) | ||
243 | { | ||
244 | cacheItems[i].TextureAsset = | ||
245 | m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | |||
250 | |||
251 | |||
252 | p.Appearance.WearableCacheItems = cacheItems; | ||
253 | |||
254 | |||
255 | |||
256 | if (m_BakedTextureModule != null) | ||
257 | { | ||
258 | m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems); | ||
259 | p.Appearance.WearableCacheItemsDirty = true; | ||
260 | |||
261 | } | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | |||
266 | public void PostInitialise() | ||
267 | { | ||
268 | } | ||
269 | |||
270 | |||
271 | |||
272 | public void Close() { } | ||
273 | |||
274 | public string Name { get { return "UploadBakedTextureModule"; } } | ||
275 | |||
276 | public Type ReplaceableInterface | ||
277 | { | ||
278 | get { return null; } | ||
279 | } | ||
280 | |||
281 | public void RegisterCaps(UUID agentID, Caps caps) | ||
282 | { | ||
283 | UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( | ||
284 | caps, m_scene.AssetService, m_persistBakedTextures); | ||
285 | |||
286 | |||
287 | |||
288 | caps.RegisterHandler( | ||
289 | "UploadBakedTexture", | ||
290 | new RestStreamHandler( | ||
291 | "POST", | ||
292 | "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, | ||
293 | avatarhandler.UploadBakedTexture, | ||
294 | "UploadBakedTexture", | ||
295 | agentID.ToString())); | ||
296 | |||
297 | |||
298 | |||
299 | |||
300 | } | ||
301 | } | ||
302 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs new file mode 100644 index 0000000..025ffea --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | |||
@@ -0,0 +1,454 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Reflection; | ||
32 | using System.Threading; | ||
33 | using log4net; | ||
34 | using Nini.Config; | ||
35 | using Mono.Addins; | ||
36 | using OpenMetaverse; | ||
37 | using OpenMetaverse.StructuredData; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Framework.Monitoring; | ||
40 | using OpenSim.Framework.Servers; | ||
41 | using OpenSim.Framework.Servers.HttpServer; | ||
42 | using OpenSim.Region.Framework.Interfaces; | ||
43 | using OpenSim.Region.Framework.Scenes; | ||
44 | using OpenSim.Framework.Capabilities; | ||
45 | using OpenSim.Services.Interfaces; | ||
46 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
47 | using OpenSim.Capabilities.Handlers; | ||
48 | |||
49 | namespace OpenSim.Region.ClientStack.Linden | ||
50 | { | ||
51 | /// <summary> | ||
52 | /// This module implements both WebFetchInventoryDescendents and FetchInventoryDescendents2 capabilities. | ||
53 | /// </summary> | ||
54 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")] | ||
55 | public class WebFetchInvDescModule : INonSharedRegionModule | ||
56 | { | ||
57 | class aPollRequest | ||
58 | { | ||
59 | public PollServiceInventoryEventArgs thepoll; | ||
60 | public UUID reqID; | ||
61 | public Hashtable request; | ||
62 | public ScenePresence presence; | ||
63 | public List<UUID> folders; | ||
64 | } | ||
65 | |||
66 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
67 | |||
68 | /// <summary> | ||
69 | /// Control whether requests will be processed asynchronously. | ||
70 | /// </summary> | ||
71 | /// <remarks> | ||
72 | /// Defaults to true. Can currently not be changed once a region has been added to the module. | ||
73 | /// </remarks> | ||
74 | public bool ProcessQueuedRequestsAsync { get; private set; } | ||
75 | |||
76 | /// <summary> | ||
77 | /// Number of inventory requests processed by this module. | ||
78 | /// </summary> | ||
79 | /// <remarks> | ||
80 | /// It's the PollServiceRequestManager that actually sends completed requests back to the requester. | ||
81 | /// </remarks> | ||
82 | public static int ProcessedRequestsCount { get; set; } | ||
83 | |||
84 | private static Stat s_queuedRequestsStat; | ||
85 | private static Stat s_processedRequestsStat; | ||
86 | |||
87 | public Scene Scene { get; private set; } | ||
88 | |||
89 | private IInventoryService m_InventoryService; | ||
90 | private ILibraryService m_LibraryService; | ||
91 | |||
92 | private bool m_Enabled; | ||
93 | |||
94 | private string m_fetchInventoryDescendents2Url; | ||
95 | private string m_webFetchInventoryDescendentsUrl; | ||
96 | |||
97 | private static FetchInvDescHandler m_webFetchHandler; | ||
98 | |||
99 | private static Thread[] m_workerThreads = null; | ||
100 | |||
101 | private static DoubleQueue<aPollRequest> m_queue = | ||
102 | new DoubleQueue<aPollRequest>(); | ||
103 | |||
104 | #region ISharedRegionModule Members | ||
105 | |||
106 | public WebFetchInvDescModule() : this(true) {} | ||
107 | |||
108 | public WebFetchInvDescModule(bool processQueuedResultsAsync) | ||
109 | { | ||
110 | ProcessQueuedRequestsAsync = processQueuedResultsAsync; | ||
111 | } | ||
112 | |||
113 | public void Initialise(IConfigSource source) | ||
114 | { | ||
115 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
116 | if (config == null) | ||
117 | return; | ||
118 | |||
119 | m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty); | ||
120 | m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); | ||
121 | |||
122 | if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) | ||
123 | { | ||
124 | m_Enabled = true; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | public void AddRegion(Scene s) | ||
129 | { | ||
130 | if (!m_Enabled) | ||
131 | return; | ||
132 | |||
133 | Scene = s; | ||
134 | } | ||
135 | |||
136 | public void RemoveRegion(Scene s) | ||
137 | { | ||
138 | if (!m_Enabled) | ||
139 | return; | ||
140 | |||
141 | Scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
142 | |||
143 | StatsManager.DeregisterStat(s_processedRequestsStat); | ||
144 | StatsManager.DeregisterStat(s_queuedRequestsStat); | ||
145 | |||
146 | if (ProcessQueuedRequestsAsync) | ||
147 | { | ||
148 | if (m_workerThreads != null) | ||
149 | { | ||
150 | foreach (Thread t in m_workerThreads) | ||
151 | Watchdog.AbortThread(t.ManagedThreadId); | ||
152 | |||
153 | m_workerThreads = null; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | Scene = null; | ||
158 | } | ||
159 | |||
160 | public void RegionLoaded(Scene s) | ||
161 | { | ||
162 | if (!m_Enabled) | ||
163 | return; | ||
164 | |||
165 | if (s_processedRequestsStat == null) | ||
166 | s_processedRequestsStat = | ||
167 | new Stat( | ||
168 | "ProcessedFetchInventoryRequests", | ||
169 | "Number of processed fetch inventory requests", | ||
170 | "These have not necessarily yet been dispatched back to the requester.", | ||
171 | "", | ||
172 | "inventory", | ||
173 | "httpfetch", | ||
174 | StatType.Pull, | ||
175 | MeasuresOfInterest.AverageChangeOverTime, | ||
176 | stat => { stat.Value = ProcessedRequestsCount; }, | ||
177 | StatVerbosity.Debug); | ||
178 | |||
179 | if (s_queuedRequestsStat == null) | ||
180 | s_queuedRequestsStat = | ||
181 | new Stat( | ||
182 | "QueuedFetchInventoryRequests", | ||
183 | "Number of fetch inventory requests queued for processing", | ||
184 | "", | ||
185 | "", | ||
186 | "inventory", | ||
187 | "httpfetch", | ||
188 | StatType.Pull, | ||
189 | MeasuresOfInterest.AverageChangeOverTime, | ||
190 | stat => { stat.Value = m_queue.Count; }, | ||
191 | StatVerbosity.Debug); | ||
192 | |||
193 | StatsManager.RegisterStat(s_processedRequestsStat); | ||
194 | StatsManager.RegisterStat(s_queuedRequestsStat); | ||
195 | |||
196 | m_InventoryService = Scene.InventoryService; | ||
197 | m_LibraryService = Scene.LibraryService; | ||
198 | |||
199 | // We'll reuse the same handler for all requests. | ||
200 | m_webFetchHandler = new FetchInvDescHandler(m_InventoryService, m_LibraryService, Scene); | ||
201 | |||
202 | Scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
203 | |||
204 | int nworkers = 2; // was 2 | ||
205 | if (ProcessQueuedRequestsAsync && m_workerThreads == null) | ||
206 | { | ||
207 | m_workerThreads = new Thread[nworkers]; | ||
208 | |||
209 | for (uint i = 0; i < nworkers; i++) | ||
210 | { | ||
211 | m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests, | ||
212 | String.Format("InventoryWorkerThread{0}", i), | ||
213 | ThreadPriority.Normal, | ||
214 | false, | ||
215 | true, | ||
216 | null, | ||
217 | int.MaxValue); | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | |||
222 | public void PostInitialise() | ||
223 | { | ||
224 | } | ||
225 | |||
226 | public void Close() { } | ||
227 | |||
228 | public string Name { get { return "WebFetchInvDescModule"; } } | ||
229 | |||
230 | public Type ReplaceableInterface | ||
231 | { | ||
232 | get { return null; } | ||
233 | } | ||
234 | |||
235 | #endregion | ||
236 | |||
237 | private class PollServiceInventoryEventArgs : PollServiceEventArgs | ||
238 | { | ||
239 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
240 | |||
241 | private Dictionary<UUID, Hashtable> responses = | ||
242 | new Dictionary<UUID, Hashtable>(); | ||
243 | |||
244 | private WebFetchInvDescModule m_module; | ||
245 | |||
246 | public PollServiceInventoryEventArgs(WebFetchInvDescModule module, string url, UUID pId) : | ||
247 | base(null, url, null, null, null, pId, int.MaxValue) | ||
248 | { | ||
249 | m_module = module; | ||
250 | |||
251 | HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); }; | ||
252 | GetEvents = (x, y) => | ||
253 | { | ||
254 | lock (responses) | ||
255 | { | ||
256 | try | ||
257 | { | ||
258 | return responses[x]; | ||
259 | } | ||
260 | finally | ||
261 | { | ||
262 | responses.Remove(x); | ||
263 | } | ||
264 | } | ||
265 | }; | ||
266 | |||
267 | Request = (x, y) => | ||
268 | { | ||
269 | ScenePresence sp = m_module.Scene.GetScenePresence(Id); | ||
270 | |||
271 | aPollRequest reqinfo = new aPollRequest(); | ||
272 | reqinfo.thepoll = this; | ||
273 | reqinfo.reqID = x; | ||
274 | reqinfo.request = y; | ||
275 | reqinfo.presence = sp; | ||
276 | reqinfo.folders = new List<UUID>(); | ||
277 | |||
278 | // Decode the request here | ||
279 | string request = y["body"].ToString(); | ||
280 | |||
281 | request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); | ||
282 | |||
283 | request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); | ||
284 | request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); | ||
285 | |||
286 | Hashtable hash = new Hashtable(); | ||
287 | try | ||
288 | { | ||
289 | hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); | ||
290 | } | ||
291 | catch (LLSD.LLSDParseException e) | ||
292 | { | ||
293 | m_log.ErrorFormat("[INVENTORY]: Fetch error: {0}{1}" + e.Message, e.StackTrace); | ||
294 | m_log.Error("Request: " + request); | ||
295 | return; | ||
296 | } | ||
297 | catch (System.Xml.XmlException) | ||
298 | { | ||
299 | m_log.ErrorFormat("[INVENTORY]: XML Format error"); | ||
300 | } | ||
301 | |||
302 | ArrayList foldersrequested = (ArrayList)hash["folders"]; | ||
303 | |||
304 | bool highPriority = false; | ||
305 | |||
306 | for (int i = 0; i < foldersrequested.Count; i++) | ||
307 | { | ||
308 | Hashtable inventoryhash = (Hashtable)foldersrequested[i]; | ||
309 | string folder = inventoryhash["folder_id"].ToString(); | ||
310 | UUID folderID; | ||
311 | if (UUID.TryParse(folder, out folderID)) | ||
312 | { | ||
313 | if (!reqinfo.folders.Contains(folderID)) | ||
314 | { | ||
315 | //TODO: Port COF handling from Avination | ||
316 | reqinfo.folders.Add(folderID); | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | |||
321 | if (highPriority) | ||
322 | m_queue.EnqueueHigh(reqinfo); | ||
323 | else | ||
324 | m_queue.EnqueueLow(reqinfo); | ||
325 | }; | ||
326 | |||
327 | NoEvents = (x, y) => | ||
328 | { | ||
329 | /* | ||
330 | lock (requests) | ||
331 | { | ||
332 | Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString()); | ||
333 | requests.Remove(request); | ||
334 | } | ||
335 | */ | ||
336 | Hashtable response = new Hashtable(); | ||
337 | |||
338 | response["int_response_code"] = 500; | ||
339 | response["str_response_string"] = "Script timeout"; | ||
340 | response["content_type"] = "text/plain"; | ||
341 | response["keepalive"] = false; | ||
342 | response["reusecontext"] = false; | ||
343 | |||
344 | return response; | ||
345 | }; | ||
346 | } | ||
347 | |||
348 | public void Process(aPollRequest requestinfo) | ||
349 | { | ||
350 | UUID requestID = requestinfo.reqID; | ||
351 | |||
352 | Hashtable response = new Hashtable(); | ||
353 | |||
354 | response["int_response_code"] = 200; | ||
355 | response["content_type"] = "text/plain"; | ||
356 | response["keepalive"] = false; | ||
357 | response["reusecontext"] = false; | ||
358 | |||
359 | response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest( | ||
360 | requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); | ||
361 | |||
362 | lock (responses) | ||
363 | { | ||
364 | if (responses.ContainsKey(requestID)) | ||
365 | m_log.WarnFormat("[FETCH INVENTORY DESCENDENTS2 MODULE]: Caught in the act of loosing responses! Please report this on mantis #7054"); | ||
366 | responses[requestID] = response; | ||
367 | } | ||
368 | |||
369 | WebFetchInvDescModule.ProcessedRequestsCount++; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | private void RegisterCaps(UUID agentID, Caps caps) | ||
374 | { | ||
375 | RegisterFetchDescendentsCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url); | ||
376 | } | ||
377 | |||
378 | private void RegisterFetchDescendentsCap(UUID agentID, Caps caps, string capName, string url) | ||
379 | { | ||
380 | string capUrl; | ||
381 | |||
382 | // disable the cap clause | ||
383 | if (url == "") | ||
384 | { | ||
385 | return; | ||
386 | } | ||
387 | // handled by the simulator | ||
388 | else if (url == "localhost") | ||
389 | { | ||
390 | capUrl = "/CAPS/" + UUID.Random() + "/"; | ||
391 | |||
392 | // Register this as a poll service | ||
393 | PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(this, capUrl, agentID); | ||
394 | args.Type = PollServiceEventArgs.EventType.Inventory; | ||
395 | |||
396 | caps.RegisterPollHandler(capName, args); | ||
397 | } | ||
398 | // external handler | ||
399 | else | ||
400 | { | ||
401 | capUrl = url; | ||
402 | IExternalCapsModule handler = Scene.RequestModuleInterface<IExternalCapsModule>(); | ||
403 | if (handler != null) | ||
404 | handler.RegisterExternalUserCapsHandler(agentID,caps,capName,capUrl); | ||
405 | else | ||
406 | caps.RegisterHandler(capName, capUrl); | ||
407 | } | ||
408 | |||
409 | // m_log.DebugFormat( | ||
410 | // "[FETCH INVENTORY DESCENDENTS2 MODULE]: Registered capability {0} at {1} in region {2} for {3}", | ||
411 | // capName, capUrl, m_scene.RegionInfo.RegionName, agentID); | ||
412 | } | ||
413 | |||
414 | // private void DeregisterCaps(UUID agentID, Caps caps) | ||
415 | // { | ||
416 | // string capUrl; | ||
417 | // | ||
418 | // if (m_capsDict.TryGetValue(agentID, out capUrl)) | ||
419 | // { | ||
420 | // MainServer.Instance.RemoveHTTPHandler("", capUrl); | ||
421 | // m_capsDict.Remove(agentID); | ||
422 | // } | ||
423 | // } | ||
424 | |||
425 | private void DoInventoryRequests() | ||
426 | { | ||
427 | while (true) | ||
428 | { | ||
429 | Watchdog.UpdateThread(); | ||
430 | |||
431 | WaitProcessQueuedInventoryRequest(); | ||
432 | } | ||
433 | } | ||
434 | |||
435 | public void WaitProcessQueuedInventoryRequest() | ||
436 | { | ||
437 | aPollRequest poolreq = m_queue.Dequeue(); | ||
438 | |||
439 | if (poolreq != null && poolreq.thepoll != null) | ||
440 | { | ||
441 | try | ||
442 | { | ||
443 | poolreq.thepoll.Process(poolreq); | ||
444 | } | ||
445 | catch (Exception e) | ||
446 | { | ||
447 | m_log.ErrorFormat( | ||
448 | "[INVENTORY]: Failed to process queued inventory request {0} for {1} in {2}. Exception {3}", | ||
449 | poolreq.reqID, poolreq.presence != null ? poolreq.presence.Name : "unknown", Scene.Name, e); | ||
450 | } | ||
451 | } | ||
452 | } | ||
453 | } | ||
454 | } | ||