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