From f79400e94ca6f8b609f5d4cbe25c5bbc04b61b77 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 1 May 2011 18:22:53 -0700 Subject: 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. --- OpenSim/Capabilities/Caps.cs | 1261 +------------------- .../Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 1210 +++++++++++++++++++ .../Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs | 87 ++ .../Linden/Caps/EventQueue/EventQueueGetModule.cs | 2 +- .../NewFileAgentInventoryVariablePriceModule.cs | 4 +- .../Framework/Caps/CapabilitiesModule.cs | 50 +- .../InterGrid/OpenGridProtocolModule.cs | 4 +- .../Framework/Interfaces/ICapabilitiesModule.cs | 14 +- OpenSim/Region/Framework/Scenes/Scene.cs | 8 +- 9 files changed, 1357 insertions(+), 1283 deletions(-) create mode 100644 OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs create mode 100644 OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs (limited to 'OpenSim') 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; namespace OpenSim.Framework.Capabilities { - public delegate void UpLoadedAsset( - string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, - byte[] data, string inventoryType, string assetType); - - public delegate void UploadedBakedTexture(UUID assetID, byte[] data); - - public delegate UUID UpdateItem(UUID itemID, byte[] data); - - public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); - - public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); - - public delegate void NewAsset(AssetBase asset); - - public delegate UUID ItemUpdatedCallback(UUID userID, UUID itemID, byte[] data); - - public delegate ArrayList TaskScriptUpdatedCallback(UUID userID, UUID itemID, UUID primID, - bool isScriptRunning, byte[] data); - - public delegate InventoryCollection FetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID, - bool fetchFolders, bool fetchItems, int sortOrder, out int version); - /// /// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that /// 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 private CapsHandlers m_capsHandlers; private Dictionary m_externalCapsHandlers; - private static readonly string m_requestPath = "0000/"; - // private static readonly string m_mapLayerPath = "0001/"; - private static readonly string m_newInventory = "0002/"; - //private static readonly string m_requestTexture = "0003/"; - private static readonly string m_notecardUpdatePath = "0004/"; - private static readonly string m_notecardTaskUpdatePath = "0005/"; -// private static readonly string m_fetchInventoryPath = "0006/"; - - // The following entries are in a module, however, they are also here so that we don't re-assign - // the path to another cap by mistake. - // private static readonly string m_parcelVoiceInfoRequestPath = "0007/"; // This is in a module. - // private static readonly string m_provisionVoiceAccountRequestPath = "0008/";// This is in a module. - - // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. - private static readonly string m_uploadBakedTexturePath = "0010/";// This is in the LandManagementModule. - - //private string eventQueue = "0100/"; - private IScene m_Scene; private IHttpServer m_httpListener; private UUID m_agentID; - private IAssetService m_assetCache; - private int m_eventQueueCount = 1; - private Queue m_capsEventQueue = new Queue(); - private bool m_dumpAssetsToFile; private string m_regionName; - private object m_fetchLock = new Object(); - private bool m_persistBakedTextures = false; + public UUID AgentID + { + get { return m_agentID; } + } + + public string RegionName + { + get { return m_regionName; } + } + + public string HostName + { + get { return m_httpListenerHostName; } + } + + public uint Port + { + get { return m_httpListenPort; } + } + + public IHttpServer HttpListener + { + get { return m_httpListener; } + } public bool SSLCaps { @@ -129,35 +107,15 @@ namespace OpenSim.Framework.Capabilities get { return m_capsHandlers; } } - // These are callbacks which will be setup by the scene so that we can update scene data when we - // receive capability calls - public NewInventoryItem AddNewInventoryItem = null; - public NewAsset AddNewAsset = null; - public ItemUpdatedCallback ItemUpdatedCall = null; - public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null; - public FetchInventoryDescendentsCAPS CAPSFetchInventoryDescendents = null; - public GetClientDelegate GetClient = null; - - public Caps(IScene scene, IAssetService assetCache, IHttpServer httpServer, string httpListen, uint httpPort, string capsPath, - UUID agent, bool dumpAssetsToFile, string regionName) + public Caps(IHttpServer httpServer, string httpListen, uint httpPort, string capsPath, + UUID agent, string regionName) { - m_Scene = scene; - m_assetCache = assetCache; m_capsObjectPath = capsPath; m_httpListener = httpServer; m_httpListenerHostName = httpListen; m_httpListenPort = httpPort; - m_persistBakedTextures = false; - IConfigSource config = m_Scene.Config; - if (config != null) - { - IConfig sconfig = config.Configs["Startup"]; - if (sconfig != null) - m_persistBakedTextures = sconfig.GetBoolean("PersistBakedTextures",m_persistBakedTextures); - } - if (httpServer != null && httpServer.UseSSL) { m_httpListenPort = httpServer.SSLPort; @@ -166,98 +124,12 @@ namespace OpenSim.Framework.Capabilities } m_agentID = agent; - m_dumpAssetsToFile = dumpAssetsToFile; m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort, (httpServer == null) ? false : httpServer.UseSSL); m_externalCapsHandlers = new Dictionary(); m_regionName = regionName; } /// - /// Register all CAPS http service handlers - /// - public void RegisterHandlers() - { - DeregisterHandlers(); - - string capsBase = "/CAPS/" + m_capsObjectPath; - - RegisterRegionServiceHandlers(capsBase); - RegisterInventoryServiceHandlers(capsBase); - } - - public void RegisterRegionServiceHandlers(string capsBase) - { - try - { - // the root of all evil - m_capsHandlers["SEED"] = new RestStreamHandler("POST", capsBase + m_requestPath, CapsRequest); - m_log.DebugFormat( - "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_agentID); - - //m_capsHandlers["MapLayer"] = - // new LLSDStreamhandler("POST", - // capsBase + m_mapLayerPath, - // GetMapLayer); - m_capsHandlers["UpdateScriptTaskInventory"] = - new RestStreamHandler("POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory); - m_capsHandlers["UpdateScriptTask"] = m_capsHandlers["UpdateScriptTaskInventory"]; - m_capsHandlers["UploadBakedTexture"] = - new RestStreamHandler("POST", capsBase + m_uploadBakedTexturePath, UploadBakedTexture); - - } - catch (Exception e) - { - m_log.Error("[CAPS]: " + e.ToString()); - } - } - - public void RegisterInventoryServiceHandlers(string capsBase) - { - try - { - // I don't think this one works... - m_capsHandlers["NewFileAgentInventory"] = - new LLSDStreamhandler("POST", - capsBase + m_newInventory, - NewAgentInventoryRequest); - m_capsHandlers["UpdateNotecardAgentInventory"] = - new RestStreamHandler("POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory); - m_capsHandlers["UpdateScriptAgentInventory"] = m_capsHandlers["UpdateNotecardAgentInventory"]; - m_capsHandlers["UpdateScriptAgent"] = m_capsHandlers["UpdateScriptAgentInventory"]; - - // As of RC 1.22.9 of the Linden client this is - // supported - - //m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest); - - // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and - // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires - // enhancements (probably filling out the folder part of the LLSD reply) to our CAPS service, - // but when I went on the Linden grid, the - // simulators I visited (version 1.21) were, surprisingly, no longer supplying this capability. Instead, - // the 1.19.1.4 client appeared to be happily flowing inventory data over UDP - // - // This is very probably just a temporary measure - once the CAPS service appears again on the Linden grid - // we will be - // able to get the data we need to implement the necessary part of the protocol to fix the issue above. - // m_capsHandlers["FetchInventoryDescendents"] = - // new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest); - - // m_capsHandlers["FetchInventoryDescendents"] = - // new LLSDStreamhandler("POST", - // capsBase + m_fetchInventory, - // FetchInventory)); - // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST", - // capsBase + m_requestTexture, - // RequestTexture); - } - catch (Exception e) - { - m_log.Error("[CAPS]: " + e.ToString()); - } - } - - /// /// Register a handler. This allows modules to register handlers. /// /// @@ -296,1086 +168,5 @@ namespace OpenSim.Framework.Capabilities } } } - - /// - /// Construct a client response detailing all the capabilities this server can provide. - /// - /// - /// - /// - /// HTTP request header object - /// HTTP response header object - /// - public string CapsRequest(string request, string path, string param, - OSHttpRequest httpRequest, OSHttpResponse httpResponse) - { - m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName); - - if (!m_Scene.CheckClient(m_agentID, httpRequest.RemoteIPEndPoint)) - { - m_log.DebugFormat("[CAPS]: Unauthorized CAPS client"); - return string.Empty; - } - - string result = LLSDHelpers.SerialiseLLSDReply(m_capsHandlers.CapsDetails); - - //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); - - return result; - } - - // FIXME: these all should probably go into the respective region - // modules - - /// - /// Processes a fetch inventory request and sends the reply - - /// - /// - /// - /// - /// - // Request is like: - // - // folders - // - // - // fetch-folders1fetch-items1folder-id8e1e3a30-b9bf-11dc-95ff-0800200c9a66owner-id11111111-1111-0000-0000-000100bba000sort-order1 - // - // - // - // - // - // multiple fetch-folder maps are allowed within the larger folders map. - public string FetchInventoryRequest(string request, string path, string param) - { - // string unmodifiedRequest = request.ToString(); - - //m_log.DebugFormat("[AGENT INVENTORY]: Received CAPS fetch inventory request {0}", unmodifiedRequest); - m_log.Debug("[CAPS]: Inventory Request in region: " + m_regionName); - - Hashtable hash = new Hashtable(); - try - { - hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); - } - catch (LLSD.LLSDParseException pe) - { - m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message); - m_log.Error("Request: " + request.ToString()); - } - - ArrayList foldersrequested = (ArrayList)hash["folders"]; - - string response = ""; - - for (int i = 0; i < foldersrequested.Count; i++) - { - string inventoryitemstr = ""; - Hashtable inventoryhash = (Hashtable)foldersrequested[i]; - - LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); - LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); - LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); - - inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); - inventoryitemstr = inventoryitemstr.Replace("folders", ""); - inventoryitemstr = inventoryitemstr.Replace("", ""); - - response += inventoryitemstr; - } - - if (response.Length == 0) - { - // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. - // Therefore, I'm concluding that the client only has so many threads available to do requests - // and when a thread stalls.. is stays stalled. - // Therefore we need to return something valid - response = "folders"; - } - else - { - response = "folders" + response + ""; - } - - //m_log.DebugFormat("[AGENT INVENTORY]: Replying to CAPS fetch inventory request with following xml"); - //m_log.Debug(Util.GetFormattedXml(response)); - - return response; - } - - public string FetchInventoryDescendentsRequest(string request, string path, string param,OSHttpRequest httpRequest, OSHttpResponse httpResponse) - { - // nasty temporary hack here, the linden client falsely - // identifies the uuid 00000000-0000-0000-0000-000000000000 - // as a string which breaks us - // - // correctly mark it as a uuid - // - request = request.Replace("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000000"); - - // another hack 1 results in a - // System.ArgumentException: Object type System.Int32 cannot - // be converted to target type: System.Boolean - // - request = request.Replace("fetch_folders0", "fetch_folders0"); - request = request.Replace("fetch_folders1", "fetch_folders1"); - - Hashtable hash = new Hashtable(); - try - { - hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); - } - catch (LLSD.LLSDParseException pe) - { - m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message); - m_log.Error("Request: " + request.ToString()); - } - - ArrayList foldersrequested = (ArrayList)hash["folders"]; - - string response = ""; - lock (m_fetchLock) - { - for (int i = 0; i < foldersrequested.Count; i++) - { - string inventoryitemstr = ""; - Hashtable inventoryhash = (Hashtable)foldersrequested[i]; - - LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); - - try{ - LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); - } - catch(Exception e) - { - m_log.Debug("[CAPS]: caught exception doing OSD deserialize" + e); - } - LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); - - inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); - inventoryitemstr = inventoryitemstr.Replace("folders", ""); - inventoryitemstr = inventoryitemstr.Replace("", ""); - - response += inventoryitemstr; - } - - - if (response.Length == 0) - { - // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. - // Therefore, I'm concluding that the client only has so many threads available to do requests - // and when a thread stalls.. is stays stalled. - // Therefore we need to return something valid - response = "folders"; - } - else - { - response = "folders" + response + ""; - } - - //m_log.DebugFormat("[CAPS]: Replying to CAPS fetch inventory request with following xml"); - //m_log.Debug("[CAPS] "+response); - - } - return response; - } - - - - /// - /// Construct an LLSD reply packet to a CAPS inventory request - /// - /// - /// - private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch) - { - LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); - LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); - contents.agent_id = m_agentID; - contents.owner_id = invFetch.owner_id; - contents.folder_id = invFetch.folder_id; - - reply.folders.Array.Add(contents); - InventoryCollection inv = new InventoryCollection(); - inv.Folders = new List(); - inv.Items = new List(); - int version = 0; - if (CAPSFetchInventoryDescendents != null) - { - inv = CAPSFetchInventoryDescendents(m_agentID, invFetch.folder_id, invFetch.owner_id, invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version); - } - - if (inv.Folders != null) - { - foreach (InventoryFolderBase invFolder in inv.Folders) - { - contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); - } - } - - if (inv.Items != null) - { - foreach (InventoryItemBase invItem in inv.Items) - { - contents.items.Array.Add(ConvertInventoryItem(invItem)); - } - } - - contents.descendents = contents.items.Array.Count + contents.categories.Array.Count; - contents.version = version; - - return reply; - } - - /// - /// Convert an internal inventory folder object into an LLSD object. - /// - /// - /// - private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder) - { - LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder(); - llsdFolder.folder_id = invFolder.ID; - llsdFolder.parent_id = invFolder.ParentID; - llsdFolder.name = invFolder.Name; - if (invFolder.Type < 0 || invFolder.Type >= TaskInventoryItem.Types.Length) - llsdFolder.type = "-1"; - else - llsdFolder.type = TaskInventoryItem.Types[invFolder.Type]; - llsdFolder.preferred_type = "-1"; - - return llsdFolder; - } - - /// - /// Convert an internal inventory item object into an LLSD object. - /// - /// - /// - private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem) - { - LLSDInventoryItem llsdItem = new LLSDInventoryItem(); - llsdItem.asset_id = invItem.AssetID; - llsdItem.created_at = invItem.CreationDate; - llsdItem.desc = invItem.Description; - llsdItem.flags = (int)invItem.Flags; - llsdItem.item_id = invItem.ID; - llsdItem.name = invItem.Name; - llsdItem.parent_id = invItem.Folder; - try - { - // TODO reevaluate after upgrade to libomv >= r2566. Probably should use UtilsConversions. - llsdItem.type = TaskInventoryItem.Types[invItem.AssetType]; - llsdItem.inv_type = TaskInventoryItem.InvTypes[invItem.InvType]; - } - catch (Exception e) - { - m_log.Error("[CAPS]: Problem setting asset/inventory type while converting inventory item " + invItem.Name + " to LLSD:", e); - } - llsdItem.permissions = new LLSDPermissions(); - llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid; - llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions; - llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions; - llsdItem.permissions.group_id = invItem.GroupID; - llsdItem.permissions.group_mask = (int)invItem.GroupPermissions; - llsdItem.permissions.is_owner_group = invItem.GroupOwned; - llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions; - llsdItem.permissions.owner_id = m_agentID; - llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions; - llsdItem.sale_info = new LLSDSaleInfo(); - llsdItem.sale_info.sale_price = invItem.SalePrice; - switch (invItem.SaleType) - { - default: - llsdItem.sale_info.sale_type = "not"; - break; - case 1: - llsdItem.sale_info.sale_type = "original"; - break; - case 2: - llsdItem.sale_info.sale_type = "copy"; - break; - case 3: - llsdItem.sale_info.sale_type = "contents"; - break; - } - - return llsdItem; - } - - /// - /// - /// - /// - /// - public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq) - { - m_log.Debug("[CAPS]: MapLayer Request in region: " + m_regionName); - LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); - mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); - return mapResponse; - } - - /// - /// - /// - /// - protected static OSDMapLayer GetOSDMapLayerResponse() - { - OSDMapLayer mapLayer = new OSDMapLayer(); - mapLayer.Right = 5000; - mapLayer.Top = 5000; - mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006"); - - return mapLayer; - } - - /// - /// - /// - /// - /// - /// - /// - public string RequestTexture(string request, string path, string param) - { - m_log.Debug("texture request " + request); - // Needs implementing (added to remove compiler warning) - return String.Empty; - } - - #region EventQueue (Currently not enabled) - - /// - /// - /// - /// - /// - /// - /// - public string ProcessEventQueue(string request, string path, string param) - { - string res = String.Empty; - - if (m_capsEventQueue.Count > 0) - { - lock (m_capsEventQueue) - { - string item = m_capsEventQueue.Dequeue(); - res = item; - } - } - else - { - res = CreateEmptyEventResponse(); - } - return res; - } - - /// - /// - /// - /// - /// - /// - public string CreateEstablishAgentComms(string caps, string ipAddressPort) - { - LLSDCapEvent eventItem = new LLSDCapEvent(); - eventItem.id = m_eventQueueCount; - //should be creating a EstablishAgentComms item, but there isn't a class for it yet - eventItem.events.Array.Add(new LLSDEmpty()); - string res = LLSDHelpers.SerialiseLLSDReply(eventItem); - m_eventQueueCount++; - - m_capsEventQueue.Enqueue(res); - return res; - } - - /// - /// - /// - /// - public string CreateEmptyEventResponse() - { - LLSDCapEvent eventItem = new LLSDCapEvent(); - eventItem.id = m_eventQueueCount; - eventItem.events.Array.Add(new LLSDEmpty()); - string res = LLSDHelpers.SerialiseLLSDReply(eventItem); - m_eventQueueCount++; - return res; - } - - #endregion - - /// - /// Called by the script task update handler. Provides a URL to which the client can upload a new asset. - /// - /// - /// - /// - /// HTTP request header object - /// HTTP response header object - /// - public string ScriptTaskInventory(string request, string path, string param, - OSHttpRequest httpRequest, OSHttpResponse httpResponse) - { - try - { - m_log.Debug("[CAPS]: ScriptTaskInventory Request in region: " + m_regionName); - //m_log.DebugFormat("[CAPS]: request: {0}, path: {1}, param: {2}", request, path, param); - - Hashtable hash = (Hashtable) LLSD.LLSDDeserialize(Utils.StringToBytes(request)); - LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate(); - LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest); - - string capsBase = "/CAPS/" + m_capsObjectPath; - string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); - - TaskInventoryScriptUpdater uploader = - new TaskInventoryScriptUpdater( - llsdUpdateRequest.item_id, - llsdUpdateRequest.task_id, - llsdUpdateRequest.is_script_running, - capsBase + uploaderPath, - m_httpListener, - m_dumpAssetsToFile); - uploader.OnUpLoad += TaskScriptUpdated; - - m_httpListener.AddStreamHandler( - new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); - - string protocol = "http://"; - - if (m_httpListener.UseSSL) - protocol = "https://"; - - string uploaderURL = protocol + m_httpListenerHostName + ":" + m_httpListenPort.ToString() + capsBase + - uploaderPath; - - LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); - uploadResponse.uploader = uploaderURL; - uploadResponse.state = "upload"; - -// m_log.InfoFormat("[CAPS]: " + -// "ScriptTaskInventory response: {0}", -// LLSDHelpers.SerialiseLLSDReply(uploadResponse))); - - return LLSDHelpers.SerialiseLLSDReply(uploadResponse); - } - catch (Exception e) - { - m_log.Error("[CAPS]: " + e.ToString()); - } - - return null; - } - - public string UploadBakedTexture(string request, string path, - string param, OSHttpRequest httpRequest, - OSHttpResponse httpResponse) - { - try - { -// m_log.Debug("[CAPS]: UploadBakedTexture Request in region: " + -// m_regionName); - - string capsBase = "/CAPS/" + m_capsObjectPath; - string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); - - BakedTextureUploader uploader = - new BakedTextureUploader(capsBase + uploaderPath, - m_httpListener); - uploader.OnUpLoad += BakedTextureUploaded; - - m_httpListener.AddStreamHandler( - new BinaryStreamHandler("POST", capsBase + uploaderPath, - uploader.uploaderCaps)); - - string protocol = "http://"; - - if (m_httpListener.UseSSL) - protocol = "https://"; - - string uploaderURL = protocol + m_httpListenerHostName + ":" + - m_httpListenPort.ToString() + capsBase + uploaderPath; - - LLSDAssetUploadResponse uploadResponse = - new LLSDAssetUploadResponse(); - uploadResponse.uploader = uploaderURL; - uploadResponse.state = "upload"; - - return LLSDHelpers.SerialiseLLSDReply(uploadResponse); - } - catch (Exception e) - { - m_log.Error("[CAPS]: " + e.ToString()); - } - - return null; - } - - /// - /// Called by the notecard update handler. Provides a URL to which the client can upload a new asset. - /// - /// - /// - /// - /// - public string NoteCardAgentInventory(string request, string path, string param, - OSHttpRequest httpRequest, OSHttpResponse httpResponse) - { - //m_log.Debug("[CAPS]: NoteCardAgentInventory Request in region: " + m_regionName + "\n" + request); - //m_log.Debug("[CAPS]: NoteCardAgentInventory Request is: " + request); - - //OpenMetaverse.StructuredData.OSDMap hash = (OpenMetaverse.StructuredData.OSDMap)OpenMetaverse.StructuredData.LLSDParser.DeserializeBinary(Utils.StringToBytes(request)); - Hashtable hash = (Hashtable) LLSD.LLSDDeserialize(Utils.StringToBytes(request)); - LLSDItemUpdate llsdRequest = new LLSDItemUpdate(); - LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest); - - string capsBase = "/CAPS/" + m_capsObjectPath; - string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); - - ItemUpdater uploader = - new ItemUpdater(llsdRequest.item_id, capsBase + uploaderPath, m_httpListener, m_dumpAssetsToFile); - uploader.OnUpLoad += ItemUpdated; - - m_httpListener.AddStreamHandler( - new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); - - string protocol = "http://"; - - if (m_httpListener.UseSSL) - protocol = "https://"; - - string uploaderURL = protocol + m_httpListenerHostName + ":" + m_httpListenPort.ToString() + capsBase + - uploaderPath; - - LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); - uploadResponse.uploader = uploaderURL; - uploadResponse.state = "upload"; - -// m_log.InfoFormat("[CAPS]: " + -// "NoteCardAgentInventory response: {0}", -// LLSDHelpers.SerialiseLLSDReply(uploadResponse))); - - return LLSDHelpers.SerialiseLLSDReply(uploadResponse); - } - - /// - /// - /// - /// - /// - public LLSDAssetUploadResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest) - { - //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); - //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); - - if (llsdRequest.asset_type == "texture" || - llsdRequest.asset_type == "animation" || - llsdRequest.asset_type == "sound") - { - IClientAPI client = null; - IScene scene = null; - if (GetClient != null) - { - client = GetClient(m_agentID); - scene = client.Scene; - - IMoneyModule mm = scene.RequestModuleInterface(); - - if (mm != null) - { - if (!mm.UploadCovered(client, mm.UploadCharge)) - { - if (client != null) - client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); - - LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); - errorResponse.uploader = ""; - errorResponse.state = "error"; - return errorResponse; - } - } - } - } - - - string assetName = llsdRequest.name; - string assetDes = llsdRequest.description; - string capsBase = "/CAPS/" + m_capsObjectPath; - UUID newAsset = UUID.Random(); - UUID newInvItem = UUID.Random(); - UUID parentFolder = llsdRequest.folder_id; - string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); - - AssetUploader uploader = - new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, - llsdRequest.asset_type, capsBase + uploaderPath, m_httpListener, m_dumpAssetsToFile); - m_httpListener.AddStreamHandler( - new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); - - string protocol = "http://"; - - if (m_httpListener.UseSSL) - protocol = "https://"; - - string uploaderURL = protocol + m_httpListenerHostName + ":" + m_httpListenPort.ToString() + capsBase + - uploaderPath; - - LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); - uploadResponse.uploader = uploaderURL; - uploadResponse.state = "upload"; - uploader.OnUpLoad += UploadCompleteHandler; - return uploadResponse; - } - - /// - /// - /// - /// - /// - /// - public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, - UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, - string assetType) - { - sbyte assType = 0; - sbyte inType = 0; - - if (inventoryType == "sound") - { - inType = 1; - assType = 1; - } - else if (inventoryType == "animation") - { - inType = 19; - assType = 20; - } - else if (inventoryType == "wearable") - { - inType = 18; - switch (assetType) - { - case "bodypart": - assType = 13; - break; - case "clothing": - assType = 5; - break; - } - } - - AssetBase asset; - asset = new AssetBase(assetID, assetName, assType, m_agentID.ToString()); - asset.Data = data; - if (AddNewAsset != null) - AddNewAsset(asset); - else if (m_assetCache != null) - m_assetCache.Store(asset); - - InventoryItemBase item = new InventoryItemBase(); - item.Owner = m_agentID; - item.CreatorId = m_agentID.ToString(); - item.CreatorData = String.Empty; - item.ID = inventoryItem; - item.AssetID = asset.FullID; - item.Description = assetDescription; - item.Name = assetName; - item.AssetType = assType; - item.InvType = inType; - item.Folder = parentFolder; - item.CurrentPermissions = (uint)PermissionMask.All; - item.BasePermissions = (uint)PermissionMask.All; - item.EveryOnePermissions = 0; - item.NextPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer); - item.CreationDate = Util.UnixTimeSinceEpoch(); - - if (AddNewInventoryItem != null) - { - AddNewInventoryItem(m_agentID, item); - } - } - - public void BakedTextureUploaded(UUID assetID, byte[] data) - { -// m_log.WarnFormat("[CAPS]: Received baked texture {0}", assetID.ToString()); - - AssetBase asset; - asset = new AssetBase(assetID, "Baked Texture", (sbyte)AssetType.Texture, m_agentID.ToString()); - asset.Data = data; - asset.Temporary = true; - asset.Local = ! m_persistBakedTextures; // Local assets aren't persisted, non-local are - m_assetCache.Store(asset); - } - - /// - /// Called when new asset data for an agent inventory item update has been uploaded. - /// - /// Item to update - /// New asset data - /// - public UUID ItemUpdated(UUID itemID, byte[] data) - { - if (ItemUpdatedCall != null) - { - return ItemUpdatedCall(m_agentID, itemID, data); - } - - return UUID.Zero; - } - - /// - /// Called when new asset data for an agent inventory item update has been uploaded. - /// - /// Item to update - /// Prim containing item to update - /// Signals whether the script to update is currently running - /// New asset data - public void TaskScriptUpdated(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors) - { - if (TaskScriptUpdatedCall != null) - { - ArrayList e = TaskScriptUpdatedCall(m_agentID, itemID, primID, isScriptRunning, data); - foreach (Object item in e) - errors.Add(item); - } - } - - public class AssetUploader - { - public event UpLoadedAsset OnUpLoad; - private UpLoadedAsset handlerUpLoad = null; - - private string uploaderPath = String.Empty; - private UUID newAssetID; - private UUID inventoryItemID; - private UUID parentFolder; - private IHttpServer httpListener; - private bool m_dumpAssetsToFile; - private string m_assetName = String.Empty; - private string m_assetDes = String.Empty; - - private string m_invType = String.Empty; - private string m_assetType = String.Empty; - - public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, - UUID parentFolderID, string invType, string assetType, string path, - IHttpServer httpServer, bool dumpAssetsToFile) - { - m_assetName = assetName; - m_assetDes = description; - newAssetID = assetID; - inventoryItemID = inventoryItem; - uploaderPath = path; - httpListener = httpServer; - parentFolder = parentFolderID; - m_assetType = assetType; - m_invType = invType; - m_dumpAssetsToFile = dumpAssetsToFile; - } - - /// - /// - /// - /// - /// - /// - /// - public string uploaderCaps(byte[] data, string path, string param) - { - UUID inv = inventoryItemID; - string res = String.Empty; - LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); - uploadComplete.new_asset = newAssetID.ToString(); - uploadComplete.new_inventory_item = inv; - uploadComplete.state = "complete"; - - res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); - - httpListener.RemoveStreamHandler("POST", uploaderPath); - - // TODO: probably make this a better set of extensions here - string extension = ".jp2"; - if (m_invType != "image") - { - extension = ".dat"; - } - - if (m_dumpAssetsToFile) - { - SaveAssetToFile(m_assetName + extension, data); - } - handlerUpLoad = OnUpLoad; - if (handlerUpLoad != null) - { - handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); - } - - return res; - } - ///Left this in and commented in case there are unforseen issues - //private void SaveAssetToFile(string filename, byte[] data) - //{ - // FileStream fs = File.Create(filename); - // BinaryWriter bw = new BinaryWriter(fs); - // bw.Write(data); - // bw.Close(); - // fs.Close(); - //} - private static void SaveAssetToFile(string filename, byte[] data) - { - string assetPath = "UserAssets"; - if (!Directory.Exists(assetPath)) - { - Directory.CreateDirectory(assetPath); - } - FileStream fs = File.Create(Path.Combine(assetPath, Util.safeFileName(filename))); - BinaryWriter bw = new BinaryWriter(fs); - bw.Write(data); - bw.Close(); - fs.Close(); - } - } - - /// - /// This class is a callback invoked when a client sends asset data to - /// an agent inventory notecard update url - /// - public class ItemUpdater - { - public event UpdateItem OnUpLoad; - - private UpdateItem handlerUpdateItem = null; - - private string uploaderPath = String.Empty; - private UUID inventoryItemID; - private IHttpServer httpListener; - private bool m_dumpAssetToFile; - - public ItemUpdater(UUID inventoryItem, string path, IHttpServer httpServer, bool dumpAssetToFile) - { - m_dumpAssetToFile = dumpAssetToFile; - - inventoryItemID = inventoryItem; - uploaderPath = path; - httpListener = httpServer; - } - - /// - /// - /// - /// - /// - /// - /// - public string uploaderCaps(byte[] data, string path, string param) - { - UUID inv = inventoryItemID; - string res = String.Empty; - LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); - UUID assetID = UUID.Zero; - handlerUpdateItem = OnUpLoad; - if (handlerUpdateItem != null) - { - assetID = handlerUpdateItem(inv, data); - } - - uploadComplete.new_asset = assetID.ToString(); - uploadComplete.new_inventory_item = inv; - uploadComplete.state = "complete"; - - res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); - - httpListener.RemoveStreamHandler("POST", uploaderPath); - - if (m_dumpAssetToFile) - { - SaveAssetToFile("updateditem" + Util.RandomClass.Next(1, 1000) + ".dat", data); - } - - return res; - } - ///Left this in and commented in case there are unforseen issues - //private void SaveAssetToFile(string filename, byte[] data) - //{ - // FileStream fs = File.Create(filename); - // BinaryWriter bw = new BinaryWriter(fs); - // bw.Write(data); - // bw.Close(); - // fs.Close(); - //} - private static void SaveAssetToFile(string filename, byte[] data) - { - string assetPath = "UserAssets"; - if (!Directory.Exists(assetPath)) - { - Directory.CreateDirectory(assetPath); - } - FileStream fs = File.Create(Path.Combine(assetPath, filename)); - BinaryWriter bw = new BinaryWriter(fs); - bw.Write(data); - bw.Close(); - fs.Close(); - } - } - - /// - /// This class is a callback invoked when a client sends asset data to - /// a task inventory script update url - /// - public class TaskInventoryScriptUpdater - { - public event UpdateTaskScript OnUpLoad; - - private UpdateTaskScript handlerUpdateTaskScript = null; - - private string uploaderPath = String.Empty; - private UUID inventoryItemID; - private UUID primID; - private bool isScriptRunning; - private IHttpServer httpListener; - private bool m_dumpAssetToFile; - - public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, int isScriptRunning, - string path, IHttpServer httpServer, bool dumpAssetToFile) - { - m_dumpAssetToFile = dumpAssetToFile; - - this.inventoryItemID = inventoryItemID; - this.primID = primID; - - // This comes in over the packet as an integer, but actually appears to be treated as a bool - this.isScriptRunning = (0 == isScriptRunning ? false : true); - - uploaderPath = path; - httpListener = httpServer; - } - - /// - /// - /// - /// - /// - /// - /// - public string uploaderCaps(byte[] data, string path, string param) - { - try - { -// m_log.InfoFormat("[CAPS]: " + -// "TaskInventoryScriptUpdater received data: {0}, path: {1}, param: {2}", -// data, path, param)); - - string res = String.Empty; - LLSDTaskScriptUploadComplete uploadComplete = new LLSDTaskScriptUploadComplete(); - - ArrayList errors = new ArrayList(); - handlerUpdateTaskScript = OnUpLoad; - if (handlerUpdateTaskScript != null) - { - handlerUpdateTaskScript(inventoryItemID, primID, isScriptRunning, data, ref errors); - } - - uploadComplete.new_asset = inventoryItemID; - uploadComplete.compiled = errors.Count > 0 ? false : true; - uploadComplete.state = "complete"; - uploadComplete.errors = new OSDArray(); - uploadComplete.errors.Array = errors; - - res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); - - httpListener.RemoveStreamHandler("POST", uploaderPath); - - if (m_dumpAssetToFile) - { - SaveAssetToFile("updatedtaskscript" + Util.RandomClass.Next(1, 1000) + ".dat", data); - } - -// m_log.InfoFormat("[CAPS]: TaskInventoryScriptUpdater.uploaderCaps res: {0}", res); - - return res; - } - catch (Exception e) - { - m_log.Error("[CAPS]: " + e.ToString()); - } - - // XXX Maybe this should be some meaningful error packet - return null; - } - ///Left this in and commented in case there are unforseen issues - //private void SaveAssetToFile(string filename, byte[] data) - //{ - // FileStream fs = File.Create(filename); - // BinaryWriter bw = new BinaryWriter(fs); - // bw.Write(data); - // bw.Close(); - // fs.Close(); - //} - private static void SaveAssetToFile(string filename, byte[] data) - { - string assetPath = "UserAssets"; - if (!Directory.Exists(assetPath)) - { - Directory.CreateDirectory(assetPath); - } - FileStream fs = File.Create(Path.Combine(assetPath, filename)); - BinaryWriter bw = new BinaryWriter(fs); - bw.Write(data); - bw.Close(); - fs.Close(); - } - } - - public class BakedTextureUploader - { - public event UploadedBakedTexture OnUpLoad; - private UploadedBakedTexture handlerUpLoad = null; - - private string uploaderPath = String.Empty; - private UUID newAssetID; - private IHttpServer httpListener; - - public BakedTextureUploader(string path, IHttpServer httpServer) - { - newAssetID = UUID.Random(); - uploaderPath = path; - httpListener = httpServer; -// m_log.InfoFormat("[CAPS] baked texture upload starting for {0}",newAssetID); - } - - /// - /// - /// - /// - /// - /// - /// - public string uploaderCaps(byte[] data, string path, string param) - { - handlerUpLoad = OnUpLoad; - if (handlerUpLoad != null) - { - Util.FireAndForget(delegate(object o) { handlerUpLoad(newAssetID, data); }); - } - - string res = String.Empty; - LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); - uploadComplete.new_asset = newAssetID.ToString(); - uploadComplete.new_inventory_item = UUID.Zero; - uploadComplete.state = "complete"; - - res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); - - httpListener.RemoveStreamHandler("POST", uploaderPath); - -// m_log.InfoFormat("[CAPS] baked texture upload completed for {0}",newAssetID); - - return res; - } - } } } 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 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; + +using OpenMetaverse; +using Nini.Config; +using log4net; + +using OpenSim.Framework; +using OpenSim.Framework.Capabilities; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Services.Interfaces; + +using Caps = OpenSim.Framework.Capabilities.Caps; + +namespace OpenSim.Region.ClientStack.Linden +{ + public delegate void UpLoadedAsset( + string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, + byte[] data, string inventoryType, string assetType); + + public delegate void UploadedBakedTexture(UUID assetID, byte[] data); + + public delegate UUID UpdateItem(UUID itemID, byte[] data); + + public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); + + public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); + + public delegate void NewAsset(AssetBase asset); + + public delegate UUID ItemUpdatedCallback(UUID userID, UUID itemID, byte[] data); + + public delegate ArrayList TaskScriptUpdatedCallback(UUID userID, UUID itemID, UUID primID, + bool isScriptRunning, byte[] data); + + public delegate InventoryCollection FetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID, + bool fetchFolders, bool fetchItems, int sortOrder, out int version); + + /// + /// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that + /// we can popup a message on the user's client if the inventory service has permanently failed). But I didn't want + /// to just pass the whole Scene into CAPS. + /// + public delegate IClientAPI GetClientDelegate(UUID agentID); + + public class BunchOfCaps + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Scene m_Scene; + private Caps m_HostCapsObj; + + private static readonly string m_requestPath = "0000/"; + // private static readonly string m_mapLayerPath = "0001/"; + private static readonly string m_newInventory = "0002/"; + //private static readonly string m_requestTexture = "0003/"; + private static readonly string m_notecardUpdatePath = "0004/"; + private static readonly string m_notecardTaskUpdatePath = "0005/"; + // private static readonly string m_fetchInventoryPath = "0006/"; + // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. + private static readonly string m_uploadBakedTexturePath = "0010/";// This is in the LandManagementModule. + + + // These are callbacks which will be setup by the scene so that we can update scene data when we + // receive capability calls + public NewInventoryItem AddNewInventoryItem = null; + public NewAsset AddNewAsset = null; + public ItemUpdatedCallback ItemUpdatedCall = null; + public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null; + public FetchInventoryDescendentsCAPS CAPSFetchInventoryDescendents = null; + public GetClientDelegate GetClient = null; + + private bool m_persistBakedTextures = false; + private IAssetService m_assetCache; + private bool m_dumpAssetsToFile; + private string m_regionName; + private object m_fetchLock = new Object(); + + public BunchOfCaps(Scene scene, Caps caps) + { + m_Scene = scene; + m_HostCapsObj = caps; + IConfigSource config = m_Scene.Config; + if (config != null) + { + IConfig sconfig = config.Configs["Startup"]; + if (sconfig != null) + m_persistBakedTextures = sconfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); + } + + RegisterHandlers(); + + AddNewInventoryItem = m_Scene.AddUploadedInventoryItem; + ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; + TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; + CAPSFetchInventoryDescendents = m_Scene.HandleFetchInventoryDescendentsCAPS; + GetClient = m_Scene.SceneContents.GetControllingClient; + + } + + /// + /// Register a bunch of CAPS http service handlers + /// + public void RegisterHandlers() + { + m_HostCapsObj.DeregisterHandlers(); + + string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; + + RegisterRegionServiceHandlers(capsBase); + RegisterInventoryServiceHandlers(capsBase); + } + + public void RegisterRegionServiceHandlers(string capsBase) + { + try + { + // the root of all evil + m_HostCapsObj.RegisterHandler("SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest)); + m_log.DebugFormat( + "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID); + + //m_capsHandlers["MapLayer"] = + // new LLSDStreamhandler("POST", + // capsBase + m_mapLayerPath, + // GetMapLayer); + IRequestHandler req = new RestStreamHandler("POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory); + m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req); + m_HostCapsObj.RegisterHandler("UpdateScriptTask", req); + m_HostCapsObj.RegisterHandler("UploadBakedTexture", new RestStreamHandler("POST", capsBase + m_uploadBakedTexturePath, UploadBakedTexture)); + + } + catch (Exception e) + { + m_log.Error("[CAPS]: " + e.ToString()); + } + } + + public void RegisterInventoryServiceHandlers(string capsBase) + { + try + { + // I don't think this one works... + m_HostCapsObj.RegisterHandler("NewFileAgentInventory", new LLSDStreamhandler("POST", + capsBase + m_newInventory, + NewAgentInventoryRequest)); + IRequestHandler req = new RestStreamHandler("POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory); + m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); + m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); + m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); + + // As of RC 1.22.9 of the Linden client this is + // supported + + //m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest); + + // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and + // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires + // enhancements (probably filling out the folder part of the LLSD reply) to our CAPS service, + // but when I went on the Linden grid, the + // simulators I visited (version 1.21) were, surprisingly, no longer supplying this capability. Instead, + // the 1.19.1.4 client appeared to be happily flowing inventory data over UDP + // + // This is very probably just a temporary measure - once the CAPS service appears again on the Linden grid + // we will be + // able to get the data we need to implement the necessary part of the protocol to fix the issue above. + // m_capsHandlers["FetchInventoryDescendents"] = + // new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest); + + // m_capsHandlers["FetchInventoryDescendents"] = + // new LLSDStreamhandler("POST", + // capsBase + m_fetchInventory, + // FetchInventory)); + // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST", + // capsBase + m_requestTexture, + // RequestTexture); + } + catch (Exception e) + { + m_log.Error("[CAPS]: " + e.ToString()); + } + } + + /// + /// Construct a client response detailing all the capabilities this server can provide. + /// + /// + /// + /// + /// HTTP request header object + /// HTTP response header object + /// + public string SeedCapRequest(string request, string path, string param, + OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName); + + if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) + { + m_log.DebugFormat("[CAPS]: Unauthorized CAPS client"); + return string.Empty; + } + + // WARNING: Add the external too + string result = LLSDHelpers.SerialiseLLSDReply(m_HostCapsObj.CapsHandlers.CapsDetails); + + //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); + + return result; + } + + /// + /// Called by the script task update handler. Provides a URL to which the client can upload a new asset. + /// + /// + /// + /// + /// HTTP request header object + /// HTTP response header object + /// + public string ScriptTaskInventory(string request, string path, string param, + OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + try + { + m_log.Debug("[CAPS]: ScriptTaskInventory Request in region: " + m_regionName); + //m_log.DebugFormat("[CAPS]: request: {0}, path: {1}, param: {2}", request, path, param); + + Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); + LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate(); + LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest); + + string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; + string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); + + TaskInventoryScriptUpdater uploader = + new TaskInventoryScriptUpdater( + llsdUpdateRequest.item_id, + llsdUpdateRequest.task_id, + llsdUpdateRequest.is_script_running, + capsBase + uploaderPath, + m_HostCapsObj.HttpListener, + m_dumpAssetsToFile); + uploader.OnUpLoad += TaskScriptUpdated; + + m_HostCapsObj.HttpListener.AddStreamHandler(new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); + + string protocol = "http://"; + + if (m_HostCapsObj.SSLCaps) + protocol = "https://"; + + string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + + uploaderPath; + + LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); + uploadResponse.uploader = uploaderURL; + uploadResponse.state = "upload"; + + // m_log.InfoFormat("[CAPS]: " + + // "ScriptTaskInventory response: {0}", + // LLSDHelpers.SerialiseLLSDReply(uploadResponse))); + + return LLSDHelpers.SerialiseLLSDReply(uploadResponse); + } + catch (Exception e) + { + m_log.Error("[CAPS]: " + e.ToString()); + } + + return null; + } + + /// + /// Called when new asset data for an agent inventory item update has been uploaded. + /// + /// Item to update + /// Prim containing item to update + /// Signals whether the script to update is currently running + /// New asset data + public void TaskScriptUpdated(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors) + { + if (TaskScriptUpdatedCall != null) + { + ArrayList e = TaskScriptUpdatedCall(m_HostCapsObj.AgentID, itemID, primID, isScriptRunning, data); + foreach (Object item in e) + errors.Add(item); + } + } + + public string UploadBakedTexture(string request, string path, + string param, OSHttpRequest httpRequest, + OSHttpResponse httpResponse) + { + try + { + // m_log.Debug("[CAPS]: UploadBakedTexture Request in region: " + + // m_regionName); + + string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; + string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); + + BakedTextureUploader uploader = + new BakedTextureUploader(capsBase + uploaderPath, m_HostCapsObj.HttpListener); + uploader.OnUpLoad += BakedTextureUploaded; + + m_HostCapsObj.HttpListener.AddStreamHandler( + new BinaryStreamHandler("POST", capsBase + uploaderPath, + uploader.uploaderCaps)); + + string protocol = "http://"; + + if (m_HostCapsObj.SSLCaps) + protocol = "https://"; + + string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + + m_HostCapsObj.Port.ToString() + capsBase + uploaderPath; + + LLSDAssetUploadResponse uploadResponse = + new LLSDAssetUploadResponse(); + uploadResponse.uploader = uploaderURL; + uploadResponse.state = "upload"; + + return LLSDHelpers.SerialiseLLSDReply(uploadResponse); + } + catch (Exception e) + { + m_log.Error("[CAPS]: " + e.ToString()); + } + + return null; + } + + public void BakedTextureUploaded(UUID assetID, byte[] data) + { + // m_log.WarnFormat("[CAPS]: Received baked texture {0}", assetID.ToString()); + + AssetBase asset; + asset = new AssetBase(assetID, "Baked Texture", (sbyte)AssetType.Texture, m_HostCapsObj.AgentID.ToString()); + asset.Data = data; + asset.Temporary = true; + asset.Local = !m_persistBakedTextures; // Local assets aren't persisted, non-local are + m_assetCache.Store(asset); + } + + /// + /// Called when new asset data for an agent inventory item update has been uploaded. + /// + /// Item to update + /// New asset data + /// + public UUID ItemUpdated(UUID itemID, byte[] data) + { + if (ItemUpdatedCall != null) + { + return ItemUpdatedCall(m_HostCapsObj.AgentID, itemID, data); + } + + return UUID.Zero; + } + + /// + /// + /// + /// + /// + public LLSDAssetUploadResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest) + { + //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); + //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); + + if (llsdRequest.asset_type == "texture" || + llsdRequest.asset_type == "animation" || + llsdRequest.asset_type == "sound") + { + IClientAPI client = null; + IScene scene = null; + if (GetClient != null) + { + client = GetClient(m_HostCapsObj.AgentID); + scene = client.Scene; + + IMoneyModule mm = scene.RequestModuleInterface(); + + if (mm != null) + { + if (!mm.UploadCovered(client, mm.UploadCharge)) + { + if (client != null) + client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); + + LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); + errorResponse.uploader = ""; + errorResponse.state = "error"; + return errorResponse; + } + } + } + } + + string assetName = llsdRequest.name; + string assetDes = llsdRequest.description; + string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; + UUID newAsset = UUID.Random(); + UUID newInvItem = UUID.Random(); + UUID parentFolder = llsdRequest.folder_id; + string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); + + AssetUploader uploader = + new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, + llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); + m_HostCapsObj.HttpListener.AddStreamHandler( + new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); + + string protocol = "http://"; + + if (m_HostCapsObj.SSLCaps) + protocol = "https://"; + + string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + + uploaderPath; + + LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); + uploadResponse.uploader = uploaderURL; + uploadResponse.state = "upload"; + uploader.OnUpLoad += UploadCompleteHandler; + return uploadResponse; + } + + /// + /// + /// + /// + /// + /// + public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, + UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, + string assetType) + { + sbyte assType = 0; + sbyte inType = 0; + + if (inventoryType == "sound") + { + inType = 1; + assType = 1; + } + else if (inventoryType == "animation") + { + inType = 19; + assType = 20; + } + else if (inventoryType == "wearable") + { + inType = 18; + switch (assetType) + { + case "bodypart": + assType = 13; + break; + case "clothing": + assType = 5; + break; + } + } + + AssetBase asset; + asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); + asset.Data = data; + if (AddNewAsset != null) + AddNewAsset(asset); + else if (m_assetCache != null) + m_assetCache.Store(asset); + + InventoryItemBase item = new InventoryItemBase(); + item.Owner = m_HostCapsObj.AgentID; + item.CreatorId = m_HostCapsObj.AgentID.ToString(); + item.CreatorData = String.Empty; + item.ID = inventoryItem; + item.AssetID = asset.FullID; + item.Description = assetDescription; + item.Name = assetName; + item.AssetType = assType; + item.InvType = inType; + item.Folder = parentFolder; + item.CurrentPermissions = (uint)PermissionMask.All; + item.BasePermissions = (uint)PermissionMask.All; + item.EveryOnePermissions = 0; + item.NextPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer); + item.CreationDate = Util.UnixTimeSinceEpoch(); + + if (AddNewInventoryItem != null) + { + AddNewInventoryItem(m_HostCapsObj.AgentID, item); + } + } + + /// + /// Processes a fetch inventory request and sends the reply + + /// + /// + /// + /// + /// + // Request is like: + // + // folders + // + // + // fetch-folders1fetch-items1folder-id8e1e3a30-b9bf-11dc-95ff-0800200c9a66owner-id11111111-1111-0000-0000-000100bba000sort-order1 + // + // + // + // + // + // multiple fetch-folder maps are allowed within the larger folders map. + public string FetchInventoryRequest(string request, string path, string param) + { + // string unmodifiedRequest = request.ToString(); + + //m_log.DebugFormat("[AGENT INVENTORY]: Received CAPS fetch inventory request {0}", unmodifiedRequest); + m_log.Debug("[CAPS]: Inventory Request in region: " + m_regionName); + + Hashtable hash = new Hashtable(); + try + { + hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); + } + catch (LLSD.LLSDParseException pe) + { + m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message); + m_log.Error("Request: " + request.ToString()); + } + + ArrayList foldersrequested = (ArrayList)hash["folders"]; + + string response = ""; + + for (int i = 0; i < foldersrequested.Count; i++) + { + string inventoryitemstr = ""; + Hashtable inventoryhash = (Hashtable)foldersrequested[i]; + + LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); + LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); + LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); + + inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); + inventoryitemstr = inventoryitemstr.Replace("folders", ""); + inventoryitemstr = inventoryitemstr.Replace("", ""); + + response += inventoryitemstr; + } + + if (response.Length == 0) + { + // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. + // Therefore, I'm concluding that the client only has so many threads available to do requests + // and when a thread stalls.. is stays stalled. + // Therefore we need to return something valid + response = "folders"; + } + else + { + response = "folders" + response + ""; + } + + //m_log.DebugFormat("[AGENT INVENTORY]: Replying to CAPS fetch inventory request with following xml"); + //m_log.Debug(Util.GetFormattedXml(response)); + + return response; + } + + public string FetchInventoryDescendentsRequest(string request, string path, string param, OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + // nasty temporary hack here, the linden client falsely + // identifies the uuid 00000000-0000-0000-0000-000000000000 + // as a string which breaks us + // + // correctly mark it as a uuid + // + request = request.Replace("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000000"); + + // another hack 1 results in a + // System.ArgumentException: Object type System.Int32 cannot + // be converted to target type: System.Boolean + // + request = request.Replace("fetch_folders0", "fetch_folders0"); + request = request.Replace("fetch_folders1", "fetch_folders1"); + + Hashtable hash = new Hashtable(); + try + { + hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); + } + catch (LLSD.LLSDParseException pe) + { + m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message); + m_log.Error("Request: " + request.ToString()); + } + + ArrayList foldersrequested = (ArrayList)hash["folders"]; + + string response = ""; + lock (m_fetchLock) + { + for (int i = 0; i < foldersrequested.Count; i++) + { + string inventoryitemstr = ""; + Hashtable inventoryhash = (Hashtable)foldersrequested[i]; + + LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); + + try + { + LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); + } + catch (Exception e) + { + m_log.Debug("[CAPS]: caught exception doing OSD deserialize" + e); + } + LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); + + inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); + inventoryitemstr = inventoryitemstr.Replace("folders", ""); + inventoryitemstr = inventoryitemstr.Replace("", ""); + + response += inventoryitemstr; + } + + + if (response.Length == 0) + { + // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. + // Therefore, I'm concluding that the client only has so many threads available to do requests + // and when a thread stalls.. is stays stalled. + // Therefore we need to return something valid + response = "folders"; + } + else + { + response = "folders" + response + ""; + } + + //m_log.DebugFormat("[CAPS]: Replying to CAPS fetch inventory request with following xml"); + //m_log.Debug("[CAPS] "+response); + + } + return response; + } + + + + /// + /// Construct an LLSD reply packet to a CAPS inventory request + /// + /// + /// + private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch) + { + LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); + LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); + contents.agent_id = m_HostCapsObj.AgentID; + contents.owner_id = invFetch.owner_id; + contents.folder_id = invFetch.folder_id; + + reply.folders.Array.Add(contents); + InventoryCollection inv = new InventoryCollection(); + inv.Folders = new List(); + inv.Items = new List(); + int version = 0; + if (CAPSFetchInventoryDescendents != null) + { + inv = CAPSFetchInventoryDescendents(m_HostCapsObj.AgentID, invFetch.folder_id, invFetch.owner_id, invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version); + } + + if (inv.Folders != null) + { + foreach (InventoryFolderBase invFolder in inv.Folders) + { + contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); + } + } + + if (inv.Items != null) + { + foreach (InventoryItemBase invItem in inv.Items) + { + contents.items.Array.Add(ConvertInventoryItem(invItem)); + } + } + + contents.descendents = contents.items.Array.Count + contents.categories.Array.Count; + contents.version = version; + + return reply; + } + + /// + /// Convert an internal inventory folder object into an LLSD object. + /// + /// + /// + private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder) + { + LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder(); + llsdFolder.folder_id = invFolder.ID; + llsdFolder.parent_id = invFolder.ParentID; + llsdFolder.name = invFolder.Name; + if (invFolder.Type < 0 || invFolder.Type >= TaskInventoryItem.Types.Length) + llsdFolder.type = "-1"; + else + llsdFolder.type = TaskInventoryItem.Types[invFolder.Type]; + llsdFolder.preferred_type = "-1"; + + return llsdFolder; + } + + /// + /// Convert an internal inventory item object into an LLSD object. + /// + /// + /// + private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem) + { + LLSDInventoryItem llsdItem = new LLSDInventoryItem(); + llsdItem.asset_id = invItem.AssetID; + llsdItem.created_at = invItem.CreationDate; + llsdItem.desc = invItem.Description; + llsdItem.flags = (int)invItem.Flags; + llsdItem.item_id = invItem.ID; + llsdItem.name = invItem.Name; + llsdItem.parent_id = invItem.Folder; + try + { + // TODO reevaluate after upgrade to libomv >= r2566. Probably should use UtilsConversions. + llsdItem.type = TaskInventoryItem.Types[invItem.AssetType]; + llsdItem.inv_type = TaskInventoryItem.InvTypes[invItem.InvType]; + } + catch (Exception e) + { + m_log.Error("[CAPS]: Problem setting asset/inventory type while converting inventory item " + invItem.Name + " to LLSD:", e); + } + llsdItem.permissions = new LLSDPermissions(); + llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid; + llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions; + llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions; + llsdItem.permissions.group_id = invItem.GroupID; + llsdItem.permissions.group_mask = (int)invItem.GroupPermissions; + llsdItem.permissions.is_owner_group = invItem.GroupOwned; + llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions; + llsdItem.permissions.owner_id = m_HostCapsObj.AgentID; + llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions; + llsdItem.sale_info = new LLSDSaleInfo(); + llsdItem.sale_info.sale_price = invItem.SalePrice; + switch (invItem.SaleType) + { + default: + llsdItem.sale_info.sale_type = "not"; + break; + case 1: + llsdItem.sale_info.sale_type = "original"; + break; + case 2: + llsdItem.sale_info.sale_type = "copy"; + break; + case 3: + llsdItem.sale_info.sale_type = "contents"; + break; + } + + return llsdItem; + } + + /// + /// + /// + /// + /// + public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq) + { + m_log.Debug("[CAPS]: MapLayer Request in region: " + m_regionName); + LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); + mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); + return mapResponse; + } + + /// + /// + /// + /// + protected static OSDMapLayer GetOSDMapLayerResponse() + { + OSDMapLayer mapLayer = new OSDMapLayer(); + mapLayer.Right = 5000; + mapLayer.Top = 5000; + mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006"); + + return mapLayer; + } + + /// + /// + /// + /// + /// + /// + /// + public string RequestTexture(string request, string path, string param) + { + m_log.Debug("texture request " + request); + // Needs implementing (added to remove compiler warning) + return String.Empty; + } + + + /// + /// Called by the notecard update handler. Provides a URL to which the client can upload a new asset. + /// + /// + /// + /// + /// + public string NoteCardAgentInventory(string request, string path, string param, + OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + //m_log.Debug("[CAPS]: NoteCardAgentInventory Request in region: " + m_regionName + "\n" + request); + //m_log.Debug("[CAPS]: NoteCardAgentInventory Request is: " + request); + + //OpenMetaverse.StructuredData.OSDMap hash = (OpenMetaverse.StructuredData.OSDMap)OpenMetaverse.StructuredData.LLSDParser.DeserializeBinary(Utils.StringToBytes(request)); + Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); + LLSDItemUpdate llsdRequest = new LLSDItemUpdate(); + LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest); + + string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; + string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); + + ItemUpdater uploader = + new ItemUpdater(llsdRequest.item_id, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); + uploader.OnUpLoad += ItemUpdated; + + m_HostCapsObj.HttpListener.AddStreamHandler( + new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); + + string protocol = "http://"; + + if (m_HostCapsObj.SSLCaps) + protocol = "https://"; + + string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + + uploaderPath; + + LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); + uploadResponse.uploader = uploaderURL; + uploadResponse.state = "upload"; + + // m_log.InfoFormat("[CAPS]: " + + // "NoteCardAgentInventory response: {0}", + // LLSDHelpers.SerialiseLLSDReply(uploadResponse))); + + return LLSDHelpers.SerialiseLLSDReply(uploadResponse); + } + } + + public class AssetUploader + { + public event UpLoadedAsset OnUpLoad; + private UpLoadedAsset handlerUpLoad = null; + + private string uploaderPath = String.Empty; + private UUID newAssetID; + private UUID inventoryItemID; + private UUID parentFolder; + private IHttpServer httpListener; + private bool m_dumpAssetsToFile; + private string m_assetName = String.Empty; + private string m_assetDes = String.Empty; + + private string m_invType = String.Empty; + private string m_assetType = String.Empty; + + public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, + UUID parentFolderID, string invType, string assetType, string path, + IHttpServer httpServer, bool dumpAssetsToFile) + { + m_assetName = assetName; + m_assetDes = description; + newAssetID = assetID; + inventoryItemID = inventoryItem; + uploaderPath = path; + httpListener = httpServer; + parentFolder = parentFolderID; + m_assetType = assetType; + m_invType = invType; + m_dumpAssetsToFile = dumpAssetsToFile; + } + + /// + /// + /// + /// + /// + /// + /// + public string uploaderCaps(byte[] data, string path, string param) + { + UUID inv = inventoryItemID; + string res = String.Empty; + LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); + uploadComplete.new_asset = newAssetID.ToString(); + uploadComplete.new_inventory_item = inv; + uploadComplete.state = "complete"; + + res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); + + httpListener.RemoveStreamHandler("POST", uploaderPath); + + // TODO: probably make this a better set of extensions here + string extension = ".jp2"; + if (m_invType != "image") + { + extension = ".dat"; + } + + if (m_dumpAssetsToFile) + { + SaveAssetToFile(m_assetName + extension, data); + } + handlerUpLoad = OnUpLoad; + if (handlerUpLoad != null) + { + handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); + } + + return res; + } + ///Left this in and commented in case there are unforseen issues + //private void SaveAssetToFile(string filename, byte[] data) + //{ + // FileStream fs = File.Create(filename); + // BinaryWriter bw = new BinaryWriter(fs); + // bw.Write(data); + // bw.Close(); + // fs.Close(); + //} + private static void SaveAssetToFile(string filename, byte[] data) + { + string assetPath = "UserAssets"; + if (!Directory.Exists(assetPath)) + { + Directory.CreateDirectory(assetPath); + } + FileStream fs = File.Create(Path.Combine(assetPath, Util.safeFileName(filename))); + BinaryWriter bw = new BinaryWriter(fs); + bw.Write(data); + bw.Close(); + fs.Close(); + } + } + + /// + /// This class is a callback invoked when a client sends asset data to + /// an agent inventory notecard update url + /// + public class ItemUpdater + { + public event UpdateItem OnUpLoad; + + private UpdateItem handlerUpdateItem = null; + + private string uploaderPath = String.Empty; + private UUID inventoryItemID; + private IHttpServer httpListener; + private bool m_dumpAssetToFile; + + public ItemUpdater(UUID inventoryItem, string path, IHttpServer httpServer, bool dumpAssetToFile) + { + m_dumpAssetToFile = dumpAssetToFile; + + inventoryItemID = inventoryItem; + uploaderPath = path; + httpListener = httpServer; + } + + /// + /// + /// + /// + /// + /// + /// + public string uploaderCaps(byte[] data, string path, string param) + { + UUID inv = inventoryItemID; + string res = String.Empty; + LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); + UUID assetID = UUID.Zero; + handlerUpdateItem = OnUpLoad; + if (handlerUpdateItem != null) + { + assetID = handlerUpdateItem(inv, data); + } + + uploadComplete.new_asset = assetID.ToString(); + uploadComplete.new_inventory_item = inv; + uploadComplete.state = "complete"; + + res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); + + httpListener.RemoveStreamHandler("POST", uploaderPath); + + if (m_dumpAssetToFile) + { + SaveAssetToFile("updateditem" + Util.RandomClass.Next(1, 1000) + ".dat", data); + } + + return res; + } + ///Left this in and commented in case there are unforseen issues + //private void SaveAssetToFile(string filename, byte[] data) + //{ + // FileStream fs = File.Create(filename); + // BinaryWriter bw = new BinaryWriter(fs); + // bw.Write(data); + // bw.Close(); + // fs.Close(); + //} + private static void SaveAssetToFile(string filename, byte[] data) + { + string assetPath = "UserAssets"; + if (!Directory.Exists(assetPath)) + { + Directory.CreateDirectory(assetPath); + } + FileStream fs = File.Create(Path.Combine(assetPath, filename)); + BinaryWriter bw = new BinaryWriter(fs); + bw.Write(data); + bw.Close(); + fs.Close(); + } + } + + /// + /// This class is a callback invoked when a client sends asset data to + /// a task inventory script update url + /// + public class TaskInventoryScriptUpdater + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public event UpdateTaskScript OnUpLoad; + + private UpdateTaskScript handlerUpdateTaskScript = null; + + private string uploaderPath = String.Empty; + private UUID inventoryItemID; + private UUID primID; + private bool isScriptRunning; + private IHttpServer httpListener; + private bool m_dumpAssetToFile; + + public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, int isScriptRunning, + string path, IHttpServer httpServer, bool dumpAssetToFile) + { + m_dumpAssetToFile = dumpAssetToFile; + + this.inventoryItemID = inventoryItemID; + this.primID = primID; + + // This comes in over the packet as an integer, but actually appears to be treated as a bool + this.isScriptRunning = (0 == isScriptRunning ? false : true); + + uploaderPath = path; + httpListener = httpServer; + } + + /// + /// + /// + /// + /// + /// + /// + public string uploaderCaps(byte[] data, string path, string param) + { + try + { + // m_log.InfoFormat("[CAPS]: " + + // "TaskInventoryScriptUpdater received data: {0}, path: {1}, param: {2}", + // data, path, param)); + + string res = String.Empty; + LLSDTaskScriptUploadComplete uploadComplete = new LLSDTaskScriptUploadComplete(); + + ArrayList errors = new ArrayList(); + handlerUpdateTaskScript = OnUpLoad; + if (handlerUpdateTaskScript != null) + { + handlerUpdateTaskScript(inventoryItemID, primID, isScriptRunning, data, ref errors); + } + + uploadComplete.new_asset = inventoryItemID; + uploadComplete.compiled = errors.Count > 0 ? false : true; + uploadComplete.state = "complete"; + uploadComplete.errors = new OSDArray(); + uploadComplete.errors.Array = errors; + + res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); + + httpListener.RemoveStreamHandler("POST", uploaderPath); + + if (m_dumpAssetToFile) + { + SaveAssetToFile("updatedtaskscript" + Util.RandomClass.Next(1, 1000) + ".dat", data); + } + + // m_log.InfoFormat("[CAPS]: TaskInventoryScriptUpdater.uploaderCaps res: {0}", res); + + return res; + } + catch (Exception e) + { + m_log.Error("[CAPS]: " + e.ToString()); + } + + // XXX Maybe this should be some meaningful error packet + return null; + } + ///Left this in and commented in case there are unforseen issues + //private void SaveAssetToFile(string filename, byte[] data) + //{ + // FileStream fs = File.Create(filename); + // BinaryWriter bw = new BinaryWriter(fs); + // bw.Write(data); + // bw.Close(); + // fs.Close(); + //} + private static void SaveAssetToFile(string filename, byte[] data) + { + string assetPath = "UserAssets"; + if (!Directory.Exists(assetPath)) + { + Directory.CreateDirectory(assetPath); + } + FileStream fs = File.Create(Path.Combine(assetPath, filename)); + BinaryWriter bw = new BinaryWriter(fs); + bw.Write(data); + bw.Close(); + fs.Close(); + } + } + + public class BakedTextureUploader + { + public event UploadedBakedTexture OnUpLoad; + private UploadedBakedTexture handlerUpLoad = null; + + private string uploaderPath = String.Empty; + private UUID newAssetID; + private IHttpServer httpListener; + + public BakedTextureUploader(string path, IHttpServer httpServer) + { + newAssetID = UUID.Random(); + uploaderPath = path; + httpListener = httpServer; + // m_log.InfoFormat("[CAPS] baked texture upload starting for {0}",newAssetID); + } + + /// + /// + /// + /// + /// + /// + /// + public string uploaderCaps(byte[] data, string path, string param) + { + handlerUpLoad = OnUpLoad; + if (handlerUpLoad != null) + { + Util.FireAndForget(delegate(object o) { handlerUpLoad(newAssetID, data); }); + } + + string res = String.Empty; + LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); + uploadComplete.new_asset = newAssetID.ToString(); + uploadComplete.new_inventory_item = UUID.Zero; + uploadComplete.state = "complete"; + + res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); + + httpListener.RemoveStreamHandler("POST", uploaderPath); + + // m_log.InfoFormat("[CAPS] baked texture upload completed for {0}",newAssetID); + + return res; + } + } + +} 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 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; + +using log4net; +using Nini.Config; +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using Caps = OpenSim.Framework.Capabilities.Caps; + +namespace OpenSim.Region.ClientStack.Linden +{ + + public class BunchOfCapsModule : INonSharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Scene m_Scene; + + #region INonSharedRegionModule + + public string Name { get { return "BunchOfCapsModule"; } } + + public Type ReplaceableInterface { get { return null; } } + + public void Initialise(IConfigSource source) + { + } + + public void Close() { } + + public void AddRegion(Scene scene) + { + m_Scene = scene; + m_Scene.EventManager.OnRegisterCaps += OnRegisterCaps; + } + + public void RemoveRegion(Scene scene) + { + } + + public void RegionLoaded(Scene scene) + { + } + + public void PostInitialise() { } + #endregion + + private void OnRegisterCaps(UUID agentID, Caps caps) + { + new BunchOfCaps(m_Scene, caps); + } + + } +} 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 } if (AvatarID != UUID.Zero) { - return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsHandlerForUser(AvatarID)); + return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID)); } else { 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 UUID parentFolder = llsdRequest.folder_id; string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/"; - Caps.AssetUploader uploader = - new Caps.AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, + AssetUploader uploader = + new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile); MainServer.Instance.AddStreamHandler( 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 /// /// Each agent has its own capabilities handler. /// - protected Dictionary m_capsHandlers = new Dictionary(); + protected Dictionary m_capsObjects = new Dictionary(); protected Dictionary capsPaths = new Dictionary(); protected Dictionary> childrenSeeds @@ -95,19 +95,19 @@ namespace OpenSim.Region.CoreModules.Framework get { return null; } } - public void AddCapsHandler(UUID agentId) + public void CreateCaps(UUID agentId) { if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId)) return; String capsObjectPath = GetCapsPath(agentId); - if (m_capsHandlers.ContainsKey(agentId)) + if (m_capsObjects.ContainsKey(agentId)) { - Caps oldCaps = m_capsHandlers[agentId]; + Caps oldCaps = m_capsObjects[agentId]; m_log.DebugFormat( - "[CAPS]: Reregistering caps for agent {0}. Old caps path {1}, new caps path {2}. ", + "[CAPS]: Recreating caps for agent {0}. Old caps path {1}, new caps path {2}. ", agentId, oldCaps.CapsObjectPath, capsObjectPath); // This should not happen. The caller code is confused. We need to fix that. // CAPs can never be reregistered, or the client will be confused. @@ -115,39 +115,29 @@ namespace OpenSim.Region.CoreModules.Framework //return; } - Caps caps - = new Caps(m_scene, - m_scene.AssetService, MainServer.Instance, m_scene.RegionInfo.ExternalHostName, + Caps caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName, (MainServer.Instance == null) ? 0: MainServer.Instance.Port, - capsObjectPath, agentId, m_scene.DumpAssetsToFile, m_scene.RegionInfo.RegionName); + capsObjectPath, agentId, m_scene.RegionInfo.RegionName); - caps.RegisterHandlers(); + m_capsObjects[agentId] = caps; m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps); - - caps.AddNewInventoryItem = m_scene.AddUploadedInventoryItem; - caps.ItemUpdatedCall = m_scene.CapsUpdateInventoryItemAsset; - caps.TaskScriptUpdatedCall = m_scene.CapsUpdateTaskInventoryScriptAsset; - caps.CAPSFetchInventoryDescendents = m_scene.HandleFetchInventoryDescendentsCAPS; - caps.GetClient = m_scene.SceneContents.GetControllingClient; - - m_capsHandlers[agentId] = caps; } - public void RemoveCapsHandler(UUID agentId) + public void RemoveCaps(UUID agentId) { if (childrenSeeds.ContainsKey(agentId)) { childrenSeeds.Remove(agentId); } - lock (m_capsHandlers) + lock (m_capsObjects) { - if (m_capsHandlers.ContainsKey(agentId)) + if (m_capsObjects.ContainsKey(agentId)) { - m_capsHandlers[agentId].DeregisterHandlers(); - m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsHandlers[agentId]); - m_capsHandlers.Remove(agentId); + m_capsObjects[agentId].DeregisterHandlers(); + m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsObjects[agentId]); + m_capsObjects.Remove(agentId); } else { @@ -158,20 +148,20 @@ namespace OpenSim.Region.CoreModules.Framework } } - public Caps GetCapsHandlerForUser(UUID agentId) + public Caps GetCapsForUser(UUID agentId) { - lock (m_capsHandlers) + lock (m_capsObjects) { - if (m_capsHandlers.ContainsKey(agentId)) + if (m_capsObjects.ContainsKey(agentId)) { - return m_capsHandlers[agentId]; + return m_capsObjects[agentId]; } } return null; } - public void NewUserConnection(AgentCircuitData agent) + public void SetAgentCapsSeeds(AgentCircuitData agent) { capsPaths[agent.AgentID] = agent.CapsPath; childrenSeeds[agent.AgentID] @@ -241,7 +231,7 @@ namespace OpenSim.Region.CoreModules.Framework System.Text.StringBuilder caps = new System.Text.StringBuilder(); caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); - foreach (KeyValuePair kvp in m_capsHandlers) + foreach (KeyValuePair kvp in m_capsObjects) { caps.AppendFormat("** User {0}:\n", kvp.Key); 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 string derezAvatarPath = "/agent/" + AvatarRezCapUUID + "/rez_avatar/derez"; // Get a reference to the user's cap so we can pull out the Caps Object Path Caps userCap - = homeScene.CapsModule.GetCapsHandlerForUser(agentData.AgentID); + = homeScene.CapsModule.GetCapsForUser(agentData.AgentID); string rezHttpProtocol = "http://"; string regionCapsHttpProtocol = "http://"; @@ -700,7 +700,7 @@ namespace OpenSim.Region.CoreModules.InterGrid { // Get a referenceokay - to their Cap object so we can pull out the capobjectroot Caps userCap - = homeScene.CapsModule.GetCapsHandlerForUser(userData.AgentID); + = homeScene.CapsModule.GetCapsForUser(userData.AgentID); //Update the circuit data in the region so this user is authorized 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 { public interface ICapabilitiesModule { - void NewUserConnection(AgentCircuitData agent); - /// /// Add a caps handler for the given agent. If the CAPS handler already exists for this agent, /// then it is replaced by a new CAPS handler. - /// - /// FIXME: On login this is called twice, once for the login and once when the connection is made. - /// This is somewhat innefficient and should be fixed. The initial login creation is necessary - /// since the client asks for capabilities immediately after being informed of the seed. /// /// /// - void AddCapsHandler(UUID agentId); + void CreateCaps(UUID agentId); /// /// Remove the caps handler for a given agent. /// /// - void RemoveCapsHandler(UUID agentId); + void RemoveCaps(UUID agentId); /// /// Will return null if the agent doesn't have a caps handler registered /// /// - Caps GetCapsHandlerForUser(UUID agentId); + Caps GetCapsForUser(UUID agentId); + + void SetAgentCapsSeeds(AgentCircuitData agent); Dictionary GetChildrenSeeds(UUID agentID); 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 m_sceneGraph.removeUserCount(!childagentYN); if (CapsModule != null) - CapsModule.RemoveCapsHandler(agentID); + CapsModule.RemoveCaps(agentID); // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever // this method is doing is HORRIBLE!!! @@ -3290,8 +3290,8 @@ namespace OpenSim.Region.Framework.Scenes if (CapsModule != null) { - CapsModule.NewUserConnection(agent); - CapsModule.AddCapsHandler(agent.AgentID); + CapsModule.SetAgentCapsSeeds(agent); + CapsModule.CreateCaps(agent.AgentID); } } else @@ -3309,7 +3309,7 @@ namespace OpenSim.Region.Framework.Scenes sp.AdjustKnownSeeds(); if (CapsModule != null) - CapsModule.NewUserConnection(agent); + CapsModule.SetAgentCapsSeeds(agent); } } -- cgit v1.1