aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs')
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs655
1 files changed, 655 insertions, 0 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
new file mode 100644
index 0000000..e0df288
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -0,0 +1,655 @@
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
28using System;
29using System.Collections.Generic;
30using System.Net;
31using System.Reflection;
32using System.Threading;
33
34using OpenSim.Framework;
35using OpenSim.Framework.Capabilities;
36using OpenSim.Framework.Client;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Region.Framework.Scenes.Serialization;
40using OpenSim.Services.Interfaces;
41
42using GridRegion = OpenSim.Services.Interfaces.GridRegion;
43
44using OpenMetaverse;
45using log4net;
46using Nini.Config;
47
48namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
49{
50 public class BasicInventoryAccessModule : INonSharedRegionModule, IInventoryAccessModule
51 {
52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 protected bool m_Enabled = false;
55 protected Scene m_Scene;
56
57 #region INonSharedRegionModule
58
59 public Type ReplaceableInterface
60 {
61 get { return null; }
62 }
63
64 public virtual string Name
65 {
66 get { return "BasicInventoryAccessModule"; }
67 }
68
69 public virtual void Initialise(IConfigSource source)
70 {
71 IConfig moduleConfig = source.Configs["Modules"];
72 if (moduleConfig != null)
73 {
74 string name = moduleConfig.GetString("InventoryAccessModule", "");
75 if (name == Name)
76 {
77 m_Enabled = true;
78 m_log.InfoFormat("[INVENTORY ACCESS MODULE]: {0} enabled.", Name);
79 }
80 }
81 }
82
83 public virtual void PostInitialise()
84 {
85 }
86
87 public virtual void AddRegion(Scene scene)
88 {
89 if (!m_Enabled)
90 return;
91
92 m_Scene = scene;
93
94 scene.RegisterModuleInterface<IInventoryAccessModule>(this);
95 scene.EventManager.OnNewClient += OnNewClient;
96 }
97
98 protected virtual void OnNewClient(IClientAPI client)
99 {
100
101 }
102
103 public virtual void Close()
104 {
105 if (!m_Enabled)
106 return;
107 }
108
109
110 public virtual void RemoveRegion(Scene scene)
111 {
112 if (!m_Enabled)
113 return;
114 m_Scene = null;
115 }
116
117 public virtual void RegionLoaded(Scene scene)
118 {
119 if (!m_Enabled)
120 return;
121
122 }
123
124 #endregion
125
126 #region Inventory Access
127
128 /// <summary>
129 /// Capability originating call to update the asset of an item in an agent's inventory
130 /// </summary>
131 /// <param name="remoteClient"></param>
132 /// <param name="itemID"></param>
133 /// <param name="data"></param>
134 /// <returns></returns>
135 public virtual UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data)
136 {
137 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
138 item = m_Scene.InventoryService.GetItem(item);
139
140 if (item != null)
141 {
142 if ((InventoryType)item.InvType == InventoryType.Notecard)
143 {
144 if (!m_Scene.Permissions.CanEditNotecard(itemID, UUID.Zero, remoteClient.AgentId))
145 {
146 remoteClient.SendAgentAlertMessage("Insufficient permissions to edit notecard", false);
147 return UUID.Zero;
148 }
149
150 remoteClient.SendAgentAlertMessage("Notecard saved", false);
151 }
152 else if ((InventoryType)item.InvType == InventoryType.LSL)
153 {
154 if (!m_Scene.Permissions.CanEditScript(itemID, UUID.Zero, remoteClient.AgentId))
155 {
156 remoteClient.SendAgentAlertMessage("Insufficient permissions to edit script", false);
157 return UUID.Zero;
158 }
159
160 remoteClient.SendAgentAlertMessage("Script saved", false);
161 }
162
163 AssetBase asset =
164 CreateAsset(item.Name, item.Description, (sbyte)item.AssetType, data, remoteClient.AgentId.ToString());
165 item.AssetID = asset.FullID;
166 m_Scene.AssetService.Store(asset);
167
168 m_Scene.InventoryService.UpdateItem(item);
169
170 // remoteClient.SendInventoryItemCreateUpdate(item);
171 return (asset.FullID);
172 }
173 else
174 {
175 m_log.ErrorFormat(
176 "[AGENT INVENTORY]: Could not find item {0} for caps inventory update",
177 itemID);
178 }
179
180 return UUID.Zero;
181 }
182
183 /// <summary>
184 /// Delete a scene object from a scene and place in the given avatar's inventory.
185 /// Returns the UUID of the newly created asset.
186 /// </summary>
187 /// <param name="action"></param>
188 /// <param name="folderID"></param>
189 /// <param name="objectGroup"></param>
190 /// <param name="remoteClient"> </param>
191 public virtual UUID DeleteToInventory(DeRezAction action, UUID folderID,
192 SceneObjectGroup objectGroup, IClientAPI remoteClient)
193 {
194 UUID assetID = UUID.Zero;
195
196 Vector3 inventoryStoredPosition = new Vector3
197 (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
198 ? 250
199 : objectGroup.AbsolutePosition.X)
200 ,
201 (objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
202 ? 250
203 : objectGroup.AbsolutePosition.X,
204 objectGroup.AbsolutePosition.Z);
205
206 Vector3 originalPosition = objectGroup.AbsolutePosition;
207
208 objectGroup.AbsolutePosition = inventoryStoredPosition;
209
210 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(objectGroup);
211
212 objectGroup.AbsolutePosition = originalPosition;
213
214 // Get the user info of the item destination
215 //
216 UUID userID = UUID.Zero;
217
218 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy ||
219 action == DeRezAction.SaveToExistingUserInventoryItem)
220 {
221 // Take or take copy require a taker
222 // Saving changes requires a local user
223 //
224 if (remoteClient == null)
225 return UUID.Zero;
226
227 userID = remoteClient.AgentId;
228 }
229 else
230 {
231 // All returns / deletes go to the object owner
232 //
233
234 userID = objectGroup.RootPart.OwnerID;
235 }
236
237 if (userID == UUID.Zero) // Can't proceed
238 {
239 return UUID.Zero;
240 }
241
242 // If we're returning someone's item, it goes back to the
243 // owner's Lost And Found folder.
244 // Delete is treated like return in this case
245 // Deleting your own items makes them go to trash
246 //
247
248 InventoryFolderBase folder = null;
249 InventoryItemBase item = null;
250
251 if (DeRezAction.SaveToExistingUserInventoryItem == action)
252 {
253 item = new InventoryItemBase(objectGroup.RootPart.FromUserInventoryItemID, userID);
254 item = m_Scene.InventoryService.GetItem(item);
255
256 //item = userInfo.RootFolder.FindItem(
257 // objectGroup.RootPart.FromUserInventoryItemID);
258
259 if (null == item)
260 {
261 m_log.DebugFormat(
262 "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.",
263 objectGroup.Name, objectGroup.UUID);
264 return UUID.Zero;
265 }
266 }
267 else
268 {
269 // Folder magic
270 //
271 if (action == DeRezAction.Delete)
272 {
273 // Deleting someone else's item
274 //
275
276
277 if (remoteClient == null ||
278 objectGroup.OwnerID != remoteClient.AgentId)
279 {
280 // Folder skeleton may not be loaded and we
281 // have to wait for the inventory to find
282 // the destination folder
283 //
284 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
285 }
286 else
287 {
288 // Assume inventory skeleton was loaded during login
289 // and all folders can be found
290 //
291 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
292 }
293 }
294 else if (action == DeRezAction.Return)
295 {
296
297 // Dump to lost + found unconditionally
298 //
299 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
300 }
301
302 if (folderID == UUID.Zero && folder == null)
303 {
304 if (action == DeRezAction.Delete)
305 {
306 // Deletes go to trash by default
307 //
308 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
309 }
310 else
311 {
312 // Catch all. Use lost & found
313 //
314
315 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
316 }
317 }
318
319 if (folder == null) // None of the above
320 {
321 //folder = userInfo.RootFolder.FindFolder(folderID);
322 folder = new InventoryFolderBase(folderID);
323
324 if (folder == null) // Nowhere to put it
325 {
326 return UUID.Zero;
327 }
328 }
329
330 item = new InventoryItemBase();
331 item.CreatorId = objectGroup.RootPart.CreatorID.ToString();
332 item.ID = UUID.Random();
333 item.InvType = (int)InventoryType.Object;
334 item.Folder = folder.ID;
335 item.Owner = userID;
336 }
337
338 AssetBase asset = CreateAsset(
339 objectGroup.GetPartName(objectGroup.RootPart.LocalId),
340 objectGroup.GetPartDescription(objectGroup.RootPart.LocalId),
341 (sbyte)AssetType.Object,
342 Utils.StringToBytes(sceneObjectXml),
343 objectGroup.OwnerID.ToString());
344 m_Scene.AssetService.Store(asset);
345 assetID = asset.FullID;
346
347 if (DeRezAction.SaveToExistingUserInventoryItem == action)
348 {
349 item.AssetID = asset.FullID;
350 m_Scene.InventoryService.UpdateItem(item);
351 }
352 else
353 {
354 item.AssetID = asset.FullID;
355
356 if (remoteClient != null && (remoteClient.AgentId != objectGroup.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions())
357 {
358 uint perms = objectGroup.GetEffectivePermissions();
359 uint nextPerms = (perms & 7) << 13;
360 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
361 perms &= ~(uint)PermissionMask.Copy;
362 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
363 perms &= ~(uint)PermissionMask.Transfer;
364 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
365 perms &= ~(uint)PermissionMask.Modify;
366
367 item.BasePermissions = perms & objectGroup.RootPart.NextOwnerMask;
368 item.CurrentPermissions = item.BasePermissions;
369 item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
370 item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask & objectGroup.RootPart.NextOwnerMask;
371 item.GroupPermissions = objectGroup.RootPart.GroupMask & objectGroup.RootPart.NextOwnerMask;
372 item.CurrentPermissions |= 8; // Slam!
373 }
374 else
375 {
376 item.BasePermissions = objectGroup.GetEffectivePermissions();
377 item.CurrentPermissions = objectGroup.GetEffectivePermissions();
378 item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
379 item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask;
380 item.GroupPermissions = objectGroup.RootPart.GroupMask;
381
382 item.CurrentPermissions |= 8; // Slam!
383 }
384
385 // TODO: add the new fields (Flags, Sale info, etc)
386 item.CreationDate = Util.UnixTimeSinceEpoch();
387 item.Description = asset.Description;
388 item.Name = asset.Name;
389 item.AssetType = asset.Type;
390
391 m_Scene.InventoryService.AddItem(item);
392
393 if (remoteClient != null && item.Owner == remoteClient.AgentId)
394 {
395 remoteClient.SendInventoryItemCreateUpdate(item, 0);
396 }
397 else
398 {
399 ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner);
400 if (notifyUser != null)
401 {
402 notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
403 }
404 }
405 }
406
407 return assetID;
408 }
409
410
411 /// <summary>
412 /// Rez an object into the scene from the user's inventory
413 /// </summary>
414 /// <param name="remoteClient"></param>
415 /// <param name="itemID"></param>
416 /// <param name="RayEnd"></param>
417 /// <param name="RayStart"></param>
418 /// <param name="RayTargetID"></param>
419 /// <param name="BypassRayCast"></param>
420 /// <param name="RayEndIsIntersection"></param>
421 /// <param name="RezSelected"></param>
422 /// <param name="RemoveItem"></param>
423 /// <param name="fromTaskID"></param>
424 /// <param name="attachment"></param>
425 /// <returns>The SceneObjectGroup rezzed or null if rez was unsuccessful.</returns>
426 public virtual SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart,
427 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
428 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
429 {
430 // Work out position details
431 byte bRayEndIsIntersection = (byte)0;
432
433 if (RayEndIsIntersection)
434 {
435 bRayEndIsIntersection = (byte)1;
436 }
437 else
438 {
439 bRayEndIsIntersection = (byte)0;
440 }
441
442 Vector3 scale = new Vector3(0.5f, 0.5f, 0.5f);
443
444
445 Vector3 pos = m_Scene.GetNewRezLocation(
446 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
447 BypassRayCast, bRayEndIsIntersection, true, scale, false);
448
449 // Rez object
450 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
451 item = m_Scene.InventoryService.GetItem(item);
452
453 if (item != null)
454 {
455 AssetBase rezAsset = m_Scene.AssetService.Get(item.AssetID.ToString());
456
457 if (rezAsset != null)
458 {
459 UUID itemId = UUID.Zero;
460
461 // If we have permission to copy then link the rezzed object back to the user inventory
462 // item that it came from. This allows us to enable 'save object to inventory'
463 if (!m_Scene.Permissions.BypassPermissions())
464 {
465 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == (uint)PermissionMask.Copy)
466 {
467 itemId = item.ID;
468 }
469 }
470 else
471 {
472 // Brave new fullperm world
473 //
474 itemId = item.ID;
475 }
476
477 string xmlData = Utils.BytesToString(rezAsset.Data);
478 SceneObjectGroup group
479 = SceneObjectSerializer.FromOriginalXmlFormat(itemId, xmlData);
480
481 if (!m_Scene.Permissions.CanRezObject(
482 group.Children.Count, remoteClient.AgentId, pos)
483 && !attachment)
484 {
485 // The client operates in no fail mode. It will
486 // have already removed the item from the folder
487 // if it's no copy.
488 // Put it back if it's not an attachment
489 //
490 if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!attachment))
491 remoteClient.SendBulkUpdateInventory(item);
492 return null;
493 }
494
495 group.ResetIDs();
496
497 if (attachment)
498 {
499 group.RootPart.ObjectFlags |= (uint)PrimFlags.Phantom;
500 group.RootPart.IsAttachment = true;
501 }
502
503 m_Scene.AddNewSceneObject(group, true);
504
505 // m_log.InfoFormat("ray end point for inventory rezz is {0} {1} {2} ", RayEnd.X, RayEnd.Y, RayEnd.Z);
506 // if attachment we set it's asset id so object updates can reflect that
507 // if not, we set it's position in world.
508 if (!attachment)
509 {
510 float offsetHeight = 0;
511 pos = m_Scene.GetNewRezLocation(
512 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
513 BypassRayCast, bRayEndIsIntersection, true, group.GetAxisAlignedBoundingBox(out offsetHeight), false);
514 pos.Z += offsetHeight;
515 group.AbsolutePosition = pos;
516 // m_log.InfoFormat("rezx point for inventory rezz is {0} {1} {2} and offsetheight was {3}", pos.X, pos.Y, pos.Z, offsetHeight);
517
518 }
519 else
520 {
521 group.SetFromItemID(itemID);
522 }
523
524 SceneObjectPart rootPart = null;
525 try
526 {
527 rootPart = group.GetChildPart(group.UUID);
528 }
529 catch (NullReferenceException)
530 {
531 string isAttachment = "";
532
533 if (attachment)
534 isAttachment = " Object was an attachment";
535
536 m_log.Error("[AGENT INVENTORY]: Error rezzing ItemID: " + itemID + " object has no rootpart." + isAttachment);
537 }
538
539 // Since renaming the item in the inventory does not affect the name stored
540 // in the serialization, transfer the correct name from the inventory to the
541 // object itself before we rez.
542 rootPart.Name = item.Name;
543 rootPart.Description = item.Description;
544
545 List<SceneObjectPart> partList = new List<SceneObjectPart>(group.Children.Values);
546
547 group.SetGroup(remoteClient.ActiveGroupId, remoteClient);
548 if (rootPart.OwnerID != item.Owner)
549 {
550 //Need to kill the for sale here
551 rootPart.ObjectSaleType = 0;
552 rootPart.SalePrice = 10;
553
554 if (m_Scene.Permissions.PropagatePermissions())
555 {
556 if ((item.CurrentPermissions & 8) != 0)
557 {
558 foreach (SceneObjectPart part in partList)
559 {
560 part.EveryoneMask = item.EveryOnePermissions;
561 part.NextOwnerMask = item.NextPermissions;
562 part.GroupMask = 0; // DO NOT propagate here
563 }
564 }
565 group.ApplyNextOwnerPermissions();
566 }
567 }
568
569 foreach (SceneObjectPart part in partList)
570 {
571 if (part.OwnerID != item.Owner)
572 {
573 part.LastOwnerID = part.OwnerID;
574 part.OwnerID = item.Owner;
575 part.Inventory.ChangeInventoryOwner(item.Owner);
576 }
577 else if (((item.CurrentPermissions & 8) != 0) && (!attachment)) // Slam!
578 {
579 part.EveryoneMask = item.EveryOnePermissions;
580 part.NextOwnerMask = item.NextPermissions;
581
582 part.GroupMask = 0; // DO NOT propagate here
583 }
584 }
585
586 rootPart.TrimPermissions();
587
588 if (!attachment)
589 {
590 if (group.RootPart.Shape.PCode == (byte)PCode.Prim)
591 {
592 group.ClearPartAttachmentData();
593 }
594 }
595
596 if (!attachment)
597 {
598 // Fire on_rez
599 group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 0);
600
601 rootPart.ScheduleFullUpdate();
602 }
603
604 if (!m_Scene.Permissions.BypassPermissions())
605 {
606 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
607 {
608 // If this is done on attachments, no
609 // copy ones will be lost, so avoid it
610 //
611 if (!attachment)
612 {
613 List<UUID> uuids = new List<UUID>();
614 uuids.Add(item.ID);
615 m_Scene.InventoryService.DeleteItems(item.Owner, uuids);
616 }
617 }
618 }
619
620 return rootPart.ParentGroup;
621 }
622 }
623
624 return null;
625 }
626
627 public virtual void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver)
628 {
629 }
630
631 #endregion
632
633 #region Misc
634
635 /// <summary>
636 /// Create a new asset data structure.
637 /// </summary>
638 /// <param name="name"></param>
639 /// <param name="description"></param>
640 /// <param name="invType"></param>
641 /// <param name="assetType"></param>
642 /// <param name="data"></param>
643 /// <returns></returns>
644 private AssetBase CreateAsset(string name, string description, sbyte assetType, byte[] data, string creatorID)
645 {
646 AssetBase asset = new AssetBase(UUID.Random(), name, assetType, creatorID);
647 asset.Description = description;
648 asset.Data = (data == null) ? new byte[1] : data;
649
650 return asset;
651 }
652
653 #endregion
654 }
655}