aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDiva Canto2011-05-01 18:22:53 -0700
committerDiva Canto2011-05-01 18:22:53 -0700
commitf79400e94ca6f8b609f5d4cbe25c5bbc04b61b77 (patch)
tree72fd894344eb030fab78be76475afae17c90a02a
parentChange GetTextureModule.cs to conform to the new IRegion module interface. NO... (diff)
downloadopensim-SC_OLD-f79400e94ca6f8b609f5d4cbe25c5bbc04b61b77.zip
opensim-SC_OLD-f79400e94ca6f8b609f5d4cbe25c5bbc04b61b77.tar.gz
opensim-SC_OLD-f79400e94ca6f8b609f5d4cbe25c5bbc04b61b77.tar.bz2
opensim-SC_OLD-f79400e94ca6f8b609f5d4cbe25c5bbc04b61b77.tar.xz
Broke down Caps.cs into a generic Caps object that simply registers/unregisters capabilities and a specific bunch of capability implementations in Linden space called BunchOfCaps.
Renamed a few methods that were misnomers. Compiles but doesn't work.
-rw-r--r--OpenSim/Capabilities/Caps.cs1261
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs1210
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs87
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs50
-rw-r--r--OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs4
-rw-r--r--OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs14
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs8
9 files changed, 1357 insertions, 1283 deletions
diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs
index c98498d..95bb465 100644
--- a/OpenSim/Capabilities/Caps.cs
+++ b/OpenSim/Capabilities/Caps.cs
@@ -41,28 +41,6 @@ using OpenSim.Services.Interfaces;
41 41
42namespace OpenSim.Framework.Capabilities 42namespace OpenSim.Framework.Capabilities
43{ 43{
44 public delegate void UpLoadedAsset(
45 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
46 byte[] data, string inventoryType, string assetType);
47
48 public delegate void UploadedBakedTexture(UUID assetID, byte[] data);
49
50 public delegate UUID UpdateItem(UUID itemID, byte[] data);
51
52 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
53
54 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item);
55
56 public delegate void NewAsset(AssetBase asset);
57
58 public delegate UUID ItemUpdatedCallback(UUID userID, UUID itemID, byte[] data);
59
60 public delegate ArrayList TaskScriptUpdatedCallback(UUID userID, UUID itemID, UUID primID,
61 bool isScriptRunning, byte[] data);
62
63 public delegate InventoryCollection FetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID,
64 bool fetchFolders, bool fetchItems, int sortOrder, out int version);
65
66 /// <summary> 44 /// <summary>
67 /// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that 45 /// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that
68 /// we can popup a message on the user's client if the inventory service has permanently failed). But I didn't want 46 /// we can popup a message on the user's client if the inventory service has permanently failed). But I didn't want
@@ -87,34 +65,34 @@ namespace OpenSim.Framework.Capabilities
87 private CapsHandlers m_capsHandlers; 65 private CapsHandlers m_capsHandlers;
88 private Dictionary<string, string> m_externalCapsHandlers; 66 private Dictionary<string, string> m_externalCapsHandlers;
89 67
90 private static readonly string m_requestPath = "0000/";
91 // private static readonly string m_mapLayerPath = "0001/";
92 private static readonly string m_newInventory = "0002/";
93 //private static readonly string m_requestTexture = "0003/";
94 private static readonly string m_notecardUpdatePath = "0004/";
95 private static readonly string m_notecardTaskUpdatePath = "0005/";
96// private static readonly string m_fetchInventoryPath = "0006/";
97
98 // The following entries are in a module, however, they are also here so that we don't re-assign
99 // the path to another cap by mistake.
100 // private static readonly string m_parcelVoiceInfoRequestPath = "0007/"; // This is in a module.
101 // private static readonly string m_provisionVoiceAccountRequestPath = "0008/";// This is in a module.
102
103 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
104 private static readonly string m_uploadBakedTexturePath = "0010/";// This is in the LandManagementModule.
105
106 //private string eventQueue = "0100/";
107 private IScene m_Scene;
108 private IHttpServer m_httpListener; 68 private IHttpServer m_httpListener;
109 private UUID m_agentID; 69 private UUID m_agentID;
110 private IAssetService m_assetCache;
111 private int m_eventQueueCount = 1;
112 private Queue<string> m_capsEventQueue = new Queue<string>();
113 private bool m_dumpAssetsToFile;
114 private string m_regionName; 70 private string m_regionName;
115 private object m_fetchLock = new Object();
116 71
117 private bool m_persistBakedTextures = false; 72 public UUID AgentID
73 {
74 get { return m_agentID; }
75 }
76
77 public string RegionName
78 {
79 get { return m_regionName; }
80 }
81
82 public string HostName
83 {
84 get { return m_httpListenerHostName; }
85 }
86
87 public uint Port
88 {
89 get { return m_httpListenPort; }
90 }
91
92 public IHttpServer HttpListener
93 {
94 get { return m_httpListener; }
95 }
118 96
119 public bool SSLCaps 97 public bool SSLCaps
120 { 98 {
@@ -129,35 +107,15 @@ namespace OpenSim.Framework.Capabilities
129 get { return m_capsHandlers; } 107 get { return m_capsHandlers; }
130 } 108 }
131 109
132 // These are callbacks which will be setup by the scene so that we can update scene data when we 110 public Caps(IHttpServer httpServer, string httpListen, uint httpPort, string capsPath,
133 // receive capability calls 111 UUID agent, string regionName)
134 public NewInventoryItem AddNewInventoryItem = null;
135 public NewAsset AddNewAsset = null;
136 public ItemUpdatedCallback ItemUpdatedCall = null;
137 public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null;
138 public FetchInventoryDescendentsCAPS CAPSFetchInventoryDescendents = null;
139 public GetClientDelegate GetClient = null;
140
141 public Caps(IScene scene, IAssetService assetCache, IHttpServer httpServer, string httpListen, uint httpPort, string capsPath,
142 UUID agent, bool dumpAssetsToFile, string regionName)
143 { 112 {
144 m_Scene = scene;
145 m_assetCache = assetCache;
146 m_capsObjectPath = capsPath; 113 m_capsObjectPath = capsPath;
147 m_httpListener = httpServer; 114 m_httpListener = httpServer;
148 m_httpListenerHostName = httpListen; 115 m_httpListenerHostName = httpListen;
149 116
150 m_httpListenPort = httpPort; 117 m_httpListenPort = httpPort;
151 118
152 m_persistBakedTextures = false;
153 IConfigSource config = m_Scene.Config;
154 if (config != null)
155 {
156 IConfig sconfig = config.Configs["Startup"];
157 if (sconfig != null)
158 m_persistBakedTextures = sconfig.GetBoolean("PersistBakedTextures",m_persistBakedTextures);
159 }
160
161 if (httpServer != null && httpServer.UseSSL) 119 if (httpServer != null && httpServer.UseSSL)
162 { 120 {
163 m_httpListenPort = httpServer.SSLPort; 121 m_httpListenPort = httpServer.SSLPort;
@@ -166,98 +124,12 @@ namespace OpenSim.Framework.Capabilities
166 } 124 }
167 125
168 m_agentID = agent; 126 m_agentID = agent;
169 m_dumpAssetsToFile = dumpAssetsToFile;
170 m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort, (httpServer == null) ? false : httpServer.UseSSL); 127 m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort, (httpServer == null) ? false : httpServer.UseSSL);
171 m_externalCapsHandlers = new Dictionary<string, string>(); 128 m_externalCapsHandlers = new Dictionary<string, string>();
172 m_regionName = regionName; 129 m_regionName = regionName;
173 } 130 }
174 131
175 /// <summary> 132 /// <summary>
176 /// Register all CAPS http service handlers
177 /// </summary>
178 public void RegisterHandlers()
179 {
180 DeregisterHandlers();
181
182 string capsBase = "/CAPS/" + m_capsObjectPath;
183
184 RegisterRegionServiceHandlers(capsBase);
185 RegisterInventoryServiceHandlers(capsBase);
186 }
187
188 public void RegisterRegionServiceHandlers(string capsBase)
189 {
190 try
191 {
192 // the root of all evil
193 m_capsHandlers["SEED"] = new RestStreamHandler("POST", capsBase + m_requestPath, CapsRequest);
194 m_log.DebugFormat(
195 "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_agentID);
196
197 //m_capsHandlers["MapLayer"] =
198 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
199 // capsBase + m_mapLayerPath,
200 // GetMapLayer);
201 m_capsHandlers["UpdateScriptTaskInventory"] =
202 new RestStreamHandler("POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory);
203 m_capsHandlers["UpdateScriptTask"] = m_capsHandlers["UpdateScriptTaskInventory"];
204 m_capsHandlers["UploadBakedTexture"] =
205 new RestStreamHandler("POST", capsBase + m_uploadBakedTexturePath, UploadBakedTexture);
206
207 }
208 catch (Exception e)
209 {
210 m_log.Error("[CAPS]: " + e.ToString());
211 }
212 }
213
214 public void RegisterInventoryServiceHandlers(string capsBase)
215 {
216 try
217 {
218 // I don't think this one works...
219 m_capsHandlers["NewFileAgentInventory"] =
220 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>("POST",
221 capsBase + m_newInventory,
222 NewAgentInventoryRequest);
223 m_capsHandlers["UpdateNotecardAgentInventory"] =
224 new RestStreamHandler("POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory);
225 m_capsHandlers["UpdateScriptAgentInventory"] = m_capsHandlers["UpdateNotecardAgentInventory"];
226 m_capsHandlers["UpdateScriptAgent"] = m_capsHandlers["UpdateScriptAgentInventory"];
227
228 // As of RC 1.22.9 of the Linden client this is
229 // supported
230
231 //m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest);
232
233 // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and
234 // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires
235 // enhancements (probably filling out the folder part of the LLSD reply) to our CAPS service,
236 // but when I went on the Linden grid, the
237 // simulators I visited (version 1.21) were, surprisingly, no longer supplying this capability. Instead,
238 // the 1.19.1.4 client appeared to be happily flowing inventory data over UDP
239 //
240 // This is very probably just a temporary measure - once the CAPS service appears again on the Linden grid
241 // we will be
242 // able to get the data we need to implement the necessary part of the protocol to fix the issue above.
243 // m_capsHandlers["FetchInventoryDescendents"] =
244 // new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest);
245
246 // m_capsHandlers["FetchInventoryDescendents"] =
247 // new LLSDStreamhandler<LLSDFetchInventoryDescendents, LLSDInventoryDescendents>("POST",
248 // capsBase + m_fetchInventory,
249 // FetchInventory));
250 // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST",
251 // capsBase + m_requestTexture,
252 // RequestTexture);
253 }
254 catch (Exception e)
255 {
256 m_log.Error("[CAPS]: " + e.ToString());
257 }
258 }
259
260 /// <summary>
261 /// Register a handler. This allows modules to register handlers. 133 /// Register a handler. This allows modules to register handlers.
262 /// </summary> 134 /// </summary>
263 /// <param name="capName"></param> 135 /// <param name="capName"></param>
@@ -296,1086 +168,5 @@ namespace OpenSim.Framework.Capabilities
296 } 168 }
297 } 169 }
298 } 170 }
299
300 /// <summary>
301 /// Construct a client response detailing all the capabilities this server can provide.
302 /// </summary>
303 /// <param name="request"></param>
304 /// <param name="path"></param>
305 /// <param name="param"></param>
306 /// <param name="httpRequest">HTTP request header object</param>
307 /// <param name="httpResponse">HTTP response header object</param>
308 /// <returns></returns>
309 public string CapsRequest(string request, string path, string param,
310 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
311 {
312 m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName);
313
314 if (!m_Scene.CheckClient(m_agentID, httpRequest.RemoteIPEndPoint))
315 {
316 m_log.DebugFormat("[CAPS]: Unauthorized CAPS client");
317 return string.Empty;
318 }
319
320 string result = LLSDHelpers.SerialiseLLSDReply(m_capsHandlers.CapsDetails);
321
322 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result);
323
324 return result;
325 }
326
327 // FIXME: these all should probably go into the respective region
328 // modules
329
330 /// <summary>
331 /// Processes a fetch inventory request and sends the reply
332
333 /// </summary>
334 /// <param name="request"></param>
335 /// <param name="path"></param>
336 /// <param name="param"></param>
337 /// <returns></returns>
338 // Request is like:
339 //<llsd>
340 // <map><key>folders</key>
341 // <array>
342 // <map>
343 // <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>
344 // </map>
345 // </array>
346 // </map>
347 //</llsd>
348 //
349 // multiple fetch-folder maps are allowed within the larger folders map.
350 public string FetchInventoryRequest(string request, string path, string param)
351 {
352 // string unmodifiedRequest = request.ToString();
353
354 //m_log.DebugFormat("[AGENT INVENTORY]: Received CAPS fetch inventory request {0}", unmodifiedRequest);
355 m_log.Debug("[CAPS]: Inventory Request in region: " + m_regionName);
356
357 Hashtable hash = new Hashtable();
358 try
359 {
360 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
361 }
362 catch (LLSD.LLSDParseException pe)
363 {
364 m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message);
365 m_log.Error("Request: " + request.ToString());
366 }
367
368 ArrayList foldersrequested = (ArrayList)hash["folders"];
369
370 string response = "";
371
372 for (int i = 0; i < foldersrequested.Count; i++)
373 {
374 string inventoryitemstr = "";
375 Hashtable inventoryhash = (Hashtable)foldersrequested[i];
376
377 LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
378 LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
379 LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest);
380
381 inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply);
382 inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
383 inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
384
385 response += inventoryitemstr;
386 }
387
388 if (response.Length == 0)
389 {
390 // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants.
391 // Therefore, I'm concluding that the client only has so many threads available to do requests
392 // and when a thread stalls.. is stays stalled.
393 // Therefore we need to return something valid
394 response = "<llsd><map><key>folders</key><array /></map></llsd>";
395 }
396 else
397 {
398 response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>";
399 }
400
401 //m_log.DebugFormat("[AGENT INVENTORY]: Replying to CAPS fetch inventory request with following xml");
402 //m_log.Debug(Util.GetFormattedXml(response));
403
404 return response;
405 }
406
407 public string FetchInventoryDescendentsRequest(string request, string path, string param,OSHttpRequest httpRequest, OSHttpResponse httpResponse)
408 {
409 // nasty temporary hack here, the linden client falsely
410 // identifies the uuid 00000000-0000-0000-0000-000000000000
411 // as a string which breaks us
412 //
413 // correctly mark it as a uuid
414 //
415 request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
416
417 // another hack <integer>1</integer> results in a
418 // System.ArgumentException: Object type System.Int32 cannot
419 // be converted to target type: System.Boolean
420 //
421 request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
422 request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
423
424 Hashtable hash = new Hashtable();
425 try
426 {
427 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
428 }
429 catch (LLSD.LLSDParseException pe)
430 {
431 m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message);
432 m_log.Error("Request: " + request.ToString());
433 }
434
435 ArrayList foldersrequested = (ArrayList)hash["folders"];
436
437 string response = "";
438 lock (m_fetchLock)
439 {
440 for (int i = 0; i < foldersrequested.Count; i++)
441 {
442 string inventoryitemstr = "";
443 Hashtable inventoryhash = (Hashtable)foldersrequested[i];
444
445 LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
446
447 try{
448 LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
449 }
450 catch(Exception e)
451 {
452 m_log.Debug("[CAPS]: caught exception doing OSD deserialize" + e);
453 }
454 LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest);
455
456 inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply);
457 inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
458 inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
459
460 response += inventoryitemstr;
461 }
462
463
464 if (response.Length == 0)
465 {
466 // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants.
467 // Therefore, I'm concluding that the client only has so many threads available to do requests
468 // and when a thread stalls.. is stays stalled.
469 // Therefore we need to return something valid
470 response = "<llsd><map><key>folders</key><array /></map></llsd>";
471 }
472 else
473 {
474 response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>";
475 }
476
477 //m_log.DebugFormat("[CAPS]: Replying to CAPS fetch inventory request with following xml");
478 //m_log.Debug("[CAPS] "+response);
479
480 }
481 return response;
482 }
483
484
485
486 /// <summary>
487 /// Construct an LLSD reply packet to a CAPS inventory request
488 /// </summary>
489 /// <param name="invFetch"></param>
490 /// <returns></returns>
491 private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch)
492 {
493 LLSDInventoryDescendents reply = new LLSDInventoryDescendents();
494 LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents();
495 contents.agent_id = m_agentID;
496 contents.owner_id = invFetch.owner_id;
497 contents.folder_id = invFetch.folder_id;
498
499 reply.folders.Array.Add(contents);
500 InventoryCollection inv = new InventoryCollection();
501 inv.Folders = new List<InventoryFolderBase>();
502 inv.Items = new List<InventoryItemBase>();
503 int version = 0;
504 if (CAPSFetchInventoryDescendents != null)
505 {
506 inv = CAPSFetchInventoryDescendents(m_agentID, invFetch.folder_id, invFetch.owner_id, invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version);
507 }
508
509 if (inv.Folders != null)
510 {
511 foreach (InventoryFolderBase invFolder in inv.Folders)
512 {
513 contents.categories.Array.Add(ConvertInventoryFolder(invFolder));
514 }
515 }
516
517 if (inv.Items != null)
518 {
519 foreach (InventoryItemBase invItem in inv.Items)
520 {
521 contents.items.Array.Add(ConvertInventoryItem(invItem));
522 }
523 }
524
525 contents.descendents = contents.items.Array.Count + contents.categories.Array.Count;
526 contents.version = version;
527
528 return reply;
529 }
530
531 /// <summary>
532 /// Convert an internal inventory folder object into an LLSD object.
533 /// </summary>
534 /// <param name="invFolder"></param>
535 /// <returns></returns>
536 private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder)
537 {
538 LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder();
539 llsdFolder.folder_id = invFolder.ID;
540 llsdFolder.parent_id = invFolder.ParentID;
541 llsdFolder.name = invFolder.Name;
542 if (invFolder.Type < 0 || invFolder.Type >= TaskInventoryItem.Types.Length)
543 llsdFolder.type = "-1";
544 else
545 llsdFolder.type = TaskInventoryItem.Types[invFolder.Type];
546 llsdFolder.preferred_type = "-1";
547
548 return llsdFolder;
549 }
550
551 /// <summary>
552 /// Convert an internal inventory item object into an LLSD object.
553 /// </summary>
554 /// <param name="invItem"></param>
555 /// <returns></returns>
556 private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem)
557 {
558 LLSDInventoryItem llsdItem = new LLSDInventoryItem();
559 llsdItem.asset_id = invItem.AssetID;
560 llsdItem.created_at = invItem.CreationDate;
561 llsdItem.desc = invItem.Description;
562 llsdItem.flags = (int)invItem.Flags;
563 llsdItem.item_id = invItem.ID;
564 llsdItem.name = invItem.Name;
565 llsdItem.parent_id = invItem.Folder;
566 try
567 {
568 // TODO reevaluate after upgrade to libomv >= r2566. Probably should use UtilsConversions.
569 llsdItem.type = TaskInventoryItem.Types[invItem.AssetType];
570 llsdItem.inv_type = TaskInventoryItem.InvTypes[invItem.InvType];
571 }
572 catch (Exception e)
573 {
574 m_log.Error("[CAPS]: Problem setting asset/inventory type while converting inventory item " + invItem.Name + " to LLSD:", e);
575 }
576 llsdItem.permissions = new LLSDPermissions();
577 llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid;
578 llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions;
579 llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions;
580 llsdItem.permissions.group_id = invItem.GroupID;
581 llsdItem.permissions.group_mask = (int)invItem.GroupPermissions;
582 llsdItem.permissions.is_owner_group = invItem.GroupOwned;
583 llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions;
584 llsdItem.permissions.owner_id = m_agentID;
585 llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions;
586 llsdItem.sale_info = new LLSDSaleInfo();
587 llsdItem.sale_info.sale_price = invItem.SalePrice;
588 switch (invItem.SaleType)
589 {
590 default:
591 llsdItem.sale_info.sale_type = "not";
592 break;
593 case 1:
594 llsdItem.sale_info.sale_type = "original";
595 break;
596 case 2:
597 llsdItem.sale_info.sale_type = "copy";
598 break;
599 case 3:
600 llsdItem.sale_info.sale_type = "contents";
601 break;
602 }
603
604 return llsdItem;
605 }
606
607 /// <summary>
608 ///
609 /// </summary>
610 /// <param name="mapReq"></param>
611 /// <returns></returns>
612 public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq)
613 {
614 m_log.Debug("[CAPS]: MapLayer Request in region: " + m_regionName);
615 LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
616 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
617 return mapResponse;
618 }
619
620 /// <summary>
621 ///
622 /// </summary>
623 /// <returns></returns>
624 protected static OSDMapLayer GetOSDMapLayerResponse()
625 {
626 OSDMapLayer mapLayer = new OSDMapLayer();
627 mapLayer.Right = 5000;
628 mapLayer.Top = 5000;
629 mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006");
630
631 return mapLayer;
632 }
633
634 /// <summary>
635 ///
636 /// </summary>
637 /// <param name="request"></param>
638 /// <param name="path"></param>
639 /// <param name="param"></param>
640 /// <returns></returns>
641 public string RequestTexture(string request, string path, string param)
642 {
643 m_log.Debug("texture request " + request);
644 // Needs implementing (added to remove compiler warning)
645 return String.Empty;
646 }
647
648 #region EventQueue (Currently not enabled)
649
650 /// <summary>
651 ///
652 /// </summary>
653 /// <param name="request"></param>
654 /// <param name="path"></param>
655 /// <param name="param"></param>
656 /// <returns></returns>
657 public string ProcessEventQueue(string request, string path, string param)
658 {
659 string res = String.Empty;
660
661 if (m_capsEventQueue.Count > 0)
662 {
663 lock (m_capsEventQueue)
664 {
665 string item = m_capsEventQueue.Dequeue();
666 res = item;
667 }
668 }
669 else
670 {
671 res = CreateEmptyEventResponse();
672 }
673 return res;
674 }
675
676 /// <summary>
677 ///
678 /// </summary>
679 /// <param name="caps"></param>
680 /// <param name="ipAddressPort"></param>
681 /// <returns></returns>
682 public string CreateEstablishAgentComms(string caps, string ipAddressPort)
683 {
684 LLSDCapEvent eventItem = new LLSDCapEvent();
685 eventItem.id = m_eventQueueCount;
686 //should be creating a EstablishAgentComms item, but there isn't a class for it yet
687 eventItem.events.Array.Add(new LLSDEmpty());
688 string res = LLSDHelpers.SerialiseLLSDReply(eventItem);
689 m_eventQueueCount++;
690
691 m_capsEventQueue.Enqueue(res);
692 return res;
693 }
694
695 /// <summary>
696 ///
697 /// </summary>
698 /// <returns></returns>
699 public string CreateEmptyEventResponse()
700 {
701 LLSDCapEvent eventItem = new LLSDCapEvent();
702 eventItem.id = m_eventQueueCount;
703 eventItem.events.Array.Add(new LLSDEmpty());
704 string res = LLSDHelpers.SerialiseLLSDReply(eventItem);
705 m_eventQueueCount++;
706 return res;
707 }
708
709 #endregion
710
711 /// <summary>
712 /// Called by the script task update handler. Provides a URL to which the client can upload a new asset.
713 /// </summary>
714 /// <param name="request"></param>
715 /// <param name="path"></param>
716 /// <param name="param"></param>
717 /// <param name="httpRequest">HTTP request header object</param>
718 /// <param name="httpResponse">HTTP response header object</param>
719 /// <returns></returns>
720 public string ScriptTaskInventory(string request, string path, string param,
721 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
722 {
723 try
724 {
725 m_log.Debug("[CAPS]: ScriptTaskInventory Request in region: " + m_regionName);
726 //m_log.DebugFormat("[CAPS]: request: {0}, path: {1}, param: {2}", request, path, param);
727
728 Hashtable hash = (Hashtable) LLSD.LLSDDeserialize(Utils.StringToBytes(request));
729 LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate();
730 LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest);
731
732 string capsBase = "/CAPS/" + m_capsObjectPath;
733 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
734
735 TaskInventoryScriptUpdater uploader =
736 new TaskInventoryScriptUpdater(
737 llsdUpdateRequest.item_id,
738 llsdUpdateRequest.task_id,
739 llsdUpdateRequest.is_script_running,
740 capsBase + uploaderPath,
741 m_httpListener,
742 m_dumpAssetsToFile);
743 uploader.OnUpLoad += TaskScriptUpdated;
744
745 m_httpListener.AddStreamHandler(
746 new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
747
748 string protocol = "http://";
749
750 if (m_httpListener.UseSSL)
751 protocol = "https://";
752
753 string uploaderURL = protocol + m_httpListenerHostName + ":" + m_httpListenPort.ToString() + capsBase +
754 uploaderPath;
755
756 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
757 uploadResponse.uploader = uploaderURL;
758 uploadResponse.state = "upload";
759
760// m_log.InfoFormat("[CAPS]: " +
761// "ScriptTaskInventory response: {0}",
762// LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
763
764 return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
765 }
766 catch (Exception e)
767 {
768 m_log.Error("[CAPS]: " + e.ToString());
769 }
770
771 return null;
772 }
773
774 public string UploadBakedTexture(string request, string path,
775 string param, OSHttpRequest httpRequest,
776 OSHttpResponse httpResponse)
777 {
778 try
779 {
780// m_log.Debug("[CAPS]: UploadBakedTexture Request in region: " +
781// m_regionName);
782
783 string capsBase = "/CAPS/" + m_capsObjectPath;
784 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
785
786 BakedTextureUploader uploader =
787 new BakedTextureUploader(capsBase + uploaderPath,
788 m_httpListener);
789 uploader.OnUpLoad += BakedTextureUploaded;
790
791 m_httpListener.AddStreamHandler(
792 new BinaryStreamHandler("POST", capsBase + uploaderPath,
793 uploader.uploaderCaps));
794
795 string protocol = "http://";
796
797 if (m_httpListener.UseSSL)
798 protocol = "https://";
799
800 string uploaderURL = protocol + m_httpListenerHostName + ":" +
801 m_httpListenPort.ToString() + capsBase + uploaderPath;
802
803 LLSDAssetUploadResponse uploadResponse =
804 new LLSDAssetUploadResponse();
805 uploadResponse.uploader = uploaderURL;
806 uploadResponse.state = "upload";
807
808 return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
809 }
810 catch (Exception e)
811 {
812 m_log.Error("[CAPS]: " + e.ToString());
813 }
814
815 return null;
816 }
817
818 /// <summary>
819 /// Called by the notecard update handler. Provides a URL to which the client can upload a new asset.
820 /// </summary>
821 /// <param name="request"></param>
822 /// <param name="path"></param>
823 /// <param name="param"></param>
824 /// <returns></returns>
825 public string NoteCardAgentInventory(string request, string path, string param,
826 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
827 {
828 //m_log.Debug("[CAPS]: NoteCardAgentInventory Request in region: " + m_regionName + "\n" + request);
829 //m_log.Debug("[CAPS]: NoteCardAgentInventory Request is: " + request);
830
831 //OpenMetaverse.StructuredData.OSDMap hash = (OpenMetaverse.StructuredData.OSDMap)OpenMetaverse.StructuredData.LLSDParser.DeserializeBinary(Utils.StringToBytes(request));
832 Hashtable hash = (Hashtable) LLSD.LLSDDeserialize(Utils.StringToBytes(request));
833 LLSDItemUpdate llsdRequest = new LLSDItemUpdate();
834 LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest);
835
836 string capsBase = "/CAPS/" + m_capsObjectPath;
837 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
838
839 ItemUpdater uploader =
840 new ItemUpdater(llsdRequest.item_id, capsBase + uploaderPath, m_httpListener, m_dumpAssetsToFile);
841 uploader.OnUpLoad += ItemUpdated;
842
843 m_httpListener.AddStreamHandler(
844 new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
845
846 string protocol = "http://";
847
848 if (m_httpListener.UseSSL)
849 protocol = "https://";
850
851 string uploaderURL = protocol + m_httpListenerHostName + ":" + m_httpListenPort.ToString() + capsBase +
852 uploaderPath;
853
854 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
855 uploadResponse.uploader = uploaderURL;
856 uploadResponse.state = "upload";
857
858// m_log.InfoFormat("[CAPS]: " +
859// "NoteCardAgentInventory response: {0}",
860// LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
861
862 return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
863 }
864
865 /// <summary>
866 ///
867 /// </summary>
868 /// <param name="llsdRequest"></param>
869 /// <returns></returns>
870 public LLSDAssetUploadResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest)
871 {
872 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
873 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
874
875 if (llsdRequest.asset_type == "texture" ||
876 llsdRequest.asset_type == "animation" ||
877 llsdRequest.asset_type == "sound")
878 {
879 IClientAPI client = null;
880 IScene scene = null;
881 if (GetClient != null)
882 {
883 client = GetClient(m_agentID);
884 scene = client.Scene;
885
886 IMoneyModule mm = scene.RequestModuleInterface<IMoneyModule>();
887
888 if (mm != null)
889 {
890 if (!mm.UploadCovered(client, mm.UploadCharge))
891 {
892 if (client != null)
893 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
894
895 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
896 errorResponse.uploader = "";
897 errorResponse.state = "error";
898 return errorResponse;
899 }
900 }
901 }
902 }
903
904
905 string assetName = llsdRequest.name;
906 string assetDes = llsdRequest.description;
907 string capsBase = "/CAPS/" + m_capsObjectPath;
908 UUID newAsset = UUID.Random();
909 UUID newInvItem = UUID.Random();
910 UUID parentFolder = llsdRequest.folder_id;
911 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
912
913 AssetUploader uploader =
914 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
915 llsdRequest.asset_type, capsBase + uploaderPath, m_httpListener, m_dumpAssetsToFile);
916 m_httpListener.AddStreamHandler(
917 new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
918
919 string protocol = "http://";
920
921 if (m_httpListener.UseSSL)
922 protocol = "https://";
923
924 string uploaderURL = protocol + m_httpListenerHostName + ":" + m_httpListenPort.ToString() + capsBase +
925 uploaderPath;
926
927 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
928 uploadResponse.uploader = uploaderURL;
929 uploadResponse.state = "upload";
930 uploader.OnUpLoad += UploadCompleteHandler;
931 return uploadResponse;
932 }
933
934 /// <summary>
935 ///
936 /// </summary>
937 /// <param name="assetID"></param>
938 /// <param name="inventoryItem"></param>
939 /// <param name="data"></param>
940 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
941 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
942 string assetType)
943 {
944 sbyte assType = 0;
945 sbyte inType = 0;
946
947 if (inventoryType == "sound")
948 {
949 inType = 1;
950 assType = 1;
951 }
952 else if (inventoryType == "animation")
953 {
954 inType = 19;
955 assType = 20;
956 }
957 else if (inventoryType == "wearable")
958 {
959 inType = 18;
960 switch (assetType)
961 {
962 case "bodypart":
963 assType = 13;
964 break;
965 case "clothing":
966 assType = 5;
967 break;
968 }
969 }
970
971 AssetBase asset;
972 asset = new AssetBase(assetID, assetName, assType, m_agentID.ToString());
973 asset.Data = data;
974 if (AddNewAsset != null)
975 AddNewAsset(asset);
976 else if (m_assetCache != null)
977 m_assetCache.Store(asset);
978
979 InventoryItemBase item = new InventoryItemBase();
980 item.Owner = m_agentID;
981 item.CreatorId = m_agentID.ToString();
982 item.CreatorData = String.Empty;
983 item.ID = inventoryItem;
984 item.AssetID = asset.FullID;
985 item.Description = assetDescription;
986 item.Name = assetName;
987 item.AssetType = assType;
988 item.InvType = inType;
989 item.Folder = parentFolder;
990 item.CurrentPermissions = (uint)PermissionMask.All;
991 item.BasePermissions = (uint)PermissionMask.All;
992 item.EveryOnePermissions = 0;
993 item.NextPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer);
994 item.CreationDate = Util.UnixTimeSinceEpoch();
995
996 if (AddNewInventoryItem != null)
997 {
998 AddNewInventoryItem(m_agentID, item);
999 }
1000 }
1001
1002 public void BakedTextureUploaded(UUID assetID, byte[] data)
1003 {
1004// m_log.WarnFormat("[CAPS]: Received baked texture {0}", assetID.ToString());
1005
1006 AssetBase asset;
1007 asset = new AssetBase(assetID, "Baked Texture", (sbyte)AssetType.Texture, m_agentID.ToString());
1008 asset.Data = data;
1009 asset.Temporary = true;
1010 asset.Local = ! m_persistBakedTextures; // Local assets aren't persisted, non-local are
1011 m_assetCache.Store(asset);
1012 }
1013
1014 /// <summary>
1015 /// Called when new asset data for an agent inventory item update has been uploaded.
1016 /// </summary>
1017 /// <param name="itemID">Item to update</param>
1018 /// <param name="data">New asset data</param>
1019 /// <returns></returns>
1020 public UUID ItemUpdated(UUID itemID, byte[] data)
1021 {
1022 if (ItemUpdatedCall != null)
1023 {
1024 return ItemUpdatedCall(m_agentID, itemID, data);
1025 }
1026
1027 return UUID.Zero;
1028 }
1029
1030 /// <summary>
1031 /// Called when new asset data for an agent inventory item update has been uploaded.
1032 /// </summary>
1033 /// <param name="itemID">Item to update</param>
1034 /// <param name="primID">Prim containing item to update</param>
1035 /// <param name="isScriptRunning">Signals whether the script to update is currently running</param>
1036 /// <param name="data">New asset data</param>
1037 public void TaskScriptUpdated(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors)
1038 {
1039 if (TaskScriptUpdatedCall != null)
1040 {
1041 ArrayList e = TaskScriptUpdatedCall(m_agentID, itemID, primID, isScriptRunning, data);
1042 foreach (Object item in e)
1043 errors.Add(item);
1044 }
1045 }
1046
1047 public class AssetUploader
1048 {
1049 public event UpLoadedAsset OnUpLoad;
1050 private UpLoadedAsset handlerUpLoad = null;
1051
1052 private string uploaderPath = String.Empty;
1053 private UUID newAssetID;
1054 private UUID inventoryItemID;
1055 private UUID parentFolder;
1056 private IHttpServer httpListener;
1057 private bool m_dumpAssetsToFile;
1058 private string m_assetName = String.Empty;
1059 private string m_assetDes = String.Empty;
1060
1061 private string m_invType = String.Empty;
1062 private string m_assetType = String.Empty;
1063
1064 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
1065 UUID parentFolderID, string invType, string assetType, string path,
1066 IHttpServer httpServer, bool dumpAssetsToFile)
1067 {
1068 m_assetName = assetName;
1069 m_assetDes = description;
1070 newAssetID = assetID;
1071 inventoryItemID = inventoryItem;
1072 uploaderPath = path;
1073 httpListener = httpServer;
1074 parentFolder = parentFolderID;
1075 m_assetType = assetType;
1076 m_invType = invType;
1077 m_dumpAssetsToFile = dumpAssetsToFile;
1078 }
1079
1080 /// <summary>
1081 ///
1082 /// </summary>
1083 /// <param name="data"></param>
1084 /// <param name="path"></param>
1085 /// <param name="param"></param>
1086 /// <returns></returns>
1087 public string uploaderCaps(byte[] data, string path, string param)
1088 {
1089 UUID inv = inventoryItemID;
1090 string res = String.Empty;
1091 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1092 uploadComplete.new_asset = newAssetID.ToString();
1093 uploadComplete.new_inventory_item = inv;
1094 uploadComplete.state = "complete";
1095
1096 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1097
1098 httpListener.RemoveStreamHandler("POST", uploaderPath);
1099
1100 // TODO: probably make this a better set of extensions here
1101 string extension = ".jp2";
1102 if (m_invType != "image")
1103 {
1104 extension = ".dat";
1105 }
1106
1107 if (m_dumpAssetsToFile)
1108 {
1109 SaveAssetToFile(m_assetName + extension, data);
1110 }
1111 handlerUpLoad = OnUpLoad;
1112 if (handlerUpLoad != null)
1113 {
1114 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType);
1115 }
1116
1117 return res;
1118 }
1119 ///Left this in and commented in case there are unforseen issues
1120 //private void SaveAssetToFile(string filename, byte[] data)
1121 //{
1122 // FileStream fs = File.Create(filename);
1123 // BinaryWriter bw = new BinaryWriter(fs);
1124 // bw.Write(data);
1125 // bw.Close();
1126 // fs.Close();
1127 //}
1128 private static void SaveAssetToFile(string filename, byte[] data)
1129 {
1130 string assetPath = "UserAssets";
1131 if (!Directory.Exists(assetPath))
1132 {
1133 Directory.CreateDirectory(assetPath);
1134 }
1135 FileStream fs = File.Create(Path.Combine(assetPath, Util.safeFileName(filename)));
1136 BinaryWriter bw = new BinaryWriter(fs);
1137 bw.Write(data);
1138 bw.Close();
1139 fs.Close();
1140 }
1141 }
1142
1143 /// <summary>
1144 /// This class is a callback invoked when a client sends asset data to
1145 /// an agent inventory notecard update url
1146 /// </summary>
1147 public class ItemUpdater
1148 {
1149 public event UpdateItem OnUpLoad;
1150
1151 private UpdateItem handlerUpdateItem = null;
1152
1153 private string uploaderPath = String.Empty;
1154 private UUID inventoryItemID;
1155 private IHttpServer httpListener;
1156 private bool m_dumpAssetToFile;
1157
1158 public ItemUpdater(UUID inventoryItem, string path, IHttpServer httpServer, bool dumpAssetToFile)
1159 {
1160 m_dumpAssetToFile = dumpAssetToFile;
1161
1162 inventoryItemID = inventoryItem;
1163 uploaderPath = path;
1164 httpListener = httpServer;
1165 }
1166
1167 /// <summary>
1168 ///
1169 /// </summary>
1170 /// <param name="data"></param>
1171 /// <param name="path"></param>
1172 /// <param name="param"></param>
1173 /// <returns></returns>
1174 public string uploaderCaps(byte[] data, string path, string param)
1175 {
1176 UUID inv = inventoryItemID;
1177 string res = String.Empty;
1178 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1179 UUID assetID = UUID.Zero;
1180 handlerUpdateItem = OnUpLoad;
1181 if (handlerUpdateItem != null)
1182 {
1183 assetID = handlerUpdateItem(inv, data);
1184 }
1185
1186 uploadComplete.new_asset = assetID.ToString();
1187 uploadComplete.new_inventory_item = inv;
1188 uploadComplete.state = "complete";
1189
1190 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1191
1192 httpListener.RemoveStreamHandler("POST", uploaderPath);
1193
1194 if (m_dumpAssetToFile)
1195 {
1196 SaveAssetToFile("updateditem" + Util.RandomClass.Next(1, 1000) + ".dat", data);
1197 }
1198
1199 return res;
1200 }
1201 ///Left this in and commented in case there are unforseen issues
1202 //private void SaveAssetToFile(string filename, byte[] data)
1203 //{
1204 // FileStream fs = File.Create(filename);
1205 // BinaryWriter bw = new BinaryWriter(fs);
1206 // bw.Write(data);
1207 // bw.Close();
1208 // fs.Close();
1209 //}
1210 private static void SaveAssetToFile(string filename, byte[] data)
1211 {
1212 string assetPath = "UserAssets";
1213 if (!Directory.Exists(assetPath))
1214 {
1215 Directory.CreateDirectory(assetPath);
1216 }
1217 FileStream fs = File.Create(Path.Combine(assetPath, filename));
1218 BinaryWriter bw = new BinaryWriter(fs);
1219 bw.Write(data);
1220 bw.Close();
1221 fs.Close();
1222 }
1223 }
1224
1225 /// <summary>
1226 /// This class is a callback invoked when a client sends asset data to
1227 /// a task inventory script update url
1228 /// </summary>
1229 public class TaskInventoryScriptUpdater
1230 {
1231 public event UpdateTaskScript OnUpLoad;
1232
1233 private UpdateTaskScript handlerUpdateTaskScript = null;
1234
1235 private string uploaderPath = String.Empty;
1236 private UUID inventoryItemID;
1237 private UUID primID;
1238 private bool isScriptRunning;
1239 private IHttpServer httpListener;
1240 private bool m_dumpAssetToFile;
1241
1242 public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, int isScriptRunning,
1243 string path, IHttpServer httpServer, bool dumpAssetToFile)
1244 {
1245 m_dumpAssetToFile = dumpAssetToFile;
1246
1247 this.inventoryItemID = inventoryItemID;
1248 this.primID = primID;
1249
1250 // This comes in over the packet as an integer, but actually appears to be treated as a bool
1251 this.isScriptRunning = (0 == isScriptRunning ? false : true);
1252
1253 uploaderPath = path;
1254 httpListener = httpServer;
1255 }
1256
1257 /// <summary>
1258 ///
1259 /// </summary>
1260 /// <param name="data"></param>
1261 /// <param name="path"></param>
1262 /// <param name="param"></param>
1263 /// <returns></returns>
1264 public string uploaderCaps(byte[] data, string path, string param)
1265 {
1266 try
1267 {
1268// m_log.InfoFormat("[CAPS]: " +
1269// "TaskInventoryScriptUpdater received data: {0}, path: {1}, param: {2}",
1270// data, path, param));
1271
1272 string res = String.Empty;
1273 LLSDTaskScriptUploadComplete uploadComplete = new LLSDTaskScriptUploadComplete();
1274
1275 ArrayList errors = new ArrayList();
1276 handlerUpdateTaskScript = OnUpLoad;
1277 if (handlerUpdateTaskScript != null)
1278 {
1279 handlerUpdateTaskScript(inventoryItemID, primID, isScriptRunning, data, ref errors);
1280 }
1281
1282 uploadComplete.new_asset = inventoryItemID;
1283 uploadComplete.compiled = errors.Count > 0 ? false : true;
1284 uploadComplete.state = "complete";
1285 uploadComplete.errors = new OSDArray();
1286 uploadComplete.errors.Array = errors;
1287
1288 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1289
1290 httpListener.RemoveStreamHandler("POST", uploaderPath);
1291
1292 if (m_dumpAssetToFile)
1293 {
1294 SaveAssetToFile("updatedtaskscript" + Util.RandomClass.Next(1, 1000) + ".dat", data);
1295 }
1296
1297// m_log.InfoFormat("[CAPS]: TaskInventoryScriptUpdater.uploaderCaps res: {0}", res);
1298
1299 return res;
1300 }
1301 catch (Exception e)
1302 {
1303 m_log.Error("[CAPS]: " + e.ToString());
1304 }
1305
1306 // XXX Maybe this should be some meaningful error packet
1307 return null;
1308 }
1309 ///Left this in and commented in case there are unforseen issues
1310 //private void SaveAssetToFile(string filename, byte[] data)
1311 //{
1312 // FileStream fs = File.Create(filename);
1313 // BinaryWriter bw = new BinaryWriter(fs);
1314 // bw.Write(data);
1315 // bw.Close();
1316 // fs.Close();
1317 //}
1318 private static void SaveAssetToFile(string filename, byte[] data)
1319 {
1320 string assetPath = "UserAssets";
1321 if (!Directory.Exists(assetPath))
1322 {
1323 Directory.CreateDirectory(assetPath);
1324 }
1325 FileStream fs = File.Create(Path.Combine(assetPath, filename));
1326 BinaryWriter bw = new BinaryWriter(fs);
1327 bw.Write(data);
1328 bw.Close();
1329 fs.Close();
1330 }
1331 }
1332
1333 public class BakedTextureUploader
1334 {
1335 public event UploadedBakedTexture OnUpLoad;
1336 private UploadedBakedTexture handlerUpLoad = null;
1337
1338 private string uploaderPath = String.Empty;
1339 private UUID newAssetID;
1340 private IHttpServer httpListener;
1341
1342 public BakedTextureUploader(string path, IHttpServer httpServer)
1343 {
1344 newAssetID = UUID.Random();
1345 uploaderPath = path;
1346 httpListener = httpServer;
1347// m_log.InfoFormat("[CAPS] baked texture upload starting for {0}",newAssetID);
1348 }
1349
1350 /// <summary>
1351 ///
1352 /// </summary>
1353 /// <param name="data"></param>
1354 /// <param name="path"></param>
1355 /// <param name="param"></param>
1356 /// <returns></returns>
1357 public string uploaderCaps(byte[] data, string path, string param)
1358 {
1359 handlerUpLoad = OnUpLoad;
1360 if (handlerUpLoad != null)
1361 {
1362 Util.FireAndForget(delegate(object o) { handlerUpLoad(newAssetID, data); });
1363 }
1364
1365 string res = String.Empty;
1366 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1367 uploadComplete.new_asset = newAssetID.ToString();
1368 uploadComplete.new_inventory_item = UUID.Zero;
1369 uploadComplete.state = "complete";
1370
1371 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1372
1373 httpListener.RemoveStreamHandler("POST", uploaderPath);
1374
1375// m_log.InfoFormat("[CAPS] baked texture upload completed for {0}",newAssetID);
1376
1377 return res;
1378 }
1379 }
1380 } 171 }
1381} 172}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
new file mode 100644
index 0000000..7a7964e
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -0,0 +1,1210 @@
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.IO;
5using System.Reflection;
6
7using OpenMetaverse;
8using Nini.Config;
9using log4net;
10
11using OpenSim.Framework;
12using OpenSim.Framework.Capabilities;
13using OpenSim.Region.Framework;
14using OpenSim.Region.Framework.Scenes;
15using OpenSim.Framework.Servers;
16using OpenSim.Framework.Servers.HttpServer;
17using OpenSim.Services.Interfaces;
18
19using Caps = OpenSim.Framework.Capabilities.Caps;
20
21namespace OpenSim.Region.ClientStack.Linden
22{
23 public delegate void UpLoadedAsset(
24 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
25 byte[] data, string inventoryType, string assetType);
26
27 public delegate void UploadedBakedTexture(UUID assetID, byte[] data);
28
29 public delegate UUID UpdateItem(UUID itemID, byte[] data);
30
31 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
32
33 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item);
34
35 public delegate void NewAsset(AssetBase asset);
36
37 public delegate UUID ItemUpdatedCallback(UUID userID, UUID itemID, byte[] data);
38
39 public delegate ArrayList TaskScriptUpdatedCallback(UUID userID, UUID itemID, UUID primID,
40 bool isScriptRunning, byte[] data);
41
42 public delegate InventoryCollection FetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID,
43 bool fetchFolders, bool fetchItems, int sortOrder, out int version);
44
45 /// <summary>
46 /// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that
47 /// we can popup a message on the user's client if the inventory service has permanently failed). But I didn't want
48 /// to just pass the whole Scene into CAPS.
49 /// </summary>
50 public delegate IClientAPI GetClientDelegate(UUID agentID);
51
52 public class BunchOfCaps
53 {
54 private static readonly ILog m_log =
55 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 private Scene m_Scene;
58 private Caps m_HostCapsObj;
59
60 private static readonly string m_requestPath = "0000/";
61 // private static readonly string m_mapLayerPath = "0001/";
62 private static readonly string m_newInventory = "0002/";
63 //private static readonly string m_requestTexture = "0003/";
64 private static readonly string m_notecardUpdatePath = "0004/";
65 private static readonly string m_notecardTaskUpdatePath = "0005/";
66 // private static readonly string m_fetchInventoryPath = "0006/";
67 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
68 private static readonly string m_uploadBakedTexturePath = "0010/";// This is in the LandManagementModule.
69
70
71 // These are callbacks which will be setup by the scene so that we can update scene data when we
72 // receive capability calls
73 public NewInventoryItem AddNewInventoryItem = null;
74 public NewAsset AddNewAsset = null;
75 public ItemUpdatedCallback ItemUpdatedCall = null;
76 public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null;
77 public FetchInventoryDescendentsCAPS CAPSFetchInventoryDescendents = null;
78 public GetClientDelegate GetClient = null;
79
80 private bool m_persistBakedTextures = false;
81 private IAssetService m_assetCache;
82 private bool m_dumpAssetsToFile;
83 private string m_regionName;
84 private object m_fetchLock = new Object();
85
86 public BunchOfCaps(Scene scene, Caps caps)
87 {
88 m_Scene = scene;
89 m_HostCapsObj = caps;
90 IConfigSource config = m_Scene.Config;
91 if (config != null)
92 {
93 IConfig sconfig = config.Configs["Startup"];
94 if (sconfig != null)
95 m_persistBakedTextures = sconfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
96 }
97
98 RegisterHandlers();
99
100 AddNewInventoryItem = m_Scene.AddUploadedInventoryItem;
101 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
102 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
103 CAPSFetchInventoryDescendents = m_Scene.HandleFetchInventoryDescendentsCAPS;
104 GetClient = m_Scene.SceneContents.GetControllingClient;
105
106 }
107
108 /// <summary>
109 /// Register a bunch of CAPS http service handlers
110 /// </summary>
111 public void RegisterHandlers()
112 {
113 m_HostCapsObj.DeregisterHandlers();
114
115 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
116
117 RegisterRegionServiceHandlers(capsBase);
118 RegisterInventoryServiceHandlers(capsBase);
119 }
120
121 public void RegisterRegionServiceHandlers(string capsBase)
122 {
123 try
124 {
125 // the root of all evil
126 m_HostCapsObj.RegisterHandler("SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest));
127 m_log.DebugFormat(
128 "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
129
130 //m_capsHandlers["MapLayer"] =
131 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
132 // capsBase + m_mapLayerPath,
133 // GetMapLayer);
134 IRequestHandler req = new RestStreamHandler("POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory);
135 m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req);
136 m_HostCapsObj.RegisterHandler("UpdateScriptTask", req);
137 m_HostCapsObj.RegisterHandler("UploadBakedTexture", new RestStreamHandler("POST", capsBase + m_uploadBakedTexturePath, UploadBakedTexture));
138
139 }
140 catch (Exception e)
141 {
142 m_log.Error("[CAPS]: " + e.ToString());
143 }
144 }
145
146 public void RegisterInventoryServiceHandlers(string capsBase)
147 {
148 try
149 {
150 // I don't think this one works...
151 m_HostCapsObj.RegisterHandler("NewFileAgentInventory", new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>("POST",
152 capsBase + m_newInventory,
153 NewAgentInventoryRequest));
154 IRequestHandler req = new RestStreamHandler("POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory);
155 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
156 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
157 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
158
159 // As of RC 1.22.9 of the Linden client this is
160 // supported
161
162 //m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest);
163
164 // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and
165 // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires
166 // enhancements (probably filling out the folder part of the LLSD reply) to our CAPS service,
167 // but when I went on the Linden grid, the
168 // simulators I visited (version 1.21) were, surprisingly, no longer supplying this capability. Instead,
169 // the 1.19.1.4 client appeared to be happily flowing inventory data over UDP
170 //
171 // This is very probably just a temporary measure - once the CAPS service appears again on the Linden grid
172 // we will be
173 // able to get the data we need to implement the necessary part of the protocol to fix the issue above.
174 // m_capsHandlers["FetchInventoryDescendents"] =
175 // new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest);
176
177 // m_capsHandlers["FetchInventoryDescendents"] =
178 // new LLSDStreamhandler<LLSDFetchInventoryDescendents, LLSDInventoryDescendents>("POST",
179 // capsBase + m_fetchInventory,
180 // FetchInventory));
181 // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST",
182 // capsBase + m_requestTexture,
183 // RequestTexture);
184 }
185 catch (Exception e)
186 {
187 m_log.Error("[CAPS]: " + e.ToString());
188 }
189 }
190
191 /// <summary>
192 /// Construct a client response detailing all the capabilities this server can provide.
193 /// </summary>
194 /// <param name="request"></param>
195 /// <param name="path"></param>
196 /// <param name="param"></param>
197 /// <param name="httpRequest">HTTP request header object</param>
198 /// <param name="httpResponse">HTTP response header object</param>
199 /// <returns></returns>
200 public string SeedCapRequest(string request, string path, string param,
201 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
202 {
203 m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName);
204
205 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
206 {
207 m_log.DebugFormat("[CAPS]: Unauthorized CAPS client");
208 return string.Empty;
209 }
210
211 // WARNING: Add the external too
212 string result = LLSDHelpers.SerialiseLLSDReply(m_HostCapsObj.CapsHandlers.CapsDetails);
213
214 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result);
215
216 return result;
217 }
218
219 /// <summary>
220 /// Called by the script task update handler. Provides a URL to which the client can upload a new asset.
221 /// </summary>
222 /// <param name="request"></param>
223 /// <param name="path"></param>
224 /// <param name="param"></param>
225 /// <param name="httpRequest">HTTP request header object</param>
226 /// <param name="httpResponse">HTTP response header object</param>
227 /// <returns></returns>
228 public string ScriptTaskInventory(string request, string path, string param,
229 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
230 {
231 try
232 {
233 m_log.Debug("[CAPS]: ScriptTaskInventory Request in region: " + m_regionName);
234 //m_log.DebugFormat("[CAPS]: request: {0}, path: {1}, param: {2}", request, path, param);
235
236 Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
237 LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate();
238 LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest);
239
240 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
241 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
242
243 TaskInventoryScriptUpdater uploader =
244 new TaskInventoryScriptUpdater(
245 llsdUpdateRequest.item_id,
246 llsdUpdateRequest.task_id,
247 llsdUpdateRequest.is_script_running,
248 capsBase + uploaderPath,
249 m_HostCapsObj.HttpListener,
250 m_dumpAssetsToFile);
251 uploader.OnUpLoad += TaskScriptUpdated;
252
253 m_HostCapsObj.HttpListener.AddStreamHandler(new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
254
255 string protocol = "http://";
256
257 if (m_HostCapsObj.SSLCaps)
258 protocol = "https://";
259
260 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
261 uploaderPath;
262
263 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
264 uploadResponse.uploader = uploaderURL;
265 uploadResponse.state = "upload";
266
267 // m_log.InfoFormat("[CAPS]: " +
268 // "ScriptTaskInventory response: {0}",
269 // LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
270
271 return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
272 }
273 catch (Exception e)
274 {
275 m_log.Error("[CAPS]: " + e.ToString());
276 }
277
278 return null;
279 }
280
281 /// <summary>
282 /// Called when new asset data for an agent inventory item update has been uploaded.
283 /// </summary>
284 /// <param name="itemID">Item to update</param>
285 /// <param name="primID">Prim containing item to update</param>
286 /// <param name="isScriptRunning">Signals whether the script to update is currently running</param>
287 /// <param name="data">New asset data</param>
288 public void TaskScriptUpdated(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors)
289 {
290 if (TaskScriptUpdatedCall != null)
291 {
292 ArrayList e = TaskScriptUpdatedCall(m_HostCapsObj.AgentID, itemID, primID, isScriptRunning, data);
293 foreach (Object item in e)
294 errors.Add(item);
295 }
296 }
297
298 public string UploadBakedTexture(string request, string path,
299 string param, OSHttpRequest httpRequest,
300 OSHttpResponse httpResponse)
301 {
302 try
303 {
304 // m_log.Debug("[CAPS]: UploadBakedTexture Request in region: " +
305 // m_regionName);
306
307 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
308 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
309
310 BakedTextureUploader uploader =
311 new BakedTextureUploader(capsBase + uploaderPath, m_HostCapsObj.HttpListener);
312 uploader.OnUpLoad += BakedTextureUploaded;
313
314 m_HostCapsObj.HttpListener.AddStreamHandler(
315 new BinaryStreamHandler("POST", capsBase + uploaderPath,
316 uploader.uploaderCaps));
317
318 string protocol = "http://";
319
320 if (m_HostCapsObj.SSLCaps)
321 protocol = "https://";
322
323 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" +
324 m_HostCapsObj.Port.ToString() + capsBase + uploaderPath;
325
326 LLSDAssetUploadResponse uploadResponse =
327 new LLSDAssetUploadResponse();
328 uploadResponse.uploader = uploaderURL;
329 uploadResponse.state = "upload";
330
331 return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
332 }
333 catch (Exception e)
334 {
335 m_log.Error("[CAPS]: " + e.ToString());
336 }
337
338 return null;
339 }
340
341 public void BakedTextureUploaded(UUID assetID, byte[] data)
342 {
343 // m_log.WarnFormat("[CAPS]: Received baked texture {0}", assetID.ToString());
344
345 AssetBase asset;
346 asset = new AssetBase(assetID, "Baked Texture", (sbyte)AssetType.Texture, m_HostCapsObj.AgentID.ToString());
347 asset.Data = data;
348 asset.Temporary = true;
349 asset.Local = !m_persistBakedTextures; // Local assets aren't persisted, non-local are
350 m_assetCache.Store(asset);
351 }
352
353 /// <summary>
354 /// Called when new asset data for an agent inventory item update has been uploaded.
355 /// </summary>
356 /// <param name="itemID">Item to update</param>
357 /// <param name="data">New asset data</param>
358 /// <returns></returns>
359 public UUID ItemUpdated(UUID itemID, byte[] data)
360 {
361 if (ItemUpdatedCall != null)
362 {
363 return ItemUpdatedCall(m_HostCapsObj.AgentID, itemID, data);
364 }
365
366 return UUID.Zero;
367 }
368
369 /// <summary>
370 ///
371 /// </summary>
372 /// <param name="llsdRequest"></param>
373 /// <returns></returns>
374 public LLSDAssetUploadResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest)
375 {
376 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
377 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
378
379 if (llsdRequest.asset_type == "texture" ||
380 llsdRequest.asset_type == "animation" ||
381 llsdRequest.asset_type == "sound")
382 {
383 IClientAPI client = null;
384 IScene scene = null;
385 if (GetClient != null)
386 {
387 client = GetClient(m_HostCapsObj.AgentID);
388 scene = client.Scene;
389
390 IMoneyModule mm = scene.RequestModuleInterface<IMoneyModule>();
391
392 if (mm != null)
393 {
394 if (!mm.UploadCovered(client, mm.UploadCharge))
395 {
396 if (client != null)
397 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
398
399 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
400 errorResponse.uploader = "";
401 errorResponse.state = "error";
402 return errorResponse;
403 }
404 }
405 }
406 }
407
408 string assetName = llsdRequest.name;
409 string assetDes = llsdRequest.description;
410 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
411 UUID newAsset = UUID.Random();
412 UUID newInvItem = UUID.Random();
413 UUID parentFolder = llsdRequest.folder_id;
414 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
415
416 AssetUploader uploader =
417 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
418 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile);
419 m_HostCapsObj.HttpListener.AddStreamHandler(
420 new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
421
422 string protocol = "http://";
423
424 if (m_HostCapsObj.SSLCaps)
425 protocol = "https://";
426
427 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
428 uploaderPath;
429
430 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
431 uploadResponse.uploader = uploaderURL;
432 uploadResponse.state = "upload";
433 uploader.OnUpLoad += UploadCompleteHandler;
434 return uploadResponse;
435 }
436
437 /// <summary>
438 ///
439 /// </summary>
440 /// <param name="assetID"></param>
441 /// <param name="inventoryItem"></param>
442 /// <param name="data"></param>
443 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
444 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
445 string assetType)
446 {
447 sbyte assType = 0;
448 sbyte inType = 0;
449
450 if (inventoryType == "sound")
451 {
452 inType = 1;
453 assType = 1;
454 }
455 else if (inventoryType == "animation")
456 {
457 inType = 19;
458 assType = 20;
459 }
460 else if (inventoryType == "wearable")
461 {
462 inType = 18;
463 switch (assetType)
464 {
465 case "bodypart":
466 assType = 13;
467 break;
468 case "clothing":
469 assType = 5;
470 break;
471 }
472 }
473
474 AssetBase asset;
475 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString());
476 asset.Data = data;
477 if (AddNewAsset != null)
478 AddNewAsset(asset);
479 else if (m_assetCache != null)
480 m_assetCache.Store(asset);
481
482 InventoryItemBase item = new InventoryItemBase();
483 item.Owner = m_HostCapsObj.AgentID;
484 item.CreatorId = m_HostCapsObj.AgentID.ToString();
485 item.CreatorData = String.Empty;
486 item.ID = inventoryItem;
487 item.AssetID = asset.FullID;
488 item.Description = assetDescription;
489 item.Name = assetName;
490 item.AssetType = assType;
491 item.InvType = inType;
492 item.Folder = parentFolder;
493 item.CurrentPermissions = (uint)PermissionMask.All;
494 item.BasePermissions = (uint)PermissionMask.All;
495 item.EveryOnePermissions = 0;
496 item.NextPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer);
497 item.CreationDate = Util.UnixTimeSinceEpoch();
498
499 if (AddNewInventoryItem != null)
500 {
501 AddNewInventoryItem(m_HostCapsObj.AgentID, item);
502 }
503 }
504
505 /// <summary>
506 /// Processes a fetch inventory request and sends the reply
507
508 /// </summary>
509 /// <param name="request"></param>
510 /// <param name="path"></param>
511 /// <param name="param"></param>
512 /// <returns></returns>
513 // Request is like:
514 //<llsd>
515 // <map><key>folders</key>
516 // <array>
517 // <map>
518 // <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>
519 // </map>
520 // </array>
521 // </map>
522 //</llsd>
523 //
524 // multiple fetch-folder maps are allowed within the larger folders map.
525 public string FetchInventoryRequest(string request, string path, string param)
526 {
527 // string unmodifiedRequest = request.ToString();
528
529 //m_log.DebugFormat("[AGENT INVENTORY]: Received CAPS fetch inventory request {0}", unmodifiedRequest);
530 m_log.Debug("[CAPS]: Inventory Request in region: " + m_regionName);
531
532 Hashtable hash = new Hashtable();
533 try
534 {
535 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
536 }
537 catch (LLSD.LLSDParseException pe)
538 {
539 m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message);
540 m_log.Error("Request: " + request.ToString());
541 }
542
543 ArrayList foldersrequested = (ArrayList)hash["folders"];
544
545 string response = "";
546
547 for (int i = 0; i < foldersrequested.Count; i++)
548 {
549 string inventoryitemstr = "";
550 Hashtable inventoryhash = (Hashtable)foldersrequested[i];
551
552 LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
553 LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
554 LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest);
555
556 inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply);
557 inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
558 inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
559
560 response += inventoryitemstr;
561 }
562
563 if (response.Length == 0)
564 {
565 // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants.
566 // Therefore, I'm concluding that the client only has so many threads available to do requests
567 // and when a thread stalls.. is stays stalled.
568 // Therefore we need to return something valid
569 response = "<llsd><map><key>folders</key><array /></map></llsd>";
570 }
571 else
572 {
573 response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>";
574 }
575
576 //m_log.DebugFormat("[AGENT INVENTORY]: Replying to CAPS fetch inventory request with following xml");
577 //m_log.Debug(Util.GetFormattedXml(response));
578
579 return response;
580 }
581
582 public string FetchInventoryDescendentsRequest(string request, string path, string param, OSHttpRequest httpRequest, OSHttpResponse httpResponse)
583 {
584 // nasty temporary hack here, the linden client falsely
585 // identifies the uuid 00000000-0000-0000-0000-000000000000
586 // as a string which breaks us
587 //
588 // correctly mark it as a uuid
589 //
590 request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
591
592 // another hack <integer>1</integer> results in a
593 // System.ArgumentException: Object type System.Int32 cannot
594 // be converted to target type: System.Boolean
595 //
596 request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
597 request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
598
599 Hashtable hash = new Hashtable();
600 try
601 {
602 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
603 }
604 catch (LLSD.LLSDParseException pe)
605 {
606 m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message);
607 m_log.Error("Request: " + request.ToString());
608 }
609
610 ArrayList foldersrequested = (ArrayList)hash["folders"];
611
612 string response = "";
613 lock (m_fetchLock)
614 {
615 for (int i = 0; i < foldersrequested.Count; i++)
616 {
617 string inventoryitemstr = "";
618 Hashtable inventoryhash = (Hashtable)foldersrequested[i];
619
620 LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
621
622 try
623 {
624 LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
625 }
626 catch (Exception e)
627 {
628 m_log.Debug("[CAPS]: caught exception doing OSD deserialize" + e);
629 }
630 LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest);
631
632 inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply);
633 inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
634 inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
635
636 response += inventoryitemstr;
637 }
638
639
640 if (response.Length == 0)
641 {
642 // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants.
643 // Therefore, I'm concluding that the client only has so many threads available to do requests
644 // and when a thread stalls.. is stays stalled.
645 // Therefore we need to return something valid
646 response = "<llsd><map><key>folders</key><array /></map></llsd>";
647 }
648 else
649 {
650 response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>";
651 }
652
653 //m_log.DebugFormat("[CAPS]: Replying to CAPS fetch inventory request with following xml");
654 //m_log.Debug("[CAPS] "+response);
655
656 }
657 return response;
658 }
659
660
661
662 /// <summary>
663 /// Construct an LLSD reply packet to a CAPS inventory request
664 /// </summary>
665 /// <param name="invFetch"></param>
666 /// <returns></returns>
667 private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch)
668 {
669 LLSDInventoryDescendents reply = new LLSDInventoryDescendents();
670 LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents();
671 contents.agent_id = m_HostCapsObj.AgentID;
672 contents.owner_id = invFetch.owner_id;
673 contents.folder_id = invFetch.folder_id;
674
675 reply.folders.Array.Add(contents);
676 InventoryCollection inv = new InventoryCollection();
677 inv.Folders = new List<InventoryFolderBase>();
678 inv.Items = new List<InventoryItemBase>();
679 int version = 0;
680 if (CAPSFetchInventoryDescendents != null)
681 {
682 inv = CAPSFetchInventoryDescendents(m_HostCapsObj.AgentID, invFetch.folder_id, invFetch.owner_id, invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version);
683 }
684
685 if (inv.Folders != null)
686 {
687 foreach (InventoryFolderBase invFolder in inv.Folders)
688 {
689 contents.categories.Array.Add(ConvertInventoryFolder(invFolder));
690 }
691 }
692
693 if (inv.Items != null)
694 {
695 foreach (InventoryItemBase invItem in inv.Items)
696 {
697 contents.items.Array.Add(ConvertInventoryItem(invItem));
698 }
699 }
700
701 contents.descendents = contents.items.Array.Count + contents.categories.Array.Count;
702 contents.version = version;
703
704 return reply;
705 }
706
707 /// <summary>
708 /// Convert an internal inventory folder object into an LLSD object.
709 /// </summary>
710 /// <param name="invFolder"></param>
711 /// <returns></returns>
712 private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder)
713 {
714 LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder();
715 llsdFolder.folder_id = invFolder.ID;
716 llsdFolder.parent_id = invFolder.ParentID;
717 llsdFolder.name = invFolder.Name;
718 if (invFolder.Type < 0 || invFolder.Type >= TaskInventoryItem.Types.Length)
719 llsdFolder.type = "-1";
720 else
721 llsdFolder.type = TaskInventoryItem.Types[invFolder.Type];
722 llsdFolder.preferred_type = "-1";
723
724 return llsdFolder;
725 }
726
727 /// <summary>
728 /// Convert an internal inventory item object into an LLSD object.
729 /// </summary>
730 /// <param name="invItem"></param>
731 /// <returns></returns>
732 private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem)
733 {
734 LLSDInventoryItem llsdItem = new LLSDInventoryItem();
735 llsdItem.asset_id = invItem.AssetID;
736 llsdItem.created_at = invItem.CreationDate;
737 llsdItem.desc = invItem.Description;
738 llsdItem.flags = (int)invItem.Flags;
739 llsdItem.item_id = invItem.ID;
740 llsdItem.name = invItem.Name;
741 llsdItem.parent_id = invItem.Folder;
742 try
743 {
744 // TODO reevaluate after upgrade to libomv >= r2566. Probably should use UtilsConversions.
745 llsdItem.type = TaskInventoryItem.Types[invItem.AssetType];
746 llsdItem.inv_type = TaskInventoryItem.InvTypes[invItem.InvType];
747 }
748 catch (Exception e)
749 {
750 m_log.Error("[CAPS]: Problem setting asset/inventory type while converting inventory item " + invItem.Name + " to LLSD:", e);
751 }
752 llsdItem.permissions = new LLSDPermissions();
753 llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid;
754 llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions;
755 llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions;
756 llsdItem.permissions.group_id = invItem.GroupID;
757 llsdItem.permissions.group_mask = (int)invItem.GroupPermissions;
758 llsdItem.permissions.is_owner_group = invItem.GroupOwned;
759 llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions;
760 llsdItem.permissions.owner_id = m_HostCapsObj.AgentID;
761 llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions;
762 llsdItem.sale_info = new LLSDSaleInfo();
763 llsdItem.sale_info.sale_price = invItem.SalePrice;
764 switch (invItem.SaleType)
765 {
766 default:
767 llsdItem.sale_info.sale_type = "not";
768 break;
769 case 1:
770 llsdItem.sale_info.sale_type = "original";
771 break;
772 case 2:
773 llsdItem.sale_info.sale_type = "copy";
774 break;
775 case 3:
776 llsdItem.sale_info.sale_type = "contents";
777 break;
778 }
779
780 return llsdItem;
781 }
782
783 /// <summary>
784 ///
785 /// </summary>
786 /// <param name="mapReq"></param>
787 /// <returns></returns>
788 public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq)
789 {
790 m_log.Debug("[CAPS]: MapLayer Request in region: " + m_regionName);
791 LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
792 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
793 return mapResponse;
794 }
795
796 /// <summary>
797 ///
798 /// </summary>
799 /// <returns></returns>
800 protected static OSDMapLayer GetOSDMapLayerResponse()
801 {
802 OSDMapLayer mapLayer = new OSDMapLayer();
803 mapLayer.Right = 5000;
804 mapLayer.Top = 5000;
805 mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006");
806
807 return mapLayer;
808 }
809
810 /// <summary>
811 ///
812 /// </summary>
813 /// <param name="request"></param>
814 /// <param name="path"></param>
815 /// <param name="param"></param>
816 /// <returns></returns>
817 public string RequestTexture(string request, string path, string param)
818 {
819 m_log.Debug("texture request " + request);
820 // Needs implementing (added to remove compiler warning)
821 return String.Empty;
822 }
823
824
825 /// <summary>
826 /// Called by the notecard update handler. Provides a URL to which the client can upload a new asset.
827 /// </summary>
828 /// <param name="request"></param>
829 /// <param name="path"></param>
830 /// <param name="param"></param>
831 /// <returns></returns>
832 public string NoteCardAgentInventory(string request, string path, string param,
833 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
834 {
835 //m_log.Debug("[CAPS]: NoteCardAgentInventory Request in region: " + m_regionName + "\n" + request);
836 //m_log.Debug("[CAPS]: NoteCardAgentInventory Request is: " + request);
837
838 //OpenMetaverse.StructuredData.OSDMap hash = (OpenMetaverse.StructuredData.OSDMap)OpenMetaverse.StructuredData.LLSDParser.DeserializeBinary(Utils.StringToBytes(request));
839 Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
840 LLSDItemUpdate llsdRequest = new LLSDItemUpdate();
841 LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest);
842
843 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
844 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
845
846 ItemUpdater uploader =
847 new ItemUpdater(llsdRequest.item_id, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile);
848 uploader.OnUpLoad += ItemUpdated;
849
850 m_HostCapsObj.HttpListener.AddStreamHandler(
851 new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
852
853 string protocol = "http://";
854
855 if (m_HostCapsObj.SSLCaps)
856 protocol = "https://";
857
858 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
859 uploaderPath;
860
861 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
862 uploadResponse.uploader = uploaderURL;
863 uploadResponse.state = "upload";
864
865 // m_log.InfoFormat("[CAPS]: " +
866 // "NoteCardAgentInventory response: {0}",
867 // LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
868
869 return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
870 }
871 }
872
873 public class AssetUploader
874 {
875 public event UpLoadedAsset OnUpLoad;
876 private UpLoadedAsset handlerUpLoad = null;
877
878 private string uploaderPath = String.Empty;
879 private UUID newAssetID;
880 private UUID inventoryItemID;
881 private UUID parentFolder;
882 private IHttpServer httpListener;
883 private bool m_dumpAssetsToFile;
884 private string m_assetName = String.Empty;
885 private string m_assetDes = String.Empty;
886
887 private string m_invType = String.Empty;
888 private string m_assetType = String.Empty;
889
890 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
891 UUID parentFolderID, string invType, string assetType, string path,
892 IHttpServer httpServer, bool dumpAssetsToFile)
893 {
894 m_assetName = assetName;
895 m_assetDes = description;
896 newAssetID = assetID;
897 inventoryItemID = inventoryItem;
898 uploaderPath = path;
899 httpListener = httpServer;
900 parentFolder = parentFolderID;
901 m_assetType = assetType;
902 m_invType = invType;
903 m_dumpAssetsToFile = dumpAssetsToFile;
904 }
905
906 /// <summary>
907 ///
908 /// </summary>
909 /// <param name="data"></param>
910 /// <param name="path"></param>
911 /// <param name="param"></param>
912 /// <returns></returns>
913 public string uploaderCaps(byte[] data, string path, string param)
914 {
915 UUID inv = inventoryItemID;
916 string res = String.Empty;
917 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
918 uploadComplete.new_asset = newAssetID.ToString();
919 uploadComplete.new_inventory_item = inv;
920 uploadComplete.state = "complete";
921
922 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
923
924 httpListener.RemoveStreamHandler("POST", uploaderPath);
925
926 // TODO: probably make this a better set of extensions here
927 string extension = ".jp2";
928 if (m_invType != "image")
929 {
930 extension = ".dat";
931 }
932
933 if (m_dumpAssetsToFile)
934 {
935 SaveAssetToFile(m_assetName + extension, data);
936 }
937 handlerUpLoad = OnUpLoad;
938 if (handlerUpLoad != null)
939 {
940 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType);
941 }
942
943 return res;
944 }
945 ///Left this in and commented in case there are unforseen issues
946 //private void SaveAssetToFile(string filename, byte[] data)
947 //{
948 // FileStream fs = File.Create(filename);
949 // BinaryWriter bw = new BinaryWriter(fs);
950 // bw.Write(data);
951 // bw.Close();
952 // fs.Close();
953 //}
954 private static void SaveAssetToFile(string filename, byte[] data)
955 {
956 string assetPath = "UserAssets";
957 if (!Directory.Exists(assetPath))
958 {
959 Directory.CreateDirectory(assetPath);
960 }
961 FileStream fs = File.Create(Path.Combine(assetPath, Util.safeFileName(filename)));
962 BinaryWriter bw = new BinaryWriter(fs);
963 bw.Write(data);
964 bw.Close();
965 fs.Close();
966 }
967 }
968
969 /// <summary>
970 /// This class is a callback invoked when a client sends asset data to
971 /// an agent inventory notecard update url
972 /// </summary>
973 public class ItemUpdater
974 {
975 public event UpdateItem OnUpLoad;
976
977 private UpdateItem handlerUpdateItem = null;
978
979 private string uploaderPath = String.Empty;
980 private UUID inventoryItemID;
981 private IHttpServer httpListener;
982 private bool m_dumpAssetToFile;
983
984 public ItemUpdater(UUID inventoryItem, string path, IHttpServer httpServer, bool dumpAssetToFile)
985 {
986 m_dumpAssetToFile = dumpAssetToFile;
987
988 inventoryItemID = inventoryItem;
989 uploaderPath = path;
990 httpListener = httpServer;
991 }
992
993 /// <summary>
994 ///
995 /// </summary>
996 /// <param name="data"></param>
997 /// <param name="path"></param>
998 /// <param name="param"></param>
999 /// <returns></returns>
1000 public string uploaderCaps(byte[] data, string path, string param)
1001 {
1002 UUID inv = inventoryItemID;
1003 string res = String.Empty;
1004 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1005 UUID assetID = UUID.Zero;
1006 handlerUpdateItem = OnUpLoad;
1007 if (handlerUpdateItem != null)
1008 {
1009 assetID = handlerUpdateItem(inv, data);
1010 }
1011
1012 uploadComplete.new_asset = assetID.ToString();
1013 uploadComplete.new_inventory_item = inv;
1014 uploadComplete.state = "complete";
1015
1016 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1017
1018 httpListener.RemoveStreamHandler("POST", uploaderPath);
1019
1020 if (m_dumpAssetToFile)
1021 {
1022 SaveAssetToFile("updateditem" + Util.RandomClass.Next(1, 1000) + ".dat", data);
1023 }
1024
1025 return res;
1026 }
1027 ///Left this in and commented in case there are unforseen issues
1028 //private void SaveAssetToFile(string filename, byte[] data)
1029 //{
1030 // FileStream fs = File.Create(filename);
1031 // BinaryWriter bw = new BinaryWriter(fs);
1032 // bw.Write(data);
1033 // bw.Close();
1034 // fs.Close();
1035 //}
1036 private static void SaveAssetToFile(string filename, byte[] data)
1037 {
1038 string assetPath = "UserAssets";
1039 if (!Directory.Exists(assetPath))
1040 {
1041 Directory.CreateDirectory(assetPath);
1042 }
1043 FileStream fs = File.Create(Path.Combine(assetPath, filename));
1044 BinaryWriter bw = new BinaryWriter(fs);
1045 bw.Write(data);
1046 bw.Close();
1047 fs.Close();
1048 }
1049 }
1050
1051 /// <summary>
1052 /// This class is a callback invoked when a client sends asset data to
1053 /// a task inventory script update url
1054 /// </summary>
1055 public class TaskInventoryScriptUpdater
1056 {
1057 private static readonly ILog m_log =
1058 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1059
1060 public event UpdateTaskScript OnUpLoad;
1061
1062 private UpdateTaskScript handlerUpdateTaskScript = null;
1063
1064 private string uploaderPath = String.Empty;
1065 private UUID inventoryItemID;
1066 private UUID primID;
1067 private bool isScriptRunning;
1068 private IHttpServer httpListener;
1069 private bool m_dumpAssetToFile;
1070
1071 public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, int isScriptRunning,
1072 string path, IHttpServer httpServer, bool dumpAssetToFile)
1073 {
1074 m_dumpAssetToFile = dumpAssetToFile;
1075
1076 this.inventoryItemID = inventoryItemID;
1077 this.primID = primID;
1078
1079 // This comes in over the packet as an integer, but actually appears to be treated as a bool
1080 this.isScriptRunning = (0 == isScriptRunning ? false : true);
1081
1082 uploaderPath = path;
1083 httpListener = httpServer;
1084 }
1085
1086 /// <summary>
1087 ///
1088 /// </summary>
1089 /// <param name="data"></param>
1090 /// <param name="path"></param>
1091 /// <param name="param"></param>
1092 /// <returns></returns>
1093 public string uploaderCaps(byte[] data, string path, string param)
1094 {
1095 try
1096 {
1097 // m_log.InfoFormat("[CAPS]: " +
1098 // "TaskInventoryScriptUpdater received data: {0}, path: {1}, param: {2}",
1099 // data, path, param));
1100
1101 string res = String.Empty;
1102 LLSDTaskScriptUploadComplete uploadComplete = new LLSDTaskScriptUploadComplete();
1103
1104 ArrayList errors = new ArrayList();
1105 handlerUpdateTaskScript = OnUpLoad;
1106 if (handlerUpdateTaskScript != null)
1107 {
1108 handlerUpdateTaskScript(inventoryItemID, primID, isScriptRunning, data, ref errors);
1109 }
1110
1111 uploadComplete.new_asset = inventoryItemID;
1112 uploadComplete.compiled = errors.Count > 0 ? false : true;
1113 uploadComplete.state = "complete";
1114 uploadComplete.errors = new OSDArray();
1115 uploadComplete.errors.Array = errors;
1116
1117 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1118
1119 httpListener.RemoveStreamHandler("POST", uploaderPath);
1120
1121 if (m_dumpAssetToFile)
1122 {
1123 SaveAssetToFile("updatedtaskscript" + Util.RandomClass.Next(1, 1000) + ".dat", data);
1124 }
1125
1126 // m_log.InfoFormat("[CAPS]: TaskInventoryScriptUpdater.uploaderCaps res: {0}", res);
1127
1128 return res;
1129 }
1130 catch (Exception e)
1131 {
1132 m_log.Error("[CAPS]: " + e.ToString());
1133 }
1134
1135 // XXX Maybe this should be some meaningful error packet
1136 return null;
1137 }
1138 ///Left this in and commented in case there are unforseen issues
1139 //private void SaveAssetToFile(string filename, byte[] data)
1140 //{
1141 // FileStream fs = File.Create(filename);
1142 // BinaryWriter bw = new BinaryWriter(fs);
1143 // bw.Write(data);
1144 // bw.Close();
1145 // fs.Close();
1146 //}
1147 private static void SaveAssetToFile(string filename, byte[] data)
1148 {
1149 string assetPath = "UserAssets";
1150 if (!Directory.Exists(assetPath))
1151 {
1152 Directory.CreateDirectory(assetPath);
1153 }
1154 FileStream fs = File.Create(Path.Combine(assetPath, filename));
1155 BinaryWriter bw = new BinaryWriter(fs);
1156 bw.Write(data);
1157 bw.Close();
1158 fs.Close();
1159 }
1160 }
1161
1162 public class BakedTextureUploader
1163 {
1164 public event UploadedBakedTexture OnUpLoad;
1165 private UploadedBakedTexture handlerUpLoad = null;
1166
1167 private string uploaderPath = String.Empty;
1168 private UUID newAssetID;
1169 private IHttpServer httpListener;
1170
1171 public BakedTextureUploader(string path, IHttpServer httpServer)
1172 {
1173 newAssetID = UUID.Random();
1174 uploaderPath = path;
1175 httpListener = httpServer;
1176 // m_log.InfoFormat("[CAPS] baked texture upload starting for {0}",newAssetID);
1177 }
1178
1179 /// <summary>
1180 ///
1181 /// </summary>
1182 /// <param name="data"></param>
1183 /// <param name="path"></param>
1184 /// <param name="param"></param>
1185 /// <returns></returns>
1186 public string uploaderCaps(byte[] data, string path, string param)
1187 {
1188 handlerUpLoad = OnUpLoad;
1189 if (handlerUpLoad != null)
1190 {
1191 Util.FireAndForget(delegate(object o) { handlerUpLoad(newAssetID, data); });
1192 }
1193
1194 string res = String.Empty;
1195 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1196 uploadComplete.new_asset = newAssetID.ToString();
1197 uploadComplete.new_inventory_item = UUID.Zero;
1198 uploadComplete.state = "complete";
1199
1200 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1201
1202 httpListener.RemoveStreamHandler("POST", uploaderPath);
1203
1204 // m_log.InfoFormat("[CAPS] baked texture upload completed for {0}",newAssetID);
1205
1206 return res;
1207 }
1208 }
1209
1210}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs
new file mode 100644
index 0000000..4436d4c
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs
@@ -0,0 +1,87 @@
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.Generic;
30using System.Reflection;
31
32using log4net;
33using Nini.Config;
34using OpenMetaverse;
35
36using OpenSim.Framework;
37using OpenSim.Region.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using Caps = OpenSim.Framework.Capabilities.Caps;
41
42namespace OpenSim.Region.ClientStack.Linden
43{
44
45 public class BunchOfCapsModule : INonSharedRegionModule
46 {
47 private static readonly ILog m_log =
48 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 private Scene m_Scene;
51
52 #region INonSharedRegionModule
53
54 public string Name { get { return "BunchOfCapsModule"; } }
55
56 public Type ReplaceableInterface { get { return null; } }
57
58 public void Initialise(IConfigSource source)
59 {
60 }
61
62 public void Close() { }
63
64 public void AddRegion(Scene scene)
65 {
66 m_Scene = scene;
67 m_Scene.EventManager.OnRegisterCaps += OnRegisterCaps;
68 }
69
70 public void RemoveRegion(Scene scene)
71 {
72 }
73
74 public void RegionLoaded(Scene scene)
75 {
76 }
77
78 public void PostInitialise() { }
79 #endregion
80
81 private void OnRegisterCaps(UUID agentID, Caps caps)
82 {
83 new BunchOfCaps(m_Scene, caps);
84 }
85
86 }
87}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index 4827baa..4920347 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -522,7 +522,7 @@ namespace OpenSim.Region.ClientStack.Linden
522 } 522 }
523 if (AvatarID != UUID.Zero) 523 if (AvatarID != UUID.Zero)
524 { 524 {
525 return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsHandlerForUser(AvatarID)); 525 return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID));
526 } 526 }
527 else 527 else
528 { 528 {
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
index eddc288..b7e79cc 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
@@ -171,8 +171,8 @@ namespace OpenSim.Region.ClientStack.Linden
171 UUID parentFolder = llsdRequest.folder_id; 171 UUID parentFolder = llsdRequest.folder_id;
172 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/"; 172 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/";
173 173
174 Caps.AssetUploader uploader = 174 AssetUploader uploader =
175 new Caps.AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 175 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
176 llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile); 176 llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile);
177 MainServer.Instance.AddStreamHandler( 177 MainServer.Instance.AddStreamHandler(
178 new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); 178 new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
index e684a0d..5e22c8c 100644
--- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
@@ -51,7 +51,7 @@ namespace OpenSim.Region.CoreModules.Framework
51 /// <summary> 51 /// <summary>
52 /// Each agent has its own capabilities handler. 52 /// Each agent has its own capabilities handler.
53 /// </summary> 53 /// </summary>
54 protected Dictionary<UUID, Caps> m_capsHandlers = new Dictionary<UUID, Caps>(); 54 protected Dictionary<UUID, Caps> m_capsObjects = new Dictionary<UUID, Caps>();
55 55
56 protected Dictionary<UUID, string> capsPaths = new Dictionary<UUID, string>(); 56 protected Dictionary<UUID, string> capsPaths = new Dictionary<UUID, string>();
57 protected Dictionary<UUID, Dictionary<ulong, string>> childrenSeeds 57 protected Dictionary<UUID, Dictionary<ulong, string>> childrenSeeds
@@ -95,19 +95,19 @@ namespace OpenSim.Region.CoreModules.Framework
95 get { return null; } 95 get { return null; }
96 } 96 }
97 97
98 public void AddCapsHandler(UUID agentId) 98 public void CreateCaps(UUID agentId)
99 { 99 {
100 if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId)) 100 if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId))
101 return; 101 return;
102 102
103 String capsObjectPath = GetCapsPath(agentId); 103 String capsObjectPath = GetCapsPath(agentId);
104 104
105 if (m_capsHandlers.ContainsKey(agentId)) 105 if (m_capsObjects.ContainsKey(agentId))
106 { 106 {
107 Caps oldCaps = m_capsHandlers[agentId]; 107 Caps oldCaps = m_capsObjects[agentId];
108 108
109 m_log.DebugFormat( 109 m_log.DebugFormat(
110 "[CAPS]: Reregistering caps for agent {0}. Old caps path {1}, new caps path {2}. ", 110 "[CAPS]: Recreating caps for agent {0}. Old caps path {1}, new caps path {2}. ",
111 agentId, oldCaps.CapsObjectPath, capsObjectPath); 111 agentId, oldCaps.CapsObjectPath, capsObjectPath);
112 // This should not happen. The caller code is confused. We need to fix that. 112 // This should not happen. The caller code is confused. We need to fix that.
113 // CAPs can never be reregistered, or the client will be confused. 113 // CAPs can never be reregistered, or the client will be confused.
@@ -115,39 +115,29 @@ namespace OpenSim.Region.CoreModules.Framework
115 //return; 115 //return;
116 } 116 }
117 117
118 Caps caps 118 Caps caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName,
119 = new Caps(m_scene,
120 m_scene.AssetService, MainServer.Instance, m_scene.RegionInfo.ExternalHostName,
121 (MainServer.Instance == null) ? 0: MainServer.Instance.Port, 119 (MainServer.Instance == null) ? 0: MainServer.Instance.Port,
122 capsObjectPath, agentId, m_scene.DumpAssetsToFile, m_scene.RegionInfo.RegionName); 120 capsObjectPath, agentId, m_scene.RegionInfo.RegionName);
123 121
124 caps.RegisterHandlers(); 122 m_capsObjects[agentId] = caps;
125 123
126 m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps); 124 m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps);
127
128 caps.AddNewInventoryItem = m_scene.AddUploadedInventoryItem;
129 caps.ItemUpdatedCall = m_scene.CapsUpdateInventoryItemAsset;
130 caps.TaskScriptUpdatedCall = m_scene.CapsUpdateTaskInventoryScriptAsset;
131 caps.CAPSFetchInventoryDescendents = m_scene.HandleFetchInventoryDescendentsCAPS;
132 caps.GetClient = m_scene.SceneContents.GetControllingClient;
133
134 m_capsHandlers[agentId] = caps;
135 } 125 }
136 126
137 public void RemoveCapsHandler(UUID agentId) 127 public void RemoveCaps(UUID agentId)
138 { 128 {
139 if (childrenSeeds.ContainsKey(agentId)) 129 if (childrenSeeds.ContainsKey(agentId))
140 { 130 {
141 childrenSeeds.Remove(agentId); 131 childrenSeeds.Remove(agentId);
142 } 132 }
143 133
144 lock (m_capsHandlers) 134 lock (m_capsObjects)
145 { 135 {
146 if (m_capsHandlers.ContainsKey(agentId)) 136 if (m_capsObjects.ContainsKey(agentId))
147 { 137 {
148 m_capsHandlers[agentId].DeregisterHandlers(); 138 m_capsObjects[agentId].DeregisterHandlers();
149 m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsHandlers[agentId]); 139 m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsObjects[agentId]);
150 m_capsHandlers.Remove(agentId); 140 m_capsObjects.Remove(agentId);
151 } 141 }
152 else 142 else
153 { 143 {
@@ -158,20 +148,20 @@ namespace OpenSim.Region.CoreModules.Framework
158 } 148 }
159 } 149 }
160 150
161 public Caps GetCapsHandlerForUser(UUID agentId) 151 public Caps GetCapsForUser(UUID agentId)
162 { 152 {
163 lock (m_capsHandlers) 153 lock (m_capsObjects)
164 { 154 {
165 if (m_capsHandlers.ContainsKey(agentId)) 155 if (m_capsObjects.ContainsKey(agentId))
166 { 156 {
167 return m_capsHandlers[agentId]; 157 return m_capsObjects[agentId];
168 } 158 }
169 } 159 }
170 160
171 return null; 161 return null;
172 } 162 }
173 163
174 public void NewUserConnection(AgentCircuitData agent) 164 public void SetAgentCapsSeeds(AgentCircuitData agent)
175 { 165 {
176 capsPaths[agent.AgentID] = agent.CapsPath; 166 capsPaths[agent.AgentID] = agent.CapsPath;
177 childrenSeeds[agent.AgentID] 167 childrenSeeds[agent.AgentID]
@@ -241,7 +231,7 @@ namespace OpenSim.Region.CoreModules.Framework
241 System.Text.StringBuilder caps = new System.Text.StringBuilder(); 231 System.Text.StringBuilder caps = new System.Text.StringBuilder();
242 caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); 232 caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName);
243 233
244 foreach (KeyValuePair<UUID, Caps> kvp in m_capsHandlers) 234 foreach (KeyValuePair<UUID, Caps> kvp in m_capsObjects)
245 { 235 {
246 caps.AppendFormat("** User {0}:\n", kvp.Key); 236 caps.AppendFormat("** User {0}:\n", kvp.Key);
247 for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.CapsDetails.GetEnumerator(); kvp2.MoveNext(); ) 237 for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.CapsDetails.GetEnumerator(); kvp2.MoveNext(); )
diff --git a/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs b/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs
index 2dd7767..07999d1 100644
--- a/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs
+++ b/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs
@@ -575,7 +575,7 @@ namespace OpenSim.Region.CoreModules.InterGrid
575 string derezAvatarPath = "/agent/" + AvatarRezCapUUID + "/rez_avatar/derez"; 575 string derezAvatarPath = "/agent/" + AvatarRezCapUUID + "/rez_avatar/derez";
576 // Get a reference to the user's cap so we can pull out the Caps Object Path 576 // Get a reference to the user's cap so we can pull out the Caps Object Path
577 Caps userCap 577 Caps userCap
578 = homeScene.CapsModule.GetCapsHandlerForUser(agentData.AgentID); 578 = homeScene.CapsModule.GetCapsForUser(agentData.AgentID);
579 579
580 string rezHttpProtocol = "http://"; 580 string rezHttpProtocol = "http://";
581 string regionCapsHttpProtocol = "http://"; 581 string regionCapsHttpProtocol = "http://";
@@ -700,7 +700,7 @@ namespace OpenSim.Region.CoreModules.InterGrid
700 { 700 {
701 // Get a referenceokay - to their Cap object so we can pull out the capobjectroot 701 // Get a referenceokay - to their Cap object so we can pull out the capobjectroot
702 Caps userCap 702 Caps userCap
703 = homeScene.CapsModule.GetCapsHandlerForUser(userData.AgentID); 703 = homeScene.CapsModule.GetCapsForUser(userData.AgentID);
704 704
705 //Update the circuit data in the region so this user is authorized 705 //Update the circuit data in the region so this user is authorized
706 homeScene.UpdateCircuitData(userData); 706 homeScene.UpdateCircuitData(userData);
diff --git a/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs b/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs
index 73bffa0..522c82d 100644
--- a/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs
@@ -34,31 +34,27 @@ namespace OpenSim.Region.Framework.Interfaces
34{ 34{
35 public interface ICapabilitiesModule 35 public interface ICapabilitiesModule
36 { 36 {
37 void NewUserConnection(AgentCircuitData agent);
38
39 /// <summary> 37 /// <summary>
40 /// Add a caps handler for the given agent. If the CAPS handler already exists for this agent, 38 /// Add a caps handler for the given agent. If the CAPS handler already exists for this agent,
41 /// then it is replaced by a new CAPS handler. 39 /// then it is replaced by a new CAPS handler.
42 ///
43 /// FIXME: On login this is called twice, once for the login and once when the connection is made.
44 /// This is somewhat innefficient and should be fixed. The initial login creation is necessary
45 /// since the client asks for capabilities immediately after being informed of the seed.
46 /// </summary> 40 /// </summary>
47 /// <param name="agentId"></param> 41 /// <param name="agentId"></param>
48 /// <param name="capsObjectPath"></param> 42 /// <param name="capsObjectPath"></param>
49 void AddCapsHandler(UUID agentId); 43 void CreateCaps(UUID agentId);
50 44
51 /// <summary> 45 /// <summary>
52 /// Remove the caps handler for a given agent. 46 /// Remove the caps handler for a given agent.
53 /// </summary> 47 /// </summary>
54 /// <param name="agentId"></param> 48 /// <param name="agentId"></param>
55 void RemoveCapsHandler(UUID agentId); 49 void RemoveCaps(UUID agentId);
56 50
57 /// <summary> 51 /// <summary>
58 /// Will return null if the agent doesn't have a caps handler registered 52 /// Will return null if the agent doesn't have a caps handler registered
59 /// </summary> 53 /// </summary>
60 /// <param name="agentId"></param> 54 /// <param name="agentId"></param>
61 Caps GetCapsHandlerForUser(UUID agentId); 55 Caps GetCapsForUser(UUID agentId);
56
57 void SetAgentCapsSeeds(AgentCircuitData agent);
62 58
63 Dictionary<ulong, string> GetChildrenSeeds(UUID agentID); 59 Dictionary<ulong, string> GetChildrenSeeds(UUID agentID);
64 60
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 7c5e246..b537381 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -3033,7 +3033,7 @@ namespace OpenSim.Region.Framework.Scenes
3033 m_sceneGraph.removeUserCount(!childagentYN); 3033 m_sceneGraph.removeUserCount(!childagentYN);
3034 3034
3035 if (CapsModule != null) 3035 if (CapsModule != null)
3036 CapsModule.RemoveCapsHandler(agentID); 3036 CapsModule.RemoveCaps(agentID);
3037 3037
3038 // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever 3038 // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
3039 // this method is doing is HORRIBLE!!! 3039 // this method is doing is HORRIBLE!!!
@@ -3290,8 +3290,8 @@ namespace OpenSim.Region.Framework.Scenes
3290 3290
3291 if (CapsModule != null) 3291 if (CapsModule != null)
3292 { 3292 {
3293 CapsModule.NewUserConnection(agent); 3293 CapsModule.SetAgentCapsSeeds(agent);
3294 CapsModule.AddCapsHandler(agent.AgentID); 3294 CapsModule.CreateCaps(agent.AgentID);
3295 } 3295 }
3296 } 3296 }
3297 else 3297 else
@@ -3309,7 +3309,7 @@ namespace OpenSim.Region.Framework.Scenes
3309 sp.AdjustKnownSeeds(); 3309 sp.AdjustKnownSeeds();
3310 3310
3311 if (CapsModule != null) 3311 if (CapsModule != null)
3312 CapsModule.NewUserConnection(agent); 3312 CapsModule.SetAgentCapsSeeds(agent);
3313 } 3313 }
3314 } 3314 }
3315 3315