aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs')
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs617
1 files changed, 617 insertions, 0 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
new file mode 100644
index 0000000..ef2125b
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
@@ -0,0 +1,617 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Threading;
31using OpenMetaverse;
32using OpenMetaverse.Packets;
33using OpenSim.Framework;
34using OpenSim.Framework.Communications;
35using OpenSim.Services.Interfaces;
36
37namespace OpenSim.Region.Framework.Scenes
38{
39 public partial class Scene
40 {
41 /// <summary>
42 /// Send chat to listeners.
43 /// </summary>
44 /// <param name='message'></param>
45 /// <param name='type'>/param>
46 /// <param name='channel'></param>
47 /// <param name='fromPos'></param>
48 /// <param name='fromName'></param>
49 /// <param name='fromID'></param>
50 /// <param name='targetID'></param>
51 /// <param name='fromAgent'></param>
52 /// <param name='broadcast'></param>
53 protected void SimChat(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName,
54 UUID fromID, UUID targetID, bool fromAgent, bool broadcast)
55 {
56 OSChatMessage args = new OSChatMessage();
57
58 args.Message = Utils.BytesToString(message);
59 args.Channel = channel;
60 args.Type = type;
61 args.Position = fromPos;
62 args.SenderUUID = fromID;
63 args.Scene = this;
64
65 if (fromAgent)
66 {
67 ScenePresence user = GetScenePresence(fromID);
68 if (user != null)
69 args.Sender = user.ControllingClient;
70 }
71 else
72 {
73 SceneObjectPart obj = GetSceneObjectPart(fromID);
74 args.SenderObject = obj;
75 }
76
77 args.From = fromName;
78 args.TargetUUID = targetID;
79
80// m_log.DebugFormat(
81// "[SCENE]: Sending message {0} on channel {1}, type {2} from {3}, broadcast {4}",
82// args.Message.Replace("\n", "\\n"), args.Channel, args.Type, fromName, broadcast);
83
84 if (broadcast)
85 EventManager.TriggerOnChatBroadcast(this, args);
86 else
87 EventManager.TriggerOnChatFromWorld(this, args);
88 }
89
90 protected void SimChat(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName,
91 UUID fromID, bool fromAgent, bool broadcast)
92 {
93 SimChat(message, type, channel, fromPos, fromName, fromID, UUID.Zero, fromAgent, broadcast);
94 }
95
96 /// <summary>
97 ///
98 /// </summary>
99 /// <param name="message"></param>
100 /// <param name="type"></param>
101 /// <param name="fromPos"></param>
102 /// <param name="fromName"></param>
103 /// <param name="fromAgentID"></param>
104 public void SimChat(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName,
105 UUID fromID, bool fromAgent)
106 {
107 SimChat(message, type, channel, fromPos, fromName, fromID, fromAgent, false);
108 }
109
110 public void SimChat(string message, ChatTypeEnum type, Vector3 fromPos, string fromName, UUID fromID, bool fromAgent)
111 {
112 SimChat(Utils.StringToBytes(message), type, 0, fromPos, fromName, fromID, fromAgent);
113 }
114
115 public void SimChat(string message, string fromName)
116 {
117 SimChat(message, ChatTypeEnum.Broadcast, Vector3.Zero, fromName, UUID.Zero, false);
118 }
119
120 /// <summary>
121 ///
122 /// </summary>
123 /// <param name="message"></param>
124 /// <param name="type"></param>
125 /// <param name="fromPos"></param>
126 /// <param name="fromName"></param>
127 /// <param name="fromAgentID"></param>
128 public void SimChatBroadcast(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName,
129 UUID fromID, bool fromAgent)
130 {
131 SimChat(message, type, channel, fromPos, fromName, fromID, fromAgent, true);
132 }
133 /// <summary>
134 ///
135 /// </summary>
136 /// <param name="message"></param>
137 /// <param name="type"></param>
138 /// <param name="fromPos"></param>
139 /// <param name="fromName"></param>
140 /// <param name="fromAgentID"></param>
141 /// <param name="targetID"></param>
142 public void SimChatToAgent(UUID targetID, byte[] message, Vector3 fromPos, string fromName, UUID fromID, bool fromAgent)
143 {
144 SimChat(message, ChatTypeEnum.Say, 0, fromPos, fromName, fromID, targetID, fromAgent, false);
145 }
146
147 /// <summary>
148 ///
149 /// </summary>
150 /// <param name="message"></param>
151 /// <param name="type"></param>
152 /// <param name="channel"></param>
153 /// <param name="fromPos"></param>
154 /// <param name="fromName"></param>
155 /// <param name="fromAgentID"></param>
156 /// <param name="targetID"></param>
157 public void SimChatToAgent(UUID targetID, byte[] message, int channel, Vector3 fromPos, string fromName, UUID fromID, bool fromAgent)
158 {
159 SimChat(message, ChatTypeEnum.Region, channel, fromPos, fromName, fromID, targetID, fromAgent, false);
160 }
161
162 /// <summary>
163 /// Invoked when the client requests a prim.
164 /// </summary>
165 /// <param name="primLocalID"></param>
166 /// <param name="remoteClient"></param>
167 public void RequestPrim(uint primLocalID, IClientAPI remoteClient)
168 {
169 SceneObjectGroup sog = GetGroupByPrim(primLocalID);
170
171 if (sog != null)
172 sog.SendFullUpdateToClient(remoteClient);
173 }
174
175 /// <summary>
176 /// Invoked when the client selects a prim.
177 /// </summary>
178 /// <param name="primLocalID"></param>
179 /// <param name="remoteClient"></param>
180 public void SelectPrim(uint primLocalID, IClientAPI remoteClient)
181 {
182 SceneObjectPart part = GetSceneObjectPart(primLocalID);
183
184 if (null == part)
185 return;
186
187 if (part.IsRoot)
188 {
189 SceneObjectGroup sog = part.ParentGroup;
190 sog.SendPropertiesToClient(remoteClient);
191 sog.IsSelected = true;
192
193 // A prim is only tainted if it's allowed to be edited by the person clicking it.
194 if (Permissions.CanEditObject(sog.UUID, remoteClient.AgentId)
195 || Permissions.CanMoveObject(sog.UUID, remoteClient.AgentId))
196 {
197 EventManager.TriggerParcelPrimCountTainted();
198 }
199 }
200 else
201 {
202 part.SendPropertiesToClient(remoteClient);
203 }
204 }
205
206 /// <summary>
207 /// Handle the update of an object's user group.
208 /// </summary>
209 /// <param name="remoteClient"></param>
210 /// <param name="groupID"></param>
211 /// <param name="objectLocalID"></param>
212 /// <param name="Garbage"></param>
213 private void HandleObjectGroupUpdate(
214 IClientAPI remoteClient, UUID groupID, uint objectLocalID, UUID Garbage)
215 {
216 if (m_groupsModule == null)
217 return;
218
219 // XXX: Might be better to get rid of this special casing and have GetMembershipData return something
220 // reasonable for a UUID.Zero group.
221 if (groupID != UUID.Zero)
222 {
223 GroupMembershipData gmd = m_groupsModule.GetMembershipData(groupID, remoteClient.AgentId);
224
225 if (gmd == null)
226 {
227// m_log.WarnFormat(
228// "[GROUPS]: User {0} is not a member of group {1} so they can't update {2} to this group",
229// remoteClient.Name, GroupID, objectLocalID);
230
231 return;
232 }
233 }
234
235 SceneObjectGroup so = ((Scene)remoteClient.Scene).GetGroupByPrim(objectLocalID);
236 if (so != null)
237 {
238 if (so.OwnerID == remoteClient.AgentId)
239 {
240 so.SetGroup(groupID, remoteClient);
241 }
242 }
243 }
244
245 /// <summary>
246 /// Handle the deselection of a prim from the client.
247 /// </summary>
248 /// <param name="primLocalID"></param>
249 /// <param name="remoteClient"></param>
250 public void DeselectPrim(uint primLocalID, IClientAPI remoteClient)
251 {
252 SceneObjectPart part = GetSceneObjectPart(primLocalID);
253 if (part == null)
254 return;
255
256 // A deselect packet contains all the local prims being deselected. However, since selection is still
257 // group based we only want the root prim to trigger a full update - otherwise on objects with many prims
258 // we end up sending many duplicate ObjectUpdates
259 if (part.ParentGroup.RootPart.LocalId != part.LocalId)
260 return;
261
262 // This is wrong, wrong, wrong. Selection should not be
263 // handled by group, but by prim. Legacy cruft.
264 // TODO: Make selection flagging per prim!
265 //
266 part.ParentGroup.IsSelected = false;
267
268 part.ParentGroup.ScheduleGroupForFullUpdate();
269
270 // If it's not an attachment, and we are allowed to move it,
271 // then we might have done so. If we moved across a parcel
272 // boundary, we will need to recount prims on the parcels.
273 // For attachments, that makes no sense.
274 //
275 if (!part.ParentGroup.IsAttachment)
276 {
277 if (Permissions.CanEditObject(
278 part.UUID, remoteClient.AgentId)
279 || Permissions.CanMoveObject(
280 part.UUID, remoteClient.AgentId))
281 EventManager.TriggerParcelPrimCountTainted();
282 }
283 }
284
285 public virtual void ProcessMoneyTransferRequest(UUID source, UUID destination, int amount,
286 int transactiontype, string description)
287 {
288 EventManager.MoneyTransferArgs args = new EventManager.MoneyTransferArgs(source, destination, amount,
289 transactiontype, description);
290
291 EventManager.TriggerMoneyTransfer(this, args);
292 }
293
294 public virtual void ProcessParcelBuy(UUID agentId, UUID groupId, bool final, bool groupOwned,
295 bool removeContribution, int parcelLocalID, int parcelArea, int parcelPrice, bool authenticated)
296 {
297 EventManager.LandBuyArgs args = new EventManager.LandBuyArgs(agentId, groupId, final, groupOwned,
298 removeContribution, parcelLocalID, parcelArea,
299 parcelPrice, authenticated);
300
301 // First, allow all validators a stab at it
302 m_eventManager.TriggerValidateLandBuy(this, args);
303
304 // Then, check validation and transfer
305 m_eventManager.TriggerLandBuy(this, args);
306 }
307
308 public virtual void ProcessObjectGrab(uint localID, Vector3 offsetPos, IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs)
309 {
310 SceneObjectPart part = GetSceneObjectPart(localID);
311
312 if (part == null)
313 return;
314
315 SceneObjectGroup obj = part.ParentGroup;
316
317 SurfaceTouchEventArgs surfaceArg = null;
318 if (surfaceArgs != null && surfaceArgs.Count > 0)
319 surfaceArg = surfaceArgs[0];
320
321 // Currently only grab/touch for the single prim
322 // the client handles rez correctly
323 obj.ObjectGrabHandler(localID, offsetPos, remoteClient);
324
325 // If the touched prim handles touches, deliver it
326 // If not, deliver to root prim
327 if ((part.ScriptEvents & scriptEvents.touch_start) != 0)
328 EventManager.TriggerObjectGrab(part.LocalId, 0, part.OffsetPosition, remoteClient, surfaceArg);
329
330 // Deliver to the root prim if the touched prim doesn't handle touches
331 // or if we're meant to pass on touches anyway. Don't send to root prim
332 // if prim touched is the root prim as we just did it
333 if (((part.ScriptEvents & scriptEvents.touch_start) == 0) ||
334 (part.PassTouches && (part.LocalId != obj.RootPart.LocalId)))
335 {
336 EventManager.TriggerObjectGrab(obj.RootPart.LocalId, part.LocalId, part.OffsetPosition, remoteClient, surfaceArg);
337 }
338 }
339
340 public virtual void ProcessObjectGrabUpdate(
341 UUID objectID, Vector3 offset, Vector3 pos, IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs)
342 {
343 SceneObjectPart part = GetSceneObjectPart(objectID);
344 if (part == null)
345 return;
346
347 SceneObjectGroup obj = part.ParentGroup;
348
349 SurfaceTouchEventArgs surfaceArg = null;
350 if (surfaceArgs != null && surfaceArgs.Count > 0)
351 surfaceArg = surfaceArgs[0];
352
353 // If the touched prim handles touches, deliver it
354 // If not, deliver to root prim
355 if ((part.ScriptEvents & scriptEvents.touch) != 0)
356 EventManager.TriggerObjectGrabbing(part.LocalId, 0, part.OffsetPosition, remoteClient, surfaceArg);
357 // Deliver to the root prim if the touched prim doesn't handle touches
358 // or if we're meant to pass on touches anyway. Don't send to root prim
359 // if prim touched is the root prim as we just did it
360 if (((part.ScriptEvents & scriptEvents.touch) == 0) ||
361 (part.PassTouches && (part.LocalId != obj.RootPart.LocalId)))
362 {
363 EventManager.TriggerObjectGrabbing(obj.RootPart.LocalId, part.LocalId, part.OffsetPosition, remoteClient, surfaceArg);
364 }
365 }
366
367 public virtual void ProcessObjectDeGrab(uint localID, IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs)
368 {
369 SceneObjectPart part = GetSceneObjectPart(localID);
370 if (part == null)
371 return;
372
373 SceneObjectGroup obj = part.ParentGroup;
374
375 SurfaceTouchEventArgs surfaceArg = null;
376 if (surfaceArgs != null && surfaceArgs.Count > 0)
377 surfaceArg = surfaceArgs[0];
378
379 // If the touched prim handles touches, deliver it
380 // If not, deliver to root prim
381 if ((part.ScriptEvents & scriptEvents.touch_end) != 0)
382 EventManager.TriggerObjectDeGrab(part.LocalId, 0, remoteClient, surfaceArg);
383 else
384 EventManager.TriggerObjectDeGrab(obj.RootPart.LocalId, part.LocalId, remoteClient, surfaceArg);
385 }
386
387 public void ProcessScriptReset(IClientAPI remoteClient, UUID objectID,
388 UUID itemID)
389 {
390 SceneObjectPart part=GetSceneObjectPart(objectID);
391 if (part == null)
392 return;
393
394 if (Permissions.CanResetScript(objectID, itemID, remoteClient.AgentId))
395 {
396 EventManager.TriggerScriptReset(part.LocalId, itemID);
397 }
398 }
399
400 void ProcessViewerEffect(IClientAPI remoteClient, List<ViewerEffectEventHandlerArg> args)
401 {
402 // TODO: don't create new blocks if recycling an old packet
403 bool discardableEffects = true;
404 ViewerEffectPacket.EffectBlock[] effectBlockArray = new ViewerEffectPacket.EffectBlock[args.Count];
405 for (int i = 0; i < args.Count; i++)
406 {
407 ViewerEffectPacket.EffectBlock effect = new ViewerEffectPacket.EffectBlock();
408 effect.AgentID = args[i].AgentID;
409 effect.Color = args[i].Color;
410 effect.Duration = args[i].Duration;
411 effect.ID = args[i].ID;
412 effect.Type = args[i].Type;
413 effect.TypeData = args[i].TypeData;
414 effectBlockArray[i] = effect;
415
416 if ((EffectType)effect.Type != EffectType.LookAt && (EffectType)effect.Type != EffectType.Beam)
417 discardableEffects = false;
418
419 //m_log.DebugFormat("[YYY]: VE {0} {1} {2}", effect.AgentID, effect.Duration, (EffectType)effect.Type);
420 }
421
422 ForEachScenePresence(sp =>
423 {
424 if (sp.ControllingClient.AgentId != remoteClient.AgentId)
425 {
426 if (!discardableEffects ||
427 (discardableEffects && ShouldSendDiscardableEffect(remoteClient, sp)))
428 {
429 //m_log.DebugFormat("[YYY]: Sending to {0}", sp.UUID);
430 sp.ControllingClient.SendViewerEffect(effectBlockArray);
431 }
432 //else
433 // m_log.DebugFormat("[YYY]: Not sending to {0}", sp.UUID);
434 }
435 });
436 }
437
438 private bool ShouldSendDiscardableEffect(IClientAPI thisClient, ScenePresence other)
439 {
440 return Vector3.Distance(other.CameraPosition, thisClient.SceneAgent.AbsolutePosition) < 10;
441 }
442
443 /// <summary>
444 /// Tell the client about the various child items and folders contained in the requested folder.
445 /// </summary>
446 /// <param name="remoteClient"></param>
447 /// <param name="folderID"></param>
448 /// <param name="ownerID"></param>
449 /// <param name="fetchFolders"></param>
450 /// <param name="fetchItems"></param>
451 /// <param name="sortOrder"></param>
452 public void HandleFetchInventoryDescendents(IClientAPI remoteClient, UUID folderID, UUID ownerID,
453 bool fetchFolders, bool fetchItems, int sortOrder)
454 {
455// m_log.DebugFormat(
456// "[USER INVENTORY]: HandleFetchInventoryDescendents() for {0}, folder={1}, fetchFolders={2}, fetchItems={3}, sortOrder={4}",
457// remoteClient.Name, folderID, fetchFolders, fetchItems, sortOrder);
458
459 if (folderID == UUID.Zero)
460 return;
461
462 // FIXME MAYBE: We're not handling sortOrder!
463
464 // TODO: This code for looking in the folder for the library should be folded somewhere else
465 // so that this class doesn't have to know the details (and so that multiple libraries, etc.
466 // can be handled transparently).
467 InventoryFolderImpl fold = null;
468 if (LibraryService != null && LibraryService.LibraryRootFolder != null)
469 {
470 if ((fold = LibraryService.LibraryRootFolder.FindFolder(folderID)) != null)
471 {
472 remoteClient.SendInventoryFolderDetails(
473 fold.Owner, folderID, fold.RequestListOfItems(),
474 fold.RequestListOfFolders(), fold.Version, fetchFolders, fetchItems);
475 return;
476 }
477 }
478
479 // We're going to send the reply async, because there may be
480 // an enormous quantity of packets -- basically the entire inventory!
481 // We don't want to block the client thread while all that is happening.
482 SendInventoryDelegate d = SendInventoryAsync;
483 d.BeginInvoke(remoteClient, folderID, ownerID, fetchFolders, fetchItems, sortOrder, SendInventoryComplete, d);
484 }
485
486 delegate void SendInventoryDelegate(IClientAPI remoteClient, UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, int sortOrder);
487
488 void SendInventoryAsync(IClientAPI remoteClient, UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, int sortOrder)
489 {
490 try
491 {
492 SendInventoryUpdate(remoteClient, new InventoryFolderBase(folderID), fetchFolders, fetchItems);
493 }
494 catch (Exception e)
495 {
496 m_log.Error(
497 string.Format(
498 "[AGENT INVENTORY]: Error in SendInventoryAsync() for {0} with folder ID {1}. Exception ", e));
499 }
500 }
501
502 void SendInventoryComplete(IAsyncResult iar)
503 {
504 SendInventoryDelegate d = (SendInventoryDelegate)iar.AsyncState;
505 d.EndInvoke(iar);
506 }
507
508 /// <summary>
509 /// Handle an inventory folder creation request from the client.
510 /// </summary>
511 /// <param name="remoteClient"></param>
512 /// <param name="folderID"></param>
513 /// <param name="folderType"></param>
514 /// <param name="folderName"></param>
515 /// <param name="parentID"></param>
516 public void HandleCreateInventoryFolder(IClientAPI remoteClient, UUID folderID, ushort folderType,
517 string folderName, UUID parentID)
518 {
519 InventoryFolderBase folder = new InventoryFolderBase(folderID, folderName, remoteClient.AgentId, (short)folderType, parentID, 1);
520 if (!InventoryService.AddFolder(folder))
521 {
522 m_log.WarnFormat(
523 "[AGENT INVENTORY]: Failed to create folder for user {0} {1}",
524 remoteClient.Name, remoteClient.AgentId);
525 }
526 }
527
528 /// <summary>
529 /// Handle a client request to update the inventory folder
530 /// </summary>
531 ///
532 /// FIXME: We call add new inventory folder because in the data layer, we happen to use an SQL REPLACE
533 /// so this will work to rename an existing folder. Needless to say, to rely on this is very confusing,
534 /// and needs to be changed.
535 ///
536 /// <param name="remoteClient"></param>
537 /// <param name="folderID"></param>
538 /// <param name="type"></param>
539 /// <param name="name"></param>
540 /// <param name="parentID"></param>
541 public void HandleUpdateInventoryFolder(IClientAPI remoteClient, UUID folderID, ushort type, string name,
542 UUID parentID)
543 {
544// m_log.DebugFormat(
545// "[AGENT INVENTORY]: Updating inventory folder {0} {1} for {2} {3}", folderID, name, remoteClient.Name, remoteClient.AgentId);
546
547 InventoryFolderBase folder = new InventoryFolderBase(folderID, remoteClient.AgentId);
548 folder = InventoryService.GetFolder(folder);
549 if (folder != null)
550 {
551 folder.Name = name;
552 folder.Type = (short)type;
553 folder.ParentID = parentID;
554 if (!InventoryService.UpdateFolder(folder))
555 {
556 m_log.ErrorFormat(
557 "[AGENT INVENTORY]: Failed to update folder for user {0} {1}",
558 remoteClient.Name, remoteClient.AgentId);
559 }
560 }
561 }
562
563 public void HandleMoveInventoryFolder(IClientAPI remoteClient, UUID folderID, UUID parentID)
564 {
565 InventoryFolderBase folder = new InventoryFolderBase(folderID, remoteClient.AgentId);
566 folder = InventoryService.GetFolder(folder);
567 if (folder != null)
568 {
569 folder.ParentID = parentID;
570 if (!InventoryService.MoveFolder(folder))
571 m_log.WarnFormat("[AGENT INVENTORY]: could not move folder {0}", folderID);
572 else
573 m_log.DebugFormat("[AGENT INVENTORY]: folder {0} moved to parent {1}", folderID, parentID);
574 }
575 else
576 {
577 m_log.WarnFormat("[AGENT INVENTORY]: request to move folder {0} but folder not found", folderID);
578 }
579 }
580
581 delegate void PurgeFolderDelegate(UUID userID, UUID folder);
582
583 /// <summary>
584 /// This should delete all the items and folders in the given directory.
585 /// </summary>
586 /// <param name="remoteClient"></param>
587 /// <param name="folderID"></param>
588 public void HandlePurgeInventoryDescendents(IClientAPI remoteClient, UUID folderID)
589 {
590 PurgeFolderDelegate d = PurgeFolderAsync;
591 try
592 {
593 d.BeginInvoke(remoteClient.AgentId, folderID, PurgeFolderCompleted, d);
594 }
595 catch (Exception e)
596 {
597 m_log.WarnFormat("[AGENT INVENTORY]: Exception on purge folder for user {0}: {1}", remoteClient.AgentId, e.Message);
598 }
599 }
600
601 private void PurgeFolderAsync(UUID userID, UUID folderID)
602 {
603 InventoryFolderBase folder = new InventoryFolderBase(folderID, userID);
604
605 if (InventoryService.PurgeFolder(folder))
606 m_log.DebugFormat("[AGENT INVENTORY]: folder {0} purged successfully", folderID);
607 else
608 m_log.WarnFormat("[AGENT INVENTORY]: could not purge folder {0}", folderID);
609 }
610
611 private void PurgeFolderCompleted(IAsyncResult iar)
612 {
613 PurgeFolderDelegate d = (PurgeFolderDelegate)iar.AsyncState;
614 d.EndInvoke(iar);
615 }
616 }
617}