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.cs632
1 files changed, 632 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..039b81b
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
@@ -0,0 +1,632 @@
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 OpenSim 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.Collections.Generic;
29using System.Threading;
30using OpenMetaverse;
31using OpenMetaverse.Packets;
32using OpenSim.Framework;
33using OpenSim.Framework.Communications;
34using OpenSim.Framework.Communications.Cache;
35
36namespace OpenSim.Region.Framework.Scenes
37{
38 public partial class Scene
39 {
40 protected void SimChat(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName,
41 UUID fromID, bool fromAgent, bool broadcast)
42 {
43 OSChatMessage args = new OSChatMessage();
44
45 args.Message = Utils.BytesToString(message);
46 args.Channel = channel;
47 args.Type = type;
48 args.Position = fromPos;
49 args.SenderUUID = fromID;
50 args.Scene = this;
51
52 if (fromAgent)
53 {
54 ScenePresence user = GetScenePresence(fromID);
55 if (user != null)
56 args.Sender = user.ControllingClient;
57 }
58 else
59 {
60 SceneObjectPart obj = GetSceneObjectPart(fromID);
61 args.SenderObject = obj;
62 }
63
64 args.From = fromName;
65 //args.
66
67 if (broadcast)
68 EventManager.TriggerOnChatBroadcast(this, args);
69 else
70 EventManager.TriggerOnChatFromWorld(this, args);
71
72 }
73 /// <summary>
74 ///
75 /// </summary>
76 /// <param name="message"></param>
77 /// <param name="type"></param>
78 /// <param name="fromPos"></param>
79 /// <param name="fromName"></param>
80 /// <param name="fromAgentID"></param>
81 public void SimChat(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName,
82 UUID fromID, bool fromAgent)
83 {
84 SimChat(message, type, channel, fromPos, fromName, fromID, fromAgent, false);
85 }
86
87 /// <summary>
88 ///
89 /// </summary>
90 /// <param name="message"></param>
91 /// <param name="type"></param>
92 /// <param name="fromPos"></param>
93 /// <param name="fromName"></param>
94 /// <param name="fromAgentID"></param>
95 public void SimChatBroadcast(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName,
96 UUID fromID, bool fromAgent)
97 {
98 SimChat(message, type, channel, fromPos, fromName, fromID, fromAgent, true);
99 }
100
101 /// <summary>
102 /// Invoked when the client selects a prim.
103 /// </summary>
104 /// <param name="primLocalID"></param>
105 /// <param name="remoteClient"></param>
106 public void SelectPrim(uint primLocalID, IClientAPI remoteClient)
107 {
108 List<EntityBase> EntityList = GetEntities();
109
110 foreach (EntityBase ent in EntityList)
111 {
112 if (ent is SceneObjectGroup)
113 {
114 if (((SceneObjectGroup) ent).LocalId == primLocalID)
115 {
116 ((SceneObjectGroup) ent).GetProperties(remoteClient);
117 ((SceneObjectGroup) ent).IsSelected = true;
118 // A prim is only tainted if it's allowed to be edited by the person clicking it.
119 if (Permissions.CanEditObject(((SceneObjectGroup)ent).UUID, remoteClient.AgentId)
120 || Permissions.CanMoveObject(((SceneObjectGroup)ent).UUID, remoteClient.AgentId))
121 {
122 EventManager.TriggerParcelPrimCountTainted();
123 }
124 break;
125 }
126 else
127 {
128 // We also need to check the children of this prim as they
129 // can be selected as well and send property information
130 bool foundPrim = false;
131 foreach (KeyValuePair<UUID, SceneObjectPart> child in ((SceneObjectGroup) ent).Children)
132 {
133 if (child.Value.LocalId == primLocalID)
134 {
135 child.Value.GetProperties(remoteClient);
136 foundPrim = true;
137 break;
138 }
139 }
140 if (foundPrim) break;
141 }
142 }
143 }
144 }
145
146 /// <summary>
147 /// Handle the deselection of a prim from the client.
148 /// </summary>
149 /// <param name="primLocalID"></param>
150 /// <param name="remoteClient"></param>
151 public void DeselectPrim(uint primLocalID, IClientAPI remoteClient)
152 {
153 SceneObjectPart part = GetSceneObjectPart(primLocalID);
154 if (part == null)
155 return;
156
157 // The prim is in the process of being deleted.
158 if (null == part.ParentGroup.RootPart)
159 return;
160
161 // A deselect packet contains all the local prims being deselected. However, since selection is still
162 // group based we only want the root prim to trigger a full update - otherwise on objects with many prims
163 // we end up sending many duplicate ObjectUpdates
164 if (part.ParentGroup.RootPart.LocalId != part.LocalId)
165 return;
166
167 bool isAttachment = false;
168
169 // This is wrong, wrong, wrong. Selection should not be
170 // handled by group, but by prim. Legacy cruft.
171 // TODO: Make selection flagging per prim!
172 //
173 part.ParentGroup.IsSelected = false;
174
175 if (part.ParentGroup.IsAttachment)
176 isAttachment = true;
177 else
178 part.ParentGroup.ScheduleGroupForFullUpdate();
179
180 // If it's not an attachment, and we are allowed to move it,
181 // then we might have done so. If we moved across a parcel
182 // boundary, we will need to recount prims on the parcels.
183 // For attachments, that makes no sense.
184 //
185 if (!isAttachment)
186 {
187 if (Permissions.CanEditObject(
188 part.UUID, remoteClient.AgentId)
189 || Permissions.CanMoveObject(
190 part.UUID, remoteClient.AgentId))
191 EventManager.TriggerParcelPrimCountTainted();
192 }
193 }
194
195 public virtual void ProcessMoneyTransferRequest(UUID source, UUID destination, int amount,
196 int transactiontype, string description)
197 {
198 EventManager.MoneyTransferArgs args = new EventManager.MoneyTransferArgs(source, destination, amount,
199 transactiontype, description);
200
201 EventManager.TriggerMoneyTransfer(this, args);
202 }
203
204 public virtual void ProcessParcelBuy(UUID agentId, UUID groupId, bool final, bool groupOwned,
205 bool removeContribution, int parcelLocalID, int parcelArea, int parcelPrice, bool authenticated)
206 {
207 EventManager.LandBuyArgs args = new EventManager.LandBuyArgs(agentId, groupId, final, groupOwned,
208 removeContribution, parcelLocalID, parcelArea,
209 parcelPrice, authenticated);
210
211 // First, allow all validators a stab at it
212 m_eventManager.TriggerValidateLandBuy(this, args);
213
214 // Then, check validation and transfer
215 m_eventManager.TriggerLandBuy(this, args);
216 }
217
218 public virtual void ProcessObjectGrab(uint localID, Vector3 offsetPos, IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs)
219 {
220 List<EntityBase> EntityList = GetEntities();
221
222 SurfaceTouchEventArgs surfaceArg = null;
223 if (surfaceArgs != null && surfaceArgs.Count > 0)
224 surfaceArg = surfaceArgs[0];
225
226 foreach (EntityBase ent in EntityList)
227 {
228 if (ent is SceneObjectGroup)
229 {
230 SceneObjectGroup obj = ent as SceneObjectGroup;
231 if (obj != null)
232 {
233 // Is this prim part of the group
234 if (obj.HasChildPrim(localID))
235 {
236 // Currently only grab/touch for the single prim
237 // the client handles rez correctly
238 obj.ObjectGrabHandler(localID, offsetPos, remoteClient);
239
240 SceneObjectPart part = obj.GetChildPart(localID);
241
242 // If the touched prim handles touches, deliver it
243 // If not, deliver to root prim
244 if ((part.ScriptEvents & scriptEvents.touch_start) != 0)
245 EventManager.TriggerObjectGrab(part.LocalId, 0, part.OffsetPosition, remoteClient, surfaceArg);
246 else
247 EventManager.TriggerObjectGrab(obj.RootPart.LocalId, part.LocalId, part.OffsetPosition, remoteClient, surfaceArg);
248
249 return;
250 }
251 }
252 }
253 }
254 }
255
256 public virtual void ProcessObjectDeGrab(uint localID, IClientAPI remoteClient)
257 {
258 List<EntityBase> EntityList = GetEntities();
259
260 foreach (EntityBase ent in EntityList)
261 {
262 if (ent is SceneObjectGroup)
263 {
264 SceneObjectGroup obj = ent as SceneObjectGroup;
265
266 // Is this prim part of the group
267 if (obj.HasChildPrim(localID))
268 {
269 SceneObjectPart part=obj.GetChildPart(localID);
270 if (part != null)
271 {
272 // If the touched prim handles touches, deliver it
273 // If not, deliver to root prim
274 if ((part.ScriptEvents & scriptEvents.touch_end) != 0)
275 EventManager.TriggerObjectDeGrab(part.LocalId, 0, remoteClient);
276 else
277 EventManager.TriggerObjectDeGrab(obj.RootPart.LocalId, part.LocalId, remoteClient);
278
279 return;
280 }
281 return;
282 }
283 }
284 }
285 }
286
287 public void ProcessAvatarPickerRequest(IClientAPI client, UUID avatarID, UUID RequestID, string query)
288 {
289 //EventManager.TriggerAvatarPickerRequest();
290
291 List<AvatarPickerAvatar> AvatarResponses = new List<AvatarPickerAvatar>();
292 AvatarResponses = m_sceneGridService.GenerateAgentPickerRequestResponse(RequestID, query);
293
294 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket) PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply);
295 // TODO: don't create new blocks if recycling an old packet
296
297 AvatarPickerReplyPacket.DataBlock[] searchData =
298 new AvatarPickerReplyPacket.DataBlock[AvatarResponses.Count];
299 AvatarPickerReplyPacket.AgentDataBlock agentData = new AvatarPickerReplyPacket.AgentDataBlock();
300
301 agentData.AgentID = avatarID;
302 agentData.QueryID = RequestID;
303 replyPacket.AgentData = agentData;
304 //byte[] bytes = new byte[AvatarResponses.Count*32];
305
306 int i = 0;
307 foreach (AvatarPickerAvatar item in AvatarResponses)
308 {
309 UUID translatedIDtem = item.AvatarID;
310 searchData[i] = new AvatarPickerReplyPacket.DataBlock();
311 searchData[i].AvatarID = translatedIDtem;
312 searchData[i].FirstName = Utils.StringToBytes((string) item.firstName);
313 searchData[i].LastName = Utils.StringToBytes((string) item.lastName);
314 i++;
315 }
316 if (AvatarResponses.Count == 0)
317 {
318 searchData = new AvatarPickerReplyPacket.DataBlock[0];
319 }
320 replyPacket.Data = searchData;
321
322 AvatarPickerReplyAgentDataArgs agent_data = new AvatarPickerReplyAgentDataArgs();
323 agent_data.AgentID = replyPacket.AgentData.AgentID;
324 agent_data.QueryID = replyPacket.AgentData.QueryID;
325
326 List<AvatarPickerReplyDataArgs> data_args = new List<AvatarPickerReplyDataArgs>();
327 for (i = 0; i < replyPacket.Data.Length; i++)
328 {
329 AvatarPickerReplyDataArgs data_arg = new AvatarPickerReplyDataArgs();
330 data_arg.AvatarID = replyPacket.Data[i].AvatarID;
331 data_arg.FirstName = replyPacket.Data[i].FirstName;
332 data_arg.LastName = replyPacket.Data[i].LastName;
333 data_args.Add(data_arg);
334 }
335 client.SendAvatarPickerReply(agent_data, data_args);
336 }
337
338 public void ProcessScriptReset(IClientAPI remoteClient, UUID objectID,
339 UUID itemID)
340 {
341 SceneObjectPart part=GetSceneObjectPart(objectID);
342 if (part == null)
343 return;
344
345 if (Permissions.CanResetScript(objectID, itemID, remoteClient.AgentId))
346 {
347 EventManager.TriggerScriptReset(part.LocalId, itemID);
348 }
349 }
350
351 /// <summary>
352 /// Handle a fetch inventory request from the client
353 /// </summary>
354 /// <param name="remoteClient"></param>
355 /// <param name="itemID"></param>
356 /// <param name="ownerID"></param>
357 public void HandleFetchInventory(IClientAPI remoteClient, UUID itemID, UUID ownerID)
358 {
359 if (ownerID == CommsManager.UserProfileCacheService.LibraryRoot.Owner)
360 {
361 //Console.WriteLine("request info for library item");
362 return;
363 }
364
365 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
366
367 if (null == userProfile)
368 {
369 m_log.ErrorFormat(
370 "[AGENT INVENTORY]: Could not find user profile for {0} {1}",
371 remoteClient.Name, remoteClient.AgentId);
372 return;
373 }
374
375 if (userProfile.HasReceivedInventory)
376 {
377 InventoryItemBase item = null;
378 if (userProfile.RootFolder == null)
379 m_log.ErrorFormat(
380 "[AGENT INVENTORY]: User {0} {1} does not have a root folder.",
381 remoteClient.Name, remoteClient.AgentId);
382 else
383 item = userProfile.RootFolder.FindItem(itemID);
384
385 if (item != null)
386 {
387 remoteClient.SendInventoryItemDetails(ownerID, item);
388 }
389 }
390 }
391
392 /// <summary>
393 /// Tell the client about the various child items and folders contained in the requested folder.
394 /// </summary>
395 /// <param name="remoteClient"></param>
396 /// <param name="folderID"></param>
397 /// <param name="ownerID"></param>
398 /// <param name="fetchFolders"></param>
399 /// <param name="fetchItems"></param>
400 /// <param name="sortOrder"></param>
401 public void HandleFetchInventoryDescendents(IClientAPI remoteClient, UUID folderID, UUID ownerID,
402 bool fetchFolders, bool fetchItems, int sortOrder)
403 {
404 // FIXME MAYBE: We're not handling sortOrder!
405
406 // TODO: This code for looking in the folder for the library should be folded back into the
407 // CachedUserInfo so that this class doesn't have to know the details (and so that multiple libraries, etc.
408 // can be handled transparently).
409 InventoryFolderImpl fold = null;
410 if ((fold = CommsManager.UserProfileCacheService.LibraryRoot.FindFolder(folderID)) != null)
411 {
412 remoteClient.SendInventoryFolderDetails(
413 fold.Owner, folderID, fold.RequestListOfItems(),
414 fold.RequestListOfFolders(), fetchFolders, fetchItems);
415 return;
416 }
417
418 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
419
420 if (null == userProfile)
421 {
422 m_log.ErrorFormat(
423 "[AGENT INVENTORY]: Could not find user profile for {0} {1}",
424 remoteClient.Name, remoteClient.AgentId);
425 return;
426 }
427
428 userProfile.SendInventoryDecendents(remoteClient, folderID, fetchFolders, fetchItems);
429 }
430
431 /// <summary>
432 /// Handle the caps inventory descendents fetch.
433 ///
434 /// Since the folder structure is sent to the client on login, I believe we only need to handle items.
435 /// </summary>
436 /// <param name="agentID"></param>
437 /// <param name="folderID"></param>
438 /// <param name="ownerID"></param>
439 /// <param name="fetchFolders"></param>
440 /// <param name="fetchItems"></param>
441 /// <param name="sortOrder"></param>
442 /// <returns>null if the inventory look up failed</returns>
443 public List<InventoryItemBase> HandleFetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID,
444 bool fetchFolders, bool fetchItems, int sortOrder)
445 {
446// m_log.DebugFormat(
447// "[INVENTORY CACHE]: Fetching folders ({0}), items ({1}) from {2} for agent {3}",
448// fetchFolders, fetchItems, folderID, agentID);
449
450 // FIXME MAYBE: We're not handling sortOrder!
451
452 // TODO: This code for looking in the folder for the library should be folded back into the
453 // CachedUserInfo so that this class doesn't have to know the details (and so that multiple libraries, etc.
454 // can be handled transparently).
455 InventoryFolderImpl fold;
456 if ((fold = CommsManager.UserProfileCacheService.LibraryRoot.FindFolder(folderID)) != null)
457 {
458 return fold.RequestListOfItems();
459 }
460
461 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(agentID);
462
463 if (null == userProfile)
464 {
465 m_log.ErrorFormat("[AGENT INVENTORY]: Could not find user profile for {0}", agentID);
466 return null;
467 }
468
469 // XXX: When a client crosses into a scene, their entire inventory is fetched
470 // asynchronously. If the client makes a request before the inventory is received, we need
471 // to give the inventory a chance to come in.
472 //
473 // This is a crude way of dealing with that by retrying the lookup. It's not quite as bad
474 // in CAPS as doing this with the udp request, since here it won't hold up other packets.
475 // In fact, here we'll be generous and try for longer.
476 if (!userProfile.HasReceivedInventory)
477 {
478 int attempts = 0;
479 while (attempts++ < 30)
480 {
481 m_log.DebugFormat(
482 "[INVENTORY CACHE]: Poll number {0} for inventory items in folder {1} for user {2}",
483 attempts, folderID, agentID);
484
485 Thread.Sleep(2000);
486
487 if (userProfile.HasReceivedInventory)
488 {
489 break;
490 }
491 }
492 }
493
494 if (userProfile.HasReceivedInventory)
495 {
496 if ((fold = userProfile.RootFolder.FindFolder(folderID)) != null)
497 {
498 return fold.RequestListOfItems();
499 }
500 else
501 {
502 m_log.WarnFormat(
503 "[AGENT INVENTORY]: Could not find folder {0} requested by user {1}",
504 folderID, agentID);
505 return null;
506 }
507 }
508 else
509 {
510 m_log.ErrorFormat("[INVENTORY CACHE]: Could not find root folder for user {0}", agentID);
511 return null;
512 }
513 }
514
515 /// <summary>
516 /// Handle an inventory folder creation request from the client.
517 /// </summary>
518 /// <param name="remoteClient"></param>
519 /// <param name="folderID"></param>
520 /// <param name="folderType"></param>
521 /// <param name="folderName"></param>
522 /// <param name="parentID"></param>
523 public void HandleCreateInventoryFolder(IClientAPI remoteClient, UUID folderID, ushort folderType,
524 string folderName, UUID parentID)
525 {
526 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
527
528 if (null == userProfile)
529 {
530 m_log.ErrorFormat(
531 "[AGENT INVENTORY]: Could not find user profile for {0} {1}",
532 remoteClient.Name, remoteClient.AgentId);
533 return;
534 }
535
536 if (!userProfile.CreateFolder(folderName, folderID, folderType, parentID))
537 {
538 m_log.ErrorFormat(
539 "[AGENT INVENTORY]: Failed to move create folder for user {0} {1}",
540 remoteClient.Name, remoteClient.AgentId);
541 }
542 }
543
544 /// <summary>
545 /// Handle a client request to update the inventory folder
546 /// </summary>
547 ///
548 /// FIXME: We call add new inventory folder because in the data layer, we happen to use an SQL REPLACE
549 /// so this will work to rename an existing folder. Needless to say, to rely on this is very confusing,
550 /// and needs to be changed.
551 ///
552 /// <param name="remoteClient"></param>
553 /// <param name="folderID"></param>
554 /// <param name="type"></param>
555 /// <param name="name"></param>
556 /// <param name="parentID"></param>
557 public void HandleUpdateInventoryFolder(IClientAPI remoteClient, UUID folderID, ushort type, string name,
558 UUID parentID)
559 {
560// m_log.DebugFormat(
561// "[AGENT INVENTORY]: Updating inventory folder {0} {1} for {2} {3}", folderID, name, remoteClient.Name, remoteClient.AgentId);
562
563 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
564
565 if (null == userProfile)
566 {
567 m_log.ErrorFormat(
568 "[AGENT INVENTORY]: Could not find user profile for {0} {1}",
569 remoteClient.Name, remoteClient.AgentId);
570 return;
571 }
572
573 if (!userProfile.UpdateFolder(name, folderID, type, parentID))
574 {
575 m_log.ErrorFormat(
576 "[AGENT INVENTORY]: Failed to update folder for user {0} {1}",
577 remoteClient.Name, remoteClient.AgentId);
578 }
579 }
580
581 /// <summary>
582 /// Handle an inventory folder move request from the client.
583 /// </summary>
584 /// <param name="remoteClient"></param>
585 /// <param name="folderID"></param>
586 /// <param name="parentID"></param>
587 public void HandleMoveInventoryFolder(IClientAPI remoteClient, UUID folderID, UUID parentID)
588 {
589 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
590
591 if (null == userProfile)
592 {
593 m_log.ErrorFormat(
594 "[AGENT INVENTORY]: Could not find user profile for {0} {1}",
595 remoteClient.Name, remoteClient.AgentId);
596 return;
597 }
598
599 if (!userProfile.MoveFolder(folderID, parentID))
600 {
601 m_log.ErrorFormat(
602 "[AGENT INVENTORY]: Failed to move folder {0} to {1} for user {2}",
603 folderID, parentID, remoteClient.Name);
604 }
605 }
606
607 /// <summary>
608 /// This should delete all the items and folders in the given directory.
609 /// </summary>
610 /// <param name="remoteClient"></param>
611 /// <param name="folderID"></param>
612 public void HandlePurgeInventoryDescendents(IClientAPI remoteClient, UUID folderID)
613 {
614 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
615
616 if (null == userProfile)
617 {
618 m_log.ErrorFormat(
619 "[AGENT INVENTORY]: Could not find user profile for {0} {1}",
620 remoteClient.Name, remoteClient.AgentId);
621 return;
622 }
623
624 if (!userProfile.PurgeFolder(folderID))
625 {
626 m_log.ErrorFormat(
627 "[AGENT INVENTORY]: Failed to purge folder for user {0} {1}",
628 remoteClient.Name, remoteClient.AgentId);
629 }
630 }
631 }
632}