InventoryAccessModule.cs 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172
  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.Generic;
  29. using System.Net;
  30. using System.Xml;
  31. using System.Reflection;
  32. using System.Text;
  33. using System.Threading;
  34. using OpenSim.Framework;
  35. using OpenSim.Framework.Capabilities;
  36. using OpenSim.Framework.Client;
  37. using OpenSim.Region.Framework.Interfaces;
  38. using OpenSim.Region.Framework.Scenes;
  39. using OpenSim.Region.Framework.Scenes.Serialization;
  40. using OpenSim.Services.Interfaces;
  41. using GridRegion = OpenSim.Services.Interfaces.GridRegion;
  42. using OpenMetaverse;
  43. using log4net;
  44. using Nini.Config;
  45. using Mono.Addins;
  46. using PermissionMask = OpenSim.Framework.PermissionMask;
  47. namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
  48. {
  49. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BasicInventoryAccessModule")]
  50. public class BasicInventoryAccessModule : INonSharedRegionModule, IInventoryAccessModule
  51. {
  52. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  53. protected bool m_Enabled = false;
  54. protected Scene m_Scene;
  55. protected IUserManagement m_UserManagement;
  56. protected IUserManagement UserManagementModule
  57. {
  58. get
  59. {
  60. if (m_UserManagement == null)
  61. m_UserManagement = m_Scene.RequestModuleInterface<IUserManagement>();
  62. return m_UserManagement;
  63. }
  64. }
  65. public bool CoalesceMultipleObjectsToInventory { get; set; }
  66. #region INonSharedRegionModule
  67. public Type ReplaceableInterface
  68. {
  69. get { return null; }
  70. }
  71. public virtual string Name
  72. {
  73. get { return "BasicInventoryAccessModule"; }
  74. }
  75. public virtual void Initialise(IConfigSource source)
  76. {
  77. IConfig moduleConfig = source.Configs["Modules"];
  78. if (moduleConfig != null)
  79. {
  80. string name = moduleConfig.GetString("InventoryAccessModule", "");
  81. if (name == Name)
  82. {
  83. m_Enabled = true;
  84. InitialiseCommon(source);
  85. m_log.InfoFormat("[INVENTORY ACCESS MODULE]: {0} enabled.", Name);
  86. }
  87. }
  88. }
  89. /// <summary>
  90. /// Common module config for both this and descendant classes.
  91. /// </summary>
  92. /// <param name="source"></param>
  93. protected virtual void InitialiseCommon(IConfigSource source)
  94. {
  95. IConfig inventoryConfig = source.Configs["Inventory"];
  96. if (inventoryConfig != null)
  97. CoalesceMultipleObjectsToInventory
  98. = inventoryConfig.GetBoolean("CoalesceMultipleObjectsToInventory", true);
  99. else
  100. CoalesceMultipleObjectsToInventory = true;
  101. }
  102. public virtual void PostInitialise()
  103. {
  104. }
  105. public virtual void AddRegion(Scene scene)
  106. {
  107. if (!m_Enabled)
  108. return;
  109. m_Scene = scene;
  110. scene.RegisterModuleInterface<IInventoryAccessModule>(this);
  111. scene.EventManager.OnNewClient += OnNewClient;
  112. }
  113. protected virtual void OnNewClient(IClientAPI client)
  114. {
  115. client.OnCreateNewInventoryItem += CreateNewInventoryItem;
  116. }
  117. public virtual void Close()
  118. {
  119. if (!m_Enabled)
  120. return;
  121. }
  122. public virtual void RemoveRegion(Scene scene)
  123. {
  124. if (!m_Enabled)
  125. return;
  126. m_Scene = null;
  127. }
  128. public virtual void RegionLoaded(Scene scene)
  129. {
  130. if (!m_Enabled)
  131. return;
  132. }
  133. #endregion
  134. #region Inventory Access
  135. /// <summary>
  136. /// Create a new inventory item. Called when the client creates a new item directly within their
  137. /// inventory (e.g. by selecting a context inventory menu option).
  138. /// </summary>
  139. /// <param name="remoteClient"></param>
  140. /// <param name="transactionID"></param>
  141. /// <param name="folderID"></param>
  142. /// <param name="callbackID"></param>
  143. /// <param name="description"></param>
  144. /// <param name="name"></param>
  145. /// <param name="invType"></param>
  146. /// <param name="type"></param>
  147. /// <param name="wearableType"></param>
  148. /// <param name="nextOwnerMask"></param>
  149. public void CreateNewInventoryItem(IClientAPI remoteClient, UUID transactionID, UUID folderID,
  150. uint callbackID, string description, string name, sbyte invType,
  151. sbyte assetType,
  152. byte wearableType, uint nextOwnerMask, int creationDate)
  153. {
  154. m_log.DebugFormat("[INVENTORY ACCESS MODULE]: Received request to create inventory item {0} in folder {1}", name, folderID);
  155. if (!m_Scene.Permissions.CanCreateUserInventory(invType, remoteClient.AgentId))
  156. return;
  157. if (transactionID == UUID.Zero)
  158. {
  159. ScenePresence presence;
  160. if (m_Scene.TryGetScenePresence(remoteClient.AgentId, out presence))
  161. {
  162. byte[] data = null;
  163. if (invType == (sbyte)InventoryType.Landmark && presence != null)
  164. {
  165. string suffix = string.Empty, prefix = string.Empty;
  166. string strdata = GenerateLandmark(presence, out prefix, out suffix);
  167. data = Encoding.ASCII.GetBytes(strdata);
  168. name = prefix + name;
  169. description += suffix;
  170. }
  171. AssetBase asset = m_Scene.CreateAsset(name, description, assetType, data, remoteClient.AgentId);
  172. m_Scene.AssetService.Store(asset);
  173. m_Scene.CreateNewInventoryItem(
  174. remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID,
  175. name, description, 0, callbackID, asset, invType, nextOwnerMask, creationDate);
  176. }
  177. else
  178. {
  179. m_log.ErrorFormat(
  180. "[INVENTORY ACCESS MODULE]: ScenePresence for agent uuid {0} unexpectedly not found in CreateNewInventoryItem",
  181. remoteClient.AgentId);
  182. }
  183. }
  184. else
  185. {
  186. IAgentAssetTransactions agentTransactions = m_Scene.AgentTransactionsModule;
  187. if (agentTransactions != null)
  188. {
  189. agentTransactions.HandleItemCreationFromTransaction(
  190. remoteClient, transactionID, folderID, callbackID, description,
  191. name, invType, assetType, wearableType, nextOwnerMask);
  192. }
  193. }
  194. }
  195. protected virtual string GenerateLandmark(ScenePresence presence, out string prefix, out string suffix)
  196. {
  197. prefix = string.Empty;
  198. suffix = string.Empty;
  199. Vector3 pos = presence.AbsolutePosition;
  200. return String.Format("Landmark version 2\nregion_id {0}\nlocal_pos {1} {2} {3}\nregion_handle {4}\n",
  201. presence.Scene.RegionInfo.RegionID,
  202. pos.X, pos.Y, pos.Z,
  203. presence.RegionHandle);
  204. }
  205. /// <summary>
  206. /// Capability originating call to update the asset of an item in an agent's inventory
  207. /// </summary>
  208. /// <param name="remoteClient"></param>
  209. /// <param name="itemID"></param>
  210. /// <param name="data"></param>
  211. /// <returns></returns>
  212. public virtual UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data)
  213. {
  214. InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
  215. item = m_Scene.InventoryService.GetItem(item);
  216. if (item.Owner != remoteClient.AgentId)
  217. return UUID.Zero;
  218. if (item != null)
  219. {
  220. if ((InventoryType)item.InvType == InventoryType.Notecard)
  221. {
  222. if (!m_Scene.Permissions.CanEditNotecard(itemID, UUID.Zero, remoteClient.AgentId))
  223. {
  224. remoteClient.SendAgentAlertMessage("Insufficient permissions to edit notecard", false);
  225. return UUID.Zero;
  226. }
  227. remoteClient.SendAlertMessage("Notecard saved");
  228. }
  229. else if ((InventoryType)item.InvType == InventoryType.LSL)
  230. {
  231. if (!m_Scene.Permissions.CanEditScript(itemID, UUID.Zero, remoteClient.AgentId))
  232. {
  233. remoteClient.SendAgentAlertMessage("Insufficient permissions to edit script", false);
  234. return UUID.Zero;
  235. }
  236. remoteClient.SendAlertMessage("Script saved");
  237. }
  238. AssetBase asset =
  239. CreateAsset(item.Name, item.Description, (sbyte)item.AssetType, data, remoteClient.AgentId.ToString());
  240. item.AssetID = asset.FullID;
  241. m_Scene.AssetService.Store(asset);
  242. m_Scene.InventoryService.UpdateItem(item);
  243. // remoteClient.SendInventoryItemCreateUpdate(item);
  244. return (asset.FullID);
  245. }
  246. else
  247. {
  248. m_log.ErrorFormat(
  249. "[INVENTORY ACCESS MODULE]: Could not find item {0} for caps inventory update",
  250. itemID);
  251. }
  252. return UUID.Zero;
  253. }
  254. public virtual List<InventoryItemBase> CopyToInventory(
  255. DeRezAction action, UUID folderID,
  256. List<SceneObjectGroup> objectGroups, IClientAPI remoteClient, bool asAttachment)
  257. {
  258. List<InventoryItemBase> copiedItems = new List<InventoryItemBase>();
  259. Dictionary<UUID, List<SceneObjectGroup>> bundlesToCopy = new Dictionary<UUID, List<SceneObjectGroup>>();
  260. if (CoalesceMultipleObjectsToInventory)
  261. {
  262. // The following code groups the SOG's by owner. No objects
  263. // belonging to different people can be coalesced, for obvious
  264. // reasons.
  265. foreach (SceneObjectGroup g in objectGroups)
  266. {
  267. if (!bundlesToCopy.ContainsKey(g.OwnerID))
  268. bundlesToCopy[g.OwnerID] = new List<SceneObjectGroup>();
  269. bundlesToCopy[g.OwnerID].Add(g);
  270. }
  271. }
  272. else
  273. {
  274. // If we don't want to coalesce then put every object in its own bundle.
  275. foreach (SceneObjectGroup g in objectGroups)
  276. {
  277. List<SceneObjectGroup> bundle = new List<SceneObjectGroup>();
  278. bundle.Add(g);
  279. bundlesToCopy[g.UUID] = bundle;
  280. }
  281. }
  282. // m_log.DebugFormat(
  283. // "[INVENTORY ACCESS MODULE]: Copying {0} object bundles to folder {1} action {2} for {3}",
  284. // bundlesToCopy.Count, folderID, action, remoteClient.Name);
  285. // Each iteration is really a separate asset being created,
  286. // with distinct destinations as well.
  287. foreach (List<SceneObjectGroup> bundle in bundlesToCopy.Values)
  288. copiedItems.Add(CopyBundleToInventory(action, folderID, bundle, remoteClient, asAttachment));
  289. return copiedItems;
  290. }
  291. /// <summary>
  292. /// Copy a bundle of objects to inventory. If there is only one object, then this will create an object
  293. /// item. If there are multiple objects then these will be saved as a single coalesced item.
  294. /// </summary>
  295. /// <param name="action"></param>
  296. /// <param name="folderID"></param>
  297. /// <param name="objlist"></param>
  298. /// <param name="remoteClient"></param>
  299. /// <param name="asAttachment">Should be true if the bundle is being copied as an attachment. This prevents
  300. /// attempted serialization of any script state which would abort any operating scripts.</param>
  301. /// <returns>The inventory item created by the copy</returns>
  302. protected InventoryItemBase CopyBundleToInventory(
  303. DeRezAction action, UUID folderID, List<SceneObjectGroup> objlist, IClientAPI remoteClient,
  304. bool asAttachment)
  305. {
  306. CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero);
  307. // Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>();
  308. foreach (SceneObjectGroup objectGroup in objlist)
  309. {
  310. if (objectGroup.RootPart.KeyframeMotion != null)
  311. objectGroup.RootPart.KeyframeMotion.Stop();
  312. objectGroup.RootPart.KeyframeMotion = null;
  313. // Vector3 inventoryStoredPosition = new Vector3
  314. // (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
  315. // ? 250
  316. // : objectGroup.AbsolutePosition.X)
  317. // ,
  318. // (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize)
  319. // ? 250
  320. // : objectGroup.AbsolutePosition.Y,
  321. // objectGroup.AbsolutePosition.Z);
  322. //
  323. // originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition;
  324. //
  325. // objectGroup.AbsolutePosition = inventoryStoredPosition;
  326. // Make sure all bits but the ones we want are clear
  327. // on take.
  328. // This will be applied to the current perms, so
  329. // it will do what we want.
  330. objectGroup.RootPart.NextOwnerMask &=
  331. ((uint)PermissionMask.Copy |
  332. (uint)PermissionMask.Transfer |
  333. (uint)PermissionMask.Modify |
  334. (uint)PermissionMask.Export);
  335. objectGroup.RootPart.NextOwnerMask |=
  336. (uint)PermissionMask.Move;
  337. coa.Add(objectGroup);
  338. }
  339. string itemXml;
  340. // If we're being called from a script, then trying to serialize that same script's state will not complete
  341. // in any reasonable time period. Therefore, we'll avoid it. The worst that can happen is that if
  342. // the client/server crashes rather than logging out normally, the attachment's scripts will resume
  343. // without state on relog. Arguably, this is what we want anyway.
  344. if (objlist.Count > 1)
  345. itemXml = CoalescedSceneObjectsSerializer.ToXml(coa, !asAttachment);
  346. else
  347. itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment);
  348. // // Restore the position of each group now that it has been stored to inventory.
  349. // foreach (SceneObjectGroup objectGroup in objlist)
  350. // objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID];
  351. InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID);
  352. // m_log.DebugFormat(
  353. // "[INVENTORY ACCESS MODULE]: Created item is {0}",
  354. // item != null ? item.ID.ToString() : "NULL");
  355. if (item == null)
  356. return null;
  357. // Can't know creator is the same, so null it in inventory
  358. if (objlist.Count > 1)
  359. {
  360. item.CreatorId = UUID.Zero.ToString();
  361. item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems;
  362. }
  363. else
  364. {
  365. item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
  366. item.CreatorData = objlist[0].RootPart.CreatorData;
  367. item.SaleType = objlist[0].RootPart.ObjectSaleType;
  368. item.SalePrice = objlist[0].RootPart.SalePrice;
  369. }
  370. AssetBase asset = CreateAsset(
  371. objlist[0].GetPartName(objlist[0].RootPart.LocalId),
  372. objlist[0].GetPartDescription(objlist[0].RootPart.LocalId),
  373. (sbyte)AssetType.Object,
  374. Utils.StringToBytes(itemXml),
  375. objlist[0].OwnerID.ToString());
  376. m_Scene.AssetService.Store(asset);
  377. item.AssetID = asset.FullID;
  378. if (DeRezAction.SaveToExistingUserInventoryItem == action)
  379. {
  380. m_Scene.InventoryService.UpdateItem(item);
  381. }
  382. else
  383. {
  384. AddPermissions(item, objlist[0], objlist, remoteClient);
  385. item.CreationDate = Util.UnixTimeSinceEpoch();
  386. item.Description = asset.Description;
  387. item.Name = asset.Name;
  388. item.AssetType = asset.Type;
  389. m_Scene.AddInventoryItem(item);
  390. if (remoteClient != null && item.Owner == remoteClient.AgentId)
  391. {
  392. remoteClient.SendInventoryItemCreateUpdate(item, 0);
  393. }
  394. else
  395. {
  396. ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner);
  397. if (notifyUser != null)
  398. {
  399. notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
  400. }
  401. }
  402. }
  403. // This is a hook to do some per-asset post-processing for subclasses that need that
  404. if (remoteClient != null)
  405. ExportAsset(remoteClient.AgentId, asset.FullID);
  406. return item;
  407. }
  408. protected virtual void ExportAsset(UUID agentID, UUID assetID)
  409. {
  410. // nothing to do here
  411. }
  412. /// <summary>
  413. /// Add relevant permissions for an object to the item.
  414. /// </summary>
  415. /// <param name="item"></param>
  416. /// <param name="so"></param>
  417. /// <param name="objsForEffectivePermissions"></param>
  418. /// <param name="remoteClient"></param>
  419. /// <returns></returns>
  420. protected InventoryItemBase AddPermissions(
  421. InventoryItemBase item, SceneObjectGroup so, List<SceneObjectGroup> objsForEffectivePermissions,
  422. IClientAPI remoteClient)
  423. {
  424. uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move | PermissionMask.Export) | 7;
  425. foreach (SceneObjectGroup grp in objsForEffectivePermissions)
  426. effectivePerms &= grp.GetEffectivePermissions();
  427. effectivePerms |= (uint)PermissionMask.Move;
  428. if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions())
  429. {
  430. uint perms = effectivePerms;
  431. uint nextPerms = (perms & 7) << 13;
  432. if ((nextPerms & (uint)PermissionMask.Copy) == 0)
  433. perms &= ~(uint)PermissionMask.Copy;
  434. if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
  435. perms &= ~(uint)PermissionMask.Transfer;
  436. if ((nextPerms & (uint)PermissionMask.Modify) == 0)
  437. perms &= ~(uint)PermissionMask.Modify;
  438. item.BasePermissions = perms & so.RootPart.NextOwnerMask;
  439. item.CurrentPermissions = item.BasePermissions;
  440. item.NextPermissions = perms & so.RootPart.NextOwnerMask;
  441. item.EveryOnePermissions = so.RootPart.EveryoneMask & so.RootPart.NextOwnerMask;
  442. item.GroupPermissions = so.RootPart.GroupMask & so.RootPart.NextOwnerMask;
  443. // Magic number badness. Maybe this deserves an enum.
  444. // bit 4 (16) is the "Slam" bit, it means treat as passed
  445. // and apply next owner perms on rez
  446. item.CurrentPermissions |= 16; // Slam!
  447. }
  448. else
  449. {
  450. item.BasePermissions = effectivePerms;
  451. item.CurrentPermissions = effectivePerms;
  452. item.NextPermissions = so.RootPart.NextOwnerMask & effectivePerms;
  453. item.EveryOnePermissions = so.RootPart.EveryoneMask & effectivePerms;
  454. item.GroupPermissions = so.RootPart.GroupMask & effectivePerms;
  455. item.CurrentPermissions &=
  456. ((uint)PermissionMask.Copy |
  457. (uint)PermissionMask.Transfer |
  458. (uint)PermissionMask.Modify |
  459. (uint)PermissionMask.Move |
  460. (uint)PermissionMask.Export |
  461. 7); // Preserve folded permissions
  462. }
  463. return item;
  464. }
  465. /// <summary>
  466. /// Create an item using details for the given scene object.
  467. /// </summary>
  468. /// <param name="action"></param>
  469. /// <param name="remoteClient"></param>
  470. /// <param name="so"></param>
  471. /// <param name="folderID"></param>
  472. /// <returns></returns>
  473. protected InventoryItemBase CreateItemForObject(
  474. DeRezAction action, IClientAPI remoteClient, SceneObjectGroup so, UUID folderID)
  475. {
  476. // Get the user info of the item destination
  477. //
  478. UUID userID = UUID.Zero;
  479. if (action == DeRezAction.Take || action == DeRezAction.TakeCopy ||
  480. action == DeRezAction.SaveToExistingUserInventoryItem)
  481. {
  482. // Take or take copy require a taker
  483. // Saving changes requires a local user
  484. //
  485. if (remoteClient == null)
  486. return null;
  487. userID = remoteClient.AgentId;
  488. // m_log.DebugFormat(
  489. // "[INVENTORY ACCESS MODULE]: Target of {0} in CreateItemForObject() is {1} {2}",
  490. // action, remoteClient.Name, userID);
  491. }
  492. else if (so.RootPart.OwnerID == so.RootPart.GroupID)
  493. {
  494. // Group owned objects go to the last owner before the object was transferred.
  495. userID = so.RootPart.LastOwnerID;
  496. }
  497. else
  498. {
  499. // Other returns / deletes go to the object owner
  500. //
  501. userID = so.RootPart.OwnerID;
  502. // m_log.DebugFormat(
  503. // "[INVENTORY ACCESS MODULE]: Target of {0} in CreateItemForObject() is object owner {1}",
  504. // action, userID);
  505. }
  506. if (userID == UUID.Zero) // Can't proceed
  507. {
  508. return null;
  509. }
  510. // If we're returning someone's item, it goes back to the
  511. // owner's Lost And Found folder.
  512. // Delete is treated like return in this case
  513. // Deleting your own items makes them go to trash
  514. //
  515. InventoryFolderBase folder = null;
  516. InventoryItemBase item = null;
  517. if (DeRezAction.SaveToExistingUserInventoryItem == action)
  518. {
  519. item = new InventoryItemBase(so.RootPart.FromUserInventoryItemID, userID);
  520. item = m_Scene.InventoryService.GetItem(item);
  521. //item = userInfo.RootFolder.FindItem(
  522. // objectGroup.RootPart.FromUserInventoryItemID);
  523. if (null == item)
  524. {
  525. m_log.DebugFormat(
  526. "[INVENTORY ACCESS MODULE]: Object {0} {1} scheduled for save to inventory has already been deleted.",
  527. so.Name, so.UUID);
  528. return null;
  529. }
  530. }
  531. else
  532. {
  533. // Folder magic
  534. //
  535. if (action == DeRezAction.Delete)
  536. {
  537. // Deleting someone else's item
  538. //
  539. if (remoteClient == null ||
  540. so.OwnerID != remoteClient.AgentId)
  541. {
  542. folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
  543. }
  544. else
  545. {
  546. folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
  547. }
  548. }
  549. else if (action == DeRezAction.Return)
  550. {
  551. // Dump to lost + found unconditionally
  552. //
  553. folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
  554. }
  555. if (folderID == UUID.Zero && folder == null)
  556. {
  557. if (action == DeRezAction.Delete)
  558. {
  559. // Deletes go to trash by default
  560. //
  561. folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
  562. }
  563. else
  564. {
  565. if (remoteClient == null || so.RootPart.OwnerID != remoteClient.AgentId)
  566. {
  567. // Taking copy of another person's item. Take to
  568. // Objects folder.
  569. folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
  570. so.FromFolderID = UUID.Zero;
  571. }
  572. else
  573. {
  574. // Catch all. Use lost & found
  575. //
  576. folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
  577. }
  578. }
  579. }
  580. // Override and put into where it came from, if it came
  581. // from anywhere in inventory and the owner is taking it back.
  582. //
  583. if (action == DeRezAction.Take || action == DeRezAction.TakeCopy)
  584. {
  585. if (so.FromFolderID != UUID.Zero && so.RootPart.OwnerID == remoteClient.AgentId)
  586. {
  587. InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID);
  588. folder = m_Scene.InventoryService.GetFolder(f);
  589. if(folder.Type == 14 || folder.Type == 16)
  590. {
  591. // folder.Type = 6;
  592. folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
  593. }
  594. }
  595. }
  596. if (folder == null) // None of the above
  597. {
  598. folder = new InventoryFolderBase(folderID);
  599. if (folder == null) // Nowhere to put it
  600. {
  601. return null;
  602. }
  603. }
  604. item = new InventoryItemBase();
  605. item.ID = UUID.Random();
  606. item.InvType = (int)InventoryType.Object;
  607. item.Folder = folder.ID;
  608. item.Owner = userID;
  609. }
  610. return item;
  611. }
  612. public virtual SceneObjectGroup RezObject(
  613. IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart,
  614. UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
  615. bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
  616. {
  617. // m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID);
  618. InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
  619. item = m_Scene.InventoryService.GetItem(item);
  620. if (item == null)
  621. {
  622. m_log.WarnFormat(
  623. "[INVENTORY ACCESS MODULE]: Could not find item {0} for {1} in RezObject()",
  624. itemID, remoteClient.Name);
  625. return null;
  626. }
  627. item.Owner = remoteClient.AgentId;
  628. return RezObject(
  629. remoteClient, item, item.AssetID,
  630. RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
  631. RezSelected, RemoveItem, fromTaskID, attachment);
  632. }
  633. public virtual SceneObjectGroup RezObject(
  634. IClientAPI remoteClient, InventoryItemBase item, UUID assetID, Vector3 RayEnd, Vector3 RayStart,
  635. UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
  636. bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
  637. {
  638. AssetBase rezAsset = m_Scene.AssetService.Get(assetID.ToString());
  639. if (rezAsset == null)
  640. {
  641. if (item != null)
  642. {
  643. m_log.WarnFormat(
  644. "[InventoryAccessModule]: Could not find asset {0} for item {1} {2} for {3} in RezObject()",
  645. assetID, item.Name, item.ID, remoteClient.Name);
  646. }
  647. else
  648. {
  649. m_log.WarnFormat(
  650. "[INVENTORY ACCESS MODULE]: Could not find asset {0} for {1} in RezObject()",
  651. assetID, remoteClient.Name);
  652. }
  653. return null;
  654. }
  655. SceneObjectGroup group = null;
  656. string xmlData = Utils.BytesToString(rezAsset.Data);
  657. List<SceneObjectGroup> objlist = new List<SceneObjectGroup>();
  658. List<Vector3> veclist = new List<Vector3>();
  659. byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0);
  660. Vector3 pos;
  661. XmlDocument doc = new XmlDocument();
  662. doc.LoadXml(xmlData);
  663. XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject");
  664. if (e == null || attachment) // Single
  665. {
  666. SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
  667. objlist.Add(g);
  668. veclist.Add(Vector3.Zero);
  669. float offsetHeight = 0;
  670. pos = m_Scene.GetNewRezLocation(
  671. RayStart, RayEnd, RayTargetID, Quaternion.Identity,
  672. BypassRayCast, bRayEndIsIntersection, true, g.GetAxisAlignedBoundingBox(out offsetHeight), false);
  673. pos.Z += offsetHeight;
  674. }
  675. else
  676. {
  677. XmlElement coll = (XmlElement)e;
  678. float bx = Convert.ToSingle(coll.GetAttribute("x"));
  679. float by = Convert.ToSingle(coll.GetAttribute("y"));
  680. float bz = Convert.ToSingle(coll.GetAttribute("z"));
  681. Vector3 bbox = new Vector3(bx, by, bz);
  682. pos = m_Scene.GetNewRezLocation(RayStart, RayEnd,
  683. RayTargetID, Quaternion.Identity,
  684. BypassRayCast, bRayEndIsIntersection, true,
  685. bbox, false);
  686. pos -= bbox / 2;
  687. XmlNodeList groups = e.SelectNodes("SceneObjectGroup");
  688. foreach (XmlNode n in groups)
  689. {
  690. SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml);
  691. objlist.Add(g);
  692. XmlElement el = (XmlElement)n;
  693. string rawX = el.GetAttribute("offsetx");
  694. string rawY = el.GetAttribute("offsety");
  695. string rawZ = el.GetAttribute("offsetz");
  696. //
  697. // m_log.DebugFormat(
  698. // "[INVENTORY ACCESS MODULE]: Converting coalesced object {0} offset <{1}, {2}, {3}>",
  699. // g.Name, rawX, rawY, rawZ);
  700. float x = Convert.ToSingle(rawX);
  701. float y = Convert.ToSingle(rawY);
  702. float z = Convert.ToSingle(rawZ);
  703. veclist.Add(new Vector3(x, y, z));
  704. }
  705. }
  706. if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, veclist, attachment))
  707. return null;
  708. for (int i = 0; i < objlist.Count; i++)
  709. {
  710. group = objlist[i];
  711. // m_log.DebugFormat(
  712. // "[INVENTORY ACCESS MODULE]: Preparing to rez {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}",
  713. // group.Name, group.LocalId, group.UUID,
  714. // group.RootPart.OwnerMask, group.RootPart.NextOwnerMask, group.RootPart.GroupMask, group.RootPart.EveryoneMask,
  715. // remoteClient.Name);
  716. // Vector3 storedPosition = group.AbsolutePosition;
  717. if (group.UUID == UUID.Zero)
  718. {
  719. m_log.Debug("[INVENTORY ACCESS MODULE]: Object has UUID.Zero! Position 3");
  720. }
  721. foreach (SceneObjectPart part in group.Parts)
  722. {
  723. // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset.
  724. part.LastOwnerID = part.OwnerID;
  725. part.OwnerID = remoteClient.AgentId;
  726. }
  727. if (!attachment)
  728. {
  729. // If it's rezzed in world, select it. Much easier to
  730. // find small items.
  731. //
  732. foreach (SceneObjectPart part in group.Parts)
  733. {
  734. part.CreateSelected = true;
  735. }
  736. }
  737. group.ResetIDs();
  738. if (attachment)
  739. {
  740. group.RootPart.Flags |= PrimFlags.Phantom;
  741. group.IsAttachment = true;
  742. }
  743. // If we're rezzing an attachment then don't ask
  744. // AddNewSceneObject() to update the client since
  745. // we'll be doing that later on. Scheduling more than
  746. // one full update during the attachment
  747. // process causes some clients to fail to display the
  748. // attachment properly.
  749. m_Scene.AddNewSceneObject(group, true, false);
  750. // if attachment we set it's asset id so object updates
  751. // can reflect that, if not, we set it's position in world.
  752. if (!attachment)
  753. {
  754. group.ScheduleGroupForFullUpdate();
  755. group.AbsolutePosition = pos + veclist[i];
  756. }
  757. group.SetGroup(remoteClient.ActiveGroupId, remoteClient);
  758. if (!attachment)
  759. {
  760. SceneObjectPart rootPart = group.RootPart;
  761. if (rootPart.Shape.PCode == (byte)PCode.Prim)
  762. group.ClearPartAttachmentData();
  763. // Fire on_rez
  764. group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1);
  765. rootPart.ParentGroup.ResumeScripts();
  766. rootPart.ScheduleFullUpdate();
  767. }
  768. // m_log.DebugFormat(
  769. // "[INVENTORY ACCESS MODULE]: Rezzed {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}",
  770. // group.Name, group.LocalId, group.UUID,
  771. // group.RootPart.OwnerMask, group.RootPart.NextOwnerMask, group.RootPart.GroupMask, group.RootPart.EveryoneMask,
  772. // remoteClient.Name);
  773. }
  774. if (item != null)
  775. DoPostRezWhenFromItem(item, attachment);
  776. return group;
  777. }
  778. /// <summary>
  779. /// Do pre-rez processing when the object comes from an item.
  780. /// </summary>
  781. /// <param name="remoteClient"></param>
  782. /// <param name="item"></param>
  783. /// <param name="objlist"></param>
  784. /// <param name="pos"></param>
  785. /// <param name="veclist">
  786. /// List of vector position adjustments for a coalesced objects. For ordinary objects
  787. /// this list will contain just Vector3.Zero. The order of adjustments must match the order of objlist
  788. /// </param>
  789. /// <param name="isAttachment"></param>
  790. /// <returns>true if we can processed with rezzing, false if we need to abort</returns>
  791. private bool DoPreRezWhenFromItem(
  792. IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist,
  793. Vector3 pos, List<Vector3> veclist, bool isAttachment)
  794. {
  795. UUID fromUserInventoryItemId = UUID.Zero;
  796. // If we have permission to copy then link the rezzed object back to the user inventory
  797. // item that it came from. This allows us to enable 'save object to inventory'
  798. if (!m_Scene.Permissions.BypassPermissions())
  799. {
  800. if ((item.CurrentPermissions & (uint)PermissionMask.Copy)
  801. == (uint)PermissionMask.Copy && (item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
  802. {
  803. fromUserInventoryItemId = item.ID;
  804. }
  805. }
  806. else
  807. {
  808. if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
  809. {
  810. // Brave new fullperm world
  811. fromUserInventoryItemId = item.ID;
  812. }
  813. }
  814. for (int i = 0; i < objlist.Count; i++)
  815. {
  816. SceneObjectGroup g = objlist[i];
  817. if (!m_Scene.Permissions.CanRezObject(
  818. g.PrimCount, remoteClient.AgentId, pos + veclist[i])
  819. && !isAttachment)
  820. {
  821. // The client operates in no fail mode. It will
  822. // have already removed the item from the folder
  823. // if it's no copy.
  824. // Put it back if it's not an attachment
  825. //
  826. if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment))
  827. remoteClient.SendBulkUpdateInventory(item);
  828. ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y);
  829. remoteClient.SendAlertMessage(string.Format(
  830. "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.",
  831. item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.Name));
  832. return false;
  833. }
  834. }
  835. for (int i = 0; i < objlist.Count; i++)
  836. {
  837. SceneObjectGroup so = objlist[i];
  838. SceneObjectPart rootPart = so.RootPart;
  839. // Since renaming the item in the inventory does not
  840. // affect the name stored in the serialization, transfer
  841. // the correct name from the inventory to the
  842. // object itself before we rez.
  843. //
  844. // Only do these for the first object if we are rezzing a coalescence.
  845. if (i == 0)
  846. {
  847. rootPart.Name = item.Name;
  848. rootPart.Description = item.Description;
  849. rootPart.ObjectSaleType = item.SaleType;
  850. rootPart.SalePrice = item.SalePrice;
  851. }
  852. so.FromFolderID = item.Folder;
  853. // m_log.DebugFormat(
  854. // "[INVENTORY ACCESS MODULE]: rootPart.OwnedID {0}, item.Owner {1}, item.CurrentPermissions {2:X}",
  855. // rootPart.OwnerID, item.Owner, item.CurrentPermissions);
  856. if ((rootPart.OwnerID != item.Owner) ||
  857. (item.CurrentPermissions & 16) != 0)
  858. {
  859. //Need to kill the for sale here
  860. rootPart.ObjectSaleType = 0;
  861. rootPart.SalePrice = 10;
  862. if (m_Scene.Permissions.PropagatePermissions())
  863. {
  864. foreach (SceneObjectPart part in so.Parts)
  865. {
  866. if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
  867. {
  868. part.EveryoneMask = item.EveryOnePermissions;
  869. part.NextOwnerMask = item.NextPermissions;
  870. }
  871. part.GroupMask = 0; // DO NOT propagate here
  872. }
  873. so.ApplyNextOwnerPermissions();
  874. }
  875. }
  876. foreach (SceneObjectPart part in so.Parts)
  877. {
  878. part.FromUserInventoryItemID = fromUserInventoryItemId;
  879. if ((part.OwnerID != item.Owner) ||
  880. (item.CurrentPermissions & 16) != 0)
  881. {
  882. part.Inventory.ChangeInventoryOwner(item.Owner);
  883. part.GroupMask = 0; // DO NOT propagate here
  884. }
  885. part.EveryoneMask = item.EveryOnePermissions;
  886. part.NextOwnerMask = item.NextPermissions;
  887. }
  888. rootPart.TrimPermissions();
  889. if (isAttachment)
  890. so.FromItemID = item.ID;
  891. }
  892. return true;
  893. }
  894. /// <summary>
  895. /// Do post-rez processing when the object comes from an item.
  896. /// </summary>
  897. /// <param name="item"></param>
  898. /// <param name="isAttachment"></param>
  899. private void DoPostRezWhenFromItem(InventoryItemBase item, bool isAttachment)
  900. {
  901. if (!m_Scene.Permissions.BypassPermissions())
  902. {
  903. if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
  904. {
  905. // If this is done on attachments, no
  906. // copy ones will be lost, so avoid it
  907. //
  908. if (!isAttachment)
  909. {
  910. List<UUID> uuids = new List<UUID>();
  911. uuids.Add(item.ID);
  912. m_Scene.InventoryService.DeleteItems(item.Owner, uuids);
  913. }
  914. }
  915. }
  916. }
  917. protected void AddUserData(SceneObjectGroup sog)
  918. {
  919. UserManagementModule.AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData);
  920. foreach (SceneObjectPart sop in sog.Parts)
  921. UserManagementModule.AddUser(sop.CreatorID, sop.CreatorData);
  922. }
  923. public virtual void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver)
  924. {
  925. }
  926. public virtual bool CanGetAgentInventoryItem(IClientAPI remoteClient, UUID itemID, UUID requestID)
  927. {
  928. InventoryItemBase assetRequestItem = GetItem(remoteClient.AgentId, itemID);
  929. if (assetRequestItem == null)
  930. {
  931. ILibraryService lib = m_Scene.RequestModuleInterface<ILibraryService>();
  932. if (lib != null)
  933. assetRequestItem = lib.LibraryRootFolder.FindItem(itemID);
  934. if (assetRequestItem == null)
  935. return false;
  936. }
  937. // At this point, we need to apply perms
  938. // only to notecards and scripts. All
  939. // other asset types are always available
  940. //
  941. if (assetRequestItem.AssetType == (int)AssetType.LSLText)
  942. {
  943. if (!m_Scene.Permissions.CanViewScript(itemID, UUID.Zero, remoteClient.AgentId))
  944. {
  945. remoteClient.SendAgentAlertMessage("Insufficient permissions to view script", false);
  946. return false;
  947. }
  948. }
  949. else if (assetRequestItem.AssetType == (int)AssetType.Notecard)
  950. {
  951. if (!m_Scene.Permissions.CanViewNotecard(itemID, UUID.Zero, remoteClient.AgentId))
  952. {
  953. remoteClient.SendAgentAlertMessage("Insufficient permissions to view notecard", false);
  954. return false;
  955. }
  956. }
  957. if (assetRequestItem.AssetID != requestID)
  958. {
  959. m_log.WarnFormat(
  960. "[INVENTORY ACCESS MODULE]: {0} requested asset {1} from item {2} but this does not match item's asset {3}",
  961. Name, requestID, itemID, assetRequestItem.AssetID);
  962. return false;
  963. }
  964. return true;
  965. }
  966. public virtual bool IsForeignUser(UUID userID, out string assetServerURL)
  967. {
  968. assetServerURL = string.Empty;
  969. return false;
  970. }
  971. #endregion
  972. #region Misc
  973. /// <summary>
  974. /// Create a new asset data structure.
  975. /// </summary>
  976. /// <param name="name"></param>
  977. /// <param name="description"></param>
  978. /// <param name="invType"></param>
  979. /// <param name="assetType"></param>
  980. /// <param name="data"></param>
  981. /// <returns></returns>
  982. private AssetBase CreateAsset(string name, string description, sbyte assetType, byte[] data, string creatorID)
  983. {
  984. AssetBase asset = new AssetBase(UUID.Random(), name, assetType, creatorID);
  985. asset.Description = description;
  986. asset.Data = (data == null) ? new byte[1] : data;
  987. return asset;
  988. }
  989. protected virtual InventoryItemBase GetItem(UUID agentID, UUID itemID)
  990. {
  991. IInventoryService invService = m_Scene.RequestModuleInterface<IInventoryService>();
  992. InventoryItemBase item = new InventoryItemBase(itemID, agentID);
  993. item = invService.GetItem(item);
  994. if (item != null && item.CreatorData != null && item.CreatorData != string.Empty)
  995. UserManagementModule.AddUser(item.CreatorIdAsUuid, item.CreatorData);
  996. return item;
  997. }
  998. #endregion
  999. }
  1000. }