Caps.cs 51 KB

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