clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections.Generic;
30 using System.Reflection;
31 using log4net;
32 using Mono.Addins;
33 using Nini.Config;
34 using OpenMetaverse;
35 using OpenSim.Framework;
36 using OpenSim.Region.Framework.Interfaces;
37 using OpenSim.Region.Framework.Scenes;
38 using OpenSim.Services.Interfaces;
39  
40 namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
41 {
42 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "InventoryTransferModule")]
43 public class InventoryTransferModule : ISharedRegionModule
44 {
45 private static readonly ILog m_log
46 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47  
48 /// <summary>
49 private List<Scene> m_Scenelist = new List<Scene>();
50  
51 private IMessageTransferModule m_TransferModule;
52 private bool m_Enabled = true;
53  
54 #region Region Module interface
55  
56 public void Initialise(IConfigSource config)
57 {
58 if (config.Configs["Messaging"] != null)
59 {
60 // Allow disabling this module in config
61 //
62 if (config.Configs["Messaging"].GetString(
63 "InventoryTransferModule", "InventoryTransferModule") !=
64 "InventoryTransferModule")
65 {
66 m_Enabled = false;
67 return;
68 }
69 }
70 }
71  
72 public void AddRegion(Scene scene)
73 {
74 if (!m_Enabled)
75 return;
76  
77 m_Scenelist.Add(scene);
78  
79 // scene.RegisterModuleInterface<IInventoryTransferModule>(this);
80  
81 scene.EventManager.OnNewClient += OnNewClient;
82 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
83 }
84  
85 public void RegionLoaded(Scene scene)
86 {
87 if (m_TransferModule == null)
88 {
89 m_TransferModule = m_Scenelist[0].RequestModuleInterface<IMessageTransferModule>();
90 if (m_TransferModule == null)
91 {
92 m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only");
93 m_Enabled = false;
94  
95 // m_Scenelist.Clear();
96 // scene.EventManager.OnNewClient -= OnNewClient;
97 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
98 }
99 }
100 }
101  
102 public void RemoveRegion(Scene scene)
103 {
104 scene.EventManager.OnNewClient -= OnNewClient;
105 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
106 m_Scenelist.Remove(scene);
107 }
108  
109 public void PostInitialise()
110 {
111 }
112  
113 public void Close()
114 {
115 }
116  
117 public string Name
118 {
119 get { return "InventoryModule"; }
120 }
121  
122 public Type ReplaceableInterface
123 {
124 get { return null; }
125 }
126  
127 #endregion
128  
129 private void OnNewClient(IClientAPI client)
130 {
131 // Inventory giving is conducted via instant message
132 client.OnInstantMessage += OnInstantMessage;
133 }
134  
135 private Scene FindClientScene(UUID agentId)
136 {
137 lock (m_Scenelist)
138 {
139 foreach (Scene scene in m_Scenelist)
140 {
141 ScenePresence presence = scene.GetScenePresence(agentId);
142 if (presence != null)
143 return scene;
144 }
145 }
146 return null;
147 }
148  
149 private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
150 {
151 // m_log.DebugFormat(
152 // "[INVENTORY TRANSFER]: {0} IM type received from client {1}. From={2} ({3}), To={4}",
153 // (InstantMessageDialog)im.dialog, client.Name,
154 // im.fromAgentID, im.fromAgentName, im.toAgentID);
155  
156 Scene scene = FindClientScene(client.AgentId);
157  
158 if (scene == null) // Something seriously wrong here.
159 return;
160  
161 if (im.dialog == (byte) InstantMessageDialog.InventoryOffered)
162 {
163 //m_log.DebugFormat("Asset type {0}", ((AssetType)im.binaryBucket[0]));
164  
165 if (im.binaryBucket.Length < 17) // Invalid
166 return;
167  
168 UUID receipientID = new UUID(im.toAgentID);
169 ScenePresence user = scene.GetScenePresence(receipientID);
170 UUID copyID;
171  
172 // First byte is the asset type
173 AssetType assetType = (AssetType)im.binaryBucket[0];
174  
175 if (AssetType.Folder == assetType)
176 {
177 UUID folderID = new UUID(im.binaryBucket, 1);
178  
179 m_log.DebugFormat(
180 "[INVENTORY TRANSFER]: Inserting original folder {0} into agent {1}'s inventory",
181 folderID, new UUID(im.toAgentID));
182  
183 InventoryFolderBase folderCopy
184 = scene.GiveInventoryFolder(client, receipientID, client.AgentId, folderID, UUID.Zero);
185  
186 if (folderCopy == null)
187 {
188 client.SendAgentAlertMessage("Can't find folder to give. Nothing given.", false);
189 return;
190 }
191  
192 // The outgoing binary bucket should contain only the byte which signals an asset folder is
193 // being copied and the following bytes for the copied folder's UUID
194 copyID = folderCopy.ID;
195 byte[] copyIDBytes = copyID.GetBytes();
196 im.binaryBucket = new byte[1 + copyIDBytes.Length];
197 im.binaryBucket[0] = (byte)AssetType.Folder;
198 Array.Copy(copyIDBytes, 0, im.binaryBucket, 1, copyIDBytes.Length);
199  
200 if (user != null)
201 user.ControllingClient.SendBulkUpdateInventory(folderCopy);
202  
203 // HACK!!
204 // Insert the ID of the copied folder into the IM so that we know which item to move to trash if it
205 // is rejected.
206 // XXX: This is probably a misuse of the session ID slot.
207 im.imSessionID = copyID.Guid;
208 }
209 else
210 {
211 // First byte of the array is probably the item type
212 // Next 16 bytes are the UUID
213  
214 UUID itemID = new UUID(im.binaryBucket, 1);
215  
216 m_log.DebugFormat("[INVENTORY TRANSFER]: (giving) Inserting item {0} "+
217 "into agent {1}'s inventory",
218 itemID, new UUID(im.toAgentID));
219  
220 string message;
221 InventoryItemBase itemCopy = scene.GiveInventoryItem(new UUID(im.toAgentID), client.AgentId, itemID, out message);
222  
223 if (itemCopy == null)
224 {
225 client.SendAgentAlertMessage(message, false);
226 return;
227 }
228  
229 copyID = itemCopy.ID;
230 Array.Copy(copyID.GetBytes(), 0, im.binaryBucket, 1, 16);
231  
232 if (user != null)
233 user.ControllingClient.SendBulkUpdateInventory(itemCopy);
234  
235 // HACK!!
236 // Insert the ID of the copied item into the IM so that we know which item to move to trash if it
237 // is rejected.
238 // XXX: This is probably a misuse of the session ID slot.
239 im.imSessionID = copyID.Guid;
240 }
241  
242 // Send the IM to the recipient. The item is already
243 // in their inventory, so it will not be lost if
244 // they are offline.
245 //
246 if (user != null)
247 {
248 user.ControllingClient.SendInstantMessage(im);
249 return;
250 }
251 else
252 {
253 if (m_TransferModule != null)
254 m_TransferModule.SendInstantMessage(im, delegate(bool success)
255 {
256 if (!success)
257 client.SendAlertMessage("User not online. Inventory has been saved");
258 });
259 }
260 }
261 else if (im.dialog == (byte) InstantMessageDialog.InventoryAccepted)
262 {
263 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
264  
265 if (user != null) // Local
266 {
267 user.ControllingClient.SendInstantMessage(im);
268 }
269 else
270 {
271 if (m_TransferModule != null)
272 m_TransferModule.SendInstantMessage(im, delegate(bool success) {
273  
274 // justincc - FIXME: Comment out for now. This code was added in commit db91044 Mon Aug 22 2011
275 // and is apparently supposed to fix bulk inventory updates after accepting items. But
276 // instead it appears to cause two copies of an accepted folder for the receiving user in
277 // at least some cases. Folder/item update is already done when the offer is made (see code above)
278  
279 // // Send BulkUpdateInventory
280 // IInventoryService invService = scene.InventoryService;
281 // UUID inventoryEntityID = new UUID(im.imSessionID); // The inventory item /folder, back from it's trip
282 //
283 // InventoryFolderBase folder = new InventoryFolderBase(inventoryEntityID, client.AgentId);
284 // folder = invService.GetFolder(folder);
285 //
286 // ScenePresence fromUser = scene.GetScenePresence(new UUID(im.fromAgentID));
287 //
288 // // If the user has left the scene by the time the message comes back then we can't send
289 // // them the update.
290 // if (fromUser != null)
291 // fromUser.ControllingClient.SendBulkUpdateInventory(folder);
292 });
293 }
294 }
295  
296 // XXX: This code was placed here to try and accomodate RLV which moves given folders named #RLV/~<name>
297 // to the requested folder, which in this case is #RLV. However, it is the viewer that appears to be
298 // response from renaming the #RLV/~example folder to ~example. For some reason this is not yet
299 // happening, possibly because we are not sending the correct inventory update messages with the correct
300 // transaction IDs
301 else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted)
302 {
303 UUID destinationFolderID = UUID.Zero;
304  
305 if (im.binaryBucket != null && im.binaryBucket.Length >= 16)
306 {
307 destinationFolderID = new UUID(im.binaryBucket, 0);
308 }
309  
310 if (destinationFolderID != UUID.Zero)
311 {
312 InventoryFolderBase destinationFolder = new InventoryFolderBase(destinationFolderID, client.AgentId);
313 if (destinationFolder == null)
314 {
315 m_log.WarnFormat(
316 "[INVENTORY TRANSFER]: TaskInventoryAccepted message from {0} in {1} specified folder {2} which does not exist",
317 client.Name, scene.Name, destinationFolderID);
318  
319 return;
320 }
321  
322 IInventoryService invService = scene.InventoryService;
323  
324 UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
325  
326 InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId);
327 item = invService.GetItem(item);
328 InventoryFolderBase folder = null;
329 UUID? previousParentFolderID = null;
330  
331 if (item != null) // It's an item
332 {
333 previousParentFolderID = item.Folder;
334 item.Folder = destinationFolderID;
335  
336 invService.DeleteItems(item.Owner, new List<UUID>() { item.ID });
337 scene.AddInventoryItem(client, item);
338 }
339 else
340 {
341 folder = new InventoryFolderBase(inventoryID, client.AgentId);
342 folder = invService.GetFolder(folder);
343  
344 if (folder != null) // It's a folder
345 {
346 previousParentFolderID = folder.ParentID;
347 folder.ParentID = destinationFolderID;
348 invService.MoveFolder(folder);
349 }
350 }
351  
352 // Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code).
353 if (previousParentFolderID != null)
354 {
355 InventoryFolderBase previousParentFolder
356 = new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId);
357 previousParentFolder = invService.GetFolder(previousParentFolder);
358 scene.SendInventoryUpdate(client, previousParentFolder, true, true);
359  
360 scene.SendInventoryUpdate(client, destinationFolder, true, true);
361 }
362 }
363 }
364 else if (
365 im.dialog == (byte)InstantMessageDialog.InventoryDeclined
366 || im.dialog == (byte)InstantMessageDialog.TaskInventoryDeclined)
367 {
368 // Here, the recipient is local and we can assume that the
369 // inventory is loaded. Courtesy of the above bulk update,
370 // It will have been pushed to the client, too
371 //
372 IInventoryService invService = scene.InventoryService;
373  
374 InventoryFolderBase trashFolder =
375 invService.GetFolderForType(client.AgentId, AssetType.TrashFolder);
376  
377 UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
378  
379 InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId);
380 item = invService.GetItem(item);
381 InventoryFolderBase folder = null;
382 UUID? previousParentFolderID = null;
383  
384 if (item != null && trashFolder != null)
385 {
386 previousParentFolderID = item.Folder;
387 item.Folder = trashFolder.ID;
388  
389 // Diva comment: can't we just update this item???
390 List<UUID> uuids = new List<UUID>();
391 uuids.Add(item.ID);
392 invService.DeleteItems(item.Owner, uuids);
393 scene.AddInventoryItem(client, item);
394 }
395 else
396 {
397 folder = new InventoryFolderBase(inventoryID, client.AgentId);
398 folder = invService.GetFolder(folder);
399  
400 if (folder != null & trashFolder != null)
401 {
402 previousParentFolderID = folder.ParentID;
403 folder.ParentID = trashFolder.ID;
404 invService.MoveFolder(folder);
405 }
406 }
407  
408 if ((null == item && null == folder) | null == trashFolder)
409 {
410 string reason = String.Empty;
411  
412 if (trashFolder == null)
413 reason += " Trash folder not found.";
414 if (item == null)
415 reason += " Item not found.";
416 if (folder == null)
417 reason += " Folder not found.";
418  
419 client.SendAgentAlertMessage("Unable to delete "+
420 "received inventory" + reason, false);
421 }
422 // Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code).
423 else if (previousParentFolderID != null)
424 {
425 InventoryFolderBase previousParentFolder
426 = new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId);
427 previousParentFolder = invService.GetFolder(previousParentFolder);
428 scene.SendInventoryUpdate(client, previousParentFolder, true, true);
429  
430 scene.SendInventoryUpdate(client, trashFolder, true, true);
431 }
432  
433 if (im.dialog == (byte)InstantMessageDialog.InventoryDeclined)
434 {
435 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
436  
437 if (user != null) // Local
438 {
439 user.ControllingClient.SendInstantMessage(im);
440 }
441 else
442 {
443 if (m_TransferModule != null)
444 m_TransferModule.SendInstantMessage(im, delegate(bool success) { });
445 }
446 }
447 }
448 }
449  
450 /// <summary>
451 ///
452 /// </summary>
453 /// <param name="im"></param>
454 private void OnGridInstantMessage(GridInstantMessage im)
455 {
456 // Check if it's a type of message that we should handle
457 if (!((im.dialog == (byte) InstantMessageDialog.InventoryOffered)
458 || (im.dialog == (byte) InstantMessageDialog.InventoryAccepted)
459 || (im.dialog == (byte) InstantMessageDialog.InventoryDeclined)
460 || (im.dialog == (byte) InstantMessageDialog.TaskInventoryDeclined)))
461 return;
462  
463 m_log.DebugFormat(
464 "[INVENTORY TRANSFER]: {0} IM type received from grid. From={1} ({2}), To={3}",
465 (InstantMessageDialog)im.dialog, im.fromAgentID, im.fromAgentName, im.toAgentID);
466  
467 // Check if this is ours to handle
468 //
469 Scene scene = FindClientScene(new UUID(im.toAgentID));
470  
471 if (scene == null)
472 return;
473  
474 // Find agent to deliver to
475 //
476 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
477  
478 if (user != null)
479 {
480 user.ControllingClient.SendInstantMessage(im);
481  
482 if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
483 {
484 AssetType assetType = (AssetType)im.binaryBucket[0];
485 UUID inventoryID = new UUID(im.binaryBucket, 1);
486  
487 IInventoryService invService = scene.InventoryService;
488 InventoryNodeBase node = null;
489 if (AssetType.Folder == assetType)
490 {
491 InventoryFolderBase folder = new InventoryFolderBase(inventoryID, new UUID(im.toAgentID));
492 node = invService.GetFolder(folder);
493 }
494 else
495 {
496 InventoryItemBase item = new InventoryItemBase(inventoryID, new UUID(im.toAgentID));
497 node = invService.GetItem(item);
498 }
499  
500 if (node != null)
501 user.ControllingClient.SendBulkUpdateInventory(node);
502 }
503 }
504 }
505 }
506 }