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.Collections;
31 using System.Reflection;
32 using System.Text;
33 using System.Timers;
34 using OpenMetaverse;
35 using OpenMetaverse.Packets;
36 using log4net;
37 using OpenSim.Framework;
38 using OpenSim.Region.Framework;
39 using OpenSim.Framework.Client;
40 using OpenSim.Region.Framework.Interfaces;
41 using OpenSim.Region.Framework.Scenes.Serialization;
42 using PermissionMask = OpenSim.Framework.PermissionMask;
43  
44 namespace OpenSim.Region.Framework.Scenes
45 {
46 public partial class Scene
47 {
48 private static readonly ILog m_log
49 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50  
51 /// <summary>
52 /// Allows asynchronous derezzing of objects from the scene into a client's inventory.
53 /// </summary>
54 protected AsyncSceneObjectGroupDeleter m_asyncSceneObjectDeleter;
55  
56 /// <summary>
57 /// Allows inventory details to be sent to clients asynchronously
58 /// </summary>
59 protected AsyncInventorySender m_asyncInventorySender;
60  
61 /// <summary>
62 /// Creates all the scripts in the scene which should be started.
63 /// </summary>
64 /// <returns>
65 /// Number of scripts that were valid for starting. This does not guarantee that all these scripts
66 /// were actually started, but just that the start could be attempt (e.g. the asset data for the script could be found)
67 /// </returns>
68 public int CreateScriptInstances()
69 {
70 m_log.InfoFormat("[SCENE]: Initializing script instances in {0}", RegionInfo.RegionName);
71  
72 int scriptsValidForStarting = 0;
73  
74 EntityBase[] entities = Entities.GetEntities();
75 foreach (EntityBase group in entities)
76 {
77 if (group is SceneObjectGroup)
78 {
79 scriptsValidForStarting
80 += ((SceneObjectGroup) group).CreateScriptInstances(0, false, DefaultScriptEngine, 0);
81 ((SceneObjectGroup) group).ResumeScripts();
82 }
83 }
84  
85 m_log.InfoFormat(
86 "[SCENE]: Initialized {0} script instances in {1}",
87 scriptsValidForStarting, RegionInfo.RegionName);
88  
89 return scriptsValidForStarting;
90 }
91  
92 /// <summary>
93 /// Lets the script engines start processing scripts.
94 /// </summary>
95 public void StartScripts()
96 {
97 // m_log.InfoFormat("[SCENE]: Starting scripts in {0}, please wait.", RegionInfo.RegionName);
98  
99 IScriptModule[] engines = RequestModuleInterfaces<IScriptModule>();
100  
101 foreach (IScriptModule engine in engines)
102 engine.StartProcessing();
103 }
104  
105 public void AddUploadedInventoryItem(UUID agentID, InventoryItemBase item)
106 {
107 IMoneyModule money = RequestModuleInterface<IMoneyModule>();
108 if (money != null)
109 {
110 money.ApplyUploadCharge(agentID, money.UploadCharge, "Asset upload");
111 }
112  
113 AddInventoryItem(item);
114 }
115  
116 public bool AddInventoryItemReturned(UUID AgentId, InventoryItemBase item)
117 {
118 if (AddInventoryItem(item))
119 return true;
120 else
121 {
122 m_log.WarnFormat(
123 "[AGENT INVENTORY]: Unable to add item {1} to agent {2} inventory", item.Name, AgentId);
124  
125 return false;
126 }
127 }
128  
129 /// <summary>
130 /// Add the given inventory item to a user's inventory.
131 /// </summary>
132 /// <param name="item"></param>
133 public bool AddInventoryItem(InventoryItemBase item)
134 {
135 if (item.Folder != UUID.Zero && InventoryService.AddItem(item))
136 {
137 int userlevel = 0;
138 if (Permissions.IsGod(item.Owner))
139 {
140 userlevel = 1;
141 }
142 EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel);
143  
144 return true;
145 }
146  
147 // OK so either the viewer didn't send a folderID or AddItem failed
148 UUID originalFolder = item.Folder;
149 InventoryFolderBase f = InventoryService.GetFolderForType(item.Owner, (AssetType)item.AssetType);
150 if (f != null)
151 {
152 m_log.DebugFormat(
153 "[AGENT INVENTORY]: Found folder {0} type {1} for item {2}",
154 f.Name, (AssetType)f.Type, item.Name);
155  
156 item.Folder = f.ID;
157 }
158 else
159 {
160 f = InventoryService.GetRootFolder(item.Owner);
161 if (f != null)
162 {
163 item.Folder = f.ID;
164 }
165 else
166 {
167 m_log.WarnFormat(
168 "[AGENT INVENTORY]: Could not find root folder for {0} when trying to add item {1} with no parent folder specified",
169 item.Owner, item.Name);
170 return false;
171 }
172 }
173  
174 if (InventoryService.AddItem(item))
175 {
176 int userlevel = 0;
177 if (Permissions.IsGod(item.Owner))
178 {
179 userlevel = 1;
180 }
181 EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel);
182  
183 if (originalFolder != UUID.Zero)
184 {
185 // Tell the viewer that the item didn't go there
186 ChangePlacement(item, f);
187 }
188  
189 return true;
190 }
191 else
192 {
193 m_log.WarnFormat(
194 "[AGENT INVENTORY]: Agent {0} could not add item {1} {2}",
195 item.Owner, item.Name, item.ID);
196  
197 return false;
198 }
199 }
200  
201 private void ChangePlacement(InventoryItemBase item, InventoryFolderBase f)
202 {
203 ScenePresence sp = GetScenePresence(item.Owner);
204 if (sp != null)
205 {
206 if (sp.ControllingClient is IClientCore)
207 {
208 IClientCore core = (IClientCore)sp.ControllingClient;
209 IClientInventory inv;
210  
211 if (core.TryGet<IClientInventory>(out inv))
212 {
213 InventoryFolderBase parent = new InventoryFolderBase(f.ParentID, f.Owner);
214 parent = InventoryService.GetFolder(parent);
215 inv.SendRemoveInventoryItems(new UUID[] { item.ID });
216 inv.SendBulkUpdateInventory(new InventoryFolderBase[0], new InventoryItemBase[] { item });
217 string message = "The item was placed in folder " + f.Name;
218 if (parent != null)
219 message += " under " + parent.Name;
220 sp.ControllingClient.SendAgentAlertMessage(message, false);
221 }
222 }
223 }
224 }
225  
226 /// <summary>
227 /// Add the given inventory item to a user's inventory.
228 /// </summary>
229 /// <param name="AgentID">
230 /// A <see cref="UUID"/>
231 /// </param>
232 /// <param name="item">
233 /// A <see cref="InventoryItemBase"/>
234 /// </param>
235 [Obsolete("Use AddInventoryItem(InventoryItemBase item) instead. This was deprecated in OpenSim 0.7.1")]
236 public void AddInventoryItem(UUID AgentID, InventoryItemBase item)
237 {
238 AddInventoryItem(item);
239 }
240  
241 /// <summary>
242 /// Add an inventory item to an avatar's inventory.
243 /// </summary>
244 /// <param name="remoteClient">The remote client controlling the avatar</param>
245 /// <param name="item">The item. This structure contains all the item metadata, including the folder
246 /// in which the item is to be placed.</param>
247 public void AddInventoryItem(IClientAPI remoteClient, InventoryItemBase item)
248 {
249 AddInventoryItem(item);
250 remoteClient.SendInventoryItemCreateUpdate(item, 0);
251 }
252  
253 /// <summary>
254 /// <see>CapsUpdatedInventoryItemAsset(IClientAPI, UUID, byte[])</see>
255 /// </summary>
256 public UUID CapsUpdateInventoryItemAsset(UUID avatarId, UUID itemID, byte[] data)
257 {
258 ScenePresence avatar;
259  
260 if (TryGetScenePresence(avatarId, out avatar))
261 {
262 IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>();
263 if (invAccess != null)
264 return invAccess.CapsUpdateInventoryItemAsset(avatar.ControllingClient, itemID, data);
265 }
266 else
267 {
268 m_log.ErrorFormat(
269 "[AGENT INVENTORY]: " +
270 "Avatar {0} cannot be found to update its inventory item asset",
271 avatarId);
272 }
273  
274 return UUID.Zero;
275 }
276  
277 /// <summary>
278 /// Capability originating call to update the asset of a script in a prim's (task's) inventory
279 /// </summary>
280 /// <param name="remoteClient"></param>
281 /// <param name="itemID"></param>
282 /// <param name="primID">The prim which contains the item to update</param>
283 /// <param name="isScriptRunning">Indicates whether the script to update is currently running</param>
284 /// <param name="data"></param>
285 public ArrayList CapsUpdateTaskInventoryScriptAsset(IClientAPI remoteClient, UUID itemId,
286 UUID primId, bool isScriptRunning, byte[] data)
287 {
288 if (!Permissions.CanEditScript(itemId, primId, remoteClient.AgentId))
289 {
290 remoteClient.SendAgentAlertMessage("Insufficient permissions to edit script", false);
291 return new ArrayList();
292 }
293  
294 // Retrieve group
295 SceneObjectPart part = GetSceneObjectPart(primId);
296 if (part == null)
297 return new ArrayList();
298  
299 SceneObjectGroup group = part.ParentGroup;
300  
301 // Retrieve item
302 TaskInventoryItem item = group.GetInventoryItem(part.LocalId, itemId);
303  
304 if (null == item)
305 {
306 m_log.ErrorFormat(
307 "[PRIM INVENTORY]: Tried to retrieve item ID {0} from prim {1}, {2} for caps script update "
308 + " but the item does not exist in this inventory",
309 itemId, part.Name, part.UUID);
310  
311 return new ArrayList();
312 }
313  
314 AssetBase asset = CreateAsset(item.Name, item.Description, (sbyte)AssetType.LSLText, data, remoteClient.AgentId);
315 AssetService.Store(asset);
316  
317 // m_log.DebugFormat(
318 // "[PRIM INVENTORY]: Stored asset {0} when updating item {1} in prim {2} for {3}",
319 // asset.ID, item.Name, part.Name, remoteClient.Name);
320  
321 if (isScriptRunning)
322 {
323 part.Inventory.RemoveScriptInstance(item.ItemID, false);
324 }
325  
326 // Update item with new asset
327 item.AssetID = asset.FullID;
328 if (group.UpdateInventoryItem(item))
329 remoteClient.SendAlertMessage("Script saved");
330  
331 part.SendPropertiesToClient(remoteClient);
332  
333 // Trigger rerunning of script (use TriggerRezScript event, see RezScript)
334 ArrayList errors = new ArrayList();
335  
336 if (isScriptRunning)
337 {
338 // Needs to determine which engine was running it and use that
339 //
340 part.Inventory.CreateScriptInstance(item.ItemID, 0, false, DefaultScriptEngine, 0);
341 errors = part.Inventory.GetScriptErrors(item.ItemID);
342 }
343 else
344 {
345 remoteClient.SendAlertMessage("Script saved");
346 }
347  
348 // Tell anyone managing scripts that a script has been reloaded/changed
349 EventManager.TriggerUpdateScript(remoteClient.AgentId, itemId, primId, isScriptRunning, item.AssetID);
350  
351 part.ParentGroup.ResumeScripts();
352 return errors;
353 }
354  
355 /// <summary>
356 /// <see>CapsUpdateTaskInventoryScriptAsset(IClientAPI, UUID, UUID, bool, byte[])</see>
357 /// </summary>
358 public ArrayList CapsUpdateTaskInventoryScriptAsset(UUID avatarId, UUID itemId,
359 UUID primId, bool isScriptRunning, byte[] data)
360 {
361 ScenePresence avatar;
362  
363 if (TryGetScenePresence(avatarId, out avatar))
364 {
365 return CapsUpdateTaskInventoryScriptAsset(
366 avatar.ControllingClient, itemId, primId, isScriptRunning, data);
367 }
368 else
369 {
370 m_log.ErrorFormat(
371 "[PRIM INVENTORY]: " +
372 "Avatar {0} cannot be found to update its prim item asset",
373 avatarId);
374 return new ArrayList();
375 }
376 }
377  
378 /// <summary>
379 /// Update an item which is either already in the client's inventory or is within
380 /// a transaction
381 /// </summary>
382 /// <param name="remoteClient"></param>
383 /// <param name="transactionID">The transaction ID. If this is UUID.Zero we will
384 /// assume that we are not in a transaction</param>
385 /// <param name="itemID">The ID of the updated item</param>
386 /// <param name="name">The name of the updated item</param>
387 /// <param name="description">The description of the updated item</param>
388 /// <param name="nextOwnerMask">The permissions of the updated item</param>
389 /* public void UpdateInventoryItemAsset(IClientAPI remoteClient, UUID transactionID,
390 UUID itemID, string name, string description,
391 uint nextOwnerMask)*/
392 public void UpdateInventoryItemAsset(IClientAPI remoteClient, UUID transactionID,
393 UUID itemID, InventoryItemBase itemUpd)
394 {
395 // m_log.DebugFormat(
396 // "[USER INVENTORY]: Updating asset for item {0} {1}, transaction ID {2} for {3}",
397 // itemID, itemUpd.Name, transactionID, remoteClient.Name);
398  
399 // This one will let people set next perms on items in agent
400 // inventory. Rut-Roh. Whatever. Make this secure. Yeah.
401 //
402 // Passing something to another avatar or a an object will already
403 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
404 item = InventoryService.GetItem(item);
405  
406 if (item != null)
407 {
408 if (item.Owner != remoteClient.AgentId)
409 return;
410  
411 item.Name = itemUpd.Name;
412 item.Description = itemUpd.Description;
413  
414 // m_log.DebugFormat(
415 // "[USER INVENTORY]: itemUpd {0} {1} {2} {3}, item {4} {5} {6} {7}",
416 // itemUpd.NextPermissions, itemUpd.GroupPermissions, itemUpd.EveryOnePermissions, item.Flags,
417 // item.NextPermissions, item.GroupPermissions, item.EveryOnePermissions, item.CurrentPermissions);
418  
419 bool sendUpdate = false;
420  
421 if (itemUpd.NextPermissions != 0) // Use this to determine validity. Can never be 0 if valid
422 {
423 // Create a set of base permissions that will not include export if the user
424 // is not allowed to change the export flag.
425 bool denyExportChange = false;
426  
427 // m_log.DebugFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions);
428  
429 // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export
430 if ((item.BasePermissions & (uint)(PermissionMask.All | PermissionMask.Export)) != (uint)(PermissionMask.All | PermissionMask.Export) || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0 || item.CreatorIdAsUuid != item.Owner)
431 denyExportChange = true;
432  
433 // m_log.DebugFormat("[XXX]: Deny Export Update {0}", denyExportChange);
434  
435 // If it is already set, force it set and also force full perm
436 // else prevent setting it. It can and should never be set unless
437 // set in base, so the condition above is valid
438 if (denyExportChange)
439 {
440 // If we are not allowed to change it, then force it to the
441 // original item's setting and if it was on, also force full perm
442 if ((item.EveryOnePermissions & (uint)PermissionMask.Export) != 0)
443 {
444 itemUpd.NextPermissions = (uint)(PermissionMask.All);
445 itemUpd.EveryOnePermissions |= (uint)PermissionMask.Export;
446 }
447 else
448 {
449 itemUpd.EveryOnePermissions &= ~(uint)PermissionMask.Export;
450 }
451 }
452 else
453 {
454 // If the new state is exportable, force full perm
455 if ((itemUpd.EveryOnePermissions & (uint)PermissionMask.Export) != 0)
456 {
457 // m_log.DebugFormat("[XXX]: Force full perm");
458 itemUpd.NextPermissions = (uint)(PermissionMask.All);
459 }
460 }
461  
462 if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions))
463 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner;
464 item.NextPermissions = itemUpd.NextPermissions & item.BasePermissions;
465  
466 if (item.EveryOnePermissions != (itemUpd.EveryOnePermissions & item.BasePermissions))
467 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone;
468 item.EveryOnePermissions = itemUpd.EveryOnePermissions & item.BasePermissions;
469  
470 if (item.GroupPermissions != (itemUpd.GroupPermissions & item.BasePermissions))
471 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup;
472 item.GroupPermissions = itemUpd.GroupPermissions & item.BasePermissions;
473  
474 item.GroupID = itemUpd.GroupID;
475 item.GroupOwned = itemUpd.GroupOwned;
476 item.CreationDate = itemUpd.CreationDate;
477 // The client sends zero if its newly created?
478  
479 if (itemUpd.CreationDate == 0)
480 item.CreationDate = Util.UnixTimeSinceEpoch();
481 else
482 item.CreationDate = itemUpd.CreationDate;
483  
484 // TODO: Check if folder changed and move item
485 //item.NextPermissions = itemUpd.Folder;
486 item.InvType = itemUpd.InvType;
487  
488 if (item.SalePrice != itemUpd.SalePrice ||
489 item.SaleType != itemUpd.SaleType)
490 item.Flags |= (uint)InventoryItemFlags.ObjectSlamSale;
491 item.SalePrice = itemUpd.SalePrice;
492 item.SaleType = itemUpd.SaleType;
493  
494 if (item.InvType == (int)InventoryType.Wearable && (item.Flags & 0xf) == 0 && (itemUpd.Flags & 0xf) != 0)
495 {
496 item.Flags = (uint)(item.Flags & 0xfffffff0) | (itemUpd.Flags & 0xf);
497 sendUpdate = true;
498 }
499  
500 InventoryService.UpdateItem(item);
501 }
502  
503 if (UUID.Zero != transactionID)
504 {
505 if (AgentTransactionsModule != null)
506 {
507 AgentTransactionsModule.HandleItemUpdateFromTransaction(remoteClient, transactionID, item);
508 }
509 }
510 else
511 {
512 // This MAY be problematic, if it is, another solution
513 // needs to be found. If inventory item flags are updated
514 // the viewer's notion of the item needs to be refreshed.
515 //
516 // In other situations we cannot send out a bulk update here, since this will cause editing of clothing to start
517 // failing frequently. Possibly this is a race with a separate transaction that uploads the asset.
518 if (sendUpdate)
519 remoteClient.SendBulkUpdateInventory(item);
520 }
521 }
522 else
523 {
524 m_log.ErrorFormat(
525 "[AGENTINVENTORY]: Item id {0} not found for an inventory item update for {1}.",
526 itemID, remoteClient.Name);
527 }
528 }
529  
530 /// <summary>
531 /// Give an inventory item from one user to another
532 /// </summary>
533 /// <param name="recipientClient"></param>
534 /// <param name="senderId">ID of the sender of the item</param>
535 /// <param name="itemId"></param>
536 public virtual void GiveInventoryItem(IClientAPI recipientClient, UUID senderId, UUID itemId)
537 {
538 InventoryItemBase itemCopy = GiveInventoryItem(recipientClient.AgentId, senderId, itemId);
539  
540 if (itemCopy != null)
541 recipientClient.SendBulkUpdateInventory(itemCopy);
542 }
543  
544 /// <summary>
545 /// Give an inventory item from one user to another
546 /// </summary>
547 /// <param name="recipient"></param>
548 /// <param name="senderId">ID of the sender of the item</param>
549 /// <param name="itemId"></param>
550 /// <returns>The inventory item copy given, null if the give was unsuccessful</returns>
551 public virtual InventoryItemBase GiveInventoryItem(UUID recipient, UUID senderId, UUID itemId)
552 {
553 return GiveInventoryItem(recipient, senderId, itemId, UUID.Zero);
554 }
555  
556 /// <summary>
557 /// Give an inventory item from one user to another
558 /// </summary>
559 /// <param name="recipient"></param>
560 /// <param name="senderId">ID of the sender of the item</param>
561 /// <param name="itemId"></param>
562 /// <param name="recipientFolderId">
563 /// The id of the folder in which the copy item should go. If UUID.Zero then the item is placed in the most
564 /// appropriate default folder.
565 /// </param>
566 /// <returns>
567 /// The inventory item copy given, null if the give was unsuccessful
568 /// </returns>
569 public virtual InventoryItemBase GiveInventoryItem(
570 UUID recipient, UUID senderId, UUID itemId, UUID recipientFolderId)
571 {
572 //Console.WriteLine("Scene.Inventory.cs: GiveInventoryItem");
573  
574 if (!Permissions.CanTransferUserInventory(itemId, senderId, recipient))
575 return null;
576  
577 InventoryItemBase item = new InventoryItemBase(itemId, senderId);
578 item = InventoryService.GetItem(item);
579  
580 if (item == null)
581 {
582 m_log.WarnFormat(
583 "[AGENT INVENTORY]: Failed to find item {0} sent by {1} to {2}", itemId, senderId, recipient);
584 return null;
585 }
586  
587 if (item.Owner != senderId)
588 {
589 m_log.WarnFormat(
590 "[AGENT INVENTORY]: Attempt to send item {0} {1} to {2} failed because sender {3} did not match item owner {4}",
591 item.Name, item.ID, recipient, senderId, item.Owner);
592 return null;
593 }
594  
595 IUserManagement uman = RequestModuleInterface<IUserManagement>();
596 if (uman != null)
597 uman.AddUser(item.CreatorIdAsUuid, item.CreatorData);
598  
599 if (!Permissions.BypassPermissions())
600 {
601 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
602 return null;
603 }
604  
605 // Insert a copy of the item into the recipient
606 InventoryItemBase itemCopy = new InventoryItemBase();
607 itemCopy.Owner = recipient;
608 itemCopy.CreatorId = item.CreatorId;
609 itemCopy.CreatorData = item.CreatorData;
610 itemCopy.ID = UUID.Random();
611 itemCopy.AssetID = item.AssetID;
612 itemCopy.Description = item.Description;
613 itemCopy.Name = item.Name;
614 itemCopy.AssetType = item.AssetType;
615 itemCopy.InvType = item.InvType;
616 itemCopy.Folder = recipientFolderId;
617  
618 if (Permissions.PropagatePermissions() && recipient != senderId)
619 {
620 // Trying to do this right this time. This is evil. If
621 // you believe in Good, go elsewhere. Vampires and other
622 // evil creatores only beyond this point. You have been
623 // warned.
624  
625 // We're going to mask a lot of things by the next perms
626 // Tweak the next perms to be nicer to our data
627 //
628 // In this mask, all the bits we do NOT want to mess
629 // with are set. These are:
630 //
631 // Transfer
632 // Copy
633 // Modufy
634 uint permsMask = ~ ((uint)PermissionMask.Copy |
635 (uint)PermissionMask.Transfer |
636 (uint)PermissionMask.Modify);
637  
638 // Now, reduce the next perms to the mask bits
639 // relevant to the operation
640 uint nextPerms = permsMask | (item.NextPermissions &
641 ((uint)PermissionMask.Copy |
642 (uint)PermissionMask.Transfer |
643 (uint)PermissionMask.Modify));
644  
645 // nextPerms now has all bits set, except for the actual
646 // next permission bits.
647  
648 // This checks for no mod, no copy, no trans.
649 // This indicates an error or messed up item. Do it like
650 // SL and assume trans
651 if (nextPerms == permsMask)
652 nextPerms |= (uint)PermissionMask.Transfer;
653  
654 // Inventory owner perms are the logical AND of the
655 // folded perms and the root prim perms, however, if
656 // the root prim is mod, the inventory perms will be
657 // mod. This happens on "take" and is of little concern
658 // here, save for preventing escalation
659  
660 // This hack ensures that items previously permalocked
661 // get unlocked when they're passed or rezzed
662 uint basePerms = item.BasePermissions |
663 (uint)PermissionMask.Move;
664 uint ownerPerms = item.CurrentPermissions;
665  
666 // If this is an object, root prim perms may be more
667 // permissive than folded perms. Use folded perms as
668 // a mask
669 if (item.InvType == (int)InventoryType.Object)
670 {
671 // Create a safe mask for the current perms
672 uint foldedPerms = (item.CurrentPermissions & 7) << 13;
673 foldedPerms |= permsMask;
674  
675 bool isRootMod = (item.CurrentPermissions &
676 (uint)PermissionMask.Modify) != 0 ?
677 true : false;
678  
679 // Mask the owner perms to the folded perms
680 ownerPerms &= foldedPerms;
681 basePerms &= foldedPerms;
682  
683 // If the root was mod, let the mask reflect that
684 // We also need to adjust the base here, because
685 // we should be able to edit in-inventory perms
686 // for the root prim, if it's mod.
687 if (isRootMod)
688 {
689 ownerPerms |= (uint)PermissionMask.Modify;
690 basePerms |= (uint)PermissionMask.Modify;
691 }
692 }
693  
694 // These will be applied to the root prim at next rez.
695 // The slam bit (bit 3) and folded permission (bits 0-2)
696 // are preserved due to the above mangling
697 ownerPerms &= nextPerms;
698  
699 // Mask the base permissions. This is a conservative
700 // approach altering only the three main perms
701 basePerms &= nextPerms;
702  
703 // Assign to the actual item. Make sure the slam bit is
704 // set, if it wasn't set before.
705 itemCopy.BasePermissions = basePerms;
706 itemCopy.CurrentPermissions = ownerPerms;
707 itemCopy.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm;
708  
709 itemCopy.NextPermissions = item.NextPermissions;
710  
711 // This preserves "everyone can move"
712 itemCopy.EveryOnePermissions = item.EveryOnePermissions &
713 nextPerms;
714  
715 // Intentionally killing "share with group" here, as
716 // the recipient will not have the group this is
717 // set to
718 itemCopy.GroupPermissions = 0;
719 }
720 else
721 {
722 itemCopy.CurrentPermissions = item.CurrentPermissions;
723 itemCopy.NextPermissions = item.NextPermissions;
724 itemCopy.EveryOnePermissions = item.EveryOnePermissions & item.NextPermissions;
725 itemCopy.GroupPermissions = item.GroupPermissions & item.NextPermissions;
726 itemCopy.BasePermissions = item.BasePermissions;
727 }
728  
729 if (itemCopy.Folder == UUID.Zero)
730 {
731 InventoryFolderBase folder = InventoryService.GetFolderForType(recipient, (AssetType)itemCopy.AssetType);
732  
733 if (folder != null)
734 {
735 itemCopy.Folder = folder.ID;
736 }
737 else
738 {
739 InventoryFolderBase root = InventoryService.GetRootFolder(recipient);
740  
741 if (root != null)
742 itemCopy.Folder = root.ID;
743 else
744 return null; // No destination
745 }
746 }
747  
748 itemCopy.GroupID = UUID.Zero;
749 itemCopy.GroupOwned = false;
750 itemCopy.Flags = item.Flags;
751 itemCopy.SalePrice = item.SalePrice;
752 itemCopy.SaleType = item.SaleType;
753  
754 IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>();
755 if (invAccess != null)
756 invAccess.TransferInventoryAssets(itemCopy, senderId, recipient);
757 AddInventoryItem(itemCopy);
758  
759 if (!Permissions.BypassPermissions())
760 {
761 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
762 {
763 List<UUID> items = new List<UUID>();
764 items.Add(itemId);
765 InventoryService.DeleteItems(senderId, items);
766 }
767 }
768  
769 return itemCopy;
770 }
771  
772 /// <summary>
773 /// Give an entire inventory folder from one user to another. The entire contents (including all descendent
774 /// folders) is given.
775 /// </summary>
776 /// <param name="recipientId"></param>
777 /// <param name="senderId">ID of the sender of the item</param>
778 /// <param name="folderId"></param>
779 /// <param name="recipientParentFolderId">
780 /// The id of the receipient folder in which the send folder should be placed. If UUID.Zero then the
781 /// recipient folder is the root folder
782 /// </param>
783 /// <returns>
784 /// The inventory folder copy given, null if the copy was unsuccessful
785 /// </returns>
786 public virtual InventoryFolderBase GiveInventoryFolder(
787 UUID recipientId, UUID senderId, UUID folderId, UUID recipientParentFolderId)
788 {
789 //// Retrieve the folder from the sender
790 InventoryFolderBase folder = InventoryService.GetFolder(new InventoryFolderBase(folderId));
791 if (null == folder)
792 {
793 m_log.ErrorFormat(
794 "[AGENT INVENTORY]: Could not find inventory folder {0} to give", folderId);
795  
796 return null;
797 }
798  
799 if (recipientParentFolderId == UUID.Zero)
800 {
801 InventoryFolderBase recipientRootFolder = InventoryService.GetRootFolder(recipientId);
802 if (recipientRootFolder != null)
803 recipientParentFolderId = recipientRootFolder.ID;
804 else
805 {
806 m_log.WarnFormat("[AGENT INVENTORY]: Unable to find root folder for receiving agent");
807 return null;
808 }
809 }
810  
811 UUID newFolderId = UUID.Random();
812 InventoryFolderBase newFolder
813 = new InventoryFolderBase(
814 newFolderId, folder.Name, recipientId, folder.Type, recipientParentFolderId, folder.Version);
815 InventoryService.AddFolder(newFolder);
816  
817 // Give all the subfolders
818 InventoryCollection contents = InventoryService.GetFolderContent(senderId, folderId);
819 foreach (InventoryFolderBase childFolder in contents.Folders)
820 {
821 GiveInventoryFolder(recipientId, senderId, childFolder.ID, newFolder.ID);
822 }
823  
824 // Give all the items
825 foreach (InventoryItemBase item in contents.Items)
826 {
827 GiveInventoryItem(recipientId, senderId, item.ID, newFolder.ID);
828 }
829  
830 return newFolder;
831 }
832  
833 public void CopyInventoryItem(IClientAPI remoteClient, uint callbackID, UUID oldAgentID, UUID oldItemID,
834 UUID newFolderID, string newName)
835 {
836 m_log.DebugFormat(
837 "[AGENT INVENTORY]: CopyInventoryItem received by {0} with oldAgentID {1}, oldItemID {2}, new FolderID {3}, newName {4}",
838 remoteClient.AgentId, oldAgentID, oldItemID, newFolderID, newName);
839  
840 InventoryItemBase item = null;
841 if (LibraryService != null && LibraryService.LibraryRootFolder != null)
842 item = LibraryService.LibraryRootFolder.FindItem(oldItemID);
843  
844 if (item == null)
845 {
846 item = new InventoryItemBase(oldItemID, remoteClient.AgentId);
847 item = InventoryService.GetItem(item);
848  
849 if (item == null)
850 {
851 m_log.Error("[AGENT INVENTORY]: Failed to find item " + oldItemID.ToString());
852 return;
853 }
854  
855 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
856 return;
857 }
858  
859 AssetBase asset = AssetService.Get(item.AssetID.ToString());
860  
861 if (asset != null)
862 {
863 if (newName != String.Empty)
864 {
865 asset.Name = newName;
866 }
867 else
868 {
869 newName = item.Name;
870 }
871  
872 if (remoteClient.AgentId == oldAgentID
873 || (LibraryService != null
874 && LibraryService.LibraryRootFolder != null
875 && oldAgentID == LibraryService.LibraryRootFolder.Owner))
876 {
877 CreateNewInventoryItem(
878 remoteClient, item.CreatorId, item.CreatorData, newFolderID,
879 newName, item.Description, item.Flags, callbackID, asset, (sbyte)item.InvType,
880 item.BasePermissions, item.CurrentPermissions, item.EveryOnePermissions,
881 item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch());
882 }
883 else
884 {
885 // If item is transfer or permissions are off or calling agent is allowed to copy item owner's inventory item.
886 if (((item.CurrentPermissions & (uint)PermissionMask.Transfer) != 0)
887 && (m_permissions.BypassPermissions()
888 || m_permissions.CanCopyUserInventory(remoteClient.AgentId, oldItemID)))
889 {
890 CreateNewInventoryItem(
891 remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Description, item.Flags, callbackID,
892 asset, (sbyte) item.InvType,
893 item.NextPermissions, item.NextPermissions, item.EveryOnePermissions & item.NextPermissions,
894 item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch());
895 }
896 }
897 }
898 else
899 {
900 m_log.ErrorFormat(
901 "[AGENT INVENTORY]: Could not copy item {0} since asset {1} could not be found",
902 item.Name, item.AssetID);
903 }
904 }
905  
906 /// <summary>
907 /// Create a new asset data structure.
908 /// </summary>
909 public AssetBase CreateAsset(string name, string description, sbyte assetType, byte[] data, UUID creatorID)
910 {
911 AssetBase asset = new AssetBase(UUID.Random(), name, assetType, creatorID.ToString());
912 asset.Description = description;
913 asset.Data = (data == null) ? new byte[1] : data;
914  
915 return asset;
916 }
917  
918 /// <summary>
919 /// Move an item within the agent's inventory.
920 /// </summary>
921 /// <param name="remoteClient"></param>
922 /// <param name="folderID"></param>
923 /// <param name="itemID"></param>
924 /// <param name="length"></param>
925 /// <param name="newName"></param>
926 public void MoveInventoryItem(IClientAPI remoteClient, List<InventoryItemBase> items)
927 {
928 m_log.DebugFormat(
929 "[AGENT INVENTORY]: Moving {0} items for user {1}", items.Count, remoteClient.AgentId);
930  
931 if (!InventoryService.MoveItems(remoteClient.AgentId, items))
932 m_log.Warn("[AGENT INVENTORY]: Failed to move items for user " + remoteClient.AgentId);
933 }
934  
935 /// <summary>
936 /// Create a new inventory item.
937 /// </summary>
938 /// <param name="remoteClient">Client creating this inventory item.</param>
939 /// <param name="creatorID"></param>
940 /// <param name="creatorData"></param>
941 /// <param name="folderID">UUID of folder in which this item should be placed.</param>
942 /// <param name="name">Item name.</para>
943 /// <param name="description">Item description.</param>
944 /// <param name="flags">Item flags</param>
945 /// <param name="callbackID">Generated by the client.</para>
946 /// <param name="asset">Asset to which this item refers.</param>
947 /// <param name="invType">Type of inventory item.</param>
948 /// <param name="nextOwnerMask">Next owner pemrissions mask.</param>
949 /// <param name="creationDate">Unix timestamp at which this item was created.</param>
950 public void CreateNewInventoryItem(
951 IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID,
952 string name, string description, uint flags, uint callbackID,
953 AssetBase asset, sbyte invType, uint nextOwnerMask, int creationDate)
954 {
955 CreateNewInventoryItem(
956 remoteClient, creatorID, creatorData, folderID, name, description, flags, callbackID, asset, invType,
957 (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, 0, nextOwnerMask, 0, creationDate);
958 }
959  
960 /// <summary>
961 /// Create a new Inventory Item
962 /// </summary>
963 /// <param name="remoteClient">Client creating this inventory item.</param>
964 /// <param name="creatorID"></param>
965 /// <param name="creatorData"></param>
966 /// <param name="folderID">UUID of folder in which this item should be placed.</param>
967 /// <param name="name">Item name.</para>
968 /// <param name="description">Item description.</param>
969 /// <param name="flags">Item flags</param>
970 /// <param name="callbackID">Generated by the client.</para>
971 /// <param name="asset">Asset to which this item refers.</param>
972 /// <param name="invType">Type of inventory item.</param>
973 /// <param name="baseMask">Base permissions mask.</param>
974 /// <param name="currentMask">Current permissions mask.</param>
975 /// <param name="everyoneMask">Everyone permissions mask.</param>
976 /// <param name="nextOwnerMask">Next owner pemrissions mask.</param>
977 /// <param name="groupMask">Group permissions mask.</param>
978 /// <param name="creationDate">Unix timestamp at which this item was created.</param>
979 private void CreateNewInventoryItem(
980 IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID,
981 string name, string description, uint flags, uint callbackID, AssetBase asset, sbyte invType,
982 uint baseMask, uint currentMask, uint everyoneMask, uint nextOwnerMask, uint groupMask, int creationDate)
983 {
984 InventoryItemBase item = new InventoryItemBase();
985 item.Owner = remoteClient.AgentId;
986 item.CreatorId = creatorID;
987 item.CreatorData = creatorData;
988 item.ID = UUID.Random();
989 item.AssetID = asset.FullID;
990 item.Name = name;
991 item.Description = description;
992 item.Flags = flags;
993 item.AssetType = asset.Type;
994 item.InvType = invType;
995 item.Folder = folderID;
996 item.CurrentPermissions = currentMask;
997 item.NextPermissions = nextOwnerMask;
998 item.EveryOnePermissions = everyoneMask;
999 item.GroupPermissions = groupMask;
1000 item.BasePermissions = baseMask;
1001 item.CreationDate = creationDate;
1002  
1003 if (AddInventoryItem(item))
1004 {
1005 remoteClient.SendInventoryItemCreateUpdate(item, callbackID);
1006 }
1007 else
1008 {
1009 m_dialogModule.SendAlertToUser(remoteClient, "Failed to create item");
1010 m_log.WarnFormat(
1011 "Failed to add item for {0} in CreateNewInventoryItem!",
1012 remoteClient.Name);
1013 }
1014 }
1015  
1016 /// <summary>
1017 /// Link an inventory item to an existing item.
1018 /// </summary>
1019 /// <remarks>
1020 /// The linkee item id is placed in the asset id slot. This appears to be what the viewer expects when
1021 /// it receives inventory information.
1022 /// </remarks>
1023 /// <param name="remoteClient"></param>
1024 /// <param name="transActionID"></param>
1025 /// <param name="folderID"></param>
1026 /// <param name="callbackID"></param>
1027 /// <param name="description"></param>
1028 /// <param name="name"></param>
1029 /// <param name="invType"></param>
1030 /// <param name="type">/param>
1031 /// <param name="olditemID"></param>
1032 private void HandleLinkInventoryItem(IClientAPI remoteClient, UUID transActionID, UUID folderID,
1033 uint callbackID, string description, string name,
1034 sbyte invType, sbyte type, UUID olditemID)
1035 {
1036 // m_log.DebugFormat(
1037 // "[AGENT INVENTORY]: Received request from {0} to create inventory item link {1} in folder {2} pointing to {3}, assetType {4}, inventoryType {5}",
1038 // remoteClient.Name, name, folderID, olditemID, (AssetType)type, (InventoryType)invType);
1039  
1040 if (!Permissions.CanCreateUserInventory(invType, remoteClient.AgentId))
1041 return;
1042  
1043 ScenePresence presence;
1044 if (TryGetScenePresence(remoteClient.AgentId, out presence))
1045 {
1046 // Disabled the check for duplicate links.
1047 //
1048 // When outfits are being adjusted, the viewer rapidly sends delete link messages followed by
1049 // create links. However, since these are handled asynchronously, the deletes do not complete before
1050 // the creates are handled. Therefore, we cannot enforce a duplicate link check.
1051 // InventoryItemBase existingLink = null;
1052 // List<InventoryItemBase> existingItems = InventoryService.GetFolderItems(remoteClient.AgentId, folderID);
1053 // foreach (InventoryItemBase item in existingItems)
1054 // if (item.AssetID == olditemID)
1055 // existingLink = item;
1056 //
1057 // if (existingLink != null)
1058 // {
1059 // m_log.WarnFormat(
1060 // "[AGENT INVENTORY]: Ignoring request from {0} to create item link {1} in folder {2} pointing to {3} since a link named {4} with id {5} already exists",
1061 // remoteClient.Name, name, folderID, olditemID, existingLink.Name, existingLink.ID);
1062 //
1063 // return;
1064 // }
1065  
1066 AssetBase asset = new AssetBase();
1067 asset.FullID = olditemID;
1068 asset.Type = type;
1069 asset.Name = name;
1070 asset.Description = description;
1071  
1072 CreateNewInventoryItem(
1073 remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID,
1074 name, description, 0, callbackID, asset, invType,
1075 (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All,
1076 (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, Util.UnixTimeSinceEpoch());
1077 }
1078 else
1079 {
1080 m_log.ErrorFormat(
1081 "ScenePresence for agent uuid {0} unexpectedly not found in HandleLinkInventoryItem",
1082 remoteClient.AgentId);
1083 }
1084 }
1085  
1086 /// <summary>
1087 /// Remove an inventory item for the client's inventory
1088 /// </summary>
1089 /// <param name="remoteClient"></param>
1090 /// <param name="itemID"></param>
1091 private void RemoveInventoryItem(IClientAPI remoteClient, List<UUID> itemIDs)
1092 {
1093 // m_log.DebugFormat(
1094 // "[AGENT INVENTORY]: Removing inventory items {0} for {1}",
1095 // string.Join(",", itemIDs.ConvertAll<string>(uuid => uuid.ToString()).ToArray()),
1096 // remoteClient.Name);
1097  
1098 InventoryService.DeleteItems(remoteClient.AgentId, itemIDs);
1099 }
1100  
1101 /// <summary>
1102 /// Removes an inventory folder. This packet is sent when the user
1103 /// right-clicks a folder that's already in trash and chooses "purge"
1104 /// </summary>
1105 /// <param name="remoteClient"></param>
1106 /// <param name="folderID"></param>
1107 private void RemoveInventoryFolder(IClientAPI remoteClient, List<UUID> folderIDs)
1108 {
1109 m_log.DebugFormat("[SCENE INVENTORY]: RemoveInventoryFolders count {0}", folderIDs.Count);
1110 InventoryService.DeleteFolders(remoteClient.AgentId, folderIDs);
1111 }
1112  
1113 /// <summary>
1114 /// Send the details of a prim's inventory to the client.
1115 /// </summary>
1116 /// <param name="remoteClient"></param>
1117 /// <param name="primLocalID"></param>
1118 public void RequestTaskInventory(IClientAPI remoteClient, uint primLocalID)
1119 {
1120 SceneObjectPart part = GetSceneObjectPart(primLocalID);
1121 if (part == null)
1122 return;
1123  
1124 if (XferManager != null)
1125 part.Inventory.RequestInventoryFile(remoteClient, XferManager);
1126 }
1127  
1128 /// <summary>
1129 /// Remove an item from a prim (task) inventory
1130 /// </summary>
1131 /// <param name="remoteClient">Unused at the moment but retained since the avatar ID might
1132 /// be necessary for a permissions check at some stage.</param>
1133 /// <param name="itemID"></param>
1134 /// <param name="localID"></param>
1135 public void RemoveTaskInventory(IClientAPI remoteClient, UUID itemID, uint localID)
1136 {
1137 SceneObjectPart part = GetSceneObjectPart(localID);
1138 SceneObjectGroup group = null;
1139 if (part != null)
1140 {
1141 group = part.ParentGroup;
1142 }
1143 if (part != null && group != null)
1144 {
1145 if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId))
1146 return;
1147  
1148 TaskInventoryItem item = group.GetInventoryItem(localID, itemID);
1149 if (item == null)
1150 return;
1151  
1152 InventoryFolderBase destFolder = InventoryService.GetFolderForType(remoteClient.AgentId, AssetType.TrashFolder);
1153  
1154 // Move the item to trash. If this is a copiable item, only
1155 // a copy will be moved and we will still need to delete
1156 // the item from the prim. If it was no copy, is will be
1157 // deleted by this method.
1158 MoveTaskInventoryItem(remoteClient, destFolder.ID, part, itemID);
1159  
1160 if (group.GetInventoryItem(localID, itemID) != null)
1161 {
1162 if (item.Type == 10)
1163 {
1164 part.RemoveScriptEvents(itemID);
1165 EventManager.TriggerRemoveScript(localID, itemID);
1166 }
1167  
1168 group.RemoveInventoryItem(localID, itemID);
1169 }
1170 part.SendPropertiesToClient(remoteClient);
1171 }
1172 }
1173  
1174 private InventoryItemBase CreateAgentInventoryItemFromTask(UUID destAgent, SceneObjectPart part, UUID itemId)
1175 {
1176 TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(itemId);
1177  
1178 if (null == taskItem)
1179 {
1180 m_log.ErrorFormat(
1181 "[PRIM INVENTORY]: Tried to retrieve item ID {0} from prim {1}, {2} for creating an avatar"
1182 + " inventory item from a prim's inventory item "
1183 + " but the required item does not exist in the prim's inventory",
1184 itemId, part.Name, part.UUID);
1185  
1186 return null;
1187 }
1188  
1189 if ((destAgent != taskItem.OwnerID) && ((taskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0))
1190 {
1191 return null;
1192 }
1193  
1194 InventoryItemBase agentItem = new InventoryItemBase();
1195  
1196 agentItem.ID = UUID.Random();
1197 agentItem.CreatorId = taskItem.CreatorID.ToString();
1198 agentItem.CreatorData = taskItem.CreatorData;
1199 agentItem.Owner = destAgent;
1200 agentItem.AssetID = taskItem.AssetID;
1201 agentItem.Description = taskItem.Description;
1202 agentItem.Name = taskItem.Name;
1203 agentItem.AssetType = taskItem.Type;
1204 agentItem.InvType = taskItem.InvType;
1205 agentItem.Flags = taskItem.Flags;
1206  
1207 if ((part.OwnerID != destAgent) && Permissions.PropagatePermissions())
1208 {
1209 agentItem.BasePermissions = taskItem.BasePermissions & (taskItem.NextPermissions | (uint)PermissionMask.Move);
1210 if (taskItem.InvType == (int)InventoryType.Object)
1211 agentItem.CurrentPermissions = agentItem.BasePermissions & (((taskItem.CurrentPermissions & 7) << 13) | (taskItem.CurrentPermissions & (uint)PermissionMask.Move));
1212 else
1213 agentItem.CurrentPermissions = agentItem.BasePermissions & taskItem.CurrentPermissions;
1214  
1215 agentItem.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm;
1216 agentItem.NextPermissions = taskItem.NextPermissions;
1217 agentItem.EveryOnePermissions = taskItem.EveryonePermissions & (taskItem.NextPermissions | (uint)PermissionMask.Move);
1218 agentItem.GroupPermissions = taskItem.GroupPermissions & taskItem.NextPermissions;
1219 }
1220 else
1221 {
1222 agentItem.BasePermissions = taskItem.BasePermissions;
1223 agentItem.CurrentPermissions = taskItem.CurrentPermissions;
1224 agentItem.NextPermissions = taskItem.NextPermissions;
1225 agentItem.EveryOnePermissions = taskItem.EveryonePermissions;
1226 agentItem.GroupPermissions = taskItem.GroupPermissions;
1227 }
1228  
1229 if (!Permissions.BypassPermissions())
1230 {
1231 if ((taskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1232 {
1233 if (taskItem.Type == 10)
1234 {
1235 part.RemoveScriptEvents(itemId);
1236 EventManager.TriggerRemoveScript(part.LocalId, itemId);
1237 }
1238  
1239 part.Inventory.RemoveInventoryItem(itemId);
1240 }
1241 }
1242  
1243 return agentItem;
1244 }
1245  
1246 /// <summary>
1247 /// Move the given item in the given prim to a folder in the client's inventory
1248 /// </summary>
1249 /// <param name="remoteClient"></param>
1250 /// <param name="folderID"></param>
1251 /// <param name="part"></param>
1252 /// <param name="itemID"></param>
1253 public InventoryItemBase MoveTaskInventoryItem(IClientAPI remoteClient, UUID folderId, SceneObjectPart part, UUID itemId)
1254 {
1255 m_log.DebugFormat(
1256 "[PRIM INVENTORY]: Adding item {0} from {1} to folder {2} for {3}",
1257 itemId, part.Name, folderId, remoteClient.Name);
1258  
1259 InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(remoteClient.AgentId, part, itemId);
1260  
1261 if (agentItem == null)
1262 return null;
1263  
1264 agentItem.Folder = folderId;
1265 AddInventoryItem(remoteClient, agentItem);
1266 return agentItem;
1267 }
1268  
1269 /// <summary>
1270 /// <see>ClientMoveTaskInventoryItem</see>
1271 /// </summary>
1272 /// <param name="remoteClient"></param>
1273 /// <param name="folderID"></param>
1274 /// <param name="primLocalID"></param>
1275 /// <param name="itemID"></param>
1276 public void ClientMoveTaskInventoryItem(IClientAPI remoteClient, UUID folderId, uint primLocalId, UUID itemId)
1277 {
1278 SceneObjectPart part = GetSceneObjectPart(primLocalId);
1279  
1280 if (null == part)
1281 {
1282 m_log.WarnFormat(
1283 "[PRIM INVENTORY]: " +
1284 "Move of inventory item {0} from prim with local id {1} failed because the prim could not be found",
1285 itemId, primLocalId);
1286  
1287 return;
1288 }
1289  
1290 TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(itemId);
1291  
1292 if (null == taskItem)
1293 {
1294 m_log.WarnFormat("[PRIM INVENTORY]: Move of inventory item {0} from prim with local id {1} failed"
1295 + " because the inventory item could not be found",
1296 itemId, primLocalId);
1297  
1298 return;
1299 }
1300  
1301 if ((taskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1302 {
1303 // If the item to be moved is no copy, we need to be able to
1304 // edit the prim.
1305 if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId))
1306 return;
1307 }
1308 else
1309 {
1310 // If the item is copiable, then we just need to have perms
1311 // on it. The delete check is a pure rights check
1312 if (!Permissions.CanDeleteObject(part.UUID, remoteClient.AgentId))
1313 return;
1314 }
1315  
1316 MoveTaskInventoryItem(remoteClient, folderId, part, itemId);
1317 }
1318  
1319 /// <summary>
1320 /// <see>MoveTaskInventoryItem</see>
1321 /// </summary>
1322 /// <param name="remoteClient"></param>
1323 /// <param name="folderID">
1324 /// The user inventory folder to move (or copy) the item to. If null, then the most
1325 /// suitable system folder is used (e.g. the Objects folder for objects). If there is no suitable folder, then
1326 /// the item is placed in the user's root inventory folder
1327 /// </param>
1328 /// <param name="part"></param>
1329 /// <param name="itemID"></param>
1330 public InventoryItemBase MoveTaskInventoryItem(UUID avatarId, UUID folderId, SceneObjectPart part, UUID itemId)
1331 {
1332 ScenePresence avatar;
1333  
1334 if (TryGetScenePresence(avatarId, out avatar))
1335 {
1336 return MoveTaskInventoryItem(avatar.ControllingClient, folderId, part, itemId);
1337 }
1338 else
1339 {
1340 InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(avatarId, part, itemId);
1341  
1342 if (agentItem == null)
1343 return null;
1344  
1345 agentItem.Folder = folderId;
1346  
1347 AddInventoryItem(agentItem);
1348  
1349 return agentItem;
1350 }
1351 }
1352  
1353 /// <summary>
1354 /// Copy a task (prim) inventory item to another task (prim)
1355 /// </summary>
1356 /// <param name="destId">ID of destination part</param>
1357 /// <param name="part">Source part</param>
1358 /// <param name="itemId">Source item id to transfer</param>
1359 public void MoveTaskInventoryItem(UUID destId, SceneObjectPart part, UUID itemId)
1360 {
1361 TaskInventoryItem srcTaskItem = part.Inventory.GetInventoryItem(itemId);
1362  
1363 if (srcTaskItem == null)
1364 {
1365 m_log.ErrorFormat(
1366 "[PRIM INVENTORY]: Tried to retrieve item ID {0} from prim {1}, {2} for moving"
1367 + " but the item does not exist in this inventory",
1368 itemId, part.Name, part.UUID);
1369  
1370 return;
1371 }
1372  
1373 SceneObjectPart destPart = GetSceneObjectPart(destId);
1374  
1375 if (destPart == null)
1376 {
1377 m_log.ErrorFormat(
1378 "[PRIM INVENTORY]: " +
1379 "Could not find prim for ID {0}",
1380 destId);
1381 return;
1382 }
1383  
1384 if (part.OwnerID != destPart.OwnerID)
1385 {
1386 // Source must have transfer permissions
1387 if ((srcTaskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
1388 return;
1389  
1390 // Object cannot copy items to an object owned by a different owner
1391 // unless llAllowInventoryDrop has been called on the destination
1392 if ((destPart.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) == 0)
1393 return;
1394 }
1395  
1396 // must have both move and modify permission to put an item in an object
1397 if ((part.OwnerMask & ((uint)PermissionMask.Move | (uint)PermissionMask.Modify)) == 0)
1398 return;
1399  
1400 TaskInventoryItem destTaskItem = new TaskInventoryItem();
1401  
1402 destTaskItem.ItemID = UUID.Random();
1403 destTaskItem.CreatorID = srcTaskItem.CreatorID;
1404 destTaskItem.CreatorData = srcTaskItem.CreatorData;
1405 destTaskItem.AssetID = srcTaskItem.AssetID;
1406 destTaskItem.GroupID = destPart.GroupID;
1407 destTaskItem.OwnerID = destPart.OwnerID;
1408 destTaskItem.ParentID = destPart.UUID;
1409 destTaskItem.ParentPartID = destPart.UUID;
1410  
1411 destTaskItem.BasePermissions = srcTaskItem.BasePermissions;
1412 destTaskItem.EveryonePermissions = srcTaskItem.EveryonePermissions;
1413 destTaskItem.GroupPermissions = srcTaskItem.GroupPermissions;
1414 destTaskItem.CurrentPermissions = srcTaskItem.CurrentPermissions;
1415 destTaskItem.NextPermissions = srcTaskItem.NextPermissions;
1416 destTaskItem.Flags = srcTaskItem.Flags;
1417  
1418 if (destPart.OwnerID != part.OwnerID)
1419 {
1420 if (Permissions.PropagatePermissions())
1421 {
1422 destTaskItem.CurrentPermissions = srcTaskItem.CurrentPermissions &
1423 (srcTaskItem.NextPermissions | (uint)PermissionMask.Move);
1424 destTaskItem.GroupPermissions = srcTaskItem.GroupPermissions &
1425 (srcTaskItem.NextPermissions | (uint)PermissionMask.Move);
1426 destTaskItem.EveryonePermissions = srcTaskItem.EveryonePermissions &
1427 (srcTaskItem.NextPermissions | (uint)PermissionMask.Move);
1428 destTaskItem.BasePermissions = srcTaskItem.BasePermissions &
1429 (srcTaskItem.NextPermissions | (uint)PermissionMask.Move);
1430 destTaskItem.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm;
1431 }
1432 }
1433  
1434 destTaskItem.Description = srcTaskItem.Description;
1435 destTaskItem.Name = srcTaskItem.Name;
1436 destTaskItem.InvType = srcTaskItem.InvType;
1437 destTaskItem.Type = srcTaskItem.Type;
1438  
1439 destPart.Inventory.AddInventoryItem(destTaskItem, part.OwnerID != destPart.OwnerID);
1440  
1441 if ((srcTaskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1442 part.Inventory.RemoveInventoryItem(itemId);
1443  
1444 ScenePresence avatar;
1445  
1446 if (TryGetScenePresence(srcTaskItem.OwnerID, out avatar))
1447 {
1448 destPart.SendPropertiesToClient(avatar.ControllingClient);
1449 }
1450 }
1451  
1452 public UUID MoveTaskInventoryItems(UUID destID, string category, SceneObjectPart host, List<UUID> items)
1453 {
1454 InventoryFolderBase rootFolder = InventoryService.GetRootFolder(destID);
1455  
1456 UUID newFolderID = UUID.Random();
1457  
1458 InventoryFolderBase newFolder = new InventoryFolderBase(newFolderID, category, destID, -1, rootFolder.ID, rootFolder.Version);
1459 InventoryService.AddFolder(newFolder);
1460  
1461 foreach (UUID itemID in items)
1462 {
1463 InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(destID, host, itemID);
1464  
1465 if (agentItem != null)
1466 {
1467 agentItem.Folder = newFolderID;
1468  
1469 AddInventoryItem(agentItem);
1470 }
1471 }
1472  
1473 ScenePresence avatar = null;
1474 if (TryGetScenePresence(destID, out avatar))
1475 {
1476 //profile.SendInventoryDecendents(avatar.ControllingClient,
1477 // profile.RootFolder.ID, true, false);
1478 //profile.SendInventoryDecendents(avatar.ControllingClient,
1479 // newFolderID, false, true);
1480  
1481 SendInventoryUpdate(avatar.ControllingClient, rootFolder, true, false);
1482 SendInventoryUpdate(avatar.ControllingClient, newFolder, false, true);
1483 }
1484  
1485 return newFolderID;
1486 }
1487  
1488 public void SendInventoryUpdate(IClientAPI client, InventoryFolderBase folder, bool fetchFolders, bool fetchItems)
1489 {
1490 if (folder == null)
1491 return;
1492  
1493 // TODO: This code for looking in the folder for the library should be folded somewhere else
1494 // so that this class doesn't have to know the details (and so that multiple libraries, etc.
1495 // can be handled transparently).
1496 InventoryFolderImpl fold = null;
1497 if (LibraryService != null && LibraryService.LibraryRootFolder != null)
1498 {
1499 if ((fold = LibraryService.LibraryRootFolder.FindFolder(folder.ID)) != null)
1500 {
1501 client.SendInventoryFolderDetails(
1502 fold.Owner, folder.ID, fold.RequestListOfItems(),
1503 fold.RequestListOfFolders(), fold.Version, fetchFolders, fetchItems);
1504 return;
1505 }
1506 }
1507  
1508 // Fetch the folder contents
1509 InventoryCollection contents = InventoryService.GetFolderContent(client.AgentId, folder.ID);
1510  
1511 // Fetch the folder itself to get its current version
1512 InventoryFolderBase containingFolder = new InventoryFolderBase(folder.ID, client.AgentId);
1513 containingFolder = InventoryService.GetFolder(containingFolder);
1514  
1515 // m_log.DebugFormat("[AGENT INVENTORY]: Sending inventory folder contents ({0} nodes) for \"{1}\" to {2} {3}",
1516 // contents.Folders.Count + contents.Items.Count, containingFolder.Name, client.FirstName, client.LastName);
1517  
1518 if (containingFolder != null)
1519 {
1520 // If the folder requested contains links, then we need to send those folders first, otherwise the links
1521 // will be broken in the viewer.
1522 HashSet<UUID> linkedItemFolderIdsToSend = new HashSet<UUID>();
1523 foreach (InventoryItemBase item in contents.Items)
1524 {
1525 if (item.AssetType == (int)AssetType.Link)
1526 {
1527 InventoryItemBase linkedItem = InventoryService.GetItem(new InventoryItemBase(item.AssetID));
1528  
1529 // Take care of genuinely broken links where the target doesn't exist
1530 // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
1531 // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
1532 // rather than having to keep track of every folder requested in the recursion.
1533 if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
1534 {
1535 // We don't need to send the folder if source and destination of the link are in the same
1536 // folder.
1537 if (linkedItem.Folder != containingFolder.ID)
1538 linkedItemFolderIdsToSend.Add(linkedItem.Folder);
1539 }
1540 }
1541 }
1542  
1543 foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend)
1544 SendInventoryUpdate(client, new InventoryFolderBase(linkedItemFolderId), false, true);
1545  
1546 client.SendInventoryFolderDetails(
1547 client.AgentId, folder.ID, contents.Items, contents.Folders,
1548 containingFolder.Version, fetchFolders, fetchItems);
1549 }
1550 }
1551  
1552 /// <summary>
1553 /// Update an item in a prim (task) inventory.
1554 /// This method does not handle scripts, <see>RezScript(IClientAPI, UUID, unit)</see>
1555 /// </summary>
1556 /// <param name="remoteClient"></param>
1557 /// <param name="transactionID"></param>
1558 /// <param name="itemInfo"></param>
1559 /// <param name="primLocalID"></param>
1560 public void UpdateTaskInventory(IClientAPI remoteClient, UUID transactionID, TaskInventoryItem itemInfo,
1561 uint primLocalID)
1562 {
1563 UUID itemID = itemInfo.ItemID;
1564  
1565 // Find the prim we're dealing with
1566 SceneObjectPart part = GetSceneObjectPart(primLocalID);
1567  
1568 if (part != null)
1569 {
1570 TaskInventoryItem currentItem = part.Inventory.GetInventoryItem(itemID);
1571 bool allowInventoryDrop = (part.GetEffectiveObjectFlags()
1572 & (uint)PrimFlags.AllowInventoryDrop) != 0;
1573  
1574 // Explicity allow anyone to add to the inventory if the
1575 // AllowInventoryDrop flag has been set. Don't however let
1576 // them update an item unless they pass the external checks
1577 //
1578 if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId)
1579 && (currentItem != null || !allowInventoryDrop))
1580 return;
1581  
1582 if (currentItem == null)
1583 {
1584 UUID copyID = UUID.Random();
1585 if (itemID != UUID.Zero)
1586 {
1587 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
1588 item = InventoryService.GetItem(item);
1589  
1590 // Try library
1591 if (null == item && LibraryService != null && LibraryService.LibraryRootFolder != null)
1592 {
1593 item = LibraryService.LibraryRootFolder.FindItem(itemID);
1594 }
1595  
1596 // If we've found the item in the user's inventory or in the library
1597 if (item != null)
1598 {
1599 part.ParentGroup.AddInventoryItem(remoteClient.AgentId, primLocalID, item, copyID);
1600 m_log.InfoFormat(
1601 "[PRIM INVENTORY]: Update with item {0} requested of prim {1} for {2}",
1602 item.Name, primLocalID, remoteClient.Name);
1603 part.SendPropertiesToClient(remoteClient);
1604 if (!Permissions.BypassPermissions())
1605 {
1606 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1607 {
1608 List<UUID> uuids = new List<UUID>();
1609 uuids.Add(itemID);
1610 RemoveInventoryItem(remoteClient, uuids);
1611 }
1612 }
1613 }
1614 else
1615 {
1616 m_log.ErrorFormat(
1617 "[PRIM INVENTORY]: Could not find inventory item {0} to update for {1}!",
1618 itemID, remoteClient.Name);
1619 }
1620 }
1621 }
1622 else // Updating existing item with new perms etc
1623 {
1624 // m_log.DebugFormat(
1625 // "[PRIM INVENTORY]: Updating item {0} in {1} for UpdateTaskInventory()",
1626 // currentItem.Name, part.Name);
1627  
1628 // Only look for an uploaded updated asset if we are passed a transaction ID. This is only the
1629 // case for updates uploded through UDP. Updates uploaded via a capability (e.g. a script update)
1630 // will not pass in a transaction ID in the update message.
1631 if (transactionID != UUID.Zero && AgentTransactionsModule != null)
1632 {
1633 AgentTransactionsModule.HandleTaskItemUpdateFromTransaction(
1634 remoteClient, part, transactionID, currentItem);
1635  
1636 if ((InventoryType)itemInfo.InvType == InventoryType.Notecard)
1637 remoteClient.SendAlertMessage("Notecard saved");
1638 else if ((InventoryType)itemInfo.InvType == InventoryType.LSL)
1639 remoteClient.SendAlertMessage("Script saved");
1640 else
1641 remoteClient.SendAlertMessage("Item saved");
1642 }
1643  
1644 // Base ALWAYS has move
1645 currentItem.BasePermissions |= (uint)PermissionMask.Move;
1646  
1647 itemInfo.Flags = currentItem.Flags;
1648  
1649 // Check if we're allowed to mess with permissions
1650 if (!Permissions.IsGod(remoteClient.AgentId)) // Not a god
1651 {
1652 if (remoteClient.AgentId != part.OwnerID) // Not owner
1653 {
1654 // Friends and group members can't change any perms
1655 itemInfo.BasePermissions = currentItem.BasePermissions;
1656 itemInfo.EveryonePermissions = currentItem.EveryonePermissions;
1657 itemInfo.GroupPermissions = currentItem.GroupPermissions;
1658 itemInfo.NextPermissions = currentItem.NextPermissions;
1659 itemInfo.CurrentPermissions = currentItem.CurrentPermissions;
1660 }
1661 else
1662 {
1663 // Owner can't change base, and can change other
1664 // only up to base
1665 itemInfo.BasePermissions = currentItem.BasePermissions;
1666 if (itemInfo.EveryonePermissions != currentItem.EveryonePermissions)
1667 itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone;
1668 if (itemInfo.GroupPermissions != currentItem.GroupPermissions)
1669 itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup;
1670 if (itemInfo.CurrentPermissions != currentItem.CurrentPermissions)
1671 itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteOwner;
1672 if (itemInfo.NextPermissions != currentItem.NextPermissions)
1673 itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner;
1674 itemInfo.EveryonePermissions &= currentItem.BasePermissions;
1675 itemInfo.GroupPermissions &= currentItem.BasePermissions;
1676 itemInfo.CurrentPermissions &= currentItem.BasePermissions;
1677 itemInfo.NextPermissions &= currentItem.BasePermissions;
1678 }
1679  
1680 }
1681 else
1682 {
1683 if (itemInfo.BasePermissions != currentItem.BasePermissions)
1684 itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteBase;
1685 if (itemInfo.EveryonePermissions != currentItem.EveryonePermissions)
1686 itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone;
1687 if (itemInfo.GroupPermissions != currentItem.GroupPermissions)
1688 itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup;
1689 if (itemInfo.CurrentPermissions != currentItem.CurrentPermissions)
1690 itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteOwner;
1691 if (itemInfo.NextPermissions != currentItem.NextPermissions)
1692 itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner;
1693 }
1694  
1695 // Next ALWAYS has move
1696 itemInfo.NextPermissions |= (uint)PermissionMask.Move;
1697  
1698 if (part.Inventory.UpdateInventoryItem(itemInfo))
1699 {
1700 part.SendPropertiesToClient(remoteClient);
1701 }
1702 }
1703 }
1704 else
1705 {
1706 m_log.WarnFormat(
1707 "[PRIM INVENTORY]: " +
1708 "Update with item {0} requested of prim {1} for {2} but this prim does not exist",
1709 itemID, primLocalID, remoteClient.Name);
1710 }
1711 }
1712  
1713 /// <summary>
1714 /// Rez a script into a prim's inventory, either ex nihilo or from an existing avatar inventory
1715 /// </summary>
1716 /// <param name="remoteClient"></param>
1717 /// <param name="itemBase"> </param>
1718 /// <param name="transactionID"></param>
1719 /// <param name="localID"></param>
1720 public void RezScript(IClientAPI remoteClient, InventoryItemBase itemBase, UUID transactionID, uint localID)
1721 {
1722 SceneObjectPart partWhereRezzed;
1723  
1724 if (itemBase.ID != UUID.Zero)
1725 partWhereRezzed = RezScriptFromAgentInventory(remoteClient.AgentId, itemBase.ID, localID);
1726 else
1727 partWhereRezzed = RezNewScript(remoteClient.AgentId, itemBase);
1728  
1729 if (partWhereRezzed != null)
1730 partWhereRezzed.SendPropertiesToClient(remoteClient);
1731 }
1732  
1733 /// <summary>
1734 /// Rez a script into a prim from an agent inventory.
1735 /// </summary>
1736 /// <param name="agentID"></param>
1737 /// <param name="fromItemID"></param>
1738 /// <param name="localID"></param>
1739 /// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
1740 public SceneObjectPart RezScriptFromAgentInventory(UUID agentID, UUID fromItemID, uint localID)
1741 {
1742 UUID copyID = UUID.Random();
1743 InventoryItemBase item = new InventoryItemBase(fromItemID, agentID);
1744 item = InventoryService.GetItem(item);
1745  
1746 // Try library
1747 // XXX clumsy, possibly should be one call
1748 if (null == item && LibraryService != null && LibraryService.LibraryRootFolder != null)
1749 {
1750 item = LibraryService.LibraryRootFolder.FindItem(fromItemID);
1751 }
1752  
1753 if (item != null)
1754 {
1755 SceneObjectPart part = GetSceneObjectPart(localID);
1756 if (part != null)
1757 {
1758 if (!Permissions.CanEditObjectInventory(part.UUID, agentID))
1759 return null;
1760  
1761 part.ParentGroup.AddInventoryItem(agentID, localID, item, copyID);
1762 // TODO: switch to posting on_rez here when scripts
1763 // have state in inventory
1764 part.Inventory.CreateScriptInstance(copyID, 0, false, DefaultScriptEngine, 0);
1765  
1766 // tell anyone watching that there is a new script in town
1767 EventManager.TriggerNewScript(agentID, part, copyID);
1768  
1769 // m_log.InfoFormat("[PRIMINVENTORY]: " +
1770 // "Rezzed script {0} into prim local ID {1} for user {2}",
1771 // item.inventoryName, localID, remoteClient.Name);
1772  
1773 part.ParentGroup.ResumeScripts();
1774  
1775 return part;
1776 }
1777 else
1778 {
1779 m_log.ErrorFormat(
1780 "[PRIM INVENTORY]: " +
1781 "Could not rez script {0} into prim local ID {1} for user {2}"
1782 + " because the prim could not be found in the region!",
1783 item.Name, localID, agentID);
1784 }
1785 }
1786 else
1787 {
1788 m_log.ErrorFormat(
1789 "[PRIM INVENTORY]: Could not find script inventory item {0} to rez for {1}!",
1790 fromItemID, agentID);
1791 }
1792  
1793 return null;
1794 }
1795  
1796 /// <summary>
1797 /// Rez a new script from nothing.
1798 /// </summary>
1799 /// <param name="remoteClient"></param>
1800 /// <param name="itemBase"></param>
1801 /// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
1802 public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase)
1803 {
1804 return RezNewScript(
1805 agentID,
1806 itemBase,
1807 "default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}");
1808 }
1809  
1810 /// <summary>
1811 /// Rez a new script from nothing with given script text.
1812 /// </summary>
1813 /// <param name="remoteClient"></param>
1814 /// <param name="itemBase">Template item.</param>
1815 /// <param name="scriptText"></param>
1816 /// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
1817 public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase, string scriptText)
1818 {
1819 // The part ID is the folder ID!
1820 SceneObjectPart part = GetSceneObjectPart(itemBase.Folder);
1821 if (part == null)
1822 {
1823 // m_log.DebugFormat(
1824 // "[SCENE INVENTORY]: Could not find part with id {0} for {1} to rez new script",
1825 // itemBase.Folder, agentID);
1826  
1827 return null;
1828 }
1829  
1830 if (!Permissions.CanCreateObjectInventory(itemBase.InvType, part.UUID, agentID))
1831 {
1832 // m_log.DebugFormat(
1833 // "[SCENE INVENTORY]: No permission to create new script in {0} for {1}", part.Name, agentID);
1834  
1835 return null;
1836 }
1837  
1838 AssetBase asset
1839 = CreateAsset(
1840 itemBase.Name,
1841 itemBase.Description,
1842 (sbyte)itemBase.AssetType,
1843 Encoding.ASCII.GetBytes(scriptText),
1844 agentID);
1845  
1846 AssetService.Store(asset);
1847  
1848 TaskInventoryItem taskItem = new TaskInventoryItem();
1849  
1850 taskItem.ResetIDs(itemBase.Folder);
1851 taskItem.ParentID = itemBase.Folder;
1852 taskItem.CreationDate = (uint)itemBase.CreationDate;
1853 taskItem.Name = itemBase.Name;
1854 taskItem.Description = itemBase.Description;
1855 taskItem.Type = itemBase.AssetType;
1856 taskItem.InvType = itemBase.InvType;
1857 taskItem.OwnerID = itemBase.Owner;
1858 taskItem.CreatorID = itemBase.CreatorIdAsUuid;
1859 taskItem.BasePermissions = itemBase.BasePermissions;
1860 taskItem.CurrentPermissions = itemBase.CurrentPermissions;
1861 taskItem.EveryonePermissions = itemBase.EveryOnePermissions;
1862 taskItem.GroupPermissions = itemBase.GroupPermissions;
1863 taskItem.NextPermissions = itemBase.NextPermissions;
1864 taskItem.GroupID = itemBase.GroupID;
1865 taskItem.GroupPermissions = 0;
1866 taskItem.Flags = itemBase.Flags;
1867 taskItem.PermsGranter = UUID.Zero;
1868 taskItem.PermsMask = 0;
1869 taskItem.AssetID = asset.FullID;
1870  
1871 part.Inventory.AddInventoryItem(taskItem, false);
1872 part.Inventory.CreateScriptInstance(taskItem, 0, false, DefaultScriptEngine, 0);
1873  
1874 // tell anyone managing scripts that a new script exists
1875 EventManager.TriggerNewScript(agentID, part, taskItem.ItemID);
1876  
1877 part.ParentGroup.ResumeScripts();
1878  
1879 return part;
1880 }
1881  
1882 /// <summary>
1883 /// Rez a script into a prim's inventory from another prim
1884 /// </summary>
1885 /// <param name="remoteClient"></param>
1886 /// <param name="itemID"> </param>
1887 /// <param name="localID"></param>
1888 public void RezScriptFromPrim(UUID srcId, SceneObjectPart srcPart, UUID destId, int pin, int running, int start_param)
1889 {
1890 TaskInventoryItem srcTaskItem = srcPart.Inventory.GetInventoryItem(srcId);
1891  
1892 if (srcTaskItem == null)
1893 {
1894 m_log.ErrorFormat(
1895 "[PRIM INVENTORY]: Tried to retrieve item ID {0} from prim {1}, {2} for rezzing a script but the "
1896 + " item does not exist in this inventory",
1897 srcId, srcPart.Name, srcPart.UUID);
1898  
1899 return;
1900 }
1901  
1902 SceneObjectPart destPart = GetSceneObjectPart(destId);
1903  
1904 if (destPart == null)
1905 {
1906 m_log.ErrorFormat(
1907 "[PRIM INVENTORY]: " +
1908 "Could not find script for ID {0}",
1909 destId);
1910 return;
1911 }
1912  
1913 // Must own the object, and have modify rights
1914 if (srcPart.OwnerID != destPart.OwnerID)
1915 {
1916 // Group permissions
1917 if ((destPart.GroupID == UUID.Zero) || (destPart.GroupID != srcPart.GroupID) ||
1918 ((destPart.GroupMask & (uint)PermissionMask.Modify) == 0))
1919 return;
1920 } else {
1921 if ((destPart.OwnerMask & (uint)PermissionMask.Modify) == 0)
1922 return;
1923 }
1924  
1925 if (destPart.ScriptAccessPin != pin)
1926 {
1927 m_log.WarnFormat(
1928 "[PRIM INVENTORY]: " +
1929 "Script in object {0} : {1}, attempted to load script {2} : {3} into object {4} : {5} with invalid pin {6}",
1930 srcPart.Name, srcId, srcTaskItem.Name, srcTaskItem.ItemID, destPart.Name, destId, pin);
1931 // the LSL Wiki says we are supposed to shout on the DEBUG_CHANNEL -
1932 // "Object: Task Object trying to illegally load script onto task Other_Object!"
1933 // How do we shout from in here?
1934 return;
1935 }
1936  
1937 TaskInventoryItem destTaskItem = new TaskInventoryItem();
1938  
1939 destTaskItem.ItemID = UUID.Random();
1940 destTaskItem.CreatorID = srcTaskItem.CreatorID;
1941 destTaskItem.CreatorData = srcTaskItem.CreatorData;
1942 destTaskItem.AssetID = srcTaskItem.AssetID;
1943 destTaskItem.GroupID = destPart.GroupID;
1944 destTaskItem.OwnerID = destPart.OwnerID;
1945 destTaskItem.ParentID = destPart.UUID;
1946 destTaskItem.ParentPartID = destPart.UUID;
1947  
1948 destTaskItem.BasePermissions = srcTaskItem.BasePermissions;
1949 destTaskItem.EveryonePermissions = srcTaskItem.EveryonePermissions;
1950 destTaskItem.GroupPermissions = srcTaskItem.GroupPermissions;
1951 destTaskItem.CurrentPermissions = srcTaskItem.CurrentPermissions;
1952 destTaskItem.NextPermissions = srcTaskItem.NextPermissions;
1953 destTaskItem.Flags = srcTaskItem.Flags;
1954  
1955 if (destPart.OwnerID != srcPart.OwnerID)
1956 {
1957 if (Permissions.PropagatePermissions())
1958 {
1959 destTaskItem.CurrentPermissions = srcTaskItem.CurrentPermissions &
1960 srcTaskItem.NextPermissions;
1961 destTaskItem.GroupPermissions = srcTaskItem.GroupPermissions &
1962 srcTaskItem.NextPermissions;
1963 destTaskItem.EveryonePermissions = srcTaskItem.EveryonePermissions &
1964 srcTaskItem.NextPermissions;
1965 destTaskItem.BasePermissions = srcTaskItem.BasePermissions &
1966 srcTaskItem.NextPermissions;
1967 destTaskItem.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm;
1968 }
1969 }
1970  
1971 destTaskItem.Description = srcTaskItem.Description;
1972 destTaskItem.Name = srcTaskItem.Name;
1973 destTaskItem.InvType = srcTaskItem.InvType;
1974 destTaskItem.Type = srcTaskItem.Type;
1975  
1976 destPart.Inventory.AddInventoryItemExclusive(destTaskItem, false);
1977  
1978 if (running > 0)
1979 {
1980 destPart.Inventory.CreateScriptInstance(destTaskItem, start_param, false, DefaultScriptEngine, 0);
1981 }
1982  
1983 destPart.ParentGroup.ResumeScripts();
1984  
1985 ScenePresence avatar;
1986  
1987 if (TryGetScenePresence(srcTaskItem.OwnerID, out avatar))
1988 {
1989 destPart.SendPropertiesToClient(avatar.ControllingClient);
1990 }
1991 }
1992  
1993 /// <summary>
1994 /// Derez one or more objects from the scene.
1995 /// </summary>
1996 /// <remarks>
1997 /// Won't actually remove the scene object in the case where the object is being copied to a user inventory.
1998 /// </remarks>
1999 /// <param name='remoteClient'>Client requesting derez</param>
2000 /// <param name='localIDs'>Local ids of root parts of objects to delete.</param>
2001 /// <param name='groupID'>Not currently used. Here because the client passes this to us.</param>
2002 /// <param name='action'>DeRezAction</param>
2003 /// <param name='destinationID'>User folder ID to place derezzed object</param>
2004 public virtual void DeRezObjects(
2005 IClientAPI remoteClient, List<uint> localIDs, UUID groupID, DeRezAction action, UUID destinationID)
2006 {
2007 // First, see of we can perform the requested action and
2008 // build a list of eligible objects
2009 List<uint> deleteIDs = new List<uint>();
2010 List<SceneObjectGroup> deleteGroups = new List<SceneObjectGroup>();
2011  
2012 // Start with true for both, then remove the flags if objects
2013 // that we can't derez are part of the selection
2014 bool permissionToTake = true;
2015 bool permissionToTakeCopy = true;
2016 bool permissionToDelete = true;
2017  
2018 foreach (uint localID in localIDs)
2019 {
2020 // Invalid id
2021 SceneObjectPart part = GetSceneObjectPart(localID);
2022 if (part == null)
2023 continue;
2024  
2025 // Already deleted by someone else
2026 if (part.ParentGroup.IsDeleted)
2027 continue;
2028  
2029 // Can't delete child prims
2030 if (part != part.ParentGroup.RootPart)
2031 continue;
2032  
2033 SceneObjectGroup grp = part.ParentGroup;
2034  
2035 deleteIDs.Add(localID);
2036 deleteGroups.Add(grp);
2037  
2038 // If child prims have invalid perms, fix them
2039 grp.AdjustChildPrimPermissions();
2040  
2041 if (remoteClient == null)
2042 {
2043 // Autoreturn has a null client. Nothing else does. So
2044 // allow only returns
2045 if (action != DeRezAction.Return)
2046 {
2047 m_log.WarnFormat(
2048 "[AGENT INVENTORY]: Ignoring attempt to {0} {1} {2} without a client",
2049 action, grp.Name, grp.UUID);
2050 return;
2051 }
2052  
2053 permissionToTakeCopy = false;
2054 }
2055 else
2056 {
2057 if (!Permissions.CanTakeCopyObject(grp.UUID, remoteClient.AgentId))
2058 permissionToTakeCopy = false;
2059  
2060 if (!Permissions.CanTakeObject(grp.UUID, remoteClient.AgentId))
2061 permissionToTake = false;
2062  
2063 if (!Permissions.CanDeleteObject(grp.UUID, remoteClient.AgentId))
2064 permissionToDelete = false;
2065 }
2066 }
2067  
2068 // Handle god perms
2069 if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId))
2070 {
2071 permissionToTake = true;
2072 permissionToTakeCopy = true;
2073 permissionToDelete = true;
2074 }
2075  
2076 // If we're re-saving, we don't even want to delete
2077 if (action == DeRezAction.SaveToExistingUserInventoryItem)
2078 permissionToDelete = false;
2079  
2080 // if we want to take a copy, we also don't want to delete
2081 // Note: after this point, the permissionToTakeCopy flag
2082 // becomes irrelevant. It already includes the permissionToTake
2083 // permission and after excluding no copy items here, we can
2084 // just use that.
2085 if (action == DeRezAction.TakeCopy)
2086 {
2087 // If we don't have permission, stop right here
2088 if (!permissionToTakeCopy)
2089 {
2090 remoteClient.SendAlertMessage("You don't have permission to take the object");
2091 return;
2092 }
2093  
2094 permissionToTake = true;
2095 // Don't delete
2096 permissionToDelete = false;
2097 }
2098  
2099 if (action == DeRezAction.Return)
2100 {
2101 if (remoteClient != null)
2102 {
2103 if (Permissions.CanReturnObjects(
2104 null,
2105 remoteClient.AgentId,
2106 deleteGroups))
2107 {
2108 permissionToTake = true;
2109 permissionToDelete = true;
2110  
2111 foreach (SceneObjectGroup g in deleteGroups)
2112 {
2113 AddReturn(g.OwnerID == g.GroupID ? g.LastOwnerID : g.OwnerID, g.Name, g.AbsolutePosition, "parcel owner return");
2114 }
2115 }
2116 }
2117 else // Auto return passes through here with null agent
2118 {
2119 permissionToTake = true;
2120 permissionToDelete = true;
2121 }
2122 }
2123  
2124 if (permissionToTake && (action != DeRezAction.Delete || this.m_useTrashOnDelete))
2125 {
2126 m_asyncSceneObjectDeleter.DeleteToInventory(
2127 action, destinationID, deleteGroups, remoteClient,
2128 permissionToDelete);
2129 }
2130 else if (permissionToDelete)
2131 {
2132 foreach (SceneObjectGroup g in deleteGroups)
2133 DeleteSceneObject(g, false);
2134 }
2135 }
2136  
2137 /// <summary>
2138 /// Event Handler Rez an object into a scene
2139 /// Calls the non-void event handler
2140 /// </summary>
2141 /// <param name="remoteClient"></param>
2142 /// <param name="itemID"></param>
2143 /// <param name="RayEnd"></param>
2144 /// <param name="RayStart"></param>
2145 /// <param name="RayTargetID"></param>
2146 /// <param name="BypassRayCast"></param>
2147 /// <param name="RayEndIsIntersection"></param>
2148 /// <param name="EveryoneMask"></param>
2149 /// <param name="GroupMask"></param>
2150 /// <param name="RezSelected"></param>
2151 /// <param name="RemoveItem"></param>
2152 /// <param name="fromTaskID"></param>
2153 public virtual void RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart,
2154 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
2155 bool RezSelected, bool RemoveItem, UUID fromTaskID)
2156 {
2157 // m_log.DebugFormat(
2158 // "[PRIM INVENTORY]: RezObject from {0} for item {1} from task id {2}",
2159 // remoteClient.Name, itemID, fromTaskID);
2160  
2161 if (fromTaskID == UUID.Zero)
2162 {
2163 IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>();
2164 if (invAccess != null)
2165 invAccess.RezObject(
2166 remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
2167 RezSelected, RemoveItem, fromTaskID, false);
2168 }
2169 else
2170 {
2171 SceneObjectPart part = GetSceneObjectPart(fromTaskID);
2172 if (part == null)
2173 {
2174 m_log.ErrorFormat(
2175 "[TASK INVENTORY]: {0} tried to rez item id {1} from object id {2} but there is no such scene object",
2176 remoteClient.Name, itemID, fromTaskID);
2177  
2178 return;
2179 }
2180  
2181 TaskInventoryItem item = part.Inventory.GetInventoryItem(itemID);
2182 if (item == null)
2183 {
2184 m_log.ErrorFormat(
2185 "[TASK INVENTORY]: {0} tried to rez item id {1} from object id {2} but there is no such item",
2186 remoteClient.Name, itemID, fromTaskID);
2187  
2188 return;
2189 }
2190  
2191 byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0);
2192 Vector3 scale = new Vector3(0.5f, 0.5f, 0.5f);
2193 Vector3 pos
2194 = GetNewRezLocation(
2195 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
2196 BypassRayCast, bRayEndIsIntersection, true, scale, false);
2197  
2198 RezObject(part, item, pos, null, Vector3.Zero, 0);
2199 }
2200 }
2201  
2202 /// <summary>
2203 /// Rez an object into the scene from a prim's inventory.
2204 /// </summary>
2205 /// <param name="sourcePart"></param>
2206 /// <param name="item"></param>
2207 /// <param name="pos">The position of the rezzed object.</param>
2208 /// <param name="rot">The rotation of the rezzed object. If null, then the rotation stored with the object
2209 /// will be used if it exists.</param>
2210 /// <param name="vel">The velocity of the rezzed object.</param>
2211 /// <param name="param"></param>
2212 /// <returns>The SceneObjectGroup rezzed or null if rez was unsuccessful</returns>
2213 public virtual SceneObjectGroup RezObject(
2214 SceneObjectPart sourcePart, TaskInventoryItem item, Vector3 pos, Quaternion? rot, Vector3 vel, int param)
2215 {
2216 if (null == item)
2217 return null;
2218  
2219 SceneObjectGroup group = sourcePart.Inventory.GetRezReadySceneObject(item);
2220  
2221 if (null == group)
2222 return null;
2223  
2224 if (!Permissions.CanRezObject(group.PrimCount, item.OwnerID, pos))
2225 return null;
2226  
2227 if (!Permissions.BypassPermissions())
2228 {
2229 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
2230 sourcePart.Inventory.RemoveInventoryItem(item.ItemID);
2231 }
2232  
2233 group.FromPartID = sourcePart.UUID;
2234 AddNewSceneObject(group, true, pos, rot, vel);
2235  
2236 // We can only call this after adding the scene object, since the scene object references the scene
2237 // to find out if scripts should be activated at all.
2238 group.CreateScriptInstances(param, true, DefaultScriptEngine, 3);
2239  
2240 group.ScheduleGroupForFullUpdate();
2241  
2242 return group;
2243 }
2244  
2245 public virtual bool returnObjects(SceneObjectGroup[] returnobjects,
2246 UUID AgentId)
2247 {
2248 List<uint> localIDs = new List<uint>();
2249  
2250 foreach (SceneObjectGroup grp in returnobjects)
2251 {
2252 AddReturn(grp.OwnerID, grp.Name, grp.AbsolutePosition,
2253 "parcel owner return");
2254 localIDs.Add(grp.RootPart.LocalId);
2255 }
2256 DeRezObjects(null, localIDs, UUID.Zero, DeRezAction.Return,
2257 UUID.Zero);
2258  
2259 return true;
2260 }
2261  
2262 public void SetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID, bool running)
2263 {
2264 SceneObjectPart part = GetSceneObjectPart(objectID);
2265 if (part == null)
2266 return;
2267  
2268 if (running)
2269 EventManager.TriggerStartScript(part.LocalId, itemID);
2270 else
2271 EventManager.TriggerStopScript(part.LocalId, itemID);
2272 }
2273  
2274 public void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID)
2275 {
2276 EventManager.TriggerGetScriptRunning(controllingClient, objectID, itemID);
2277 }
2278  
2279 void ObjectOwner(IClientAPI remoteClient, UUID ownerID, UUID groupID, List<uint> localIDs)
2280 {
2281 if (!Permissions.IsGod(remoteClient.AgentId))
2282 {
2283 if (ownerID != UUID.Zero)
2284 return;
2285  
2286 if (!Permissions.CanDeedObject(remoteClient.AgentId, groupID))
2287 return;
2288 }
2289  
2290 List<SceneObjectGroup> groups = new List<SceneObjectGroup>();
2291  
2292 foreach (uint localID in localIDs)
2293 {
2294 SceneObjectPart part = GetSceneObjectPart(localID);
2295 if (part == null)
2296 continue;
2297  
2298 if (!groups.Contains(part.ParentGroup))
2299 groups.Add(part.ParentGroup);
2300 }
2301  
2302 foreach (SceneObjectGroup sog in groups)
2303 {
2304 if (ownerID != UUID.Zero)
2305 {
2306 sog.SetOwnerId(ownerID);
2307 sog.SetGroup(groupID, remoteClient);
2308 sog.ScheduleGroupForFullUpdate();
2309  
2310 SceneObjectPart[] partList = sog.Parts;
2311  
2312 foreach (SceneObjectPart child in partList)
2313 {
2314 child.Inventory.ChangeInventoryOwner(ownerID);
2315 child.TriggerScriptChangedEvent(Changed.OWNER);
2316 }
2317 }
2318 else
2319 {
2320 if (!Permissions.CanEditObject(sog.UUID, remoteClient.AgentId))
2321 continue;
2322  
2323 if (sog.GroupID != groupID)
2324 continue;
2325  
2326 SceneObjectPart[] partList = sog.Parts;
2327  
2328 foreach (SceneObjectPart child in partList)
2329 {
2330 child.LastOwnerID = child.OwnerID;
2331 child.Inventory.ChangeInventoryOwner(groupID);
2332 child.TriggerScriptChangedEvent(Changed.OWNER);
2333 }
2334  
2335 sog.SetOwnerId(groupID);
2336 sog.ApplyNextOwnerPermissions();
2337 }
2338 }
2339  
2340 foreach (uint localID in localIDs)
2341 {
2342 SceneObjectPart part = GetSceneObjectPart(localID);
2343 if (part == null)
2344 continue;
2345 part.SendPropertiesToClient(remoteClient);
2346 }
2347 }
2348  
2349 public void DelinkObjects(List<uint> primIds, IClientAPI client)
2350 {
2351 List<SceneObjectPart> parts = new List<SceneObjectPart>();
2352  
2353 foreach (uint localID in primIds)
2354 {
2355 SceneObjectPart part = GetSceneObjectPart(localID);
2356  
2357 if (part == null)
2358 continue;
2359  
2360 if (Permissions.CanDelinkObject(client.AgentId, part.ParentGroup.RootPart.UUID))
2361 parts.Add(part);
2362 }
2363  
2364 m_sceneGraph.DelinkObjects(parts);
2365 }
2366  
2367 /// <summary>
2368 /// Link the scene objects containing the indicated parts to a root object.
2369 /// </summary>
2370 /// <param name="client"></param>
2371 /// <param name="parentPrimId">A root prim id of the object which will be the root prim of the resulting linkset.</param>
2372 /// <param name="childPrimIds">A list of child prims for the objects that should be linked in.</param>
2373 public void LinkObjects(IClientAPI client, uint parentPrimId, List<uint> childPrimIds)
2374 {
2375 LinkObjects(client.AgentId, parentPrimId, childPrimIds);
2376 }
2377  
2378 /// <summary>
2379 /// Link the scene objects containing the indicated parts to a root object.
2380 /// </summary>
2381 /// <param name="agentId">The ID of the user linking.</param>
2382 /// <param name="parentPrimId">A root prim id of the object which will be the root prim of the resulting linkset.</param>
2383 /// <param name="childPrimIds">A list of child prims for the objects that should be linked in.</param>
2384 public void LinkObjects(UUID agentId, uint parentPrimId, List<uint> childPrimIds)
2385 {
2386 List<UUID> owners = new List<UUID>();
2387  
2388 List<SceneObjectPart> children = new List<SceneObjectPart>();
2389 SceneObjectPart root = GetSceneObjectPart(parentPrimId);
2390  
2391 if (root == null)
2392 {
2393 m_log.DebugFormat("[LINK]: Can't find linkset root prim {0}", parentPrimId);
2394 return;
2395 }
2396  
2397 if (!Permissions.CanLinkObject(agentId, root.ParentGroup.RootPart.UUID))
2398 {
2399 m_log.DebugFormat("[LINK]: Refusing link. No permissions on root prim");
2400 return;
2401 }
2402  
2403 foreach (uint localID in childPrimIds)
2404 {
2405 SceneObjectPart part = GetSceneObjectPart(localID);
2406  
2407 if (part == null)
2408 continue;
2409  
2410 if (!owners.Contains(part.OwnerID))
2411 owners.Add(part.OwnerID);
2412  
2413 if (Permissions.CanLinkObject(agentId, part.ParentGroup.RootPart.UUID))
2414 children.Add(part);
2415 }
2416  
2417 // Must be all one owner
2418 //
2419 if (owners.Count > 1)
2420 {
2421 m_log.DebugFormat("[LINK]: Refusing link. Too many owners");
2422 return;
2423 }
2424  
2425 if (children.Count == 0)
2426 {
2427 m_log.DebugFormat("[LINK]: Refusing link. No permissions to link any of the children");
2428 return;
2429 }
2430  
2431 m_sceneGraph.LinkObjects(root, children);
2432 }
2433  
2434 private string PermissionString(uint permissions)
2435 {
2436 PermissionMask perms = (PermissionMask)permissions &
2437 (PermissionMask.Move |
2438 PermissionMask.Copy |
2439 PermissionMask.Transfer |
2440 PermissionMask.Modify);
2441 return perms.ToString();
2442 }
2443 }
2444 }