Caps.cs 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections;
  29. using System.Collections.Generic;
  30. using System.IO;
  31. using System.Reflection;
  32. using log4net;
  33. using OpenMetaverse;
  34. using OpenSim.Framework.Servers;
  35. using OpenSim.Framework.Servers.HttpServer;
  36. using OpenSim.Services.Interfaces;
  37. // using OpenSim.Region.Framework.Interfaces;
  38. namespace OpenSim.Framework.Capabilities
  39. {
  40. public delegate void UpLoadedAsset(
  41. string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
  42. byte[] data, string inventoryType, string assetType);
  43. public delegate UUID UpdateItem(UUID itemID, byte[] data);
  44. public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
  45. public delegate void NewInventoryItem(UUID userID, InventoryItemBase item);
  46. public delegate void NewAsset(AssetBase asset);
  47. public delegate UUID ItemUpdatedCallback(UUID userID, UUID itemID, byte[] data);
  48. public delegate ArrayList TaskScriptUpdatedCallback(UUID userID, UUID itemID, UUID primID,
  49. bool isScriptRunning, byte[] data);
  50. public delegate InventoryCollection FetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID,
  51. bool fetchFolders, bool fetchItems, int sortOrder, out int version);
  52. /// <summary>
  53. /// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that
  54. /// we can popup a message on the user's client if the inventory service has permanently failed). But I didn't want
  55. /// to just pass the whole Scene into CAPS.
  56. /// </summary>
  57. public delegate IClientAPI GetClientDelegate(UUID agentID);
  58. public class Caps
  59. {
  60. private static readonly ILog m_log =
  61. LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  62. private string m_httpListenerHostName;
  63. private uint m_httpListenPort;
  64. /// <summary>
  65. /// This is the uuid portion of every CAPS path. It is used to make capability urls private to the requester.
  66. /// </summary>
  67. private string m_capsObjectPath;
  68. public string CapsObjectPath { get { return m_capsObjectPath; } }
  69. private CapsHandlers m_capsHandlers;
  70. private static readonly string m_requestPath = "0000/";
  71. // private static readonly string m_mapLayerPath = "0001/";
  72. private static readonly string m_newInventory = "0002/";
  73. //private static readonly string m_requestTexture = "0003/";
  74. private static readonly string m_notecardUpdatePath = "0004/";
  75. private static readonly string m_notecardTaskUpdatePath = "0005/";
  76. // private static readonly string m_fetchInventoryPath = "0006/";
  77. // The following entries are in a module, however, they are also here so that we don't re-assign
  78. // the path to another cap by mistake.
  79. // private static readonly string m_parcelVoiceInfoRequestPath = "0007/"; // This is in a module.
  80. // private static readonly string m_provisionVoiceAccountRequestPath = "0008/";// This is in a module.
  81. // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
  82. //private string eventQueue = "0100/";
  83. private IScene m_Scene;
  84. private IHttpServer m_httpListener;
  85. private UUID m_agentID;
  86. private IAssetService m_assetCache;
  87. private int m_eventQueueCount = 1;
  88. private Queue<string> m_capsEventQueue = new Queue<string>();
  89. private bool m_dumpAssetsToFile;
  90. private string m_regionName;
  91. private object m_fetchLock = new Object();
  92. public bool SSLCaps
  93. {
  94. get { return m_httpListener.UseSSL; }
  95. }
  96. public string SSLCommonName
  97. {
  98. get { return m_httpListener.SSLCommonName; }
  99. }
  100. public CapsHandlers CapsHandlers
  101. {
  102. get { return m_capsHandlers; }
  103. }
  104. // These are callbacks which will be setup by the scene so that we can update scene data when we
  105. // receive capability calls
  106. public NewInventoryItem AddNewInventoryItem = null;
  107. public NewAsset AddNewAsset = null;
  108. public ItemUpdatedCallback ItemUpdatedCall = null;
  109. public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null;
  110. public FetchInventoryDescendentsCAPS CAPSFetchInventoryDescendents = null;
  111. public GetClientDelegate GetClient = null;
  112. public Caps(IScene scene, IAssetService assetCache, IHttpServer httpServer, string httpListen, uint httpPort, string capsPath,
  113. UUID agent, bool dumpAssetsToFile, string regionName)
  114. {
  115. m_Scene = scene;
  116. m_assetCache = assetCache;
  117. m_capsObjectPath = capsPath;
  118. m_httpListener = httpServer;
  119. m_httpListenerHostName = httpListen;
  120. m_httpListenPort = httpPort;
  121. if (httpServer.UseSSL)
  122. {
  123. m_httpListenPort = httpServer.SSLPort;
  124. httpListen = httpServer.SSLCommonName;
  125. httpPort = httpServer.SSLPort;
  126. }
  127. m_agentID = agent;
  128. m_dumpAssetsToFile = dumpAssetsToFile;
  129. m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort, httpServer.UseSSL);
  130. m_regionName = regionName;
  131. }
  132. /// <summary>
  133. /// Register all CAPS http service handlers
  134. /// </summary>
  135. public void RegisterHandlers()
  136. {
  137. DeregisterHandlers();
  138. string capsBase = "/CAPS/" + m_capsObjectPath;
  139. RegisterRegionServiceHandlers(capsBase);
  140. RegisterInventoryServiceHandlers(capsBase);
  141. }
  142. public void RegisterRegionServiceHandlers(string capsBase)
  143. {
  144. try
  145. {
  146. // the root of all evil
  147. m_capsHandlers["SEED"] = new RestStreamHandler("POST", capsBase + m_requestPath, CapsRequest);
  148. m_log.DebugFormat(
  149. "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_agentID);
  150. //m_capsHandlers["MapLayer"] =
  151. // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
  152. // capsBase + m_mapLayerPath,
  153. // GetMapLayer);
  154. m_capsHandlers["UpdateScriptTaskInventory"] =
  155. new RestStreamHandler("POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory);
  156. m_capsHandlers["UpdateScriptTask"] = m_capsHandlers["UpdateScriptTaskInventory"];
  157. }
  158. catch (Exception e)
  159. {
  160. m_log.Error("[CAPS]: " + e.ToString());
  161. }
  162. }
  163. public void RegisterInventoryServiceHandlers(string capsBase)
  164. {
  165. try
  166. {
  167. // I don't think this one works...
  168. m_capsHandlers["NewFileAgentInventory"] =
  169. new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>("POST",
  170. capsBase + m_newInventory,
  171. NewAgentInventoryRequest);
  172. m_capsHandlers["UpdateNotecardAgentInventory"] =
  173. new RestStreamHandler("POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory);
  174. m_capsHandlers["UpdateScriptAgentInventory"] = m_capsHandlers["UpdateNotecardAgentInventory"];
  175. m_capsHandlers["UpdateScriptAgent"] = m_capsHandlers["UpdateScriptAgentInventory"];
  176. // As of RC 1.22.9 of the Linden client this is
  177. // supported
  178. //m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest);
  179. // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and
  180. // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires
  181. // enhancements (probably filling out the folder part of the LLSD reply) to our CAPS service,
  182. // but when I went on the Linden grid, the
  183. // simulators I visited (version 1.21) were, surprisingly, no longer supplying this capability. Instead,
  184. // the 1.19.1.4 client appeared to be happily flowing inventory data over UDP
  185. //
  186. // This is very probably just a temporary measure - once the CAPS service appears again on the Linden grid
  187. // we will be
  188. // able to get the data we need to implement the necessary part of the protocol to fix the issue above.
  189. // m_capsHandlers["FetchInventoryDescendents"] =
  190. // new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest);
  191. // m_capsHandlers["FetchInventoryDescendents"] =
  192. // new LLSDStreamhandler<LLSDFetchInventoryDescendents, LLSDInventoryDescendents>("POST",
  193. // capsBase + m_fetchInventory,
  194. // FetchInventory));
  195. // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST",
  196. // capsBase + m_requestTexture,
  197. // RequestTexture);
  198. }
  199. catch (Exception e)
  200. {
  201. m_log.Error("[CAPS]: " + e.ToString());
  202. }
  203. }
  204. /// <summary>
  205. /// Register a handler. This allows modules to register handlers.
  206. /// </summary>
  207. /// <param name="capName"></param>
  208. /// <param name="handler"></param>
  209. public void RegisterHandler(string capName, IRequestHandler handler)
  210. {
  211. m_capsHandlers[capName] = handler;
  212. //m_log.DebugFormat("[CAPS]: Registering handler for \"{0}\": path {1}", capName, handler.Path);
  213. }
  214. /// <summary>
  215. /// Remove all CAPS service handlers.
  216. ///
  217. /// </summary>
  218. /// <param name="httpListener"></param>
  219. /// <param name="path"></param>
  220. /// <param name="restMethod"></param>
  221. public void DeregisterHandlers()
  222. {
  223. if (m_capsHandlers != null)
  224. {
  225. foreach (string capsName in m_capsHandlers.Caps)
  226. {
  227. m_capsHandlers.Remove(capsName);
  228. }
  229. }
  230. }
  231. /// <summary>
  232. /// Construct a client response detailing all the capabilities this server can provide.
  233. /// </summary>
  234. /// <param name="request"></param>
  235. /// <param name="path"></param>
  236. /// <param name="param"></param>
  237. /// <param name="httpRequest">HTTP request header object</param>
  238. /// <param name="httpResponse">HTTP response header object</param>
  239. /// <returns></returns>
  240. public string CapsRequest(string request, string path, string param,
  241. OSHttpRequest httpRequest, OSHttpResponse httpResponse)
  242. {
  243. m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName);
  244. if (!m_Scene.CheckClient(m_agentID, httpRequest.RemoteIPEndPoint))
  245. {
  246. m_log.DebugFormat("[CAPS]: Unauthorized CAPS client");
  247. return string.Empty;
  248. }
  249. string result = LLSDHelpers.SerialiseLLSDReply(m_capsHandlers.CapsDetails);
  250. //m_log.DebugFormat("[CAPS] CapsRequest {0}", result);
  251. return result;
  252. }
  253. // FIXME: these all should probably go into the respective region
  254. // modules
  255. /// <summary>
  256. /// Processes a fetch inventory request and sends the reply
  257. /// </summary>
  258. /// <param name="request"></param>
  259. /// <param name="path"></param>
  260. /// <param name="param"></param>
  261. /// <returns></returns>
  262. // Request is like:
  263. //<llsd>
  264. // <map><key>folders</key>
  265. // <array>
  266. // <map>
  267. // <key>fetch-folders</key><boolean>1</boolean><key>fetch-items</key><boolean>1</boolean><key>folder-id</key><uuid>8e1e3a30-b9bf-11dc-95ff-0800200c9a66</uuid><key>owner-id</key><uuid>11111111-1111-0000-0000-000100bba000</uuid><key>sort-order</key><integer>1</integer>
  268. // </map>
  269. // </array>
  270. // </map>
  271. //</llsd>
  272. //
  273. // multiple fetch-folder maps are allowed within the larger folders map.
  274. public string FetchInventoryRequest(string request, string path, string param)
  275. {
  276. // string unmodifiedRequest = request.ToString();
  277. //m_log.DebugFormat("[AGENT INVENTORY]: Received CAPS fetch inventory request {0}", unmodifiedRequest);
  278. m_log.Debug("[CAPS]: Inventory Request in region: " + m_regionName);
  279. Hashtable hash = new Hashtable();
  280. try
  281. {
  282. hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
  283. }
  284. catch (LLSD.LLSDParseException pe)
  285. {
  286. m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message);
  287. m_log.Error("Request: " + request.ToString());
  288. }
  289. ArrayList foldersrequested = (ArrayList)hash["folders"];
  290. string response = "";
  291. for (int i = 0; i < foldersrequested.Count; i++)
  292. {
  293. string inventoryitemstr = "";
  294. Hashtable inventoryhash = (Hashtable)foldersrequested[i];
  295. LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
  296. LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
  297. LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest);
  298. inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply);
  299. inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
  300. inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
  301. response += inventoryitemstr;
  302. }
  303. if (response.Length == 0)
  304. {
  305. // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants.
  306. // Therefore, I'm concluding that the client only has so many threads available to do requests
  307. // and when a thread stalls.. is stays stalled.
  308. // Therefore we need to return something valid
  309. response = "<llsd><map><key>folders</key><array /></map></llsd>";
  310. }
  311. else
  312. {
  313. response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>";
  314. }
  315. //m_log.DebugFormat("[AGENT INVENTORY]: Replying to CAPS fetch inventory request with following xml");
  316. //m_log.Debug(Util.GetFormattedXml(response));
  317. return response;
  318. }
  319. public string FetchInventoryDescendentsRequest(string request, string path, string param,OSHttpRequest httpRequest, OSHttpResponse httpResponse)
  320. {
  321. // nasty temporary hack here, the linden client falsely
  322. // identifies the uuid 00000000-0000-0000-0000-000000000000
  323. // as a string which breaks us
  324. //
  325. // correctly mark it as a uuid
  326. //
  327. request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
  328. // another hack <integer>1</integer> results in a
  329. // System.ArgumentException: Object type System.Int32 cannot
  330. // be converted to target type: System.Boolean
  331. //
  332. request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
  333. request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
  334. Hashtable hash = new Hashtable();
  335. try
  336. {
  337. hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
  338. }
  339. catch (LLSD.LLSDParseException pe)
  340. {
  341. m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message);
  342. m_log.Error("Request: " + request.ToString());
  343. }
  344. ArrayList foldersrequested = (ArrayList)hash["folders"];
  345. string response = "";
  346. lock (m_fetchLock)
  347. {
  348. for (int i = 0; i < foldersrequested.Count; i++)
  349. {
  350. string inventoryitemstr = "";
  351. Hashtable inventoryhash = (Hashtable)foldersrequested[i];
  352. LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
  353. try{
  354. LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
  355. }
  356. catch(Exception e)
  357. {
  358. m_log.Debug("[CAPS]: caught exception doing OSD deserialize" + e);
  359. }
  360. LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest);
  361. inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply);
  362. inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
  363. inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
  364. response += inventoryitemstr;
  365. }
  366. if (response.Length == 0)
  367. {
  368. // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants.
  369. // Therefore, I'm concluding that the client only has so many threads available to do requests
  370. // and when a thread stalls.. is stays stalled.
  371. // Therefore we need to return something valid
  372. response = "<llsd><map><key>folders</key><array /></map></llsd>";
  373. }
  374. else
  375. {
  376. response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>";
  377. }
  378. //m_log.DebugFormat("[CAPS]: Replying to CAPS fetch inventory request with following xml");
  379. //m_log.Debug("[CAPS] "+response);
  380. }
  381. return response;
  382. }
  383. /// <summary>
  384. /// Construct an LLSD reply packet to a CAPS inventory request
  385. /// </summary>
  386. /// <param name="invFetch"></param>
  387. /// <returns></returns>
  388. private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch)
  389. {
  390. LLSDInventoryDescendents reply = new LLSDInventoryDescendents();
  391. LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents();
  392. contents.agent_id = m_agentID;
  393. contents.owner_id = invFetch.owner_id;
  394. contents.folder_id = invFetch.folder_id;
  395. reply.folders.Array.Add(contents);
  396. InventoryCollection inv = new InventoryCollection();
  397. inv.Folders = new List<InventoryFolderBase>();
  398. inv.Items = new List<InventoryItemBase>();
  399. int version = 0;
  400. if (CAPSFetchInventoryDescendents != null)
  401. {
  402. inv = CAPSFetchInventoryDescendents(m_agentID, invFetch.folder_id, invFetch.owner_id, invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version);
  403. }
  404. if (inv.Folders != null)
  405. {
  406. foreach (InventoryFolderBase invFolder in inv.Folders)
  407. {
  408. contents.categories.Array.Add(ConvertInventoryFolder(invFolder));
  409. }
  410. }
  411. if (inv.Items != null)
  412. {
  413. foreach (InventoryItemBase invItem in inv.Items)
  414. {
  415. contents.items.Array.Add(ConvertInventoryItem(invItem));
  416. }
  417. }
  418. contents.descendents = contents.items.Array.Count + contents.categories.Array.Count;
  419. contents.version = version;
  420. return reply;
  421. }
  422. /// <summary>
  423. /// Convert an internal inventory folder object into an LLSD object.
  424. /// </summary>
  425. /// <param name="invFolder"></param>
  426. /// <returns></returns>
  427. private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder)
  428. {
  429. LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder();
  430. llsdFolder.folder_id = invFolder.ID;
  431. llsdFolder.parent_id = invFolder.ParentID;
  432. llsdFolder.name = invFolder.Name;
  433. if (invFolder.Type < 0 || invFolder.Type >= TaskInventoryItem.Types.Length)
  434. llsdFolder.type = "-1";
  435. else
  436. llsdFolder.type = TaskInventoryItem.Types[invFolder.Type];
  437. llsdFolder.preferred_type = "-1";
  438. return llsdFolder;
  439. }
  440. /// <summary>
  441. /// Convert an internal inventory item object into an LLSD object.
  442. /// </summary>
  443. /// <param name="invItem"></param>
  444. /// <returns></returns>
  445. private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem)
  446. {
  447. LLSDInventoryItem llsdItem = new LLSDInventoryItem();
  448. llsdItem.asset_id = invItem.AssetID;
  449. llsdItem.created_at = invItem.CreationDate;
  450. llsdItem.desc = invItem.Description;
  451. llsdItem.flags = (int)invItem.Flags;
  452. llsdItem.item_id = invItem.ID;
  453. llsdItem.name = invItem.Name;
  454. llsdItem.parent_id = invItem.Folder;
  455. try
  456. {
  457. // TODO reevaluate after upgrade to libomv >= r2566. Probably should use UtilsConversions.
  458. llsdItem.type = TaskInventoryItem.Types[invItem.AssetType];
  459. llsdItem.inv_type = TaskInventoryItem.InvTypes[invItem.InvType];
  460. }
  461. catch (Exception e)
  462. {
  463. m_log.Error("[CAPS]: Problem setting asset/inventory type while converting inventory item " + invItem.Name + " to LLSD:", e);
  464. }
  465. llsdItem.permissions = new LLSDPermissions();
  466. llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid;
  467. llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions;
  468. llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions;
  469. llsdItem.permissions.group_id = invItem.GroupID;
  470. llsdItem.permissions.group_mask = (int)invItem.GroupPermissions;
  471. llsdItem.permissions.is_owner_group = invItem.GroupOwned;
  472. llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions;
  473. llsdItem.permissions.owner_id = m_agentID;
  474. llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions;
  475. llsdItem.sale_info = new LLSDSaleInfo();
  476. llsdItem.sale_info.sale_price = invItem.SalePrice;
  477. switch (invItem.SaleType)
  478. {
  479. default:
  480. llsdItem.sale_info.sale_type = "not";
  481. break;
  482. case 1:
  483. llsdItem.sale_info.sale_type = "original";
  484. break;
  485. case 2:
  486. llsdItem.sale_info.sale_type = "copy";
  487. break;
  488. case 3:
  489. llsdItem.sale_info.sale_type = "contents";
  490. break;
  491. }
  492. return llsdItem;
  493. }
  494. /// <summary>
  495. ///
  496. /// </summary>
  497. /// <param name="mapReq"></param>
  498. /// <returns></returns>
  499. public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq)
  500. {
  501. m_log.Debug("[CAPS]: MapLayer Request in region: " + m_regionName);
  502. LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
  503. mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
  504. return mapResponse;
  505. }
  506. /// <summary>
  507. ///
  508. /// </summary>
  509. /// <returns></returns>
  510. protected static OSDMapLayer GetOSDMapLayerResponse()
  511. {
  512. OSDMapLayer mapLayer = new OSDMapLayer();
  513. mapLayer.Right = 5000;
  514. mapLayer.Top = 5000;
  515. mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006");
  516. return mapLayer;
  517. }
  518. /// <summary>
  519. ///
  520. /// </summary>
  521. /// <param name="request"></param>
  522. /// <param name="path"></param>
  523. /// <param name="param"></param>
  524. /// <returns></returns>
  525. public string RequestTexture(string request, string path, string param)
  526. {
  527. m_log.Debug("texture request " + request);
  528. // Needs implementing (added to remove compiler warning)
  529. return String.Empty;
  530. }
  531. #region EventQueue (Currently not enabled)
  532. /// <summary>
  533. ///
  534. /// </summary>
  535. /// <param name="request"></param>
  536. /// <param name="path"></param>
  537. /// <param name="param"></param>
  538. /// <returns></returns>
  539. public string ProcessEventQueue(string request, string path, string param)
  540. {
  541. string res = String.Empty;
  542. if (m_capsEventQueue.Count > 0)
  543. {
  544. lock (m_capsEventQueue)
  545. {
  546. string item = m_capsEventQueue.Dequeue();
  547. res = item;
  548. }
  549. }
  550. else
  551. {
  552. res = CreateEmptyEventResponse();
  553. }
  554. return res;
  555. }
  556. /// <summary>
  557. ///
  558. /// </summary>
  559. /// <param name="caps"></param>
  560. /// <param name="ipAddressPort"></param>
  561. /// <returns></returns>
  562. public string CreateEstablishAgentComms(string caps, string ipAddressPort)
  563. {
  564. LLSDCapEvent eventItem = new LLSDCapEvent();
  565. eventItem.id = m_eventQueueCount;
  566. //should be creating a EstablishAgentComms item, but there isn't a class for it yet
  567. eventItem.events.Array.Add(new LLSDEmpty());
  568. string res = LLSDHelpers.SerialiseLLSDReply(eventItem);
  569. m_eventQueueCount++;
  570. m_capsEventQueue.Enqueue(res);
  571. return res;
  572. }
  573. /// <summary>
  574. ///
  575. /// </summary>
  576. /// <returns></returns>
  577. public string CreateEmptyEventResponse()
  578. {
  579. LLSDCapEvent eventItem = new LLSDCapEvent();
  580. eventItem.id = m_eventQueueCount;
  581. eventItem.events.Array.Add(new LLSDEmpty());
  582. string res = LLSDHelpers.SerialiseLLSDReply(eventItem);
  583. m_eventQueueCount++;
  584. return res;
  585. }
  586. #endregion
  587. /// <summary>
  588. /// Called by the script task update handler. Provides a URL to which the client can upload a new asset.
  589. /// </summary>
  590. /// <param name="request"></param>
  591. /// <param name="path"></param>
  592. /// <param name="param"></param>
  593. /// <param name="httpRequest">HTTP request header object</param>
  594. /// <param name="httpResponse">HTTP response header object</param>
  595. /// <returns></returns>
  596. public string ScriptTaskInventory(string request, string path, string param,
  597. OSHttpRequest httpRequest, OSHttpResponse httpResponse)
  598. {
  599. try
  600. {
  601. m_log.Debug("[CAPS]: ScriptTaskInventory Request in region: " + m_regionName);
  602. //m_log.DebugFormat("[CAPS]: request: {0}, path: {1}, param: {2}", request, path, param);
  603. Hashtable hash = (Hashtable) LLSD.LLSDDeserialize(Utils.StringToBytes(request));
  604. LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate();
  605. LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest);
  606. string capsBase = "/CAPS/" + m_capsObjectPath;
  607. string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
  608. TaskInventoryScriptUpdater uploader =
  609. new TaskInventoryScriptUpdater(
  610. llsdUpdateRequest.item_id,
  611. llsdUpdateRequest.task_id,
  612. llsdUpdateRequest.is_script_running,
  613. capsBase + uploaderPath,
  614. m_httpListener,
  615. m_dumpAssetsToFile);
  616. uploader.OnUpLoad += TaskScriptUpdated;
  617. m_httpListener.AddStreamHandler(
  618. new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
  619. string protocol = "http://";
  620. if (m_httpListener.UseSSL)
  621. protocol = "https://";
  622. string uploaderURL = protocol + m_httpListenerHostName + ":" + m_httpListenPort.ToString() + capsBase +
  623. uploaderPath;
  624. LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
  625. uploadResponse.uploader = uploaderURL;
  626. uploadResponse.state = "upload";
  627. // m_log.InfoFormat("[CAPS]: " +
  628. // "ScriptTaskInventory response: {0}",
  629. // LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
  630. return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
  631. }
  632. catch (Exception e)
  633. {
  634. m_log.Error("[CAPS]: " + e.ToString());
  635. }
  636. return null;
  637. }
  638. /// <summary>
  639. /// Called by the notecard update handler. Provides a URL to which the client can upload a new asset.
  640. /// </summary>
  641. /// <param name="request"></param>
  642. /// <param name="path"></param>
  643. /// <param name="param"></param>
  644. /// <returns></returns>
  645. public string NoteCardAgentInventory(string request, string path, string param,
  646. OSHttpRequest httpRequest, OSHttpResponse httpResponse)
  647. {
  648. //m_log.Debug("[CAPS]: NoteCardAgentInventory Request in region: " + m_regionName + "\n" + request);
  649. //m_log.Debug("[CAPS]: NoteCardAgentInventory Request is: " + request);
  650. //OpenMetaverse.StructuredData.OSDMap hash = (OpenMetaverse.StructuredData.OSDMap)OpenMetaverse.StructuredData.LLSDParser.DeserializeBinary(Utils.StringToBytes(request));
  651. Hashtable hash = (Hashtable) LLSD.LLSDDeserialize(Utils.StringToBytes(request));
  652. LLSDItemUpdate llsdRequest = new LLSDItemUpdate();
  653. LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest);
  654. string capsBase = "/CAPS/" + m_capsObjectPath;
  655. string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
  656. ItemUpdater uploader =
  657. new ItemUpdater(llsdRequest.item_id, capsBase + uploaderPath, m_httpListener, m_dumpAssetsToFile);
  658. uploader.OnUpLoad += ItemUpdated;
  659. m_httpListener.AddStreamHandler(
  660. new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
  661. string protocol = "http://";
  662. if (m_httpListener.UseSSL)
  663. protocol = "https://";
  664. string uploaderURL = protocol + m_httpListenerHostName + ":" + m_httpListenPort.ToString() + capsBase +
  665. uploaderPath;
  666. LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
  667. uploadResponse.uploader = uploaderURL;
  668. uploadResponse.state = "upload";
  669. // m_log.InfoFormat("[CAPS]: " +
  670. // "NoteCardAgentInventory response: {0}",
  671. // LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
  672. return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
  673. }
  674. /// <summary>
  675. ///
  676. /// </summary>
  677. /// <param name="llsdRequest"></param>
  678. /// <returns></returns>
  679. public LLSDAssetUploadResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest)
  680. {
  681. //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
  682. //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
  683. if (llsdRequest.asset_type == "texture" ||
  684. llsdRequest.asset_type == "animation" ||
  685. llsdRequest.asset_type == "sound")
  686. {
  687. IClientAPI client = null;
  688. IScene scene = null;
  689. if (GetClient != null)
  690. {
  691. client = GetClient(m_agentID);
  692. scene = client.Scene;
  693. IMoneyModule mm = scene.RequestModuleInterface<IMoneyModule>();
  694. if (mm != null)
  695. {
  696. if (!mm.UploadCovered(client, mm.UploadCharge))
  697. {
  698. if (client != null)
  699. client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
  700. LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
  701. errorResponse.uploader = "";
  702. errorResponse.state = "error";
  703. return errorResponse;
  704. }
  705. }
  706. }
  707. }
  708. string assetName = llsdRequest.name;
  709. string assetDes = llsdRequest.description;
  710. string capsBase = "/CAPS/" + m_capsObjectPath;
  711. UUID newAsset = UUID.Random();
  712. UUID newInvItem = UUID.Random();
  713. UUID parentFolder = llsdRequest.folder_id;
  714. string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
  715. AssetUploader uploader =
  716. new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
  717. llsdRequest.asset_type, capsBase + uploaderPath, m_httpListener, m_dumpAssetsToFile);
  718. m_httpListener.AddStreamHandler(
  719. new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
  720. string protocol = "http://";
  721. if (m_httpListener.UseSSL)
  722. protocol = "https://";
  723. string uploaderURL = protocol + m_httpListenerHostName + ":" + m_httpListenPort.ToString() + capsBase +
  724. uploaderPath;
  725. LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
  726. uploadResponse.uploader = uploaderURL;
  727. uploadResponse.state = "upload";
  728. uploader.OnUpLoad += UploadCompleteHandler;
  729. return uploadResponse;
  730. }
  731. /// <summary>
  732. ///
  733. /// </summary>
  734. /// <param name="assetID"></param>
  735. /// <param name="inventoryItem"></param>
  736. /// <param name="data"></param>
  737. public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
  738. UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
  739. string assetType)
  740. {
  741. sbyte assType = 0;
  742. sbyte inType = 0;
  743. if (inventoryType == "sound")
  744. {
  745. inType = 1;
  746. assType = 1;
  747. }
  748. else if (inventoryType == "animation")
  749. {
  750. inType = 19;
  751. assType = 20;
  752. }
  753. else if (inventoryType == "wearable")
  754. {
  755. inType = 18;
  756. switch (assetType)
  757. {
  758. case "bodypart":
  759. assType = 13;
  760. break;
  761. case "clothing":
  762. assType = 5;
  763. break;
  764. }
  765. }
  766. AssetBase asset;
  767. asset = new AssetBase(assetID, assetName, assType, m_agentID.ToString());
  768. asset.Data = data;
  769. if (AddNewAsset != null)
  770. AddNewAsset(asset);
  771. else if (m_assetCache != null)
  772. m_assetCache.Store(asset);
  773. InventoryItemBase item = new InventoryItemBase();
  774. item.Owner = m_agentID;
  775. item.CreatorId = m_agentID.ToString();
  776. item.ID = inventoryItem;
  777. item.AssetID = asset.FullID;
  778. item.Description = assetDescription;
  779. item.Name = assetName;
  780. item.AssetType = assType;
  781. item.InvType = inType;
  782. item.Folder = parentFolder;
  783. item.CurrentPermissions = 2147483647;
  784. item.BasePermissions = 2147483647;
  785. item.EveryOnePermissions = 0;
  786. item.NextPermissions = 2147483647;
  787. item.CreationDate = Util.UnixTimeSinceEpoch();
  788. if (AddNewInventoryItem != null)
  789. {
  790. AddNewInventoryItem(m_agentID, item);
  791. }
  792. }
  793. /// <summary>
  794. /// Called when new asset data for an agent inventory item update has been uploaded.
  795. /// </summary>
  796. /// <param name="itemID">Item to update</param>
  797. /// <param name="data">New asset data</param>
  798. /// <returns></returns>
  799. public UUID ItemUpdated(UUID itemID, byte[] data)
  800. {
  801. if (ItemUpdatedCall != null)
  802. {
  803. return ItemUpdatedCall(m_agentID, itemID, data);
  804. }
  805. return UUID.Zero;
  806. }
  807. /// <summary>
  808. /// Called when new asset data for an agent inventory item update has been uploaded.
  809. /// </summary>
  810. /// <param name="itemID">Item to update</param>
  811. /// <param name="primID">Prim containing item to update</param>
  812. /// <param name="isScriptRunning">Signals whether the script to update is currently running</param>
  813. /// <param name="data">New asset data</param>
  814. public void TaskScriptUpdated(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors)
  815. {
  816. if (TaskScriptUpdatedCall != null)
  817. {
  818. ArrayList e = TaskScriptUpdatedCall(m_agentID, itemID, primID, isScriptRunning, data);
  819. foreach (Object item in e)
  820. errors.Add(item);
  821. }
  822. }
  823. public class AssetUploader
  824. {
  825. public event UpLoadedAsset OnUpLoad;
  826. private UpLoadedAsset handlerUpLoad = null;
  827. private string uploaderPath = String.Empty;
  828. private UUID newAssetID;
  829. private UUID inventoryItemID;
  830. private UUID parentFolder;
  831. private IHttpServer httpListener;
  832. private bool m_dumpAssetsToFile;
  833. private string m_assetName = String.Empty;
  834. private string m_assetDes = String.Empty;
  835. private string m_invType = String.Empty;
  836. private string m_assetType = String.Empty;
  837. public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
  838. UUID parentFolderID, string invType, string assetType, string path,
  839. IHttpServer httpServer, bool dumpAssetsToFile)
  840. {
  841. m_assetName = assetName;
  842. m_assetDes = description;
  843. newAssetID = assetID;
  844. inventoryItemID = inventoryItem;
  845. uploaderPath = path;
  846. httpListener = httpServer;
  847. parentFolder = parentFolderID;
  848. m_assetType = assetType;
  849. m_invType = invType;
  850. m_dumpAssetsToFile = dumpAssetsToFile;
  851. }
  852. /// <summary>
  853. ///
  854. /// </summary>
  855. /// <param name="data"></param>
  856. /// <param name="path"></param>
  857. /// <param name="param"></param>
  858. /// <returns></returns>
  859. public string uploaderCaps(byte[] data, string path, string param)
  860. {
  861. UUID inv = inventoryItemID;
  862. string res = String.Empty;
  863. LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
  864. uploadComplete.new_asset = newAssetID.ToString();
  865. uploadComplete.new_inventory_item = inv;
  866. uploadComplete.state = "complete";
  867. res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
  868. httpListener.RemoveStreamHandler("POST", uploaderPath);
  869. // TODO: probably make this a better set of extensions here
  870. string extension = ".jp2";
  871. if (m_invType != "image")
  872. {
  873. extension = ".dat";
  874. }
  875. if (m_dumpAssetsToFile)
  876. {
  877. SaveAssetToFile(m_assetName + extension, data);
  878. }
  879. handlerUpLoad = OnUpLoad;
  880. if (handlerUpLoad != null)
  881. {
  882. handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType);
  883. }
  884. return res;
  885. }
  886. ///Left this in and commented in case there are unforseen issues
  887. //private void SaveAssetToFile(string filename, byte[] data)
  888. //{
  889. // FileStream fs = File.Create(filename);
  890. // BinaryWriter bw = new BinaryWriter(fs);
  891. // bw.Write(data);
  892. // bw.Close();
  893. // fs.Close();
  894. //}
  895. private static void SaveAssetToFile(string filename, byte[] data)
  896. {
  897. string assetPath = "UserAssets";
  898. if (!Directory.Exists(assetPath))
  899. {
  900. Directory.CreateDirectory(assetPath);
  901. }
  902. FileStream fs = File.Create(Path.Combine(assetPath, Util.safeFileName(filename)));
  903. BinaryWriter bw = new BinaryWriter(fs);
  904. bw.Write(data);
  905. bw.Close();
  906. fs.Close();
  907. }
  908. }
  909. /// <summary>
  910. /// This class is a callback invoked when a client sends asset data to
  911. /// an agent inventory notecard update url
  912. /// </summary>
  913. public class ItemUpdater
  914. {
  915. public event UpdateItem OnUpLoad;
  916. private UpdateItem handlerUpdateItem = null;
  917. private string uploaderPath = String.Empty;
  918. private UUID inventoryItemID;
  919. private IHttpServer httpListener;
  920. private bool m_dumpAssetToFile;
  921. public ItemUpdater(UUID inventoryItem, string path, IHttpServer httpServer, bool dumpAssetToFile)
  922. {
  923. m_dumpAssetToFile = dumpAssetToFile;
  924. inventoryItemID = inventoryItem;
  925. uploaderPath = path;
  926. httpListener = httpServer;
  927. }
  928. /// <summary>
  929. ///
  930. /// </summary>
  931. /// <param name="data"></param>
  932. /// <param name="path"></param>
  933. /// <param name="param"></param>
  934. /// <returns></returns>
  935. public string uploaderCaps(byte[] data, string path, string param)
  936. {
  937. UUID inv = inventoryItemID;
  938. string res = String.Empty;
  939. LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
  940. UUID assetID = UUID.Zero;
  941. handlerUpdateItem = OnUpLoad;
  942. if (handlerUpdateItem != null)
  943. {
  944. assetID = handlerUpdateItem(inv, data);
  945. }
  946. uploadComplete.new_asset = assetID.ToString();
  947. uploadComplete.new_inventory_item = inv;
  948. uploadComplete.state = "complete";
  949. res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
  950. httpListener.RemoveStreamHandler("POST", uploaderPath);
  951. if (m_dumpAssetToFile)
  952. {
  953. SaveAssetToFile("updateditem" + Util.RandomClass.Next(1, 1000) + ".dat", data);
  954. }
  955. return res;
  956. }
  957. ///Left this in and commented in case there are unforseen issues
  958. //private void SaveAssetToFile(string filename, byte[] data)
  959. //{
  960. // FileStream fs = File.Create(filename);
  961. // BinaryWriter bw = new BinaryWriter(fs);
  962. // bw.Write(data);
  963. // bw.Close();
  964. // fs.Close();
  965. //}
  966. private static void SaveAssetToFile(string filename, byte[] data)
  967. {
  968. string assetPath = "UserAssets";
  969. if (!Directory.Exists(assetPath))
  970. {
  971. Directory.CreateDirectory(assetPath);
  972. }
  973. FileStream fs = File.Create(Path.Combine(assetPath, filename));
  974. BinaryWriter bw = new BinaryWriter(fs);
  975. bw.Write(data);
  976. bw.Close();
  977. fs.Close();
  978. }
  979. }
  980. /// <summary>
  981. /// This class is a callback invoked when a client sends asset data to
  982. /// a task inventory script update url
  983. /// </summary>
  984. public class TaskInventoryScriptUpdater
  985. {
  986. public event UpdateTaskScript OnUpLoad;
  987. private UpdateTaskScript handlerUpdateTaskScript = null;
  988. private string uploaderPath = String.Empty;
  989. private UUID inventoryItemID;
  990. private UUID primID;
  991. private bool isScriptRunning;
  992. private IHttpServer httpListener;
  993. private bool m_dumpAssetToFile;
  994. public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, int isScriptRunning,
  995. string path, IHttpServer httpServer, bool dumpAssetToFile)
  996. {
  997. m_dumpAssetToFile = dumpAssetToFile;
  998. this.inventoryItemID = inventoryItemID;
  999. this.primID = primID;
  1000. // This comes in over the packet as an integer, but actually appears to be treated as a bool
  1001. this.isScriptRunning = (0 == isScriptRunning ? false : true);
  1002. uploaderPath = path;
  1003. httpListener = httpServer;
  1004. }
  1005. /// <summary>
  1006. ///
  1007. /// </summary>
  1008. /// <param name="data"></param>
  1009. /// <param name="path"></param>
  1010. /// <param name="param"></param>
  1011. /// <returns></returns>
  1012. public string uploaderCaps(byte[] data, string path, string param)
  1013. {
  1014. try
  1015. {
  1016. // m_log.InfoFormat("[CAPS]: " +
  1017. // "TaskInventoryScriptUpdater received data: {0}, path: {1}, param: {2}",
  1018. // data, path, param));
  1019. string res = String.Empty;
  1020. LLSDTaskScriptUploadComplete uploadComplete = new LLSDTaskScriptUploadComplete();
  1021. ArrayList errors = new ArrayList();
  1022. handlerUpdateTaskScript = OnUpLoad;
  1023. if (handlerUpdateTaskScript != null)
  1024. {
  1025. handlerUpdateTaskScript(inventoryItemID, primID, isScriptRunning, data, ref errors);
  1026. }
  1027. uploadComplete.new_asset = inventoryItemID;
  1028. uploadComplete.compiled = errors.Count > 0 ? false : true;
  1029. uploadComplete.state = "complete";
  1030. uploadComplete.errors = new OSDArray();
  1031. uploadComplete.errors.Array = errors;
  1032. res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
  1033. httpListener.RemoveStreamHandler("POST", uploaderPath);
  1034. if (m_dumpAssetToFile)
  1035. {
  1036. SaveAssetToFile("updatedtaskscript" + Util.RandomClass.Next(1, 1000) + ".dat", data);
  1037. }
  1038. // m_log.InfoFormat("[CAPS]: TaskInventoryScriptUpdater.uploaderCaps res: {0}", res);
  1039. return res;
  1040. }
  1041. catch (Exception e)
  1042. {
  1043. m_log.Error("[CAPS]: " + e.ToString());
  1044. }
  1045. // XXX Maybe this should be some meaningful error packet
  1046. return null;
  1047. }
  1048. ///Left this in and commented in case there are unforseen issues
  1049. //private void SaveAssetToFile(string filename, byte[] data)
  1050. //{
  1051. // FileStream fs = File.Create(filename);
  1052. // BinaryWriter bw = new BinaryWriter(fs);
  1053. // bw.Write(data);
  1054. // bw.Close();
  1055. // fs.Close();
  1056. //}
  1057. private static void SaveAssetToFile(string filename, byte[] data)
  1058. {
  1059. string assetPath = "UserAssets";
  1060. if (!Directory.Exists(assetPath))
  1061. {
  1062. Directory.CreateDirectory(assetPath);
  1063. }
  1064. FileStream fs = File.Create(Path.Combine(assetPath, filename));
  1065. BinaryWriter bw = new BinaryWriter(fs);
  1066. bw.Write(data);
  1067. bw.Close();
  1068. fs.Close();
  1069. }
  1070. }
  1071. }
  1072. }