aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Capabilities/Caps.cs
diff options
context:
space:
mode:
authordiva2009-06-18 00:48:39 +0000
committerdiva2009-06-18 00:48:39 +0000
commit913bc3bdb380cebebd11b657966486448962ab47 (patch)
treef41837093cd692b9fe42a21c9cb1473ef81dd0f1 /OpenSim/Framework/Capabilities/Caps.cs
parentFix an uninitialized data block. Thanks, jhurliman (diff)
downloadopensim-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.cs1212
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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Reflection;
33using log4net;
34using OpenMetaverse;
35using OpenSim.Framework.Servers;
36using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Services.Interfaces;
38
39// using OpenSim.Region.Framework.Interfaces;
40
41namespace 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}