clockwerk-opensim-stable – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.IO;
32 using System.Reflection;
33 using System.Text;
34  
35 using OpenMetaverse;
36 using OpenMetaverse.StructuredData;
37 using Nini.Config;
38 using log4net;
39  
40 using OpenSim.Framework;
41 using OpenSim.Framework.Capabilities;
42 using OpenSim.Region.Framework;
43 using OpenSim.Region.Framework.Scenes;
44 using OpenSim.Region.Framework.Scenes.Serialization;
45 using OpenSim.Framework.Servers;
46 using OpenSim.Framework.Servers.HttpServer;
47 using OpenSim.Services.Interfaces;
48  
49 using Caps = OpenSim.Framework.Capabilities.Caps;
50 using OSDArray = OpenMetaverse.StructuredData.OSDArray;
51 using OSDMap = OpenMetaverse.StructuredData.OSDMap;
52 using PermissionMask = OpenSim.Framework.PermissionMask;
53  
54 namespace OpenSim.Region.ClientStack.Linden
55 {
56 public delegate void UpLoadedAsset(
57 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
58 byte[] data, string inventoryType, string assetType);
59  
60 public delegate UUID UpdateItem(UUID itemID, byte[] data);
61  
62 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
63  
64 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item);
65  
66 public delegate void NewAsset(AssetBase asset);
67  
68 public delegate UUID ItemUpdatedCallback(UUID userID, UUID itemID, byte[] data);
69  
70 public delegate ArrayList TaskScriptUpdatedCallback(UUID userID, UUID itemID, UUID primID,
71 bool isScriptRunning, byte[] data);
72  
73 public delegate InventoryCollection FetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID,
74 bool fetchFolders, bool fetchItems, int sortOrder, out int version);
75  
76 /// <summary>
77 /// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that
78 /// we can popup a message on the user's client if the inventory service has permanently failed). But I didn't want
79 /// to just pass the whole Scene into CAPS.
80 /// </summary>
81 public delegate IClientAPI GetClientDelegate(UUID agentID);
82  
83 public class BunchOfCaps
84 {
85 private static readonly ILog m_log =
86 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
87  
88 private Scene m_Scene;
89 private Caps m_HostCapsObj;
90  
91 private static readonly string m_requestPath = "0000/";
92 // private static readonly string m_mapLayerPath = "0001/";
93 private static readonly string m_newInventory = "0002/";
94 //private static readonly string m_requestTexture = "0003/";
95 private static readonly string m_notecardUpdatePath = "0004/";
96 private static readonly string m_notecardTaskUpdatePath = "0005/";
97 // private static readonly string m_fetchInventoryPath = "0006/";
98 private static readonly string m_copyFromNotecardPath = "0007/";
99 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
100 private static readonly string m_getObjectPhysicsDataPath = "0101/";
101 /* 0102 - 0103 RESERVED */
102 private static readonly string m_UpdateAgentInformationPath = "0500/";
103  
104 // These are callbacks which will be setup by the scene so that we can update scene data when we
105 // receive capability calls
106 public NewInventoryItem AddNewInventoryItem = null;
107 public NewAsset AddNewAsset = null;
108 public ItemUpdatedCallback ItemUpdatedCall = null;
109 public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null;
110 public FetchInventoryDescendentsCAPS CAPSFetchInventoryDescendents = null;
111 public GetClientDelegate GetClient = null;
112  
113 private bool m_persistBakedTextures = false;
114 private IAssetService m_assetService;
115 private bool m_dumpAssetsToFile = false;
116 private string m_regionName;
117 private int m_levelUpload = 0;
118  
119 public BunchOfCaps(Scene scene, Caps caps)
120 {
121 m_Scene = scene;
122 m_HostCapsObj = caps;
123 IConfigSource config = m_Scene.Config;
124 if (config != null)
125 {
126 IConfig sconfig = config.Configs["Startup"];
127 if (sconfig != null)
128 {
129 m_levelUpload = sconfig.GetInt("LevelUpload", 0);
130 }
131  
132 IConfig appearanceConfig = config.Configs["Appearance"];
133 if (appearanceConfig != null)
134 {
135 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
136 }
137 }
138  
139 m_assetService = m_Scene.AssetService;
140 m_regionName = m_Scene.RegionInfo.RegionName;
141  
142 RegisterHandlers();
143  
144 AddNewInventoryItem = m_Scene.AddUploadedInventoryItem;
145 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
146 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
147 GetClient = m_Scene.SceneGraph.GetControllingClient;
148 }
149  
150 /// <summary>
151 /// Register a bunch of CAPS http service handlers
152 /// </summary>
153 public void RegisterHandlers()
154 {
155 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
156  
157 RegisterRegionServiceHandlers(capsBase);
158 RegisterInventoryServiceHandlers(capsBase);
159 }
160  
161 public void RegisterRegionServiceHandlers(string capsBase)
162 {
163 try
164 {
165 // the root of all evil
166 m_HostCapsObj.RegisterHandler(
167 "SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null));
168  
169 // m_log.DebugFormat(
170 // "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
171  
172 //m_capsHandlers["MapLayer"] =
173 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
174 // capsBase + m_mapLayerPath,
175 // GetMapLayer);
176 IRequestHandler req
177 = new RestStreamHandler(
178 "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null);
179  
180 m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req);
181 m_HostCapsObj.RegisterHandler("UpdateScriptTask", req);
182 }
183 catch (Exception e)
184 {
185 m_log.Error("[CAPS]: " + e.ToString());
186 }
187 }
188  
189 public void RegisterInventoryServiceHandlers(string capsBase)
190 {
191 try
192 {
193 // I don't think this one works...
194 m_HostCapsObj.RegisterHandler(
195 "NewFileAgentInventory",
196 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>(
197 "POST",
198 capsBase + m_newInventory,
199 NewAgentInventoryRequest,
200 "NewFileAgentInventory",
201 null));
202  
203 IRequestHandler req
204 = new RestStreamHandler(
205 "POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory, "Update*", null);
206  
207 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
208 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
209 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
210  
211 IRequestHandler getObjectPhysicsDataHandler
212 = new RestStreamHandler(
213 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null);
214 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
215  
216 IRequestHandler UpdateAgentInformationHandler
217 = new RestStreamHandler(
218 "POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation, "UpdateAgentInformation", null);
219 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
220  
221 m_HostCapsObj.RegisterHandler(
222 "CopyInventoryFromNotecard",
223 new RestStreamHandler(
224 "POST", capsBase + m_copyFromNotecardPath, CopyInventoryFromNotecard, "CopyInventoryFromNotecard", null));
225  
226 // As of RC 1.22.9 of the Linden client this is
227 // supported
228  
229 //m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest);
230  
231 // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and
232 // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires
233 // enhancements (probably filling out the folder part of the LLSD reply) to our CAPS service,
234 // but when I went on the Linden grid, the
235 // simulators I visited (version 1.21) were, surprisingly, no longer supplying this capability. Instead,
236 // the 1.19.1.4 client appeared to be happily flowing inventory data over UDP
237 //
238 // This is very probably just a temporary measure - once the CAPS service appears again on the Linden grid
239 // we will be
240 // able to get the data we need to implement the necessary part of the protocol to fix the issue above.
241 // m_capsHandlers["FetchInventoryDescendents"] =
242 // new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest);
243  
244 // m_capsHandlers["FetchInventoryDescendents"] =
245 // new LLSDStreamhandler<LLSDFetchInventoryDescendents, LLSDInventoryDescendents>("POST",
246 // capsBase + m_fetchInventory,
247 // FetchInventory));
248 // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST",
249 // capsBase + m_requestTexture,
250 // RequestTexture);
251 }
252 catch (Exception e)
253 {
254 m_log.Error("[CAPS]: " + e.ToString());
255 }
256 }
257  
258 /// <summary>
259 /// Construct a client response detailing all the capabilities this server can provide.
260 /// </summary>
261 /// <param name="request"></param>
262 /// <param name="path"></param>
263 /// <param name="param"></param>
264 /// <param name="httpRequest">HTTP request header object</param>
265 /// <param name="httpResponse">HTTP response header object</param>
266 /// <returns></returns>
267 public string SeedCapRequest(string request, string path, string param,
268 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
269 {
270 m_log.DebugFormat(
271 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
272  
273 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
274 {
275 m_log.WarnFormat(
276 "[CAPS]: Unauthorized CAPS client {0} from {1}",
277 m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint);
278  
279 return string.Empty;
280 }
281  
282 OSDArray capsRequested = (OSDArray)OSDParser.DeserializeLLSDXml(request);
283 List<string> validCaps = new List<string>();
284  
285 foreach (OSD c in capsRequested)
286 validCaps.Add(c.AsString());
287  
288 string result = LLSDHelpers.SerialiseLLSDReply(m_HostCapsObj.GetCapsDetails(true, validCaps));
289  
290 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result);
291  
292 return result;
293 }
294  
295 /// <summary>
296 /// Called by the script task update handler. Provides a URL to which the client can upload a new asset.
297 /// </summary>
298 /// <param name="request"></param>
299 /// <param name="path"></param>
300 /// <param name="param"></param>
301 /// <param name="httpRequest">HTTP request header object</param>
302 /// <param name="httpResponse">HTTP response header object</param>
303 /// <returns></returns>
304 public string ScriptTaskInventory(string request, string path, string param,
305 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
306 {
307 try
308 {
309 // m_log.Debug("[CAPS]: ScriptTaskInventory Request in region: " + m_regionName);
310 //m_log.DebugFormat("[CAPS]: request: {0}, path: {1}, param: {2}", request, path, param);
311  
312 Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
313 LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate();
314 LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest);
315  
316 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
317 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
318  
319 TaskInventoryScriptUpdater uploader =
320 new TaskInventoryScriptUpdater(
321 llsdUpdateRequest.item_id,
322 llsdUpdateRequest.task_id,
323 llsdUpdateRequest.is_script_running,
324 capsBase + uploaderPath,
325 m_HostCapsObj.HttpListener,
326 m_dumpAssetsToFile);
327 uploader.OnUpLoad += TaskScriptUpdated;
328  
329 m_HostCapsObj.HttpListener.AddStreamHandler(
330 new BinaryStreamHandler(
331 "POST", capsBase + uploaderPath, uploader.uploaderCaps, "TaskInventoryScriptUpdater", null));
332  
333 string protocol = "http://";
334  
335 if (m_HostCapsObj.SSLCaps)
336 protocol = "https://";
337  
338 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
339 uploaderPath;
340  
341 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
342 uploadResponse.uploader = uploaderURL;
343 uploadResponse.state = "upload";
344  
345 // m_log.InfoFormat("[CAPS]: " +
346 // "ScriptTaskInventory response: {0}",
347 // LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
348  
349 return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
350 }
351 catch (Exception e)
352 {
353 m_log.Error("[CAPS]: " + e.ToString());
354 }
355  
356 return null;
357 }
358  
359 /// <summary>
360 /// Called when new asset data for an agent inventory item update has been uploaded.
361 /// </summary>
362 /// <param name="itemID">Item to update</param>
363 /// <param name="primID">Prim containing item to update</param>
364 /// <param name="isScriptRunning">Signals whether the script to update is currently running</param>
365 /// <param name="data">New asset data</param>
366 public void TaskScriptUpdated(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors)
367 {
368 if (TaskScriptUpdatedCall != null)
369 {
370 ArrayList e = TaskScriptUpdatedCall(m_HostCapsObj.AgentID, itemID, primID, isScriptRunning, data);
371 foreach (Object item in e)
372 errors.Add(item);
373 }
374 }
375  
376 /// <summary>
377 /// Called when new asset data for an agent inventory item update has been uploaded.
378 /// </summary>
379 /// <param name="itemID">Item to update</param>
380 /// <param name="data">New asset data</param>
381 /// <returns></returns>
382 public UUID ItemUpdated(UUID itemID, byte[] data)
383 {
384 if (ItemUpdatedCall != null)
385 {
386 return ItemUpdatedCall(m_HostCapsObj.AgentID, itemID, data);
387 }
388  
389 return UUID.Zero;
390 }
391  
392 /// <summary>
393 ///
394 /// </summary>
395 /// <param name="llsdRequest"></param>
396 /// <returns></returns>
397 public LLSDAssetUploadResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest)
398 {
399 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
400 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
401  
402 if (llsdRequest.asset_type == "texture" ||
403 llsdRequest.asset_type == "animation" ||
404 llsdRequest.asset_type == "sound")
405 {
406 ScenePresence avatar = null;
407 IClientAPI client = null;
408 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
409  
410 // check user level
411 if (avatar != null)
412 {
413 client = avatar.ControllingClient;
414  
415 if (avatar.UserLevel < m_levelUpload)
416 {
417 if (client != null)
418 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false);
419  
420 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
421 errorResponse.uploader = "";
422 errorResponse.state = "error";
423 return errorResponse;
424 }
425 }
426  
427 // check funds
428 if (client != null)
429 {
430 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
431  
432 if (mm != null)
433 {
434 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge))
435 {
436 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
437  
438 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
439 errorResponse.uploader = "";
440 errorResponse.state = "error";
441 return errorResponse;
442 }
443 }
444 }
445 }
446  
447 string assetName = llsdRequest.name;
448 string assetDes = llsdRequest.description;
449 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
450 UUID newAsset = UUID.Random();
451 UUID newInvItem = UUID.Random();
452 UUID parentFolder = llsdRequest.folder_id;
453 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
454  
455 AssetUploader uploader =
456 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
457 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile);
458  
459 m_HostCapsObj.HttpListener.AddStreamHandler(
460 new BinaryStreamHandler(
461 "POST",
462 capsBase + uploaderPath,
463 uploader.uploaderCaps,
464 "NewAgentInventoryRequest",
465 m_HostCapsObj.AgentID.ToString()));
466  
467 string protocol = "http://";
468  
469 if (m_HostCapsObj.SSLCaps)
470 protocol = "https://";
471  
472 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
473 uploaderPath;
474  
475 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
476 uploadResponse.uploader = uploaderURL;
477 uploadResponse.state = "upload";
478 uploader.OnUpLoad += UploadCompleteHandler;
479 return uploadResponse;
480 }
481  
482 /// <summary>
483 /// Convert raw uploaded data into the appropriate asset and item.
484 /// </summary>
485 /// <param name="assetID"></param>
486 /// <param name="inventoryItem"></param>
487 /// <param name="data"></param>
488 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
489 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
490 string assetType)
491 {
492 m_log.DebugFormat(
493 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
494 assetID, inventoryItem, inventoryType, assetType);
495  
496 sbyte assType = 0;
497 sbyte inType = 0;
498  
499 if (inventoryType == "sound")
500 {
501 inType = 1;
502 assType = 1;
503 }
504 else if (inventoryType == "animation")
505 {
506 inType = 19;
507 assType = 20;
508 }
509 else if (inventoryType == "wearable")
510 {
511 inType = 18;
512 switch (assetType)
513 {
514 case "bodypart":
515 assType = 13;
516 break;
517 case "clothing":
518 assType = 5;
519 break;
520 }
521 }
522 else if (inventoryType == "object")
523 {
524 inType = (sbyte)InventoryType.Object;
525 assType = (sbyte)AssetType.Object;
526  
527 List<Vector3> positions = new List<Vector3>();
528 List<Quaternion> rotations = new List<Quaternion>();
529 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
530 OSDArray instance_list = (OSDArray)request["instance_list"];
531 OSDArray mesh_list = (OSDArray)request["mesh_list"];
532 OSDArray texture_list = (OSDArray)request["texture_list"];
533 SceneObjectGroup grp = null;
534  
535 List<UUID> textures = new List<UUID>();
536 for (int i = 0; i < texture_list.Count; i++)
537 {
538 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, "");
539 textureAsset.Data = texture_list[i].AsBinary();
540 m_assetService.Store(textureAsset);
541 textures.Add(textureAsset.FullID);
542 }
543  
544 for (int i = 0; i < mesh_list.Count; i++)
545 {
546 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
547  
548 Primitive.TextureEntry textureEntry
549 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
550 OSDMap inner_instance_list = (OSDMap)instance_list[i];
551  
552 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
553 for (uint face = 0; face < face_list.Count; face++)
554 {
555 OSDMap faceMap = (OSDMap)face_list[(int)face];
556 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
557 if(faceMap.ContainsKey("fullbright"))
558 f.Fullbright = faceMap["fullbright"].AsBoolean();
559 if (faceMap.ContainsKey ("diffuse_color"))
560 f.RGBA = faceMap["diffuse_color"].AsColor4();
561  
562 int textureNum = faceMap["image"].AsInteger();
563 float imagerot = faceMap["imagerot"].AsInteger();
564 float offsets = (float)faceMap["offsets"].AsReal();
565 float offsett = (float)faceMap["offsett"].AsReal();
566 float scales = (float)faceMap["scales"].AsReal();
567 float scalet = (float)faceMap["scalet"].AsReal();
568  
569 if(imagerot != 0)
570 f.Rotation = imagerot;
571  
572 if(offsets != 0)
573 f.OffsetU = offsets;
574  
575 if (offsett != 0)
576 f.OffsetV = offsett;
577  
578 if (scales != 0)
579 f.RepeatU = scales;
580  
581 if (scalet != 0)
582 f.RepeatV = scalet;
583  
584 if (textures.Count > textureNum)
585 f.TextureID = textures[textureNum];
586 else
587 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
588  
589 textureEntry.FaceTextures[face] = f;
590 }
591  
592 pbs.TextureEntry = textureEntry.GetBytes();
593  
594 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, "");
595 meshAsset.Data = mesh_list[i].AsBinary();
596 m_assetService.Store(meshAsset);
597  
598 pbs.SculptEntry = true;
599 pbs.SculptTexture = meshAsset.FullID;
600 pbs.SculptType = (byte)SculptType.Mesh;
601 pbs.SculptData = meshAsset.Data;
602  
603 Vector3 position = inner_instance_list["position"].AsVector3();
604 Vector3 scale = inner_instance_list["scale"].AsVector3();
605 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
606  
607 // no longer used - begin ------------------------
608 // int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
609 // int material = inner_instance_list["material"].AsInteger();
610 // int mesh = inner_instance_list["mesh"].AsInteger();
611  
612 // OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
613 // int base_mask = permissions["base_mask"].AsInteger();
614 // int everyone_mask = permissions["everyone_mask"].AsInteger();
615 // UUID creator_id = permissions["creator_id"].AsUUID();
616 // UUID group_id = permissions["group_id"].AsUUID();
617 // int group_mask = permissions["group_mask"].AsInteger();
618 // bool is_owner_group = permissions["is_owner_group"].AsBoolean();
619 // UUID last_owner_id = permissions["last_owner_id"].AsUUID();
620 // int next_owner_mask = permissions["next_owner_mask"].AsInteger();
621 // UUID owner_id = permissions["owner_id"].AsUUID();
622 // int owner_mask = permissions["owner_mask"].AsInteger();
623 // no longer used - end ------------------------
624  
625 UUID owner_id = m_HostCapsObj.AgentID;
626  
627 SceneObjectPart prim
628 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
629  
630 prim.Scale = scale;
631 //prim.OffsetPosition = position;
632 rotations.Add(rotation);
633 positions.Add(position);
634 prim.UUID = UUID.Random();
635 prim.CreatorID = owner_id;
636 prim.OwnerID = owner_id;
637 prim.GroupID = UUID.Zero;
638 prim.LastOwnerID = prim.OwnerID;
639 prim.CreationDate = Util.UnixTimeSinceEpoch();
640 prim.Name = assetName;
641 prim.Description = "";
642  
643 // prim.BaseMask = (uint)base_mask;
644 // prim.EveryoneMask = (uint)everyone_mask;
645 // prim.GroupMask = (uint)group_mask;
646 // prim.NextOwnerMask = (uint)next_owner_mask;
647 // prim.OwnerMask = (uint)owner_mask;
648  
649 if (grp == null)
650 grp = new SceneObjectGroup(prim);
651 else
652 grp.AddPart(prim);
653 }
654  
655 Vector3 rootPos = positions[0];
656  
657 if (grp.Parts.Length > 1)
658 {
659 // Fix first link number
660 grp.RootPart.LinkNum++;
661  
662 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
663 Quaternion tmprot;
664 Vector3 offset;
665  
666 // fix children rotations and positions
667 for (int i = 1; i < rotations.Count; i++)
668 {
669 tmprot = rotations[i];
670 tmprot = rootRotConj * tmprot;
671  
672 grp.Parts[i].RotationOffset = tmprot;
673  
674 offset = positions[i] - rootPos;
675  
676 offset *= rootRotConj;
677 grp.Parts[i].OffsetPosition = offset;
678 }
679  
680 grp.AbsolutePosition = rootPos;
681 grp.UpdateGroupRotationR(rotations[0]);
682 }
683 else
684 {
685 grp.AbsolutePosition = rootPos;
686 grp.UpdateGroupRotationR(rotations[0]);
687 }
688  
689 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
690 }
691  
692 AssetBase asset;
693 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString());
694 asset.Data = data;
695 if (AddNewAsset != null)
696 AddNewAsset(asset);
697 else if (m_assetService != null)
698 m_assetService.Store(asset);
699  
700 InventoryItemBase item = new InventoryItemBase();
701 item.Owner = m_HostCapsObj.AgentID;
702 item.CreatorId = m_HostCapsObj.AgentID.ToString();
703 item.CreatorData = String.Empty;
704 item.ID = inventoryItem;
705 item.AssetID = asset.FullID;
706 item.Description = assetDescription;
707 item.Name = assetName;
708 item.AssetType = assType;
709 item.InvType = inType;
710 item.Folder = parentFolder;
711  
712 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
713 // (owner) permissions. This becomes a problem if next permissions are changed.
714 item.CurrentPermissions
715 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
716  
717 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
718 item.EveryOnePermissions = 0;
719 item.NextPermissions = (uint)PermissionMask.All;
720 item.CreationDate = Util.UnixTimeSinceEpoch();
721  
722 if (AddNewInventoryItem != null)
723 {
724 AddNewInventoryItem(m_HostCapsObj.AgentID, item);
725 }
726 }
727  
728 /// <summary>
729 ///
730 /// </summary>
731 /// <param name="mapReq"></param>
732 /// <returns></returns>
733 public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq)
734 {
735 m_log.Debug("[CAPS]: MapLayer Request in region: " + m_regionName);
736 LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
737 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
738 return mapResponse;
739 }
740  
741 /// <summary>
742 ///
743 /// </summary>
744 /// <returns></returns>
745 protected static OSDMapLayer GetOSDMapLayerResponse()
746 {
747 OSDMapLayer mapLayer = new OSDMapLayer();
748 mapLayer.Right = 5000;
749 mapLayer.Top = 5000;
750 mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006");
751  
752 return mapLayer;
753 }
754  
755 /// <summary>
756 ///
757 /// </summary>
758 /// <param name="request"></param>
759 /// <param name="path"></param>
760 /// <param name="param"></param>
761 /// <returns></returns>
762 public string RequestTexture(string request, string path, string param)
763 {
764 m_log.Debug("texture request " + request);
765 // Needs implementing (added to remove compiler warning)
766 return String.Empty;
767 }
768  
769  
770 /// <summary>
771 /// Called by the notecard update handler. Provides a URL to which the client can upload a new asset.
772 /// </summary>
773 /// <param name="request"></param>
774 /// <param name="path"></param>
775 /// <param name="param"></param>
776 /// <returns></returns>
777 public string NoteCardAgentInventory(string request, string path, string param,
778 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
779 {
780 //m_log.Debug("[CAPS]: NoteCardAgentInventory Request in region: " + m_regionName + "\n" + request);
781 //m_log.Debug("[CAPS]: NoteCardAgentInventory Request is: " + request);
782  
783 //OpenMetaverse.StructuredData.OSDMap hash = (OpenMetaverse.StructuredData.OSDMap)OpenMetaverse.StructuredData.LLSDParser.DeserializeBinary(Utils.StringToBytes(request));
784 Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
785 LLSDItemUpdate llsdRequest = new LLSDItemUpdate();
786 LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest);
787  
788 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
789 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
790  
791 ItemUpdater uploader =
792 new ItemUpdater(llsdRequest.item_id, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile);
793 uploader.OnUpLoad += ItemUpdated;
794  
795 m_HostCapsObj.HttpListener.AddStreamHandler(
796 new BinaryStreamHandler(
797 "POST", capsBase + uploaderPath, uploader.uploaderCaps, "NoteCardAgentInventory", null));
798  
799 string protocol = "http://";
800  
801 if (m_HostCapsObj.SSLCaps)
802 protocol = "https://";
803  
804 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
805 uploaderPath;
806  
807 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
808 uploadResponse.uploader = uploaderURL;
809 uploadResponse.state = "upload";
810  
811 // m_log.InfoFormat("[CAPS]: " +
812 // "NoteCardAgentInventory response: {0}",
813 // LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
814  
815 return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
816 }
817  
818 /// <summary>
819 /// Called by the CopyInventoryFromNotecard caps handler.
820 /// </summary>
821 /// <param name="request"></param>
822 /// <param name="path"></param>
823 /// <param name="param"></param>
824 public string CopyInventoryFromNotecard(string request, string path, string param,
825 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
826 {
827 Hashtable response = new Hashtable();
828 response["int_response_code"] = 404;
829 response["content_type"] = "text/plain";
830 response["keepalive"] = false;
831 response["str_response_string"] = "";
832  
833 try
834 {
835 OSDMap content = (OSDMap)OSDParser.DeserializeLLSDXml(request);
836 UUID objectID = content["object-id"].AsUUID();
837 UUID notecardID = content["notecard-id"].AsUUID();
838 UUID folderID = content["folder-id"].AsUUID();
839 UUID itemID = content["item-id"].AsUUID();
840  
841 // m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, FolderID:{0}, ItemID:{1}, NotecardID:{2}, ObjectID:{3}", folderID, itemID, notecardID, objectID);
842  
843 if (objectID != UUID.Zero)
844 {
845 SceneObjectPart part = m_Scene.GetSceneObjectPart(objectID);
846 if (part != null)
847 {
848 // TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(notecardID);
849 if (!m_Scene.Permissions.CanCopyObjectInventory(notecardID, objectID, m_HostCapsObj.AgentID))
850 {
851 return LLSDHelpers.SerialiseLLSDReply(response);
852 }
853 }
854 }
855  
856 InventoryItemBase item = null;
857 InventoryItemBase copyItem = null;
858 IClientAPI client = null;
859  
860 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
861 item = m_Scene.InventoryService.GetItem(new InventoryItemBase(itemID));
862 if (item != null)
863 {
864 copyItem = m_Scene.GiveInventoryItem(m_HostCapsObj.AgentID, item.Owner, itemID, folderID);
865 if (copyItem != null && client != null)
866 {
867 m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, ItemID:{0}, FolderID:{1}", copyItem.ID, copyItem.Folder);
868 client.SendBulkUpdateInventory(copyItem);
869 }
870 }
871 else
872 {
873 m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard - Failed to retrieve item {0} from notecard {1}", itemID, notecardID);
874 if (client != null)
875 client.SendAlertMessage("Failed to retrieve item");
876 }
877 }
878 catch (Exception e)
879 {
880 m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard : {0}", e.ToString());
881 }
882  
883 response["int_response_code"] = 200;
884 return LLSDHelpers.SerialiseLLSDReply(response);
885 }
886  
887 public string GetObjectPhysicsData(string request, string path,
888 string param, IOSHttpRequest httpRequest,
889 IOSHttpResponse httpResponse)
890 {
891 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
892 OSDMap resp = new OSDMap();
893 OSDArray object_ids = (OSDArray)req["object_ids"];
894  
895 for (int i = 0 ; i < object_ids.Count ; i++)
896 {
897 UUID uuid = object_ids[i].AsUUID();
898  
899 SceneObjectPart obj = m_Scene.GetSceneObjectPart(uuid);
900 if (obj != null)
901 {
902 OSDMap object_data = new OSDMap();
903  
904 object_data["PhysicsShapeType"] = obj.PhysicsShapeType;
905 object_data["Density"] = obj.Density;
906 object_data["Friction"] = obj.Friction;
907 object_data["Restitution"] = obj.Restitution;
908 object_data["GravityMultiplier"] = obj.GravityModifier;
909  
910 resp[uuid.ToString()] = object_data;
911 }
912 }
913  
914 string response = OSDParser.SerializeLLSDXmlString(resp);
915 return response;
916 }
917  
918 public string UpdateAgentInformation(string request, string path,
919 string param, IOSHttpRequest httpRequest,
920 IOSHttpResponse httpResponse)
921 {
922 // OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
923 OSDMap resp = new OSDMap();
924  
925 OSDMap accessPrefs = new OSDMap();
926 accessPrefs["max"] = "A";
927  
928 resp["access_prefs"] = accessPrefs;
929  
930 string response = OSDParser.SerializeLLSDXmlString(resp);
931 return response;
932 }
933 }
934  
935 public class AssetUploader
936 {
937 public event UpLoadedAsset OnUpLoad;
938 private UpLoadedAsset handlerUpLoad = null;
939  
940 private string uploaderPath = String.Empty;
941 private UUID newAssetID;
942 private UUID inventoryItemID;
943 private UUID parentFolder;
944 private IHttpServer httpListener;
945 private bool m_dumpAssetsToFile;
946 private string m_assetName = String.Empty;
947 private string m_assetDes = String.Empty;
948  
949 private string m_invType = String.Empty;
950 private string m_assetType = String.Empty;
951  
952 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
953 UUID parentFolderID, string invType, string assetType, string path,
954 IHttpServer httpServer, bool dumpAssetsToFile)
955 {
956 m_assetName = assetName;
957 m_assetDes = description;
958 newAssetID = assetID;
959 inventoryItemID = inventoryItem;
960 uploaderPath = path;
961 httpListener = httpServer;
962 parentFolder = parentFolderID;
963 m_assetType = assetType;
964 m_invType = invType;
965 m_dumpAssetsToFile = dumpAssetsToFile;
966 }
967  
968 /// <summary>
969 /// Handle raw asset upload data via the capability.
970 /// </summary>
971 /// <param name="data"></param>
972 /// <param name="path"></param>
973 /// <param name="param"></param>
974 /// <returns></returns>
975 public string uploaderCaps(byte[] data, string path, string param)
976 {
977 UUID inv = inventoryItemID;
978 string res = String.Empty;
979 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
980 uploadComplete.new_asset = newAssetID.ToString();
981 uploadComplete.new_inventory_item = inv;
982 uploadComplete.state = "complete";
983  
984 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
985  
986 httpListener.RemoveStreamHandler("POST", uploaderPath);
987  
988 // TODO: probably make this a better set of extensions here
989 string extension = ".jp2";
990 if (m_invType != "image")
991 {
992 extension = ".dat";
993 }
994  
995 if (m_dumpAssetsToFile)
996 {
997 SaveAssetToFile(m_assetName + extension, data);
998 }
999 handlerUpLoad = OnUpLoad;
1000 if (handlerUpLoad != null)
1001 {
1002 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType);
1003 }
1004  
1005 return res;
1006 }
1007  
1008 ///Left this in and commented in case there are unforseen issues
1009 //private void SaveAssetToFile(string filename, byte[] data)
1010 //{
1011 // FileStream fs = File.Create(filename);
1012 // BinaryWriter bw = new BinaryWriter(fs);
1013 // bw.Write(data);
1014 // bw.Close();
1015 // fs.Close();
1016 //}
1017  
1018 private static void SaveAssetToFile(string filename, byte[] data)
1019 {
1020 string assetPath = "UserAssets";
1021 if (!Directory.Exists(assetPath))
1022 {
1023 Directory.CreateDirectory(assetPath);
1024 }
1025 FileStream fs = File.Create(Path.Combine(assetPath, Util.safeFileName(filename)));
1026 BinaryWriter bw = new BinaryWriter(fs);
1027 bw.Write(data);
1028 bw.Close();
1029 fs.Close();
1030 }
1031 }
1032  
1033 /// <summary>
1034 /// This class is a callback invoked when a client sends asset data to
1035 /// an agent inventory notecard update url
1036 /// </summary>
1037 public class ItemUpdater
1038 {
1039 public event UpdateItem OnUpLoad;
1040  
1041 private UpdateItem handlerUpdateItem = null;
1042  
1043 private string uploaderPath = String.Empty;
1044 private UUID inventoryItemID;
1045 private IHttpServer httpListener;
1046 private bool m_dumpAssetToFile;
1047  
1048 public ItemUpdater(UUID inventoryItem, string path, IHttpServer httpServer, bool dumpAssetToFile)
1049 {
1050 m_dumpAssetToFile = dumpAssetToFile;
1051  
1052 inventoryItemID = inventoryItem;
1053 uploaderPath = path;
1054 httpListener = httpServer;
1055 }
1056  
1057 /// <summary>
1058 /// Handle raw uploaded asset data.
1059 /// </summary>
1060 /// <param name="data"></param>
1061 /// <param name="path"></param>
1062 /// <param name="param"></param>
1063 /// <returns></returns>
1064 public string uploaderCaps(byte[] data, string path, string param)
1065 {
1066 UUID inv = inventoryItemID;
1067 string res = String.Empty;
1068 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1069 UUID assetID = UUID.Zero;
1070 handlerUpdateItem = OnUpLoad;
1071 if (handlerUpdateItem != null)
1072 {
1073 assetID = handlerUpdateItem(inv, data);
1074 }
1075  
1076 uploadComplete.new_asset = assetID.ToString();
1077 uploadComplete.new_inventory_item = inv;
1078 uploadComplete.state = "complete";
1079  
1080 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1081  
1082 httpListener.RemoveStreamHandler("POST", uploaderPath);
1083  
1084 if (m_dumpAssetToFile)
1085 {
1086 SaveAssetToFile("updateditem" + Util.RandomClass.Next(1, 1000) + ".dat", data);
1087 }
1088  
1089 return res;
1090 }
1091  
1092 ///Left this in and commented in case there are unforseen issues
1093 //private void SaveAssetToFile(string filename, byte[] data)
1094 //{
1095 // FileStream fs = File.Create(filename);
1096 // BinaryWriter bw = new BinaryWriter(fs);
1097 // bw.Write(data);
1098 // bw.Close();
1099 // fs.Close();
1100 //}
1101  
1102 private static void SaveAssetToFile(string filename, byte[] data)
1103 {
1104 string assetPath = "UserAssets";
1105 if (!Directory.Exists(assetPath))
1106 {
1107 Directory.CreateDirectory(assetPath);
1108 }
1109 FileStream fs = File.Create(Path.Combine(assetPath, filename));
1110 BinaryWriter bw = new BinaryWriter(fs);
1111 bw.Write(data);
1112 bw.Close();
1113 fs.Close();
1114 }
1115 }
1116  
1117 /// <summary>
1118 /// This class is a callback invoked when a client sends asset data to
1119 /// a task inventory script update url
1120 /// </summary>
1121 public class TaskInventoryScriptUpdater
1122 {
1123 private static readonly ILog m_log =
1124 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1125  
1126 public event UpdateTaskScript OnUpLoad;
1127  
1128 private UpdateTaskScript handlerUpdateTaskScript = null;
1129  
1130 private string uploaderPath = String.Empty;
1131 private UUID inventoryItemID;
1132 private UUID primID;
1133 private bool isScriptRunning;
1134 private IHttpServer httpListener;
1135 private bool m_dumpAssetToFile;
1136  
1137 public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, int isScriptRunning,
1138 string path, IHttpServer httpServer, bool dumpAssetToFile)
1139 {
1140 m_dumpAssetToFile = dumpAssetToFile;
1141  
1142 this.inventoryItemID = inventoryItemID;
1143 this.primID = primID;
1144  
1145 // This comes in over the packet as an integer, but actually appears to be treated as a bool
1146 this.isScriptRunning = (0 == isScriptRunning ? false : true);
1147  
1148 uploaderPath = path;
1149 httpListener = httpServer;
1150 }
1151  
1152 /// <summary>
1153 ///
1154 /// </summary>
1155 /// <param name="data"></param>
1156 /// <param name="path"></param>
1157 /// <param name="param"></param>
1158 /// <returns></returns>
1159 public string uploaderCaps(byte[] data, string path, string param)
1160 {
1161 try
1162 {
1163 // m_log.InfoFormat("[CAPS]: " +
1164 // "TaskInventoryScriptUpdater received data: {0}, path: {1}, param: {2}",
1165 // data, path, param));
1166  
1167 string res = String.Empty;
1168 LLSDTaskScriptUploadComplete uploadComplete = new LLSDTaskScriptUploadComplete();
1169  
1170 ArrayList errors = new ArrayList();
1171 handlerUpdateTaskScript = OnUpLoad;
1172 if (handlerUpdateTaskScript != null)
1173 {
1174 handlerUpdateTaskScript(inventoryItemID, primID, isScriptRunning, data, ref errors);
1175 }
1176  
1177 uploadComplete.new_asset = inventoryItemID;
1178 uploadComplete.compiled = errors.Count > 0 ? false : true;
1179 uploadComplete.state = "complete";
1180 uploadComplete.errors = new OpenSim.Framework.Capabilities.OSDArray();
1181 uploadComplete.errors.Array = errors;
1182  
1183 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1184  
1185 httpListener.RemoveStreamHandler("POST", uploaderPath);
1186  
1187 if (m_dumpAssetToFile)
1188 {
1189 SaveAssetToFile("updatedtaskscript" + Util.RandomClass.Next(1, 1000) + ".dat", data);
1190 }
1191  
1192 // m_log.InfoFormat("[CAPS]: TaskInventoryScriptUpdater.uploaderCaps res: {0}", res);
1193  
1194 return res;
1195 }
1196 catch (Exception e)
1197 {
1198 m_log.Error("[CAPS]: " + e.ToString());
1199 }
1200  
1201 // XXX Maybe this should be some meaningful error packet
1202 return null;
1203 }
1204  
1205 ///Left this in and commented in case there are unforseen issues
1206 //private void SaveAssetToFile(string filename, byte[] data)
1207 //{
1208 // FileStream fs = File.Create(filename);
1209 // BinaryWriter bw = new BinaryWriter(fs);
1210 // bw.Write(data);
1211 // bw.Close();
1212 // fs.Close();
1213 //}
1214 private static void SaveAssetToFile(string filename, byte[] data)
1215 {
1216 string assetPath = "UserAssets";
1217 if (!Directory.Exists(assetPath))
1218 {
1219 Directory.CreateDirectory(assetPath);
1220 }
1221 FileStream fs = File.Create(Path.Combine(assetPath, filename));
1222 BinaryWriter bw = new BinaryWriter(fs);
1223 bw.Write(data);
1224 bw.Close();
1225 fs.Close();
1226 }
1227 }
1228 }