clockwerk-opensim – Blame information for rev 1

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