diff options
author | diva | 2009-06-18 00:48:39 +0000 |
---|---|---|
committer | diva | 2009-06-18 00:48:39 +0000 |
commit | 913bc3bdb380cebebd11b657966486448962ab47 (patch) | |
tree | f41837093cd692b9fe42a21c9cb1473ef81dd0f1 /OpenSim/Framework/Capabilities/Caps.cs | |
parent | Fix an uninitialized data block. Thanks, jhurliman (diff) | |
download | opensim-SC_OLD-913bc3bdb380cebebd11b657966486448962ab47.zip opensim-SC_OLD-913bc3bdb380cebebd11b657966486448962ab47.tar.gz opensim-SC_OLD-913bc3bdb380cebebd11b657966486448962ab47.tar.bz2 opensim-SC_OLD-913bc3bdb380cebebd11b657966486448962ab47.tar.xz |
Moved OpenSim/Framework/Communications/Capabilities up to OpenSim/Framework/Capabilities. Didn't change the namespace because VC# is not helping, and this would imply manually changing more than 50 files. So the namespace is still OpenSim.Framework.Communications.Capabilities, to be cleaned up later by someone with more energy.
Diffstat (limited to 'OpenSim/Framework/Capabilities/Caps.cs')
-rw-r--r-- | OpenSim/Framework/Capabilities/Caps.cs | 1212 |
1 files changed, 1212 insertions, 0 deletions
diff --git a/OpenSim/Framework/Capabilities/Caps.cs b/OpenSim/Framework/Capabilities/Caps.cs new file mode 100644 index 0000000..bd38b50 --- /dev/null +++ b/OpenSim/Framework/Capabilities/Caps.cs | |||
@@ -0,0 +1,1212 @@ | |||
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 log4net; | ||
34 | using OpenMetaverse; | ||
35 | using OpenSim.Framework.Servers; | ||
36 | using OpenSim.Framework.Servers.HttpServer; | ||
37 | using OpenSim.Services.Interfaces; | ||
38 | |||
39 | // using OpenSim.Region.Framework.Interfaces; | ||
40 | |||
41 | namespace OpenSim.Framework.Communications.Capabilities | ||
42 | { | ||
43 | public delegate void UpLoadedAsset( | ||
44 | string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, | ||
45 | byte[] data, string inventoryType, string assetType); | ||
46 | |||
47 | public delegate UUID UpdateItem(UUID itemID, byte[] data); | ||
48 | |||
49 | public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data); | ||
50 | |||
51 | public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); | ||
52 | |||
53 | public delegate void NewAsset(AssetBase asset); | ||
54 | |||
55 | public delegate UUID ItemUpdatedCallback(UUID userID, UUID itemID, byte[] data); | ||
56 | |||
57 | public delegate void TaskScriptUpdatedCallback(UUID userID, UUID itemID, UUID primID, | ||
58 | bool isScriptRunning, byte[] data); | ||
59 | |||
60 | public delegate List<InventoryItemBase> FetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID, | ||
61 | bool fetchFolders, bool fetchItems, int sortOrder); | ||
62 | |||
63 | /// <summary> | ||
64 | /// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that | ||
65 | /// we can popup a message on the user's client if the inventory service has permanently failed). But I didn't want | ||
66 | /// to just pass the whole Scene into CAPS. | ||
67 | /// </summary> | ||
68 | public delegate IClientAPI GetClientDelegate(UUID agentID); | ||
69 | |||
70 | public class Caps | ||
71 | { | ||
72 | private static readonly ILog m_log = | ||
73 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
74 | |||
75 | private string m_httpListenerHostName; | ||
76 | private uint m_httpListenPort; | ||
77 | |||
78 | /// <summary> | ||
79 | /// This is the uuid portion of every CAPS path. It is used to make capability urls private to the requester. | ||
80 | /// </summary> | ||
81 | private string m_capsObjectPath; | ||
82 | public string CapsObjectPath { get { return m_capsObjectPath; } } | ||
83 | |||
84 | private CapsHandlers m_capsHandlers; | ||
85 | |||
86 | private static readonly string m_requestPath = "0000/"; | ||
87 | // private static readonly string m_mapLayerPath = "0001/"; | ||
88 | private static readonly string m_newInventory = "0002/"; | ||
89 | //private static readonly string m_requestTexture = "0003/"; | ||
90 | private static readonly string m_notecardUpdatePath = "0004/"; | ||
91 | private static readonly string m_notecardTaskUpdatePath = "0005/"; | ||
92 | // private static readonly string m_fetchInventoryPath = "0006/"; | ||
93 | |||
94 | // The following entries are in a module, however, they are also here so that we don't re-assign | ||
95 | // the path to another cap by mistake. | ||
96 | // private static readonly string m_parcelVoiceInfoRequestPath = "0007/"; // This is in a module. | ||
97 | // private static readonly string m_provisionVoiceAccountRequestPath = "0008/";// This is in a module. | ||
98 | |||
99 | // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. | ||
100 | |||
101 | //private string eventQueue = "0100/"; | ||
102 | private IHttpServer m_httpListener; | ||
103 | private UUID m_agentID; | ||
104 | private IAssetService m_assetCache; | ||
105 | private int m_eventQueueCount = 1; | ||
106 | private Queue<string> m_capsEventQueue = new Queue<string>(); | ||
107 | private bool m_dumpAssetsToFile; | ||
108 | private string m_regionName; | ||
109 | |||
110 | public bool SSLCaps | ||
111 | { | ||
112 | get { return m_httpListener.UseSSL; } | ||
113 | } | ||
114 | public string SSLCommonName | ||
115 | { | ||
116 | get { return m_httpListener.SSLCommonName; } | ||
117 | } | ||
118 | public CapsHandlers CapsHandlers | ||
119 | { | ||
120 | get { return m_capsHandlers; } | ||
121 | } | ||
122 | |||
123 | // These are callbacks which will be setup by the scene so that we can update scene data when we | ||
124 | // receive capability calls | ||
125 | public NewInventoryItem AddNewInventoryItem = null; | ||
126 | public NewAsset AddNewAsset = null; | ||
127 | public ItemUpdatedCallback ItemUpdatedCall = null; | ||
128 | public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null; | ||
129 | public FetchInventoryDescendentsCAPS CAPSFetchInventoryDescendents = null; | ||
130 | public GetClientDelegate GetClient = null; | ||
131 | |||
132 | public Caps(IAssetService assetCache, IHttpServer httpServer, string httpListen, uint httpPort, string capsPath, | ||
133 | UUID agent, bool dumpAssetsToFile, string regionName) | ||
134 | { | ||
135 | m_assetCache = assetCache; | ||
136 | m_capsObjectPath = capsPath; | ||
137 | m_httpListener = httpServer; | ||
138 | m_httpListenerHostName = httpListen; | ||
139 | |||
140 | m_httpListenPort = httpPort; | ||
141 | |||
142 | if (httpServer.UseSSL) | ||
143 | { | ||
144 | m_httpListenPort = httpServer.SSLPort; | ||
145 | httpListen = httpServer.SSLCommonName; | ||
146 | httpPort = httpServer.SSLPort; | ||
147 | } | ||
148 | |||
149 | m_agentID = agent; | ||
150 | m_dumpAssetsToFile = dumpAssetsToFile; | ||
151 | m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort, httpServer.UseSSL); | ||
152 | m_regionName = regionName; | ||
153 | } | ||
154 | |||
155 | /// <summary> | ||
156 | /// Register all CAPS http service handlers | ||
157 | /// </summary> | ||
158 | public void RegisterHandlers() | ||
159 | { | ||
160 | DeregisterHandlers(); | ||
161 | |||
162 | string capsBase = "/CAPS/" + m_capsObjectPath; | ||
163 | |||
164 | RegisterRegionServiceHandlers(capsBase); | ||
165 | RegisterInventoryServiceHandlers(capsBase); | ||
166 | |||
167 | } | ||
168 | |||
169 | public void RegisterRegionServiceHandlers(string capsBase) | ||
170 | { | ||
171 | try | ||
172 | { | ||
173 | // the root of all evil | ||
174 | m_capsHandlers["SEED"] = new RestStreamHandler("POST", capsBase + m_requestPath, CapsRequest); | ||
175 | m_log.DebugFormat( | ||
176 | "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_agentID); | ||
177 | |||
178 | //m_capsHandlers["MapLayer"] = | ||
179 | // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", | ||
180 | // capsBase + m_mapLayerPath, | ||
181 | // GetMapLayer); | ||
182 | m_capsHandlers["UpdateScriptTaskInventory"] = | ||
183 | new RestStreamHandler("POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory); | ||
184 | m_capsHandlers["UpdateScriptTask"] = m_capsHandlers["UpdateScriptTaskInventory"]; | ||
185 | |||
186 | } | ||
187 | catch (Exception e) | ||
188 | { | ||
189 | m_log.Error("[CAPS]: " + e.ToString()); | ||
190 | } | ||
191 | } | ||
192 | |||
193 | public void RegisterInventoryServiceHandlers(string capsBase) | ||
194 | { | ||
195 | try | ||
196 | { | ||
197 | // I don't think this one works... | ||
198 | m_capsHandlers["NewFileAgentInventory"] = | ||
199 | new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>("POST", | ||
200 | capsBase + m_newInventory, | ||
201 | NewAgentInventoryRequest); | ||
202 | m_capsHandlers["UpdateNotecardAgentInventory"] = | ||
203 | new RestStreamHandler("POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory); | ||
204 | m_capsHandlers["UpdateScriptAgentInventory"] = m_capsHandlers["UpdateNotecardAgentInventory"]; | ||
205 | m_capsHandlers["UpdateScriptAgent"] = m_capsHandlers["UpdateScriptAgentInventory"]; | ||
206 | |||
207 | // As of RC 1.22.9 of the Linden client this is | ||
208 | // supported | ||
209 | |||
210 | // m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest); | ||
211 | |||
212 | // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and | ||
213 | // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires | ||
214 | // enhancements (probably filling out the folder part of the LLSD reply) to our CAPS service, | ||
215 | // but when I went on the Linden grid, the | ||
216 | // simulators I visited (version 1.21) were, surprisingly, no longer supplying this capability. Instead, | ||
217 | // the 1.19.1.4 client appeared to be happily flowing inventory data over UDP | ||
218 | // | ||
219 | // This is very probably just a temporary measure - once the CAPS service appears again on the Linden grid | ||
220 | // we will be | ||
221 | // able to get the data we need to implement the necessary part of the protocol to fix the issue above. | ||
222 | // m_capsHandlers["FetchInventoryDescendents"] = | ||
223 | // new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest); | ||
224 | |||
225 | // m_capsHandlers["FetchInventoryDescendents"] = | ||
226 | // new LLSDStreamhandler<LLSDFetchInventoryDescendents, LLSDInventoryDescendents>("POST", | ||
227 | // capsBase + m_fetchInventory, | ||
228 | // FetchInventory)); | ||
229 | // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST", | ||
230 | // capsBase + m_requestTexture, | ||
231 | // RequestTexture); | ||
232 | } | ||
233 | catch (Exception e) | ||
234 | { | ||
235 | m_log.Error("[CAPS]: " + e.ToString()); | ||
236 | } | ||
237 | } | ||
238 | |||
239 | /// <summary> | ||
240 | /// Register a handler. This allows modules to register handlers. | ||
241 | /// </summary> | ||
242 | /// <param name="capName"></param> | ||
243 | /// <param name="handler"></param> | ||
244 | public void RegisterHandler(string capName, IRequestHandler handler) | ||
245 | { | ||
246 | m_capsHandlers[capName] = handler; | ||
247 | //m_log.DebugFormat("[CAPS]: Registering handler for \"{0}\": path {1}", capName, handler.Path); | ||
248 | } | ||
249 | |||
250 | /// <summary> | ||
251 | /// Remove all CAPS service handlers. | ||
252 | /// | ||
253 | /// </summary> | ||
254 | /// <param name="httpListener"></param> | ||
255 | /// <param name="path"></param> | ||
256 | /// <param name="restMethod"></param> | ||
257 | public void DeregisterHandlers() | ||
258 | { | ||
259 | if (m_capsHandlers != null) | ||
260 | { | ||
261 | foreach (string capsName in m_capsHandlers.Caps) | ||
262 | { | ||
263 | m_capsHandlers.Remove(capsName); | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | |||
268 | /// <summary> | ||
269 | /// Construct a client response detailing all the capabilities this server can provide. | ||
270 | /// </summary> | ||
271 | /// <param name="request"></param> | ||
272 | /// <param name="path"></param> | ||
273 | /// <param name="param"></param> | ||
274 | /// <param name="httpRequest">HTTP request header object</param> | ||
275 | /// <param name="httpResponse">HTTP response header object</param> | ||
276 | /// <returns></returns> | ||
277 | public string CapsRequest(string request, string path, string param, | ||
278 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
279 | { | ||
280 | //m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName); | ||
281 | |||
282 | string result = LLSDHelpers.SerialiseLLSDReply(m_capsHandlers.CapsDetails); | ||
283 | |||
284 | //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); | ||
285 | |||
286 | return result; | ||
287 | } | ||
288 | |||
289 | // FIXME: these all should probably go into the respective region | ||
290 | // modules | ||
291 | |||
292 | /// <summary> | ||
293 | /// Processes a fetch inventory request and sends the reply | ||
294 | |||
295 | /// </summary> | ||
296 | /// <param name="request"></param> | ||
297 | /// <param name="path"></param> | ||
298 | /// <param name="param"></param> | ||
299 | /// <returns></returns> | ||
300 | // Request is like: | ||
301 | //<llsd> | ||
302 | // <map><key>folders</key> | ||
303 | // <array> | ||
304 | // <map> | ||
305 | // <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> | ||
306 | // </map> | ||
307 | // </array> | ||
308 | // </map> | ||
309 | //</llsd> | ||
310 | // | ||
311 | // multiple fetch-folder maps are allowed within the larger folders map. | ||
312 | public string FetchInventoryRequest(string request, string path, string param) | ||
313 | { | ||
314 | // string unmodifiedRequest = request.ToString(); | ||
315 | |||
316 | //m_log.DebugFormat("[AGENT INVENTORY]: Received CAPS fetch inventory request {0}", unmodifiedRequest); | ||
317 | m_log.Debug("[CAPS]: Inventory Request in region: " + m_regionName); | ||
318 | |||
319 | Hashtable hash = new Hashtable(); | ||
320 | try | ||
321 | { | ||
322 | hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); | ||
323 | } | ||
324 | catch (LLSD.LLSDParseException pe) | ||
325 | { | ||
326 | m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message); | ||
327 | m_log.Error("Request: " + request.ToString()); | ||
328 | } | ||
329 | |||
330 | ArrayList foldersrequested = (ArrayList)hash["folders"]; | ||
331 | |||
332 | string response = ""; | ||
333 | |||
334 | for (int i = 0; i < foldersrequested.Count; i++) | ||
335 | { | ||
336 | string inventoryitemstr = ""; | ||
337 | Hashtable inventoryhash = (Hashtable)foldersrequested[i]; | ||
338 | |||
339 | LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); | ||
340 | LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); | ||
341 | LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); | ||
342 | |||
343 | inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); | ||
344 | inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); | ||
345 | inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); | ||
346 | |||
347 | response += inventoryitemstr; | ||
348 | } | ||
349 | |||
350 | if (response.Length == 0) | ||
351 | { | ||
352 | // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. | ||
353 | // Therefore, I'm concluding that the client only has so many threads available to do requests | ||
354 | // and when a thread stalls.. is stays stalled. | ||
355 | // Therefore we need to return something valid | ||
356 | response = "<llsd><map><key>folders</key><array /></map></llsd>"; | ||
357 | } | ||
358 | else | ||
359 | { | ||
360 | response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; | ||
361 | } | ||
362 | |||
363 | //m_log.DebugFormat("[AGENT INVENTORY]: Replying to CAPS fetch inventory request with following xml"); | ||
364 | //m_log.Debug(Util.GetFormattedXml(response)); | ||
365 | |||
366 | return response; | ||
367 | } | ||
368 | |||
369 | public string FetchInventoryDescendentsRequest(string request, string path, string param,OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
370 | { | ||
371 | // m_log.Debug("[CAPS]: FetchInventoryDescendentsRequest in region: " + m_regionName + "request is "+request); | ||
372 | |||
373 | // nasty temporary hack here, the linden client falsely identifies the uuid 00000000-0000-0000-0000-000000000000 as a string which breaks us | ||
374 | // correctly mark it as a uuid | ||
375 | request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); | ||
376 | |||
377 | // another hack <integer>1</integer> results in a System.ArgumentException: Object type System.Int32 cannot be converted to target type: System.Boolean | ||
378 | request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); | ||
379 | request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); | ||
380 | Hashtable hash = new Hashtable(); | ||
381 | try | ||
382 | { | ||
383 | hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); | ||
384 | } | ||
385 | catch (LLSD.LLSDParseException pe) | ||
386 | { | ||
387 | m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message); | ||
388 | m_log.Error("Request: " + request.ToString()); | ||
389 | } | ||
390 | |||
391 | ArrayList foldersrequested = (ArrayList)hash["folders"]; | ||
392 | |||
393 | string response = ""; | ||
394 | for (int i = 0; i < foldersrequested.Count; i++) | ||
395 | { | ||
396 | string inventoryitemstr = ""; | ||
397 | Hashtable inventoryhash = (Hashtable)foldersrequested[i]; | ||
398 | |||
399 | LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); | ||
400 | |||
401 | try{ | ||
402 | LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); | ||
403 | } | ||
404 | catch(Exception e) | ||
405 | { | ||
406 | m_log.Debug("[CAPS]: caught exception doing OSD deserialize" + e); | ||
407 | } | ||
408 | LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); | ||
409 | |||
410 | inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); | ||
411 | inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); | ||
412 | inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); | ||
413 | |||
414 | response += inventoryitemstr; | ||
415 | } | ||
416 | |||
417 | |||
418 | if (response.Length == 0) | ||
419 | { | ||
420 | // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. | ||
421 | // Therefore, I'm concluding that the client only has so many threads available to do requests | ||
422 | // and when a thread stalls.. is stays stalled. | ||
423 | // Therefore we need to return something valid | ||
424 | response = "<llsd><map><key>folders</key><array /></map></llsd>"; | ||
425 | } | ||
426 | else | ||
427 | { | ||
428 | response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; | ||
429 | } | ||
430 | |||
431 | //m_log.DebugFormat("[CAPS]: Replying to CAPS fetch inventory request with following xml"); | ||
432 | //m_log.Debug("[CAPS] "+response); | ||
433 | |||
434 | return response; | ||
435 | } | ||
436 | |||
437 | |||
438 | |||
439 | /// <summary> | ||
440 | /// Construct an LLSD reply packet to a CAPS inventory request | ||
441 | /// </summary> | ||
442 | /// <param name="invFetch"></param> | ||
443 | /// <returns></returns> | ||
444 | private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch) | ||
445 | { | ||
446 | LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); | ||
447 | LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); | ||
448 | contents.agent_id = m_agentID; | ||
449 | contents.owner_id = invFetch.owner_id; | ||
450 | contents.folder_id = invFetch.folder_id; | ||
451 | |||
452 | // The version number being sent back was originally 1. | ||
453 | // Unfortunately, on 1.19.1.4, this means that we see a problem where on subsequent logins | ||
454 | // without clearing client cache, objects in the root folder disappear until the cache is cleared, | ||
455 | // at which point they reappear. | ||
456 | // | ||
457 | // Seeing the version to something other than 0 may be the right thing to do, but there is | ||
458 | // a greater subtlety of the second life protocol that needs to be understood first. | ||
459 | contents.version = 0; | ||
460 | |||
461 | contents.descendents = 0; | ||
462 | reply.folders.Array.Add(contents); | ||
463 | List<InventoryItemBase> itemList = null; | ||
464 | if (CAPSFetchInventoryDescendents != null) | ||
465 | { | ||
466 | itemList = CAPSFetchInventoryDescendents(m_agentID, invFetch.folder_id, invFetch.owner_id, invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order); | ||
467 | } | ||
468 | |||
469 | if (itemList != null) | ||
470 | { | ||
471 | foreach (InventoryItemBase invItem in itemList) | ||
472 | { | ||
473 | contents.items.Array.Add(ConvertInventoryItem(invItem)); | ||
474 | } | ||
475 | } | ||
476 | /* The following block is removed as it ALWAYS sends the error to the client because the RC 1.22.9 client tries to | ||
477 | find items that have become dissasociated with a paret folder and have parent of 00000000-0000-00000.... | ||
478 | else | ||
479 | { | ||
480 | IClientAPI client = GetClient(m_agentID); | ||
481 | |||
482 | // We're going to both notify the client of inventory service failure and send back a 'no folder contents' response. | ||
483 | // If we don't send back the response, | ||
484 | // the client becomes unhappy (see Teravus' comment in FetchInventoryRequest()) | ||
485 | if (client != null) | ||
486 | { | ||
487 | client.SendAgentAlertMessage( | ||
488 | "AGIN0001E: The inventory service has either failed or is not responding. Your inventory will not function properly for the rest of this session. Please clear your cache and relog.", | ||
489 | true); | ||
490 | } | ||
491 | else | ||
492 | { | ||
493 | m_log.ErrorFormat( | ||
494 | "[AGENT INVENTORY]: Could not lookup controlling client for {0} in order to notify them of the inventory service failure", | ||
495 | m_agentID); | ||
496 | } | ||
497 | }*/ | ||
498 | |||
499 | contents.descendents = contents.items.Array.Count; | ||
500 | return reply; | ||
501 | } | ||
502 | |||
503 | /// <summary> | ||
504 | /// Convert an internal inventory item object into an LLSD object. | ||
505 | /// </summary> | ||
506 | /// <param name="invItem"></param> | ||
507 | /// <returns></returns> | ||
508 | private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem) | ||
509 | { | ||
510 | LLSDInventoryItem llsdItem = new LLSDInventoryItem(); | ||
511 | llsdItem.asset_id = invItem.AssetID; | ||
512 | llsdItem.created_at = invItem.CreationDate; | ||
513 | llsdItem.desc = invItem.Description; | ||
514 | llsdItem.flags = 0; | ||
515 | llsdItem.item_id = invItem.ID; | ||
516 | llsdItem.name = invItem.Name; | ||
517 | llsdItem.parent_id = invItem.Folder; | ||
518 | try | ||
519 | { | ||
520 | // TODO reevaluate after upgrade to libomv >= r2566. Probably should use UtilsConversions. | ||
521 | llsdItem.type = TaskInventoryItem.Types[invItem.AssetType]; | ||
522 | llsdItem.inv_type = TaskInventoryItem.InvTypes[invItem.InvType]; | ||
523 | } | ||
524 | catch (Exception e) | ||
525 | { | ||
526 | m_log.Error("[CAPS]: Problem setting asset/inventory type while converting inventory item " + invItem.Name + " to LLSD:", e); | ||
527 | } | ||
528 | llsdItem.permissions = new LLSDPermissions(); | ||
529 | llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid; | ||
530 | llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions; | ||
531 | llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions; | ||
532 | llsdItem.permissions.group_id = UUID.Zero; | ||
533 | llsdItem.permissions.group_mask = 0; | ||
534 | llsdItem.permissions.is_owner_group = false; | ||
535 | llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions; | ||
536 | llsdItem.permissions.owner_id = m_agentID; // FixMe | ||
537 | llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions; | ||
538 | llsdItem.sale_info = new LLSDSaleInfo(); | ||
539 | llsdItem.sale_info.sale_price = 10; | ||
540 | llsdItem.sale_info.sale_type = "not"; | ||
541 | |||
542 | return llsdItem; | ||
543 | } | ||
544 | |||
545 | /// <summary> | ||
546 | /// | ||
547 | /// </summary> | ||
548 | /// <param name="mapReq"></param> | ||
549 | /// <returns></returns> | ||
550 | public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq) | ||
551 | { | ||
552 | m_log.Debug("[CAPS]: MapLayer Request in region: " + m_regionName); | ||
553 | LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); | ||
554 | mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); | ||
555 | return mapResponse; | ||
556 | } | ||
557 | |||
558 | /// <summary> | ||
559 | /// | ||
560 | /// </summary> | ||
561 | /// <returns></returns> | ||
562 | protected static OSDMapLayer GetOSDMapLayerResponse() | ||
563 | { | ||
564 | OSDMapLayer mapLayer = new OSDMapLayer(); | ||
565 | mapLayer.Right = 5000; | ||
566 | mapLayer.Top = 5000; | ||
567 | mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006"); | ||
568 | |||
569 | return mapLayer; | ||
570 | } | ||
571 | |||
572 | /// <summary> | ||
573 | /// | ||
574 | /// </summary> | ||
575 | /// <param name="request"></param> | ||
576 | /// <param name="path"></param> | ||
577 | /// <param name="param"></param> | ||
578 | /// <returns></returns> | ||
579 | public string RequestTexture(string request, string path, string param) | ||
580 | { | ||
581 | m_log.Debug("texture request " + request); | ||
582 | // Needs implementing (added to remove compiler warning) | ||
583 | return String.Empty; | ||
584 | } | ||
585 | |||
586 | #region EventQueue (Currently not enabled) | ||
587 | |||
588 | /// <summary> | ||
589 | /// | ||
590 | /// </summary> | ||
591 | /// <param name="request"></param> | ||
592 | /// <param name="path"></param> | ||
593 | /// <param name="param"></param> | ||
594 | /// <returns></returns> | ||
595 | public string ProcessEventQueue(string request, string path, string param) | ||
596 | { | ||
597 | string res = String.Empty; | ||
598 | |||
599 | if (m_capsEventQueue.Count > 0) | ||
600 | { | ||
601 | lock (m_capsEventQueue) | ||
602 | { | ||
603 | string item = m_capsEventQueue.Dequeue(); | ||
604 | res = item; | ||
605 | } | ||
606 | } | ||
607 | else | ||
608 | { | ||
609 | res = CreateEmptyEventResponse(); | ||
610 | } | ||
611 | return res; | ||
612 | } | ||
613 | |||
614 | /// <summary> | ||
615 | /// | ||
616 | /// </summary> | ||
617 | /// <param name="caps"></param> | ||
618 | /// <param name="ipAddressPort"></param> | ||
619 | /// <returns></returns> | ||
620 | public string CreateEstablishAgentComms(string caps, string ipAddressPort) | ||
621 | { | ||
622 | LLSDCapEvent eventItem = new LLSDCapEvent(); | ||
623 | eventItem.id = m_eventQueueCount; | ||
624 | //should be creating a EstablishAgentComms item, but there isn't a class for it yet | ||
625 | eventItem.events.Array.Add(new LLSDEmpty()); | ||
626 | string res = LLSDHelpers.SerialiseLLSDReply(eventItem); | ||
627 | m_eventQueueCount++; | ||
628 | |||
629 | m_capsEventQueue.Enqueue(res); | ||
630 | return res; | ||
631 | } | ||
632 | |||
633 | /// <summary> | ||
634 | /// | ||
635 | /// </summary> | ||
636 | /// <returns></returns> | ||
637 | public string CreateEmptyEventResponse() | ||
638 | { | ||
639 | LLSDCapEvent eventItem = new LLSDCapEvent(); | ||
640 | eventItem.id = m_eventQueueCount; | ||
641 | eventItem.events.Array.Add(new LLSDEmpty()); | ||
642 | string res = LLSDHelpers.SerialiseLLSDReply(eventItem); | ||
643 | m_eventQueueCount++; | ||
644 | return res; | ||
645 | } | ||
646 | |||
647 | #endregion | ||
648 | |||
649 | /// <summary> | ||
650 | /// Called by the script task update handler. Provides a URL to which the client can upload a new asset. | ||
651 | /// </summary> | ||
652 | /// <param name="request"></param> | ||
653 | /// <param name="path"></param> | ||
654 | /// <param name="param"></param> | ||
655 | /// <param name="httpRequest">HTTP request header object</param> | ||
656 | /// <param name="httpResponse">HTTP response header object</param> | ||
657 | /// <returns></returns> | ||
658 | public string ScriptTaskInventory(string request, string path, string param, | ||
659 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
660 | { | ||
661 | try | ||
662 | { | ||
663 | m_log.Debug("[CAPS]: ScriptTaskInventory Request in region: " + m_regionName); | ||
664 | //m_log.DebugFormat("[CAPS]: request: {0}, path: {1}, param: {2}", request, path, param); | ||
665 | |||
666 | Hashtable hash = (Hashtable) LLSD.LLSDDeserialize(Utils.StringToBytes(request)); | ||
667 | LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate(); | ||
668 | LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest); | ||
669 | |||
670 | string capsBase = "/CAPS/" + m_capsObjectPath; | ||
671 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | ||
672 | |||
673 | TaskInventoryScriptUpdater uploader = | ||
674 | new TaskInventoryScriptUpdater( | ||
675 | llsdUpdateRequest.item_id, | ||
676 | llsdUpdateRequest.task_id, | ||
677 | llsdUpdateRequest.is_script_running, | ||
678 | capsBase + uploaderPath, | ||
679 | m_httpListener, | ||
680 | m_dumpAssetsToFile); | ||
681 | uploader.OnUpLoad += TaskScriptUpdated; | ||
682 | |||
683 | m_httpListener.AddStreamHandler( | ||
684 | new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); | ||
685 | |||
686 | string protocol = "http://"; | ||
687 | |||
688 | if (m_httpListener.UseSSL) | ||
689 | protocol = "https://"; | ||
690 | |||
691 | string uploaderURL = protocol + m_httpListenerHostName + ":" + m_httpListenPort.ToString() + capsBase + | ||
692 | uploaderPath; | ||
693 | |||
694 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); | ||
695 | uploadResponse.uploader = uploaderURL; | ||
696 | uploadResponse.state = "upload"; | ||
697 | |||
698 | // m_log.InfoFormat("[CAPS]: " + | ||
699 | // "ScriptTaskInventory response: {0}", | ||
700 | // LLSDHelpers.SerialiseLLSDReply(uploadResponse))); | ||
701 | |||
702 | return LLSDHelpers.SerialiseLLSDReply(uploadResponse); | ||
703 | } | ||
704 | catch (Exception e) | ||
705 | { | ||
706 | m_log.Error("[CAPS]: " + e.ToString()); | ||
707 | } | ||
708 | |||
709 | return null; | ||
710 | } | ||
711 | |||
712 | /// <summary> | ||
713 | /// Called by the notecard update handler. Provides a URL to which the client can upload a new asset. | ||
714 | /// </summary> | ||
715 | /// <param name="request"></param> | ||
716 | /// <param name="path"></param> | ||
717 | /// <param name="param"></param> | ||
718 | /// <returns></returns> | ||
719 | public string NoteCardAgentInventory(string request, string path, string param, | ||
720 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
721 | { | ||
722 | //m_log.Debug("[CAPS]: NoteCardAgentInventory Request in region: " + m_regionName + "\n" + request); | ||
723 | //m_log.Debug("[CAPS]: NoteCardAgentInventory Request is: " + request); | ||
724 | |||
725 | //OpenMetaverse.StructuredData.OSDMap hash = (OpenMetaverse.StructuredData.OSDMap)OpenMetaverse.StructuredData.LLSDParser.DeserializeBinary(Utils.StringToBytes(request)); | ||
726 | Hashtable hash = (Hashtable) LLSD.LLSDDeserialize(Utils.StringToBytes(request)); | ||
727 | LLSDItemUpdate llsdRequest = new LLSDItemUpdate(); | ||
728 | LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest); | ||
729 | |||
730 | string capsBase = "/CAPS/" + m_capsObjectPath; | ||
731 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | ||
732 | |||
733 | ItemUpdater uploader = | ||
734 | new ItemUpdater(llsdRequest.item_id, capsBase + uploaderPath, m_httpListener, m_dumpAssetsToFile); | ||
735 | uploader.OnUpLoad += ItemUpdated; | ||
736 | |||
737 | m_httpListener.AddStreamHandler( | ||
738 | new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); | ||
739 | |||
740 | string protocol = "http://"; | ||
741 | |||
742 | if (m_httpListener.UseSSL) | ||
743 | protocol = "https://"; | ||
744 | |||
745 | string uploaderURL = protocol + m_httpListenerHostName + ":" + m_httpListenPort.ToString() + capsBase + | ||
746 | uploaderPath; | ||
747 | |||
748 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); | ||
749 | uploadResponse.uploader = uploaderURL; | ||
750 | uploadResponse.state = "upload"; | ||
751 | |||
752 | // m_log.InfoFormat("[CAPS]: " + | ||
753 | // "NoteCardAgentInventory response: {0}", | ||
754 | // LLSDHelpers.SerialiseLLSDReply(uploadResponse))); | ||
755 | |||
756 | return LLSDHelpers.SerialiseLLSDReply(uploadResponse); | ||
757 | } | ||
758 | |||
759 | /// <summary> | ||
760 | /// | ||
761 | /// </summary> | ||
762 | /// <param name="llsdRequest"></param> | ||
763 | /// <returns></returns> | ||
764 | public LLSDAssetUploadResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest) | ||
765 | { | ||
766 | //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); | ||
767 | //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); | ||
768 | |||
769 | if (llsdRequest.asset_type == "texture" || | ||
770 | llsdRequest.asset_type == "animation" || | ||
771 | llsdRequest.asset_type == "sound") | ||
772 | { | ||
773 | IClientAPI client = null; | ||
774 | IScene scene = null; | ||
775 | if (GetClient != null) | ||
776 | { | ||
777 | client = GetClient(m_agentID); | ||
778 | scene = client.Scene; | ||
779 | |||
780 | IMoneyModule mm = scene.RequestModuleInterface<IMoneyModule>(); | ||
781 | |||
782 | if (mm != null) | ||
783 | { | ||
784 | if (!mm.UploadCovered(client)) | ||
785 | { | ||
786 | if (client != null) | ||
787 | client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); | ||
788 | |||
789 | LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); | ||
790 | errorResponse.uploader = ""; | ||
791 | errorResponse.state = "error"; | ||
792 | return errorResponse; | ||
793 | } | ||
794 | } | ||
795 | } | ||
796 | } | ||
797 | |||
798 | |||
799 | string assetName = llsdRequest.name; | ||
800 | string assetDes = llsdRequest.description; | ||
801 | string capsBase = "/CAPS/" + m_capsObjectPath; | ||
802 | UUID newAsset = UUID.Random(); | ||
803 | UUID newInvItem = UUID.Random(); | ||
804 | UUID parentFolder = llsdRequest.folder_id; | ||
805 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | ||
806 | |||
807 | AssetUploader uploader = | ||
808 | new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, | ||
809 | llsdRequest.asset_type, capsBase + uploaderPath, m_httpListener, m_dumpAssetsToFile); | ||
810 | m_httpListener.AddStreamHandler( | ||
811 | new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); | ||
812 | |||
813 | string protocol = "http://"; | ||
814 | |||
815 | if (m_httpListener.UseSSL) | ||
816 | protocol = "https://"; | ||
817 | |||
818 | string uploaderURL = protocol + m_httpListenerHostName + ":" + m_httpListenPort.ToString() + capsBase + | ||
819 | uploaderPath; | ||
820 | |||
821 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); | ||
822 | uploadResponse.uploader = uploaderURL; | ||
823 | uploadResponse.state = "upload"; | ||
824 | uploader.OnUpLoad += UploadCompleteHandler; | ||
825 | return uploadResponse; | ||
826 | } | ||
827 | |||
828 | /// <summary> | ||
829 | /// | ||
830 | /// </summary> | ||
831 | /// <param name="assetID"></param> | ||
832 | /// <param name="inventoryItem"></param> | ||
833 | /// <param name="data"></param> | ||
834 | public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, | ||
835 | UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, | ||
836 | string assetType) | ||
837 | { | ||
838 | sbyte assType = 0; | ||
839 | sbyte inType = 0; | ||
840 | |||
841 | if (inventoryType == "sound") | ||
842 | { | ||
843 | inType = 1; | ||
844 | assType = 1; | ||
845 | } | ||
846 | else if (inventoryType == "animation") | ||
847 | { | ||
848 | inType = 19; | ||
849 | assType = 20; | ||
850 | } | ||
851 | else if (inventoryType == "wearable") | ||
852 | { | ||
853 | inType = 18; | ||
854 | switch (assetType) | ||
855 | { | ||
856 | case "bodypart": | ||
857 | assType = 13; | ||
858 | break; | ||
859 | case "clothing": | ||
860 | assType = 5; | ||
861 | break; | ||
862 | } | ||
863 | } | ||
864 | |||
865 | AssetBase asset; | ||
866 | asset = new AssetBase(); | ||
867 | asset.FullID = assetID; | ||
868 | asset.Type = assType; | ||
869 | asset.Name = assetName; | ||
870 | asset.Data = data; | ||
871 | if (AddNewAsset != null) | ||
872 | AddNewAsset(asset); | ||
873 | else if (m_assetCache != null) | ||
874 | m_assetCache.Store(asset); | ||
875 | |||
876 | InventoryItemBase item = new InventoryItemBase(); | ||
877 | item.Owner = m_agentID; | ||
878 | item.CreatorId = m_agentID.ToString(); | ||
879 | item.ID = inventoryItem; | ||
880 | item.AssetID = asset.FullID; | ||
881 | item.Description = assetDescription; | ||
882 | item.Name = assetName; | ||
883 | item.AssetType = assType; | ||
884 | item.InvType = inType; | ||
885 | item.Folder = parentFolder; | ||
886 | item.CurrentPermissions = 2147483647; | ||
887 | item.BasePermissions = 2147483647; | ||
888 | item.EveryOnePermissions = 0; | ||
889 | item.NextPermissions = 2147483647; | ||
890 | item.CreationDate = Util.UnixTimeSinceEpoch(); | ||
891 | |||
892 | if (AddNewInventoryItem != null) | ||
893 | { | ||
894 | AddNewInventoryItem(m_agentID, item); | ||
895 | } | ||
896 | } | ||
897 | |||
898 | /// <summary> | ||
899 | /// Called when new asset data for an agent inventory item update has been uploaded. | ||
900 | /// </summary> | ||
901 | /// <param name="itemID">Item to update</param> | ||
902 | /// <param name="data">New asset data</param> | ||
903 | /// <returns></returns> | ||
904 | public UUID ItemUpdated(UUID itemID, byte[] data) | ||
905 | { | ||
906 | if (ItemUpdatedCall != null) | ||
907 | { | ||
908 | return ItemUpdatedCall(m_agentID, itemID, data); | ||
909 | } | ||
910 | |||
911 | return UUID.Zero; | ||
912 | } | ||
913 | |||
914 | /// <summary> | ||
915 | /// Called when new asset data for an agent inventory item update has been uploaded. | ||
916 | /// </summary> | ||
917 | /// <param name="itemID">Item to update</param> | ||
918 | /// <param name="primID">Prim containing item to update</param> | ||
919 | /// <param name="isScriptRunning">Signals whether the script to update is currently running</param> | ||
920 | /// <param name="data">New asset data</param> | ||
921 | public void TaskScriptUpdated(UUID itemID, UUID primID, bool isScriptRunning, byte[] data) | ||
922 | { | ||
923 | if (TaskScriptUpdatedCall != null) | ||
924 | { | ||
925 | TaskScriptUpdatedCall(m_agentID, itemID, primID, isScriptRunning, data); | ||
926 | } | ||
927 | } | ||
928 | |||
929 | public class AssetUploader | ||
930 | { | ||
931 | public event UpLoadedAsset OnUpLoad; | ||
932 | private UpLoadedAsset handlerUpLoad = null; | ||
933 | |||
934 | private string uploaderPath = String.Empty; | ||
935 | private UUID newAssetID; | ||
936 | private UUID inventoryItemID; | ||
937 | private UUID parentFolder; | ||
938 | private IHttpServer httpListener; | ||
939 | private bool m_dumpAssetsToFile; | ||
940 | private string m_assetName = String.Empty; | ||
941 | private string m_assetDes = String.Empty; | ||
942 | |||
943 | private string m_invType = String.Empty; | ||
944 | private string m_assetType = String.Empty; | ||
945 | |||
946 | public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, | ||
947 | UUID parentFolderID, string invType, string assetType, string path, | ||
948 | IHttpServer httpServer, bool dumpAssetsToFile) | ||
949 | { | ||
950 | m_assetName = assetName; | ||
951 | m_assetDes = description; | ||
952 | newAssetID = assetID; | ||
953 | inventoryItemID = inventoryItem; | ||
954 | uploaderPath = path; | ||
955 | httpListener = httpServer; | ||
956 | parentFolder = parentFolderID; | ||
957 | m_assetType = assetType; | ||
958 | m_invType = invType; | ||
959 | m_dumpAssetsToFile = dumpAssetsToFile; | ||
960 | } | ||
961 | |||
962 | /// <summary> | ||
963 | /// | ||
964 | /// </summary> | ||
965 | /// <param name="data"></param> | ||
966 | /// <param name="path"></param> | ||
967 | /// <param name="param"></param> | ||
968 | /// <returns></returns> | ||
969 | public string uploaderCaps(byte[] data, string path, string param) | ||
970 | { | ||
971 | UUID inv = inventoryItemID; | ||
972 | string res = String.Empty; | ||
973 | LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); | ||
974 | uploadComplete.new_asset = newAssetID.ToString(); | ||
975 | uploadComplete.new_inventory_item = inv; | ||
976 | uploadComplete.state = "complete"; | ||
977 | |||
978 | res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); | ||
979 | |||
980 | httpListener.RemoveStreamHandler("POST", uploaderPath); | ||
981 | |||
982 | // TODO: probably make this a better set of extensions here | ||
983 | string extension = ".jp2"; | ||
984 | if (m_invType != "image") | ||
985 | { | ||
986 | extension = ".dat"; | ||
987 | } | ||
988 | |||
989 | if (m_dumpAssetsToFile) | ||
990 | { | ||
991 | SaveAssetToFile(m_assetName + extension, data); | ||
992 | } | ||
993 | handlerUpLoad = OnUpLoad; | ||
994 | if (handlerUpLoad != null) | ||
995 | { | ||
996 | handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); | ||
997 | } | ||
998 | |||
999 | return res; | ||
1000 | } | ||
1001 | ///Left this in and commented in case there are unforseen issues | ||
1002 | //private void SaveAssetToFile(string filename, byte[] data) | ||
1003 | //{ | ||
1004 | // FileStream fs = File.Create(filename); | ||
1005 | // BinaryWriter bw = new BinaryWriter(fs); | ||
1006 | // bw.Write(data); | ||
1007 | // bw.Close(); | ||
1008 | // fs.Close(); | ||
1009 | //} | ||
1010 | private static void SaveAssetToFile(string filename, byte[] data) | ||
1011 | { | ||
1012 | string assetPath = "UserAssets"; | ||
1013 | if (!Directory.Exists(assetPath)) | ||
1014 | { | ||
1015 | Directory.CreateDirectory(assetPath); | ||
1016 | } | ||
1017 | FileStream fs = File.Create(Path.Combine(assetPath, Util.safeFileName(filename))); | ||
1018 | BinaryWriter bw = new BinaryWriter(fs); | ||
1019 | bw.Write(data); | ||
1020 | bw.Close(); | ||
1021 | fs.Close(); | ||
1022 | } | ||
1023 | } | ||
1024 | |||
1025 | /// <summary> | ||
1026 | /// This class is a callback invoked when a client sends asset data to | ||
1027 | /// an agent inventory notecard update url | ||
1028 | /// </summary> | ||
1029 | public class ItemUpdater | ||
1030 | { | ||
1031 | public event UpdateItem OnUpLoad; | ||
1032 | |||
1033 | private UpdateItem handlerUpdateItem = null; | ||
1034 | |||
1035 | private string uploaderPath = String.Empty; | ||
1036 | private UUID inventoryItemID; | ||
1037 | private IHttpServer httpListener; | ||
1038 | private bool m_dumpAssetToFile; | ||
1039 | |||
1040 | public ItemUpdater(UUID inventoryItem, string path, IHttpServer httpServer, bool dumpAssetToFile) | ||
1041 | { | ||
1042 | m_dumpAssetToFile = dumpAssetToFile; | ||
1043 | |||
1044 | inventoryItemID = inventoryItem; | ||
1045 | uploaderPath = path; | ||
1046 | httpListener = httpServer; | ||
1047 | } | ||
1048 | |||
1049 | /// <summary> | ||
1050 | /// | ||
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 | UUID assetID = UUID.Zero; | ||
1062 | handlerUpdateItem = OnUpLoad; | ||
1063 | if (handlerUpdateItem != null) | ||
1064 | { | ||
1065 | assetID = handlerUpdateItem(inv, data); | ||
1066 | } | ||
1067 | |||
1068 | uploadComplete.new_asset = assetID.ToString(); | ||
1069 | uploadComplete.new_inventory_item = inv; | ||
1070 | uploadComplete.state = "complete"; | ||
1071 | |||
1072 | res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); | ||
1073 | |||
1074 | httpListener.RemoveStreamHandler("POST", uploaderPath); | ||
1075 | |||
1076 | if (m_dumpAssetToFile) | ||
1077 | { | ||
1078 | SaveAssetToFile("updateditem" + Util.RandomClass.Next(1, 1000) + ".dat", data); | ||
1079 | } | ||
1080 | |||
1081 | return res; | ||
1082 | } | ||
1083 | ///Left this in and commented in case there are unforseen issues | ||
1084 | //private void SaveAssetToFile(string filename, byte[] data) | ||
1085 | //{ | ||
1086 | // FileStream fs = File.Create(filename); | ||
1087 | // BinaryWriter bw = new BinaryWriter(fs); | ||
1088 | // bw.Write(data); | ||
1089 | // bw.Close(); | ||
1090 | // fs.Close(); | ||
1091 | //} | ||
1092 | private static void SaveAssetToFile(string filename, byte[] data) | ||
1093 | { | ||
1094 | string assetPath = "UserAssets"; | ||
1095 | if (!Directory.Exists(assetPath)) | ||
1096 | { | ||
1097 | Directory.CreateDirectory(assetPath); | ||
1098 | } | ||
1099 | FileStream fs = File.Create(Path.Combine(assetPath, filename)); | ||
1100 | BinaryWriter bw = new BinaryWriter(fs); | ||
1101 | bw.Write(data); | ||
1102 | bw.Close(); | ||
1103 | fs.Close(); | ||
1104 | } | ||
1105 | } | ||
1106 | |||
1107 | /// <summary> | ||
1108 | /// This class is a callback invoked when a client sends asset data to | ||
1109 | /// a task inventory script update url | ||
1110 | /// </summary> | ||
1111 | public class TaskInventoryScriptUpdater | ||
1112 | { | ||
1113 | public event UpdateTaskScript OnUpLoad; | ||
1114 | |||
1115 | private UpdateTaskScript handlerUpdateTaskScript = null; | ||
1116 | |||
1117 | private string uploaderPath = String.Empty; | ||
1118 | private UUID inventoryItemID; | ||
1119 | private UUID primID; | ||
1120 | private bool isScriptRunning; | ||
1121 | private IHttpServer httpListener; | ||
1122 | private bool m_dumpAssetToFile; | ||
1123 | |||
1124 | public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, int isScriptRunning, | ||
1125 | string path, IHttpServer httpServer, bool dumpAssetToFile) | ||
1126 | { | ||
1127 | m_dumpAssetToFile = dumpAssetToFile; | ||
1128 | |||
1129 | this.inventoryItemID = inventoryItemID; | ||
1130 | this.primID = primID; | ||
1131 | |||
1132 | // This comes in over the packet as an integer, but actually appears to be treated as a bool | ||
1133 | this.isScriptRunning = (0 == isScriptRunning ? false : true); | ||
1134 | |||
1135 | uploaderPath = path; | ||
1136 | httpListener = httpServer; | ||
1137 | } | ||
1138 | |||
1139 | /// <summary> | ||
1140 | /// | ||
1141 | /// </summary> | ||
1142 | /// <param name="data"></param> | ||
1143 | /// <param name="path"></param> | ||
1144 | /// <param name="param"></param> | ||
1145 | /// <returns></returns> | ||
1146 | public string uploaderCaps(byte[] data, string path, string param) | ||
1147 | { | ||
1148 | try | ||
1149 | { | ||
1150 | // m_log.InfoFormat("[CAPS]: " + | ||
1151 | // "TaskInventoryScriptUpdater received data: {0}, path: {1}, param: {2}", | ||
1152 | // data, path, param)); | ||
1153 | |||
1154 | string res = String.Empty; | ||
1155 | LLSDTaskInventoryUploadComplete uploadComplete = new LLSDTaskInventoryUploadComplete(); | ||
1156 | |||
1157 | handlerUpdateTaskScript = OnUpLoad; | ||
1158 | if (handlerUpdateTaskScript != null) | ||
1159 | { | ||
1160 | handlerUpdateTaskScript(inventoryItemID, primID, isScriptRunning, data); | ||
1161 | } | ||
1162 | |||
1163 | uploadComplete.item_id = inventoryItemID; | ||
1164 | uploadComplete.task_id = primID; | ||
1165 | uploadComplete.state = "complete"; | ||
1166 | |||
1167 | res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); | ||
1168 | |||
1169 | httpListener.RemoveStreamHandler("POST", uploaderPath); | ||
1170 | |||
1171 | if (m_dumpAssetToFile) | ||
1172 | { | ||
1173 | SaveAssetToFile("updatedtaskscript" + Util.RandomClass.Next(1, 1000) + ".dat", data); | ||
1174 | } | ||
1175 | |||
1176 | // m_log.InfoFormat("[CAPS]: TaskInventoryScriptUpdater.uploaderCaps res: {0}", res); | ||
1177 | |||
1178 | return res; | ||
1179 | } | ||
1180 | catch (Exception e) | ||
1181 | { | ||
1182 | m_log.Error("[CAPS]: " + e.ToString()); | ||
1183 | } | ||
1184 | |||
1185 | // XXX Maybe this should be some meaningful error packet | ||
1186 | return null; | ||
1187 | } | ||
1188 | ///Left this in and commented in case there are unforseen issues | ||
1189 | //private void SaveAssetToFile(string filename, byte[] data) | ||
1190 | //{ | ||
1191 | // FileStream fs = File.Create(filename); | ||
1192 | // BinaryWriter bw = new BinaryWriter(fs); | ||
1193 | // bw.Write(data); | ||
1194 | // bw.Close(); | ||
1195 | // fs.Close(); | ||
1196 | //} | ||
1197 | private static void SaveAssetToFile(string filename, byte[] data) | ||
1198 | { | ||
1199 | string assetPath = "UserAssets"; | ||
1200 | if (!Directory.Exists(assetPath)) | ||
1201 | { | ||
1202 | Directory.CreateDirectory(assetPath); | ||
1203 | } | ||
1204 | FileStream fs = File.Create(Path.Combine(assetPath, filename)); | ||
1205 | BinaryWriter bw = new BinaryWriter(fs); | ||
1206 | bw.Write(data); | ||
1207 | bw.Close(); | ||
1208 | fs.Close(); | ||
1209 | } | ||
1210 | } | ||
1211 | } | ||
1212 | } | ||