using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Capabilities;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Framework.Servers.HttpServer;
using OSDMap = OpenMetaverse.StructuredData.OSDMap;
namespace OpenSim.Region.ClientStack.Linden
{
public delegate UUID UpdateItem(UUID itemID, UUID objectID, byte[] data);
public delegate UUID ItemUpdatedCallback(UUID userID, UUID itemID, UUID objectID, byte[] data);
public partial class BunchOfCaps
{
public void UpdateNotecardItemAsset(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, OSDMap map)
{
UpdateInventoryItemAsset(httpRequest, httpResponse, map, (byte)AssetType.Notecard);
}
public void UpdateAnimSetItemAsset(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, OSDMap map)
{
//UpdateInventoryItemAsset(httpRequest, httpResponse, map, CustomInventoryType.AnimationSet);
}
public void UpdateScriptItemAsset(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, OSDMap map)
{
UpdateInventoryItemAsset(httpRequest, httpResponse, map, (byte)AssetType.LSLText);
}
public void UpdateSettingsItemAsset(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, OSDMap map)
{
UpdateInventoryItemAsset(httpRequest, httpResponse, map, (byte)AssetType.Settings);
}
public void UpdateMaterialItemAsset(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, OSDMap map)
{
UpdateInventoryItemAsset(httpRequest, httpResponse, map, (byte)AssetType.Material);
}
public void UpdateGestureItemAsset(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, OSDMap map)
{
UpdateInventoryItemAsset(httpRequest, httpResponse, map, (byte)AssetType.Gesture);
}
private void UpdateInventoryItemAsset(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, OSDMap map, byte atype, bool taskSript = false)
{
m_log.Debug("[CAPS]: UpdateInventoryItemAsset Request in region: " + m_regionName + "\n");
httpResponse.StatusCode = (int)HttpStatusCode.OK;
UUID itemID = UUID.Zero;
UUID objectID = UUID.Zero;
try
{
if (map.TryGetValue("item_id", out OSD itmp))
itemID = itmp;
if (map.TryGetValue("task_id", out OSD tmp))
objectID = tmp;
}
catch { }
if (itemID.IsZero())
{
LLSDAssetUploadError error = new LLSDAssetUploadError();
error.message = "failed to recode request";
error.identifier = UUID.Zero;
httpResponse.RawBuffer = Util.UTF8NBGetbytes(LLSDHelpers.SerialiseLLSDReply(error));
return;
}
if (!objectID.IsZero())
{
SceneObjectPart sop = m_Scene.GetSceneObjectPart(objectID);
if (sop == null)
{
LLSDAssetUploadError error = new LLSDAssetUploadError();
error.message = "object not found";
error.identifier = UUID.Zero;
httpResponse.RawBuffer = Util.UTF8NBGetbytes(LLSDHelpers.SerialiseLLSDReply(error));
return;
}
if (!m_Scene.Permissions.CanEditObjectInventory(objectID, m_AgentID))
{
LLSDAssetUploadError error = new LLSDAssetUploadError();
error.message = "No permissions to edit objec";
error.identifier = UUID.Zero;
httpResponse.RawBuffer = Util.UTF8NBGetbytes(LLSDHelpers.SerialiseLLSDReply(error));
return;
}
}
string uploaderPath = GetNewCapPath();
string protocol = m_HostCapsObj.SSLCaps ? "https://" : "http://";
string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath;
LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
uploadResponse.uploader = uploaderURL;
uploadResponse.state = "upload";
ItemUpdater uploader = new ItemUpdater(itemID, objectID, atype, uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile);
uploader.m_remoteAdress = httpRequest.RemoteIPEndPoint.Address;
uploader.OnUpLoad += ItemUpdated;
var uploaderHandler = new SimpleBinaryHandler("POST", uploaderPath, uploader.process);
uploaderHandler.MaxDataSize = 10000000; // change per asset type?
m_HostCapsObj.HttpListener.AddSimpleStreamHandler(uploaderHandler);
// m_log.InfoFormat("[CAPS]: UpdateAgentInventoryAsset response: {0}",
// LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
httpResponse.RawBuffer = Util.UTF8NBGetbytes(LLSDHelpers.SerialiseLLSDReply(uploadResponse));
}
///
/// Called when new asset data for an inventory item update has been uploaded.
///
/// Item to update
/// New asset data
///
public UUID ItemUpdated(UUID itemID, UUID objectID, byte[] data)
{
if (ItemUpdatedCall != null)
{
return ItemUpdatedCall(m_HostCapsObj.AgentID, itemID, objectID, data);
}
return UUID.Zero;
}
///
/// 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 void UpdateScriptTaskInventory(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, OSDMap map)
{
httpResponse.StatusCode = (int)HttpStatusCode.OK;
try
{
//m_log.Debug("[CAPS]: ScriptTaskInventory Request in region: " + m_regionName);
//m_log.DebugFormat("[CAPS]: request: {0}, path: {1}, param: {2}", request, path, param);
UUID itemID = UUID.Zero;
UUID objectID = UUID.Zero;
bool is_script_running = false;
OSD tmp;
try
{
if (map.TryGetValue("item_id", out tmp))
itemID = tmp;
if (map.TryGetValue("task_id", out tmp))
objectID = tmp;
if (map.TryGetValue("is_script_running", out tmp))
is_script_running = tmp;
}
catch { }
if (itemID.IsZero() || objectID.IsZero())
{
LLSDAssetUploadError error = new LLSDAssetUploadError();
error.message = "failed to recode request";
error.identifier = UUID.Zero;
httpResponse.RawBuffer = Util.UTF8NBGetbytes(LLSDHelpers.SerialiseLLSDReply(error));
return;
}
SceneObjectPart sop = m_Scene.GetSceneObjectPart(objectID);
if (sop == null)
{
LLSDAssetUploadError error = new LLSDAssetUploadError();
error.message = "object not found";
error.identifier = UUID.Zero;
httpResponse.RawBuffer = Util.UTF8NBGetbytes(LLSDHelpers.SerialiseLLSDReply(error));
return;
}
if (!m_Scene.Permissions.CanEditObjectInventory(objectID, m_AgentID))
{
LLSDAssetUploadError error = new LLSDAssetUploadError();
error.message = "No permissions to edit objec";
error.identifier = UUID.Zero;
httpResponse.RawBuffer = Util.UTF8NBGetbytes(LLSDHelpers.SerialiseLLSDReply(error));
return;
}
if (!m_Scene.Permissions.CanEditScript(itemID, objectID, m_AgentID))
{
LLSDAssetUploadError error = new LLSDAssetUploadError();
error.message = "No permissions to edit script";
error.identifier = UUID.Zero;
httpResponse.RawBuffer = Util.UTF8NBGetbytes(LLSDHelpers.SerialiseLLSDReply(error));
return;
}
string uploaderPath = GetNewCapPath();
string protocol = m_HostCapsObj.SSLCaps ? "https://" : "http://";
string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath;
LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
uploadResponse.uploader = uploaderURL;
uploadResponse.state = "upload";
TaskInventoryScriptUpdater uploader = new TaskInventoryScriptUpdater(itemID, objectID, is_script_running,
uploaderPath, m_HostCapsObj.HttpListener, httpRequest.RemoteIPEndPoint.Address, m_dumpAssetsToFile);
uploader.OnUpLoad += TaskScriptUpdated;
var uploaderHandler = new SimpleBinaryHandler("POST", uploaderPath, uploader.process);
uploaderHandler.MaxDataSize = 10000000; // change per asset type?
m_HostCapsObj.HttpListener.AddSimpleStreamHandler(uploaderHandler);
// m_log.InfoFormat("[CAPS]: " +
// "ScriptTaskInventory response: {0}",
// LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
httpResponse.RawBuffer = Util.UTF8NBGetbytes(LLSDHelpers.SerialiseLLSDReply(uploadResponse));
}
catch (Exception e)
{
m_log.Error("[UpdateScriptTaskInventory]: " + e.ToString());
}
}
///
/// 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);
}
}
static public bool ValidateAssetData(byte assetType, byte[] data)
{
return true;
}
///
/// This class is a callback invoked when a client sends asset data to
/// an agent inventory notecard update url
///
public class ItemUpdater : ExpiringCapBase
{
public event UpdateItem OnUpLoad = null;
private UUID m_inventoryItemID;
private UUID m_objectID;
private bool m_dumpAssetToFile;
public IPAddress m_remoteAdress;
private byte m_assetType;
public ItemUpdater(UUID inventoryItem, UUID objectid, byte aType, string path, IHttpServer httpServer, bool dumpAssetToFile):
base(httpServer, path)
{
m_dumpAssetToFile = dumpAssetToFile;
m_inventoryItemID = inventoryItem;
m_objectID = objectid;
m_httpListener = httpServer;
m_assetType = aType;
Start(30000);
}
///
/// Handle raw uploaded asset data.
///
///
///
///
///
public void process(IOSHttpRequest request, IOSHttpResponse response, byte[] data)
{
Stop();
if (!request.RemoteIPEndPoint.Address.Equals(m_remoteAdress))
{
response.StatusCode = (int)HttpStatusCode.Unauthorized;
return;
}
string res = String.Empty;
if (OnUpLoad == null)
{
response.StatusCode = (int)HttpStatusCode.Gone;
return;
}
if (!BunchOfCaps.ValidateAssetData(m_assetType, data))
{
response.StatusCode = (int)HttpStatusCode.BadRequest;
return;
}
UUID assetID = OnUpLoad(m_inventoryItemID, m_objectID, data);
if (assetID.IsZero())
{
LLSDAssetUploadError uperror = new LLSDAssetUploadError();
uperror.message = "Failed to update inventory item asset";
uperror.identifier = m_inventoryItemID;
res = LLSDHelpers.SerialiseLLSDReply(uperror);
}
else
{
LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
uploadComplete.new_asset = assetID.ToString();
uploadComplete.new_inventory_item = m_inventoryItemID;
uploadComplete.state = "complete";
res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
}
if (m_dumpAssetToFile)
{
Util.SaveAssetToFile("updateditem" + Random.Shared.Next(1, 1000) + ".dat", data);
}
response.StatusCode = (int)HttpStatusCode.OK;
response.RawBuffer = Util.UTF8NBGetbytes(res);
}
}
///
/// This class is a callback invoked when a client sends asset data to
/// a task inventory script update url
///
public class TaskInventoryScriptUpdater : ExpiringCapBase
{
public event UpdateTaskScript OnUpLoad;
private UUID m_inventoryItemID;
private UUID m_primID;
private bool m_isScriptRunning;
private bool m_dumpAssetToFile;
public IPAddress m_remoteAddress;
public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, bool isScriptRunning,
string path, IHttpServer httpServer, IPAddress address,
bool dumpAssetToFile) : base(httpServer, path)
{
m_dumpAssetToFile = dumpAssetToFile;
m_inventoryItemID = inventoryItemID;
m_primID = primID;
m_isScriptRunning = isScriptRunning;
m_remoteAddress = address;
Start(30000);
}
///
///
///
///
///
///
///
public void process(IOSHttpRequest request, IOSHttpResponse response, byte[] data)
{
Stop();
if (!request.RemoteIPEndPoint.Address.Equals(m_remoteAddress))
{
response.StatusCode = (int)HttpStatusCode.Unauthorized;
return;
}
if (OnUpLoad == null)
{
response.StatusCode = (int)HttpStatusCode.Gone;
return;
}
if (!BunchOfCaps.ValidateAssetData((byte)AssetType.LSLText, data))
{
response.StatusCode = (int)HttpStatusCode.BadRequest;
return;
}
response.StatusCode = (int)HttpStatusCode.OK;
try
{
string res = String.Empty;
LLSDTaskScriptUploadComplete uploadComplete = new LLSDTaskScriptUploadComplete();
ArrayList errors = new ArrayList();
OnUpLoad?.Invoke(m_inventoryItemID, m_primID, m_isScriptRunning, data, ref errors);
uploadComplete.new_asset = m_inventoryItemID;
uploadComplete.compiled = errors.Count > 0 ? false : true;
uploadComplete.state = "complete";
uploadComplete.errors = new OpenSim.Framework.Capabilities.OSDArray();
uploadComplete.errors.Array = errors;
res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
if (m_dumpAssetToFile)
{
Util.SaveAssetToFile("updatedtaskscript" + Random.Shared.Next(1, 1000) + ".dat", data);
}
// m_log.InfoFormat("[CAPS]: TaskInventoryScriptUpdater.uploaderCaps res: {0}", res);
response.RawBuffer = Util.UTF8NBGetbytes(res);
}
catch
{
LLSDAssetUploadError error = new LLSDAssetUploadError();
error.message = "could not compile script";
error.identifier = UUID.Zero;
response.RawBuffer = Util.UTF8NBGetbytes(LLSDHelpers.SerialiseLLSDReply(error));
return;
}
}
}
}
}