aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorDiva Canto2011-05-02 14:33:34 -0700
committerDiva Canto2011-05-02 14:33:34 -0700
commit883f21dd026cbed55f2e12af491e2f9902b80d4a (patch)
tree86b9a1c11775b8834076fe2628d122f9a40ed84e /OpenSim
parentMerge branch 'master' into caps (diff)
downloadopensim-SC_OLD-883f21dd026cbed55f2e12af491e2f9902b80d4a.zip
opensim-SC_OLD-883f21dd026cbed55f2e12af491e2f9902b80d4a.tar.gz
opensim-SC_OLD-883f21dd026cbed55f2e12af491e2f9902b80d4a.tar.bz2
opensim-SC_OLD-883f21dd026cbed55f2e12af491e2f9902b80d4a.tar.xz
WebFetchInventoryDescendents working. Tested with robust.
Diffstat (limited to '')
-rw-r--r--OpenSim/Capabilities/Caps.cs4
-rw-r--r--OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs299
-rw-r--r--OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs76
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs285
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs131
5 files changed, 516 insertions, 279 deletions
diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs
index 95bb465..e188896 100644
--- a/OpenSim/Capabilities/Caps.cs
+++ b/OpenSim/Capabilities/Caps.cs
@@ -106,6 +106,10 @@ namespace OpenSim.Framework.Capabilities
106 { 106 {
107 get { return m_capsHandlers; } 107 get { return m_capsHandlers; }
108 } 108 }
109 public Dictionary<string, string> ExternalCapsHandlers
110 {
111 get { return m_externalCapsHandlers; }
112 }
109 113
110 public Caps(IHttpServer httpServer, string httpListen, uint httpPort, string capsPath, 114 public Caps(IHttpServer httpServer, string httpListen, uint httpPort, string capsPath,
111 UUID agent, string regionName) 115 UUID agent, string regionName)
diff --git a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs
new file mode 100644
index 0000000..6fd7946
--- /dev/null
+++ b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs
@@ -0,0 +1,299 @@
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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using log4net;
33using Nini.Config;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Framework;
37using OpenSim.Framework.Capabilities;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Framework.Servers.HttpServer;
40using OpenSim.Services.Interfaces;
41using Caps = OpenSim.Framework.Capabilities.Caps;
42
43namespace OpenSim.Capabilities.Handlers
44{
45
46 public class WebFetchInvDescHandler
47 {
48 private static readonly ILog m_log =
49 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 private IInventoryService m_InventoryService;
52 private ILibraryService m_LibraryService;
53 private object m_fetchLock = new Object();
54
55 public WebFetchInvDescHandler(IInventoryService invService, ILibraryService libService)
56 {
57 m_InventoryService = invService;
58 m_LibraryService = libService;
59 }
60
61 public string FetchInventoryDescendentsRequest(string request, string path, string param, OSHttpRequest httpRequest, OSHttpResponse httpResponse)
62 {
63 // nasty temporary hack here, the linden client falsely
64 // identifies the uuid 00000000-0000-0000-0000-000000000000
65 // as a string which breaks us
66 //
67 // correctly mark it as a uuid
68 //
69 request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
70
71 // another hack <integer>1</integer> results in a
72 // System.ArgumentException: Object type System.Int32 cannot
73 // be converted to target type: System.Boolean
74 //
75 request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
76 request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
77
78 Hashtable hash = new Hashtable();
79 try
80 {
81 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
82 }
83 catch (LLSD.LLSDParseException pe)
84 {
85 m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message);
86 m_log.Error("Request: " + request.ToString());
87 }
88
89 ArrayList foldersrequested = (ArrayList)hash["folders"];
90
91 string response = "";
92 lock (m_fetchLock)
93 {
94 for (int i = 0; i < foldersrequested.Count; i++)
95 {
96 string inventoryitemstr = "";
97 Hashtable inventoryhash = (Hashtable)foldersrequested[i];
98
99 LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
100
101 try
102 {
103 LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
104 }
105 catch (Exception e)
106 {
107 m_log.Debug("[CAPS]: caught exception doing OSD deserialize" + e);
108 }
109 LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest);
110
111 inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply);
112 inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
113 inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
114
115 response += inventoryitemstr;
116 }
117
118
119 if (response.Length == 0)
120 {
121 // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants.
122 // Therefore, I'm concluding that the client only has so many threads available to do requests
123 // and when a thread stalls.. is stays stalled.
124 // Therefore we need to return something valid
125 response = "<llsd><map><key>folders</key><array /></map></llsd>";
126 }
127 else
128 {
129 response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>";
130 }
131
132 //m_log.DebugFormat("[CAPS]: Replying to CAPS fetch inventory request with following xml");
133 //m_log.Debug("[CAPS] "+response);
134
135 }
136 return response;
137 }
138
139 /// <summary>
140 /// Construct an LLSD reply packet to a CAPS inventory request
141 /// </summary>
142 /// <param name="invFetch"></param>
143 /// <returns></returns>
144 private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch)
145 {
146 LLSDInventoryDescendents reply = new LLSDInventoryDescendents();
147 LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents();
148 contents.agent_id = invFetch.owner_id;
149 contents.owner_id = invFetch.owner_id;
150 contents.folder_id = invFetch.folder_id;
151
152 reply.folders.Array.Add(contents);
153 InventoryCollection inv = new InventoryCollection();
154 inv.Folders = new List<InventoryFolderBase>();
155 inv.Items = new List<InventoryItemBase>();
156 int version = 0;
157
158 inv = Fetch(invFetch.owner_id, invFetch.folder_id, invFetch.owner_id, invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version);
159
160 if (inv.Folders != null)
161 {
162 foreach (InventoryFolderBase invFolder in inv.Folders)
163 {
164 contents.categories.Array.Add(ConvertInventoryFolder(invFolder));
165 }
166 }
167
168 if (inv.Items != null)
169 {
170 foreach (InventoryItemBase invItem in inv.Items)
171 {
172 contents.items.Array.Add(ConvertInventoryItem(invItem));
173 }
174 }
175
176 contents.descendents = contents.items.Array.Count + contents.categories.Array.Count;
177 contents.version = version;
178
179 return reply;
180 }
181
182 public InventoryCollection Fetch(UUID agentID, UUID folderID, UUID ownerID,
183 bool fetchFolders, bool fetchItems, int sortOrder, out int version)
184 {
185 m_log.DebugFormat(
186 "[WEBFETCHINVENTORYDESCENDANTS]: Fetching folders ({0}), items ({1}) from {2} for agent {3}",
187 fetchFolders, fetchItems, folderID, agentID);
188
189 version = 0;
190 InventoryFolderImpl fold;
191 if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null && agentID == m_LibraryService.LibraryRootFolder.Owner)
192 if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(folderID)) != null)
193 {
194 InventoryCollection ret = new InventoryCollection();
195 ret.Folders = new List<InventoryFolderBase>();
196 ret.Items = fold.RequestListOfItems();
197
198 return ret;
199 }
200
201 InventoryCollection contents = new InventoryCollection();
202
203 if (folderID != UUID.Zero)
204 {
205 contents = m_InventoryService.GetFolderContent(agentID, folderID);
206 InventoryFolderBase containingFolder = new InventoryFolderBase();
207 containingFolder.ID = folderID;
208 containingFolder.Owner = agentID;
209 containingFolder = m_InventoryService.GetFolder(containingFolder);
210 if (containingFolder != null)
211 version = containingFolder.Version;
212 }
213 else
214 {
215 // Lost itemsm don't really need a version
216 version = 1;
217 }
218
219 return contents;
220
221 }
222 /// <summary>
223 /// Convert an internal inventory folder object into an LLSD object.
224 /// </summary>
225 /// <param name="invFolder"></param>
226 /// <returns></returns>
227 private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder)
228 {
229 LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder();
230 llsdFolder.folder_id = invFolder.ID;
231 llsdFolder.parent_id = invFolder.ParentID;
232 llsdFolder.name = invFolder.Name;
233 if (invFolder.Type < 0 || invFolder.Type >= TaskInventoryItem.Types.Length)
234 llsdFolder.type = "-1";
235 else
236 llsdFolder.type = TaskInventoryItem.Types[invFolder.Type];
237 llsdFolder.preferred_type = "-1";
238
239 return llsdFolder;
240 }
241
242 /// <summary>
243 /// Convert an internal inventory item object into an LLSD object.
244 /// </summary>
245 /// <param name="invItem"></param>
246 /// <returns></returns>
247 private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem)
248 {
249 LLSDInventoryItem llsdItem = new LLSDInventoryItem();
250 llsdItem.asset_id = invItem.AssetID;
251 llsdItem.created_at = invItem.CreationDate;
252 llsdItem.desc = invItem.Description;
253 llsdItem.flags = (int)invItem.Flags;
254 llsdItem.item_id = invItem.ID;
255 llsdItem.name = invItem.Name;
256 llsdItem.parent_id = invItem.Folder;
257 try
258 {
259 // TODO reevaluate after upgrade to libomv >= r2566. Probably should use UtilsConversions.
260 llsdItem.type = TaskInventoryItem.Types[invItem.AssetType];
261 llsdItem.inv_type = TaskInventoryItem.InvTypes[invItem.InvType];
262 }
263 catch (Exception e)
264 {
265 m_log.ErrorFormat("[CAPS]: Problem setting asset {0} inventory {1} types while converting inventory item {2}: {3}", invItem.AssetType, invItem.InvType, invItem.Name, e.Message);
266 }
267 llsdItem.permissions = new LLSDPermissions();
268 llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid;
269 llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions;
270 llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions;
271 llsdItem.permissions.group_id = invItem.GroupID;
272 llsdItem.permissions.group_mask = (int)invItem.GroupPermissions;
273 llsdItem.permissions.is_owner_group = invItem.GroupOwned;
274 llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions;
275 llsdItem.permissions.owner_id = invItem.Owner;
276 llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions;
277 llsdItem.sale_info = new LLSDSaleInfo();
278 llsdItem.sale_info.sale_price = invItem.SalePrice;
279 switch (invItem.SaleType)
280 {
281 default:
282 llsdItem.sale_info.sale_type = "not";
283 break;
284 case 1:
285 llsdItem.sale_info.sale_type = "original";
286 break;
287 case 2:
288 llsdItem.sale_info.sale_type = "copy";
289 break;
290 case 3:
291 llsdItem.sale_info.sale_type = "contents";
292 break;
293 }
294
295 return llsdItem;
296 }
297
298 }
299}
diff --git a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs
new file mode 100644
index 0000000..92eeb14
--- /dev/null
+++ b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs
@@ -0,0 +1,76 @@
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
28using System;
29using Nini.Config;
30using OpenSim.Server.Base;
31using OpenSim.Services.Interfaces;
32using OpenSim.Framework.Servers.HttpServer;
33using OpenSim.Server.Handlers.Base;
34using OpenMetaverse;
35
36namespace OpenSim.Capabilities.Handlers
37{
38 public class WebFetchInvDescServerConnector : ServiceConnector
39 {
40 private IInventoryService m_InventoryService;
41 private ILibraryService m_LibraryService;
42 private string m_ConfigName = "CapsService";
43
44 public WebFetchInvDescServerConnector(IConfigSource config, IHttpServer server, string configName) :
45 base(config, server, configName)
46 {
47 if (configName != String.Empty)
48 m_ConfigName = configName;
49
50 IConfig serverConfig = config.Configs[m_ConfigName];
51 if (serverConfig == null)
52 throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName));
53
54 string invService = serverConfig.GetString("InventoryService", String.Empty);
55
56 if (invService == String.Empty)
57 throw new Exception("No InventoryService in config file");
58
59 Object[] args = new Object[] { config };
60 m_InventoryService =
61 ServerUtils.LoadPlugin<IInventoryService>(invService, args);
62
63 if (m_InventoryService == null)
64 throw new Exception(String.Format("Failed to load InventoryService from {0}; config is {1}", invService, m_ConfigName));
65
66 string libService = serverConfig.GetString("LibraryService", String.Empty);
67 m_LibraryService =
68 ServerUtils.LoadPlugin<ILibraryService>(libService, args);
69
70 WebFetchInvDescHandler webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
71 IRequestHandler reqHandler = new RestStreamHandler("POST", "/CAPS/WebFetchInvDesc/" /*+ UUID.Random()*/, webFetchHandler.FetchInventoryDescendentsRequest);
72 server.AddStreamHandler(reqHandler);
73 }
74
75 }
76}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 7945d5e..2f1b9aa 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -81,7 +81,6 @@ namespace OpenSim.Region.ClientStack.Linden
81 private IAssetService m_assetService; 81 private IAssetService m_assetService;
82 private bool m_dumpAssetsToFile; 82 private bool m_dumpAssetsToFile;
83 private string m_regionName; 83 private string m_regionName;
84 private object m_fetchLock = new Object();
85 84
86 public BunchOfCaps(Scene scene, Caps caps) 85 public BunchOfCaps(Scene scene, Caps caps)
87 { 86 {
@@ -211,8 +210,12 @@ namespace OpenSim.Region.ClientStack.Linden
211 return string.Empty; 210 return string.Empty;
212 } 211 }
213 212
214 // WARNING: Add the external too 213 Hashtable caps = m_HostCapsObj.CapsHandlers.CapsDetails;
215 string result = LLSDHelpers.SerialiseLLSDReply(m_HostCapsObj.CapsHandlers.CapsDetails); 214 // Add the external too
215 foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers)
216 caps[kvp.Key] = kvp.Value;
217
218 string result = LLSDHelpers.SerialiseLLSDReply(caps);
216 219
217 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); 220 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result);
218 221
@@ -505,283 +508,7 @@ namespace OpenSim.Region.ClientStack.Linden
505 } 508 }
506 } 509 }
507 510
508 /// <summary>
509 /// Processes a fetch inventory request and sends the reply
510
511 /// </summary>
512 /// <param name="request"></param>
513 /// <param name="path"></param>
514 /// <param name="param"></param>
515 /// <returns></returns>
516 // Request is like:
517 //<llsd>
518 // <map><key>folders</key>
519 // <array>
520 // <map>
521 // <key>fetch-folders</key><boolean>1</boolean><key>fetch-items</key><boolean>1</boolean><key>folder-id</key><uuid>8e1e3a30-b9bf-11dc-95ff-0800200c9a66</uuid><key>owner-id</key><uuid>11111111-1111-0000-0000-000100bba000</uuid><key>sort-order</key><integer>1</integer>
522 // </map>
523 // </array>
524 // </map>
525 //</llsd>
526 //
527 // multiple fetch-folder maps are allowed within the larger folders map.
528 public string FetchInventoryRequest(string request, string path, string param)
529 {
530 // string unmodifiedRequest = request.ToString();
531
532 //m_log.DebugFormat("[AGENT INVENTORY]: Received CAPS fetch inventory request {0}", unmodifiedRequest);
533 m_log.Debug("[CAPS]: Inventory Request in region: " + m_regionName);
534
535 Hashtable hash = new Hashtable();
536 try
537 {
538 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
539 }
540 catch (LLSD.LLSDParseException pe)
541 {
542 m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message);
543 m_log.Error("Request: " + request.ToString());
544 }
545
546 ArrayList foldersrequested = (ArrayList)hash["folders"];
547
548 string response = "";
549
550 for (int i = 0; i < foldersrequested.Count; i++)
551 {
552 string inventoryitemstr = "";
553 Hashtable inventoryhash = (Hashtable)foldersrequested[i];
554
555 LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
556 LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
557 LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest);
558
559 inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply);
560 inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
561 inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
562
563 response += inventoryitemstr;
564 }
565
566 if (response.Length == 0)
567 {
568 // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants.
569 // Therefore, I'm concluding that the client only has so many threads available to do requests
570 // and when a thread stalls.. is stays stalled.
571 // Therefore we need to return something valid
572 response = "<llsd><map><key>folders</key><array /></map></llsd>";
573 }
574 else
575 {
576 response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>";
577 }
578
579 //m_log.DebugFormat("[AGENT INVENTORY]: Replying to CAPS fetch inventory request with following xml");
580 //m_log.Debug(Util.GetFormattedXml(response));
581
582 return response;
583 }
584
585 public string FetchInventoryDescendentsRequest(string request, string path, string param, OSHttpRequest httpRequest, OSHttpResponse httpResponse)
586 {
587 // nasty temporary hack here, the linden client falsely
588 // identifies the uuid 00000000-0000-0000-0000-000000000000
589 // as a string which breaks us
590 //
591 // correctly mark it as a uuid
592 //
593 request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
594
595 // another hack <integer>1</integer> results in a
596 // System.ArgumentException: Object type System.Int32 cannot
597 // be converted to target type: System.Boolean
598 //
599 request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
600 request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
601
602 Hashtable hash = new Hashtable();
603 try
604 {
605 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
606 }
607 catch (LLSD.LLSDParseException pe)
608 {
609 m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message);
610 m_log.Error("Request: " + request.ToString());
611 }
612
613 ArrayList foldersrequested = (ArrayList)hash["folders"];
614
615 string response = "";
616 lock (m_fetchLock)
617 {
618 for (int i = 0; i < foldersrequested.Count; i++)
619 {
620 string inventoryitemstr = "";
621 Hashtable inventoryhash = (Hashtable)foldersrequested[i];
622
623 LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
624
625 try
626 {
627 LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
628 }
629 catch (Exception e)
630 {
631 m_log.Debug("[CAPS]: caught exception doing OSD deserialize" + e);
632 }
633 LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest);
634
635 inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply);
636 inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
637 inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
638
639 response += inventoryitemstr;
640 }
641
642
643 if (response.Length == 0)
644 {
645 // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants.
646 // Therefore, I'm concluding that the client only has so many threads available to do requests
647 // and when a thread stalls.. is stays stalled.
648 // Therefore we need to return something valid
649 response = "<llsd><map><key>folders</key><array /></map></llsd>";
650 }
651 else
652 {
653 response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>";
654 }
655
656 //m_log.DebugFormat("[CAPS]: Replying to CAPS fetch inventory request with following xml");
657 //m_log.Debug("[CAPS] "+response);
658
659 }
660 return response;
661 }
662
663
664
665 /// <summary>
666 /// Construct an LLSD reply packet to a CAPS inventory request
667 /// </summary>
668 /// <param name="invFetch"></param>
669 /// <returns></returns>
670 private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch)
671 {
672 LLSDInventoryDescendents reply = new LLSDInventoryDescendents();
673 LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents();
674 contents.agent_id = m_HostCapsObj.AgentID;
675 contents.owner_id = invFetch.owner_id;
676 contents.folder_id = invFetch.folder_id;
677
678 reply.folders.Array.Add(contents);
679 InventoryCollection inv = new InventoryCollection();
680 inv.Folders = new List<InventoryFolderBase>();
681 inv.Items = new List<InventoryItemBase>();
682 int version = 0;
683 if (CAPSFetchInventoryDescendents != null)
684 {
685 inv = CAPSFetchInventoryDescendents(m_HostCapsObj.AgentID, invFetch.folder_id, invFetch.owner_id, invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version);
686 }
687
688 if (inv.Folders != null)
689 {
690 foreach (InventoryFolderBase invFolder in inv.Folders)
691 {
692 contents.categories.Array.Add(ConvertInventoryFolder(invFolder));
693 }
694 }
695
696 if (inv.Items != null)
697 {
698 foreach (InventoryItemBase invItem in inv.Items)
699 {
700 contents.items.Array.Add(ConvertInventoryItem(invItem));
701 }
702 }
703
704 contents.descendents = contents.items.Array.Count + contents.categories.Array.Count;
705 contents.version = version;
706
707 return reply;
708 }
709
710 /// <summary>
711 /// Convert an internal inventory folder object into an LLSD object.
712 /// </summary>
713 /// <param name="invFolder"></param>
714 /// <returns></returns>
715 private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder)
716 {
717 LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder();
718 llsdFolder.folder_id = invFolder.ID;
719 llsdFolder.parent_id = invFolder.ParentID;
720 llsdFolder.name = invFolder.Name;
721 if (invFolder.Type < 0 || invFolder.Type >= TaskInventoryItem.Types.Length)
722 llsdFolder.type = "-1";
723 else
724 llsdFolder.type = TaskInventoryItem.Types[invFolder.Type];
725 llsdFolder.preferred_type = "-1";
726
727 return llsdFolder;
728 }
729
730 /// <summary>
731 /// Convert an internal inventory item object into an LLSD object.
732 /// </summary>
733 /// <param name="invItem"></param>
734 /// <returns></returns>
735 private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem)
736 {
737 LLSDInventoryItem llsdItem = new LLSDInventoryItem();
738 llsdItem.asset_id = invItem.AssetID;
739 llsdItem.created_at = invItem.CreationDate;
740 llsdItem.desc = invItem.Description;
741 llsdItem.flags = (int)invItem.Flags;
742 llsdItem.item_id = invItem.ID;
743 llsdItem.name = invItem.Name;
744 llsdItem.parent_id = invItem.Folder;
745 try
746 {
747 // TODO reevaluate after upgrade to libomv >= r2566. Probably should use UtilsConversions.
748 llsdItem.type = TaskInventoryItem.Types[invItem.AssetType];
749 llsdItem.inv_type = TaskInventoryItem.InvTypes[invItem.InvType];
750 }
751 catch (Exception e)
752 {
753 m_log.Error("[CAPS]: Problem setting asset/inventory type while converting inventory item " + invItem.Name + " to LLSD:", e);
754 }
755 llsdItem.permissions = new LLSDPermissions();
756 llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid;
757 llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions;
758 llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions;
759 llsdItem.permissions.group_id = invItem.GroupID;
760 llsdItem.permissions.group_mask = (int)invItem.GroupPermissions;
761 llsdItem.permissions.is_owner_group = invItem.GroupOwned;
762 llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions;
763 llsdItem.permissions.owner_id = m_HostCapsObj.AgentID;
764 llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions;
765 llsdItem.sale_info = new LLSDSaleInfo();
766 llsdItem.sale_info.sale_price = invItem.SalePrice;
767 switch (invItem.SaleType)
768 {
769 default:
770 llsdItem.sale_info.sale_type = "not";
771 break;
772 case 1:
773 llsdItem.sale_info.sale_type = "original";
774 break;
775 case 2:
776 llsdItem.sale_info.sale_type = "copy";
777 break;
778 case 3:
779 llsdItem.sale_info.sale_type = "contents";
780 break;
781 }
782 511
783 return llsdItem;
784 }
785 512
786 /// <summary> 513 /// <summary>
787 /// 514 ///
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
new file mode 100644
index 0000000..55f220d
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -0,0 +1,131 @@
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
28using System;
29using System.Collections;
30using System.Reflection;
31using log4net;
32using Nini.Config;
33using Mono.Addins;
34using OpenMetaverse;
35using OpenSim.Framework;
36using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces;
40using Caps = OpenSim.Framework.Capabilities.Caps;
41using OpenSim.Capabilities.Handlers;
42
43namespace OpenSim.Region.ClientStack.Linden
44{
45
46 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
47 public class WebFetchInvDescModule : INonSharedRegionModule
48 {
49 private static readonly ILog m_log =
50 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 private Scene m_scene;
52
53 private IInventoryService m_InventoryService;
54 private ILibraryService m_LibraryService;
55 private bool m_Enabled = false;
56 private string m_URL;
57
58 #region ISharedRegionModule Members
59
60 public void Initialise(IConfigSource source)
61 {
62 IConfig config = source.Configs["ClientStack.LindenCaps"];
63 if (config == null)
64 return;
65
66 m_URL = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty);
67 // Cap doesn't exist
68 if (m_URL != string.Empty)
69 m_Enabled = true;
70 }
71
72 public void AddRegion(Scene s)
73 {
74 if (!m_Enabled)
75 return;
76
77 m_scene = s;
78 }
79
80 public void RemoveRegion(Scene s)
81 {
82 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
83 m_scene = null;
84 }
85
86 public void RegionLoaded(Scene s)
87 {
88 if (!m_Enabled)
89 return;
90
91 m_InventoryService = m_scene.InventoryService; ;
92 m_LibraryService = m_scene.LibraryService;
93 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
94 }
95
96 public void PostInitialise()
97 {
98 }
99
100 public void Close() { }
101
102 public string Name { get { return "WebFetchInvDescModule"; } }
103
104 public Type ReplaceableInterface
105 {
106 get { return null; }
107 }
108
109 #endregion
110
111 public void RegisterCaps(UUID agentID, Caps caps)
112 {
113 UUID capID = UUID.Random();
114
115 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
116 if (m_URL == "localhost")
117 {
118 m_log.InfoFormat("[WEBFETCHINVENTORYDESCENDANTS]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
119 WebFetchInvDescHandler webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
120 IRequestHandler reqHandler = new RestStreamHandler("POST", "/CAPS/" + UUID.Random(), webFetchHandler.FetchInventoryDescendentsRequest);
121 caps.RegisterHandler("WebFetchInventoryDescendents", reqHandler);
122 }
123 else
124 {
125 m_log.InfoFormat("[WEBFETCHINVENTORYDESCENDANTS]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName);
126 caps.RegisterHandler("WebFetchInventoryDescendents", m_URL);
127 }
128 }
129
130 }
131}