opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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, 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 List<InventoryItemBase> CopyToInventory(
297 DeRezAction action, UUID folderID,
298 List<SceneObjectGroup> objectGroups, IClientAPI remoteClient, bool asAttachment)
299 {
300 List<InventoryItemBase> copiedItems = new List<InventoryItemBase>();
301  
302 Dictionary<UUID, List<SceneObjectGroup>> bundlesToCopy = new Dictionary<UUID, List<SceneObjectGroup>>();
303  
304 if (CoalesceMultipleObjectsToInventory)
305 {
306 // The following code groups the SOG's by owner. No objects
307 // belonging to different people can be coalesced, for obvious
308 // reasons.
309 foreach (SceneObjectGroup g in objectGroups)
310 {
311 if (!bundlesToCopy.ContainsKey(g.OwnerID))
312 bundlesToCopy[g.OwnerID] = new List<SceneObjectGroup>();
313  
314 bundlesToCopy[g.OwnerID].Add(g);
315 }
316 }
317 else
318 {
319 // If we don't want to coalesce then put every object in its own bundle.
320 foreach (SceneObjectGroup g in objectGroups)
321 {
322 List<SceneObjectGroup> bundle = new List<SceneObjectGroup>();
323 bundle.Add(g);
324 bundlesToCopy[g.UUID] = bundle;
325 }
326 }
327  
328 // m_log.DebugFormat(
329 // "[INVENTORY ACCESS MODULE]: Copying {0} object bundles to folder {1} action {2} for {3}",
330 // bundlesToCopy.Count, folderID, action, remoteClient.Name);
331  
332 // Each iteration is really a separate asset being created,
333 // with distinct destinations as well.
334 foreach (List<SceneObjectGroup> bundle in bundlesToCopy.Values)
335 copiedItems.Add(CopyBundleToInventory(action, folderID, bundle, remoteClient, asAttachment));
336  
337 return copiedItems;
338 }
339  
340 /// <summary>
341 /// Copy a bundle of objects to inventory. If there is only one object, then this will create an object
342 /// item. If there are multiple objects then these will be saved as a single coalesced item.
343 /// </summary>
344 /// <param name="action"></param>
345 /// <param name="folderID"></param>
346 /// <param name="objlist"></param>
347 /// <param name="remoteClient"></param>
348 /// <param name="asAttachment">Should be true if the bundle is being copied as an attachment. This prevents
349 /// attempted serialization of any script state which would abort any operating scripts.</param>
350 /// <returns>The inventory item created by the copy</returns>
351 protected InventoryItemBase CopyBundleToInventory(
352 DeRezAction action, UUID folderID, List<SceneObjectGroup> objlist, IClientAPI remoteClient,
353 bool asAttachment)
354 {
355 CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero);
356 // Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>();
357  
358 foreach (SceneObjectGroup objectGroup in objlist)
359 {
360 if (objectGroup.RootPart.KeyframeMotion != null)
361 objectGroup.RootPart.KeyframeMotion.Stop();
362 objectGroup.RootPart.KeyframeMotion = null;
363 // Vector3 inventoryStoredPosition = new Vector3
364 // (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
365 // ? 250
366 // : objectGroup.AbsolutePosition.X)
367 // ,
368 // (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize)
369 // ? 250
370 // : objectGroup.AbsolutePosition.Y,
371 // objectGroup.AbsolutePosition.Z);
372 //
373 // originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition;
374 //
375 // objectGroup.AbsolutePosition = inventoryStoredPosition;
376  
377 // Make sure all bits but the ones we want are clear
378 // on take.
379 // This will be applied to the current perms, so
380 // it will do what we want.
381 objectGroup.RootPart.NextOwnerMask &=
382 ((uint)PermissionMask.Copy |
383 (uint)PermissionMask.Transfer |
384 (uint)PermissionMask.Modify |
385 (uint)PermissionMask.Export);
386 objectGroup.RootPart.NextOwnerMask |=
387 (uint)PermissionMask.Move;
388  
389 coa.Add(objectGroup);
390 }
391  
392 string itemXml;
393  
394 // If we're being called from a script, then trying to serialize that same script's state will not complete
395 // in any reasonable time period. Therefore, we'll avoid it. The worst that can happen is that if
396 // the client/server crashes rather than logging out normally, the attachment's scripts will resume
397 // without state on relog. Arguably, this is what we want anyway.
398 if (objlist.Count > 1)
399 itemXml = CoalescedSceneObjectsSerializer.ToXml(coa, !asAttachment);
400 else
401 itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment);
402  
403 // // Restore the position of each group now that it has been stored to inventory.
404 // foreach (SceneObjectGroup objectGroup in objlist)
405 // objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID];
406  
407 InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID);
408  
409 // m_log.DebugFormat(
410 // "[INVENTORY ACCESS MODULE]: Created item is {0}",
411 // item != null ? item.ID.ToString() : "NULL");
412  
413 if (item == null)
414 return null;
415  
416 item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
417 item.CreatorData = objlist[0].RootPart.CreatorData;
418  
419 if (objlist.Count > 1)
420 {
421 item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems;
422  
423 // If the objects have different creators then don't specify a creator at all
424 foreach (SceneObjectGroup objectGroup in objlist)
425 {
426 if ((objectGroup.RootPart.CreatorID.ToString() != item.CreatorId)
427 || (objectGroup.RootPart.CreatorData.ToString() != item.CreatorData))
428 {
429 item.CreatorId = UUID.Zero.ToString();
430 item.CreatorData = string.Empty;
431 break;
432 }
433 }
434 }
435 else
436 {
437 item.SaleType = objlist[0].RootPart.ObjectSaleType;
438 item.SalePrice = objlist[0].RootPart.SalePrice;
439 }
440  
441 AssetBase asset = CreateAsset(
442 objlist[0].GetPartName(objlist[0].RootPart.LocalId),
443 objlist[0].GetPartDescription(objlist[0].RootPart.LocalId),
444 (sbyte)AssetType.Object,
445 Utils.StringToBytes(itemXml),
446 objlist[0].OwnerID.ToString());
447 m_Scene.AssetService.Store(asset);
448  
449 item.AssetID = asset.FullID;
450  
451 if (DeRezAction.SaveToExistingUserInventoryItem == action)
452 {
453 m_Scene.InventoryService.UpdateItem(item);
454 }
455 else
456 {
457 item.CreationDate = Util.UnixTimeSinceEpoch();
458 item.Description = asset.Description;
459 item.Name = asset.Name;
460 item.AssetType = asset.Type;
461  
462 AddPermissions(item, objlist[0], objlist, remoteClient);
463  
464 m_Scene.AddInventoryItem(item);
465  
466 if (remoteClient != null && item.Owner == remoteClient.AgentId)
467 {
468 remoteClient.SendInventoryItemCreateUpdate(item, 0);
469 }
470 else
471 {
472 ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner);
473 if (notifyUser != null)
474 {
475 notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
476 }
477 }
478 }
479  
480 // This is a hook to do some per-asset post-processing for subclasses that need that
481 if (remoteClient != null)
482 ExportAsset(remoteClient.AgentId, asset.FullID);
483  
484 return item;
485 }
486  
487 protected virtual void ExportAsset(UUID agentID, UUID assetID)
488 {
489 // nothing to do here
490 }
491  
492 /// <summary>
493 /// Add relevant permissions for an object to the item.
494 /// </summary>
495 /// <param name="item"></param>
496 /// <param name="so"></param>
497 /// <param name="objsForEffectivePermissions"></param>
498 /// <param name="remoteClient"></param>
499 /// <returns></returns>
500 protected InventoryItemBase AddPermissions(
501 InventoryItemBase item, SceneObjectGroup so, List<SceneObjectGroup> objsForEffectivePermissions,
502 IClientAPI remoteClient)
503 {
504 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move | PermissionMask.Export) | 7;
505 uint allObjectsNextOwnerPerms = 0x7fffffff;
506 uint allObjectsEveryOnePerms = 0x7fffffff;
507 uint allObjectsGroupPerms = 0x7fffffff;
508  
509 foreach (SceneObjectGroup grp in objsForEffectivePermissions)
510 {
511 effectivePerms &= grp.GetEffectivePermissions();
512 allObjectsNextOwnerPerms &= grp.RootPart.NextOwnerMask;
513 allObjectsEveryOnePerms &= grp.RootPart.EveryoneMask;
514 allObjectsGroupPerms &= grp.RootPart.GroupMask;
515 }
516 effectivePerms |= (uint)PermissionMask.Move;
517  
518 //PermissionsUtil.LogPermissions(item.Name, "Before AddPermissions", item.BasePermissions, item.CurrentPermissions, item.NextPermissions);
519  
520 if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions())
521 {
522 uint perms = effectivePerms;
523 PermissionsUtil.ApplyFoldedPermissions(effectivePerms, ref perms);
524  
525 item.BasePermissions = perms & allObjectsNextOwnerPerms;
526 item.CurrentPermissions = item.BasePermissions;
527 item.NextPermissions = perms & allObjectsNextOwnerPerms;
528 item.EveryOnePermissions = allObjectsEveryOnePerms & allObjectsNextOwnerPerms;
529 item.GroupPermissions = allObjectsGroupPerms & allObjectsNextOwnerPerms;
530  
531 // apply next owner perms on rez
532 item.CurrentPermissions |= SceneObjectGroup.SLAM;
533 }
534 else
535 {
536 item.BasePermissions = effectivePerms;
537 item.CurrentPermissions = effectivePerms;
538 item.NextPermissions = allObjectsNextOwnerPerms & effectivePerms;
539 item.EveryOnePermissions = allObjectsEveryOnePerms & effectivePerms;
540 item.GroupPermissions = allObjectsGroupPerms & effectivePerms;
541  
542 item.CurrentPermissions &=
543 ((uint)PermissionMask.Copy |
544 (uint)PermissionMask.Transfer |
545 (uint)PermissionMask.Modify |
546 (uint)PermissionMask.Move |
547 (uint)PermissionMask.Export |
548 7); // Preserve folded permissions
549 }
550  
551 //PermissionsUtil.LogPermissions(item.Name, "After AddPermissions", item.BasePermissions, item.CurrentPermissions, item.NextPermissions);
552  
553 return item;
554 }
555  
556 /// <summary>
557 /// Create an item using details for the given scene object.
558 /// </summary>
559 /// <param name="action"></param>
560 /// <param name="remoteClient"></param>
561 /// <param name="so"></param>
562 /// <param name="folderID"></param>
563 /// <returns></returns>
564 protected InventoryItemBase CreateItemForObject(
565 DeRezAction action, IClientAPI remoteClient, SceneObjectGroup so, UUID folderID)
566 {
567 // Get the user info of the item destination
568 //
569 UUID userID = UUID.Zero;
570  
571 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy ||
572 action == DeRezAction.SaveToExistingUserInventoryItem)
573 {
574 // Take or take copy require a taker
575 // Saving changes requires a local user
576 //
577 if (remoteClient == null)
578 return null;
579  
580 userID = remoteClient.AgentId;
581  
582 // m_log.DebugFormat(
583 // "[INVENTORY ACCESS MODULE]: Target of {0} in CreateItemForObject() is {1} {2}",
584 // action, remoteClient.Name, userID);
585 }
586 else if (so.RootPart.OwnerID == so.RootPart.GroupID)
587 {
588 // Group owned objects go to the last owner before the object was transferred.
589 userID = so.RootPart.LastOwnerID;
590 }
591 else
592 {
593 // Other returns / deletes go to the object owner
594 //
595 userID = so.RootPart.OwnerID;
596  
597 // m_log.DebugFormat(
598 // "[INVENTORY ACCESS MODULE]: Target of {0} in CreateItemForObject() is object owner {1}",
599 // action, userID);
600 }
601  
602 if (userID == UUID.Zero) // Can't proceed
603 {
604 return null;
605 }
606  
607 // If we're returning someone's item, it goes back to the
608 // owner's Lost And Found folder.
609 // Delete is treated like return in this case
610 // Deleting your own items makes them go to trash
611 //
612  
613 InventoryFolderBase folder = null;
614 InventoryItemBase item = null;
615  
616 if (DeRezAction.SaveToExistingUserInventoryItem == action)
617 {
618 item = new InventoryItemBase(so.RootPart.FromUserInventoryItemID, userID);
619 item = m_Scene.InventoryService.GetItem(item);
620  
621 //item = userInfo.RootFolder.FindItem(
622 // objectGroup.RootPart.FromUserInventoryItemID);
623  
624 if (null == item)
625 {
626 m_log.DebugFormat(
627 "[INVENTORY ACCESS MODULE]: Object {0} {1} scheduled for save to inventory has already been deleted.",
628 so.Name, so.UUID);
629  
630 return null;
631 }
632 }
633 else
634 {
635 // Folder magic
636 //
637 if (action == DeRezAction.Delete)
638 {
639 // Deleting someone else's item
640 //
641 if (remoteClient == null ||
642 so.OwnerID != remoteClient.AgentId)
643 {
644 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
645 }
646 else
647 {
648 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
649 }
650 }
651 else if (action == DeRezAction.Return)
652 {
653 // Dump to lost + found unconditionally
654 //
655 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
656 }
657  
658 if (folderID == UUID.Zero && folder == null)
659 {
660 if (action == DeRezAction.Delete)
661 {
662 // Deletes go to trash by default
663 //
664 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
665 }
666 else
667 {
668 if (remoteClient == null || so.RootPart.OwnerID != remoteClient.AgentId)
669 {
670 // Taking copy of another person's item. Take to
671 // Objects folder.
672 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
673 so.FromFolderID = UUID.Zero;
674 }
675 else
676 {
677 // Catch all. Use lost & found
678 //
679 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
680 }
681 }
682 }
683  
684 // Override and put into where it came from, if it came
685 // from anywhere in inventory and the owner is taking it back.
686 //
687 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy)
688 {
689 if (so.FromFolderID != UUID.Zero && so.RootPart.OwnerID == remoteClient.AgentId)
690 {
691 InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID);
692 folder = m_Scene.InventoryService.GetFolder(f);
693  
694 if(folder.Type == 14 || folder.Type == 16)
695 {
696 // folder.Type = 6;
697 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
698 }
699 }
700 }
701  
702 if (folder == null) // None of the above
703 {
704 folder = new InventoryFolderBase(folderID);
705  
706 if (folder == null) // Nowhere to put it
707 {
708 return null;
709 }
710 }
711  
712 item = new InventoryItemBase();
713 item.ID = UUID.Random();
714 item.InvType = (int)InventoryType.Object;
715 item.Folder = folder.ID;
716 item.Owner = userID;
717 }
718  
719 return item;
720 }
721  
722 public virtual SceneObjectGroup RezObject(
723 IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart,
724 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
725 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
726 {
727 // m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID);
728  
729 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
730 item = m_Scene.InventoryService.GetItem(item);
731  
732 if (item == null)
733 {
734 m_log.WarnFormat(
735 "[INVENTORY ACCESS MODULE]: Could not find item {0} for {1} in RezObject()",
736 itemID, remoteClient.Name);
737  
738 return null;
739 }
740  
741 item.Owner = remoteClient.AgentId;
742  
743 return RezObject(
744 remoteClient, item, item.AssetID,
745 RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
746 RezSelected, RemoveItem, fromTaskID, attachment);
747 }
748  
749 public virtual SceneObjectGroup RezObject(
750 IClientAPI remoteClient, InventoryItemBase item, UUID assetID, Vector3 RayEnd, Vector3 RayStart,
751 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
752 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
753 {
754 AssetBase rezAsset = m_Scene.AssetService.Get(assetID.ToString());
755  
756 if (rezAsset == null)
757 {
758 if (item != null)
759 {
760 m_log.WarnFormat(
761 "[InventoryAccessModule]: Could not find asset {0} for item {1} {2} for {3} in RezObject()",
762 assetID, item.Name, item.ID, remoteClient.Name);
763 }
764 else
765 {
766 m_log.WarnFormat(
767 "[INVENTORY ACCESS MODULE]: Could not find asset {0} for {1} in RezObject()",
768 assetID, remoteClient.Name);
769 }
770  
771 return null;
772 }
773  
774 SceneObjectGroup group = null;
775  
776 List<SceneObjectGroup> objlist;
777 List<Vector3> veclist;
778 Vector3 bbox;
779 float offsetHeight;
780 byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0);
781 Vector3 pos;
782  
783 bool single = m_Scene.GetObjectsToRez(rezAsset.Data, attachment, out objlist, out veclist, out bbox, out offsetHeight);
784  
785 if (single)
786 {
787 pos = m_Scene.GetNewRezLocation(
788 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
789 BypassRayCast, bRayEndIsIntersection, true, bbox, false);
790 pos.Z += offsetHeight;
791 }
792 else
793 {
794 pos = m_Scene.GetNewRezLocation(RayStart, RayEnd,
795 RayTargetID, Quaternion.Identity,
796 BypassRayCast, bRayEndIsIntersection, true,
797 bbox, false);
798 pos -= bbox / 2;
799 }
800  
801 if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, veclist, attachment))
802 return null;
803  
804 for (int i = 0; i < objlist.Count; i++)
805 {
806 group = objlist[i];
807  
808 // m_log.DebugFormat(
809 // "[INVENTORY ACCESS MODULE]: Preparing to rez {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}",
810 // group.Name, group.LocalId, group.UUID,
811 // group.RootPart.OwnerMask, group.RootPart.NextOwnerMask, group.RootPart.GroupMask, group.RootPart.EveryoneMask,
812 // remoteClient.Name);
813  
814 // Vector3 storedPosition = group.AbsolutePosition;
815 if (group.UUID == UUID.Zero)
816 {
817 m_log.Debug("[INVENTORY ACCESS MODULE]: Object has UUID.Zero! Position 3");
818 }
819  
820 // if this was previously an attachment and is now being rezzed,
821 // save the old attachment info.
822 if (group.IsAttachment == false && group.RootPart.Shape.State != 0)
823 {
824 group.RootPart.AttachedPos = group.AbsolutePosition;
825 group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint;
826 }
827  
828 if (item == null)
829 {
830 // Change ownership. Normally this is done in DoPreRezWhenFromItem(), but in this case we must do it here.
831 foreach (SceneObjectPart part in group.Parts)
832 {
833 // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset.
834 part.LastOwnerID = part.OwnerID;
835 part.OwnerID = remoteClient.AgentId;
836 }
837 }
838  
839 if (!attachment)
840 {
841 // If it's rezzed in world, select it. Much easier to
842 // find small items.
843 //
844 foreach (SceneObjectPart part in group.Parts)
845 {
846 part.CreateSelected = true;
847 }
848 }
849  
850 group.ResetIDs();
851  
852 if (attachment)
853 {
854 group.RootPart.Flags |= PrimFlags.Phantom;
855 group.IsAttachment = true;
856 }
857  
858 // If we're rezzing an attachment then don't ask
859 // AddNewSceneObject() to update the client since
860 // we'll be doing that later on. Scheduling more than
861 // one full update during the attachment
862 // process causes some clients to fail to display the
863 // attachment properly.
864 m_Scene.AddNewSceneObject(group, true, false);
865  
866 // if attachment we set it's asset id so object updates
867 // can reflect that, if not, we set it's position in world.
868 if (!attachment)
869 {
870 group.ScheduleGroupForFullUpdate();
871  
872 group.AbsolutePosition = pos + veclist[i];
873 }
874  
875 group.SetGroup(remoteClient.ActiveGroupId, remoteClient);
876  
877 if (!attachment)
878 {
879 SceneObjectPart rootPart = group.RootPart;
880  
881 if (rootPart.Shape.PCode == (byte)PCode.Prim)
882 group.ClearPartAttachmentData();
883  
884 // Fire on_rez
885 group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1);
886 rootPart.ParentGroup.ResumeScripts();
887  
888 rootPart.ScheduleFullUpdate();
889 }
890  
891 // m_log.DebugFormat(
892 // "[INVENTORY ACCESS MODULE]: Rezzed {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}",
893 // group.Name, group.LocalId, group.UUID,
894 // group.RootPart.OwnerMask, group.RootPart.NextOwnerMask, group.RootPart.GroupMask, group.RootPart.EveryoneMask,
895 // remoteClient.Name);
896 }
897  
898 if (item != null)
899 DoPostRezWhenFromItem(item, attachment);
900  
901 return group;
902 }
903  
904 /// <summary>
905 /// Do pre-rez processing when the object comes from an item.
906 /// </summary>
907 /// <param name="remoteClient"></param>
908 /// <param name="item"></param>
909 /// <param name="objlist"></param>
910 /// <param name="pos"></param>
911 /// <param name="veclist">
912 /// List of vector position adjustments for a coalesced objects. For ordinary objects
913 /// this list will contain just Vector3.Zero. The order of adjustments must match the order of objlist
914 /// </param>
915 /// <param name="isAttachment"></param>
916 /// <returns>true if we can processed with rezzing, false if we need to abort</returns>
917 private bool DoPreRezWhenFromItem(
918 IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist,
919 Vector3 pos, List<Vector3> veclist, bool isAttachment)
920 {
921 UUID fromUserInventoryItemId = UUID.Zero;
922  
923 // If we have permission to copy then link the rezzed object back to the user inventory
924 // item that it came from. This allows us to enable 'save object to inventory'
925 if (!m_Scene.Permissions.BypassPermissions())
926 {
927 if ((item.CurrentPermissions & (uint)PermissionMask.Copy)
928 == (uint)PermissionMask.Copy && (item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
929 {
930 fromUserInventoryItemId = item.ID;
931 }
932 }
933 else
934 {
935 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
936 {
937 // Brave new fullperm world
938 fromUserInventoryItemId = item.ID;
939 }
940 }
941  
942 for (int i = 0; i < objlist.Count; i++)
943 {
944 SceneObjectGroup g = objlist[i];
945  
946 if (!m_Scene.Permissions.CanRezObject(
947 g.PrimCount, remoteClient.AgentId, pos + veclist[i])
948 && !isAttachment)
949 {
950 // The client operates in no fail mode. It will
951 // have already removed the item from the folder
952 // if it's no copy.
953 // Put it back if it's not an attachment
954 //
955 if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment))
956 remoteClient.SendBulkUpdateInventory(item);
957  
958 ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y);
959 remoteClient.SendAlertMessage(string.Format(
960 "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.",
961 item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.Name));
962  
963 return false;
964 }
965 }
966  
967 for (int i = 0; i < objlist.Count; i++)
968 {
969 SceneObjectGroup so = objlist[i];
970 SceneObjectPart rootPart = so.RootPart;
971  
972 // Since renaming the item in the inventory does not
973 // affect the name stored in the serialization, transfer
974 // the correct name from the inventory to the
975 // object itself before we rez.
976 //
977 // Only do these for the first object if we are rezzing a coalescence.
978 if (i == 0)
979 {
980 rootPart.Name = item.Name;
981 rootPart.Description = item.Description;
982 rootPart.ObjectSaleType = item.SaleType;
983 rootPart.SalePrice = item.SalePrice;
984 }
985  
986 so.FromFolderID = item.Folder;
987  
988 // m_log.DebugFormat(
989 // "[INVENTORY ACCESS MODULE]: rootPart.OwnedID {0}, item.Owner {1}, item.CurrentPermissions {2:X}",
990 // rootPart.OwnerID, item.Owner, item.CurrentPermissions);
991  
992 if ((rootPart.OwnerID != item.Owner) || (item.CurrentPermissions & SceneObjectGroup.SLAM) != 0)
993 {
994 //Need to kill the for sale here
995 rootPart.ObjectSaleType = 0;
996 rootPart.SalePrice = 10;
997 }
998  
999 foreach (SceneObjectPart part in so.Parts)
1000 {
1001 part.FromUserInventoryItemID = fromUserInventoryItemId;
1002 part.ApplyPermissionsOnRez(item, true, m_Scene);
1003 }
1004  
1005 rootPart.TrimPermissions();
1006  
1007 if (isAttachment)
1008 so.FromItemID = item.ID;
1009 }
1010  
1011 return true;
1012 }
1013  
1014 /// <summary>
1015 /// Do post-rez processing when the object comes from an item.
1016 /// </summary>
1017 /// <param name="item"></param>
1018 /// <param name="isAttachment"></param>
1019 private void DoPostRezWhenFromItem(InventoryItemBase item, bool isAttachment)
1020 {
1021 if (!m_Scene.Permissions.BypassPermissions())
1022 {
1023 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1024 {
1025 // If this is done on attachments, no
1026 // copy ones will be lost, so avoid it
1027 //
1028 if (!isAttachment)
1029 {
1030 List<UUID> uuids = new List<UUID>();
1031 uuids.Add(item.ID);
1032 m_Scene.InventoryService.DeleteItems(item.Owner, uuids);
1033 }
1034 }
1035 }
1036 }
1037  
1038 protected void AddUserData(SceneObjectGroup sog)
1039 {
1040 UserManagementModule.AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData);
1041 foreach (SceneObjectPart sop in sog.Parts)
1042 UserManagementModule.AddUser(sop.CreatorID, sop.CreatorData);
1043 }
1044  
1045 public virtual void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver)
1046 {
1047 }
1048  
1049 public virtual bool CanGetAgentInventoryItem(IClientAPI remoteClient, UUID itemID, UUID requestID)
1050 {
1051 InventoryItemBase assetRequestItem = GetItem(remoteClient.AgentId, itemID);
1052  
1053 if (assetRequestItem == null)
1054 {
1055 ILibraryService lib = m_Scene.RequestModuleInterface<ILibraryService>();
1056  
1057 if (lib != null)
1058 assetRequestItem = lib.LibraryRootFolder.FindItem(itemID);
1059  
1060 if (assetRequestItem == null)
1061 return false;
1062 }
1063  
1064 // At this point, we need to apply perms
1065 // only to notecards and scripts. All
1066 // other asset types are always available
1067 //
1068 if (assetRequestItem.AssetType == (int)AssetType.LSLText)
1069 {
1070 if (!m_Scene.Permissions.CanViewScript(itemID, UUID.Zero, remoteClient.AgentId))
1071 {
1072 remoteClient.SendAgentAlertMessage("Insufficient permissions to view script", false);
1073 return false;
1074 }
1075 }
1076 else if (assetRequestItem.AssetType == (int)AssetType.Notecard)
1077 {
1078 if (!m_Scene.Permissions.CanViewNotecard(itemID, UUID.Zero, remoteClient.AgentId))
1079 {
1080 remoteClient.SendAgentAlertMessage("Insufficient permissions to view notecard", false);
1081 return false;
1082 }
1083 }
1084  
1085 if (assetRequestItem.AssetID != requestID)
1086 {
1087 m_log.WarnFormat(
1088 "[INVENTORY ACCESS MODULE]: {0} requested asset {1} from item {2} but this does not match item's asset {3}",
1089 Name, requestID, itemID, assetRequestItem.AssetID);
1090  
1091 return false;
1092 }
1093  
1094 return true;
1095 }
1096  
1097  
1098 public virtual bool IsForeignUser(UUID userID, out string assetServerURL)
1099 {
1100 assetServerURL = string.Empty;
1101 return false;
1102 }
1103  
1104 #endregion
1105  
1106 #region Misc
1107  
1108 /// <summary>
1109 /// Create a new asset data structure.
1110 /// </summary>
1111 /// <param name="name"></param>
1112 /// <param name="description"></param>
1113 /// <param name="invType"></param>
1114 /// <param name="assetType"></param>
1115 /// <param name="data"></param>
1116 /// <returns></returns>
1117 private AssetBase CreateAsset(string name, string description, sbyte assetType, byte[] data, string creatorID)
1118 {
1119 AssetBase asset = new AssetBase(UUID.Random(), name, assetType, creatorID);
1120 asset.Description = description;
1121 asset.Data = (data == null) ? new byte[1] : data;
1122  
1123 return asset;
1124 }
1125  
1126 protected virtual InventoryItemBase GetItem(UUID agentID, UUID itemID)
1127 {
1128 IInventoryService invService = m_Scene.RequestModuleInterface<IInventoryService>();
1129 InventoryItemBase item = new InventoryItemBase(itemID, agentID);
1130 item = invService.GetItem(item);
1131  
1132 if (item != null && item.CreatorData != null && item.CreatorData != string.Empty)
1133 UserManagementModule.AddUser(item.CreatorIdAsUuid, item.CreatorData);
1134  
1135 return item;
1136 }
1137  
1138 #endregion
1139 }
1140 }