clockwerk-opensim-stable – 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, 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 // Can't know creator is the same, so null it in inventory
417 if (objlist.Count > 1)
418 {
419 item.CreatorId = UUID.Zero.ToString();
420 item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems;
421 }
422 else
423 {
424 item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
425 item.CreatorData = objlist[0].RootPart.CreatorData;
426 item.SaleType = objlist[0].RootPart.ObjectSaleType;
427 item.SalePrice = objlist[0].RootPart.SalePrice;
428 }
429  
430 AssetBase asset = CreateAsset(
431 objlist[0].GetPartName(objlist[0].RootPart.LocalId),
432 objlist[0].GetPartDescription(objlist[0].RootPart.LocalId),
433 (sbyte)AssetType.Object,
434 Utils.StringToBytes(itemXml),
435 objlist[0].OwnerID.ToString());
436 m_Scene.AssetService.Store(asset);
437  
438 item.AssetID = asset.FullID;
439  
440 if (DeRezAction.SaveToExistingUserInventoryItem == action)
441 {
442 m_Scene.InventoryService.UpdateItem(item);
443 }
444 else
445 {
446 AddPermissions(item, objlist[0], objlist, remoteClient);
447  
448 item.CreationDate = Util.UnixTimeSinceEpoch();
449 item.Description = asset.Description;
450 item.Name = asset.Name;
451 item.AssetType = asset.Type;
452  
453 m_Scene.AddInventoryItem(item);
454  
455 if (remoteClient != null && item.Owner == remoteClient.AgentId)
456 {
457 remoteClient.SendInventoryItemCreateUpdate(item, 0);
458 }
459 else
460 {
461 ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner);
462 if (notifyUser != null)
463 {
464 notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
465 }
466 }
467 }
468  
469 // This is a hook to do some per-asset post-processing for subclasses that need that
470 if (remoteClient != null)
471 ExportAsset(remoteClient.AgentId, asset.FullID);
472  
473 return item;
474 }
475  
476 protected virtual void ExportAsset(UUID agentID, UUID assetID)
477 {
478 // nothing to do here
479 }
480  
481 /// <summary>
482 /// Add relevant permissions for an object to the item.
483 /// </summary>
484 /// <param name="item"></param>
485 /// <param name="so"></param>
486 /// <param name="objsForEffectivePermissions"></param>
487 /// <param name="remoteClient"></param>
488 /// <returns></returns>
489 protected InventoryItemBase AddPermissions(
490 InventoryItemBase item, SceneObjectGroup so, List<SceneObjectGroup> objsForEffectivePermissions,
491 IClientAPI remoteClient)
492 {
493 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move | PermissionMask.Export) | 7;
494 foreach (SceneObjectGroup grp in objsForEffectivePermissions)
495 effectivePerms &= grp.GetEffectivePermissions();
496 effectivePerms |= (uint)PermissionMask.Move;
497  
498 if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions())
499 {
500 uint perms = effectivePerms;
501 uint nextPerms = (perms & 7) << 13;
502 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
503 perms &= ~(uint)PermissionMask.Copy;
504 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
505 perms &= ~(uint)PermissionMask.Transfer;
506 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
507 perms &= ~(uint)PermissionMask.Modify;
508  
509 item.BasePermissions = perms & so.RootPart.NextOwnerMask;
510 item.CurrentPermissions = item.BasePermissions;
511 item.NextPermissions = perms & so.RootPart.NextOwnerMask;
512 item.EveryOnePermissions = so.RootPart.EveryoneMask & so.RootPart.NextOwnerMask;
513 item.GroupPermissions = so.RootPart.GroupMask & so.RootPart.NextOwnerMask;
514  
515 // Magic number badness. Maybe this deserves an enum.
516 // bit 4 (16) is the "Slam" bit, it means treat as passed
517 // and apply next owner perms on rez
518 item.CurrentPermissions |= 16; // Slam!
519 }
520 else
521 {
522 item.BasePermissions = effectivePerms;
523 item.CurrentPermissions = effectivePerms;
524 item.NextPermissions = so.RootPart.NextOwnerMask & effectivePerms;
525 item.EveryOnePermissions = so.RootPart.EveryoneMask & effectivePerms;
526 item.GroupPermissions = so.RootPart.GroupMask & effectivePerms;
527  
528 item.CurrentPermissions &=
529 ((uint)PermissionMask.Copy |
530 (uint)PermissionMask.Transfer |
531 (uint)PermissionMask.Modify |
532 (uint)PermissionMask.Move |
533 (uint)PermissionMask.Export |
534 7); // Preserve folded permissions
535 }
536  
537 return item;
538 }
539  
540 /// <summary>
541 /// Create an item using details for the given scene object.
542 /// </summary>
543 /// <param name="action"></param>
544 /// <param name="remoteClient"></param>
545 /// <param name="so"></param>
546 /// <param name="folderID"></param>
547 /// <returns></returns>
548 protected InventoryItemBase CreateItemForObject(
549 DeRezAction action, IClientAPI remoteClient, SceneObjectGroup so, UUID folderID)
550 {
551 // Get the user info of the item destination
552 //
553 UUID userID = UUID.Zero;
554  
555 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy ||
556 action == DeRezAction.SaveToExistingUserInventoryItem)
557 {
558 // Take or take copy require a taker
559 // Saving changes requires a local user
560 //
561 if (remoteClient == null)
562 return null;
563  
564 userID = remoteClient.AgentId;
565  
566 // m_log.DebugFormat(
567 // "[INVENTORY ACCESS MODULE]: Target of {0} in CreateItemForObject() is {1} {2}",
568 // action, remoteClient.Name, userID);
569 }
570 else if (so.RootPart.OwnerID == so.RootPart.GroupID)
571 {
572 // Group owned objects go to the last owner before the object was transferred.
573 userID = so.RootPart.LastOwnerID;
574 }
575 else
576 {
577 // Other returns / deletes go to the object owner
578 //
579 userID = so.RootPart.OwnerID;
580  
581 // m_log.DebugFormat(
582 // "[INVENTORY ACCESS MODULE]: Target of {0} in CreateItemForObject() is object owner {1}",
583 // action, userID);
584 }
585  
586 if (userID == UUID.Zero) // Can't proceed
587 {
588 return null;
589 }
590  
591 // If we're returning someone's item, it goes back to the
592 // owner's Lost And Found folder.
593 // Delete is treated like return in this case
594 // Deleting your own items makes them go to trash
595 //
596  
597 InventoryFolderBase folder = null;
598 InventoryItemBase item = null;
599  
600 if (DeRezAction.SaveToExistingUserInventoryItem == action)
601 {
602 item = new InventoryItemBase(so.RootPart.FromUserInventoryItemID, userID);
603 item = m_Scene.InventoryService.GetItem(item);
604  
605 //item = userInfo.RootFolder.FindItem(
606 // objectGroup.RootPart.FromUserInventoryItemID);
607  
608 if (null == item)
609 {
610 m_log.DebugFormat(
611 "[INVENTORY ACCESS MODULE]: Object {0} {1} scheduled for save to inventory has already been deleted.",
612 so.Name, so.UUID);
613  
614 return null;
615 }
616 }
617 else
618 {
619 // Folder magic
620 //
621 if (action == DeRezAction.Delete)
622 {
623 // Deleting someone else's item
624 //
625 if (remoteClient == null ||
626 so.OwnerID != remoteClient.AgentId)
627 {
628 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
629 }
630 else
631 {
632 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
633 }
634 }
635 else if (action == DeRezAction.Return)
636 {
637 // Dump to lost + found unconditionally
638 //
639 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
640 }
641  
642 if (folderID == UUID.Zero && folder == null)
643 {
644 if (action == DeRezAction.Delete)
645 {
646 // Deletes go to trash by default
647 //
648 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
649 }
650 else
651 {
652 if (remoteClient == null || so.RootPart.OwnerID != remoteClient.AgentId)
653 {
654 // Taking copy of another person's item. Take to
655 // Objects folder.
656 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
657 so.FromFolderID = UUID.Zero;
658 }
659 else
660 {
661 // Catch all. Use lost & found
662 //
663 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
664 }
665 }
666 }
667  
668 // Override and put into where it came from, if it came
669 // from anywhere in inventory and the owner is taking it back.
670 //
671 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy)
672 {
673 if (so.FromFolderID != UUID.Zero && so.RootPart.OwnerID == remoteClient.AgentId)
674 {
675 InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID);
676 folder = m_Scene.InventoryService.GetFolder(f);
677  
678 if(folder.Type == 14 || folder.Type == 16)
679 {
680 // folder.Type = 6;
681 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
682 }
683 }
684 }
685  
686 if (folder == null) // None of the above
687 {
688 folder = new InventoryFolderBase(folderID);
689  
690 if (folder == null) // Nowhere to put it
691 {
692 return null;
693 }
694 }
695  
696 item = new InventoryItemBase();
697 item.ID = UUID.Random();
698 item.InvType = (int)InventoryType.Object;
699 item.Folder = folder.ID;
700 item.Owner = userID;
701 }
702  
703 return item;
704 }
705  
706 public virtual SceneObjectGroup RezObject(
707 IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart,
708 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
709 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
710 {
711 // m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID);
712  
713 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
714 item = m_Scene.InventoryService.GetItem(item);
715  
716 if (item == null)
717 {
718 m_log.WarnFormat(
719 "[INVENTORY ACCESS MODULE]: Could not find item {0} for {1} in RezObject()",
720 itemID, remoteClient.Name);
721  
722 return null;
723 }
724  
725 item.Owner = remoteClient.AgentId;
726  
727 return RezObject(
728 remoteClient, item, item.AssetID,
729 RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
730 RezSelected, RemoveItem, fromTaskID, attachment);
731 }
732  
733 public virtual SceneObjectGroup RezObject(
734 IClientAPI remoteClient, InventoryItemBase item, UUID assetID, Vector3 RayEnd, Vector3 RayStart,
735 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
736 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
737 {
738 AssetBase rezAsset = m_Scene.AssetService.Get(assetID.ToString());
739  
740 if (rezAsset == null)
741 {
742 if (item != null)
743 {
744 m_log.WarnFormat(
745 "[InventoryAccessModule]: Could not find asset {0} for item {1} {2} for {3} in RezObject()",
746 assetID, item.Name, item.ID, remoteClient.Name);
747 }
748 else
749 {
750 m_log.WarnFormat(
751 "[INVENTORY ACCESS MODULE]: Could not find asset {0} for {1} in RezObject()",
752 assetID, remoteClient.Name);
753 }
754  
755 return null;
756 }
757  
758 SceneObjectGroup group = null;
759  
760 string xmlData = Utils.BytesToString(rezAsset.Data);
761 List<SceneObjectGroup> objlist = new List<SceneObjectGroup>();
762 List<Vector3> veclist = new List<Vector3>();
763 byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0);
764 Vector3 pos;
765  
766 XmlDocument doc = new XmlDocument();
767 doc.LoadXml(xmlData);
768 XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject");
769 if (e == null || attachment) // Single
770 {
771 SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
772  
773 objlist.Add(g);
774 veclist.Add(Vector3.Zero);
775  
776 float offsetHeight = 0;
777 pos = m_Scene.GetNewRezLocation(
778 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
779 BypassRayCast, bRayEndIsIntersection, true, g.GetAxisAlignedBoundingBox(out offsetHeight), false);
780 pos.Z += offsetHeight;
781 }
782 else
783 {
784 XmlElement coll = (XmlElement)e;
785 float bx = Convert.ToSingle(coll.GetAttribute("x"));
786 float by = Convert.ToSingle(coll.GetAttribute("y"));
787 float bz = Convert.ToSingle(coll.GetAttribute("z"));
788 Vector3 bbox = new Vector3(bx, by, bz);
789  
790 pos = m_Scene.GetNewRezLocation(RayStart, RayEnd,
791 RayTargetID, Quaternion.Identity,
792 BypassRayCast, bRayEndIsIntersection, true,
793 bbox, false);
794  
795 pos -= bbox / 2;
796  
797 XmlNodeList groups = e.SelectNodes("SceneObjectGroup");
798 foreach (XmlNode n in groups)
799 {
800 SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml);
801  
802 objlist.Add(g);
803 XmlElement el = (XmlElement)n;
804  
805 string rawX = el.GetAttribute("offsetx");
806 string rawY = el.GetAttribute("offsety");
807 string rawZ = el.GetAttribute("offsetz");
808 //
809 // m_log.DebugFormat(
810 // "[INVENTORY ACCESS MODULE]: Converting coalesced object {0} offset <{1}, {2}, {3}>",
811 // g.Name, rawX, rawY, rawZ);
812  
813 float x = Convert.ToSingle(rawX);
814 float y = Convert.ToSingle(rawY);
815 float z = Convert.ToSingle(rawZ);
816 veclist.Add(new Vector3(x, y, z));
817 }
818 }
819  
820 if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, veclist, attachment))
821 return null;
822  
823 for (int i = 0; i < objlist.Count; i++)
824 {
825 group = objlist[i];
826  
827 // m_log.DebugFormat(
828 // "[INVENTORY ACCESS MODULE]: Preparing to rez {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}",
829 // group.Name, group.LocalId, group.UUID,
830 // group.RootPart.OwnerMask, group.RootPart.NextOwnerMask, group.RootPart.GroupMask, group.RootPart.EveryoneMask,
831 // remoteClient.Name);
832  
833 // Vector3 storedPosition = group.AbsolutePosition;
834 if (group.UUID == UUID.Zero)
835 {
836 m_log.Debug("[INVENTORY ACCESS MODULE]: Object has UUID.Zero! Position 3");
837 }
838  
839 foreach (SceneObjectPart part in group.Parts)
840 {
841 // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset.
842 part.LastOwnerID = part.OwnerID;
843 part.OwnerID = remoteClient.AgentId;
844 }
845  
846 if (!attachment)
847 {
848 // If it's rezzed in world, select it. Much easier to
849 // find small items.
850 //
851 foreach (SceneObjectPart part in group.Parts)
852 {
853 part.CreateSelected = true;
854 }
855 }
856  
857 group.ResetIDs();
858  
859 if (attachment)
860 {
861 group.RootPart.Flags |= PrimFlags.Phantom;
862 group.IsAttachment = true;
863 }
864  
865 // If we're rezzing an attachment then don't ask
866 // AddNewSceneObject() to update the client since
867 // we'll be doing that later on. Scheduling more than
868 // one full update during the attachment
869 // process causes some clients to fail to display the
870 // attachment properly.
871 m_Scene.AddNewSceneObject(group, true, false);
872  
873 // if attachment we set it's asset id so object updates
874 // can reflect that, if not, we set it's position in world.
875 if (!attachment)
876 {
877 group.ScheduleGroupForFullUpdate();
878  
879 group.AbsolutePosition = pos + veclist[i];
880 }
881  
882 group.SetGroup(remoteClient.ActiveGroupId, remoteClient);
883  
884 if (!attachment)
885 {
886 SceneObjectPart rootPart = group.RootPart;
887  
888 if (rootPart.Shape.PCode == (byte)PCode.Prim)
889 group.ClearPartAttachmentData();
890  
891 // Fire on_rez
892 group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1);
893 rootPart.ParentGroup.ResumeScripts();
894  
895 rootPart.ScheduleFullUpdate();
896 }
897  
898 // m_log.DebugFormat(
899 // "[INVENTORY ACCESS MODULE]: Rezzed {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}",
900 // group.Name, group.LocalId, group.UUID,
901 // group.RootPart.OwnerMask, group.RootPart.NextOwnerMask, group.RootPart.GroupMask, group.RootPart.EveryoneMask,
902 // remoteClient.Name);
903 }
904  
905 if (item != null)
906 DoPostRezWhenFromItem(item, attachment);
907  
908 return group;
909 }
910  
911 /// <summary>
912 /// Do pre-rez processing when the object comes from an item.
913 /// </summary>
914 /// <param name="remoteClient"></param>
915 /// <param name="item"></param>
916 /// <param name="objlist"></param>
917 /// <param name="pos"></param>
918 /// <param name="veclist">
919 /// List of vector position adjustments for a coalesced objects. For ordinary objects
920 /// this list will contain just Vector3.Zero. The order of adjustments must match the order of objlist
921 /// </param>
922 /// <param name="isAttachment"></param>
923 /// <returns>true if we can processed with rezzing, false if we need to abort</returns>
924 private bool DoPreRezWhenFromItem(
925 IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist,
926 Vector3 pos, List<Vector3> veclist, bool isAttachment)
927 {
928 UUID fromUserInventoryItemId = UUID.Zero;
929  
930 // If we have permission to copy then link the rezzed object back to the user inventory
931 // item that it came from. This allows us to enable 'save object to inventory'
932 if (!m_Scene.Permissions.BypassPermissions())
933 {
934 if ((item.CurrentPermissions & (uint)PermissionMask.Copy)
935 == (uint)PermissionMask.Copy && (item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
936 {
937 fromUserInventoryItemId = item.ID;
938 }
939 }
940 else
941 {
942 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
943 {
944 // Brave new fullperm world
945 fromUserInventoryItemId = item.ID;
946 }
947 }
948  
949 for (int i = 0; i < objlist.Count; i++)
950 {
951 SceneObjectGroup g = objlist[i];
952  
953 if (!m_Scene.Permissions.CanRezObject(
954 g.PrimCount, remoteClient.AgentId, pos + veclist[i])
955 && !isAttachment)
956 {
957 // The client operates in no fail mode. It will
958 // have already removed the item from the folder
959 // if it's no copy.
960 // Put it back if it's not an attachment
961 //
962 if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment))
963 remoteClient.SendBulkUpdateInventory(item);
964  
965 ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y);
966 remoteClient.SendAlertMessage(string.Format(
967 "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.",
968 item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.Name));
969  
970 return false;
971 }
972 }
973  
974 for (int i = 0; i < objlist.Count; i++)
975 {
976 SceneObjectGroup so = objlist[i];
977 SceneObjectPart rootPart = so.RootPart;
978  
979 // Since renaming the item in the inventory does not
980 // affect the name stored in the serialization, transfer
981 // the correct name from the inventory to the
982 // object itself before we rez.
983 //
984 // Only do these for the first object if we are rezzing a coalescence.
985 if (i == 0)
986 {
987 rootPart.Name = item.Name;
988 rootPart.Description = item.Description;
989 rootPart.ObjectSaleType = item.SaleType;
990 rootPart.SalePrice = item.SalePrice;
991 }
992  
993 so.FromFolderID = item.Folder;
994  
995 // m_log.DebugFormat(
996 // "[INVENTORY ACCESS MODULE]: rootPart.OwnedID {0}, item.Owner {1}, item.CurrentPermissions {2:X}",
997 // rootPart.OwnerID, item.Owner, item.CurrentPermissions);
998  
999 if ((rootPart.OwnerID != item.Owner) ||
1000 (item.CurrentPermissions & 16) != 0)
1001 {
1002 //Need to kill the for sale here
1003 rootPart.ObjectSaleType = 0;
1004 rootPart.SalePrice = 10;
1005  
1006 if (m_Scene.Permissions.PropagatePermissions())
1007 {
1008 foreach (SceneObjectPart part in so.Parts)
1009 {
1010 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
1011 {
1012 part.EveryoneMask = item.EveryOnePermissions;
1013 part.NextOwnerMask = item.NextPermissions;
1014 }
1015 part.GroupMask = 0; // DO NOT propagate here
1016 }
1017  
1018 so.ApplyNextOwnerPermissions();
1019 }
1020 }
1021  
1022 foreach (SceneObjectPart part in so.Parts)
1023 {
1024 part.FromUserInventoryItemID = fromUserInventoryItemId;
1025  
1026 if ((part.OwnerID != item.Owner) ||
1027 (item.CurrentPermissions & 16) != 0)
1028 {
1029 part.Inventory.ChangeInventoryOwner(item.Owner);
1030 part.GroupMask = 0; // DO NOT propagate here
1031 }
1032  
1033 part.EveryoneMask = item.EveryOnePermissions;
1034 part.NextOwnerMask = item.NextPermissions;
1035 }
1036  
1037 rootPart.TrimPermissions();
1038  
1039 if (isAttachment)
1040 so.FromItemID = item.ID;
1041 }
1042  
1043 return true;
1044 }
1045  
1046 /// <summary>
1047 /// Do post-rez processing when the object comes from an item.
1048 /// </summary>
1049 /// <param name="item"></param>
1050 /// <param name="isAttachment"></param>
1051 private void DoPostRezWhenFromItem(InventoryItemBase item, bool isAttachment)
1052 {
1053 if (!m_Scene.Permissions.BypassPermissions())
1054 {
1055 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1056 {
1057 // If this is done on attachments, no
1058 // copy ones will be lost, so avoid it
1059 //
1060 if (!isAttachment)
1061 {
1062 List<UUID> uuids = new List<UUID>();
1063 uuids.Add(item.ID);
1064 m_Scene.InventoryService.DeleteItems(item.Owner, uuids);
1065 }
1066 }
1067 }
1068 }
1069  
1070 protected void AddUserData(SceneObjectGroup sog)
1071 {
1072 UserManagementModule.AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData);
1073 foreach (SceneObjectPart sop in sog.Parts)
1074 UserManagementModule.AddUser(sop.CreatorID, sop.CreatorData);
1075 }
1076  
1077 public virtual void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver)
1078 {
1079 }
1080  
1081 public virtual bool CanGetAgentInventoryItem(IClientAPI remoteClient, UUID itemID, UUID requestID)
1082 {
1083 InventoryItemBase assetRequestItem = GetItem(remoteClient.AgentId, itemID);
1084  
1085 if (assetRequestItem == null)
1086 {
1087 ILibraryService lib = m_Scene.RequestModuleInterface<ILibraryService>();
1088  
1089 if (lib != null)
1090 assetRequestItem = lib.LibraryRootFolder.FindItem(itemID);
1091  
1092 if (assetRequestItem == null)
1093 return false;
1094 }
1095  
1096 // At this point, we need to apply perms
1097 // only to notecards and scripts. All
1098 // other asset types are always available
1099 //
1100 if (assetRequestItem.AssetType == (int)AssetType.LSLText)
1101 {
1102 if (!m_Scene.Permissions.CanViewScript(itemID, UUID.Zero, remoteClient.AgentId))
1103 {
1104 remoteClient.SendAgentAlertMessage("Insufficient permissions to view script", false);
1105 return false;
1106 }
1107 }
1108 else if (assetRequestItem.AssetType == (int)AssetType.Notecard)
1109 {
1110 if (!m_Scene.Permissions.CanViewNotecard(itemID, UUID.Zero, remoteClient.AgentId))
1111 {
1112 remoteClient.SendAgentAlertMessage("Insufficient permissions to view notecard", false);
1113 return false;
1114 }
1115 }
1116  
1117 if (assetRequestItem.AssetID != requestID)
1118 {
1119 m_log.WarnFormat(
1120 "[INVENTORY ACCESS MODULE]: {0} requested asset {1} from item {2} but this does not match item's asset {3}",
1121 Name, requestID, itemID, assetRequestItem.AssetID);
1122  
1123 return false;
1124 }
1125  
1126 return true;
1127 }
1128  
1129  
1130 public virtual bool IsForeignUser(UUID userID, out string assetServerURL)
1131 {
1132 assetServerURL = string.Empty;
1133 return false;
1134 }
1135  
1136 #endregion
1137  
1138 #region Misc
1139  
1140 /// <summary>
1141 /// Create a new asset data structure.
1142 /// </summary>
1143 /// <param name="name"></param>
1144 /// <param name="description"></param>
1145 /// <param name="invType"></param>
1146 /// <param name="assetType"></param>
1147 /// <param name="data"></param>
1148 /// <returns></returns>
1149 private AssetBase CreateAsset(string name, string description, sbyte assetType, byte[] data, string creatorID)
1150 {
1151 AssetBase asset = new AssetBase(UUID.Random(), name, assetType, creatorID);
1152 asset.Description = description;
1153 asset.Data = (data == null) ? new byte[1] : data;
1154  
1155 return asset;
1156 }
1157  
1158 protected virtual InventoryItemBase GetItem(UUID agentID, UUID itemID)
1159 {
1160 IInventoryService invService = m_Scene.RequestModuleInterface<IInventoryService>();
1161 InventoryItemBase item = new InventoryItemBase(itemID, agentID);
1162 item = invService.GetItem(item);
1163  
1164 if (item != null && item.CreatorData != null && item.CreatorData != string.Empty)
1165 UserManagementModule.AddUser(item.CreatorIdAsUuid, item.CreatorData);
1166  
1167 return item;
1168 }
1169  
1170 #endregion
1171 }
1172 }