aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs792
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs430
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs544
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs93
-rw-r--r--OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs200
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs168
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs285
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs5
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs30
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs5
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs50
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs31
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs20
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs1
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs198
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs18
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs170
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs1
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs155
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs86
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs120
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs106
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs (renamed from OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs)179
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs192
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs (renamed from OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs)275
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs8
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs166
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs448
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs23
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs3
-rw-r--r--OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs1406
34 files changed, 5038 insertions, 1184 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 58ed554..2f67c4e 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -29,6 +29,7 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Reflection; 30using System.Reflection;
31using System.IO; 31using System.IO;
32using System.Threading;
32using System.Xml; 33using System.Xml;
33using log4net; 34using log4net;
34using Mono.Addins; 35using Mono.Addins;
@@ -48,6 +49,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
48 { 49 {
49 #region INonSharedRegionModule 50 #region INonSharedRegionModule
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 public int DebugLevel { get; set; }
54
55 /// <summary>
56 /// Period to sleep per 100 prims in order to avoid CPU spikes when an avatar with many attachments logs in/changes
57 /// outfit or many avatars with a medium levels of attachments login/change outfit simultaneously.
58 /// </summary>
59 /// <remarks>
60 /// A value of 0 will apply no pause. The pause is specified in milliseconds.
61 /// </remarks>
62 public int ThrottlePer100PrimsRezzed { get; set; }
51 63
52 private Scene m_scene; 64 private Scene m_scene;
53 private IInventoryAccessModule m_invAccessModule; 65 private IInventoryAccessModule m_invAccessModule;
@@ -64,21 +76,127 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
64 { 76 {
65 IConfig config = source.Configs["Attachments"]; 77 IConfig config = source.Configs["Attachments"];
66 if (config != null) 78 if (config != null)
79 {
67 Enabled = config.GetBoolean("Enabled", true); 80 Enabled = config.GetBoolean("Enabled", true);
81
82 ThrottlePer100PrimsRezzed = config.GetInt("ThrottlePer100PrimsRezzed", 0);
83 }
68 else 84 else
85 {
69 Enabled = true; 86 Enabled = true;
87 }
70 } 88 }
71 89
72 public void AddRegion(Scene scene) 90 public void AddRegion(Scene scene)
73 { 91 {
74 m_scene = scene; 92 m_scene = scene;
75 m_scene.RegisterModuleInterface<IAttachmentsModule>(this);
76
77 if (Enabled) 93 if (Enabled)
94 {
95 // Only register module with scene if it is enabled. All callers check for a null attachments module.
96 // Ideally, there should be a null attachments module for when this core attachments module has been
97 // disabled. Registering only when enabled allows for other attachments module implementations.
98 m_scene.RegisterModuleInterface<IAttachmentsModule>(this);
78 m_scene.EventManager.OnNewClient += SubscribeToClientEvents; 99 m_scene.EventManager.OnNewClient += SubscribeToClientEvents;
100 m_scene.EventManager.OnStartScript += (localID, itemID) => HandleScriptStateChange(localID, true);
101 m_scene.EventManager.OnStopScript += (localID, itemID) => HandleScriptStateChange(localID, false);
102
103 MainConsole.Instance.Commands.AddCommand(
104 "Debug",
105 false,
106 "debug attachments log",
107 "debug attachments log [0|1]",
108 "Turn on attachments debug logging",
109 " <= 0 - turns off debug logging\n"
110 + " >= 1 - turns on attachment message debug logging",
111 HandleDebugAttachmentsLog);
112
113 MainConsole.Instance.Commands.AddCommand(
114 "Debug",
115 false,
116 "debug attachments throttle",
117 "debug attachments throttle <ms>",
118 "Turn on attachments throttling.",
119 "This requires a millisecond value. " +
120 " == 0 - disable throttling.\n"
121 + " > 0 - sleeps for this number of milliseconds per 100 prims rezzed.",
122 HandleDebugAttachmentsThrottle);
123
124 MainConsole.Instance.Commands.AddCommand(
125 "Debug",
126 false,
127 "debug attachments status",
128 "debug attachments status",
129 "Show current attachments debug status",
130 HandleDebugAttachmentsStatus);
131 }
79 132
80 // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI 133 // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI
81 } 134 }
135
136 private void HandleDebugAttachmentsLog(string module, string[] args)
137 {
138 int debugLevel;
139
140 if (!(args.Length == 4 && int.TryParse(args[3], out debugLevel)))
141 {
142 MainConsole.Instance.OutputFormat("Usage: debug attachments log [0|1]");
143 }
144 else
145 {
146 DebugLevel = debugLevel;
147 MainConsole.Instance.OutputFormat(
148 "Set attachments debug level to {0} in {1}", DebugLevel, m_scene.Name);
149 }
150 }
151
152 private void HandleDebugAttachmentsThrottle(string module, string[] args)
153 {
154 int ms;
155
156 if (args.Length == 4 && int.TryParse(args[3], out ms))
157 {
158 ThrottlePer100PrimsRezzed = ms;
159 MainConsole.Instance.OutputFormat(
160 "Attachments rez throttle per 100 prims is now {0} in {1}", ThrottlePer100PrimsRezzed, m_scene.Name);
161
162 return;
163 }
164
165 MainConsole.Instance.OutputFormat("Usage: debug attachments throttle <ms>");
166 }
167
168 private void HandleDebugAttachmentsStatus(string module, string[] args)
169 {
170 MainConsole.Instance.OutputFormat("Settings for {0}", m_scene.Name);
171 MainConsole.Instance.OutputFormat("Debug logging level: {0}", DebugLevel);
172 MainConsole.Instance.OutputFormat("Throttle per 100 prims: {0}ms", ThrottlePer100PrimsRezzed);
173 }
174
175 /// <summary>
176 /// Listen for client triggered running state changes so that we can persist the script's object if necessary.
177 /// </summary>
178 /// <param name='localID'></param>
179 /// <param name='itemID'></param>
180 private void HandleScriptStateChange(uint localID, bool started)
181 {
182 SceneObjectGroup sog = m_scene.GetGroupByPrim(localID);
183 if (sog != null && sog.IsAttachment)
184 {
185 if (!started)
186 {
187 // FIXME: This is a convoluted way for working out whether the script state has changed to stop
188 // because it has been manually stopped or because the stop was called in UpdateDetachedObject() below
189 // This needs to be handled in a less tangled way.
190 ScenePresence sp = m_scene.GetScenePresence(sog.AttachedAvatar);
191 if (sp.ControllingClient.IsActive)
192 sog.HasGroupChanged = true;
193 }
194 else
195 {
196 sog.HasGroupChanged = true;
197 }
198 }
199 }
82 200
83 public void RemoveRegion(Scene scene) 201 public void RemoveRegion(Scene scene)
84 { 202 {
@@ -127,8 +245,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
127 string state = sog.GetStateSnapshot(); 245 string state = sog.GetStateSnapshot();
128 ad.AttachmentObjectStates.Add(state); 246 ad.AttachmentObjectStates.Add(state);
129 sp.InTransitScriptStates.Add(state); 247 sp.InTransitScriptStates.Add(state);
130 // Let's remove the scripts of the original object here 248
131 sog.RemoveScriptInstances(true); 249 // Scripts of the originals will be removed when the Agent is successfully removed.
250 // sog.RemoveScriptInstances(true);
132 } 251 }
133 } 252 }
134 } 253 }
@@ -136,6 +255,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
136 255
137 public void CopyAttachments(AgentData ad, IScenePresence sp) 256 public void CopyAttachments(AgentData ad, IScenePresence sp)
138 { 257 {
258// m_log.DebugFormat("[ATTACHMENTS MODULE]: Copying attachment data into {0} in {1}", sp.Name, m_scene.Name);
259
139 if (ad.AttachmentObjects != null && ad.AttachmentObjects.Count > 0) 260 if (ad.AttachmentObjects != null && ad.AttachmentObjects.Count > 0)
140 { 261 {
141 lock (sp.AttachmentsSyncLock) 262 lock (sp.AttachmentsSyncLock)
@@ -146,16 +267,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
146 { 267 {
147 ((SceneObjectGroup)so).LocalId = 0; 268 ((SceneObjectGroup)so).LocalId = 0;
148 ((SceneObjectGroup)so).RootPart.ClearUpdateSchedule(); 269 ((SceneObjectGroup)so).RootPart.ClearUpdateSchedule();
270
271// m_log.DebugFormat(
272// "[ATTACHMENTS MODULE]: Copying script state with {0} bytes for object {1} for {2} in {3}",
273// ad.AttachmentObjectStates[i].Length, so.Name, sp.Name, m_scene.Name);
274
149 so.SetState(ad.AttachmentObjectStates[i++], m_scene); 275 so.SetState(ad.AttachmentObjectStates[i++], m_scene);
150 m_scene.IncomingCreateObject(Vector3.Zero, so); 276 m_scene.IncomingCreateObject(Vector3.Zero, so);
151 } 277 }
152 } 278 }
153 } 279 }
154 280
155 /// <summary>
156 /// RezAttachments. This should only be called upon login on the first region.
157 /// Attachment rezzings on crossings and TPs are done in a different way.
158 /// </summary>
159 public void RezAttachments(IScenePresence sp) 281 public void RezAttachments(IScenePresence sp)
160 { 282 {
161 if (!Enabled) 283 if (!Enabled)
@@ -164,15 +286,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
164 if (null == sp.Appearance) 286 if (null == sp.Appearance)
165 { 287 {
166 m_log.WarnFormat("[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}", sp.UUID); 288 m_log.WarnFormat("[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}", sp.UUID);
289
167 return; 290 return;
168 } 291 }
169 292
170// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0}", sp.Name); 293 if (sp.GetAttachments().Count > 0)
294 {
295 if (DebugLevel > 0)
296 m_log.DebugFormat(
297 "[ATTACHMENTS MODULE]: Not doing simulator-side attachment rez for {0} in {1} as their viewer has already rezzed attachments",
298 m_scene.Name, sp.Name);
299
300 return;
301 }
302
303 if (DebugLevel > 0)
304 m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0} from simulator-side", sp.Name);
171 305
172 List<AvatarAttachment> attachments = sp.Appearance.GetAttachments(); 306 List<AvatarAttachment> attachments = sp.Appearance.GetAttachments();
307
308 // Let's get all items at once, so they get cached
309 UUID[] items = new UUID[attachments.Count];
310 int i = 0;
311 foreach (AvatarAttachment attach in attachments)
312 items[i++] = attach.ItemID;
313 m_scene.InventoryService.GetMultipleItems(sp.UUID, items);
314
173 foreach (AvatarAttachment attach in attachments) 315 foreach (AvatarAttachment attach in attachments)
174 { 316 {
175 uint p = (uint)attach.AttachPoint; 317 uint attachmentPt = (uint)attach.AttachPoint;
176 318
177// m_log.DebugFormat( 319// m_log.DebugFormat(
178// "[ATTACHMENTS MODULE]: Doing initial rez of attachment with itemID {0}, assetID {1}, point {2} for {3} in {4}", 320// "[ATTACHMENTS MODULE]: Doing initial rez of attachment with itemID {0}, assetID {1}, point {2} for {3} in {4}",
@@ -190,16 +332,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
190 { 332 {
191 // If we're an NPC then skip all the item checks and manipulations since we don't have an 333 // If we're an NPC then skip all the item checks and manipulations since we don't have an
192 // inventory right now. 334 // inventory right now.
193 if (sp.PresenceType == PresenceType.Npc) 335 RezSingleAttachmentFromInventoryInternal(
194 RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p); 336 sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, attachmentPt, true);
195 else
196 RezSingleAttachmentFromInventory(sp, attach.ItemID, p);
197 } 337 }
198 catch (Exception e) 338 catch (Exception e)
199 { 339 {
200 UUID agentId = (sp.ControllingClient == null) ? (UUID)null : sp.ControllingClient.AgentId; 340 UUID agentId = (sp.ControllingClient == null) ? default(UUID) : sp.ControllingClient.AgentId;
201 m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment with itemID {0}, assetID {1}, point {2} for {3}: {4}\n{5}", 341 m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment with itemID {0}, assetID {1}, point {2} for {3}: {4}\n{5}",
202 attach.ItemID, attach.AssetID, p, agentId, e.Message, e.StackTrace); 342 attach.ItemID, attach.AssetID, attachmentPt, agentId, e.Message, e.StackTrace);
203 } 343 }
204 } 344 }
205 } 345 }
@@ -209,14 +349,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
209 if (!Enabled) 349 if (!Enabled)
210 return; 350 return;
211 351
212// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); 352 List<SceneObjectGroup> attachments = sp.GetAttachments();
353
354 if (DebugLevel > 0)
355 m_log.DebugFormat(
356 "[ATTACHMENTS MODULE]: Saving for {0} attachments for {1} in {2}",
357 attachments.Count, sp.Name, m_scene.Name);
358
359 if (attachments.Count <= 0)
360 return;
361
362 Dictionary<SceneObjectGroup, string> scriptStates = new Dictionary<SceneObjectGroup, string>();
363
364 foreach (SceneObjectGroup so in attachments)
365 {
366 // Scripts MUST be snapshotted before the object is
367 // removed from the scene because doing otherwise will
368 // clobber the run flag
369 // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from
370 // scripts performing attachment operations at the same time. Getting object states stops the scripts.
371 scriptStates[so] = PrepareScriptInstanceForSave(so, false);
372
373// m_log.DebugFormat(
374// "[ATTACHMENTS MODULE]: For object {0} for {1} in {2} got saved state {3}",
375// so.Name, sp.Name, m_scene.Name, scriptStates[so]);
376 }
213 377
214 lock (sp.AttachmentsSyncLock) 378 lock (sp.AttachmentsSyncLock)
215 { 379 {
216 foreach (SceneObjectGroup so in sp.GetAttachments()) 380 foreach (SceneObjectGroup so in attachments)
217 { 381 UpdateDetachedObject(sp, so, scriptStates[so]);
218 UpdateDetachedObject(sp, so);
219 }
220 382
221 sp.ClearAttachments(); 383 sp.ClearAttachments();
222 } 384 }
@@ -227,9 +389,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
227 if (!Enabled) 389 if (!Enabled)
228 return; 390 return;
229 391
230// m_log.DebugFormat( 392 if (DebugLevel > 0)
231// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}", 393 m_log.DebugFormat(
232// m_scene.RegionInfo.RegionName, sp.Name, silent); 394 "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}",
395 m_scene.RegionInfo.RegionName, sp.Name, silent);
233 396
234 foreach (SceneObjectGroup sop in sp.GetAttachments()) 397 foreach (SceneObjectGroup sop in sp.GetAttachments())
235 { 398 {
@@ -238,114 +401,149 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
238 401
239 sp.ClearAttachments(); 402 sp.ClearAttachments();
240 } 403 }
241 404
242 public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp) 405 public bool AttachObject(
406 IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool addToInventory, bool append)
243 { 407 {
244 if (!Enabled) 408 if (!Enabled)
245 return false; 409 return false;
246 410
247 if (AttachObjectInternal(sp, group, attachmentPt, silent, temp)) 411 group.DetachFromBackup();
248 {
249 m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
250 return true;
251 }
252 412
253 return false; 413 bool success = AttachObjectInternal(sp, group, attachmentPt, silent, addToInventory, false, append);
414
415 if (!success)
416 group.AttachToBackup();
417
418 return success;
254 } 419 }
255 420
256 private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp) 421 /// <summary>
422 /// Internal method which actually does all the work for attaching an object.
423 /// </summary>
424 /// <returns>The object attached.</returns>
425 /// <param name='sp'></param>
426 /// <param name='group'>The object to attach.</param>
427 /// <param name='attachmentPt'></param>
428 /// <param name='silent'></param>
429 /// <param name='addToInventory'>If true then add object to user inventory.</param>
430 /// <param name='resumeScripts'>If true then scripts are resumed on the attached object.</param>
431 /// <param name='append'>Append to attachment point rather than replace.</param>
432 private bool AttachObjectInternal(
433 IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool addToInventory, bool resumeScripts, bool append)
257 { 434 {
258 lock (sp.AttachmentsSyncLock) 435 if (group.GetSittingAvatarsCount() != 0)
259 { 436 {
260// m_log.DebugFormat( 437 if (DebugLevel > 0)
261// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", 438 m_log.WarnFormat(
262// group.Name, group.LocalId, sp.Name, attachmentPt, silent); 439 "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it",
440 group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount());
263 441
264 if (group.GetSittingAvatarsCount() != 0) 442 return false;
265 { 443 }
266// m_log.WarnFormat( 444
267// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it", 445 Vector3 attachPos = group.AbsolutePosition;
268// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount()); 446 // If the attachment point isn't the same as the one previously used
269 447 // set it's offset position = 0 so that it appears on the attachment point
270 return false; 448 // and not in a weird location somewhere unknown.
271 } 449 if (attachmentPt != (uint)AttachmentPoint.Default && attachmentPt != group.AttachmentPoint)
272 450 {
273 if (sp.GetAttachments(attachmentPt).Contains(group)) 451 attachPos = Vector3.Zero;
274 { 452 }
275 // m_log.WarnFormat( 453
276 // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", 454 // if the attachment point is the same as previous, make sure we get the saved
277 // group.Name, group.LocalId, sp.Name, AttachmentPt); 455 // position info.
278 456 if (attachmentPt != 0 && attachmentPt == group.RootPart.Shape.LastAttachPoint)
279 return false; 457 {
280 } 458 attachPos = group.RootPart.AttachedPos;
281 459 }
282 Vector3 attachPos = group.AbsolutePosition; 460
283 461 // AttachmentPt 0 means the client chose to 'wear' the attachment.
284 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 462 if (attachmentPt == (uint)AttachmentPoint.Default)
285 // be removed when that functionality is implemented in opensim 463 {
286 attachmentPt &= 0x7f; 464 // Check object for stored attachment point
287 465 attachmentPt = group.AttachmentPoint;
288 // If the attachment point isn't the same as the one previously used 466 }
289 // set it's offset position = 0 so that it appears on the attachment point 467
290 // and not in a weird location somewhere unknown. 468 // if we didn't find an attach point, look for where it was last attached
291 if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint) 469 if (attachmentPt == 0)
292 { 470 {
293 attachPos = Vector3.Zero; 471 attachmentPt = (uint)group.RootPart.Shape.LastAttachPoint;
294 } 472 attachPos = group.RootPart.AttachedPos;
295 473 group.HasGroupChanged = true;
296 // AttachmentPt 0 means the client chose to 'wear' the attachment. 474 }
297 if (attachmentPt == 0) 475
476 // if we still didn't find a suitable attachment point.......
477 if (attachmentPt == 0)
478 {
479 // Stick it on left hand with Zero Offset from the attachment point.
480 attachmentPt = (uint)AttachmentPoint.LeftHand;
481 attachPos = Vector3.Zero;
482 }
483
484 group.AttachmentPoint = attachmentPt;
485 group.AbsolutePosition = attachPos;
486
487 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
488
489 if (attachments.Contains(group))
490 {
491 if (DebugLevel > 0)
492 m_log.WarnFormat(
493 "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
494 group.Name, group.LocalId, sp.Name, attachmentPt);
495
496 return false;
497 }
498
499 // If we already have 5, remove the oldest until only 4 are left. Skip over temp ones
500 while (attachments.Count >= 5)
501 {
502 if (attachments[0].FromItemID != UUID.Zero)
503 DetachSingleAttachmentToInv(sp, attachments[0]);
504 attachments.RemoveAt(0);
505 }
506
507 // If we're not appending, remove the rest as well
508 if (attachments.Count != 0 && !append)
509 {
510 foreach (SceneObjectGroup g in attachments)
298 { 511 {
299 // Check object for stored attachment point 512 if (g.FromItemID != UUID.Zero)
300 attachmentPt = group.AttachmentPoint; 513 DetachSingleAttachmentToInv(sp, g);
301 } 514 }
515 }
516
517 lock (sp.AttachmentsSyncLock)
518 {
519 if (addToInventory && sp.PresenceType != PresenceType.Npc)
520 UpdateUserInventoryWithAttachment(sp, group, attachmentPt, append);
302 521
303 // if we still didn't find a suitable attachment point....... 522 AttachToAgent(sp, group, attachmentPt, attachPos, silent);
304 if (attachmentPt == 0) 523
524 if (resumeScripts)
305 { 525 {
306 // Stick it on left hand with Zero Offset from the attachment point. 526 // Fire after attach, so we don't get messy perms dialogs
307 attachmentPt = (uint)AttachmentPoint.LeftHand; 527 // 4 == AttachedRez
308 attachPos = Vector3.Zero; 528 group.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
529 group.ResumeScripts();
309 } 530 }
310
311 group.AttachmentPoint = attachmentPt;
312 group.AbsolutePosition = attachPos;
313 531
314 if (sp.PresenceType != PresenceType.Npc) 532 // Do this last so that event listeners have access to all the effects of the attachment
315 UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp); 533 m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
316
317 AttachToAgent(sp, group, attachmentPt, attachPos, silent);
318 } 534 }
319 535
320 return true; 536 return true;
321 } 537 }
322 538
323 private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool temp) 539 private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool append)
324 { 540 {
325 // Remove any previous attachments
326 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
327
328 // At the moment we can only deal with a single attachment
329 if (attachments.Count != 0)
330 {
331 if (attachments[0].FromItemID != UUID.Zero)
332 DetachSingleAttachmentToInvInternal(sp, attachments[0]);
333 // Error logging commented because UUID.Zero now means temp attachment
334// else
335// m_log.WarnFormat(
336// "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!",
337// attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
338 }
339
340 // Add the new attachment to inventory if we don't already have it. 541 // Add the new attachment to inventory if we don't already have it.
341 if (!temp) 542 UUID newAttachmentItemID = group.FromItemID;
342 { 543 if (newAttachmentItemID == UUID.Zero)
343 UUID newAttachmentItemID = group.FromItemID; 544 newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
344 if (newAttachmentItemID == UUID.Zero)
345 newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
346 545
347 ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); 546 ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group, append);
348 }
349 } 547 }
350 548
351 public SceneObjectGroup RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) 549 public SceneObjectGroup RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt)
@@ -353,41 +551,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
353 if (!Enabled) 551 if (!Enabled)
354 return null; 552 return null;
355 553
356// m_log.DebugFormat( 554 if (DebugLevel > 0)
357// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}", 555 m_log.DebugFormat(
358// (AttachmentPoint)AttachmentPt, itemID, sp.Name); 556 "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2} in {3}",
359 557 (AttachmentPoint)AttachmentPt, itemID, sp.Name, m_scene.Name);
360 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
361 // be removed when that functionality is implemented in opensim
362 AttachmentPt &= 0x7f;
363 558
364 // Viewer 2/3 sometimes asks to re-wear items that are already worn (and show up in it's inventory as such). 559 // We check the attachments in the avatar appearance here rather than the objects attached to the
365 // This often happens during login - not sure the exact reason. 560 // ScenePresence itself so that we can ignore calls by viewer 2/3 to attach objects on startup. We are
366 // For now, we will ignore the request. Unfortunately, this means that we need to dig through all the 561 // already doing this in ScenePresence.MakeRootAgent(). Simulator-side attaching needs to be done
367 // ScenePresence attachments. We can't use the data in AvatarAppearance because that's present at login 562 // because pre-outfit folder viewers (most version 1 viewers) require it.
368 // before anything has actually been attached.
369 bool alreadyOn = false; 563 bool alreadyOn = false;
370 List<SceneObjectGroup> existingAttachments = sp.GetAttachments(); 564 List<AvatarAttachment> existingAttachments = sp.Appearance.GetAttachments();
371 foreach (SceneObjectGroup so in existingAttachments) 565 foreach (AvatarAttachment existingAttachment in existingAttachments)
372 { 566 {
373 if (so.FromItemID == itemID) 567 if (existingAttachment.ItemID == itemID)
374 { 568 {
375 alreadyOn = true; 569 alreadyOn = true;
376 break; 570 break;
377 } 571 }
378 } 572 }
379 573
380// if (sp.Appearance.GetAttachmentForItem(itemID) != null)
381 if (alreadyOn) 574 if (alreadyOn)
382 { 575 {
383// m_log.WarnFormat( 576 if (DebugLevel > 0)
384// "[ATTACHMENTS MODULE]: Ignoring request by {0} to wear item {1} at {2} since it is already worn", 577 m_log.DebugFormat(
385// sp.Name, itemID, AttachmentPt); 578 "[ATTACHMENTS MODULE]: Ignoring request by {0} to wear item {1} at {2} since it is already worn",
579 sp.Name, itemID, AttachmentPt);
386 580
387 return null; 581 return null;
388 } 582 }
389 583
390 return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt); 584 bool append = (AttachmentPt & 0x80) != 0;
585 AttachmentPt &= 0x7f;
586
587 return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, append);
391 } 588 }
392 589
393 public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist) 590 public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist)
@@ -395,13 +592,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
395 if (!Enabled) 592 if (!Enabled)
396 return; 593 return;
397 594
398 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); 595 if (DebugLevel > 0)
399 lock (sp.AttachmentsSyncLock) 596 m_log.DebugFormat(
597 "[ATTACHMENTS MODULE]: Rezzing {0} attachments from inventory for {1} in {2}",
598 rezlist.Count, sp.Name, m_scene.Name);
599
600 foreach (KeyValuePair<UUID, uint> rez in rezlist)
400 { 601 {
401 foreach (KeyValuePair<UUID, uint> rez in rezlist) 602 RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value);
402 {
403 RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value);
404 }
405 } 603 }
406 } 604 }
407 605
@@ -415,9 +613,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
415 if (!Enabled) 613 if (!Enabled)
416 return; 614 return;
417 615
418// m_log.DebugFormat( 616 if (DebugLevel > 0)
419// "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", 617 m_log.DebugFormat(
420// sp.UUID, soLocalId); 618 "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}",
619 sp.UUID, soLocalId);
421 620
422 SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId); 621 SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId);
423 622
@@ -433,9 +632,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
433 if (inventoryID == UUID.Zero) 632 if (inventoryID == UUID.Zero)
434 return; 633 return;
435 634
436// m_log.DebugFormat( 635 if (DebugLevel > 0)
437// "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}", 636 m_log.DebugFormat(
438// so.Name, so.LocalId, inventoryID); 637 "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}",
638 so.Name, so.LocalId, inventoryID);
439 639
440 lock (sp.AttachmentsSyncLock) 640 lock (sp.AttachmentsSyncLock)
441 { 641 {
@@ -463,6 +663,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
463 so.ClearPartAttachmentData(); 663 so.ClearPartAttachmentData();
464 rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive); 664 rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive);
465 so.HasGroupChanged = true; 665 so.HasGroupChanged = true;
666 so.RootPart.Shape.LastAttachPoint = (byte)so.AttachmentPoint;
466 rootPart.Rezzed = DateTime.Now; 667 rootPart.Rezzed = DateTime.Now;
467 rootPart.RemFlag(PrimFlags.TemporaryOnRez); 668 rootPart.RemFlag(PrimFlags.TemporaryOnRez);
468 so.AttachToBackup(); 669 so.AttachToBackup();
@@ -481,25 +682,38 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
481 682
482 public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so) 683 public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so)
483 { 684 {
685 if (so.AttachedAvatar != sp.UUID)
686 {
687 m_log.WarnFormat(
688 "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}",
689 so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName);
690
691 return;
692 }
693
694 if (DebugLevel > 0)
695 m_log.DebugFormat(
696 "[ATTACHMENTS MODULE]: Detaching object {0} {1} (FromItemID {2}) for {3} in {4}",
697 so.Name, so.LocalId, so.FromItemID, sp.Name, m_scene.Name);
698
699 // Scripts MUST be snapshotted before the object is
700 // removed from the scene because doing otherwise will
701 // clobber the run flag
702 // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from
703 // scripts performing attachment operations at the same time. Getting object states stops the scripts.
704 string scriptedState = PrepareScriptInstanceForSave(so, true);
705
484 lock (sp.AttachmentsSyncLock) 706 lock (sp.AttachmentsSyncLock)
485 { 707 {
486 // Save avatar attachment information 708 // Save avatar attachment information
487// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID); 709// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID);
488 710
489 if (so.AttachedAvatar != sp.UUID)
490 {
491 m_log.WarnFormat(
492 "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}",
493 so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName);
494
495 return;
496 }
497
498 bool changed = sp.Appearance.DetachAttachment(so.FromItemID); 711 bool changed = sp.Appearance.DetachAttachment(so.FromItemID);
499 if (changed && m_scene.AvatarFactory != null) 712 if (changed && m_scene.AvatarFactory != null)
500 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); 713 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
501 714
502 DetachSingleAttachmentToInvInternal(sp, so); 715 sp.RemoveAttachment(so);
716 UpdateDetachedObject(sp, so, scriptedState);
503 } 717 }
504 } 718 }
505 719
@@ -588,15 +802,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
588 (sbyte)AssetType.Object, 802 (sbyte)AssetType.Object,
589 Utils.StringToBytes(sceneObjectXml), 803 Utils.StringToBytes(sceneObjectXml),
590 sp.UUID); 804 sp.UUID);
591 m_scene.AssetService.Store(asset);
592 805
593 item.AssetID = asset.FullID; 806 if (m_invAccessModule != null)
594 item.Description = asset.Description; 807 m_invAccessModule.UpdateInventoryItemAsset(sp.UUID, item, asset);
595 item.Name = asset.Name;
596 item.AssetType = asset.Type;
597 item.InvType = (int)InventoryType.Object;
598
599 m_scene.InventoryService.UpdateItem(item);
600 808
601 // If the name of the object has been changed whilst attached then we want to update the inventory 809 // If the name of the object has been changed whilst attached then we want to update the inventory
602 // item in the viewer. 810 // item in the viewer.
@@ -606,12 +814,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
606 814
607 grp.HasGroupChanged = false; // Prevent it being saved over and over 815 grp.HasGroupChanged = false; // Prevent it being saved over and over
608 } 816 }
609// else 817 else if (DebugLevel > 0)
610// { 818 {
611// m_log.DebugFormat( 819 m_log.DebugFormat(
612// "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", 820 "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}",
613// grp.UUID, grp.AttachmentPoint); 821 grp.UUID, grp.AttachmentPoint);
614// } 822 }
615 } 823 }
616 824
617 /// <summary> 825 /// <summary>
@@ -629,11 +837,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
629 private void AttachToAgent( 837 private void AttachToAgent(
630 IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) 838 IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
631 { 839 {
632// m_log.DebugFormat( 840 if (DebugLevel > 0)
633// "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", 841 m_log.DebugFormat(
634// so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); 842 "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} at pt {2} pos {3} {4} in {5}",
635 843 so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos, m_scene.Name);
636 so.DetachFromBackup();
637 844
638 // Remove from database and parcel prim count 845 // Remove from database and parcel prim count
639 m_scene.DeleteFromStorage(so.UUID); 846 m_scene.DeleteFromStorage(so.UUID);
@@ -656,16 +863,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
656 { 863 {
657 if (so.HasPrivateAttachmentPoint) 864 if (so.HasPrivateAttachmentPoint)
658 { 865 {
659// m_log.DebugFormat( 866 if (DebugLevel > 0)
660// "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}", 867 m_log.DebugFormat(
661// so.Name, sp.Name, so.AttachmentPoint); 868 "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}",
869 so.Name, sp.Name, so.AttachmentPoint);
662 870
663 // As this scene object can now only be seen by the attaching avatar, tell everybody else in the 871 // As this scene object can now only be seen by the attaching avatar, tell everybody else in the
664 // scene that it's no longer in their awareness. 872 // scene that it's no longer in their awareness.
665 m_scene.ForEachClient( 873 m_scene.ForEachClient(
666 client => 874 client =>
667 { if (client.AgentId != so.AttachedAvatar) 875 { if (client.AgentId != so.AttachedAvatar)
668 client.SendKillObject(m_scene.RegionInfo.RegionHandle, new List<uint>() { so.LocalId }); 876 client.SendKillObject(new List<uint>() { so.LocalId });
669 }); 877 });
670 } 878 }
671 879
@@ -692,14 +900,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
692 if (m_invAccessModule == null) 900 if (m_invAccessModule == null)
693 return null; 901 return null;
694 902
695 // m_log.DebugFormat( 903 if (DebugLevel > 0)
696 // "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", 904 m_log.DebugFormat(
697 // grp.Name, grp.LocalId, remoteClient.Name); 905 "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}",
906 grp.Name, grp.LocalId, sp.Name);
698 907
699 InventoryItemBase newItem 908 InventoryItemBase newItem
700 = m_invAccessModule.CopyToInventory( 909 = m_invAccessModule.CopyToInventory(
701 DeRezAction.TakeCopy, 910 DeRezAction.TakeCopy,
702 m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object).ID, 911 m_scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object).ID,
703 new List<SceneObjectGroup> { grp }, 912 new List<SceneObjectGroup> { grp },
704 sp.ControllingClient, true)[0]; 913 sp.ControllingClient, true)[0];
705 914
@@ -709,8 +918,32 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
709 return newItem; 918 return newItem;
710 } 919 }
711 920
712 private string GetObjectScriptStates(SceneObjectGroup grp) 921 /// <summary>
922 /// Prepares the script instance for save.
923 /// </summary>
924 /// <remarks>
925 /// This involves triggering the detach event and getting the script state (which also stops the script)
926 /// This MUST be done outside sp.AttachmentsSyncLock, since otherwise there is a chance of deadlock if a
927 /// running script is performing attachment operations.
928 /// </remarks>
929 /// <returns>
930 /// The script state ready for persistence.
931 /// </returns>
932 /// <param name='grp'>
933 /// </param>
934 /// <param name='fireDetachEvent'>
935 /// If true, then fire the script event before we save its state.
936 /// </param>
937 private string PrepareScriptInstanceForSave(SceneObjectGroup grp, bool fireDetachEvent)
713 { 938 {
939 if (fireDetachEvent)
940 {
941 m_scene.EventManager.TriggerOnAttach(grp.LocalId, grp.FromItemID, UUID.Zero);
942
943 // Allow detach event time to do some work before stopping the script
944 Thread.Sleep(2);
945 }
946
714 using (StringWriter sw = new StringWriter()) 947 using (StringWriter sw = new StringWriter())
715 { 948 {
716 using (XmlTextWriter writer = new XmlTextWriter(sw)) 949 using (XmlTextWriter writer = new XmlTextWriter(sw))
@@ -722,7 +955,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
722 } 955 }
723 } 956 }
724 957
725 private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so) 958 private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so, string scriptedState)
726 { 959 {
727 // Don't save attachments for HG visitors, it 960 // Don't save attachments for HG visitors, it
728 // messes up their inventory. When a HG visitor logs 961 // messes up their inventory. When a HG visitor logs
@@ -735,11 +968,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
735 && (m_scene.UserManagementModule == null 968 && (m_scene.UserManagementModule == null
736 || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID)); 969 || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID));
737 970
738 // Scripts MUST be snapshotted before the object is
739 // removed from the scene because doing otherwise will
740 // clobber the run flag
741 string scriptedState = GetObjectScriptStates(so);
742
743 // Remove the object from the scene so no more updates 971 // Remove the object from the scene so no more updates
744 // are sent. Doing this before the below changes will ensure 972 // are sent. Doing this before the below changes will ensure
745 // updates can't cause "HUD artefacts" 973 // updates can't cause "HUD artefacts"
@@ -763,91 +991,88 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
763 so.RemoveScriptInstances(true); 991 so.RemoveScriptInstances(true);
764 } 992 }
765 993
766 private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so) 994 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
995 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, bool append)
767 { 996 {
768 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name); 997 if (m_invAccessModule == null)
998 return null;
769 999
770 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero); 1000 SceneObjectGroup objatt;
771 sp.RemoveAttachment(so);
772 1001
773 UpdateDetachedObject(sp, so); 1002 if (itemID != UUID.Zero)
774 } 1003 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
1004 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
1005 false, false, sp.UUID, true);
1006 else
1007 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
1008 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
1009 false, false, sp.UUID, true);
775 1010
776 private SceneObjectGroup RezSingleAttachmentFromInventoryInternal( 1011 if (objatt == null)
777 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt) 1012 {
778 { 1013 m_log.WarnFormat(
779 if (m_invAccessModule == null) 1014 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
780 return null; 1015 itemID, sp.Name, attachmentPt);
781 1016
782 lock (sp.AttachmentsSyncLock) 1017 return null;
1018 }
1019 else if (itemID == UUID.Zero)
783 { 1020 {
784 SceneObjectGroup objatt; 1021 // We need to have a FromItemID for multiple attachments on a single attach point to appear. This is
1022 // true on Singularity 1.8.5 and quite possibly other viewers as well. As NPCs don't have an inventory
1023 // we will satisfy this requirement by inserting a random UUID.
1024 objatt.FromItemID = UUID.Random();
1025 }
785 1026
786 if (itemID != UUID.Zero) 1027 if (DebugLevel > 0)
787 objatt = m_invAccessModule.RezObject(sp.ControllingClient, 1028 m_log.DebugFormat(
788 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, 1029 "[ATTACHMENTS MODULE]: Rezzed single object {0} with {1} prims for attachment to {2} on point {3} in {4}",
789 false, false, sp.UUID, true); 1030 objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name);
790 else 1031
791 objatt = m_invAccessModule.RezObject(sp.ControllingClient, 1032 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
792 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, 1033 objatt.HasGroupChanged = false;
793 false, false, sp.UUID, true); 1034 bool tainted = false;
1035 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
1036 tainted = true;
1037
1038 // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
1039 // course of events. If not, then it's probably not worth trying to recover the situation
1040 // since this is more likely to trigger further exceptions and confuse later debugging. If
1041 // exceptions can be thrown in expected error conditions (not NREs) then make this consistent
1042 // since other normal error conditions will simply return false instead.
1043 // This will throw if the attachment fails
1044 try
1045 {
1046 AttachObjectInternal(sp, objatt, attachmentPt, false, true, true, append);
1047 }
1048 catch (Exception e)
1049 {
1050 m_log.ErrorFormat(
1051 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
1052 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
794 1053
795 if (objatt != null) 1054 // Make sure the object doesn't stick around and bail
796 { 1055 sp.RemoveAttachment(objatt);
797// m_log.DebugFormat( 1056 m_scene.DeleteSceneObject(objatt, false);
798// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", 1057 return null;
799// objatt.Name, sp.Name, attachmentPt, m_scene.Name); 1058 }
800
801 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
802 objatt.HasGroupChanged = false;
803 bool tainted = false;
804 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
805 tainted = true;
806
807 // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
808 // course of events. If not, then it's probably not worth trying to recover the situation
809 // since this is more likely to trigger further exceptions and confuse later debugging. If
810 // exceptions can be thrown in expected error conditions (not NREs) then make this consistent
811 // since other normal error conditions will simply return false instead.
812 // This will throw if the attachment fails
813 try
814 {
815 AttachObjectInternal(sp, objatt, attachmentPt, false, false);
816 }
817 catch (Exception e)
818 {
819 m_log.ErrorFormat(
820 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
821 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
822
823 // Make sure the object doesn't stick around and bail
824 sp.RemoveAttachment(objatt);
825 m_scene.DeleteSceneObject(objatt, false);
826 return null;
827 }
828 1059
829 if (tainted) 1060 if (tainted)
830 objatt.HasGroupChanged = true; 1061 objatt.HasGroupChanged = true;
831 1062
832 // Fire after attach, so we don't get messy perms dialogs 1063 if (ThrottlePer100PrimsRezzed > 0)
833 // 4 == AttachedRez 1064 {
834 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); 1065 int throttleMs = (int)Math.Round((float)objatt.PrimCount / 100 * ThrottlePer100PrimsRezzed);
835 objatt.ResumeScripts();
836 1066
837 // Do this last so that event listeners have access to all the effects of the attachment 1067 if (DebugLevel > 0)
838 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); 1068 m_log.DebugFormat(
1069 "[ATTACHMENTS MODULE]: Throttling by {0}ms after rez of {1} with {2} prims for attachment to {3} on point {4} in {5}",
1070 throttleMs, objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name);
839 1071
840 return objatt; 1072 Thread.Sleep(throttleMs);
841 }
842 else
843 {
844 m_log.WarnFormat(
845 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
846 itemID, sp.Name, attachmentPt);
847 }
848 } 1073 }
849 1074
850 return null; 1075 return objatt;
851 } 1076 }
852 1077
853 /// <summary> 1078 /// <summary>
@@ -857,7 +1082,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
857 /// <param name="AttachmentPt"></param> 1082 /// <param name="AttachmentPt"></param>
858 /// <param name="itemID"></param> 1083 /// <param name="itemID"></param>
859 /// <param name="att"></param> 1084 /// <param name="att"></param>
860 private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) 1085 private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att, bool append)
861 { 1086 {
862// m_log.DebugFormat( 1087// m_log.DebugFormat(
863// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", 1088// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}",
@@ -880,12 +1105,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
880 if (item == null) 1105 if (item == null)
881 return; 1106 return;
882 1107
883 bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); 1108 int attFlag = append ? 0x80 : 0;
1109 bool changed = sp.Appearance.SetAttachment((int)AttachmentPt | attFlag, itemID, item.AssetID);
884 if (changed && m_scene.AvatarFactory != null) 1110 if (changed && m_scene.AvatarFactory != null)
885 { 1111 {
886// m_log.DebugFormat( 1112 if (DebugLevel > 0)
887// "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()", 1113 m_log.DebugFormat(
888// sp.Name, att.Name, AttachmentPt); 1114 "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()",
1115 sp.Name, att.Name, AttachmentPt);
889 1116
890 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); 1117 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
891 } 1118 }
@@ -900,9 +1127,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
900 if (!Enabled) 1127 if (!Enabled)
901 return null; 1128 return null;
902 1129
903 // m_log.DebugFormat( 1130 if (DebugLevel > 0)
904 // "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", 1131 m_log.DebugFormat(
905 // (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); 1132 "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}",
1133 (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name);
906 1134
907 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); 1135 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
908 1136
@@ -933,9 +1161,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
933 1161
934 private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) 1162 private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent)
935 { 1163 {
936// m_log.DebugFormat( 1164 if (DebugLevel > 0)
937// "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", 1165 m_log.DebugFormat(
938// objectLocalID, remoteClient.Name, AttachmentPt, silent); 1166 "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})",
1167 objectLocalID, remoteClient.Name, AttachmentPt, silent);
939 1168
940 if (!Enabled) 1169 if (!Enabled)
941 return; 1170 return;
@@ -964,12 +1193,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
964 return; 1193 return;
965 } 1194 }
966 1195
967 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 1196 bool append = (AttachmentPt & 0x80) != 0;
968 // be removed when that functionality is implemented in opensim
969 AttachmentPt &= 0x7f; 1197 AttachmentPt &= 0x7f;
970 1198
971 // Calls attach with a Zero position 1199 // Calls attach with a Zero position
972 AttachObject(sp, part.ParentGroup, AttachmentPt, false, false); 1200 if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, true, append))
1201 {
1202 if (DebugLevel > 0)
1203 m_log.Debug(
1204 "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId
1205 + ", AttachmentPoint: " + AttachmentPt);
1206
1207 // Save avatar attachment information
1208 m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId);
1209 }
973 } 1210 }
974 catch (Exception e) 1211 catch (Exception e)
975 { 1212 {
@@ -997,17 +1234,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
997 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); 1234 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
998 if (sp != null) 1235 if (sp != null)
999 { 1236 {
1000 lock (sp.AttachmentsSyncLock) 1237 List<SceneObjectGroup> attachments = sp.GetAttachments();
1238
1239 foreach (SceneObjectGroup group in attachments)
1001 { 1240 {
1002 List<SceneObjectGroup> attachments = sp.GetAttachments(); 1241 if (group.FromItemID == itemID && group.FromItemID != UUID.Zero)
1003
1004 foreach (SceneObjectGroup group in attachments)
1005 { 1242 {
1006 if (group.FromItemID == itemID && group.FromItemID != UUID.Zero) 1243 DetachSingleAttachmentToInv(sp, group);
1007 { 1244 return;
1008 DetachSingleAttachmentToInv(sp, group);
1009 return;
1010 }
1011 } 1245 }
1012 } 1246 }
1013 } 1247 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
index 0ee01c7..0ac3add 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
@@ -37,7 +37,8 @@ using Nini.Config;
37using NUnit.Framework; 37using NUnit.Framework;
38using OpenMetaverse; 38using OpenMetaverse;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Framework.Communications; 40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Region.CoreModules.Avatar.Attachments; 42using OpenSim.Region.CoreModules.Avatar.Attachments;
42using OpenSim.Region.CoreModules.Framework; 43using OpenSim.Region.CoreModules.Framework;
43using OpenSim.Region.CoreModules.Framework.EntityTransfer; 44using OpenSim.Region.CoreModules.Framework.EntityTransfer;
@@ -51,7 +52,6 @@ using OpenSim.Region.ScriptEngine.Interfaces;
51using OpenSim.Region.ScriptEngine.XEngine; 52using OpenSim.Region.ScriptEngine.XEngine;
52using OpenSim.Services.Interfaces; 53using OpenSim.Services.Interfaces;
53using OpenSim.Tests.Common; 54using OpenSim.Tests.Common;
54using OpenSim.Tests.Common.Mock;
55 55
56namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests 56namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
57{ 57{
@@ -130,7 +130,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
130 config.AddConfig("Modules"); 130 config.AddConfig("Modules");
131 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); 131 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
132 132
133 modules.Add(new AttachmentsModule()); 133 AttachmentsModule attMod = new AttachmentsModule();
134 attMod.DebugLevel = 1;
135 modules.Add(attMod);
134 modules.Add(new BasicInventoryAccessModule()); 136 modules.Add(new BasicInventoryAccessModule());
135 } 137 }
136 138
@@ -195,9 +197,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
195 string attName = "att"; 197 string attName = "att";
196 198
197 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); 199 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
200 Assert.That(so.Backup, Is.True);
198 201
199 m_numberOfAttachEventsFired = 0; 202 m_numberOfAttachEventsFired = 0;
200 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false); 203 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false);
201 204
202 // Check status on scene presence 205 // Check status on scene presence
203 Assert.That(sp.HasAttachments(), Is.True); 206 Assert.That(sp.HasAttachments(), Is.True);
@@ -209,6 +212,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
209 Assert.That(attSo.IsAttachment); 212 Assert.That(attSo.IsAttachment);
210 Assert.That(attSo.UsesPhysics, Is.False); 213 Assert.That(attSo.UsesPhysics, Is.False);
211 Assert.That(attSo.IsTemporary, Is.False); 214 Assert.That(attSo.IsTemporary, Is.False);
215 Assert.That(attSo.Backup, Is.False);
212 216
213 // Check item status 217 // Check item status
214 Assert.That( 218 Assert.That(
@@ -219,7 +223,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
219 Assert.That(attachmentItem, Is.Not.Null); 223 Assert.That(attachmentItem, Is.Not.Null);
220 Assert.That(attachmentItem.Name, Is.EqualTo(attName)); 224 Assert.That(attachmentItem.Name, Is.EqualTo(attName));
221 225
222 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); 226 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object);
223 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); 227 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
224 228
225 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); 229 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
@@ -228,6 +232,120 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
228 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); 232 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
229 } 233 }
230 234
235 [Test]
236 public void TestWearAttachmentFromGround()
237 {
238 TestHelpers.InMethod();
239// TestHelpers.EnableLogging();
240
241 Scene scene = CreateTestScene();
242 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
243 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
244
245 SceneObjectGroup so2 = SceneHelpers.AddSceneObject(scene, "att2", sp.UUID);
246
247 {
248 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "att1", sp.UUID);
249
250 m_numberOfAttachEventsFired = 0;
251 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Default, false, true, false);
252
253 // Check status on scene presence
254 Assert.That(sp.HasAttachments(), Is.True);
255 List<SceneObjectGroup> attachments = sp.GetAttachments();
256 Assert.That(attachments.Count, Is.EqualTo(1));
257 SceneObjectGroup attSo = attachments[0];
258 Assert.That(attSo.Name, Is.EqualTo(so.Name));
259 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
260 Assert.That(attSo.IsAttachment);
261 Assert.That(attSo.UsesPhysics, Is.False);
262 Assert.That(attSo.IsTemporary, Is.False);
263
264 // Check item status
265 Assert.That(
266 sp.Appearance.GetAttachpoint(attSo.FromItemID),
267 Is.EqualTo((int)AttachmentPoint.LeftHand));
268
269 InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
270 Assert.That(attachmentItem, Is.Not.Null);
271 Assert.That(attachmentItem.Name, Is.EqualTo(so.Name));
272
273 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object);
274 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
275
276 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(2));
277
278 // Check events
279 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
280 }
281
282 // Test wearing a different attachment from the ground.
283 {
284 scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false);
285
286 // Check status on scene presence
287 Assert.That(sp.HasAttachments(), Is.True);
288 List<SceneObjectGroup> attachments = sp.GetAttachments();
289 Assert.That(attachments.Count, Is.EqualTo(1));
290 SceneObjectGroup attSo = attachments[0];
291 Assert.That(attSo.Name, Is.EqualTo(so2.Name));
292 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
293 Assert.That(attSo.IsAttachment);
294 Assert.That(attSo.UsesPhysics, Is.False);
295 Assert.That(attSo.IsTemporary, Is.False);
296
297 // Check item status
298 Assert.That(
299 sp.Appearance.GetAttachpoint(attSo.FromItemID),
300 Is.EqualTo((int)AttachmentPoint.LeftHand));
301
302 InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
303 Assert.That(attachmentItem, Is.Not.Null);
304 Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name));
305
306 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object);
307 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
308
309 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
310
311 // Check events
312 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
313 }
314
315 // Test rewearing an already worn attachment from ground. Nothing should happen.
316 {
317 scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false);
318
319 // Check status on scene presence
320 Assert.That(sp.HasAttachments(), Is.True);
321 List<SceneObjectGroup> attachments = sp.GetAttachments();
322 Assert.That(attachments.Count, Is.EqualTo(1));
323 SceneObjectGroup attSo = attachments[0];
324 Assert.That(attSo.Name, Is.EqualTo(so2.Name));
325 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
326 Assert.That(attSo.IsAttachment);
327 Assert.That(attSo.UsesPhysics, Is.False);
328 Assert.That(attSo.IsTemporary, Is.False);
329
330 // Check item status
331 Assert.That(
332 sp.Appearance.GetAttachpoint(attSo.FromItemID),
333 Is.EqualTo((int)AttachmentPoint.LeftHand));
334
335 InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
336 Assert.That(attachmentItem, Is.Not.Null);
337 Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name));
338
339 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object);
340 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
341
342 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
343
344 // Check events
345 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
346 }
347 }
348
231 /// <summary> 349 /// <summary>
232 /// Test that we do not attempt to attach an in-world object that someone else is sitting on. 350 /// Test that we do not attempt to attach an in-world object that someone else is sitting on.
233 /// </summary> 351 /// </summary>
@@ -254,7 +372,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
254 sp2.AbsolutePosition = new Vector3(0, 0, 0); 372 sp2.AbsolutePosition = new Vector3(0, 0, 0);
255 sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero); 373 sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero);
256 374
257 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false); 375 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false);
258 376
259 Assert.That(sp.HasAttachments(), Is.False); 377 Assert.That(sp.HasAttachments(), Is.False);
260 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); 378 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
@@ -267,7 +385,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
267 public void TestRezAttachmentFromInventory() 385 public void TestRezAttachmentFromInventory()
268 { 386 {
269 TestHelpers.InMethod(); 387 TestHelpers.InMethod();
270// log4net.Config.XmlConfigurator.Configure(); 388// TestHelpers.EnableLogging();
271 389
272 Scene scene = CreateTestScene(); 390 Scene scene = CreateTestScene();
273 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); 391 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
@@ -275,29 +393,141 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
275 393
276 InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); 394 InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
277 395
278 m_numberOfAttachEventsFired = 0; 396 {
279 scene.AttachmentsModule.RezSingleAttachmentFromInventory( 397 scene.AttachmentsModule.RezSingleAttachmentFromInventory(
280 sp, attItem.ID, (uint)AttachmentPoint.Chest); 398 sp, attItem.ID, (uint)AttachmentPoint.Chest);
281 399
282 // Check scene presence status 400 // Check scene presence status
283 Assert.That(sp.HasAttachments(), Is.True); 401 Assert.That(sp.HasAttachments(), Is.True);
284 List<SceneObjectGroup> attachments = sp.GetAttachments(); 402 List<SceneObjectGroup> attachments = sp.GetAttachments();
285 Assert.That(attachments.Count, Is.EqualTo(1)); 403 Assert.That(attachments.Count, Is.EqualTo(1));
286 SceneObjectGroup attSo = attachments[0]; 404 SceneObjectGroup attSo = attachments[0];
287 Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); 405 Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
288 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); 406 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
289 Assert.That(attSo.IsAttachment); 407 Assert.That(attSo.IsAttachment);
290 Assert.That(attSo.UsesPhysics, Is.False); 408 Assert.That(attSo.UsesPhysics, Is.False);
291 Assert.That(attSo.IsTemporary, Is.False); 409 Assert.That(attSo.IsTemporary, Is.False);
410 Assert.IsFalse(attSo.Backup);
411
412 // Check appearance status
413 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
414 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
415 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
416
417 // Check events
418 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
419 }
420
421 // Test attaching an already attached attachment
422 {
423 scene.AttachmentsModule.RezSingleAttachmentFromInventory(
424 sp, attItem.ID, (uint)AttachmentPoint.Chest);
292 425
293 // Check appearance status 426 // Check scene presence status
294 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); 427 Assert.That(sp.HasAttachments(), Is.True);
295 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); 428 List<SceneObjectGroup> attachments = sp.GetAttachments();
429 Assert.That(attachments.Count, Is.EqualTo(1));
430 SceneObjectGroup attSo = attachments[0];
431 Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
432 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
433 Assert.That(attSo.IsAttachment);
434 Assert.That(attSo.UsesPhysics, Is.False);
435 Assert.That(attSo.IsTemporary, Is.False);
436
437 // Check appearance status
438 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
439 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
440 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
441
442 // Check events
443 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
444 }
445 }
296 446
297 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); 447 /// <summary>
448 /// Test wearing an attachment from inventory, as opposed to explicit choosing the rez point
449 /// </summary>
450 [Test]
451 public void TestWearAttachmentFromInventory()
452 {
453 TestHelpers.InMethod();
454// TestHelpers.EnableLogging();
298 455
299 // Check events 456 Scene scene = CreateTestScene();
300 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); 457 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
458 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID);
459
460 InventoryItemBase attItem1 = CreateAttachmentItem(scene, ua1.PrincipalID, "att1", 0x10, 0x20);
461 InventoryItemBase attItem2 = CreateAttachmentItem(scene, ua1.PrincipalID, "att2", 0x11, 0x21);
462
463 {
464 m_numberOfAttachEventsFired = 0;
465 scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem1.ID, (uint)AttachmentPoint.Default);
466
467 // default attachment point is currently the left hand.
468 Assert.That(sp.HasAttachments(), Is.True);
469 List<SceneObjectGroup> attachments = sp.GetAttachments();
470 Assert.That(attachments.Count, Is.EqualTo(1));
471 SceneObjectGroup attSo = attachments[0];
472 Assert.That(attSo.Name, Is.EqualTo(attItem1.Name));
473 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
474 Assert.That(attSo.IsAttachment);
475
476 // Check appearance status
477 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
478 Assert.That(sp.Appearance.GetAttachpoint(attItem1.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
479 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
480
481 // Check events
482 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
483 }
484
485 // Test wearing a second attachment at the same position
486 // Until multiple attachments at one point is implemented, this will remove the first attachment
487 // This test relies on both attachments having the same default attachment point (in this case LeftHand
488 // since none other has been set).
489 {
490 scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default);
491
492 // default attachment point is currently the left hand.
493 Assert.That(sp.HasAttachments(), Is.True);
494 List<SceneObjectGroup> attachments = sp.GetAttachments();
495 Assert.That(attachments.Count, Is.EqualTo(1));
496 SceneObjectGroup attSo = attachments[0];
497 Assert.That(attSo.Name, Is.EqualTo(attItem2.Name));
498 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
499 Assert.That(attSo.IsAttachment);
500
501 // Check appearance status
502 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
503 Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
504 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
505
506 // Check events
507 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
508 }
509
510 // Test wearing an already attached attachment
511 {
512 scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default);
513
514 // default attachment point is currently the left hand.
515 Assert.That(sp.HasAttachments(), Is.True);
516 List<SceneObjectGroup> attachments = sp.GetAttachments();
517 Assert.That(attachments.Count, Is.EqualTo(1));
518 SceneObjectGroup attSo = attachments[0];
519 Assert.That(attSo.Name, Is.EqualTo(attItem2.Name));
520 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
521 Assert.That(attSo.IsAttachment);
522
523 // Check appearance status
524 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
525 Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
526 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
527
528 // Check events
529 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
530 }
301 } 531 }
302 532
303 /// <summary> 533 /// <summary>
@@ -315,7 +545,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
315 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10); 545 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10);
316 TaskInventoryItem scriptItem 546 TaskInventoryItem scriptItem
317 = TaskInventoryHelpers.AddScript( 547 = TaskInventoryHelpers.AddScript(
318 scene, 548 scene.AssetService,
319 so.RootPart, 549 so.RootPart,
320 "scriptItem", 550 "scriptItem",
321 "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }"); 551 "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }");
@@ -372,7 +602,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
372 Assert.That(scene.InventoryService.GetItem(new InventoryItemBase(attItem.ID)), Is.Null); 602 Assert.That(scene.InventoryService.GetItem(new InventoryItemBase(attItem.ID)), Is.Null);
373 603
374 // Check object in scene 604 // Check object in scene
375 Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null); 605 SceneObjectGroup soInScene = scene.GetSceneObjectGroup("att");
606 Assert.That(soInScene, Is.Not.Null);
607 Assert.IsTrue(soInScene.Backup);
376 608
377 // Check events 609 // Check events
378 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); 610 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
@@ -426,7 +658,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
426 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10); 658 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10);
427 TaskInventoryItem scriptTaskItem 659 TaskInventoryItem scriptTaskItem
428 = TaskInventoryHelpers.AddScript( 660 = TaskInventoryHelpers.AddScript(
429 scene, 661 scene.AssetService,
430 so.RootPart, 662 so.RootPart,
431 "scriptItem", 663 "scriptItem",
432 "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }"); 664 "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }");
@@ -490,7 +722,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
490 SceneObjectGroup rezzedAtt = presence.GetAttachments()[0]; 722 SceneObjectGroup rezzedAtt = presence.GetAttachments()[0];
491 723
492 m_numberOfAttachEventsFired = 0; 724 m_numberOfAttachEventsFired = 0;
493 scene.IncomingCloseAgent(presence.UUID, false); 725 scene.CloseAgent(presence.UUID, false);
494 726
495 // Check that we can't retrieve this attachment from the scene. 727 // Check that we can't retrieve this attachment from the scene.
496 Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null); 728 Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null);
@@ -503,7 +735,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
503 public void TestRezAttachmentsOnAvatarEntrance() 735 public void TestRezAttachmentsOnAvatarEntrance()
504 { 736 {
505 TestHelpers.InMethod(); 737 TestHelpers.InMethod();
506// log4net.Config.XmlConfigurator.Configure(); 738// TestHelpers.EnableLogging();
507 739
508 Scene scene = CreateTestScene(); 740 Scene scene = CreateTestScene();
509 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); 741 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
@@ -526,6 +758,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
526 Assert.That(attSo.IsAttachment); 758 Assert.That(attSo.IsAttachment);
527 Assert.That(attSo.UsesPhysics, Is.False); 759 Assert.That(attSo.UsesPhysics, Is.False);
528 Assert.That(attSo.IsTemporary, Is.False); 760 Assert.That(attSo.IsTemporary, Is.False);
761 Assert.IsFalse(attSo.Backup);
529 762
530 // Check appearance status 763 // Check appearance status
531 List<AvatarAttachment> retreivedAttachments = presence.Appearance.GetAttachments(); 764 List<AvatarAttachment> retreivedAttachments = presence.Appearance.GetAttachments();
@@ -569,12 +802,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
569 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); 802 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
570 } 803 }
571 804
805/*
572 [Test] 806 [Test]
573 public void TestSameSimulatorNeighbouringRegionsTeleport() 807 public void TestSameSimulatorNeighbouringRegionsTeleportV1()
574 { 808 {
575 TestHelpers.InMethod(); 809 TestHelpers.InMethod();
576// TestHelpers.EnableLogging(); 810// TestHelpers.EnableLogging();
577 811
812 BaseHttpServer httpServer = new BaseHttpServer(99999);
813 MainServer.AddHttpServer(httpServer);
814 MainServer.Instance = httpServer;
815
578 AttachmentsModule attModA = new AttachmentsModule(); 816 AttachmentsModule attModA = new AttachmentsModule();
579 AttachmentsModule attModB = new AttachmentsModule(); 817 AttachmentsModule attModB = new AttachmentsModule();
580 EntityTransferModule etmA = new EntityTransferModule(); 818 EntityTransferModule etmA = new EntityTransferModule();
@@ -603,8 +841,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
603 SceneHelpers.SetupSceneModules( 841 SceneHelpers.SetupSceneModules(
604 sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); 842 sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule());
605 843
844 // FIXME: Hack - this is here temporarily to revert back to older entity transfer behaviour
845 lscm.ServiceVersion = 0.1f;
846
606 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); 847 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1);
607 ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, ua1.PrincipalID, sh.SceneManager); 848
849 AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
850 TestClient tc = new TestClient(acd, sceneA);
851 List<TestClient> destinationTestClients = new List<TestClient>();
852 EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients);
853
854 ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd);
608 beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); 855 beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32);
609 856
610 InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); 857 InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20);
@@ -623,7 +870,119 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
623 teleportLookAt, 870 teleportLookAt,
624 (uint)TeleportFlags.ViaLocation); 871 (uint)TeleportFlags.ViaLocation);
625 872
626 ((TestClient)beforeTeleportSp.ControllingClient).CompleteTeleportClientSide(); 873 destinationTestClients[0].CompleteMovement();
874
875 // Check attachments have made it into sceneB
876 ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID);
877
878 // This is appearance data, as opposed to actually rezzed attachments
879 List<AvatarAttachment> sceneBAttachments = afterTeleportSceneBSp.Appearance.GetAttachments();
880 Assert.That(sceneBAttachments.Count, Is.EqualTo(1));
881 Assert.That(sceneBAttachments[0].AttachPoint, Is.EqualTo((int)AttachmentPoint.Chest));
882 Assert.That(sceneBAttachments[0].ItemID, Is.EqualTo(attItem.ID));
883 Assert.That(sceneBAttachments[0].AssetID, Is.EqualTo(attItem.AssetID));
884 Assert.That(afterTeleportSceneBSp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
885
886 // This is the actual attachment
887 List<SceneObjectGroup> actualSceneBAttachments = afterTeleportSceneBSp.GetAttachments();
888 Assert.That(actualSceneBAttachments.Count, Is.EqualTo(1));
889 SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0];
890 Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name));
891 Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest));
892 Assert.IsFalse(actualSceneBAtt.Backup);
893
894 Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1));
895
896 // Check attachments have been removed from sceneA
897 ScenePresence afterTeleportSceneASp = sceneA.GetScenePresence(ua1.PrincipalID);
898
899 // Since this is appearance data, it is still present on the child avatar!
900 List<AvatarAttachment> sceneAAttachments = afterTeleportSceneASp.Appearance.GetAttachments();
901 Assert.That(sceneAAttachments.Count, Is.EqualTo(1));
902 Assert.That(afterTeleportSceneASp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
903
904 // This is the actual attachment, which should no longer exist
905 List<SceneObjectGroup> actualSceneAAttachments = afterTeleportSceneASp.GetAttachments();
906 Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0));
907
908 Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0));
909
910 // Check events
911 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
912 }
913*/
914
915 [Test]
916 public void TestSameSimulatorNeighbouringRegionsTeleportV2()
917 {
918 TestHelpers.InMethod();
919// TestHelpers.EnableLogging();
920
921 BaseHttpServer httpServer = new BaseHttpServer(99999);
922 MainServer.AddHttpServer(httpServer);
923 MainServer.Instance = httpServer;
924
925 AttachmentsModule attModA = new AttachmentsModule();
926 AttachmentsModule attModB = new AttachmentsModule();
927 EntityTransferModule etmA = new EntityTransferModule();
928 EntityTransferModule etmB = new EntityTransferModule();
929 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
930
931 IConfigSource config = new IniConfigSource();
932 IConfig modulesConfig = config.AddConfig("Modules");
933 modulesConfig.Set("EntityTransferModule", etmA.Name);
934 modulesConfig.Set("SimulationServices", lscm.Name);
935
936 modulesConfig.Set("InventoryAccessModule", "BasicInventoryAccessModule");
937
938 SceneHelpers sh = new SceneHelpers();
939 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
940 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000);
941
942 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
943 SceneHelpers.SetupSceneModules(
944 sceneA, config, new CapabilitiesModule(), etmA, attModA, new BasicInventoryAccessModule());
945 SceneHelpers.SetupSceneModules(
946 sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule());
947
948 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1);
949
950 AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
951 TestClient tc = new TestClient(acd, sceneA);
952 List<TestClient> destinationTestClients = new List<TestClient>();
953 EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients);
954
955 ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd);
956 beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32);
957
958 Assert.That(destinationTestClients.Count, Is.EqualTo(1));
959 Assert.That(destinationTestClients[0], Is.Not.Null);
960
961 InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20);
962
963 sceneA.AttachmentsModule.RezSingleAttachmentFromInventory(
964 beforeTeleportSp, attItem.ID, (uint)AttachmentPoint.Chest);
965
966 Vector3 teleportPosition = new Vector3(10, 11, 12);
967 Vector3 teleportLookAt = new Vector3(20, 21, 22);
968
969 // Here, we need to make clientA's receipt of SendRegionTeleport trigger clientB's CompleteMovement(). This
970 // is to operate the teleport V2 mechanism where the EntityTransferModule will first request the client to
971 // CompleteMovement to the region and then call UpdateAgent to the destination region to confirm the receipt
972 // Both these operations will occur on different threads and will wait for each other.
973 // We have to do this via ThreadPool directly since FireAndForget has been switched to sync for the V1
974 // test protocol, where we are trying to avoid unpredictable async operations in regression tests.
975 tc.OnTestClientSendRegionTeleport
976 += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL)
977 => ThreadPool.UnsafeQueueUserWorkItem(o => destinationTestClients[0].CompleteMovement(), null);
978
979 m_numberOfAttachEventsFired = 0;
980 sceneA.RequestTeleportLocation(
981 beforeTeleportSp.ControllingClient,
982 sceneB.RegionInfo.RegionHandle,
983 teleportPosition,
984 teleportLookAt,
985 (uint)TeleportFlags.ViaLocation);
627 986
628 // Check attachments have made it into sceneB 987 // Check attachments have made it into sceneB
629 ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID); 988 ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID);
@@ -642,6 +1001,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
642 SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0]; 1001 SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0];
643 Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name)); 1002 Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name));
644 Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest)); 1003 Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest));
1004 Assert.IsFalse(actualSceneBAtt.Backup);
645 1005
646 Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1)); 1006 Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1));
647 1007
@@ -663,4 +1023,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
663 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); 1023 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
664 } 1024 }
665 } 1025 }
666} \ No newline at end of file 1026}
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index 0a69979..cfb082b 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -40,6 +40,7 @@ using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
41 41
42using Mono.Addins; 42using Mono.Addins;
43using PermissionMask = OpenSim.Framework.PermissionMask;
43 44
44namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory 45namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
45{ 46{
@@ -54,6 +55,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
54 55
55 private int m_savetime = 5; // seconds to wait before saving changed appearance 56 private int m_savetime = 5; // seconds to wait before saving changed appearance
56 private int m_sendtime = 2; // seconds to wait before sending changed appearance 57 private int m_sendtime = 2; // seconds to wait before sending changed appearance
58 private bool m_reusetextures = false;
57 59
58 private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates 60 private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates
59 private System.Timers.Timer m_updateTimer = new System.Timers.Timer(); 61 private System.Timers.Timer m_updateTimer = new System.Timers.Timer();
@@ -72,6 +74,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
72 { 74 {
73 m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); 75 m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime)));
74 m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); 76 m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime)));
77 m_reusetextures = appearanceConfig.GetBoolean("ReuseTextures",m_reusetextures);
78
75 // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime); 79 // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime);
76 } 80 }
77 81
@@ -130,6 +134,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
130 client.OnRequestWearables += Client_OnRequestWearables; 134 client.OnRequestWearables += Client_OnRequestWearables;
131 client.OnSetAppearance += Client_OnSetAppearance; 135 client.OnSetAppearance += Client_OnSetAppearance;
132 client.OnAvatarNowWearing += Client_OnAvatarNowWearing; 136 client.OnAvatarNowWearing += Client_OnAvatarNowWearing;
137 client.OnCachedTextureRequest += Client_OnCachedTextureRequest;
133 } 138 }
134 139
135 #endregion 140 #endregion
@@ -140,9 +145,24 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
140 /// <param name="sp"></param> 145 /// <param name="sp"></param>
141 /// <param name="texture"></param> 146 /// <param name="texture"></param>
142 /// <param name="visualParam"></param> 147 /// <param name="visualParam"></param>
143 public void SetAppearance(IScenePresence sp, AvatarAppearance appearance) 148 public void SetAppearance(IScenePresence sp, AvatarAppearance appearance, WearableCacheItem[] cacheItems)
144 { 149 {
145 SetAppearance(sp, appearance.Texture, appearance.VisualParams); 150 SetAppearance(sp, appearance.Texture, appearance.VisualParams, cacheItems);
151 }
152
153
154 public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
155 {
156 float oldoff = sp.Appearance.AvatarFeetOffset;
157 Vector3 oldbox = sp.Appearance.AvatarBoxSize;
158
159 SetAppearance(sp, textureEntry, visualParams, cacheItems);
160 sp.Appearance.SetSize(avSize);
161
162 float off = sp.Appearance.AvatarFeetOffset;
163 Vector3 box = sp.Appearance.AvatarBoxSize;
164 if (oldoff != off || oldbox != box)
165 ((ScenePresence)sp).SetSize(box, off);
146 } 166 }
147 167
148 /// <summary> 168 /// <summary>
@@ -151,7 +171,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
151 /// <param name="sp"></param> 171 /// <param name="sp"></param>
152 /// <param name="texture"></param> 172 /// <param name="texture"></param>
153 /// <param name="visualParam"></param> 173 /// <param name="visualParam"></param>
154 public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams) 174 public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, WearableCacheItem[] cacheItems)
155 { 175 {
156// m_log.DebugFormat( 176// m_log.DebugFormat(
157// "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}", 177// "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}",
@@ -174,18 +194,27 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
174 // m_log.DebugFormat( 194 // m_log.DebugFormat(
175 // "[AVFACTORY]: Setting visual params for {0} to {1}", 195 // "[AVFACTORY]: Setting visual params for {0} to {1}",
176 // client.Name, string.Join(", ", visualParamsStrings)); 196 // client.Name, string.Join(", ", visualParamsStrings));
177 197/*
178 float oldHeight = sp.Appearance.AvatarHeight; 198 float oldHeight = sp.Appearance.AvatarHeight;
179 changed = sp.Appearance.SetVisualParams(visualParams); 199 changed = sp.Appearance.SetVisualParams(visualParams);
180 200
181 if (sp.Appearance.AvatarHeight != oldHeight && sp.Appearance.AvatarHeight > 0) 201 if (sp.Appearance.AvatarHeight != oldHeight && sp.Appearance.AvatarHeight > 0)
182 ((ScenePresence)sp).SetHeight(sp.Appearance.AvatarHeight); 202 ((ScenePresence)sp).SetHeight(sp.Appearance.AvatarHeight);
183 } 203 */
204// float oldoff = sp.Appearance.AvatarFeetOffset;
205// Vector3 oldbox = sp.Appearance.AvatarBoxSize;
206 changed = sp.Appearance.SetVisualParams(visualParams);
207// float off = sp.Appearance.AvatarFeetOffset;
208// Vector3 box = sp.Appearance.AvatarBoxSize;
209// if(oldoff != off || oldbox != box)
210// ((ScenePresence)sp).SetSize(box,off);
184 211
212 }
213
185 // Process the baked texture array 214 // Process the baked texture array
186 if (textureEntry != null) 215 if (textureEntry != null)
187 { 216 {
188// m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID); 217 m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID);
189 218
190// WriteBakedTexturesReport(sp, m_log.DebugFormat); 219// WriteBakedTexturesReport(sp, m_log.DebugFormat);
191 220
@@ -222,7 +251,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
222 private void SendAppearance(ScenePresence sp) 251 private void SendAppearance(ScenePresence sp)
223 { 252 {
224 // Send the appearance to everyone in the scene 253 // Send the appearance to everyone in the scene
225 sp.SendAppearanceToAllOtherAgents(); 254 sp.SendAppearanceToAllOtherClients();
226 255
227 // Send animations back to the avatar as well 256 // Send animations back to the avatar as well
228 sp.Animator.SendAnimPack(); 257 sp.Animator.SendAnimPack();
@@ -254,6 +283,17 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
254 return GetBakedTextureFaces(sp); 283 return GetBakedTextureFaces(sp);
255 } 284 }
256 285
286 public WearableCacheItem[] GetCachedItems(UUID agentId)
287 {
288 ScenePresence sp = m_scene.GetScenePresence(agentId);
289 WearableCacheItem[] items = sp.Appearance.WearableCacheItems;
290 //foreach (WearableCacheItem item in items)
291 //{
292
293 //}
294 return items;
295 }
296
257 public bool SaveBakedTextures(UUID agentId) 297 public bool SaveBakedTextures(UUID agentId)
258 { 298 {
259 ScenePresence sp = m_scene.GetScenePresence(agentId); 299 ScenePresence sp = m_scene.GetScenePresence(agentId);
@@ -287,6 +327,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
287 327
288 if (asset != null) 328 if (asset != null)
289 { 329 {
330 // Replace an HG ID with the simple asset ID so that we can persist textures for foreign HG avatars
331 asset.ID = asset.FullID.ToString();
332
290 asset.Temporary = false; 333 asset.Temporary = false;
291 asset.Local = false; 334 asset.Local = false;
292 m_scene.AssetService.Store(asset); 335 m_scene.AssetService.Store(asset);
@@ -323,7 +366,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
323 366
324 public void QueueAppearanceSave(UUID agentid) 367 public void QueueAppearanceSave(UUID agentid)
325 { 368 {
326 // m_log.WarnFormat("[AVFACTORY]: Queue appearance save for {0}", agentid); 369// m_log.DebugFormat("[AVFACTORY]: Queueing appearance save for {0}", agentid);
327 370
328 // 10000 ticks per millisecond, 1000 milliseconds per second 371 // 10000 ticks per millisecond, 1000 milliseconds per second
329 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000); 372 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000);
@@ -337,6 +380,53 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
337 public bool ValidateBakedTextureCache(IScenePresence sp) 380 public bool ValidateBakedTextureCache(IScenePresence sp)
338 { 381 {
339 bool defonly = true; // are we only using default textures 382 bool defonly = true; // are we only using default textures
383 IImprovedAssetCache cache = m_scene.RequestModuleInterface<IImprovedAssetCache>();
384 IBakedTextureModule bakedModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
385 WearableCacheItem[] wearableCache = null;
386
387 // Cache wearable data for teleport.
388 // Only makes sense if there's a bake module and a cache module
389 if (bakedModule != null && cache != null)
390 {
391 try
392 {
393 wearableCache = bakedModule.Get(sp.UUID);
394 }
395 catch (Exception)
396 {
397
398 }
399 if (wearableCache != null)
400 {
401 for (int i = 0; i < wearableCache.Length; i++)
402 {
403 cache.Cache(wearableCache[i].TextureAsset);
404 }
405 }
406 }
407 /*
408 IBakedTextureModule bakedModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
409 if (invService.GetRootFolder(userID) != null)
410 {
411 WearableCacheItem[] wearableCache = null;
412 if (bakedModule != null)
413 {
414 try
415 {
416 wearableCache = bakedModule.Get(userID);
417 appearance.WearableCacheItems = wearableCache;
418 appearance.WearableCacheItemsDirty = false;
419 foreach (WearableCacheItem item in wearableCache)
420 {
421 appearance.Texture.FaceTextures[item.TextureIndex].TextureID = item.TextureID;
422 }
423 }
424 catch (Exception)
425 {
426
427 }
428 }
429 */
340 430
341 // Process the texture entry 431 // Process the texture entry
342 for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) 432 for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
@@ -344,10 +434,32 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
344 int idx = AvatarAppearance.BAKE_INDICES[i]; 434 int idx = AvatarAppearance.BAKE_INDICES[i];
345 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; 435 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx];
346 436
347 // if there is no texture entry, skip it 437 // No face, so lets check our baked service cache, teleport or login.
348 if (face == null) 438 if (face == null)
349 continue; 439 {
350 440 if (wearableCache != null)
441 {
442 // If we find the an appearance item, set it as the textureentry and the face
443 WearableCacheItem searchitem = WearableCacheItem.SearchTextureIndex((uint) idx, wearableCache);
444 if (searchitem != null)
445 {
446 sp.Appearance.Texture.FaceTextures[idx] = sp.Appearance.Texture.CreateFace((uint) idx);
447 sp.Appearance.Texture.FaceTextures[idx].TextureID = searchitem.TextureID;
448 face = sp.Appearance.Texture.FaceTextures[idx];
449 }
450 else
451 {
452 // if there is no texture entry and no baked cache, skip it
453 continue;
454 }
455 }
456 else
457 {
458 //No texture entry face and no cache. Skip this face.
459 continue;
460 }
461 }
462
351// m_log.DebugFormat( 463// m_log.DebugFormat(
352// "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", 464// "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}",
353// face.TextureID, idx, client.Name, client.AgentId); 465// face.TextureID, idx, client.Name, client.AgentId);
@@ -374,6 +486,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
374 public int RequestRebake(IScenePresence sp, bool missingTexturesOnly) 486 public int RequestRebake(IScenePresence sp, bool missingTexturesOnly)
375 { 487 {
376 int texturesRebaked = 0; 488 int texturesRebaked = 0;
489// IImprovedAssetCache cache = m_scene.RequestModuleInterface<IImprovedAssetCache>();
377 490
378 for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) 491 for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
379 { 492 {
@@ -480,7 +593,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
480 593
481 if (sendTime < now) 594 if (sendTime < now)
482 { 595 {
483 Util.FireAndForget(o => SendAppearance(avatarID)); 596 Util.FireAndForget(o => SendAppearance(avatarID), null, "AvatarFactoryModule.SendAppearance");
484 m_sendqueue.Remove(avatarID); 597 m_sendqueue.Remove(avatarID);
485 } 598 }
486 } 599 }
@@ -498,7 +611,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
498 611
499 if (sendTime < now) 612 if (sendTime < now)
500 { 613 {
501 Util.FireAndForget(o => SaveAppearance(avatarID)); 614 Util.FireAndForget(o => SaveAppearance(avatarID), null, "AvatarFactoryModule.SaveAppearance");
502 m_savequeue.Remove(avatarID); 615 m_savequeue.Remove(avatarID);
503 } 616 }
504 } 617 }
@@ -526,7 +639,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
526 return; 639 return;
527 } 640 }
528 641
529 // m_log.WarnFormat("[AVFACTORY] avatar {0} save appearance",agentid); 642// m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid);
530 643
531 // This could take awhile since it needs to pull inventory 644 // This could take awhile since it needs to pull inventory
532 // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape 645 // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape
@@ -535,6 +648,14 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
535 // multiple save requests. 648 // multiple save requests.
536 SetAppearanceAssets(sp.UUID, sp.Appearance); 649 SetAppearanceAssets(sp.UUID, sp.Appearance);
537 650
651// List<AvatarAttachment> attachments = sp.Appearance.GetAttachments();
652// foreach (AvatarAttachment att in attachments)
653// {
654// m_log.DebugFormat(
655// "[AVFACTORY]: For {0} saving attachment {1} at point {2}",
656// sp.Name, att.ItemID, att.AttachPoint);
657// }
658
538 m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); 659 m_scene.AvatarService.SetAppearance(agentid, sp.Appearance);
539 660
540 // Trigger this here because it's the final step in the set/queue/save process for appearance setting. 661 // Trigger this here because it's the final step in the set/queue/save process for appearance setting.
@@ -542,6 +663,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
542 m_scene.EventManager.TriggerAvatarAppearanceChanged(sp); 663 m_scene.EventManager.TriggerAvatarAppearanceChanged(sp);
543 } 664 }
544 665
666 /// <summary>
667 /// For a given set of appearance items, check whether the items are valid and add their asset IDs to
668 /// appearance data.
669 /// </summary>
670 /// <param name='userID'></param>
671 /// <param name='appearance'></param>
545 private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance) 672 private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance)
546 { 673 {
547 IInventoryService invService = m_scene.InventoryService; 674 IInventoryService invService = m_scene.InventoryService;
@@ -553,7 +680,13 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
553 for (int j = 0; j < appearance.Wearables[i].Count; j++) 680 for (int j = 0; j < appearance.Wearables[i].Count; j++)
554 { 681 {
555 if (appearance.Wearables[i][j].ItemID == UUID.Zero) 682 if (appearance.Wearables[i][j].ItemID == UUID.Zero)
683 {
684 m_log.WarnFormat(
685 "[AVFACTORY]: Wearable item {0}:{1} for user {2} unexpectedly UUID.Zero. Ignoring.",
686 i, j, userID);
687
556 continue; 688 continue;
689 }
557 690
558 // Ignore ruth's assets 691 // Ignore ruth's assets
559 if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) 692 if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
@@ -568,7 +701,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
568 } 701 }
569 else 702 else
570 { 703 {
571 m_log.ErrorFormat( 704 m_log.WarnFormat(
572 "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default", 705 "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default",
573 appearance.Wearables[i][j].ItemID, (WearableType)i); 706 appearance.Wearables[i][j].ItemID, (WearableType)i);
574 707
@@ -581,8 +714,311 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
581 { 714 {
582 m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID); 715 m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID);
583 } 716 }
717
718// IInventoryService invService = m_scene.InventoryService;
719// bool resetwearable = false;
720// if (invService.GetRootFolder(userID) != null)
721// {
722// for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
723// {
724// for (int j = 0; j < appearance.Wearables[i].Count; j++)
725// {
726// // Check if the default wearables are not set
727// if (appearance.Wearables[i][j].ItemID == UUID.Zero)
728// {
729// switch ((WearableType) i)
730// {
731// case WearableType.Eyes:
732// case WearableType.Hair:
733// case WearableType.Shape:
734// case WearableType.Skin:
735// //case WearableType.Underpants:
736// TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
737// resetwearable = true;
738// m_log.Warn("[AVFACTORY]: UUID.Zero Wearables, passing fake values.");
739// resetwearable = true;
740// break;
741//
742// }
743// continue;
744// }
745//
746// // Ignore ruth's assets except for the body parts! missing body parts fail avatar appearance on V1
747// if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
748// {
749// switch ((WearableType)i)
750// {
751// case WearableType.Eyes:
752// case WearableType.Hair:
753// case WearableType.Shape:
754// case WearableType.Skin:
755// //case WearableType.Underpants:
756// TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
757//
758// m_log.WarnFormat("[AVFACTORY]: {0} Default Wearables, passing existing values.", (WearableType)i);
759// resetwearable = true;
760// break;
761//
762// }
763// continue;
764// }
765//
766// InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID);
767// baseItem = invService.GetItem(baseItem);
768//
769// if (baseItem != null)
770// {
771// appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID);
772// int unmodifiedWearableIndexForClosure = i;
773// m_scene.AssetService.Get(baseItem.AssetID.ToString(), this,
774// delegate(string x, object y, AssetBase z)
775// {
776// if (z == null)
777// {
778// TryAndRepairBrokenWearable(
779// (WearableType)unmodifiedWearableIndexForClosure, invService,
780// userID, appearance);
781// }
782// });
783// }
784// else
785// {
786// m_log.ErrorFormat(
787// "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default",
788// appearance.Wearables[i][j].ItemID, (WearableType)i);
789//
790// TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
791// resetwearable = true;
792//
793// }
794// }
795// }
796//
797// // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
798// if (appearance.Wearables[(int) WearableType.Eyes] == null)
799// {
800// m_log.WarnFormat("[AVFACTORY]: {0} Eyes are Null, passing existing values.", (WearableType.Eyes));
801//
802// TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance);
803// resetwearable = true;
804// }
805// else
806// {
807// if (appearance.Wearables[(int) WearableType.Eyes][0].ItemID == UUID.Zero)
808// {
809// m_log.WarnFormat("[AVFACTORY]: Eyes are UUID.Zero are broken, {0} {1}",
810// appearance.Wearables[(int) WearableType.Eyes][0].ItemID,
811// appearance.Wearables[(int) WearableType.Eyes][0].AssetID);
812// TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance);
813// resetwearable = true;
814//
815// }
816//
817// }
818// // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
819// if (appearance.Wearables[(int)WearableType.Shape] == null)
820// {
821// m_log.WarnFormat("[AVFACTORY]: {0} shape is Null, passing existing values.", (WearableType.Shape));
822//
823// TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance);
824// resetwearable = true;
825// }
826// else
827// {
828// if (appearance.Wearables[(int)WearableType.Shape][0].ItemID == UUID.Zero)
829// {
830// m_log.WarnFormat("[AVFACTORY]: Shape is UUID.Zero and broken, {0} {1}",
831// appearance.Wearables[(int)WearableType.Shape][0].ItemID,
832// appearance.Wearables[(int)WearableType.Shape][0].AssetID);
833// TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance);
834// resetwearable = true;
835//
836// }
837//
838// }
839// // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
840// if (appearance.Wearables[(int)WearableType.Hair] == null)
841// {
842// m_log.WarnFormat("[AVFACTORY]: {0} Hair is Null, passing existing values.", (WearableType.Hair));
843//
844// TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance);
845// resetwearable = true;
846// }
847// else
848// {
849// if (appearance.Wearables[(int)WearableType.Hair][0].ItemID == UUID.Zero)
850// {
851// m_log.WarnFormat("[AVFACTORY]: Hair is UUID.Zero and broken, {0} {1}",
852// appearance.Wearables[(int)WearableType.Hair][0].ItemID,
853// appearance.Wearables[(int)WearableType.Hair][0].AssetID);
854// TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance);
855// resetwearable = true;
856//
857// }
858//
859// }
860// // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
861// if (appearance.Wearables[(int)WearableType.Skin] == null)
862// {
863// m_log.WarnFormat("[AVFACTORY]: {0} Skin is Null, passing existing values.", (WearableType.Skin));
864//
865// TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance);
866// resetwearable = true;
867// }
868// else
869// {
870// if (appearance.Wearables[(int)WearableType.Skin][0].ItemID == UUID.Zero)
871// {
872// m_log.WarnFormat("[AVFACTORY]: Skin is UUID.Zero and broken, {0} {1}",
873// appearance.Wearables[(int)WearableType.Skin][0].ItemID,
874// appearance.Wearables[(int)WearableType.Skin][0].AssetID);
875// TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance);
876// resetwearable = true;
877//
878// }
879//
880// }
881// if (resetwearable)
882// {
883// ScenePresence presence = null;
884// if (m_scene.TryGetScenePresence(userID, out presence))
885// {
886// presence.ControllingClient.SendWearables(presence.Appearance.Wearables,
887// presence.Appearance.Serial++);
888// }
889// }
890//
891// }
892// else
893// {
894// m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID);
895// }
896 }
897
898 private void TryAndRepairBrokenWearable(WearableType type, IInventoryService invService, UUID userID,AvatarAppearance appearance)
899 {
900 UUID defaultwearable = GetDefaultItem(type);
901 if (defaultwearable != UUID.Zero)
902 {
903 UUID newInvItem = UUID.Random();
904 InventoryItemBase itembase = new InventoryItemBase(newInvItem, userID)
905 {
906 AssetID =
907 defaultwearable,
908 AssetType
909 =
910 (int)
911 FolderType
912 .BodyPart,
913 CreatorId
914 =
915 userID
916 .ToString
917 (),
918 //InvType = (int)InventoryType.Wearable,
919
920 Description
921 =
922 "Failed Wearable Replacement",
923 Folder =
924 invService
925 .GetFolderForType
926 (userID,
927 FolderType
928 .BodyPart)
929 .ID,
930 Flags = (uint) type,
931 Name = Enum.GetName(typeof (WearableType), type),
932 BasePermissions = (uint) PermissionMask.Copy,
933 CurrentPermissions = (uint) PermissionMask.Copy,
934 EveryOnePermissions = (uint) PermissionMask.Copy,
935 GroupPermissions = (uint) PermissionMask.Copy,
936 NextPermissions = (uint) PermissionMask.Copy
937 };
938 invService.AddItem(itembase);
939 UUID LinkInvItem = UUID.Random();
940 itembase = new InventoryItemBase(LinkInvItem, userID)
941 {
942 AssetID =
943 newInvItem,
944 AssetType
945 =
946 (int)
947 AssetType
948 .Link,
949 CreatorId
950 =
951 userID
952 .ToString
953 (),
954 InvType = (int) InventoryType.Wearable,
955
956 Description
957 =
958 "Failed Wearable Replacement",
959 Folder =
960 invService
961 .GetFolderForType
962 (userID,
963 FolderType
964 .CurrentOutfit)
965 .ID,
966 Flags = (uint) type,
967 Name = Enum.GetName(typeof (WearableType), type),
968 BasePermissions = (uint) PermissionMask.Copy,
969 CurrentPermissions = (uint) PermissionMask.Copy,
970 EveryOnePermissions = (uint) PermissionMask.Copy,
971 GroupPermissions = (uint) PermissionMask.Copy,
972 NextPermissions = (uint) PermissionMask.Copy
973 };
974 invService.AddItem(itembase);
975 appearance.Wearables[(int)type] = new AvatarWearable(newInvItem, GetDefaultItem(type));
976 ScenePresence presence = null;
977 if (m_scene.TryGetScenePresence(userID, out presence))
978 {
979 m_scene.SendInventoryUpdate(presence.ControllingClient,
980 invService.GetFolderForType(userID,
981 FolderType
982 .CurrentOutfit),
983 false, true);
984 }
985 }
584 } 986 }
585 987
988 private UUID GetDefaultItem(WearableType wearable)
989 {
990 // These are ruth
991 UUID ret = UUID.Zero;
992 switch (wearable)
993 {
994 case WearableType.Eyes:
995 ret = new UUID("4bb6fa4d-1cd2-498a-a84c-95c1a0e745a7");
996 break;
997 case WearableType.Hair:
998 ret = new UUID("d342e6c0-b9d2-11dc-95ff-0800200c9a66");
999 break;
1000 case WearableType.Pants:
1001 ret = new UUID("00000000-38f9-1111-024e-222222111120");
1002 break;
1003 case WearableType.Shape:
1004 ret = new UUID("66c41e39-38f9-f75a-024e-585989bfab73");
1005 break;
1006 case WearableType.Shirt:
1007 ret = new UUID("00000000-38f9-1111-024e-222222111110");
1008 break;
1009 case WearableType.Skin:
1010 ret = new UUID("77c41e39-38f9-f75a-024e-585989bbabbb");
1011 break;
1012 case WearableType.Undershirt:
1013 ret = new UUID("16499ebb-3208-ec27-2def-481881728f47");
1014 break;
1015 case WearableType.Underpants:
1016 ret = new UUID("4ac2e9c7-3671-d229-316a-67717730841d");
1017 break;
1018 }
1019
1020 return ret;
1021 }
586 #endregion 1022 #endregion
587 1023
588 #region Client Event Handlers 1024 #region Client Event Handlers
@@ -592,12 +1028,17 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
592 /// <param name="client"></param> 1028 /// <param name="client"></param>
593 private void Client_OnRequestWearables(IClientAPI client) 1029 private void Client_OnRequestWearables(IClientAPI client)
594 { 1030 {
595 // m_log.DebugFormat("[AVFACTORY]: Client_OnRequestWearables called for {0} ({1})", client.Name, client.AgentId); 1031 Util.FireAndForget(delegate(object x)
596 ScenePresence sp = m_scene.GetScenePresence(client.AgentId); 1032 {
597 if (sp != null) 1033 Thread.Sleep(4000);
598 client.SendWearables(sp.Appearance.Wearables, sp.Appearance.Serial++); 1034
599 else 1035 // m_log.DebugFormat("[AVFACTORY]: Client_OnRequestWearables called for {0} ({1})", client.Name, client.AgentId);
600 m_log.WarnFormat("[AVFACTORY]: Client_OnRequestWearables unable to find presence for {0}", client.AgentId); 1036 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
1037 if (sp != null)
1038 client.SendWearables(sp.Appearance.Wearables, sp.Appearance.Serial++);
1039 else
1040 m_log.WarnFormat("[AVFACTORY]: Client_OnRequestWearables unable to find presence for {0}", client.AgentId);
1041 }, null, "AvatarFactoryModule.OnClientRequestWearables");
601 } 1042 }
602 1043
603 /// <summary> 1044 /// <summary>
@@ -606,12 +1047,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
606 /// <param name="client"></param> 1047 /// <param name="client"></param>
607 /// <param name="texture"></param> 1048 /// <param name="texture"></param>
608 /// <param name="visualParam"></param> 1049 /// <param name="visualParam"></param>
609 private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams) 1050 private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
610 { 1051 {
611 // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId); 1052 // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId);
612 ScenePresence sp = m_scene.GetScenePresence(client.AgentId); 1053 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
613 if (sp != null) 1054 if (sp != null)
614 SetAppearance(sp, textureEntry, visualParams); 1055 SetAppearance(sp, textureEntry, visualParams,avSize, cacheItems);
615 else 1056 else
616 m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId); 1057 m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId);
617 } 1058 }
@@ -659,6 +1100,61 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
659 QueueAppearanceSave(client.AgentId); 1100 QueueAppearanceSave(client.AgentId);
660 } 1101 }
661 } 1102 }
1103
1104 /// <summary>
1105 /// Respond to the cached textures request from the client
1106 /// </summary>
1107 /// <param name="client"></param>
1108 /// <param name="serial"></param>
1109 /// <param name="cachedTextureRequest"></param>
1110 private void Client_OnCachedTextureRequest(IClientAPI client, int serial, List<CachedTextureRequestArg> cachedTextureRequest)
1111 {
1112 // m_log.WarnFormat("[AVFACTORY]: Client_OnCachedTextureRequest called for {0} ({1})", client.Name, client.AgentId);
1113 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
1114
1115 List<CachedTextureResponseArg> cachedTextureResponse = new List<CachedTextureResponseArg>();
1116 foreach (CachedTextureRequestArg request in cachedTextureRequest)
1117 {
1118 UUID texture = UUID.Zero;
1119 int index = request.BakedTextureIndex;
1120
1121 if (m_reusetextures)
1122 {
1123 // this is the most insanely dumb way to do this... however it seems to
1124 // actually work. if the appearance has been reset because wearables have
1125 // changed then the texture entries are zero'd out until the bakes are
1126 // uploaded. on login, if the textures exist in the cache (eg if you logged
1127 // into the simulator recently, then the appearance will pull those and send
1128 // them back in the packet and you won't have to rebake. if the textures aren't
1129 // in the cache then the intial makeroot() call in scenepresence will zero
1130 // them out.
1131 //
1132 // a better solution (though how much better is an open question) is to
1133 // store the hashes in the appearance and compare them. Thats's coming.
1134
1135 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index];
1136 if (face != null)
1137 texture = face.TextureID;
1138
1139 // m_log.WarnFormat("[AVFACTORY]: reuse texture {0} for index {1}",texture,index);
1140 }
1141
1142 CachedTextureResponseArg response = new CachedTextureResponseArg();
1143 response.BakedTextureIndex = index;
1144 response.BakedTextureID = texture;
1145 response.HostName = null;
1146
1147 cachedTextureResponse.Add(response);
1148 }
1149
1150 // m_log.WarnFormat("[AVFACTORY]: serial is {0}",serial);
1151 // The serial number appears to be used to match requests and responses
1152 // in the texture transaction. We just send back the serial number
1153 // that was provided in the request. The viewer bumps this for us.
1154 client.SendCachedTextureResponse(sp, serial, cachedTextureResponse);
1155 }
1156
1157
662 #endregion 1158 #endregion
663 1159
664 public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction) 1160 public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction)
@@ -690,7 +1186,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
690 } 1186 }
691 1187
692 bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp); 1188 bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp);
693 outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "corrupt"); 1189 outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete");
694 } 1190 }
695 } 1191 }
696} 1192}
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
index 1830d41..9513408 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
@@ -34,7 +34,6 @@ using OpenSim.Framework;
34using OpenSim.Region.CoreModules.Asset; 34using OpenSim.Region.CoreModules.Asset;
35using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Tests.Common; 36using OpenSim.Tests.Common;
37using OpenSim.Tests.Common.Mock;
38 37
39namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory 38namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
40{ 39{
@@ -48,23 +47,103 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
48 public void TestSetAppearance() 47 public void TestSetAppearance()
49 { 48 {
50 TestHelpers.InMethod(); 49 TestHelpers.InMethod();
51// log4net.Config.XmlConfigurator.Configure(); 50// TestHelpers.EnableLogging();
52 51
53 UUID userId = TestHelpers.ParseTail(0x1); 52 UUID userId = TestHelpers.ParseTail(0x1);
53 UUID bakedTextureID = TestHelpers.ParseTail(0x2);
54 54
55 // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly
56 // to the AssetService, which will then store temporary and local assets permanently
57 CoreAssetCache assetCache = new CoreAssetCache();
58
55 AvatarFactoryModule afm = new AvatarFactoryModule(); 59 AvatarFactoryModule afm = new AvatarFactoryModule();
56 TestScene scene = new SceneHelpers().SetupScene(); 60 TestScene scene = new SceneHelpers(assetCache).SetupScene();
57 SceneHelpers.SetupSceneModules(scene, afm); 61 SceneHelpers.SetupSceneModules(scene, afm);
58 ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); 62 ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId);
59 63
64 // TODO: Use the actual BunchOfCaps functionality once we slot in the CapabilitiesModules
65 AssetBase bakedTextureAsset;
66 bakedTextureAsset
67 = new AssetBase(
68 bakedTextureID, "Test Baked Texture", (sbyte)AssetType.Texture, userId.ToString());
69 bakedTextureAsset.Data = new byte[] { 2 }; // Not necessary to have a genuine JPEG2000 asset here yet
70 bakedTextureAsset.Temporary = true;
71 bakedTextureAsset.Local = true;
72 scene.AssetService.Store(bakedTextureAsset);
73
60 byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT]; 74 byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT];
61 for (byte i = 0; i < visualParams.Length; i++) 75 for (byte i = 0; i < visualParams.Length; i++)
62 visualParams[i] = i; 76 visualParams[i] = i;
63 77
64 afm.SetAppearance(sp, new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)), visualParams); 78 Primitive.TextureEntry bakedTextureEntry = new Primitive.TextureEntry(TestHelpers.ParseTail(0x10));
79 uint eyesFaceIndex = (uint)AppearanceManager.BakeTypeToAgentTextureIndex(BakeType.Eyes);
80 Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex);
81
82 int rebakeRequestsReceived = 0;
83 ((TestClient)sp.ControllingClient).OnReceivedSendRebakeAvatarTextures += id => rebakeRequestsReceived++;
84
85 // This is the alpha texture
86 eyesFace.TextureID = bakedTextureID;
87 afm.SetAppearance(sp, bakedTextureEntry, visualParams, null);
88
89 Assert.That(rebakeRequestsReceived, Is.EqualTo(0));
90
91 AssetBase eyesBake = scene.AssetService.Get(bakedTextureID.ToString());
92 Assert.That(eyesBake, Is.Not.Null);
93 Assert.That(eyesBake.Temporary, Is.True);
94 Assert.That(eyesBake.Local, Is.True);
95 }
96
97 /// <summary>
98 /// Test appearance setting where the baked texture UUID are library alpha textures.
99 /// </summary>
100 /// <remarks>
101 /// For a mesh avatar, it appears these 'baked textures' are used. So these should not trigger a request to
102 /// rebake.
103 /// </remarks>
104 [Test]
105 public void TestSetAppearanceAlphaBakedTextures()
106 {
107 TestHelpers.InMethod();
108// TestHelpers.EnableLogging();
109
110 UUID userId = TestHelpers.ParseTail(0x1);
111 UUID alphaTextureID = new UUID("3a367d1c-bef1-6d43-7595-e88c1e3aadb3");
112
113 // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly
114 // to the AssetService, which will then store temporary and local assets permanently
115 CoreAssetCache assetCache = new CoreAssetCache();
116
117 AvatarFactoryModule afm = new AvatarFactoryModule();
118 TestScene scene = new SceneHelpers(assetCache).SetupScene();
119 SceneHelpers.SetupSceneModules(scene, afm);
120 ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId);
121
122 AssetBase libraryAsset;
123 libraryAsset
124 = new AssetBase(
125 alphaTextureID, "Default Alpha Layer Texture", (sbyte)AssetType.Texture, userId.ToString());
126 libraryAsset.Data = new byte[] { 2 }; // Not necessary to have a genuine JPEG2000 asset here yet
127 libraryAsset.Temporary = false;
128 libraryAsset.Local = false;
129 scene.AssetService.Store(libraryAsset);
130
131 byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT];
132 for (byte i = 0; i < visualParams.Length; i++)
133 visualParams[i] = i;
134
135 Primitive.TextureEntry bakedTextureEntry = new Primitive.TextureEntry(TestHelpers.ParseTail(0x10));
136 uint eyesFaceIndex = (uint)AppearanceManager.BakeTypeToAgentTextureIndex(BakeType.Eyes);
137 Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex);
138
139 int rebakeRequestsReceived = 0;
140 ((TestClient)sp.ControllingClient).OnReceivedSendRebakeAvatarTextures += id => rebakeRequestsReceived++;
65 141
66 // TODO: Check baked texture 142 // This is the alpha texture
67 Assert.AreEqual(visualParams, sp.Appearance.VisualParams); 143 eyesFace.TextureID = alphaTextureID;
144 afm.SetAppearance(sp, bakedTextureEntry, visualParams, null);
145
146 Assert.That(rebakeRequestsReceived, Is.EqualTo(0));
68 } 147 }
69 148
70 [Test] 149 [Test]
@@ -102,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
102 Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex); 181 Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex);
103 eyesFace.TextureID = eyesTextureId; 182 eyesFace.TextureID = eyesTextureId;
104 183
105 afm.SetAppearance(sp, bakedTextureEntry, visualParams); 184 afm.SetAppearance(sp, bakedTextureEntry, visualParams, null);
106 afm.SaveBakedTextures(userId); 185 afm.SaveBakedTextures(userId);
107// Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = afm.GetBakedTextureFaces(userId); 186// Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = afm.GetBakedTextureFaces(userId);
108 187
diff --git a/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs b/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs
new file mode 100644
index 0000000..414f06a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs
@@ -0,0 +1,200 @@
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 OpenMetaverse;
29using Nini.Config;
30using System;
31using System.IO;
32using System.Text;
33using System.Xml;
34using System.Xml.Serialization;
35using System.Collections;
36using System.Collections.Generic;
37using System.Reflection;
38using log4net;
39using OpenSim.Framework;
40using OpenSim.Framework.ServiceAuth;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Services.Interfaces;
44using Mono.Addins;
45
46namespace OpenSim.Region.CoreModules.Avatar.BakedTextures
47{
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XBakes.Module")]
49 public class XBakesModule : INonSharedRegionModule, IBakedTextureModule
50 {
51 protected Scene m_Scene;
52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 private UTF8Encoding enc = new UTF8Encoding();
54 private string m_URL = String.Empty;
55 private static XmlSerializer m_serializer = new XmlSerializer(typeof(AssetBase));
56
57 private static IServiceAuth m_Auth;
58
59 public void Initialise(IConfigSource configSource)
60 {
61 IConfig config = configSource.Configs["XBakes"];
62 if (config == null)
63 return;
64
65 m_URL = config.GetString("URL", String.Empty);
66 m_Auth = ServiceAuth.Create(configSource, "XBakes");
67 }
68
69 public void AddRegion(Scene scene)
70 {
71 // m_log.InfoFormat("[XBakes]: Enabled for region {0}", scene.RegionInfo.RegionName);
72 m_Scene = scene;
73
74 scene.RegisterModuleInterface<IBakedTextureModule>(this);
75 }
76
77 public void RegionLoaded(Scene scene)
78 {
79 }
80
81 public void RemoveRegion(Scene scene)
82 {
83 }
84
85 public void Close()
86 {
87 }
88
89 public string Name
90 {
91 get { return "XBakes.Module"; }
92 }
93
94 public Type ReplaceableInterface
95 {
96 get { return null; }
97 }
98
99 public WearableCacheItem[] Get(UUID id)
100 {
101 if (m_URL == String.Empty)
102 return null;
103
104 int size = 0;
105
106 using (RestClient rc = new RestClient(m_URL))
107 {
108 List<WearableCacheItem> ret = new List<WearableCacheItem>();
109 rc.AddResourcePath("bakes");
110 rc.AddResourcePath(id.ToString());
111
112 rc.RequestMethod = "GET";
113
114 try
115 {
116 Stream s = rc.Request(m_Auth);
117
118 using (XmlTextReader sr = new XmlTextReader(s))
119 {
120 sr.ReadStartElement("BakedAppearance");
121 while (sr.LocalName == "BakedTexture")
122 {
123 string sTextureIndex = sr.GetAttribute("TextureIndex");
124 int lTextureIndex = Convert.ToInt32(sTextureIndex);
125 string sCacheId = sr.GetAttribute("CacheId");
126 UUID lCacheId = UUID.Zero;
127 if (!(UUID.TryParse(sCacheId, out lCacheId)))
128 {
129 // ?? Nothing here
130 }
131
132 ++size;
133
134 sr.ReadStartElement("BakedTexture");
135 AssetBase a = (AssetBase)m_serializer.Deserialize(sr);
136 ret.Add(new WearableCacheItem() { CacheId = lCacheId, TextureIndex = (uint)lTextureIndex, TextureAsset = a, TextureID = a.FullID });
137
138 sr.ReadEndElement();
139 }
140
141 m_log.DebugFormat("[XBakes]: read {0} textures for user {1}", ret.Count, id);
142 }
143
144 return ret.ToArray();
145 }
146 catch (XmlException)
147 {
148 return null;
149 }
150 }
151 }
152
153 public void Store(UUID agentId, WearableCacheItem[] data)
154 {
155 if (m_URL == String.Empty)
156 return;
157
158 MemoryStream reqStream;
159
160 using (MemoryStream bakeStream = new MemoryStream())
161 using (XmlTextWriter bakeWriter = new XmlTextWriter(bakeStream, null))
162 {
163 bakeWriter.WriteStartElement(String.Empty, "BakedAppearance", String.Empty);
164
165 for (int i = 0; i < data.Length; i++)
166 {
167 if (data[i] != null)
168 {
169 bakeWriter.WriteStartElement(String.Empty, "BakedTexture", String.Empty);
170 bakeWriter.WriteAttributeString(String.Empty, "TextureIndex", String.Empty, data[i].TextureIndex.ToString());
171 bakeWriter.WriteAttributeString(String.Empty, "CacheId", String.Empty, data[i].CacheId.ToString());
172 if (data[i].TextureAsset != null)
173 m_serializer.Serialize(bakeWriter, data[i].TextureAsset);
174
175 bakeWriter.WriteEndElement();
176 }
177 }
178
179 bakeWriter.WriteEndElement();
180 bakeWriter.Flush();
181
182 reqStream = new MemoryStream(bakeStream.ToArray());
183 }
184
185 RestClient rc = new RestClient(m_URL);
186 rc.AddResourcePath("bakes");
187 rc.AddResourcePath(agentId.ToString());
188
189 rc.RequestMethod = "POST";
190
191 Util.FireAndForget(
192 delegate
193 {
194 rc.Request(reqStream, m_Auth);
195 m_log.DebugFormat("[XBakes]: stored {0} textures for user {1}", data.Length, agentId);
196 }, null, "XBakesModule.Store"
197 );
198 }
199 }
200} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
index 6d62ff0..f0b1e67 100644
--- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
@@ -32,6 +32,7 @@ using log4net;
32using Nini.Config; 32using Nini.Config;
33using Mono.Addins; 33using Mono.Addins;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
35using OpenSim.Framework; 36using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
@@ -50,7 +51,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
50 private int m_saydistance = 20; 51 private int m_saydistance = 20;
51 private int m_shoutdistance = 100; 52 private int m_shoutdistance = 100;
52 private int m_whisperdistance = 10; 53 private int m_whisperdistance = 10;
53 private List<Scene> m_scenes = new List<Scene>();
54 54
55 internal object m_syncy = new object(); 55 internal object m_syncy = new object();
56 56
@@ -61,18 +61,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
61 { 61 {
62 m_config = config.Configs["Chat"]; 62 m_config = config.Configs["Chat"];
63 63
64 if (null == m_config) 64 if (m_config != null)
65 { 65 {
66 m_log.Info("[CHAT]: no config found, plugin disabled"); 66 if (!m_config.GetBoolean("enabled", true))
67 m_enabled = false; 67 {
68 return; 68 m_log.Info("[CHAT]: plugin disabled by configuration");
69 } 69 m_enabled = false;
70 70 return;
71 if (!m_config.GetBoolean("enabled", true)) 71 }
72 {
73 m_log.Info("[CHAT]: plugin disabled by configuration");
74 m_enabled = false;
75 return;
76 } 72 }
77 73
78 m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance); 74 m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance);
@@ -82,18 +78,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
82 78
83 public virtual void AddRegion(Scene scene) 79 public virtual void AddRegion(Scene scene)
84 { 80 {
85 if (!m_enabled) return; 81 if (!m_enabled)
82 return;
86 83
87 lock (m_syncy) 84 scene.EventManager.OnNewClient += OnNewClient;
88 { 85 scene.EventManager.OnChatFromWorld += OnChatFromWorld;
89 if (!m_scenes.Contains(scene)) 86 scene.EventManager.OnChatBroadcast += OnChatBroadcast;
90 {
91 m_scenes.Add(scene);
92 scene.EventManager.OnNewClient += OnNewClient;
93 scene.EventManager.OnChatFromWorld += OnChatFromWorld;
94 scene.EventManager.OnChatBroadcast += OnChatBroadcast;
95 }
96 }
97 87
98 m_log.InfoFormat("[CHAT]: Initialized for {0} w:{1} s:{2} S:{3}", scene.RegionInfo.RegionName, 88 m_log.InfoFormat("[CHAT]: Initialized for {0} w:{1} s:{2} S:{3}", scene.RegionInfo.RegionName,
99 m_whisperdistance, m_saydistance, m_shoutdistance); 89 m_whisperdistance, m_saydistance, m_shoutdistance);
@@ -101,22 +91,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
101 91
102 public virtual void RegionLoaded(Scene scene) 92 public virtual void RegionLoaded(Scene scene)
103 { 93 {
94 if (!m_enabled)
95 return;
96
97 ISimulatorFeaturesModule featuresModule = scene.RequestModuleInterface<ISimulatorFeaturesModule>();
98
99 if (featuresModule != null)
100 featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest;
101
104 } 102 }
105 103
106 public virtual void RemoveRegion(Scene scene) 104 public virtual void RemoveRegion(Scene scene)
107 { 105 {
108 if (!m_enabled) return; 106 if (!m_enabled)
107 return;
109 108
110 lock (m_syncy) 109 scene.EventManager.OnNewClient -= OnNewClient;
111 { 110 scene.EventManager.OnChatFromWorld -= OnChatFromWorld;
112 if (m_scenes.Contains(scene)) 111 scene.EventManager.OnChatBroadcast -= OnChatBroadcast;
113 {
114 scene.EventManager.OnNewClient -= OnNewClient;
115 scene.EventManager.OnChatFromWorld -= OnChatFromWorld;
116 scene.EventManager.OnChatBroadcast -= OnChatBroadcast;
117 m_scenes.Remove(scene);
118 }
119 }
120 } 112 }
121 113
122 public virtual void Close() 114 public virtual void Close()
@@ -191,23 +183,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
191 UUID ownerID = UUID.Zero; 183 UUID ownerID = UUID.Zero;
192 UUID targetID = c.TargetUUID; 184 UUID targetID = c.TargetUUID;
193 string message = c.Message; 185 string message = c.Message;
194 IScene scene = c.Scene; 186 Scene scene = (Scene)c.Scene;
195 Vector3 fromPos = c.Position; 187 Vector3 fromPos = c.Position;
196 Vector3 regionPos = new Vector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, 188 Vector3 regionPos = new Vector3(scene.RegionInfo.WorldLocX, scene.RegionInfo.WorldLocY, 0);
197 scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
198 189
199 if (c.Channel == DEBUG_CHANNEL) c.Type = ChatTypeEnum.DebugChannel; 190 if (c.Channel == DEBUG_CHANNEL) c.Type = ChatTypeEnum.DebugChannel;
200 191
201 switch (sourceType) 192 switch (sourceType)
202 { 193 {
203 case ChatSourceType.Agent: 194 case ChatSourceType.Agent:
204 if (!(scene is Scene)) 195 ScenePresence avatar = scene.GetScenePresence(c.Sender.AgentId);
205 {
206 m_log.WarnFormat("[CHAT]: scene {0} is not a Scene object, cannot obtain scene presence for {1}",
207 scene.RegionInfo.RegionName, c.Sender.AgentId);
208 return;
209 }
210 ScenePresence avatar = (scene as Scene).GetScenePresence(c.Sender.AgentId);
211 fromPos = avatar.AbsolutePosition; 196 fromPos = avatar.AbsolutePosition;
212 fromName = avatar.Name; 197 fromName = avatar.Name;
213 fromID = c.Sender.AgentId; 198 fromID = c.Sender.AgentId;
@@ -234,36 +219,33 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
234 219
235 HashSet<UUID> receiverIDs = new HashSet<UUID>(); 220 HashSet<UUID> receiverIDs = new HashSet<UUID>();
236 221
237 foreach (Scene s in m_scenes) 222 if (targetID == UUID.Zero)
238 { 223 {
239 if (targetID == UUID.Zero) 224 // This should use ForEachClient, but clients don't have a position.
240 { 225 // If camera is moved into client, then camera position can be used
241 // This should use ForEachClient, but clients don't have a position. 226 scene.ForEachScenePresence(
242 // If camera is moved into client, then camera position can be used 227 delegate(ScenePresence presence)
243 s.ForEachRootScenePresence(
244 delegate(ScenePresence presence)
245 {
246 if (TrySendChatMessage(
247 presence, fromPos, regionPos, fromID, ownerID, fromName, c.Type, message, sourceType, false))
248 receiverIDs.Add(presence.UUID);
249 }
250 );
251 }
252 else
253 {
254 // This is a send to a specific client eg from llRegionSayTo
255 // no need to check distance etc, jand send is as say
256 ScenePresence presence = s.GetScenePresence(targetID);
257 if (presence != null && !presence.IsChildAgent)
258 { 228 {
259 if (TrySendChatMessage( 229 if (TrySendChatMessage(
260 presence, fromPos, regionPos, fromID, ownerID, fromName, ChatTypeEnum.Say, message, sourceType, true)) 230 presence, fromPos, regionPos, fromID, ownerID, fromName, c.Type, message, sourceType, false))
261 receiverIDs.Add(presence.UUID); 231 receiverIDs.Add(presence.UUID);
262 } 232 }
233 );
234 }
235 else
236 {
237 // This is a send to a specific client eg from llRegionSayTo
238 // no need to check distance etc, jand send is as say
239 ScenePresence presence = scene.GetScenePresence(targetID);
240 if (presence != null && !presence.IsChildAgent)
241 {
242 if (TrySendChatMessage(
243 presence, fromPos, regionPos, fromID, ownerID, fromName, ChatTypeEnum.Say, message, sourceType, true))
244 receiverIDs.Add(presence.UUID);
263 } 245 }
264 } 246 }
265 247
266 (scene as Scene).EventManager.TriggerOnChatToClients( 248 scene.EventManager.TriggerOnChatToClients(
267 fromID, receiverIDs, message, c.Type, fromPos, fromName, sourceType, ChatAudibleLevel.Fully); 249 fromID, receiverIDs, message, c.Type, fromPos, fromName, sourceType, ChatAudibleLevel.Fully);
268 } 250 }
269 251
@@ -288,17 +270,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
288 string fromName = c.From; 270 string fromName = c.From;
289 271
290 UUID fromID = UUID.Zero; 272 UUID fromID = UUID.Zero;
273 UUID ownerID = UUID.Zero;
291 ChatSourceType sourceType = ChatSourceType.Object; 274 ChatSourceType sourceType = ChatSourceType.Object;
292 if (null != c.Sender) 275 if (null != c.Sender)
293 { 276 {
294 ScenePresence avatar = (c.Scene as Scene).GetScenePresence(c.Sender.AgentId); 277 ScenePresence avatar = (c.Scene as Scene).GetScenePresence(c.Sender.AgentId);
295 fromID = c.Sender.AgentId; 278 fromID = c.Sender.AgentId;
296 fromName = avatar.Name; 279 fromName = avatar.Name;
280 ownerID = c.Sender.AgentId;
297 sourceType = ChatSourceType.Agent; 281 sourceType = ChatSourceType.Agent;
298 } 282 }
299 else if (c.SenderUUID != UUID.Zero) 283 else if (c.SenderUUID != UUID.Zero)
300 { 284 {
301 fromID = c.SenderUUID; 285 fromID = c.SenderUUID;
286 ownerID = ((SceneObjectPart)c.SenderObject).OwnerID;
302 } 287 }
303 288
304 // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType); 289 // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType);
@@ -316,7 +301,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
316 return; 301 return;
317 302
318 client.SendChatMessage( 303 client.SendChatMessage(
319 c.Message, (byte)cType, CenterOfRegion, fromName, fromID, fromID, 304 c.Message, (byte)cType, CenterOfRegion, fromName, fromID, ownerID,
320 (byte)sourceType, (byte)ChatAudibleLevel.Fully); 305 (byte)sourceType, (byte)ChatAudibleLevel.Fully);
321 306
322 receiverIDs.Add(client.AgentId); 307 receiverIDs.Add(client.AgentId);
@@ -348,18 +333,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
348 UUID fromAgentID, UUID ownerID, string fromName, ChatTypeEnum type, 333 UUID fromAgentID, UUID ownerID, string fromName, ChatTypeEnum type,
349 string message, ChatSourceType src, bool ignoreDistance) 334 string message, ChatSourceType src, bool ignoreDistance)
350 { 335 {
351 // don't send stuff to child agents 336 if (presence.LifecycleState != ScenePresenceState.Running)
352 if (presence.IsChildAgent) return false; 337 return false;
353
354 Vector3 fromRegionPos = fromPos + regionPos;
355 Vector3 toRegionPos = presence.AbsolutePosition +
356 new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize,
357 presence.Scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
358
359 int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos);
360 338
361 if (!ignoreDistance) 339 if (!ignoreDistance)
362 { 340 {
341 Vector3 fromRegionPos = fromPos + regionPos;
342 Vector3 toRegionPos = presence.AbsolutePosition +
343 new Vector3(presence.Scene.RegionInfo.WorldLocX, presence.Scene.RegionInfo.WorldLocY, 0);
344
345 int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos);
346
363 if (type == ChatTypeEnum.Whisper && dis > m_whisperdistance || 347 if (type == ChatTypeEnum.Whisper && dis > m_whisperdistance ||
364 type == ChatTypeEnum.Say && dis > m_saydistance || 348 type == ChatTypeEnum.Say && dis > m_saydistance ||
365 type == ChatTypeEnum.Shout && dis > m_shoutdistance) 349 type == ChatTypeEnum.Shout && dis > m_shoutdistance)
@@ -375,5 +359,33 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
375 359
376 return true; 360 return true;
377 } 361 }
362
363 #region SimulatorFeaturesRequest
364
365 static OSDInteger m_SayRange, m_WhisperRange, m_ShoutRange;
366
367 private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features)
368 {
369 OSD extras = new OSDMap();
370 if (features.ContainsKey("OpenSimExtras"))
371 extras = features["OpenSimExtras"];
372 else
373 features["OpenSimExtras"] = extras;
374
375 if (m_SayRange == null)
376 {
377 // Do this only once
378 m_SayRange = new OSDInteger(m_saydistance);
379 m_WhisperRange = new OSDInteger(m_whisperdistance);
380 m_ShoutRange = new OSDInteger(m_shoutdistance);
381 }
382
383 ((OSDMap)extras)["say-range"] = m_SayRange;
384 ((OSDMap)extras)["whisper-range"] = m_WhisperRange;
385 ((OSDMap)extras)["shout-range"] = m_ShoutRange;
386
387 }
388
389 #endregion
378 } 390 }
379} \ No newline at end of file 391}
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs
new file mode 100644
index 0000000..3018d94
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs
@@ -0,0 +1,285 @@
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 log4net.Config;
31using Nini.Config;
32using NUnit.Framework;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Framework.Servers;
36using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Region.CoreModules.Avatar.Chat;
38using OpenSim.Region.CoreModules.Framework;
39using OpenSim.Region.CoreModules.Framework.EntityTransfer;
40using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Services.Interfaces;
43using OpenSim.Tests.Common;
44
45namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests
46{
47 [TestFixture]
48 public class ChatModuleTests : OpenSimTestCase
49 {
50 [TestFixtureSetUp]
51 public void FixtureInit()
52 {
53 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
54 // We must do this here so that child agent positions are updated in a predictable manner.
55 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
56 }
57
58 [TestFixtureTearDown]
59 public void TearDown()
60 {
61 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
62 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
63 // tests really shouldn't).
64 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
65 }
66
67 private void SetupNeighbourRegions(TestScene sceneA, TestScene sceneB)
68 {
69 // XXX: HTTP server is not (and should not be) necessary for this test, though it's absence makes the
70 // CapabilitiesModule complain when it can't set up HTTP endpoints.
71 // BaseHttpServer httpServer = new BaseHttpServer(99999);
72 // MainServer.AddHttpServer(httpServer);
73 // MainServer.Instance = httpServer;
74
75 // We need entity transfer modules so that when sp2 logs into the east region, the region calls
76 // EntityTransferModuleto set up a child agent on the west region.
77 // XXX: However, this is not an entity transfer so is misleading.
78 EntityTransferModule etmA = new EntityTransferModule();
79 EntityTransferModule etmB = new EntityTransferModule();
80 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
81
82 IConfigSource config = new IniConfigSource();
83 config.AddConfig("Chat");
84 IConfig modulesConfig = config.AddConfig("Modules");
85 modulesConfig.Set("EntityTransferModule", etmA.Name);
86 modulesConfig.Set("SimulationServices", lscm.Name);
87
88 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
89 SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, new ChatModule());
90 SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB, new ChatModule());
91 }
92
93 /// <summary>
94 /// Tests chat between neighbour regions on the east-west axis
95 /// </summary>
96 /// <remarks>
97 /// Really, this is a combination of a child agent position update test and a chat range test. These need
98 /// to be separated later on.
99 /// </remarks>
100 [Test]
101 public void TestInterRegionChatDistanceEastWest()
102 {
103 TestHelpers.InMethod();
104// TestHelpers.EnableLogging();
105
106 UUID sp1Uuid = TestHelpers.ParseTail(0x11);
107 UUID sp2Uuid = TestHelpers.ParseTail(0x12);
108
109 Vector3 sp1Position = new Vector3(6, 128, 20);
110 Vector3 sp2Position = new Vector3(250, 128, 20);
111
112 SceneHelpers sh = new SceneHelpers();
113 TestScene sceneWest = sh.SetupScene("sceneWest", TestHelpers.ParseTail(0x1), 1000, 1000);
114 TestScene sceneEast = sh.SetupScene("sceneEast", TestHelpers.ParseTail(0x2), 1001, 1000);
115
116 SetupNeighbourRegions(sceneWest, sceneEast);
117
118 ScenePresence sp1 = SceneHelpers.AddScenePresence(sceneEast, sp1Uuid);
119 TestClient sp1Client = (TestClient)sp1.ControllingClient;
120
121 // If we don't set agents to flying, test will go wrong as they instantly fall to z = 0.
122 // TODO: May need to create special complete no-op test physics module rather than basic physics, since
123 // physics is irrelevant to this test.
124 sp1.Flying = true;
125
126 // When sp1 logs in to sceneEast, it sets up a child agent in sceneWest and informs the sp2 client to
127 // make the connection. For this test, will simplify this chain by making the connection directly.
128 ScenePresence sp1Child = SceneHelpers.AddChildScenePresence(sceneWest, sp1Uuid);
129 TestClient sp1ChildClient = (TestClient)sp1Child.ControllingClient;
130
131 sp1.AbsolutePosition = sp1Position;
132
133 ScenePresence sp2 = SceneHelpers.AddScenePresence(sceneWest, sp2Uuid);
134 TestClient sp2Client = (TestClient)sp2.ControllingClient;
135 sp2.Flying = true;
136
137 ScenePresence sp2Child = SceneHelpers.AddChildScenePresence(sceneEast, sp2Uuid);
138 TestClient sp2ChildClient = (TestClient)sp2Child.ControllingClient;
139
140 sp2.AbsolutePosition = sp2Position;
141
142 // We must update the scenes in order to make the root new root agents trigger position updates in their
143 // children.
144 sceneWest.Update(1);
145 sceneEast.Update(1);
146
147 // Check child positions are correct.
148 Assert.AreEqual(
149 new Vector3(sp1Position.X + sceneEast.RegionInfo.RegionSizeX, sp1Position.Y, sp1Position.Z),
150 sp1ChildClient.SceneAgent.AbsolutePosition);
151
152 Assert.AreEqual(
153 new Vector3(sp2Position.X - sceneWest.RegionInfo.RegionSizeX, sp2Position.Y, sp2Position.Z),
154 sp2ChildClient.SceneAgent.AbsolutePosition);
155
156 string receivedSp1ChatMessage = "";
157 string receivedSp2ChatMessage = "";
158
159 sp1ChildClient.OnReceivedChatMessage
160 += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp1ChatMessage = message;
161 sp2ChildClient.OnReceivedChatMessage
162 += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp2ChatMessage = message;
163
164 TestUserInRange(sp1Client, "ello darling", ref receivedSp2ChatMessage);
165 TestUserInRange(sp2Client, "fantastic cats", ref receivedSp1ChatMessage);
166
167 sp1Position = new Vector3(30, 128, 20);
168 sp1.AbsolutePosition = sp1Position;
169 sceneEast.Update(1);
170
171 // Check child position is correct.
172 Assert.AreEqual(
173 new Vector3(sp1Position.X + sceneEast.RegionInfo.RegionSizeX, sp1Position.Y, sp1Position.Z),
174 sp1ChildClient.SceneAgent.AbsolutePosition);
175
176 TestUserOutOfRange(sp1Client, "beef", ref receivedSp2ChatMessage);
177 TestUserOutOfRange(sp2Client, "lentils", ref receivedSp1ChatMessage);
178 }
179
180 /// <summary>
181 /// Tests chat between neighbour regions on the north-south axis
182 /// </summary>
183 /// <remarks>
184 /// Really, this is a combination of a child agent position update test and a chat range test. These need
185 /// to be separated later on.
186 /// </remarks>
187 [Test]
188 public void TestInterRegionChatDistanceNorthSouth()
189 {
190 TestHelpers.InMethod();
191 // TestHelpers.EnableLogging();
192
193 UUID sp1Uuid = TestHelpers.ParseTail(0x11);
194 UUID sp2Uuid = TestHelpers.ParseTail(0x12);
195
196 Vector3 sp1Position = new Vector3(128, 250, 20);
197 Vector3 sp2Position = new Vector3(128, 6, 20);
198
199 SceneHelpers sh = new SceneHelpers();
200 TestScene sceneNorth = sh.SetupScene("sceneNorth", TestHelpers.ParseTail(0x1), 1000, 1000);
201 TestScene sceneSouth = sh.SetupScene("sceneSouth", TestHelpers.ParseTail(0x2), 1000, 1001);
202
203 SetupNeighbourRegions(sceneNorth, sceneSouth);
204
205 ScenePresence sp1 = SceneHelpers.AddScenePresence(sceneNorth, sp1Uuid);
206 TestClient sp1Client = (TestClient)sp1.ControllingClient;
207
208 // If we don't set agents to flying, test will go wrong as they instantly fall to z = 0.
209 // TODO: May need to create special complete no-op test physics module rather than basic physics, since
210 // physics is irrelevant to this test.
211 sp1.Flying = true;
212
213 // When sp1 logs in to sceneEast, it sets up a child agent in sceneNorth and informs the sp2 client to
214 // make the connection. For this test, will simplify this chain by making the connection directly.
215 ScenePresence sp1Child = SceneHelpers.AddChildScenePresence(sceneSouth, sp1Uuid);
216 TestClient sp1ChildClient = (TestClient)sp1Child.ControllingClient;
217
218 sp1.AbsolutePosition = sp1Position;
219
220 ScenePresence sp2 = SceneHelpers.AddScenePresence(sceneSouth, sp2Uuid);
221 TestClient sp2Client = (TestClient)sp2.ControllingClient;
222 sp2.Flying = true;
223
224 ScenePresence sp2Child = SceneHelpers.AddChildScenePresence(sceneNorth, sp2Uuid);
225 TestClient sp2ChildClient = (TestClient)sp2Child.ControllingClient;
226
227 sp2.AbsolutePosition = sp2Position;
228
229 // We must update the scenes in order to make the root new root agents trigger position updates in their
230 // children.
231 sceneNorth.Update(1);
232 sceneSouth.Update(1);
233
234 // Check child positions are correct.
235 Assert.AreEqual(
236 new Vector3(sp1Position.X, sp1Position.Y - sceneNorth.RegionInfo.RegionSizeY, sp1Position.Z),
237 sp1ChildClient.SceneAgent.AbsolutePosition);
238
239 Assert.AreEqual(
240 new Vector3(sp2Position.X, sp2Position.Y + sceneSouth.RegionInfo.RegionSizeY, sp2Position.Z),
241 sp2ChildClient.SceneAgent.AbsolutePosition);
242
243 string receivedSp1ChatMessage = "";
244 string receivedSp2ChatMessage = "";
245
246 sp1ChildClient.OnReceivedChatMessage
247 += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp1ChatMessage = message;
248 sp2ChildClient.OnReceivedChatMessage
249 += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp2ChatMessage = message;
250
251 TestUserInRange(sp1Client, "ello darling", ref receivedSp2ChatMessage);
252 TestUserInRange(sp2Client, "fantastic cats", ref receivedSp1ChatMessage);
253
254 sp1Position = new Vector3(30, 128, 20);
255 sp1.AbsolutePosition = sp1Position;
256 sceneNorth.Update(1);
257
258 // Check child position is correct.
259 Assert.AreEqual(
260 new Vector3(sp1Position.X, sp1Position.Y - sceneNorth.RegionInfo.RegionSizeY, sp1Position.Z),
261 sp1ChildClient.SceneAgent.AbsolutePosition);
262
263 TestUserOutOfRange(sp1Client, "beef", ref receivedSp2ChatMessage);
264 TestUserOutOfRange(sp2Client, "lentils", ref receivedSp1ChatMessage);
265 }
266
267 private void TestUserInRange(TestClient speakClient, string testMessage, ref string receivedMessage)
268 {
269 receivedMessage = "";
270
271 speakClient.Chat(0, ChatTypeEnum.Say, testMessage);
272
273 Assert.AreEqual(testMessage, receivedMessage);
274 }
275
276 private void TestUserOutOfRange(TestClient speakClient, string testMessage, ref string receivedMessage)
277 {
278 receivedMessage = "";
279
280 speakClient.Chat(0, ChatTypeEnum.Say, testMessage);
281
282 Assert.AreNotEqual(testMessage, receivedMessage);
283 }
284 }
285} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
index 343cdb5..fc23b72 100644
--- a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
@@ -31,6 +31,7 @@ using Nini.Config;
31using OpenSim.Framework; 31using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces; 32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes; 33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Services.Interfaces;
34using OpenMetaverse; 35using OpenMetaverse;
35 36
36using Mono.Addins; 37using Mono.Addins;
@@ -182,6 +183,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule
182 try 183 try
183 { 184 {
184 ILandObject obj = avatar.Scene.LandChannel.GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); 185 ILandObject obj = avatar.Scene.LandChannel.GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
186
187 if (obj == null)
188 return;
189
185 if ((obj.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0 190 if ((obj.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0
186 || avatar.Scene.RegionInfo.RegionSettings.AllowDamage) 191 || avatar.Scene.RegionInfo.RegionSettings.AllowDamage)
187 { 192 {
diff --git a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
index d26907b..a896897 100644
--- a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
@@ -133,13 +133,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog
133 UUID objectID, UUID ownerID, string message, UUID textureID, 133 UUID objectID, UUID ownerID, string message, UUID textureID,
134 int ch, string[] buttonlabels) 134 int ch, string[] buttonlabels)
135 { 135 {
136 UserAccount account = m_scene.UserAccountService.GetUserAccount( 136 string username = m_scene.UserManagementModule.GetUserName(ownerID);
137 m_scene.RegionInfo.ScopeID, ownerID); 137 string ownerFirstName, ownerLastName = String.Empty;
138 string ownerFirstName, ownerLastName; 138 if (!String.IsNullOrEmpty(username))
139 if (account != null)
140 { 139 {
141 ownerFirstName = account.FirstName; 140 string[] parts = username.Split(' ');
142 ownerLastName = account.LastName; 141 ownerFirstName = parts[0];
142 if (parts.Length > 1)
143 ownerLastName = username.Split(' ')[1];
143 } 144 }
144 else 145 else
145 { 146 {
@@ -170,17 +171,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog
170 } 171 }
171 172
172 public void SendTextBoxToUser(UUID avatarid, string message, 173 public void SendTextBoxToUser(UUID avatarid, string message,
173 int chatChannel, string name, UUID objectid, UUID ownerid) 174 int chatChannel, string name, UUID objectid, UUID ownerID)
174 { 175 {
175 UserAccount account = m_scene.UserAccountService.GetUserAccount( 176 string username = m_scene.UserManagementModule.GetUserName(ownerID);
176 m_scene.RegionInfo.ScopeID, ownerid); 177 string ownerFirstName, ownerLastName = String.Empty;
177 string ownerFirstName, ownerLastName; 178 if (!String.IsNullOrEmpty(username))
178 UUID ownerID = UUID.Zero;
179 if (account != null)
180 { 179 {
181 ownerFirstName = account.FirstName; 180 string[] parts = username.Split(' ');
182 ownerLastName = account.LastName; 181 ownerFirstName = parts[0];
183 ownerID = account.PrincipalID; 182 if (parts.Length > 1)
183 ownerLastName = username.Split(' ')[1];
184 } 184 }
185 else 185 else
186 { 186 {
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
index 5ec0ea9..eb23e83 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
@@ -36,6 +36,7 @@ using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Services.Interfaces; 37using OpenSim.Services.Interfaces;
38using Mono.Addins; 38using Mono.Addins;
39using PermissionMask = OpenSim.Framework.PermissionMask;
39 40
40namespace OpenSim.Region.CoreModules.Avatar.Friends 41namespace OpenSim.Region.CoreModules.Avatar.Friends
41{ 42{
@@ -180,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
180 if (folderID == UUID.Zero) 181 if (folderID == UUID.Zero)
181 { 182 {
182 InventoryFolderBase folder = inv.GetFolderForType(userID, 183 InventoryFolderBase folder = inv.GetFolderForType(userID,
183 AssetType.CallingCard); 184 FolderType.CallingCard);
184 185
185 if (folder == null) // Nowhere to put it 186 if (folder == null) // Nowhere to put it
186 return UUID.Zero; 187 return UUID.Zero;
@@ -236,7 +237,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
236 IInventoryService invService = m_Scenes[0].InventoryService; 237 IInventoryService invService = m_Scenes[0].InventoryService;
237 238
238 InventoryFolderBase trashFolder = 239 InventoryFolderBase trashFolder =
239 invService.GetFolderForType(client.AgentId, AssetType.TrashFolder); 240 invService.GetFolderForType(client.AgentId, FolderType.Trash);
240 241
241 InventoryItemBase item = new InventoryItemBase(transactionID, client.AgentId); 242 InventoryItemBase item = new InventoryItemBase(transactionID, client.AgentId);
242 item = invService.GetItem(item); 243 item = invService.GetItem(item);
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index 8056030..08e7dd2 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -38,7 +38,6 @@ using OpenMetaverse;
38using Mono.Addins; 38using Mono.Addins;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Framework.Servers.HttpServer; 40using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Framework.Communications;
42using OpenSim.Framework.Servers; 41using OpenSim.Framework.Servers;
43using OpenSim.Region.Framework.Interfaces; 42using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes; 43using OpenSim.Region.Framework.Scenes;
@@ -94,6 +93,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
94 protected Dictionary<UUID, UserFriendData> m_Friends = new Dictionary<UUID, UserFriendData>(); 93 protected Dictionary<UUID, UserFriendData> m_Friends = new Dictionary<UUID, UserFriendData>();
95 94
96 /// <summary> 95 /// <summary>
96 /// Maintain a record of clients that need to notify about their online status. This only
97 /// needs to be done on login. Subsequent online/offline friend changes are sent by a different mechanism.
98 /// </summary>
99 protected HashSet<UUID> m_NeedsToNotifyStatus = new HashSet<UUID>();
100
101 /// <summary>
97 /// Maintain a record of viewers that need to be sent notifications for friends that are online. This only 102 /// Maintain a record of viewers that need to be sent notifications for friends that are online. This only
98 /// needs to be done on login. Subsequent online/offline friend changes are sent by a different mechanism. 103 /// needs to be done on login. Subsequent online/offline friend changes are sent by a different mechanism.
99 /// </summary> 104 /// </summary>
@@ -324,6 +329,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
324 private void OnMakeRootAgent(ScenePresence sp) 329 private void OnMakeRootAgent(ScenePresence sp)
325 { 330 {
326 RecacheFriends(sp.ControllingClient); 331 RecacheFriends(sp.ControllingClient);
332
333 lock (m_NeedsToNotifyStatus)
334 {
335 if (m_NeedsToNotifyStatus.Remove(sp.UUID))
336 {
337 // Inform the friends that this user is online. This can only be done once the client is a Root Agent.
338 StatusChange(sp.UUID, true);
339 }
340 }
327 } 341 }
328 342
329 private void OnClientLogin(IClientAPI client) 343 private void OnClientLogin(IClientAPI client)
@@ -331,8 +345,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
331 UUID agentID = client.AgentId; 345 UUID agentID = client.AgentId;
332 346
333 //m_log.DebugFormat("[XXX]: OnClientLogin!"); 347 //m_log.DebugFormat("[XXX]: OnClientLogin!");
334 // Inform the friends that this user is online 348
335 StatusChange(agentID, true); 349 // Register that we need to send this user's status to friends. This can only be done
350 // once the client becomes a Root Agent, because as part of sending out the presence
351 // we also get back the presence of the HG friends, and we need to send that to the
352 // client, but that can only be done when the client is a Root Agent.
353 lock (m_NeedsToNotifyStatus)
354 m_NeedsToNotifyStatus.Add(agentID);
336 355
337 // Register that we need to send the list of online friends to this user 356 // Register that we need to send the list of online friends to this user
338 lock (m_NeedsListOfOnlineFriends) 357 lock (m_NeedsListOfOnlineFriends)
@@ -371,7 +390,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
371 foreach (string fid in outstanding) 390 foreach (string fid in outstanding)
372 { 391 {
373 UUID fromAgentID; 392 UUID fromAgentID;
374 string firstname = "Unknown", lastname = "User"; 393 string firstname = "Unknown", lastname = "UserFMSFOIN";
375 if (!GetAgentInfo(client.Scene.RegionInfo.ScopeID, fid, out fromAgentID, out firstname, out lastname)) 394 if (!GetAgentInfo(client.Scene.RegionInfo.ScopeID, fid, out fromAgentID, out firstname, out lastname))
376 { 395 {
377 m_log.DebugFormat("[FRIENDS MODULE]: skipping malformed friend {0}", fid); 396 m_log.DebugFormat("[FRIENDS MODULE]: skipping malformed friend {0}", fid);
@@ -397,7 +416,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
397 416
398 protected virtual bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) 417 protected virtual bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last)
399 { 418 {
400 first = "Unknown"; last = "User"; 419 first = "Unknown"; last = "UserFMGAI";
401 if (!UUID.TryParse(fid, out agentID)) 420 if (!UUID.TryParse(fid, out agentID))
402 return false; 421 return false;
403 422
@@ -491,13 +510,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
491 510
492 // Notify about this user status 511 // Notify about this user status
493 StatusNotify(friendList, agentID, online); 512 StatusNotify(friendList, agentID, online);
494 } 513 }, null, "FriendsModule.StatusChange"
495 ); 514 );
496 } 515 }
497 } 516 }
498 517
499 protected virtual void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online) 518 protected virtual void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online)
500 { 519 {
520 //m_log.DebugFormat("[FRIENDS]: Entering StatusNotify for {0}", userID);
521
501 List<string> friendStringIds = friendList.ConvertAll<string>(friend => friend.Friend); 522 List<string> friendStringIds = friendList.ConvertAll<string>(friend => friend.Friend);
502 List<string> remoteFriendStringIds = new List<string>(); 523 List<string> remoteFriendStringIds = new List<string>();
503 foreach (string friendStringId in friendStringIds) 524 foreach (string friendStringId in friendStringIds)
@@ -523,12 +544,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
523 foreach (PresenceInfo friendSession in friendSessions) 544 foreach (PresenceInfo friendSession in friendSessions)
524 { 545 {
525 // let's guard against sessions-gone-bad 546 // let's guard against sessions-gone-bad
526 if (friendSession.RegionID != UUID.Zero) 547 if (friendSession != null && friendSession.RegionID != UUID.Zero)
527 { 548 {
549 //m_log.DebugFormat("[FRIENDS]: Get region {0}", friendSession.RegionID);
528 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID); 550 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
529 //m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName); 551 if (region != null)
530 m_FriendsSimConnector.StatusNotify(region, userID, friendSession.UserID, online); 552 {
553 m_FriendsSimConnector.StatusNotify(region, userID, friendSession.UserID, online);
554 }
531 } 555 }
556 //else
557 // m_log.DebugFormat("[FRIENDS]: friend session is null or the region is UUID.Zero");
532 } 558 }
533 } 559 }
534 560
@@ -685,7 +711,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
685 // 711 //
686 712
687 // Try local 713 // Try local
688 if (LocalFriendshipTerminated(exfriendID)) 714 if (LocalFriendshipTerminated(client.AgentId, exfriendID))
689 return; 715 return;
690 716
691 PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { exfriendID.ToString() }); 717 PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { exfriendID.ToString() });
@@ -827,13 +853,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
827 return false; 853 return false;
828 } 854 }
829 855
830 public bool LocalFriendshipTerminated(UUID exfriendID) 856 public bool LocalFriendshipTerminated(UUID userID, UUID exfriendID)
831 { 857 {
832 IClientAPI friendClient = LocateClientObject(exfriendID); 858 IClientAPI friendClient = LocateClientObject(exfriendID);
833 if (friendClient != null) 859 if (friendClient != null)
834 { 860 {
835 // the friend in this sim as root agent 861 // the friend in this sim as root agent
836 friendClient.SendTerminateFriend(exfriendID); 862 friendClient.SendTerminateFriend(userID);
837 // update local cache 863 // update local cache
838 RecacheFriends(friendClient); 864 RecacheFriends(friendClient);
839 // we're done 865 // we're done
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs
index 637beef..13512a2 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -42,19 +42,27 @@ using log4net;
42 42
43namespace OpenSim.Region.CoreModules.Avatar.Friends 43namespace OpenSim.Region.CoreModules.Avatar.Friends
44{ 44{
45 public class FriendsRequestHandler : BaseStreamHandler 45 public class FriendsRequestHandler : BaseStreamHandlerBasicDOSProtector
46 { 46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 48
49 private FriendsModule m_FriendsModule; 49 private FriendsModule m_FriendsModule;
50 50
51 public FriendsRequestHandler(FriendsModule fmodule) 51 public FriendsRequestHandler(FriendsModule fmodule)
52 : base("POST", "/friends") 52 : base("POST", "/friends", new BasicDosProtectorOptions()
53 {
54 AllowXForwardedFor = true,
55 ForgetTimeSpan = TimeSpan.FromMinutes(2),
56 MaxRequestsInTimeframe = 20,
57 ReportingName = "FRIENDSDOSPROTECTOR",
58 RequestTimeSpan = TimeSpan.FromSeconds(5),
59 ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod
60 })
53 { 61 {
54 m_FriendsModule = fmodule; 62 m_FriendsModule = fmodule;
55 } 63 }
56 64
57 public override byte[] Handle( 65 protected override byte[] ProcessRequest(
58 string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 66 string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
59 { 67 {
60 StreamReader sr = new StreamReader(requestData); 68 StreamReader sr = new StreamReader(requestData);
@@ -193,7 +201,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
193 if (!UUID.TryParse(request["ToID"].ToString(), out toID)) 201 if (!UUID.TryParse(request["ToID"].ToString(), out toID))
194 return FailureResult(); 202 return FailureResult();
195 203
196 if (m_FriendsModule.LocalFriendshipTerminated(toID)) 204 if (m_FriendsModule.LocalFriendshipTerminated(fromID, toID))
197 return SuccessResult(); 205 return SuccessResult();
198 206
199 return FailureResult(); 207 return FailureResult();
@@ -281,18 +289,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
281 289
282 rootElement.AppendChild(result); 290 rootElement.AppendChild(result);
283 291
284 return DocToBytes(doc); 292 return Util.DocToBytes(doc);
285 }
286
287 private byte[] DocToBytes(XmlDocument doc)
288 {
289 MemoryStream ms = new MemoryStream();
290 XmlTextWriter xw = new XmlTextWriter(ms, null);
291 xw.Formatting = Formatting.Indented;
292 doc.WriteTo(xw);
293 xw.Flush();
294
295 return ms.ToArray();
296 } 293 }
297 294
298 #endregion 295 #endregion
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
index bf5c0bb..27b7376 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
@@ -183,6 +183,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
183 if (Util.ParseUniversalUserIdentifier(finfo.Friend, out id, out url, out first, out last, out tmp)) 183 if (Util.ParseUniversalUserIdentifier(finfo.Friend, out id, out url, out first, out last, out tmp))
184 { 184 {
185 IUserManagement uMan = m_Scenes[0].RequestModuleInterface<IUserManagement>(); 185 IUserManagement uMan = m_Scenes[0].RequestModuleInterface<IUserManagement>();
186 m_log.DebugFormat("[HGFRIENDS MODULE]: caching {0}", finfo.Friend);
186 uMan.AddUser(id, url + ";" + first + " " + last); 187 uMan.AddUser(id, url + ";" + first + " " + last);
187 } 188 }
188 } 189 }
@@ -238,6 +239,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
238 fList.Add(s.Substring(0, 36)); 239 fList.Add(s.Substring(0, 36));
239 } 240 }
240 241
242 // FIXME: also query the presence status of friends in other grids (like in HGStatusNotifier.Notify())
243
241 PresenceInfo[] presence = PresenceService.GetAgents(fList.ToArray()); 244 PresenceInfo[] presence = PresenceService.GetAgents(fList.ToArray());
242 foreach (PresenceInfo pi in presence) 245 foreach (PresenceInfo pi in presence)
243 { 246 {
@@ -251,7 +254,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
251 254
252 protected override void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online) 255 protected override void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online)
253 { 256 {
254// m_log.DebugFormat("[HGFRIENDS MODULE]: Entering StatusNotify for {0}", userID); 257 //m_log.DebugFormat("[HGFRIENDS MODULE]: Entering StatusNotify for {0}", userID);
255 258
256 // First, let's divide the friends on a per-domain basis 259 // First, let's divide the friends on a per-domain basis
257 Dictionary<string, List<FriendInfo>> friendsPerDomain = new Dictionary<string, List<FriendInfo>>(); 260 Dictionary<string, List<FriendInfo>> friendsPerDomain = new Dictionary<string, List<FriendInfo>>();
@@ -293,7 +296,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
293 296
294 protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) 297 protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last)
295 { 298 {
296 first = "Unknown"; last = "User"; 299 first = "Unknown"; last = "UserHGGAI";
297 if (base.GetAgentInfo(scopeID, fid, out agentID, out first, out last)) 300 if (base.GetAgentInfo(scopeID, fid, out agentID, out first, out last))
298 return true; 301 return true;
299 302
@@ -349,7 +352,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
349 352
350 public override FriendInfo[] GetFriendsFromService(IClientAPI client) 353 public override FriendInfo[] GetFriendsFromService(IClientAPI client)
351 { 354 {
352// m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetFriendsFromService for {0}", client.Name); 355 // m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetFriendsFromService for {0}", client.Name);
353 Boolean agentIsLocal = true; 356 Boolean agentIsLocal = true;
354 if (UserManagementModule != null) 357 if (UserManagementModule != null)
355 agentIsLocal = UserManagementModule.IsLocalGridUser(client.AgentId); 358 agentIsLocal = UserManagementModule.IsLocalGridUser(client.AgentId);
@@ -362,13 +365,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
362 AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode); 365 AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode);
363 if (agentClientCircuit != null) 366 if (agentClientCircuit != null)
364 { 367 {
365 //[XXX] string agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit); 368 // Note that this is calling a different interface than base; this one calls with a string param!
366
367 finfos = FriendsService.GetFriends(client.AgentId.ToString()); 369 finfos = FriendsService.GetFriends(client.AgentId.ToString());
368 m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, client.AgentId.ToString()); 370 m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, client.AgentId.ToString());
369 } 371 }
370 372
371// m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetFriendsFromService for {0}", client.Name); 373 // m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetFriendsFromService for {0}", client.Name);
372 374
373 return finfos; 375 return finfos;
374 } 376 }
@@ -658,7 +660,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
658 FriendsService.Delete(friendUUI, agentID.ToString()); 660 FriendsService.Delete(friendUUI, agentID.ToString());
659 661
660 // notify the exfriend's service 662 // notify the exfriend's service
661 Util.FireAndForget(delegate { Delete(exfriendID, agentID, friendUUI); }); 663 Util.FireAndForget(
664 delegate { Delete(exfriendID, agentID, friendUUI); }, null, "HGFriendsModule.DeleteFriendshipForeignFriend");
662 665
663 m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentID, friendUUI); 666 m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentID, friendUUI);
664 return true; 667 return true;
@@ -676,7 +679,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
676 FriendsService.Delete(agentUUI, exfriendID.ToString()); 679 FriendsService.Delete(agentUUI, exfriendID.ToString());
677 680
678 // notify the agent's service? 681 // notify the agent's service?
679 Util.FireAndForget(delegate { Delete(agentID, exfriendID, agentUUI); }); 682 Util.FireAndForget(
683 delegate { Delete(agentID, exfriendID, agentUUI); }, null, "HGFriendsModule.DeleteFriendshipLocalFriend");
680 684
681 m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentUUI, exfriendID); 685 m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentUUI, exfriendID);
682 return true; 686 return true;
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
index 961117e..e6fd54e 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
@@ -35,7 +35,6 @@ using OpenSim.Framework;
35using OpenSim.Region.CoreModules.Avatar.Friends; 35using OpenSim.Region.CoreModules.Avatar.Friends;
36using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Tests.Common; 37using OpenSim.Tests.Common;
38using OpenSim.Tests.Common.Mock;
39 38
40namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests 39namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
41{ 40{
diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
index 5a7446f..3b6d970 100644
--- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
@@ -26,20 +26,37 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
29using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Collections.Specialized;
32using System.IO;
33using System.Reflection;
34using System.Web;
35using System.Xml;
36using log4net;
37using Mono.Addins;
30using Nini.Config; 38using Nini.Config;
31using OpenMetaverse; 39using OpenMetaverse;
40using OpenMetaverse.Messages.Linden;
41using OpenMetaverse.StructuredData;
32using OpenSim.Framework; 42using OpenSim.Framework;
43using OpenSim.Framework.Capabilities;
44using OpenSim.Framework.Servers;
45using OpenSim.Framework.Servers.HttpServer;
33using OpenSim.Region.Framework.Scenes; 46using OpenSim.Region.Framework.Scenes;
34using OpenSim.Region.Framework.Interfaces; 47using OpenSim.Region.Framework.Interfaces;
35 48using Caps = OpenSim.Framework.Capabilities.Caps;
36using Mono.Addins; 49using OSDArray = OpenMetaverse.StructuredData.OSDArray;
50using OSDMap = OpenMetaverse.StructuredData.OSDMap;
37 51
38namespace OpenSim.Region.CoreModules.Avatar.Gods 52namespace OpenSim.Region.CoreModules.Avatar.Gods
39{ 53{
40 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GodsModule")] 54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GodsModule")]
41 public class GodsModule : INonSharedRegionModule, IGodsModule 55 public class GodsModule : INonSharedRegionModule, IGodsModule
42 { 56 {
57 private static readonly ILog m_log =
58 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59
43 /// <summary>Special UUID for actions that apply to all agents</summary> 60 /// <summary>Special UUID for actions that apply to all agents</summary>
44 private static readonly UUID ALL_AGENTS = new UUID("44e87126-e794-4ded-05b3-7c42da3d5cdb"); 61 private static readonly UUID ALL_AGENTS = new UUID("44e87126-e794-4ded-05b3-7c42da3d5cdb");
45 62
@@ -65,6 +82,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
65 m_scene = scene; 82 m_scene = scene;
66 m_scene.RegisterModuleInterface<IGodsModule>(this); 83 m_scene.RegisterModuleInterface<IGodsModule>(this);
67 m_scene.EventManager.OnNewClient += SubscribeToClientEvents; 84 m_scene.EventManager.OnNewClient += SubscribeToClientEvents;
85 m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
86 scene.EventManager.OnIncomingInstantMessage +=
87 OnIncomingInstantMessage;
68 } 88 }
69 89
70 public void RemoveRegion(Scene scene) 90 public void RemoveRegion(Scene scene)
@@ -98,6 +118,47 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
98 client.OnRequestGodlikePowers -= RequestGodlikePowers; 118 client.OnRequestGodlikePowers -= RequestGodlikePowers;
99 } 119 }
100 120
121 private void OnRegisterCaps(UUID agentID, Caps caps)
122 {
123 string uri = "/CAPS/" + UUID.Random();
124
125 caps.RegisterHandler(
126 "UntrustedSimulatorMessage",
127 new RestStreamHandler("POST", uri, HandleUntrustedSimulatorMessage, "UntrustedSimulatorMessage", null));
128 }
129
130 private string HandleUntrustedSimulatorMessage(string request,
131 string path, string param, IOSHttpRequest httpRequest,
132 IOSHttpResponse httpResponse)
133 {
134 OSDMap osd = (OSDMap)OSDParser.DeserializeLLSDXml(request);
135
136 string message = osd["message"].AsString();
137
138 if (message == "GodKickUser")
139 {
140 OSDMap body = (OSDMap)osd["body"];
141 OSDArray userInfo = (OSDArray)body["UserInfo"];
142 OSDMap userData = (OSDMap)userInfo[0];
143
144 UUID agentID = userData["AgentID"].AsUUID();
145 UUID godID = userData["GodID"].AsUUID();
146 UUID godSessionID = userData["GodSessionID"].AsUUID();
147 uint kickFlags = userData["KickFlags"].AsUInteger();
148 string reason = userData["Reason"].AsString();
149 ScenePresence god = m_scene.GetScenePresence(godID);
150 if (god == null || god.ControllingClient.SessionId != godSessionID)
151 return String.Empty;
152
153 KickUser(godID, godSessionID, agentID, kickFlags, Util.StringToBytes1024(reason));
154 }
155 else
156 {
157 m_log.ErrorFormat("[GOD]: Unhandled UntrustedSimulatorMessage: {0}", message);
158 }
159 return String.Empty;
160 }
161
101 public void RequestGodlikePowers( 162 public void RequestGodlikePowers(
102 UUID agentID, UUID sessionID, UUID token, bool godLike, IClientAPI controllingClient) 163 UUID agentID, UUID sessionID, UUID token, bool godLike, IClientAPI controllingClient)
103 { 164 {
@@ -146,76 +207,85 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
146 /// <param name="reason">The message to send to the user after it's been turned into a field</param> 207 /// <param name="reason">The message to send to the user after it's been turned into a field</param>
147 public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason) 208 public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason)
148 { 209 {
149 UUID kickUserID = ALL_AGENTS; 210 if (!m_scene.Permissions.IsGod(godID))
150 211 return;
212
151 ScenePresence sp = m_scene.GetScenePresence(agentID); 213 ScenePresence sp = m_scene.GetScenePresence(agentID);
152 214
153 if (sp != null || agentID == kickUserID) 215 if (sp == null && agentID != ALL_AGENTS)
154 { 216 {
155 if (m_scene.Permissions.IsGod(godID)) 217 IMessageTransferModule transferModule =
218 m_scene.RequestModuleInterface<IMessageTransferModule>();
219 if (transferModule != null)
156 { 220 {
157 if (kickflags == 0) 221 m_log.DebugFormat("[GODS]: Sending nonlocal kill for agent {0}", agentID);
158 { 222 transferModule.SendInstantMessage(new GridInstantMessage(
159 if (agentID == kickUserID) 223 m_scene, godID, "God", agentID, (byte)250, false,
160 { 224 Utils.BytesToString(reason), UUID.Zero, true,
161 string reasonStr = Utils.BytesToString(reason); 225 new Vector3(), new byte[] {(byte)kickflags}, true),
162 226 delegate(bool success) {} );
163 m_scene.ForEachClient( 227 }
164 delegate(IClientAPI controller) 228 return;
165 { 229 }
166 if (controller.AgentId != godID)
167 controller.Kick(reasonStr);
168 }
169 );
170
171 // This is a bit crude. It seems the client will be null before it actually stops the thread
172 // The thread will kill itself eventually :/
173 // Is there another way to make sure *all* clients get this 'inter region' message?
174 m_scene.ForEachRootClient(
175 delegate(IClientAPI client)
176 {
177 if (client.AgentId != godID)
178 {
179 client.Close();
180 }
181 }
182 );
183 }
184 else
185 {
186 m_scene.SceneGraph.removeUserCount(!sp.IsChildAgent);
187 230
188 sp.ControllingClient.Kick(Utils.BytesToString(reason)); 231 switch (kickflags)
189 sp.ControllingClient.Close(); 232 {
190 } 233 case 0:
191 } 234 if (sp != null)
192 235 {
193 if (kickflags == 1) 236 KickPresence(sp, Utils.BytesToString(reason));
194 {
195 sp.AllowMovement = false;
196 if (DialogModule != null)
197 {
198 DialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
199 DialogModule.SendAlertToUser(godID, "User Frozen");
200 }
201 }
202
203 if (kickflags == 2)
204 {
205 sp.AllowMovement = true;
206 if (DialogModule != null)
207 {
208 DialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
209 DialogModule.SendAlertToUser(godID, "User Unfrozen");
210 }
211 }
212 } 237 }
213 else 238 else if (agentID == ALL_AGENTS)
214 { 239 {
215 if (DialogModule != null) 240 m_scene.ForEachRootScenePresence(
216 DialogModule.SendAlertToUser(godID, "Kick request denied"); 241 delegate(ScenePresence p)
242 {
243 if (p.UUID != godID && (!m_scene.Permissions.IsGod(p.UUID)))
244 KickPresence(p, Utils.BytesToString(reason));
245 }
246 );
217 } 247 }
248 break;
249 case 1:
250 if (sp != null)
251 {
252 sp.AllowMovement = false;
253 m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
254 m_dialogModule.SendAlertToUser(godID, "User Frozen");
255 }
256 break;
257 case 2:
258 if (sp != null)
259 {
260 sp.AllowMovement = true;
261 m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
262 m_dialogModule.SendAlertToUser(godID, "User Unfrozen");
263 }
264 break;
265 default:
266 break;
267 }
268 }
269
270 private void KickPresence(ScenePresence sp, string reason)
271 {
272 if (sp.IsChildAgent)
273 return;
274 sp.ControllingClient.Kick(reason);
275 sp.Scene.CloseAgent(sp.UUID, true);
276 }
277
278 private void OnIncomingInstantMessage(GridInstantMessage msg)
279 {
280 if (msg.dialog == (uint)250) // Nonlocal kick
281 {
282 UUID agentID = new UUID(msg.toAgentID);
283 string reason = msg.message;
284 UUID godID = new UUID(msg.fromAgentID);
285 uint kickMode = (uint)msg.binaryBucket[0];
286
287 KickUser(godID, UUID.Zero, agentID, kickMode, Util.StringToBytes1024(reason));
218 } 288 }
219 } 289 }
220 } 290 }
221} \ No newline at end of file 291}
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs
index 7bf19c2..a1b918a 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs
@@ -210,10 +210,10 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
210 success = m_IMService.OutgoingInstantMessage(im, url, foreigner); 210 success = m_IMService.OutgoingInstantMessage(im, url, foreigner);
211 211
212 if (!success && !foreigner) 212 if (!success && !foreigner)
213 HandleUndeliveredMessage(im, result); 213 HandleUndeliverableMessage(im, result);
214 else 214 else
215 result(success); 215 result(success);
216 }); 216 }, null, "HGMessageTransferModule.SendInstantMessage");
217 217
218 return; 218 return;
219 } 219 }
@@ -246,7 +246,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
246 return successful; 246 return successful;
247 } 247 }
248 248
249 protected void HandleUndeliveredMessage(GridInstantMessage im, MessageResultNotification result) 249 public void HandleUndeliverableMessage(GridInstantMessage im, MessageResultNotification result)
250 { 250 {
251 UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage; 251 UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage;
252 252
@@ -282,7 +282,17 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
282 string uasURL = circuit.ServiceURLs["HomeURI"].ToString(); 282 string uasURL = circuit.ServiceURLs["HomeURI"].ToString();
283 m_log.DebugFormat("[HG MESSAGE TRANSFER]: getting UUI of user {0} from {1}", toAgent, uasURL); 283 m_log.DebugFormat("[HG MESSAGE TRANSFER]: getting UUI of user {0} from {1}", toAgent, uasURL);
284 UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uasURL); 284 UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uasURL);
285 return uasConn.GetUUI(fromAgent, toAgent); 285
286 string agentUUI = string.Empty;
287 try
288 {
289 agentUUI = uasConn.GetUUI(fromAgent, toAgent);
290 }
291 catch (Exception e) {
292 m_log.Debug("[HG MESSAGE TRANSFER]: GetUUI call failed ", e);
293 }
294
295 return agentUUI;
286 } 296 }
287 } 297 }
288 } 298 }
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
index fa935cd..2462ff8 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
@@ -181,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
181 SendGridInstantMessageViaXMLRPC(im, result); 181 SendGridInstantMessageViaXMLRPC(im, result);
182 } 182 }
183 183
184 private void HandleUndeliveredMessage(GridInstantMessage im, MessageResultNotification result) 184 public void HandleUndeliverableMessage(GridInstantMessage im, MessageResultNotification result)
185 { 185 {
186 UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage; 186 UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage;
187 187
@@ -372,7 +372,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
372 gim.fromAgentName = fromAgentName; 372 gim.fromAgentName = fromAgentName;
373 gim.fromGroup = fromGroup; 373 gim.fromGroup = fromGroup;
374 gim.imSessionID = imSessionID.Guid; 374 gim.imSessionID = imSessionID.Guid;
375 gim.RegionID = UUID.Zero.Guid; // RegionID.Guid; 375 gim.RegionID = RegionID.Guid;
376 gim.timestamp = timestamp; 376 gim.timestamp = timestamp;
377 gim.toAgentID = toAgentID.Guid; 377 gim.toAgentID = toAgentID.Guid;
378 gim.message = message; 378 gim.message = message;
@@ -428,7 +428,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
428 /// <summary> 428 /// <summary>
429 /// delegate for sending a grid instant message asynchronously 429 /// delegate for sending a grid instant message asynchronously
430 /// </summary> 430 /// </summary>
431 public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID); 431 public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result);
432 432
433 protected virtual void GridInstantMessageCompleted(IAsyncResult iar) 433 protected virtual void GridInstantMessageCompleted(IAsyncResult iar)
434 { 434 {
@@ -442,138 +442,87 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
442 { 442 {
443 GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; 443 GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync;
444 444
445 d.BeginInvoke(im, result, UUID.Zero, GridInstantMessageCompleted, d); 445 d.BeginInvoke(im, result, GridInstantMessageCompleted, d);
446 } 446 }
447 447
448 /// <summary> 448 /// <summary>
449 /// Recursive SendGridInstantMessage over XMLRPC method. 449 /// Internal SendGridInstantMessage over XMLRPC method.
450 /// This is called from within a dedicated thread.
451 /// The first time this is called, prevRegionHandle will be 0 Subsequent times this is called from
452 /// itself, prevRegionHandle will be the last region handle that we tried to send.
453 /// If the handles are the same, we look up the user's location using the grid.
454 /// If the handles are still the same, we end. The send failed.
455 /// </summary> 450 /// </summary>
456 /// <param name="prevRegionHandle"> 451 /// <remarks>
457 /// Pass in 0 the first time this method is called. It will be called recursively with the last 452 /// This is called from within a dedicated thread.
458 /// regionhandle tried 453 /// </remarks>
459 /// </param> 454 private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result)
460 protected virtual void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID)
461 { 455 {
462 UUID toAgentID = new UUID(im.toAgentID); 456 UUID toAgentID = new UUID(im.toAgentID);
463 457 UUID regionID;
464 PresenceInfo upd = null; 458 bool needToLookupAgent;
465
466 bool lookupAgent = false;
467 459
468 lock (m_UserRegionMap) 460 lock (m_UserRegionMap)
461 needToLookupAgent = !m_UserRegionMap.TryGetValue(toAgentID, out regionID);
462
463 while (true)
469 { 464 {
470 if (m_UserRegionMap.ContainsKey(toAgentID)) 465 if (needToLookupAgent)
471 { 466 {
472 upd = new PresenceInfo(); 467 PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() });
473 upd.RegionID = m_UserRegionMap[toAgentID];
474 468
475 // We need to compare the current regionhandle with the previous region handle 469 UUID foundRegionID = UUID.Zero;
476 // or the recursive loop will never end because it will never try to lookup the agent again
477 if (prevRegionID == upd.RegionID)
478 {
479 lookupAgent = true;
480 }
481 }
482 else
483 {
484 lookupAgent = true;
485 }
486 }
487
488 470
489 // Are we needing to look-up an agent? 471 if (presences != null)
490 if (lookupAgent)
491 {
492 // Non-cached user agent lookup.
493 PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() });
494 if (presences != null && presences.Length > 0)
495 {
496 foreach (PresenceInfo p in presences)
497 { 472 {
498 if (p.RegionID != UUID.Zero) 473 foreach (PresenceInfo p in presences)
499 { 474 {
500 upd = p; 475 if (p.RegionID != UUID.Zero)
501 break; 476 {
477 foundRegionID = p.RegionID;
478 break;
479 }
502 } 480 }
503 } 481 }
504 }
505 482
506 if (upd != null) 483 // If not found or the found region is the same as the last lookup, then message is undeliverable
507 { 484 if (foundRegionID == UUID.Zero || foundRegionID == regionID)
508 // check if we've tried this before.. 485 break;
509 // This is one way to end the recursive loop 486 else
510 // 487 regionID = foundRegionID;
511 if (upd.RegionID == prevRegionID)
512 {
513 // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
514 HandleUndeliveredMessage(im, result);
515 return;
516 }
517 } 488 }
518 else 489
490 GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, regionID);
491 if (reginfo == null)
519 { 492 {
520 // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); 493 m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", regionID);
521 HandleUndeliveredMessage(im, result); 494 break;
522 return;
523 } 495 }
524 }
525 496
526 if (upd != null) 497 // Try to send the message to the agent via the retrieved region.
527 { 498 Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im);
528 GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, 499 msgdata["region_handle"] = 0;
529 upd.RegionID); 500 bool imresult = doIMSending(reginfo, msgdata);
530 if (reginfo != null) 501
502 // If the message delivery was successful, then cache the entry.
503 if (imresult)
531 { 504 {
532 Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); 505 lock (m_UserRegionMap)
533 // Not actually used anymore, left in for compatibility
534 // Remove at next interface change
535 //
536 msgdata["region_handle"] = 0;
537 bool imresult = doIMSending(reginfo, msgdata);
538 if (imresult)
539 {
540 // IM delivery successful, so store the Agent's location in our local cache.
541 lock (m_UserRegionMap)
542 {
543 if (m_UserRegionMap.ContainsKey(toAgentID))
544 {
545 m_UserRegionMap[toAgentID] = upd.RegionID;
546 }
547 else
548 {
549 m_UserRegionMap.Add(toAgentID, upd.RegionID);
550 }
551 }
552 result(true);
553 }
554 else
555 { 506 {
556 // try again, but lookup user this time. 507 m_UserRegionMap[toAgentID] = regionID;
557 // Warning, this must call the Async version
558 // of this method or we'll be making thousands of threads
559 // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync
560 // The version that spawns the thread is SendGridInstantMessageViaXMLRPC
561
562 // This is recursive!!!!!
563 SendGridInstantMessageViaXMLRPCAsync(im, result,
564 upd.RegionID);
565 } 508 }
509 result(true);
510 return;
566 } 511 }
567 else 512
568 { 513 // If we reach this point in the first iteration of the while, then we may have unsuccessfully tried
569 m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", upd.RegionID); 514 // to use a locally cached region ID. All subsequent attempts need to lookup agent details from
570 HandleUndeliveredMessage(im, result); 515 // the presence service.
571 } 516 needToLookupAgent = true;
572 }
573 else
574 {
575 HandleUndeliveredMessage(im, result);
576 } 517 }
518
519 // If we reached this point then the message was not deliverable. Remove the bad cache entry and
520 // signal the delivery failure.
521 lock (m_UserRegionMap)
522 m_UserRegionMap.Remove(toAgentID);
523
524 // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
525 HandleUndeliverableMessage(im, result);
577 } 526 }
578 527
579 /// <summary> 528 /// <summary>
@@ -584,7 +533,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
584 /// <returns>Bool if the message was successfully delivered at the other side.</returns> 533 /// <returns>Bool if the message was successfully delivered at the other side.</returns>
585 protected virtual bool doIMSending(GridRegion reginfo, Hashtable xmlrpcdata) 534 protected virtual bool doIMSending(GridRegion reginfo, Hashtable xmlrpcdata)
586 { 535 {
587
588 ArrayList SendParams = new ArrayList(); 536 ArrayList SendParams = new ArrayList();
589 SendParams.Add(xmlrpcdata); 537 SendParams.Add(xmlrpcdata);
590 XmlRpcRequest GridReq = new XmlRpcRequest("grid_instant_message", SendParams); 538 XmlRpcRequest GridReq = new XmlRpcRequest("grid_instant_message", SendParams);
@@ -672,7 +620,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
672 gim["position_x"] = msg.Position.X.ToString(); 620 gim["position_x"] = msg.Position.X.ToString();
673 gim["position_y"] = msg.Position.Y.ToString(); 621 gim["position_y"] = msg.Position.Y.ToString();
674 gim["position_z"] = msg.Position.Z.ToString(); 622 gim["position_z"] = msg.Position.Z.ToString();
675 gim["region_id"] = msg.RegionID.ToString(); 623 gim["region_id"] = new UUID(msg.RegionID).ToString();
676 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None); 624 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None);
677 return gim; 625 return gim;
678 } 626 }
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs
index 7ce2813..315d372 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs
@@ -32,7 +32,6 @@ using Nini.Config;
32using Mono.Addins; 32using Mono.Addins;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Communications;
36using OpenSim.Framework.Servers; 35using OpenSim.Framework.Servers;
37using OpenSim.Framework.Client; 36using OpenSim.Framework.Client;
38using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
index 7d763fa..9cdb1c2 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
@@ -32,7 +32,6 @@ using Mono.Addins;
32using Nini.Config; 32using Nini.Config;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Communications;
36using OpenSim.Framework.Servers; 35using OpenSim.Framework.Servers;
37using OpenSim.Framework.Client; 36using OpenSim.Framework.Client;
38using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
@@ -182,7 +181,10 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
182 "POST", m_RestURL + "/RetrieveMessages/", client.AgentId); 181 "POST", m_RestURL + "/RetrieveMessages/", client.AgentId);
183 182
184 if (msglist == null) 183 if (msglist == null)
184 {
185 m_log.WarnFormat("[OFFLINE MESSAGING]: WARNING null message list."); 185 m_log.WarnFormat("[OFFLINE MESSAGING]: WARNING null message list.");
186 return;
187 }
186 188
187 foreach (GridInstantMessage im in msglist) 189 foreach (GridInstantMessage im in msglist)
188 { 190 {
@@ -223,12 +225,8 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
223 return; 225 return;
224 } 226 }
225 227
226 Scene scene = FindScene(new UUID(im.fromAgentID));
227 if (scene == null)
228 scene = m_SceneList[0];
229
230 bool success = SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>( 228 bool success = SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>(
231 "POST", m_RestURL+"/SaveMessage/", im); 229 "POST", m_RestURL+"/SaveMessage/", im, 10000);
232 230
233 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) 231 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
234 { 232 {
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs
index 4c678c2..c2440d8 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs
@@ -49,8 +49,10 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
49 private static readonly ILog m_log = LogManager.GetLogger( 49 private static readonly ILog m_log = LogManager.GetLogger(
50 MethodBase.GetCurrentMethod().DeclaringType); 50 MethodBase.GetCurrentMethod().DeclaringType);
51 51
52#pragma warning disable 0067
52 public event PresenceChange OnPresenceChange; 53 public event PresenceChange OnPresenceChange;
53 public event BulkPresenceData OnBulkPresenceData; 54 public event BulkPresenceData OnBulkPresenceData;
55#pragma warning restore 0067
54 56
55 protected List<Scene> m_Scenes = new List<Scene>(); 57 protected List<Scene> m_Scenes = new List<Scene>();
56 58
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
index ecbd07f..4a06fd1 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
@@ -61,16 +61,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
61 61
62 private UserAccount m_userInfo; 62 private UserAccount m_userInfo;
63 private string m_invPath; 63 private string m_invPath;
64
65 /// <value>
66 /// ID of this request
67 /// </value>
68 protected UUID m_id;
64 69
65 /// <summary> 70 /// <summary>
66 /// Do we want to merge this load with existing inventory? 71 /// Do we want to merge this load with existing inventory?
67 /// </summary> 72 /// </summary>
68 protected bool m_merge; 73 protected bool m_merge;
69 74
70 /// <value> 75 protected IInventoryService m_InventoryService;
71 /// We only use this to request modules 76 protected IAssetService m_AssetService;
72 /// </value> 77 protected IUserAccountService m_UserAccountService;
73 protected Scene m_scene; 78
79 private InventoryArchiverModule m_module;
74 80
75 /// <value> 81 /// <value>
76 /// The stream from which the inventory archive will be loaded. 82 /// The stream from which the inventory archive will be loaded.
@@ -115,12 +121,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
115 /// Record the creator id that should be associated with an asset. This is used to adjust asset creator ids 121 /// Record the creator id that should be associated with an asset. This is used to adjust asset creator ids
116 /// after OSP resolution (since OSP creators are only stored in the item 122 /// after OSP resolution (since OSP creators are only stored in the item
117 /// </summary> 123 /// </summary>
118 protected Dictionary<UUID, UUID> m_creatorIdForAssetId = new Dictionary<UUID, UUID>(); 124 protected Dictionary<UUID, UUID> m_creatorIdForAssetId = new Dictionary<UUID, UUID>();
125
126 public InventoryArchiveReadRequest(
127 IInventoryService inv, IAssetService assets, IUserAccountService uacc, UserAccount userInfo, string invPath, string loadPath, bool merge)
128 : this(UUID.Zero, null,
129 inv,
130 assets,
131 uacc,
132 userInfo,
133 invPath,
134 loadPath,
135 merge)
136 {
137 }
119 138
120 public InventoryArchiveReadRequest( 139 public InventoryArchiveReadRequest(
121 Scene scene, UserAccount userInfo, string invPath, string loadPath, bool merge) 140 UUID id, InventoryArchiverModule module, IInventoryService inv, IAssetService assets, IUserAccountService uacc, UserAccount userInfo, string invPath, string loadPath, bool merge)
122 : this( 141 : this(
123 scene, 142 id,
143 module,
144 inv,
145 assets,
146 uacc,
124 userInfo, 147 userInfo,
125 invPath, 148 invPath,
126 new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress), 149 new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress),
@@ -129,13 +152,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
129 } 152 }
130 153
131 public InventoryArchiveReadRequest( 154 public InventoryArchiveReadRequest(
132 Scene scene, UserAccount userInfo, string invPath, Stream loadStream, bool merge) 155 UUID id, InventoryArchiverModule module, IInventoryService inv, IAssetService assets, IUserAccountService uacc, UserAccount userInfo, string invPath, Stream loadStream, bool merge)
133 { 156 {
134 m_scene = scene; 157 m_id = id;
158 m_InventoryService = inv;
159 m_AssetService = assets;
160 m_UserAccountService = uacc;
135 m_merge = merge; 161 m_merge = merge;
136 m_userInfo = userInfo; 162 m_userInfo = userInfo;
137 m_invPath = invPath; 163 m_invPath = invPath;
138 m_loadStream = loadStream; 164 m_loadStream = loadStream;
165 m_module = module;
139 166
140 // FIXME: Do not perform this check since older versions of OpenSim do save the control file after other things 167 // FIXME: Do not perform this check since older versions of OpenSim do save the control file after other things
141 // (I thought they weren't). We will need to bump the version number and perform this check on all 168 // (I thought they weren't). We will need to bump the version number and perform this check on all
@@ -158,11 +185,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
158 { 185 {
159 try 186 try
160 { 187 {
188 Exception reportedException = null;
189
161 string filePath = "ERROR"; 190 string filePath = "ERROR";
162 191
163 List<InventoryFolderBase> folderCandidates 192 List<InventoryFolderBase> folderCandidates
164 = InventoryArchiveUtils.FindFolderByPath( 193 = InventoryArchiveUtils.FindFoldersByPath(
165 m_scene.InventoryService, m_userInfo.PrincipalID, m_invPath); 194 m_InventoryService, m_userInfo.PrincipalID, m_invPath);
166 195
167 if (folderCandidates.Count == 0) 196 if (folderCandidates.Count == 0)
168 { 197 {
@@ -194,14 +223,25 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
194 } 223 }
195 224
196 archive.Close(); 225 archive.Close();
197 226
198 m_log.DebugFormat( 227 m_log.DebugFormat(
199 "[INVENTORY ARCHIVER]: Successfully loaded {0} assets with {1} failures", 228 "[INVENTORY ARCHIVER]: Successfully loaded {0} assets with {1} failures",
200 m_successfulAssetRestores, m_failedAssetRestores); 229 m_successfulAssetRestores, m_failedAssetRestores);
201 m_log.InfoFormat("[INVENTORY ARCHIVER]: Successfully loaded {0} items", m_successfulItemRestores); 230
231 //Alicia: When this is called by LibraryModule or Tests, m_module will be null as event is not required
232 if(m_module != null)
233 m_module.TriggerInventoryArchiveLoaded(m_id, true, m_userInfo, m_invPath, m_loadStream, reportedException, m_successfulItemRestores);
202 234
203 return m_loadedNodes; 235 return m_loadedNodes;
204 } 236 }
237 catch(Exception Ex)
238 {
239 // Trigger saved event with failed result and exception data
240 if (m_module != null)
241 m_module.TriggerInventoryArchiveLoaded(m_id, false, m_userInfo, m_invPath, m_loadStream, Ex, 0);
242
243 return m_loadedNodes;
244 }
205 finally 245 finally
206 { 246 {
207 m_loadStream.Close(); 247 m_loadStream.Close();
@@ -296,8 +336,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
296 // iar name and try to find that instead. 336 // iar name and try to find that instead.
297 string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath); 337 string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath);
298 List<InventoryFolderBase> folderCandidates 338 List<InventoryFolderBase> folderCandidates
299 = InventoryArchiveUtils.FindFolderByPath( 339 = InventoryArchiveUtils.FindFoldersByPath(
300 m_scene.InventoryService, m_userInfo.PrincipalID, plainPath); 340 m_InventoryService, m_userInfo.PrincipalID, plainPath);
301 341
302 if (folderCandidates.Count != 0) 342 if (folderCandidates.Count != 0)
303 { 343 {
@@ -372,15 +412,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
372 newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName); 412 newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName);
373 UUID newFolderId = UUID.Random(); 413 UUID newFolderId = UUID.Random();
374 414
375 // Asset type has to be Unknown here rather than Folder, otherwise the created folder can't be
376 // deleted once the client has relogged.
377 // The root folder appears to be labelled AssetType.Folder (shows up as "Category" in the client)
378 // even though there is a AssetType.RootCategory
379 destFolder 415 destFolder
380 = new InventoryFolderBase( 416 = new InventoryFolderBase(
381 newFolderId, newFolderName, m_userInfo.PrincipalID, 417 newFolderId, newFolderName, m_userInfo.PrincipalID,
382 (short)AssetType.Unknown, destFolder.ID, 1); 418 (short)FolderType.None, destFolder.ID, 1);
383 m_scene.InventoryService.AddFolder(destFolder); 419 m_InventoryService.AddFolder(destFolder);
384 420
385 // Record that we have now created this folder 421 // Record that we have now created this folder
386 iarPathExisting += rawDirsToCreate[i] + "/"; 422 iarPathExisting += rawDirsToCreate[i] + "/";
@@ -406,7 +442,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
406 // Don't use the item ID that's in the file 442 // Don't use the item ID that's in the file
407 item.ID = UUID.Random(); 443 item.ID = UUID.Random();
408 444
409 UUID ospResolvedId = OspResolver.ResolveOspa(item.CreatorId, m_scene.UserAccountService); 445 UUID ospResolvedId = OspResolver.ResolveOspa(item.CreatorId, m_UserAccountService);
410 if (UUID.Zero != ospResolvedId) // The user exists in this grid 446 if (UUID.Zero != ospResolvedId) // The user exists in this grid
411 { 447 {
412// m_log.DebugFormat("[INVENTORY ARCHIVER]: Found creator {0} via OSPA resolution", ospResolvedId); 448// m_log.DebugFormat("[INVENTORY ARCHIVER]: Found creator {0} via OSPA resolution", ospResolvedId);
@@ -418,7 +454,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
418 item.CreatorId = ospResolvedId.ToString(); 454 item.CreatorId = ospResolvedId.ToString();
419 item.CreatorData = string.Empty; 455 item.CreatorData = string.Empty;
420 } 456 }
421 else if (item.CreatorData == null || item.CreatorData == String.Empty) 457 else if (string.IsNullOrEmpty(item.CreatorData))
422 { 458 {
423 item.CreatorId = m_userInfo.PrincipalID.ToString(); 459 item.CreatorId = m_userInfo.PrincipalID.ToString();
424// item.CreatorIdAsUuid = new UUID(item.CreatorId); 460// item.CreatorIdAsUuid = new UUID(item.CreatorId);
@@ -436,7 +472,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
436 // relying on native tar tools. 472 // relying on native tar tools.
437 m_creatorIdForAssetId[item.AssetID] = item.CreatorIdAsUuid; 473 m_creatorIdForAssetId[item.AssetID] = item.CreatorIdAsUuid;
438 474
439 m_scene.AddInventoryItem(item); 475 if (!m_InventoryService.AddItem(item))
476 m_log.WarnFormat("[INVENTORY ARCHIVER]: Unable to save item {0} in folder {1}", item.Name, item.Folder);
440 477
441 return item; 478 return item;
442 } 479 }
@@ -479,52 +516,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
479 { 516 {
480 if (m_creatorIdForAssetId.ContainsKey(assetId)) 517 if (m_creatorIdForAssetId.ContainsKey(assetId))
481 { 518 {
482 string xmlData = Utils.BytesToString(data); 519 data = SceneObjectSerializer.ModifySerializedObject(assetId, data,
483 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>(); 520 sog => {
521 bool modified = false;
522
523 foreach (SceneObjectPart sop in sog.Parts)
524 {
525 if (string.IsNullOrEmpty(sop.CreatorData))
526 {
527 sop.CreatorID = m_creatorIdForAssetId[assetId];
528 modified = true;
529 }
530 }
531
532 return modified;
533 });
484 534
485 CoalescedSceneObjects coa = null; 535 if (data == null)
486 if (CoalescedSceneObjectsSerializer.TryFromXml(xmlData, out coa)) 536 return false;
487 {
488// m_log.DebugFormat(
489// "[INVENTORY ARCHIVER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count);
490
491 if (coa.Objects.Count == 0)
492 {
493 m_log.WarnFormat(
494 "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of coalesced object from asset {0} as it has zero loaded components",
495 assetId);
496 return false;
497 }
498
499 sceneObjects.AddRange(coa.Objects);
500 }
501 else
502 {
503 SceneObjectGroup deserializedObject = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
504
505 if (deserializedObject != null)
506 {
507 sceneObjects.Add(deserializedObject);
508 }
509 else
510 {
511 m_log.WarnFormat(
512 "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of object from asset {0} as deserialization failed",
513 assetId);
514
515 return false;
516 }
517 }
518
519 foreach (SceneObjectGroup sog in sceneObjects)
520 foreach (SceneObjectPart sop in sog.Parts)
521 if (sop.CreatorData == null || sop.CreatorData == "")
522 sop.CreatorID = m_creatorIdForAssetId[assetId];
523
524 if (coa != null)
525 data = Utils.StringToBytes(CoalescedSceneObjectsSerializer.ToXml(coa));
526 else
527 data = Utils.StringToBytes(SceneObjectSerializer.ToOriginalXmlFormat(sceneObjects[0]));
528 } 537 }
529 } 538 }
530 539
@@ -533,7 +542,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
533 AssetBase asset = new AssetBase(assetId, "From IAR", assetType, UUID.Zero.ToString()); 542 AssetBase asset = new AssetBase(assetId, "From IAR", assetType, UUID.Zero.ToString());
534 asset.Data = data; 543 asset.Data = data;
535 544
536 m_scene.AssetService.Store(asset); 545 m_AssetService.Store(asset);
537 546
538 return true; 547 return true;
539 } 548 }
@@ -546,7 +555,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
546 return false; 555 return false;
547 } 556 }
548 } 557 }
549 558
550 /// <summary> 559 /// <summary>
551 /// Load control file 560 /// Load control file
552 /// </summary> 561 /// </summary>
@@ -652,4 +661,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
652 m_assetsLoaded = true; 661 m_assetsLoaded = true;
653 } 662 }
654 } 663 }
655} \ No newline at end of file 664}
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs
index 0d90a15..dbaf2aa 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs
@@ -52,13 +52,82 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
52 /// <summary> 52 /// <summary>
53 /// Find a folder given a PATH_DELIMITER delimited path starting from a user's root folder 53 /// Find a folder given a PATH_DELIMITER delimited path starting from a user's root folder
54 /// </summary> 54 /// </summary>
55 /// <remarks>
56 /// This method does not handle paths that contain multiple delimitors
57 ///
58 /// FIXME: We have no way of distinguishing folders with the same path
55 /// 59 ///
60 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
61 /// </remarks>
62 /// <param name="inventoryService">
63 /// Inventory service to query
64 /// </param>
65 /// <param name="userId">
66 /// User id to search
67 /// </param>
68 /// <param name="path">
69 /// The path to the required folder.
70 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
71 /// </param>
72 /// <returns>The folder found. Please note that if there are multiple folders with the same name then an
73 /// unspecified one will be returned. If no such folder eixsts then null is returned</returns>
74 public static InventoryFolderBase FindFolderByPath(
75 IInventoryService inventoryService, UUID userId, string path)
76 {
77 List<InventoryFolderBase> folders = FindFoldersByPath(inventoryService, userId, path);
78
79 if (folders.Count == 0)
80 return null;
81 else
82 return folders[0];
83 }
84
85 /// <summary>
86 /// Find a folder given a PATH_DELIMITER delimited path starting from a given folder
87 /// </summary>
88 /// <remarks>
56 /// This method does not handle paths that contain multiple delimitors 89 /// This method does not handle paths that contain multiple delimitors
57 /// 90 ///
58 /// FIXME: We have no way of distinguishing folders with the same path 91 /// FIXME: We have no way of distinguishing folders with the same path
59 /// 92 ///
60 /// FIXME: Delimitors which occur in names themselves are not currently escapable. 93 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
94 /// </remarks>
95 /// <param name="inventoryService">
96 /// Inventory service to query
97 /// </param>
98 /// <param name="startFolder">
99 /// The folder from which the path starts
100 /// </param>
101 /// <param name="path">
102 /// The path to the required folder.
103 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
104 /// </param>
105 /// <returns>The folder found. Please note that if there are multiple folders with the same name then an
106 /// unspecified one will be returned. If no such folder eixsts then null is returned</returns>
107 public static InventoryFolderBase FindFolderByPath(
108 IInventoryService inventoryService, InventoryFolderBase startFolder, string path)
109 {
110 if (null == startFolder)
111 return null;
112
113 List<InventoryFolderBase> folders = FindFoldersByPath(inventoryService, startFolder, path);
114
115 if (folders.Count == 0)
116 return null;
117 else
118 return folders[0];
119 }
120
121 /// <summary>
122 /// Find a set of folders given a PATH_DELIMITER delimited path starting from a user's root folder
123 /// </summary>
124 /// <remarks>
125 /// This method does not handle paths that contain multiple delimitors
126 ///
127 /// FIXME: We have no way of distinguishing folders with the same path
61 /// 128 ///
129 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
130 /// </remarks>
62 /// <param name="inventoryService"> 131 /// <param name="inventoryService">
63 /// Inventory service to query 132 /// Inventory service to query
64 /// </param> 133 /// </param>
@@ -70,7 +139,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
70 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. 139 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
71 /// </param> 140 /// </param>
72 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns> 141 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns>
73 public static List<InventoryFolderBase> FindFolderByPath( 142 public static List<InventoryFolderBase> FindFoldersByPath(
74 IInventoryService inventoryService, UUID userId, string path) 143 IInventoryService inventoryService, UUID userId, string path)
75 { 144 {
76 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId); 145 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId);
@@ -78,19 +147,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
78 if (null == rootFolder) 147 if (null == rootFolder)
79 return new List<InventoryFolderBase>(); 148 return new List<InventoryFolderBase>();
80 149
81 return FindFolderByPath(inventoryService, rootFolder, path); 150 return FindFoldersByPath(inventoryService, rootFolder, path);
82 } 151 }
83 152
84 /// <summary> 153 /// <summary>
85 /// Find a folder given a PATH_DELIMITER delimited path starting from this folder 154 /// Find a set of folders given a PATH_DELIMITER delimited path starting from this folder
86 /// </summary> 155 /// </summary>
87 /// 156 /// <remarks>
88 /// This method does not handle paths that contain multiple delimitors 157 /// This method does not handle paths that contain multiple delimitors
89 /// 158 ///
90 /// FIXME: We have no way of distinguishing folders with the same path. 159 /// FIXME: We have no way of distinguishing folders with the same path.
91 /// 160 ///
92 /// FIXME: Delimitors which occur in names themselves are not currently escapable. 161 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
93 /// 162 /// </remarks>
94 /// <param name="inventoryService"> 163 /// <param name="inventoryService">
95 /// Inventory service to query 164 /// Inventory service to query
96 /// </param> 165 /// </param>
@@ -102,7 +171,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
102 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. 171 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
103 /// </param> 172 /// </param>
104 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns> 173 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns>
105 public static List<InventoryFolderBase> FindFolderByPath( 174 public static List<InventoryFolderBase> FindFoldersByPath(
106 IInventoryService inventoryService, InventoryFolderBase startFolder, string path) 175 IInventoryService inventoryService, InventoryFolderBase startFolder, string path)
107 { 176 {
108 List<InventoryFolderBase> foundFolders = new List<InventoryFolderBase>(); 177 List<InventoryFolderBase> foundFolders = new List<InventoryFolderBase>();
@@ -133,12 +202,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
133 202
134 InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID); 203 InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID);
135 204
205// m_log.DebugFormat(
206// "Found {0} folders in {1} for {2}", contents.Folders.Count, startFolder.Name, startFolder.Owner);
207
136 foreach (InventoryFolderBase folder in contents.Folders) 208 foreach (InventoryFolderBase folder in contents.Folders)
137 { 209 {
138 if (folder.Name == components[0]) 210 if (folder.Name == components[0])
139 { 211 {
140 if (components.Length > 1) 212 if (components.Length > 1)
141 foundFolders.AddRange(FindFolderByPath(inventoryService, folder, components[1])); 213 foundFolders.AddRange(FindFoldersByPath(inventoryService, folder, components[1]));
142 else 214 else
143 foundFolders.Add(folder); 215 foundFolders.Add(folder);
144 } 216 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
index d0e88f6..f002ad7 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
@@ -34,6 +34,7 @@ using System.Xml;
34using log4net; 34using log4net;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Framework.Monitoring;
37using OpenSim.Framework.Serialization; 38using OpenSim.Framework.Serialization;
38using OpenSim.Framework.Serialization.External; 39using OpenSim.Framework.Serialization.External;
39using OpenSim.Region.CoreModules.World.Archiver; 40using OpenSim.Region.CoreModules.World.Archiver;
@@ -42,6 +43,8 @@ using OpenSim.Services.Interfaces;
42using Ionic.Zlib; 43using Ionic.Zlib;
43using GZipStream = Ionic.Zlib.GZipStream; 44using GZipStream = Ionic.Zlib.GZipStream;
44using CompressionMode = Ionic.Zlib.CompressionMode; 45using CompressionMode = Ionic.Zlib.CompressionMode;
46using CompressionLevel = Ionic.Zlib.CompressionLevel;
47using PermissionMask = OpenSim.Framework.PermissionMask;
45 48
46namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver 49namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
47{ 50{
@@ -54,6 +57,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
54 /// </summary> 57 /// </summary>
55 public bool SaveAssets { get; set; } 58 public bool SaveAssets { get; set; }
56 59
60 /// <summary>
61 /// Determines which items will be included in the archive, according to their permissions.
62 /// Default is null, meaning no permission checks.
63 /// </summary>
64 public string FilterContent { get; set; }
65
66 /// <summary>
67 /// Counter for inventory items saved to archive for passing to compltion event
68 /// </summary>
69 public int CountItems { get; set; }
70
71 /// <summary>
72 /// Counter for inventory items skipped due to permission filter option for passing to compltion event
73 /// </summary>
74 public int CountFiltered { get; set; }
75
57 /// <value> 76 /// <value>
58 /// Used to select all inventory nodes in a folder but not the folder itself 77 /// Used to select all inventory nodes in a folder but not the folder itself
59 /// </value> 78 /// </value>
@@ -73,12 +92,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
73 /// <value> 92 /// <value>
74 /// ID of this request 93 /// ID of this request
75 /// </value> 94 /// </value>
76 protected Guid m_id; 95 protected UUID m_id;
77
78 /// <value>
79 /// Used to collect the uuids of the assets that we need to save into the archive
80 /// </value>
81 protected Dictionary<UUID, AssetType> m_assetUuids = new Dictionary<UUID, AssetType>();
82 96
83 /// <value> 97 /// <value>
84 /// Used to collect the uuids of the users that we need to save into the archive 98 /// Used to collect the uuids of the users that we need to save into the archive
@@ -94,7 +108,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
94 /// Constructor 108 /// Constructor
95 /// </summary> 109 /// </summary>
96 public InventoryArchiveWriteRequest( 110 public InventoryArchiveWriteRequest(
97 Guid id, InventoryArchiverModule module, Scene scene, 111 UUID id, InventoryArchiverModule module, Scene scene,
98 UserAccount userInfo, string invPath, string savePath) 112 UserAccount userInfo, string invPath, string savePath)
99 : this( 113 : this(
100 id, 114 id,
@@ -110,7 +124,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
110 /// Constructor 124 /// Constructor
111 /// </summary> 125 /// </summary>
112 public InventoryArchiveWriteRequest( 126 public InventoryArchiveWriteRequest(
113 Guid id, InventoryArchiverModule module, Scene scene, 127 UUID id, InventoryArchiverModule module, Scene scene,
114 UserAccount userInfo, string invPath, Stream saveStream) 128 UserAccount userInfo, string invPath, Stream saveStream)
115 { 129 {
116 m_id = id; 130 m_id = id;
@@ -122,9 +136,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
122 m_assetGatherer = new UuidGatherer(m_scene.AssetService); 136 m_assetGatherer = new UuidGatherer(m_scene.AssetService);
123 137
124 SaveAssets = true; 138 SaveAssets = true;
139 FilterContent = null;
125 } 140 }
126 141
127 protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids) 142 protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut)
128 { 143 {
129 Exception reportedException = null; 144 Exception reportedException = null;
130 bool succeeded = true; 145 bool succeeded = true;
@@ -143,8 +158,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
143 m_saveStream.Close(); 158 m_saveStream.Close();
144 } 159 }
145 160
161 if (timedOut)
162 {
163 succeeded = false;
164 reportedException = new Exception("Loading assets timed out");
165 }
166
146 m_module.TriggerInventoryArchiveSaved( 167 m_module.TriggerInventoryArchiveSaved(
147 m_id, succeeded, m_userInfo, m_invPath, m_saveStream, reportedException); 168 m_id, succeeded, m_userInfo, m_invPath, m_saveStream, reportedException, CountItems, CountFiltered);
148 } 169 }
149 170
150 protected void SaveInvItem(InventoryItemBase inventoryItem, string path, Dictionary<string, object> options, IUserAccountService userAccountService) 171 protected void SaveInvItem(InventoryItemBase inventoryItem, string path, Dictionary<string, object> options, IUserAccountService userAccountService)
@@ -160,10 +181,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
160 "[INVENTORY ARCHIVER]: Skipping inventory item {0} {1} at {2}", 181 "[INVENTORY ARCHIVER]: Skipping inventory item {0} {1} at {2}",
161 inventoryItem.Name, inventoryItem.ID, path); 182 inventoryItem.Name, inventoryItem.ID, path);
162 } 183 }
184
185 CountFiltered++;
186
163 return; 187 return;
164 } 188 }
165 } 189 }
166 190
191 // Check For Permissions Filter Flags
192 if (!CanUserArchiveObject(m_userInfo.PrincipalID, inventoryItem))
193 {
194 m_log.InfoFormat(
195 "[INVENTORY ARCHIVER]: Insufficient permissions, skipping inventory item {0} {1} at {2}",
196 inventoryItem.Name, inventoryItem.ID, path);
197
198 // Count Items Excluded
199 CountFiltered++;
200
201 return;
202 }
203
167 if (options.ContainsKey("verbose")) 204 if (options.ContainsKey("verbose"))
168 m_log.InfoFormat( 205 m_log.InfoFormat(
169 "[INVENTORY ARCHIVER]: Saving item {0} {1} (asset UUID {2})", 206 "[INVENTORY ARCHIVER]: Saving item {0} {1} (asset UUID {2})",
@@ -179,9 +216,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
179 216
180 AssetType itemAssetType = (AssetType)inventoryItem.AssetType; 217 AssetType itemAssetType = (AssetType)inventoryItem.AssetType;
181 218
219 // Count inventory items (different to asset count)
220 CountItems++;
221
182 // Don't chase down link asset items as they actually point to their target item IDs rather than an asset 222 // Don't chase down link asset items as they actually point to their target item IDs rather than an asset
183 if (SaveAssets && itemAssetType != AssetType.Link && itemAssetType != AssetType.LinkFolder) 223 if (SaveAssets && itemAssetType != AssetType.Link && itemAssetType != AssetType.LinkFolder)
184 m_assetGatherer.GatherAssetUuids(inventoryItem.AssetID, (AssetType)inventoryItem.AssetType, m_assetUuids); 224 m_assetGatherer.AddForInspection(inventoryItem.AssetID);
185 } 225 }
186 226
187 /// <summary> 227 /// <summary>
@@ -237,6 +277,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
237 } 277 }
238 278
239 /// <summary> 279 /// <summary>
280 /// Checks whether the user has permission to export an inventory item to an IAR.
281 /// </summary>
282 /// <param name="UserID">The user</param>
283 /// <param name="InvItem">The inventory item</param>
284 /// <returns>Whether the user is allowed to export the object to an IAR</returns>
285 private bool CanUserArchiveObject(UUID UserID, InventoryItemBase InvItem)
286 {
287 if (FilterContent == null)
288 return true;// Default To Allow Export
289
290 bool permitted = true;
291
292 bool canCopy = (InvItem.CurrentPermissions & (uint)PermissionMask.Copy) != 0;
293 bool canTransfer = (InvItem.CurrentPermissions & (uint)PermissionMask.Transfer) != 0;
294 bool canMod = (InvItem.CurrentPermissions & (uint)PermissionMask.Modify) != 0;
295
296 if (FilterContent.Contains("C") && !canCopy)
297 permitted = false;
298
299 if (FilterContent.Contains("T") && !canTransfer)
300 permitted = false;
301
302 if (FilterContent.Contains("M") && !canMod)
303 permitted = false;
304
305 return permitted;
306 }
307
308 /// <summary>
240 /// Execute the inventory write request 309 /// Execute the inventory write request
241 /// </summary> 310 /// </summary>
242 public void Execute(Dictionary<string, object> options, IUserAccountService userAccountService) 311 public void Execute(Dictionary<string, object> options, IUserAccountService userAccountService)
@@ -244,6 +313,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
244 if (options.ContainsKey("noassets") && (bool)options["noassets"]) 313 if (options.ContainsKey("noassets") && (bool)options["noassets"])
245 SaveAssets = false; 314 SaveAssets = false;
246 315
316 // Set Permission filter if flag is set
317 if (options.ContainsKey("checkPermissions"))
318 {
319 Object temp;
320 if (options.TryGetValue("checkPermissions", out temp))
321 FilterContent = temp.ToString().ToUpper();
322 }
323
247 try 324 try
248 { 325 {
249 InventoryFolderBase inventoryFolder = null; 326 InventoryFolderBase inventoryFolder = null;
@@ -266,6 +343,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
266 saveFolderContentsOnly = true; 343 saveFolderContentsOnly = true;
267 maxComponentIndex--; 344 maxComponentIndex--;
268 } 345 }
346 else if (maxComponentIndex == -1)
347 {
348 // If the user has just specified "/", then don't save the root "My Inventory" folder. This is
349 // more intuitive then requiring the user to specify "/*" for this.
350 saveFolderContentsOnly = true;
351 }
269 352
270 m_invPath = String.Empty; 353 m_invPath = String.Empty;
271 for (int i = 0; i <= maxComponentIndex; i++) 354 for (int i = 0; i <= maxComponentIndex; i++)
@@ -283,7 +366,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
283 { 366 {
284 m_invPath = m_invPath.Remove(m_invPath.LastIndexOf(InventoryFolderImpl.PATH_DELIMITER)); 367 m_invPath = m_invPath.Remove(m_invPath.LastIndexOf(InventoryFolderImpl.PATH_DELIMITER));
285 List<InventoryFolderBase> candidateFolders 368 List<InventoryFolderBase> candidateFolders
286 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, rootFolder, m_invPath); 369 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, rootFolder, m_invPath);
287 if (candidateFolders.Count > 0) 370 if (candidateFolders.Count > 0)
288 inventoryFolder = candidateFolders[0]; 371 inventoryFolder = candidateFolders[0];
289 } 372 }
@@ -297,7 +380,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
297 // We couldn't find the path indicated 380 // We couldn't find the path indicated
298 string errorMessage = string.Format("Aborted save. Could not find inventory path {0}", m_invPath); 381 string errorMessage = string.Format("Aborted save. Could not find inventory path {0}", m_invPath);
299 Exception e = new InventoryArchiverException(errorMessage); 382 Exception e = new InventoryArchiverException(errorMessage);
300 m_module.TriggerInventoryArchiveSaved(m_id, false, m_userInfo, m_invPath, m_saveStream, e); 383 m_module.TriggerInventoryArchiveSaved(m_id, false, m_userInfo, m_invPath, m_saveStream, e, 0, 0);
301 throw e; 384 throw e;
302 } 385 }
303 386
@@ -335,22 +418,25 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
335 418
336 if (SaveAssets) 419 if (SaveAssets)
337 { 420 {
338 m_log.DebugFormat("[INVENTORY ARCHIVER]: Saving {0} assets for items", m_assetUuids.Count); 421 m_assetGatherer.GatherAll();
422
423 m_log.DebugFormat(
424 "[INVENTORY ARCHIVER]: Saving {0} assets for items", m_assetGatherer.GatheredUuids.Count);
339 425
340 AssetsRequest ar 426 AssetsRequest ar
341 = new AssetsRequest( 427 = new AssetsRequest(
342 new AssetsArchiver(m_archiveWriter), 428 new AssetsArchiver(m_archiveWriter),
343 m_assetUuids, m_scene.AssetService, 429 m_assetGatherer.GatheredUuids, m_scene.AssetService,
344 m_scene.UserAccountService, m_scene.RegionInfo.ScopeID, 430 m_scene.UserAccountService, m_scene.RegionInfo.ScopeID,
345 options, ReceivedAllAssets); 431 options, ReceivedAllAssets);
346 432
347 Util.FireAndForget(o => ar.Execute()); 433 WorkManager.RunInThread(o => ar.Execute(), null, string.Format("AssetsRequest ({0})", m_scene.Name));
348 } 434 }
349 else 435 else
350 { 436 {
351 m_log.DebugFormat("[INVENTORY ARCHIVER]: Not saving assets since --noassets was specified"); 437 m_log.DebugFormat("[INVENTORY ARCHIVER]: Not saving assets since --noassets was specified");
352 438
353 ReceivedAllAssets(new List<UUID>(), new List<UUID>()); 439 ReceivedAllAssets(new List<UUID>(), new List<UUID>(), false);
354 } 440 }
355 } 441 }
356 catch (Exception) 442 catch (Exception)
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
index 849449b..8847414 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
@@ -34,7 +34,6 @@ using NDesk.Options;
34using Nini.Config; 34using Nini.Config;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Framework.Communications;
38using OpenSim.Framework.Console; 37using OpenSim.Framework.Console;
39using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
@@ -57,6 +56,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
57// public bool DisablePresenceChecks { get; set; } 56// public bool DisablePresenceChecks { get; set; }
58 57
59 public event InventoryArchiveSaved OnInventoryArchiveSaved; 58 public event InventoryArchiveSaved OnInventoryArchiveSaved;
59 public event InventoryArchiveLoaded OnInventoryArchiveLoaded;
60 60
61 /// <summary> 61 /// <summary>
62 /// The file to load and save inventory if no filename has been specified 62 /// The file to load and save inventory if no filename has been specified
@@ -64,9 +64,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
64 protected const string DEFAULT_INV_BACKUP_FILENAME = "user-inventory.iar"; 64 protected const string DEFAULT_INV_BACKUP_FILENAME = "user-inventory.iar";
65 65
66 /// <value> 66 /// <value>
67 /// Pending save completions initiated from the console 67 /// Pending save and load completions initiated from the console
68 /// </value> 68 /// </value>
69 protected List<Guid> m_pendingConsoleSaves = new List<Guid>(); 69 protected List<UUID> m_pendingConsoleTasks = new List<UUID>();
70 70
71 /// <value> 71 /// <value>
72 /// All scenes that this module knows about 72 /// All scenes that this module knows about
@@ -111,6 +111,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
111 { 111 {
112 scene.RegisterModuleInterface<IInventoryArchiverModule>(this); 112 scene.RegisterModuleInterface<IInventoryArchiverModule>(this);
113 OnInventoryArchiveSaved += SaveInvConsoleCommandCompleted; 113 OnInventoryArchiveSaved += SaveInvConsoleCommandCompleted;
114 OnInventoryArchiveLoaded += LoadInvConsoleCommandCompleted;
114 115
115 scene.AddCommand( 116 scene.AddCommand(
116 "Archiving", this, "load iar", 117 "Archiving", this, "load iar",
@@ -139,7 +140,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
139 + "-e|--exclude=<name/uuid> don't save the inventory item in archive" + Environment.NewLine 140 + "-e|--exclude=<name/uuid> don't save the inventory item in archive" + Environment.NewLine
140 + "-f|--excludefolder=<folder/uuid> don't save contents of the folder in archive" + Environment.NewLine 141 + "-f|--excludefolder=<folder/uuid> don't save contents of the folder in archive" + Environment.NewLine
141 + "-v|--verbose extra debug messages.\n" 142 + "-v|--verbose extra debug messages.\n"
142 + "--noassets stops assets being saved to the IAR.", 143 + "--noassets stops assets being saved to the IAR."
144 + "--perm=<permissions> stops items with insufficient permissions from being saved to the IAR.\n"
145 + " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer, \"M\" = Modify.\n",
143 HandleSaveInvConsoleCommand); 146 HandleSaveInvConsoleCommand);
144 147
145 m_aScene = scene; 148 m_aScene = scene;
@@ -175,22 +178,34 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
175 /// Trigger the inventory archive saved event. 178 /// Trigger the inventory archive saved event.
176 /// </summary> 179 /// </summary>
177 protected internal void TriggerInventoryArchiveSaved( 180 protected internal void TriggerInventoryArchiveSaved(
178 Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, 181 UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream,
179 Exception reportedException) 182 Exception reportedException, int SaveCount, int FilterCount)
180 { 183 {
181 InventoryArchiveSaved handlerInventoryArchiveSaved = OnInventoryArchiveSaved; 184 InventoryArchiveSaved handlerInventoryArchiveSaved = OnInventoryArchiveSaved;
182 if (handlerInventoryArchiveSaved != null) 185 if (handlerInventoryArchiveSaved != null)
183 handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException); 186 handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException, SaveCount , FilterCount);
187 }
188
189 /// <summary>
190 /// Trigger the inventory archive loaded event.
191 /// </summary>
192 protected internal void TriggerInventoryArchiveLoaded(
193 UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream loadStream,
194 Exception reportedException, int LoadCount)
195 {
196 InventoryArchiveLoaded handlerInventoryArchiveLoaded = OnInventoryArchiveLoaded;
197 if (handlerInventoryArchiveLoaded != null)
198 handlerInventoryArchiveLoaded(id, succeeded, userInfo, invPath, loadStream, reportedException, LoadCount);
184 } 199 }
185 200
186 public bool ArchiveInventory( 201 public bool ArchiveInventory(
187 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream) 202 UUID id, string firstName, string lastName, string invPath, string pass, Stream saveStream)
188 { 203 {
189 return ArchiveInventory(id, firstName, lastName, invPath, pass, saveStream, new Dictionary<string, object>()); 204 return ArchiveInventory(id, firstName, lastName, invPath, pass, saveStream, new Dictionary<string, object>());
190 } 205 }
191 206
192 public bool ArchiveInventory( 207 public bool ArchiveInventory(
193 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream, 208 UUID id, string firstName, string lastName, string invPath, string pass, Stream saveStream,
194 Dictionary<string, object> options) 209 Dictionary<string, object> options)
195 { 210 {
196 if (m_scenes.Count > 0) 211 if (m_scenes.Count > 0)
@@ -230,7 +245,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
230 } 245 }
231 246
232 public bool ArchiveInventory( 247 public bool ArchiveInventory(
233 Guid id, string firstName, string lastName, string invPath, string pass, string savePath, 248 UUID id, string firstName, string lastName, string invPath, string pass, string savePath,
234 Dictionary<string, object> options) 249 Dictionary<string, object> options)
235 { 250 {
236// if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath)) 251// if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath))
@@ -272,13 +287,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
272 return false; 287 return false;
273 } 288 }
274 289
275 public bool DearchiveInventory(string firstName, string lastName, string invPath, string pass, Stream loadStream) 290 public bool DearchiveInventory(UUID id, string firstName, string lastName, string invPath, string pass, Stream loadStream)
276 { 291 {
277 return DearchiveInventory(firstName, lastName, invPath, pass, loadStream, new Dictionary<string, object>()); 292 return DearchiveInventory(id, firstName, lastName, invPath, pass, loadStream, new Dictionary<string, object>());
278 } 293 }
279 294
280 public bool DearchiveInventory( 295 public bool DearchiveInventory(
281 string firstName, string lastName, string invPath, string pass, Stream loadStream, 296 UUID id, string firstName, string lastName, string invPath, string pass, Stream loadStream,
282 Dictionary<string, object> options) 297 Dictionary<string, object> options)
283 { 298 {
284 if (m_scenes.Count > 0) 299 if (m_scenes.Count > 0)
@@ -294,7 +309,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
294 309
295 try 310 try
296 { 311 {
297 request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream, merge); 312 request = new InventoryArchiveReadRequest(id, this, m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadStream, merge);
298 } 313 }
299 catch (EntryPointNotFoundException e) 314 catch (EntryPointNotFoundException e)
300 { 315 {
@@ -326,7 +341,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
326 } 341 }
327 342
328 public bool DearchiveInventory( 343 public bool DearchiveInventory(
329 string firstName, string lastName, string invPath, string pass, string loadPath, 344 UUID id, string firstName, string lastName, string invPath, string pass, string loadPath,
330 Dictionary<string, object> options) 345 Dictionary<string, object> options)
331 { 346 {
332 if (m_scenes.Count > 0) 347 if (m_scenes.Count > 0)
@@ -342,7 +357,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
342 357
343 try 358 try
344 { 359 {
345 request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath, merge); 360 request = new InventoryArchiveReadRequest(id, this, m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadPath, merge);
346 } 361 }
347 catch (EntryPointNotFoundException e) 362 catch (EntryPointNotFoundException e)
348 { 363 {
@@ -378,6 +393,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
378 { 393 {
379 try 394 try
380 { 395 {
396 UUID id = UUID.Random();
397
381 Dictionary<string, object> options = new Dictionary<string, object>(); 398 Dictionary<string, object> options = new Dictionary<string, object>();
382 OptionSet optionSet = new OptionSet().Add("m|merge", delegate (string v) { options["merge"] = v != null; }); 399 OptionSet optionSet = new OptionSet().Add("m|merge", delegate (string v) { options["merge"] = v != null; });
383 400
@@ -400,10 +417,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
400 "[INVENTORY ARCHIVER]: Loading archive {0} to inventory path {1} for {2} {3}", 417 "[INVENTORY ARCHIVER]: Loading archive {0} to inventory path {1} for {2} {3}",
401 loadPath, invPath, firstName, lastName); 418 loadPath, invPath, firstName, lastName);
402 419
403 if (DearchiveInventory(firstName, lastName, invPath, pass, loadPath, options)) 420 lock (m_pendingConsoleTasks)
404 m_log.InfoFormat( 421 m_pendingConsoleTasks.Add(id);
405 "[INVENTORY ARCHIVER]: Loaded archive {0} for {1} {2}", 422
406 loadPath, firstName, lastName); 423 DearchiveInventory(id, firstName, lastName, invPath, pass, loadPath, options);
407 } 424 }
408 catch (InventoryArchiverException e) 425 catch (InventoryArchiverException e)
409 { 426 {
@@ -417,7 +434,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
417 /// <param name="cmdparams"></param> 434 /// <param name="cmdparams"></param>
418 protected void HandleSaveInvConsoleCommand(string module, string[] cmdparams) 435 protected void HandleSaveInvConsoleCommand(string module, string[] cmdparams)
419 { 436 {
420 Guid id = Guid.NewGuid(); 437 UUID id = UUID.Random();
421 438
422 Dictionary<string, object> options = new Dictionary<string, object>(); 439 Dictionary<string, object> options = new Dictionary<string, object>();
423 440
@@ -439,6 +456,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
439 options["excludefolders"] = new List<String>(); 456 options["excludefolders"] = new List<String>();
440 ((List<String>)options["excludefolders"]).Add(v); 457 ((List<String>)options["excludefolders"]).Add(v);
441 }); 458 });
459 ops.Add("perm=", delegate(string v) { options["checkPermissions"] = v; });
442 460
443 List<string> mainParams = ops.Parse(cmdparams); 461 List<string> mainParams = ops.Parse(cmdparams);
444 462
@@ -464,8 +482,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
464 "[INVENTORY ARCHIVER]: Saving archive {0} using inventory path {1} for {2} {3}", 482 "[INVENTORY ARCHIVER]: Saving archive {0} using inventory path {1} for {2} {3}",
465 savePath, invPath, firstName, lastName); 483 savePath, invPath, firstName, lastName);
466 484
467 lock (m_pendingConsoleSaves) 485 lock (m_pendingConsoleTasks)
468 m_pendingConsoleSaves.Add(id); 486 m_pendingConsoleTasks.Add(id);
469 487
470 ArchiveInventory(id, firstName, lastName, invPath, pass, savePath, options); 488 ArchiveInventory(id, firstName, lastName, invPath, pass, savePath, options);
471 } 489 }
@@ -476,20 +494,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
476 } 494 }
477 495
478 private void SaveInvConsoleCommandCompleted( 496 private void SaveInvConsoleCommandCompleted(
479 Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, 497 UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream,
480 Exception reportedException) 498 Exception reportedException, int SaveCount, int FilterCount)
481 { 499 {
482 lock (m_pendingConsoleSaves) 500 lock (m_pendingConsoleTasks)
483 { 501 {
484 if (m_pendingConsoleSaves.Contains(id)) 502 if (m_pendingConsoleTasks.Contains(id))
485 m_pendingConsoleSaves.Remove(id); 503 m_pendingConsoleTasks.Remove(id);
486 else 504 else
487 return; 505 return;
488 } 506 }
489 507
490 if (succeeded) 508 if (succeeded)
491 { 509 {
492 m_log.InfoFormat("[INVENTORY ARCHIVER]: Saved archive for {0} {1}", userInfo.FirstName, userInfo.LastName); 510 // Report success and include item count and filter count (Skipped items due to --perm or --exclude switches)
511 if(FilterCount == 0)
512 m_log.InfoFormat("[INVENTORY ARCHIVER]: Saved archive with {0} items for {1} {2}", SaveCount, userInfo.FirstName, userInfo.LastName);
513 else
514 m_log.InfoFormat("[INVENTORY ARCHIVER]: Saved archive with {0} items for {1} {2}. Skipped {3} items due to exclude and/or perm switches", SaveCount, userInfo.FirstName, userInfo.LastName, FilterCount);
493 } 515 }
494 else 516 else
495 { 517 {
@@ -499,6 +521,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
499 } 521 }
500 } 522 }
501 523
524 private void LoadInvConsoleCommandCompleted(
525 UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream loadStream,
526 Exception reportedException, int LoadCount)
527 {
528 lock (m_pendingConsoleTasks)
529 {
530 if (m_pendingConsoleTasks.Contains(id))
531 m_pendingConsoleTasks.Remove(id);
532 else
533 return;
534 }
535
536 if (succeeded)
537 {
538 m_log.InfoFormat("[INVENTORY ARCHIVER]: Loaded {0} items from archive {1} for {2} {3}", LoadCount, invPath, userInfo.FirstName, userInfo.LastName);
539 }
540 else
541 {
542 m_log.ErrorFormat(
543 "[INVENTORY ARCHIVER]: Archive load for {0} {1} failed - {2}",
544 userInfo.FirstName, userInfo.LastName, reportedException.Message);
545 }
546 }
547
502 /// <summary> 548 /// <summary>
503 /// Get user information for the given name. 549 /// Get user information for the given name.
504 /// </summary> 550 /// </summary>
@@ -536,7 +582,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
536 } 582 }
537 catch (Exception e) 583 catch (Exception e)
538 { 584 {
539 m_log.ErrorFormat("[INVENTORY ARCHIVER]: Could not authenticate password, {0}", e.Message); 585 m_log.ErrorFormat("[INVENTORY ARCHIVER]: Could not authenticate password, {0}", e);
540 return null; 586 return null;
541 } 587 }
542 } 588 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs
index 6eb3605..c2e645f 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs
@@ -36,137 +36,19 @@ using OpenSim.Data;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Framework.Serialization; 37using OpenSim.Framework.Serialization;
38using OpenSim.Framework.Serialization.External; 38using OpenSim.Framework.Serialization.External;
39using OpenSim.Framework.Communications;
40using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; 39using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
41using OpenSim.Region.CoreModules.World.Serialiser; 40using OpenSim.Region.CoreModules.World.Serialiser;
42using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.Framework.Scenes.Serialization; 42using OpenSim.Region.Framework.Scenes.Serialization;
44using OpenSim.Services.Interfaces; 43using OpenSim.Services.Interfaces;
45using OpenSim.Tests.Common; 44using OpenSim.Tests.Common;
46using OpenSim.Tests.Common.Mock;
47 45
48namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests 46namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
49{ 47{
50 [TestFixture] 48 [TestFixture]
51 public class PathTests : InventoryArchiveTestCase 49 public class InventoryArchiveLoadPathTests : InventoryArchiveTestCase
52 { 50 {
53 /// <summary> 51 /// <summary>
54 /// Test saving an inventory path to a V0.1 OpenSim Inventory Archive
55 /// (subject to change since there is no fixed format yet).
56 /// </summary>
57 [Test]
58 public void TestSavePathToIarV0_1()
59 {
60 TestHelpers.InMethod();
61// log4net.Config.XmlConfigurator.Configure();
62
63 InventoryArchiverModule archiverModule = new InventoryArchiverModule();
64
65 Scene scene = new SceneHelpers().SetupScene();
66 SceneHelpers.SetupSceneModules(scene, archiverModule);
67
68 // Create user
69 string userFirstName = "Jock";
70 string userLastName = "Stirrup";
71 string userPassword = "troll";
72 UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020");
73 UserAccountHelpers.CreateUserWithInventory(scene, userFirstName, userLastName, userId, userPassword);
74
75 // Create asset
76 SceneObjectGroup object1;
77 SceneObjectPart part1;
78 {
79 string partName = "My Little Dog Object";
80 UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040");
81 PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere();
82 Vector3 groupPosition = new Vector3(10, 20, 30);
83 Quaternion rotationOffset = new Quaternion(20, 30, 40, 50);
84 Vector3 offsetPosition = new Vector3(5, 10, 15);
85
86 part1 = new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition);
87 part1.Name = partName;
88
89 object1 = new SceneObjectGroup(part1);
90 scene.AddNewSceneObject(object1, false);
91 }
92
93 UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060");
94 AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1);
95 scene.AssetService.Store(asset1);
96
97 // Create item
98 UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080");
99 InventoryItemBase item1 = new InventoryItemBase();
100 item1.Name = "My Little Dog";
101 item1.AssetID = asset1.FullID;
102 item1.ID = item1Id;
103 InventoryFolderBase objsFolder
104 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, userId, "Objects")[0];
105 item1.Folder = objsFolder.ID;
106 scene.AddInventoryItem(item1);
107
108 MemoryStream archiveWriteStream = new MemoryStream();
109 archiverModule.OnInventoryArchiveSaved += SaveCompleted;
110
111 // Test saving a particular path
112 mre.Reset();
113 archiverModule.ArchiveInventory(
114 Guid.NewGuid(), userFirstName, userLastName, "Objects", userPassword, archiveWriteStream);
115 mre.WaitOne(60000, false);
116
117 byte[] archive = archiveWriteStream.ToArray();
118 MemoryStream archiveReadStream = new MemoryStream(archive);
119 TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
120
121 //bool gotControlFile = false;
122 bool gotObject1File = false;
123 //bool gotObject2File = false;
124 string expectedObject1FileName = InventoryArchiveWriteRequest.CreateArchiveItemName(item1);
125 string expectedObject1FilePath = string.Format(
126 "{0}{1}{2}",
127 ArchiveConstants.INVENTORY_PATH,
128 InventoryArchiveWriteRequest.CreateArchiveFolderName(objsFolder),
129 expectedObject1FileName);
130
131 string filePath;
132 TarArchiveReader.TarEntryType tarEntryType;
133
134// Console.WriteLine("Reading archive");
135
136 while (tar.ReadEntry(out filePath, out tarEntryType) != null)
137 {
138// Console.WriteLine("Got {0}", filePath);
139
140// if (ArchiveConstants.CONTROL_FILE_PATH == filePath)
141// {
142// gotControlFile = true;
143// }
144
145 if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH) && filePath.EndsWith(".xml"))
146 {
147// string fileName = filePath.Remove(0, "Objects/".Length);
148//
149// if (fileName.StartsWith(part1.Name))
150// {
151 Assert.That(expectedObject1FilePath, Is.EqualTo(filePath));
152 gotObject1File = true;
153// }
154// else if (fileName.StartsWith(part2.Name))
155// {
156// Assert.That(fileName, Is.EqualTo(expectedObject2FileName));
157// gotObject2File = true;
158// }
159 }
160 }
161
162// Assert.That(gotControlFile, Is.True, "No control file in archive");
163 Assert.That(gotObject1File, Is.True, "No item1 file in archive");
164// Assert.That(gotObject2File, Is.True, "No object2 file in archive");
165
166 // TODO: Test presence of more files and contents of files.
167 }
168
169 /// <summary>
170 /// Test loading an IAR to various different inventory paths. 52 /// Test loading an IAR to various different inventory paths.
171 /// </summary> 53 /// </summary>
172 [Test] 54 [Test]
@@ -185,26 +67,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
185 67
186 UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "meowfood"); 68 UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "meowfood");
187 UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire"); 69 UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire");
188 70
189 archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); 71 archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream);
190 InventoryItemBase foundItem1 72 InventoryItemBase foundItem1
191 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); 73 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
192 74
193 Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); 75 Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1");
194 76
195 // Now try loading to a root child folder 77 // Now try loading to a root child folder
196 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xA"); 78 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xA", false);
197 MemoryStream archiveReadStream = new MemoryStream(m_iarStream.ToArray()); 79 MemoryStream archiveReadStream = new MemoryStream(m_iarStream.ToArray());
198 archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "xA", "meowfood", archiveReadStream); 80 archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "xA", "meowfood", archiveReadStream);
199 81
200 InventoryItemBase foundItem2 82 InventoryItemBase foundItem2
201 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, "xA/" + m_item1Name); 83 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, "xA/" + m_item1Name);
202 Assert.That(foundItem2, Is.Not.Null, "Didn't find loaded item 2"); 84 Assert.That(foundItem2, Is.Not.Null, "Didn't find loaded item 2");
203 85
204 // Now try loading to a more deeply nested folder 86 // Now try loading to a more deeply nested folder
205 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC"); 87 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC", false);
206 archiveReadStream = new MemoryStream(archiveReadStream.ToArray()); 88 archiveReadStream = new MemoryStream(archiveReadStream.ToArray());
207 archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "xB/xC", "meowfood", archiveReadStream); 89 archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "xB/xC", "meowfood", archiveReadStream);
208 90
209 InventoryItemBase foundItem3 91 InventoryItemBase foundItem3
210 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC/" + m_item1Name); 92 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC/" + m_item1Name);
@@ -226,7 +108,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
226 SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); 108 SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule);
227 109
228 UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "password"); 110 UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "password");
229 archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/Objects", "password", m_iarStream); 111 archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "/Objects", "password", m_iarStream);
230 112
231 InventoryItemBase foundItem1 113 InventoryItemBase foundItem1
232 = InventoryArchiveUtils.FindItemByPath( 114 = InventoryArchiveUtils.FindItemByPath(
@@ -287,7 +169,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
287 item1.AssetID = asset1.FullID; 169 item1.AssetID = asset1.FullID;
288 item1.ID = item1Id; 170 item1.ID = item1Id;
289 InventoryFolderBase objsFolder 171 InventoryFolderBase objsFolder
290 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, userId, "Objects")[0]; 172 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, userId, "Objects")[0];
291 item1.Folder = objsFolder.ID; 173 item1.Folder = objsFolder.ID;
292 scene.AddInventoryItem(item1); 174 scene.AddInventoryItem(item1);
293 175
@@ -296,13 +178,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
296 178
297 mre.Reset(); 179 mre.Reset();
298 archiverModule.ArchiveInventory( 180 archiverModule.ArchiveInventory(
299 Guid.NewGuid(), userFirstName, userLastName, "Objects", userPassword, archiveWriteStream); 181 UUID.Random(), userFirstName, userLastName, "Objects", userPassword, archiveWriteStream);
300 mre.WaitOne(60000, false); 182 mre.WaitOne(60000, false);
301 183
302 // LOAD ITEM 184 // LOAD ITEM
303 MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); 185 MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
304 186
305 archiverModule.DearchiveInventory(userFirstName, userLastName, "Scripts", userPassword, archiveReadStream); 187 archiverModule.DearchiveInventory(UUID.Random(), userFirstName, userLastName, "Scripts", userPassword, archiveReadStream);
306 188
307 InventoryItemBase foundItem1 189 InventoryItemBase foundItem1
308 = InventoryArchiveUtils.FindItemByPath( 190 = InventoryArchiveUtils.FindItemByPath(
@@ -345,40 +227,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
345 227
346 { 228 {
347 // Test replication of path1 229 // Test replication of path1
348 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false) 230 new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false)
349 .ReplicateArchivePathToUserInventory( 231 .ReplicateArchivePathToUserInventory(
350 iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 232 iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
351 foldersCreated, nodesLoaded); 233 foldersCreated, nodesLoaded);
352 234
353 List<InventoryFolderBase> folder1Candidates 235 List<InventoryFolderBase> folder1Candidates
354 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); 236 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1Name);
355 Assert.That(folder1Candidates.Count, Is.EqualTo(1)); 237 Assert.That(folder1Candidates.Count, Is.EqualTo(1));
356 238
357 InventoryFolderBase folder1 = folder1Candidates[0]; 239 InventoryFolderBase folder1 = folder1Candidates[0];
358 List<InventoryFolderBase> folder2aCandidates 240 List<InventoryFolderBase> folder2aCandidates
359 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1, folder2aName); 241 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2aName);
360 Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); 242 Assert.That(folder2aCandidates.Count, Is.EqualTo(1));
361 } 243 }
362 244
363 { 245 {
364 // Test replication of path2 246 // Test replication of path2
365 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false) 247 new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false)
366 .ReplicateArchivePathToUserInventory( 248 .ReplicateArchivePathToUserInventory(
367 iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 249 iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
368 foldersCreated, nodesLoaded); 250 foldersCreated, nodesLoaded);
369 251
370 List<InventoryFolderBase> folder1Candidates 252 List<InventoryFolderBase> folder1Candidates
371 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); 253 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1Name);
372 Assert.That(folder1Candidates.Count, Is.EqualTo(1)); 254 Assert.That(folder1Candidates.Count, Is.EqualTo(1));
373 255
374 InventoryFolderBase folder1 = folder1Candidates[0]; 256 InventoryFolderBase folder1 = folder1Candidates[0];
375 257
376 List<InventoryFolderBase> folder2aCandidates 258 List<InventoryFolderBase> folder2aCandidates
377 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1, folder2aName); 259 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2aName);
378 Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); 260 Assert.That(folder2aCandidates.Count, Is.EqualTo(1));
379 261
380 List<InventoryFolderBase> folder2bCandidates 262 List<InventoryFolderBase> folder2bCandidates
381 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1, folder2bName); 263 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2bName);
382 Assert.That(folder2bCandidates.Count, Is.EqualTo(1)); 264 Assert.That(folder2bCandidates.Count, Is.EqualTo(1));
383 } 265 }
384 } 266 }
@@ -401,20 +283,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
401 283
402 InventoryFolderBase folder1 284 InventoryFolderBase folder1
403 = UserInventoryHelpers.CreateInventoryFolder( 285 = UserInventoryHelpers.CreateInventoryFolder(
404 scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 286 scene.InventoryService, ua1.PrincipalID, folder1ExistingName, false);
405 287
406 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); 288 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random());
407 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); 289 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random());
408 290
409 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); 291 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName });
410 292
411 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false) 293 new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false)
412 .ReplicateArchivePathToUserInventory( 294 .ReplicateArchivePathToUserInventory(
413 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 295 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
414 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>()); 296 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
415 297
416 List<InventoryFolderBase> folder1PostCandidates 298 List<InventoryFolderBase> folder1PostCandidates
417 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 299 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
418 Assert.That(folder1PostCandidates.Count, Is.EqualTo(2)); 300 Assert.That(folder1PostCandidates.Count, Is.EqualTo(2));
419 301
420 // FIXME: Temporarily, we're going to do something messy to make sure we pick up the created folder. 302 // FIXME: Temporarily, we're going to do something messy to make sure we pick up the created folder.
@@ -430,7 +312,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
430// Assert.That(folder1Post.ID, Is.EqualTo(folder1.ID)); 312// Assert.That(folder1Post.ID, Is.EqualTo(folder1.ID));
431 313
432 List<InventoryFolderBase> folder2PostCandidates 314 List<InventoryFolderBase> folder2PostCandidates
433 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1Post, "b"); 315 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1Post, "b");
434 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); 316 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
435 } 317 }
436 318
@@ -452,26 +334,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
452 334
453 InventoryFolderBase folder1 335 InventoryFolderBase folder1
454 = UserInventoryHelpers.CreateInventoryFolder( 336 = UserInventoryHelpers.CreateInventoryFolder(
455 scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 337 scene.InventoryService, ua1.PrincipalID, folder1ExistingName, false);
456 338
457 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); 339 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random());
458 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); 340 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random());
459 341
460 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); 342 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName });
461 343
462 new InventoryArchiveReadRequest(scene, ua1, folder1ExistingName, (Stream)null, true) 344 new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, folder1ExistingName, (Stream)null, true)
463 .ReplicateArchivePathToUserInventory( 345 .ReplicateArchivePathToUserInventory(
464 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 346 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
465 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>()); 347 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
466 348
467 List<InventoryFolderBase> folder1PostCandidates 349 List<InventoryFolderBase> folder1PostCandidates
468 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 350 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
469 Assert.That(folder1PostCandidates.Count, Is.EqualTo(1)); 351 Assert.That(folder1PostCandidates.Count, Is.EqualTo(1));
470 Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID)); 352 Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID));
471 353
472 List<InventoryFolderBase> folder2PostCandidates 354 List<InventoryFolderBase> folder2PostCandidates
473 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1PostCandidates[0], "b"); 355 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1PostCandidates[0], "b");
474 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); 356 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
475 } 357 }
476 } 358 }
477} \ No newline at end of file 359}
360
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs
new file mode 100644
index 0000000..57b4f80
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs
@@ -0,0 +1,192 @@
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.IO;
31using System.Reflection;
32using System.Threading;
33using NUnit.Framework;
34using OpenMetaverse;
35using OpenSim.Data;
36using OpenSim.Framework;
37using OpenSim.Framework.Serialization;
38using OpenSim.Framework.Serialization.External;
39using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
40using OpenSim.Region.CoreModules.World.Serialiser;
41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.Framework.Scenes.Serialization;
43using OpenSim.Services.Interfaces;
44using OpenSim.Tests.Common;
45
46namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
47{
48 [TestFixture]
49 public class InventoryArchiveLoadTests : InventoryArchiveTestCase
50 {
51 protected TestScene m_scene;
52 protected InventoryArchiverModule m_archiverModule;
53
54 [SetUp]
55 public override void SetUp()
56 {
57 base.SetUp();
58
59 SerialiserModule serialiserModule = new SerialiserModule();
60 m_archiverModule = new InventoryArchiverModule();
61
62 m_scene = new SceneHelpers().SetupScene();
63 SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule);
64 }
65
66 [Test]
67 public void TestLoadCoalesecedItem()
68 {
69 TestHelpers.InMethod();
70// TestHelpers.EnableLogging();
71
72 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password");
73 m_archiverModule.DearchiveInventory(UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream);
74
75 InventoryItemBase coaItem
76 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_coaItemName);
77
78 Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1");
79
80 string assetXml = AssetHelpers.ReadAssetAsString(m_scene.AssetService, coaItem.AssetID);
81
82 CoalescedSceneObjects coa;
83 bool readResult = CoalescedSceneObjectsSerializer.TryFromXml(assetXml, out coa);
84
85 Assert.That(readResult, Is.True);
86 Assert.That(coa.Count, Is.EqualTo(2));
87
88 List<SceneObjectGroup> coaObjects = coa.Objects;
89 Assert.That(coaObjects[0].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000120")));
90 Assert.That(coaObjects[0].AbsolutePosition, Is.EqualTo(new Vector3(15, 30, 45)));
91
92 Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140")));
93 Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75)));
94 }
95
96 /// <summary>
97 /// Test case where a creator account exists for the creator UUID embedded in item metadata and serialized
98 /// objects.
99 /// </summary>
100 [Test]
101 public void TestLoadIarCreatorAccountPresent()
102 {
103 TestHelpers.InMethod();
104// log4net.Config.XmlConfigurator.Configure();
105
106 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "meowfood");
107
108 m_archiverModule.DearchiveInventory(UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/", "meowfood", m_iarStream);
109 InventoryItemBase foundItem1
110 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_item1Name);
111
112 Assert.That(
113 foundItem1.CreatorId, Is.EqualTo(m_uaLL1.PrincipalID.ToString()),
114 "Loaded item non-uuid creator doesn't match original");
115 Assert.That(
116 foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL1.PrincipalID),
117 "Loaded item uuid creator doesn't match original");
118 Assert.That(foundItem1.Owner, Is.EqualTo(m_uaLL1.PrincipalID),
119 "Loaded item owner doesn't match inventory reciever");
120
121 AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
122 string xmlData = Utils.BytesToString(asset1.Data);
123 SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
124
125 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID));
126 }
127
128// /// <summary>
129// /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
130// /// an account exists with the same name as the creator, though not the same id.
131// /// </summary>
132// [Test]
133// public void TestLoadIarV0_1SameNameCreator()
134// {
135// TestHelpers.InMethod();
136// TestHelpers.EnableLogging();
137//
138// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood");
139// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire");
140//
141// m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream);
142// InventoryItemBase foundItem1
143// = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
144//
145// Assert.That(
146// foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()),
147// "Loaded item non-uuid creator doesn't match original");
148// Assert.That(
149// foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID),
150// "Loaded item uuid creator doesn't match original");
151// Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID),
152// "Loaded item owner doesn't match inventory reciever");
153//
154// AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
155// string xmlData = Utils.BytesToString(asset1.Data);
156// SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
157//
158// Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID));
159// }
160
161 /// <summary>
162 /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
163 /// the creator or an account with the creator's name does not exist within the system.
164 /// </summary>
165 [Test]
166 public void TestLoadIarV0_1AbsentCreator()
167 {
168 TestHelpers.InMethod();
169// log4net.Config.XmlConfigurator.Configure();
170
171 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "password");
172 m_archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "/", "password", m_iarStream);
173
174 InventoryItemBase foundItem1
175 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
176
177 Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1");
178 Assert.That(
179 foundItem1.CreatorId, Is.EqualTo(m_uaMT.PrincipalID.ToString()),
180 "Loaded item non-uuid creator doesn't match that of the loading user");
181 Assert.That(
182 foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaMT.PrincipalID),
183 "Loaded item uuid creator doesn't match that of the loading user");
184
185 AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
186 string xmlData = Utils.BytesToString(asset1.Data);
187 SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
188
189 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaMT.PrincipalID));
190 }
191 }
192} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs
index 06f6e49..7265405 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs
@@ -36,19 +36,17 @@ using OpenSim.Data;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Framework.Serialization; 37using OpenSim.Framework.Serialization;
38using OpenSim.Framework.Serialization.External; 38using OpenSim.Framework.Serialization.External;
39using OpenSim.Framework.Communications;
40using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; 39using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
41using OpenSim.Region.CoreModules.World.Serialiser; 40using OpenSim.Region.CoreModules.World.Serialiser;
42using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.Framework.Scenes.Serialization; 42using OpenSim.Region.Framework.Scenes.Serialization;
44using OpenSim.Services.Interfaces; 43using OpenSim.Services.Interfaces;
45using OpenSim.Tests.Common; 44using OpenSim.Tests.Common;
46using OpenSim.Tests.Common.Mock;
47 45
48namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests 46namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
49{ 47{
50 [TestFixture] 48 [TestFixture]
51 public class InventoryArchiverTests : InventoryArchiveTestCase 49 public class InventoryArchiveSaveTests : InventoryArchiveTestCase
52 { 50 {
53 protected TestScene m_scene; 51 protected TestScene m_scene;
54 protected InventoryArchiverModule m_archiverModule; 52 protected InventoryArchiverModule m_archiverModule;
@@ -64,36 +62,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
64 m_scene = new SceneHelpers().SetupScene(); 62 m_scene = new SceneHelpers().SetupScene();
65 SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); 63 SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule);
66 } 64 }
67
68 [Test]
69 public void TestLoadCoalesecedItem()
70 {
71 TestHelpers.InMethod();
72// TestHelpers.EnableLogging();
73
74 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password");
75 m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream);
76
77 InventoryItemBase coaItem
78 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_coaItemName);
79
80 Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1");
81
82 string assetXml = AssetHelpers.ReadAssetAsString(m_scene.AssetService, coaItem.AssetID);
83
84 CoalescedSceneObjects coa;
85 bool readResult = CoalescedSceneObjectsSerializer.TryFromXml(assetXml, out coa);
86
87 Assert.That(readResult, Is.True);
88 Assert.That(coa.Count, Is.EqualTo(2));
89
90 List<SceneObjectGroup> coaObjects = coa.Objects;
91 Assert.That(coaObjects[0].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000120")));
92 Assert.That(coaObjects[0].AbsolutePosition, Is.EqualTo(new Vector3(15, 30, 45)));
93
94 Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140")));
95 Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75)));
96 }
97 65
98 /// <summary> 66 /// <summary>
99 /// Test that the IAR has the required files in the right order. 67 /// Test that the IAR has the required files in the right order.
@@ -115,12 +83,145 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
115 byte[] data = tar.ReadEntry(out filePath, out tarEntryType); 83 byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
116 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); 84 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
117 85
118 InventoryArchiveReadRequest iarr 86 InventoryArchiveReadRequest iarr
119 = new InventoryArchiveReadRequest(null, null, null, (Stream)null, false); 87 = new InventoryArchiveReadRequest(UUID.Random(), null, null, null, null, null, null, (Stream)null, false);
120 iarr.LoadControlFile(filePath, data); 88 iarr.LoadControlFile(filePath, data);
121 89
122 Assert.That(iarr.ControlFileLoaded, Is.True); 90 Assert.That(iarr.ControlFileLoaded, Is.True);
123 } 91 }
92
93 [Test]
94 public void TestSaveRootFolderToIar()
95 {
96 TestHelpers.InMethod();
97// TestHelpers.EnableLogging();
98
99 string userFirstName = "Jock";
100 string userLastName = "Stirrup";
101 string userPassword = "troll";
102 UUID userId = TestHelpers.ParseTail(0x20);
103
104 UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword);
105
106 MemoryStream archiveWriteStream = new MemoryStream();
107 m_archiverModule.OnInventoryArchiveSaved += SaveCompleted;
108
109 mre.Reset();
110 m_archiverModule.ArchiveInventory(
111 UUID.Random(), userFirstName, userLastName, "/", userPassword, archiveWriteStream);
112 mre.WaitOne(60000, false);
113
114 // Test created iar
115 byte[] archive = archiveWriteStream.ToArray();
116 MemoryStream archiveReadStream = new MemoryStream(archive);
117 TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
118
119// InventoryArchiveUtils.
120 bool gotObjectsFolder = false;
121
122 string objectsFolderName
123 = string.Format(
124 "{0}{1}",
125 ArchiveConstants.INVENTORY_PATH,
126 InventoryArchiveWriteRequest.CreateArchiveFolderName(
127 UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, userId, "Objects")));
128
129 string filePath;
130 TarArchiveReader.TarEntryType tarEntryType;
131
132 while (tar.ReadEntry(out filePath, out tarEntryType) != null)
133 {
134// Console.WriteLine("Got {0}", filePath);
135
136 // Lazily, we only bother to look for the system objects folder created when we call CreateUserWithInventory()
137 // XXX: But really we need to stop all that stuff being created in tests or check for such folders
138 // more thoroughly
139 if (filePath == objectsFolderName)
140 gotObjectsFolder = true;
141 }
142
143 Assert.That(gotObjectsFolder, Is.True);
144 }
145
146 [Test]
147 public void TestSaveNonRootFolderToIar()
148 {
149 TestHelpers.InMethod();
150// TestHelpers.EnableLogging();
151
152 string userFirstName = "Jock";
153 string userLastName = "Stirrup";
154 string userPassword = "troll";
155 UUID userId = TestHelpers.ParseTail(0x20);
156
157 UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword);
158
159 // Create base folder
160 InventoryFolderBase f1
161 = UserInventoryHelpers.CreateInventoryFolder(m_scene.InventoryService, userId, "f1", true);
162
163 // Create item1
164 SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Dog Object", 0x5);
165 InventoryItemBase i1 = UserInventoryHelpers.AddInventoryItem(m_scene, so1, 0x50, 0x60, "f1");
166
167 // Create embedded folder
168 InventoryFolderBase f1_1
169 = UserInventoryHelpers.CreateInventoryFolder(m_scene.InventoryService, userId, "f1/f1.1", true);
170
171 // Create embedded item
172 SceneObjectGroup so1_1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Cat Object", 0x6);
173 InventoryItemBase i2 = UserInventoryHelpers.AddInventoryItem(m_scene, so1_1, 0x500, 0x600, "f1/f1.1");
174
175 MemoryStream archiveWriteStream = new MemoryStream();
176 m_archiverModule.OnInventoryArchiveSaved += SaveCompleted;
177
178 mre.Reset();
179 m_archiverModule.ArchiveInventory(
180 UUID.Random(), userFirstName, userLastName, "f1", userPassword, archiveWriteStream);
181 mre.WaitOne(60000, false);
182
183 // Test created iar
184 byte[] archive = archiveWriteStream.ToArray();
185 MemoryStream archiveReadStream = new MemoryStream(archive);
186 TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
187
188// InventoryArchiveUtils.
189 bool gotf1 = false, gotf1_1 = false, gotso1 = false, gotso2 = false;
190
191 string f1FileName
192 = string.Format("{0}{1}", ArchiveConstants.INVENTORY_PATH, InventoryArchiveWriteRequest.CreateArchiveFolderName(f1));
193 string f1_1FileName
194 = string.Format("{0}{1}", f1FileName, InventoryArchiveWriteRequest.CreateArchiveFolderName(f1_1));
195 string so1FileName
196 = string.Format("{0}{1}", f1FileName, InventoryArchiveWriteRequest.CreateArchiveItemName(i1));
197 string so2FileName
198 = string.Format("{0}{1}", f1_1FileName, InventoryArchiveWriteRequest.CreateArchiveItemName(i2));
199
200 string filePath;
201 TarArchiveReader.TarEntryType tarEntryType;
202
203 while (tar.ReadEntry(out filePath, out tarEntryType) != null)
204 {
205// Console.WriteLine("Got {0}", filePath);
206
207 if (filePath == f1FileName)
208 gotf1 = true;
209 else if (filePath == f1_1FileName)
210 gotf1_1 = true;
211 else if (filePath == so1FileName)
212 gotso1 = true;
213 else if (filePath == so2FileName)
214 gotso2 = true;
215 }
216
217// Assert.That(gotControlFile, Is.True, "No control file in archive");
218 Assert.That(gotf1, Is.True);
219 Assert.That(gotf1_1, Is.True);
220 Assert.That(gotso1, Is.True);
221 Assert.That(gotso2, Is.True);
222
223 // TODO: Test presence of more files and contents of files.
224 }
124 225
125 /// <summary> 226 /// <summary>
126 /// Test saving a single inventory item to an IAR 227 /// Test saving a single inventory item to an IAR
@@ -155,7 +256,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
155 item1.AssetID = asset1.FullID; 256 item1.AssetID = asset1.FullID;
156 item1.ID = item1Id; 257 item1.ID = item1Id;
157 InventoryFolderBase objsFolder 258 InventoryFolderBase objsFolder
158 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, userId, "Objects")[0]; 259 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, userId, "Objects")[0];
159 item1.Folder = objsFolder.ID; 260 item1.Folder = objsFolder.ID;
160 m_scene.AddInventoryItem(item1); 261 m_scene.AddInventoryItem(item1);
161 262
@@ -164,7 +265,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
164 265
165 mre.Reset(); 266 mre.Reset();
166 m_archiverModule.ArchiveInventory( 267 m_archiverModule.ArchiveInventory(
167 Guid.NewGuid(), userFirstName, userLastName, "Objects/" + item1Name, userPassword, archiveWriteStream); 268 UUID.Random(), userFirstName, userLastName, "Objects/" + item1Name, userPassword, archiveWriteStream);
168 mre.WaitOne(60000, false); 269 mre.WaitOne(60000, false);
169 270
170 byte[] archive = archiveWriteStream.ToArray(); 271 byte[] archive = archiveWriteStream.ToArray();
@@ -250,7 +351,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
250 item1.AssetID = asset1.FullID; 351 item1.AssetID = asset1.FullID;
251 item1.ID = item1Id; 352 item1.ID = item1Id;
252 InventoryFolderBase objsFolder 353 InventoryFolderBase objsFolder
253 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, userId, "Objects")[0]; 354 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, userId, "Objects")[0];
254 item1.Folder = objsFolder.ID; 355 item1.Folder = objsFolder.ID;
255 m_scene.AddInventoryItem(item1); 356 m_scene.AddInventoryItem(item1);
256 357
@@ -261,7 +362,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
261 362
262 // When we're not saving assets, archiving is being done synchronously. 363 // When we're not saving assets, archiving is being done synchronously.
263 m_archiverModule.ArchiveInventory( 364 m_archiverModule.ArchiveInventory(
264 Guid.NewGuid(), userFirstName, userLastName, "Objects/" + item1Name, userPassword, archiveWriteStream, options); 365 UUID.Random(), userFirstName, userLastName, "Objects/" + item1Name, userPassword, archiveWriteStream, options);
265 366
266 byte[] archive = archiveWriteStream.ToArray(); 367 byte[] archive = archiveWriteStream.ToArray();
267 MemoryStream archiveReadStream = new MemoryStream(archive); 368 MemoryStream archiveReadStream = new MemoryStream(archive);
@@ -317,101 +418,5 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
317 418
318 // TODO: Test presence of more files and contents of files. 419 // TODO: Test presence of more files and contents of files.
319 } 420 }
320
321 /// <summary>
322 /// Test case where a creator account exists for the creator UUID embedded in item metadata and serialized
323 /// objects.
324 /// </summary>
325 [Test]
326 public void TestLoadIarCreatorAccountPresent()
327 {
328 TestHelpers.InMethod();
329// log4net.Config.XmlConfigurator.Configure();
330
331 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "meowfood");
332
333 m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "meowfood", m_iarStream);
334 InventoryItemBase foundItem1
335 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_item1Name);
336
337 Assert.That(
338 foundItem1.CreatorId, Is.EqualTo(m_uaLL1.PrincipalID.ToString()),
339 "Loaded item non-uuid creator doesn't match original");
340 Assert.That(
341 foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL1.PrincipalID),
342 "Loaded item uuid creator doesn't match original");
343 Assert.That(foundItem1.Owner, Is.EqualTo(m_uaLL1.PrincipalID),
344 "Loaded item owner doesn't match inventory reciever");
345
346 AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
347 string xmlData = Utils.BytesToString(asset1.Data);
348 SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
349
350 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID));
351 }
352
353// /// <summary>
354// /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
355// /// an account exists with the same name as the creator, though not the same id.
356// /// </summary>
357// [Test]
358// public void TestLoadIarV0_1SameNameCreator()
359// {
360// TestHelpers.InMethod();
361// TestHelpers.EnableLogging();
362//
363// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood");
364// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire");
365//
366// m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream);
367// InventoryItemBase foundItem1
368// = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
369//
370// Assert.That(
371// foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()),
372// "Loaded item non-uuid creator doesn't match original");
373// Assert.That(
374// foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID),
375// "Loaded item uuid creator doesn't match original");
376// Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID),
377// "Loaded item owner doesn't match inventory reciever");
378//
379// AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
380// string xmlData = Utils.BytesToString(asset1.Data);
381// SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
382//
383// Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID));
384// }
385
386 /// <summary>
387 /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
388 /// the creator or an account with the creator's name does not exist within the system.
389 /// </summary>
390 [Test]
391 public void TestLoadIarV0_1AbsentCreator()
392 {
393 TestHelpers.InMethod();
394// log4net.Config.XmlConfigurator.Configure();
395
396 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "password");
397 m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "password", m_iarStream);
398
399 InventoryItemBase foundItem1
400 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
401
402 Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1");
403 Assert.That(
404 foundItem1.CreatorId, Is.EqualTo(m_uaMT.PrincipalID.ToString()),
405 "Loaded item non-uuid creator doesn't match that of the loading user");
406 Assert.That(
407 foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaMT.PrincipalID),
408 "Loaded item uuid creator doesn't match that of the loading user");
409
410 AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
411 string xmlData = Utils.BytesToString(asset1.Data);
412 SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
413
414 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaMT.PrincipalID));
415 }
416 } 421 }
417} \ No newline at end of file 422} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs
index db78da9..519c697 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs
@@ -36,14 +36,12 @@ using OpenSim.Data;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Framework.Serialization; 37using OpenSim.Framework.Serialization;
38using OpenSim.Framework.Serialization.External; 38using OpenSim.Framework.Serialization.External;
39using OpenSim.Framework.Communications;
40using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; 39using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
41using OpenSim.Region.CoreModules.World.Serialiser; 40using OpenSim.Region.CoreModules.World.Serialiser;
42using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.Framework.Scenes.Serialization; 42using OpenSim.Region.Framework.Scenes.Serialization;
44using OpenSim.Services.Interfaces; 43using OpenSim.Services.Interfaces;
45using OpenSim.Tests.Common; 44using OpenSim.Tests.Common;
46using OpenSim.Tests.Common.Mock;
47 45
48namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests 46namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
49{ 47{
@@ -163,14 +161,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
163 scene.AddInventoryItem(coaItem); 161 scene.AddInventoryItem(coaItem);
164 162
165 archiverModule.ArchiveInventory( 163 archiverModule.ArchiveInventory(
166 Guid.NewGuid(), m_uaLL1.FirstName, m_uaLL1.LastName, "/*", "hampshire", archiveWriteStream); 164 UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/*", "hampshire", archiveWriteStream);
167 165
168 m_iarStreamBytes = archiveWriteStream.ToArray(); 166 m_iarStreamBytes = archiveWriteStream.ToArray();
169 } 167 }
170 168
171 protected void SaveCompleted( 169 protected void SaveCompleted(
172 Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, 170 UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream,
173 Exception reportedException) 171 Exception reportedException, int SaveCount, int FilterCount)
174 { 172 {
175 mre.Set(); 173 mre.Set();
176 } 174 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
index bcb7f42..bba48cc 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
@@ -47,10 +47,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
47 47
48 /// <summary> 48 /// <summary>
49 private List<Scene> m_Scenelist = new List<Scene>(); 49 private List<Scene> m_Scenelist = new List<Scene>();
50// private Dictionary<UUID, Scene> m_AgentRegions =
51// new Dictionary<UUID, Scene>();
52 50
53 private IMessageTransferModule m_TransferModule = null; 51 private IMessageTransferModule m_TransferModule;
54 private bool m_Enabled = true; 52 private bool m_Enabled = true;
55 53
56 #region Region Module interface 54 #region Region Module interface
@@ -81,9 +79,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
81// scene.RegisterModuleInterface<IInventoryTransferModule>(this); 79// scene.RegisterModuleInterface<IInventoryTransferModule>(this);
82 80
83 scene.EventManager.OnNewClient += OnNewClient; 81 scene.EventManager.OnNewClient += OnNewClient;
84// scene.EventManager.OnClientClosed += ClientLoggedOut;
85 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; 82 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
86// scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
87 } 83 }
88 84
89 public void RegionLoaded(Scene scene) 85 public void RegionLoaded(Scene scene)
@@ -96,11 +92,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
96 m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only"); 92 m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only");
97 m_Enabled = false; 93 m_Enabled = false;
98 94
99 m_Scenelist.Clear(); 95// m_Scenelist.Clear();
100 scene.EventManager.OnNewClient -= OnNewClient; 96// scene.EventManager.OnNewClient -= OnNewClient;
101// scene.EventManager.OnClientClosed -= ClientLoggedOut;
102 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; 97 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
103// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
104 } 98 }
105 } 99 }
106 } 100 }
@@ -108,9 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
108 public void RemoveRegion(Scene scene) 102 public void RemoveRegion(Scene scene)
109 { 103 {
110 scene.EventManager.OnNewClient -= OnNewClient; 104 scene.EventManager.OnNewClient -= OnNewClient;
111// scene.EventManager.OnClientClosed -= ClientLoggedOut;
112 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; 105 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
113// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
114 m_Scenelist.Remove(scene); 106 m_Scenelist.Remove(scene);
115 } 107 }
116 108
@@ -139,11 +131,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
139 // Inventory giving is conducted via instant message 131 // Inventory giving is conducted via instant message
140 client.OnInstantMessage += OnInstantMessage; 132 client.OnInstantMessage += OnInstantMessage;
141 } 133 }
142
143// protected void OnSetRootAgentScene(UUID id, Scene scene)
144// {
145// m_AgentRegions[id] = scene;
146// }
147 134
148 private Scene FindClientScene(UUID agentId) 135 private Scene FindClientScene(UUID agentId)
149 { 136 {
@@ -162,8 +149,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
162 private void OnInstantMessage(IClientAPI client, GridInstantMessage im) 149 private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
163 { 150 {
164// m_log.DebugFormat( 151// m_log.DebugFormat(
165// "[INVENTORY TRANSFER]: {0} IM type received from {1}", 152// "[INVENTORY TRANSFER]: {0} IM type received from client {1}. From={2} ({3}), To={4}",
166// (InstantMessageDialog)im.dialog, client.Name); 153// (InstantMessageDialog)im.dialog, client.Name,
154// im.fromAgentID, im.fromAgentName, im.toAgentID);
167 155
168 Scene scene = FindClientScene(client.AgentId); 156 Scene scene = FindClientScene(client.AgentId);
169 157
@@ -188,12 +176,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
188 { 176 {
189 UUID folderID = new UUID(im.binaryBucket, 1); 177 UUID folderID = new UUID(im.binaryBucket, 1);
190 178
191 m_log.DebugFormat("[INVENTORY TRANSFER]: Inserting original folder {0} "+ 179 m_log.DebugFormat(
192 "into agent {1}'s inventory", 180 "[INVENTORY TRANSFER]: Inserting original folder {0} into agent {1}'s inventory",
193 folderID, new UUID(im.toAgentID)); 181 folderID, new UUID(im.toAgentID));
194 182
195 InventoryFolderBase folderCopy 183 InventoryFolderBase folderCopy
196 = scene.GiveInventoryFolder(receipientID, client.AgentId, folderID, UUID.Zero); 184 = scene.GiveInventoryFolder(client, receipientID, client.AgentId, folderID, UUID.Zero);
197 185
198 if (folderCopy == null) 186 if (folderCopy == null)
199 { 187 {
@@ -213,7 +201,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
213 user.ControllingClient.SendBulkUpdateInventory(folderCopy); 201 user.ControllingClient.SendBulkUpdateInventory(folderCopy);
214 202
215 // HACK!! 203 // HACK!!
216 im.imSessionID = folderID.Guid; 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;
217 } 208 }
218 else 209 else
219 { 210 {
@@ -226,13 +217,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
226 "into agent {1}'s inventory", 217 "into agent {1}'s inventory",
227 itemID, new UUID(im.toAgentID)); 218 itemID, new UUID(im.toAgentID));
228 219
229 InventoryItemBase itemCopy = scene.GiveInventoryItem( 220 string message;
230 new UUID(im.toAgentID), 221 InventoryItemBase itemCopy = scene.GiveInventoryItem(new UUID(im.toAgentID), client.AgentId, itemID, out message);
231 client.AgentId, itemID);
232 222
233 if (itemCopy == null) 223 if (itemCopy == null)
234 { 224 {
235 client.SendAgentAlertMessage("Can't find item to give. Nothing given.", false); 225 client.SendAgentAlertMessage(message, false);
236 return; 226 return;
237 } 227 }
238 228
@@ -243,7 +233,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
243 user.ControllingClient.SendBulkUpdateInventory(itemCopy); 233 user.ControllingClient.SendBulkUpdateInventory(itemCopy);
244 234
245 // HACK!! 235 // HACK!!
246 im.imSessionID = itemID.Guid; 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;
247 } 240 }
248 241
249 // Send the IM to the recipient. The item is already 242 // Send the IM to the recipient. The item is already
@@ -379,7 +372,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
379 IInventoryService invService = scene.InventoryService; 372 IInventoryService invService = scene.InventoryService;
380 373
381 InventoryFolderBase trashFolder = 374 InventoryFolderBase trashFolder =
382 invService.GetFolderForType(client.AgentId, AssetType.TrashFolder); 375 invService.GetFolderForType(client.AgentId, FolderType.Trash);
383 376
384 UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip 377 UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
385 378
@@ -403,7 +396,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
403 { 396 {
404 folder = new InventoryFolderBase(inventoryID, client.AgentId); 397 folder = new InventoryFolderBase(inventoryID, client.AgentId);
405 folder = invService.GetFolder(folder); 398 folder = invService.GetFolder(folder);
406 399
407 if (folder != null & trashFolder != null) 400 if (folder != null & trashFolder != null)
408 { 401 {
409 previousParentFolderID = folder.ParentID; 402 previousParentFolderID = folder.ParentID;
@@ -454,90 +447,61 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
454 } 447 }
455 } 448 }
456 449
457// public bool NeedSceneCacheClear(UUID agentID, Scene scene)
458// {
459// if (!m_AgentRegions.ContainsKey(agentID))
460// {
461// // Since we can get here two ways, we need to scan
462// // the scenes here. This is somewhat more expensive
463// // but helps avoid a nasty bug
464// //
465//
466// foreach (Scene s in m_Scenelist)
467// {
468// ScenePresence presence;
469//
470// if (s.TryGetScenePresence(agentID, out presence))
471// {
472// // If the agent is in this scene, then we
473// // are being called twice in a single
474// // teleport. This is wasteful of cycles
475// // but harmless due to this 2nd level check
476// //
477// // If the agent is found in another scene
478// // then the list wasn't current
479// //
480// // If the agent is totally unknown, then what
481// // are we even doing here??
482// //
483// if (s == scene)
484// {
485// //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
486// return true;
487// }
488// else
489// {
490// //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
491// return false;
492// }
493// }
494// }
495// //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
496// return true;
497// }
498//
499// // The agent is left in current Scene, so we must be
500// // going to another instance
501// //
502// if (m_AgentRegions[agentID] == scene)
503// {
504// //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
505// m_AgentRegions.Remove(agentID);
506// return true;
507// }
508//
509// // Another region has claimed the agent
510// //
511// //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
512// return false;
513// }
514//
515// public void ClientLoggedOut(UUID agentID, Scene scene)
516// {
517// if (m_AgentRegions.ContainsKey(agentID))
518// m_AgentRegions.Remove(agentID);
519// }
520
521 /// <summary> 450 /// <summary>
522 /// 451 ///
523 /// </summary> 452 /// </summary>
524 /// <param name="msg"></param> 453 /// <param name="im"></param>
525 private void OnGridInstantMessage(GridInstantMessage msg) 454 private void OnGridInstantMessage(GridInstantMessage im)
526 { 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.TaskInventoryOffered)
459 || (im.dialog == (byte) InstantMessageDialog.InventoryAccepted)
460 || (im.dialog == (byte) InstantMessageDialog.InventoryDeclined)
461 || (im.dialog == (byte) InstantMessageDialog.TaskInventoryDeclined)))
462 return;
463
464 m_log.DebugFormat(
465 "[INVENTORY TRANSFER]: {0} IM type received from grid. From={1} ({2}), To={3}",
466 (InstantMessageDialog)im.dialog, im.fromAgentID, im.fromAgentName, im.toAgentID);
467
527 // Check if this is ours to handle 468 // Check if this is ours to handle
528 // 469 //
529 Scene scene = FindClientScene(new UUID(msg.toAgentID)); 470 Scene scene = FindClientScene(new UUID(im.toAgentID));
530 471
531 if (scene == null) 472 if (scene == null)
532 return; 473 return;
533 474
534 // Find agent to deliver to 475 // Find agent to deliver to
535 // 476 //
536 ScenePresence user = scene.GetScenePresence(new UUID(msg.toAgentID)); 477 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
537 478
538 // Just forward to local handling 479 if (user != null)
539 OnInstantMessage(user.ControllingClient, msg); 480 {
481 user.ControllingClient.SendInstantMessage(im);
482
483 if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
484 {
485 AssetType assetType = (AssetType)im.binaryBucket[0];
486 UUID inventoryID = new UUID(im.binaryBucket, 1);
487
488 IInventoryService invService = scene.InventoryService;
489 InventoryNodeBase node = null;
490 if (AssetType.Folder == assetType)
491 {
492 InventoryFolderBase folder = new InventoryFolderBase(inventoryID, new UUID(im.toAgentID));
493 node = invService.GetFolder(folder);
494 }
495 else
496 {
497 InventoryItemBase item = new InventoryItemBase(inventoryID, new UUID(im.toAgentID));
498 node = invService.GetItem(item);
499 }
540 500
501 if (node != null)
502 user.ControllingClient.SendBulkUpdateInventory(node);
503 }
504 }
541 } 505 }
542 } 506 }
543} 507}
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs
new file mode 100644
index 0000000..7ddc396
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs
@@ -0,0 +1,448 @@
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.Reflection;
31using log4net.Config;
32using Nini.Config;
33using NUnit.Framework;
34using OpenMetaverse;
35using OpenMetaverse.Assets;
36using OpenSim.Framework;
37using OpenSim.Region.CoreModules.Avatar.Inventory.Transfer;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenSim.Tests.Common;
42
43namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests
44{
45 [TestFixture]
46 public class InventoryTransferModuleTests : OpenSimTestCase
47 {
48 protected TestScene m_scene;
49
50 [SetUp]
51 public override void SetUp()
52 {
53 base.SetUp();
54
55 IConfigSource config = new IniConfigSource();
56 config.AddConfig("Messaging");
57 config.Configs["Messaging"].Set("InventoryTransferModule", "InventoryTransferModule");
58
59 m_scene = new SceneHelpers().SetupScene();
60 SceneHelpers.SetupSceneModules(m_scene, config, new InventoryTransferModule());
61 }
62
63 [Test]
64 public void TestAcceptGivenItem()
65 {
66// TestHelpers.EnableLogging();
67
68 UUID initialSessionId = TestHelpers.ParseTail(0x10);
69 UUID itemId = TestHelpers.ParseTail(0x100);
70 UUID assetId = TestHelpers.ParseTail(0x200);
71
72 UserAccount ua1
73 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
74 UserAccount ua2
75 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
76
77 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
78 TestClient giverClient = (TestClient)giverSp.ControllingClient;
79
80 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
81 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
82
83 // Create the object to test give
84 InventoryItemBase originalItem
85 = UserInventoryHelpers.CreateInventoryItem(
86 m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object);
87
88 byte[] giveImBinaryBucket = new byte[17];
89 byte[] itemIdBytes = itemId.GetBytes();
90 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
91
92 GridInstantMessage giveIm
93 = new GridInstantMessage(
94 m_scene,
95 giverSp.UUID,
96 giverSp.Name,
97 receiverSp.UUID,
98 (byte)InstantMessageDialog.InventoryOffered,
99 false,
100 "inventory offered msg",
101 initialSessionId,
102 false,
103 Vector3.Zero,
104 giveImBinaryBucket,
105 true);
106
107 giverClient.HandleImprovedInstantMessage(giveIm);
108
109 // These details might not all be correct.
110 GridInstantMessage acceptIm
111 = new GridInstantMessage(
112 m_scene,
113 receiverSp.UUID,
114 receiverSp.Name,
115 giverSp.UUID,
116 (byte)InstantMessageDialog.InventoryAccepted,
117 false,
118 "inventory accepted msg",
119 initialSessionId,
120 false,
121 Vector3.Zero,
122 null,
123 true);
124
125 receiverClient.HandleImprovedInstantMessage(acceptIm);
126
127 // Test for item remaining in the giver's inventory (here we assume a copy item)
128 // TODO: Test no-copy items.
129 InventoryItemBase originalItemAfterGive
130 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
131
132 Assert.That(originalItemAfterGive, Is.Not.Null);
133 Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID));
134
135 // Test for item successfully making it into the receiver's inventory
136 InventoryItemBase receivedItem
137 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Objects/givenObj");
138
139 Assert.That(receivedItem, Is.Not.Null);
140 Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID));
141
142 // Test that on a delete, item still exists and is accessible for the giver.
143 m_scene.InventoryService.DeleteItems(receiverSp.UUID, new List<UUID>() { receivedItem.ID });
144
145 InventoryItemBase originalItemAfterDelete
146 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
147
148 Assert.That(originalItemAfterDelete, Is.Not.Null);
149
150 // TODO: Test scenario where giver deletes their item first.
151 }
152
153 /// <summary>
154 /// Test user rejection of a given item.
155 /// </summary>
156 /// <remarks>
157 /// A rejected item still ends up in the user's trash folder.
158 /// </remarks>
159 [Test]
160 public void TestRejectGivenItem()
161 {
162// TestHelpers.EnableLogging();
163
164 UUID initialSessionId = TestHelpers.ParseTail(0x10);
165 UUID itemId = TestHelpers.ParseTail(0x100);
166 UUID assetId = TestHelpers.ParseTail(0x200);
167
168 UserAccount ua1
169 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
170 UserAccount ua2
171 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
172
173 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
174 TestClient giverClient = (TestClient)giverSp.ControllingClient;
175
176 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
177 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
178
179 // Create the object to test give
180 InventoryItemBase originalItem
181 = UserInventoryHelpers.CreateInventoryItem(
182 m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object);
183
184 GridInstantMessage receivedIm = null;
185 receiverClient.OnReceivedInstantMessage += im => receivedIm = im;
186
187 byte[] giveImBinaryBucket = new byte[17];
188 byte[] itemIdBytes = itemId.GetBytes();
189 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
190
191 GridInstantMessage giveIm
192 = new GridInstantMessage(
193 m_scene,
194 giverSp.UUID,
195 giverSp.Name,
196 receiverSp.UUID,
197 (byte)InstantMessageDialog.InventoryOffered,
198 false,
199 "inventory offered msg",
200 initialSessionId,
201 false,
202 Vector3.Zero,
203 giveImBinaryBucket,
204 true);
205
206 giverClient.HandleImprovedInstantMessage(giveIm);
207
208 // These details might not all be correct.
209 // Session ID is now the created item ID (!)
210 GridInstantMessage rejectIm
211 = new GridInstantMessage(
212 m_scene,
213 receiverSp.UUID,
214 receiverSp.Name,
215 giverSp.UUID,
216 (byte)InstantMessageDialog.InventoryDeclined,
217 false,
218 "inventory declined msg",
219 new UUID(receivedIm.imSessionID),
220 false,
221 Vector3.Zero,
222 null,
223 true);
224
225 receiverClient.HandleImprovedInstantMessage(rejectIm);
226
227 // Test for item remaining in the giver's inventory (here we assume a copy item)
228 // TODO: Test no-copy items.
229 InventoryItemBase originalItemAfterGive
230 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
231
232 Assert.That(originalItemAfterGive, Is.Not.Null);
233 Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID));
234
235 // Test for item successfully making it into the receiver's inventory
236 InventoryItemBase receivedItem
237 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Trash/givenObj");
238
239 InventoryFolderBase trashFolder
240 = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, FolderType.Trash);
241
242 Assert.That(receivedItem, Is.Not.Null);
243 Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID));
244 Assert.That(receivedItem.Folder, Is.EqualTo(trashFolder.ID));
245
246 // Test that on a delete, item still exists and is accessible for the giver.
247 m_scene.InventoryService.PurgeFolder(trashFolder);
248
249 InventoryItemBase originalItemAfterDelete
250 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
251
252 Assert.That(originalItemAfterDelete, Is.Not.Null);
253 }
254
255 [Test]
256 public void TestAcceptGivenFolder()
257 {
258 TestHelpers.InMethod();
259// TestHelpers.EnableLogging();
260
261 UUID initialSessionId = TestHelpers.ParseTail(0x10);
262 UUID folderId = TestHelpers.ParseTail(0x100);
263
264 UserAccount ua1
265 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
266 UserAccount ua2
267 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
268
269 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
270 TestClient giverClient = (TestClient)giverSp.ControllingClient;
271
272 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
273 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
274
275 InventoryFolderBase originalFolder
276 = UserInventoryHelpers.CreateInventoryFolder(
277 m_scene.InventoryService, giverSp.UUID, folderId, "f1", true);
278
279 byte[] giveImBinaryBucket = new byte[17];
280 giveImBinaryBucket[0] = (byte)AssetType.Folder;
281 byte[] itemIdBytes = folderId.GetBytes();
282 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
283
284 GridInstantMessage giveIm
285 = new GridInstantMessage(
286 m_scene,
287 giverSp.UUID,
288 giverSp.Name,
289 receiverSp.UUID,
290 (byte)InstantMessageDialog.InventoryOffered,
291 false,
292 "inventory offered msg",
293 initialSessionId,
294 false,
295 Vector3.Zero,
296 giveImBinaryBucket,
297 true);
298
299 giverClient.HandleImprovedInstantMessage(giveIm);
300
301 // These details might not all be correct.
302 GridInstantMessage acceptIm
303 = new GridInstantMessage(
304 m_scene,
305 receiverSp.UUID,
306 receiverSp.Name,
307 giverSp.UUID,
308 (byte)InstantMessageDialog.InventoryAccepted,
309 false,
310 "inventory accepted msg",
311 initialSessionId,
312 false,
313 Vector3.Zero,
314 null,
315 true);
316
317 receiverClient.HandleImprovedInstantMessage(acceptIm);
318
319 // Test for item remaining in the giver's inventory (here we assume a copy item)
320 // TODO: Test no-copy items.
321 InventoryFolderBase originalFolderAfterGive
322 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
323
324 Assert.That(originalFolderAfterGive, Is.Not.Null);
325 Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID));
326
327 // Test for item successfully making it into the receiver's inventory
328 InventoryFolderBase receivedFolder
329 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "f1");
330
331 Assert.That(receivedFolder, Is.Not.Null);
332 Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID));
333
334 // Test that on a delete, item still exists and is accessible for the giver.
335 m_scene.InventoryService.DeleteFolders(receiverSp.UUID, new List<UUID>() { receivedFolder.ID });
336
337 InventoryFolderBase originalFolderAfterDelete
338 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
339
340 Assert.That(originalFolderAfterDelete, Is.Not.Null);
341
342 // TODO: Test scenario where giver deletes their item first.
343 }
344
345 /// <summary>
346 /// Test user rejection of a given item.
347 /// </summary>
348 /// <remarks>
349 /// A rejected item still ends up in the user's trash folder.
350 /// </remarks>
351 [Test]
352 public void TestRejectGivenFolder()
353 {
354 TestHelpers.InMethod();
355// TestHelpers.EnableLogging();
356
357 UUID initialSessionId = TestHelpers.ParseTail(0x10);
358 UUID folderId = TestHelpers.ParseTail(0x100);
359
360 UserAccount ua1
361 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
362 UserAccount ua2
363 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
364
365 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
366 TestClient giverClient = (TestClient)giverSp.ControllingClient;
367
368 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
369 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
370
371 // Create the folder to test give
372 InventoryFolderBase originalFolder
373 = UserInventoryHelpers.CreateInventoryFolder(
374 m_scene.InventoryService, giverSp.UUID, folderId, "f1", true);
375
376 GridInstantMessage receivedIm = null;
377 receiverClient.OnReceivedInstantMessage += im => receivedIm = im;
378
379 byte[] giveImBinaryBucket = new byte[17];
380 giveImBinaryBucket[0] = (byte)AssetType.Folder;
381 byte[] itemIdBytes = folderId.GetBytes();
382 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
383
384 GridInstantMessage giveIm
385 = new GridInstantMessage(
386 m_scene,
387 giverSp.UUID,
388 giverSp.Name,
389 receiverSp.UUID,
390 (byte)InstantMessageDialog.InventoryOffered,
391 false,
392 "inventory offered msg",
393 initialSessionId,
394 false,
395 Vector3.Zero,
396 giveImBinaryBucket,
397 true);
398
399 giverClient.HandleImprovedInstantMessage(giveIm);
400
401 // These details might not all be correct.
402 // Session ID is now the created item ID (!)
403 GridInstantMessage rejectIm
404 = new GridInstantMessage(
405 m_scene,
406 receiverSp.UUID,
407 receiverSp.Name,
408 giverSp.UUID,
409 (byte)InstantMessageDialog.InventoryDeclined,
410 false,
411 "inventory declined msg",
412 new UUID(receivedIm.imSessionID),
413 false,
414 Vector3.Zero,
415 null,
416 true);
417
418 receiverClient.HandleImprovedInstantMessage(rejectIm);
419
420 // Test for item remaining in the giver's inventory (here we assume a copy item)
421 // TODO: Test no-copy items.
422 InventoryFolderBase originalFolderAfterGive
423 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
424
425 Assert.That(originalFolderAfterGive, Is.Not.Null);
426 Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID));
427
428 // Test for folder successfully making it into the receiver's inventory
429 InventoryFolderBase receivedFolder
430 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "Trash/f1");
431
432 InventoryFolderBase trashFolder
433 = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, FolderType.Trash);
434
435 Assert.That(receivedFolder, Is.Not.Null);
436 Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID));
437 Assert.That(receivedFolder.ParentID, Is.EqualTo(trashFolder.ID));
438
439 // Test that on a delete, item still exists and is accessible for the giver.
440 m_scene.InventoryService.PurgeFolder(trashFolder);
441
442 InventoryFolderBase originalFolderAfterDelete
443 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
444
445 Assert.That(originalFolderAfterDelete, Is.Not.Null);
446 }
447 }
448} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs
index 232a4fe..24286a4 100644
--- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs
@@ -65,7 +65,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
65 { 65 {
66 m_Enabled = true; 66 m_Enabled = true;
67 67
68 m_ThisGridURL = config.Configs["Messaging"].GetString("Gatekeeper", string.Empty); 68 m_ThisGridURL = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
69 new string[] { "Startup", "Hypergrid", "Messaging" }, String.Empty);
70 // Legacy. Remove soon!
71 m_ThisGridURL = config.Configs["Messaging"].GetString("Gatekeeper", m_ThisGridURL);
69 m_log.DebugFormat("[LURE MODULE]: {0} enabled", Name); 72 m_log.DebugFormat("[LURE MODULE]: {0} enabled", Name);
70 } 73 }
71 } 74 }
@@ -151,7 +154,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
151 154
152 void OnIncomingInstantMessage(GridInstantMessage im) 155 void OnIncomingInstantMessage(GridInstantMessage im)
153 { 156 {
154 if (im.dialog == (byte)InstantMessageDialog.RequestTeleport) 157 if (im.dialog == (byte)InstantMessageDialog.RequestTeleport
158 || im.dialog == (byte)InstantMessageDialog.GodLikeRequestTeleport)
155 { 159 {
156 UUID sessionID = new UUID(im.imSessionID); 160 UUID sessionID = new UUID(im.imSessionID);
157 161
@@ -235,16 +239,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
235 GatekeeperServiceConnector gConn = new GatekeeperServiceConnector(); 239 GatekeeperServiceConnector gConn = new GatekeeperServiceConnector();
236 GridRegion gatekeeper = new GridRegion(); 240 GridRegion gatekeeper = new GridRegion();
237 gatekeeper.ServerURI = url; 241 gatekeeper.ServerURI = url;
238 GridRegion finalDestination = gConn.GetHyperlinkRegion(gatekeeper, new UUID(im.RegionID)); 242 string homeURI = scene.GetAgentHomeURI(client.AgentId);
243
244 string message;
245 GridRegion finalDestination = gConn.GetHyperlinkRegion(gatekeeper, new UUID(im.RegionID), client.AgentId, homeURI, out message);
239 if (finalDestination != null) 246 if (finalDestination != null)
240 { 247 {
241 ScenePresence sp = scene.GetScenePresence(client.AgentId); 248 ScenePresence sp = scene.GetScenePresence(client.AgentId);
242 IEntityTransferModule transferMod = scene.RequestModuleInterface<IEntityTransferModule>(); 249 IEntityTransferModule transferMod = scene.RequestModuleInterface<IEntityTransferModule>();
243 250
244 if (transferMod != null && sp != null) 251 if (transferMod != null && sp != null)
252 {
253 if (message != null)
254 sp.ControllingClient.SendAgentAlertMessage(message, true);
255
245 transferMod.DoTeleport( 256 transferMod.DoTeleport(
246 sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 0f), 257 sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 0f),
247 Vector3.UnitX, teleportflags); 258 Vector3.UnitX, teleportflags);
259 }
260 }
261 else
262 {
263 m_log.InfoFormat("[HG LURE MODULE]: Lure failed: {0}", message);
264 client.SendAgentAlertMessage(message, true);
248 } 265 }
249 } 266 }
250 } 267 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
index e4b0cfa..465ffbc 100644
--- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
@@ -165,7 +165,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
165 (uint)presence.AbsolutePosition.Y, 165 (uint)presence.AbsolutePosition.Y,
166 (uint)Math.Ceiling(presence.AbsolutePosition.Z)); 166 (uint)Math.Ceiling(presence.AbsolutePosition.Z));
167 167
168 m_log.DebugFormat("TP invite with message {0}", message); 168 m_log.DebugFormat("[LURE MODULE]: TP invite with message {0}, type {1}", message, lureType);
169 169
170 GridInstantMessage m = new GridInstantMessage(scene, client.AgentId, 170 GridInstantMessage m = new GridInstantMessage(scene, client.AgentId,
171 client.FirstName+" "+client.LastName, targetid, 171 client.FirstName+" "+client.LastName, targetid,
diff --git a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs
index bf24030..2bb24ae 100644
--- a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs
@@ -57,6 +57,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Profile
57 57
58 public void Initialise(IConfigSource config) 58 public void Initialise(IConfigSource config)
59 { 59 {
60 if(config.Configs["UserProfiles"] != null)
61 return;
62
60 m_log.DebugFormat("[PROFILE MODULE]: Basic Profile Module enabled"); 63 m_log.DebugFormat("[PROFILE MODULE]: Basic Profile Module enabled");
61 m_Enabled = true; 64 m_Enabled = true;
62 } 65 }
diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs
new file mode 100644
index 0000000..c20369c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs
@@ -0,0 +1,1406 @@
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.IO;
30using System.Text;
31using System.Collections;
32using System.Collections.Generic;
33using System.Globalization;
34using System.Net;
35using System.Net.Sockets;
36using System.Reflection;
37using System.Xml;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using log4net;
41using Nini.Config;
42using Nwc.XmlRpc;
43using OpenSim.Framework;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Services.Interfaces;
47using Mono.Addins;
48using OpenSim.Services.Connectors.Hypergrid;
49using OpenSim.Framework.Servers.HttpServer;
50using OpenSim.Services.UserProfilesService;
51using GridRegion = OpenSim.Services.Interfaces.GridRegion;
52using Microsoft.CSharp;
53
54namespace OpenSim.Region.CoreModules.Avatar.UserProfiles
55{
56 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserProfilesModule")]
57 public class UserProfileModule : IProfileModule, INonSharedRegionModule
58 {
59 /// <summary>
60 /// Logging
61 /// </summary>
62 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
63
64 // The pair of Dictionaries are used to handle the switching of classified ads
65 // by maintaining a cache of classified id to creator id mappings and an interest
66 // count. The entries are removed when the interest count reaches 0.
67 Dictionary<UUID, UUID> m_classifiedCache = new Dictionary<UUID, UUID>();
68 Dictionary<UUID, int> m_classifiedInterest = new Dictionary<UUID, int>();
69
70 private JsonRpcRequestManager rpc = new JsonRpcRequestManager();
71
72 public Scene Scene
73 {
74 get; private set;
75 }
76
77 /// <summary>
78 /// Gets or sets the ConfigSource.
79 /// </summary>
80 /// <value>
81 /// The configuration
82 /// </value>
83 public IConfigSource Config
84 {
85 get;
86 set;
87 }
88
89 /// <summary>
90 /// Gets or sets the URI to the profile server.
91 /// </summary>
92 /// <value>
93 /// The profile server URI.
94 /// </value>
95 public string ProfileServerUri
96 {
97 get;
98 set;
99 }
100
101 IProfileModule ProfileModule
102 {
103 get; set;
104 }
105
106 IUserManagement UserManagementModule
107 {
108 get; set;
109 }
110
111 /// <summary>
112 /// Gets or sets a value indicating whether this
113 /// <see cref="OpenSim.Region.Coremodules.UserProfiles.UserProfileModule"/> is enabled.
114 /// </summary>
115 /// <value>
116 /// <c>true</c> if enabled; otherwise, <c>false</c>.
117 /// </value>
118 public bool Enabled
119 {
120 get;
121 set;
122 }
123
124 public string MyGatekeeper
125 {
126 get; private set;
127 }
128
129
130 #region IRegionModuleBase implementation
131 /// <summary>
132 /// This is called to initialize the region module. For shared modules, this is called exactly once, after
133 /// creating the single (shared) instance. For non-shared modules, this is called once on each instance, after
134 /// the instace for the region has been created.
135 /// </summary>
136 /// <param name='source'>
137 /// Source.
138 /// </param>
139 public void Initialise(IConfigSource source)
140 {
141 Config = source;
142 ReplaceableInterface = typeof(IProfileModule);
143
144 IConfig profileConfig = Config.Configs["UserProfiles"];
145
146 if (profileConfig == null)
147 {
148 m_log.Debug("[PROFILES]: UserProfiles disabled, no configuration");
149 Enabled = false;
150 return;
151 }
152
153 // If we find ProfileURL then we configure for FULL support
154 // else we setup for BASIC support
155 ProfileServerUri = profileConfig.GetString("ProfileServiceURL", "");
156 if (ProfileServerUri == "")
157 {
158 Enabled = false;
159 return;
160 }
161
162 m_log.Debug("[PROFILES]: Full Profiles Enabled");
163 ReplaceableInterface = null;
164 Enabled = true;
165
166 MyGatekeeper = Util.GetConfigVarFromSections<string>(source, "GatekeeperURI",
167 new string[] { "Startup", "Hypergrid", "UserProfiles" }, String.Empty);
168 }
169
170 /// <summary>
171 /// Adds the region.
172 /// </summary>
173 /// <param name='scene'>
174 /// Scene.
175 /// </param>
176 public void AddRegion(Scene scene)
177 {
178 if(!Enabled)
179 return;
180
181 Scene = scene;
182 Scene.RegisterModuleInterface<IProfileModule>(this);
183 Scene.EventManager.OnNewClient += OnNewClient;
184 Scene.EventManager.OnMakeRootAgent += HandleOnMakeRootAgent;
185
186 UserManagementModule = Scene.RequestModuleInterface<IUserManagement>();
187 }
188
189 void HandleOnMakeRootAgent (ScenePresence obj)
190 {
191 if(obj.PresenceType == PresenceType.Npc)
192 return;
193
194 Util.FireAndForget(delegate
195 {
196 GetImageAssets(((IScenePresence)obj).UUID);
197 }, null, "UserProfileModule.GetImageAssets");
198 }
199
200 /// <summary>
201 /// Removes the region.
202 /// </summary>
203 /// <param name='scene'>
204 /// Scene.
205 /// </param>
206 public void RemoveRegion(Scene scene)
207 {
208 if(!Enabled)
209 return;
210 }
211
212 /// <summary>
213 /// This will be called once for every scene loaded. In a shared module this will be multiple times in one
214 /// instance, while a nonshared module instance will only be called once. This method is called after AddRegion
215 /// has been called in all modules for that scene, providing an opportunity to request another module's
216 /// interface, or hook an event from another module.
217 /// </summary>
218 /// <param name='scene'>
219 /// Scene.
220 /// </param>
221 public void RegionLoaded(Scene scene)
222 {
223 if(!Enabled)
224 return;
225 }
226
227 /// <summary>
228 /// If this returns non-null, it is the type of an interface that this module intends to register. This will
229 /// cause the loader to defer loading of this module until all other modules have been loaded. If no other
230 /// module has registered the interface by then, this module will be activated, else it will remain inactive,
231 /// letting the other module take over. This should return non-null ONLY in modules that are intended to be
232 /// easily replaceable, e.g. stub implementations that the developer expects to be replaced by third party
233 /// provided modules.
234 /// </summary>
235 /// <value>
236 /// The replaceable interface.
237 /// </value>
238 public Type ReplaceableInterface
239 {
240 get; private set;
241 }
242
243 /// <summary>
244 /// Called as the instance is closed.
245 /// </summary>
246 public void Close()
247 {
248 }
249
250 /// <value>
251 /// The name of the module
252 /// </value>
253 /// <summary>
254 /// Gets the module name.
255 /// </summary>
256 public string Name
257 {
258 get { return "UserProfileModule"; }
259 }
260 #endregion IRegionModuleBase implementation
261
262 #region Region Event Handlers
263 /// <summary>
264 /// Raises the new client event.
265 /// </summary>
266 /// <param name='client'>
267 /// Client.
268 /// </param>
269 void OnNewClient(IClientAPI client)
270 {
271 //Profile
272 client.OnRequestAvatarProperties += RequestAvatarProperties;
273 client.OnUpdateAvatarProperties += AvatarPropertiesUpdate;
274 client.OnAvatarInterestUpdate += AvatarInterestsUpdate;
275
276 // Classifieds
277 client.AddGenericPacketHandler("avatarclassifiedsrequest", ClassifiedsRequest);
278 client.OnClassifiedInfoUpdate += ClassifiedInfoUpdate;
279 client.OnClassifiedInfoRequest += ClassifiedInfoRequest;
280 client.OnClassifiedDelete += ClassifiedDelete;
281
282 // Picks
283 client.AddGenericPacketHandler("avatarpicksrequest", PicksRequest);
284 client.AddGenericPacketHandler("pickinforequest", PickInfoRequest);
285 client.OnPickInfoUpdate += PickInfoUpdate;
286 client.OnPickDelete += PickDelete;
287
288 // Notes
289 client.AddGenericPacketHandler("avatarnotesrequest", NotesRequest);
290 client.OnAvatarNotesUpdate += NotesUpdate;
291
292 // Preferences
293 client.OnUserInfoRequest += UserPreferencesRequest;
294 client.OnUpdateUserInfo += UpdateUserPreferences;
295 }
296 #endregion Region Event Handlers
297
298 #region Classified
299 ///
300 /// <summary>
301 /// Handles the avatar classifieds request.
302 /// </summary>
303 /// <param name='sender'>
304 /// Sender.
305 /// </param>
306 /// <param name='method'>
307 /// Method.
308 /// </param>
309 /// <param name='args'>
310 /// Arguments.
311 /// </param>
312 public void ClassifiedsRequest(Object sender, string method, List<String> args)
313 {
314 if (!(sender is IClientAPI))
315 return;
316
317 IClientAPI remoteClient = (IClientAPI)sender;
318
319 UUID targetID;
320 UUID.TryParse(args[0], out targetID);
321
322 // Can't handle NPC yet...
323 ScenePresence p = FindPresence(targetID);
324
325 if (null != p)
326 {
327 if (p.PresenceType == PresenceType.Npc)
328 return;
329 }
330
331 string serverURI = string.Empty;
332 GetUserProfileServerURI(targetID, out serverURI);
333 UUID creatorId = UUID.Zero;
334 Dictionary<UUID, string> classifieds = new Dictionary<UUID, string>();
335
336 OSDMap parameters= new OSDMap();
337 UUID.TryParse(args[0], out creatorId);
338 parameters.Add("creatorId", OSD.FromUUID(creatorId));
339 OSD Params = (OSD)parameters;
340 if(!rpc.JsonRpcRequest(ref Params, "avatarclassifiedsrequest", serverURI, UUID.Random().ToString()))
341 {
342 remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds);
343 return;
344 }
345
346 parameters = (OSDMap)Params;
347
348 OSDArray list = (OSDArray)parameters["result"];
349
350
351 foreach(OSD map in list)
352 {
353 OSDMap m = (OSDMap)map;
354 UUID cid = m["classifieduuid"].AsUUID();
355 string name = m["name"].AsString();
356
357 classifieds[cid] = name;
358
359 lock (m_classifiedCache)
360 {
361 if (!m_classifiedCache.ContainsKey(cid))
362 {
363 m_classifiedCache.Add(cid,creatorId);
364 m_classifiedInterest.Add(cid, 0);
365 }
366
367 m_classifiedInterest[cid]++;
368 }
369 }
370
371 remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds);
372 }
373
374 public void ClassifiedInfoRequest(UUID queryClassifiedID, IClientAPI remoteClient)
375 {
376 UUID target = remoteClient.AgentId;
377 UserClassifiedAdd ad = new UserClassifiedAdd();
378 ad.ClassifiedId = queryClassifiedID;
379
380 lock (m_classifiedCache)
381 {
382 if (m_classifiedCache.ContainsKey(queryClassifiedID))
383 {
384 target = m_classifiedCache[queryClassifiedID];
385
386 m_classifiedInterest[queryClassifiedID] --;
387
388 if (m_classifiedInterest[queryClassifiedID] == 0)
389 {
390 m_classifiedInterest.Remove(queryClassifiedID);
391 m_classifiedCache.Remove(queryClassifiedID);
392 }
393 }
394 }
395
396 string serverURI = string.Empty;
397 GetUserProfileServerURI(target, out serverURI);
398
399 object Ad = (object)ad;
400 if(!rpc.JsonRpcRequest(ref Ad, "classifieds_info_query", serverURI, UUID.Random().ToString()))
401 {
402 remoteClient.SendAgentAlertMessage(
403 "Error getting classified info", false);
404 return;
405 }
406 ad = (UserClassifiedAdd) Ad;
407
408 if(ad.CreatorId == UUID.Zero)
409 return;
410
411 Vector3 globalPos = new Vector3();
412 Vector3.TryParse(ad.GlobalPos, out globalPos);
413
414 remoteClient.SendClassifiedInfoReply(ad.ClassifiedId, ad.CreatorId, (uint)ad.CreationDate, (uint)ad.ExpirationDate,
415 (uint)ad.Category, ad.Name, ad.Description, ad.ParcelId, (uint)ad.ParentEstate,
416 ad.SnapshotId, ad.SimName, globalPos, ad.ParcelName, ad.Flags, ad.Price);
417
418 }
419
420 /// <summary>
421 /// Classifieds info update.
422 /// </summary>
423 /// <param name='queryclassifiedID'>
424 /// Queryclassified I.
425 /// </param>
426 /// <param name='queryCategory'>
427 /// Query category.
428 /// </param>
429 /// <param name='queryName'>
430 /// Query name.
431 /// </param>
432 /// <param name='queryDescription'>
433 /// Query description.
434 /// </param>
435 /// <param name='queryParcelID'>
436 /// Query parcel I.
437 /// </param>
438 /// <param name='queryParentEstate'>
439 /// Query parent estate.
440 /// </param>
441 /// <param name='querySnapshotID'>
442 /// Query snapshot I.
443 /// </param>
444 /// <param name='queryGlobalPos'>
445 /// Query global position.
446 /// </param>
447 /// <param name='queryclassifiedFlags'>
448 /// Queryclassified flags.
449 /// </param>
450 /// <param name='queryclassifiedPrice'>
451 /// Queryclassified price.
452 /// </param>
453 /// <param name='remoteClient'>
454 /// Remote client.
455 /// </param>
456 public void ClassifiedInfoUpdate(UUID queryclassifiedID, uint queryCategory, string queryName, string queryDescription, UUID queryParcelID,
457 uint queryParentEstate, UUID querySnapshotID, Vector3 queryGlobalPos, byte queryclassifiedFlags,
458 int queryclassifiedPrice, IClientAPI remoteClient)
459 {
460 Scene s = (Scene)remoteClient.Scene;
461 IMoneyModule money = s.RequestModuleInterface<IMoneyModule>();
462
463 if (money != null)
464 {
465 if (!money.AmountCovered(remoteClient.AgentId, queryclassifiedPrice))
466 {
467 remoteClient.SendAgentAlertMessage("You do not have enough money to create requested classified.", false);
468 return;
469 }
470 money.ApplyCharge(remoteClient.AgentId, queryclassifiedPrice, MoneyTransactionType.ClassifiedCharge);
471 }
472
473 UserClassifiedAdd ad = new UserClassifiedAdd();
474
475 Vector3 pos = remoteClient.SceneAgent.AbsolutePosition;
476 ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y);
477 ScenePresence p = FindPresence(remoteClient.AgentId);
478
479 string serverURI = string.Empty;
480 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
481
482 if (land == null)
483 {
484 ad.ParcelName = string.Empty;
485 }
486 else
487 {
488 ad.ParcelName = land.LandData.Name;
489 }
490
491 ad.CreatorId = remoteClient.AgentId;
492 ad.ClassifiedId = queryclassifiedID;
493 ad.Category = Convert.ToInt32(queryCategory);
494 ad.Name = queryName;
495 ad.Description = queryDescription;
496 ad.ParentEstate = Convert.ToInt32(queryParentEstate);
497 ad.SnapshotId = querySnapshotID;
498 ad.SimName = remoteClient.Scene.RegionInfo.RegionName;
499 ad.GlobalPos = queryGlobalPos.ToString ();
500 ad.Flags = queryclassifiedFlags;
501 ad.Price = queryclassifiedPrice;
502 ad.ParcelId = p.currentParcelUUID;
503
504 object Ad = ad;
505
506 OSD.SerializeMembers(Ad);
507
508 if(!rpc.JsonRpcRequest(ref Ad, "classified_update", serverURI, UUID.Random().ToString()))
509 {
510 remoteClient.SendAgentAlertMessage(
511 "Error updating classified", false);
512 return;
513 }
514 }
515
516 /// <summary>
517 /// Classifieds delete.
518 /// </summary>
519 /// <param name='queryClassifiedID'>
520 /// Query classified I.
521 /// </param>
522 /// <param name='remoteClient'>
523 /// Remote client.
524 /// </param>
525 public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient)
526 {
527 string serverURI = string.Empty;
528 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
529
530 UUID classifiedId;
531 OSDMap parameters= new OSDMap();
532 UUID.TryParse(queryClassifiedID.ToString(), out classifiedId);
533 parameters.Add("classifiedId", OSD.FromUUID(classifiedId));
534 OSD Params = (OSD)parameters;
535 if(!rpc.JsonRpcRequest(ref Params, "classified_delete", serverURI, UUID.Random().ToString()))
536 {
537 remoteClient.SendAgentAlertMessage(
538 "Error classified delete", false);
539 return;
540 }
541
542 parameters = (OSDMap)Params;
543 }
544 #endregion Classified
545
546 #region Picks
547 /// <summary>
548 /// Handles the avatar picks request.
549 /// </summary>
550 /// <param name='sender'>
551 /// Sender.
552 /// </param>
553 /// <param name='method'>
554 /// Method.
555 /// </param>
556 /// <param name='args'>
557 /// Arguments.
558 /// </param>
559 public void PicksRequest(Object sender, string method, List<String> args)
560 {
561 if (!(sender is IClientAPI))
562 return;
563
564 IClientAPI remoteClient = (IClientAPI)sender;
565
566 UUID targetId;
567 UUID.TryParse(args[0], out targetId);
568
569 // Can't handle NPC yet...
570 ScenePresence p = FindPresence(targetId);
571
572 if (null != p)
573 {
574 if (p.PresenceType == PresenceType.Npc)
575 return;
576 }
577
578 string serverURI = string.Empty;
579 GetUserProfileServerURI(targetId, out serverURI);
580
581 Dictionary<UUID, string> picks = new Dictionary<UUID, string>();
582
583 OSDMap parameters= new OSDMap();
584 parameters.Add("creatorId", OSD.FromUUID(targetId));
585 OSD Params = (OSD)parameters;
586 if(!rpc.JsonRpcRequest(ref Params, "avatarpicksrequest", serverURI, UUID.Random().ToString()))
587 {
588 remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks);
589 return;
590 }
591
592 parameters = (OSDMap)Params;
593
594 OSDArray list = (OSDArray)parameters["result"];
595
596 foreach(OSD map in list)
597 {
598 OSDMap m = (OSDMap)map;
599 UUID cid = m["pickuuid"].AsUUID();
600 string name = m["name"].AsString();
601
602 m_log.DebugFormat("[PROFILES]: PicksRequest {0}", name);
603
604 picks[cid] = name;
605 }
606 remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks);
607 }
608
609 /// <summary>
610 /// Handles the pick info request.
611 /// </summary>
612 /// <param name='sender'>
613 /// Sender.
614 /// </param>
615 /// <param name='method'>
616 /// Method.
617 /// </param>
618 /// <param name='args'>
619 /// Arguments.
620 /// </param>
621 public void PickInfoRequest(Object sender, string method, List<String> args)
622 {
623 if (!(sender is IClientAPI))
624 return;
625
626 UUID targetID;
627 UUID.TryParse (args [0], out targetID);
628 string serverURI = string.Empty;
629 GetUserProfileServerURI (targetID, out serverURI);
630
631 string theirGatekeeperURI;
632 GetUserGatekeeperURI (targetID, out theirGatekeeperURI);
633
634 IClientAPI remoteClient = (IClientAPI)sender;
635
636 UserProfilePick pick = new UserProfilePick ();
637 UUID.TryParse (args [0], out pick.CreatorId);
638 UUID.TryParse (args [1], out pick.PickId);
639
640
641 object Pick = (object)pick;
642 if (!rpc.JsonRpcRequest (ref Pick, "pickinforequest", serverURI, UUID.Random ().ToString ())) {
643 remoteClient.SendAgentAlertMessage (
644 "Error selecting pick", false);
645 return;
646 }
647 pick = (UserProfilePick)Pick;
648
649 Vector3 globalPos = new Vector3(Vector3.Zero);
650
651 // Smoke and mirrors
652 if (pick.Gatekeeper == MyGatekeeper)
653 {
654 Vector3.TryParse(pick.GlobalPos,out globalPos);
655 }
656 else
657 {
658 // Setup the illusion
659 string region = string.Format("{0} {1}",pick.Gatekeeper,pick.SimName);
660 GridRegion target = Scene.GridService.GetRegionByName(Scene.RegionInfo.ScopeID, region);
661
662 if(target == null)
663 {
664 // This is a dead or unreachable region
665 }
666 else
667 {
668 // Work our slight of hand
669 int x = target.RegionLocX;
670 int y = target.RegionLocY;
671
672 dynamic synthX = globalPos.X - (globalPos.X/Constants.RegionSize) * Constants.RegionSize;
673 synthX += x;
674 globalPos.X = synthX;
675
676 dynamic synthY = globalPos.Y - (globalPos.Y/Constants.RegionSize) * Constants.RegionSize;
677 synthY += y;
678 globalPos.Y = synthY;
679 }
680 }
681
682 m_log.DebugFormat("[PROFILES]: PickInfoRequest: {0} : {1}", pick.Name.ToString(), pick.SnapshotId.ToString());
683
684 // Pull the rabbit out of the hat
685 remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name,
686 pick.Desc,pick.SnapshotId,pick.ParcelName,pick.OriginalName,pick.SimName,
687 globalPos,pick.SortOrder,pick.Enabled);
688 }
689
690 /// <summary>
691 /// Updates the userpicks
692 /// </summary>
693 /// <param name='remoteClient'>
694 /// Remote client.
695 /// </param>
696 /// <param name='pickID'>
697 /// Pick I.
698 /// </param>
699 /// <param name='creatorID'>
700 /// the creator of the pick
701 /// </param>
702 /// <param name='topPick'>
703 /// Top pick.
704 /// </param>
705 /// <param name='name'>
706 /// Name.
707 /// </param>
708 /// <param name='desc'>
709 /// Desc.
710 /// </param>
711 /// <param name='snapshotID'>
712 /// Snapshot I.
713 /// </param>
714 /// <param name='sortOrder'>
715 /// Sort order.
716 /// </param>
717 /// <param name='enabled'>
718 /// Enabled.
719 /// </param>
720 public void PickInfoUpdate(IClientAPI remoteClient, UUID pickID, UUID creatorID, bool topPick, string name, string desc, UUID snapshotID, int sortOrder, bool enabled)
721 {
722 //TODO: See how this works with NPC, May need to test
723 m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString());
724
725 UserProfilePick pick = new UserProfilePick();
726 string serverURI = string.Empty;
727 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
728 ScenePresence p = FindPresence(remoteClient.AgentId);
729
730 Vector3 avaPos = p.AbsolutePosition;
731 // Getting the global position for the Avatar
732 Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.WorldLocX + avaPos.X,
733 remoteClient.Scene.RegionInfo.WorldLocY + avaPos.Y,
734 avaPos.Z);
735
736 string landParcelName = "My Parcel";
737 UUID landParcelID = p.currentParcelUUID;
738
739 ILandObject land = p.Scene.LandChannel.GetLandObject(avaPos.X, avaPos.Y);
740
741 if (land != null)
742 {
743 // If land found, use parcel uuid from here because the value from SP will be blank if the avatar hasnt moved
744 landParcelName = land.LandData.Name;
745 landParcelID = land.LandData.GlobalID;
746 }
747 else
748 {
749 m_log.WarnFormat(
750 "[PROFILES]: PickInfoUpdate found no parcel info at {0},{1} in {2}",
751 avaPos.X, avaPos.Y, p.Scene.Name);
752 }
753
754
755 pick.PickId = pickID;
756 pick.CreatorId = creatorID;
757 pick.TopPick = topPick;
758 pick.Name = name;
759 pick.Desc = desc;
760 pick.ParcelId = landParcelID;
761 pick.SnapshotId = snapshotID;
762 pick.ParcelName = landParcelName;
763 pick.SimName = remoteClient.Scene.RegionInfo.RegionName;
764 pick.Gatekeeper = MyGatekeeper;
765 pick.GlobalPos = posGlobal.ToString();
766 pick.SortOrder = sortOrder;
767 pick.Enabled = enabled;
768
769 object Pick = (object)pick;
770 if(!rpc.JsonRpcRequest(ref Pick, "picks_update", serverURI, UUID.Random().ToString()))
771 {
772 remoteClient.SendAgentAlertMessage(
773 "Error updating pick", false);
774 return;
775 }
776
777 m_log.DebugFormat("[PROFILES]: Finish PickInfoUpdate {0} {1}", pick.Name, pick.PickId.ToString());
778 }
779
780 /// <summary>
781 /// Delete a Pick
782 /// </summary>
783 /// <param name='remoteClient'>
784 /// Remote client.
785 /// </param>
786 /// <param name='queryPickID'>
787 /// Query pick I.
788 /// </param>
789 public void PickDelete(IClientAPI remoteClient, UUID queryPickID)
790 {
791 string serverURI = string.Empty;
792 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
793
794 OSDMap parameters= new OSDMap();
795 parameters.Add("pickId", OSD.FromUUID(queryPickID));
796 OSD Params = (OSD)parameters;
797 if(!rpc.JsonRpcRequest(ref Params, "picks_delete", serverURI, UUID.Random().ToString()))
798 {
799 remoteClient.SendAgentAlertMessage(
800 "Error picks delete", false);
801 return;
802 }
803 }
804 #endregion Picks
805
806 #region Notes
807 /// <summary>
808 /// Handles the avatar notes request.
809 /// </summary>
810 /// <param name='sender'>
811 /// Sender.
812 /// </param>
813 /// <param name='method'>
814 /// Method.
815 /// </param>
816 /// <param name='args'>
817 /// Arguments.
818 /// </param>
819 public void NotesRequest(Object sender, string method, List<String> args)
820 {
821 UserProfileNotes note = new UserProfileNotes();
822
823 if (!(sender is IClientAPI))
824 return;
825
826 IClientAPI remoteClient = (IClientAPI)sender;
827 string serverURI = string.Empty;
828 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
829 note.UserId = remoteClient.AgentId;
830 UUID.TryParse(args[0], out note.TargetId);
831
832 object Note = (object)note;
833 if(!rpc.JsonRpcRequest(ref Note, "avatarnotesrequest", serverURI, UUID.Random().ToString()))
834 {
835 remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes);
836 return;
837 }
838 note = (UserProfileNotes) Note;
839
840 remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes);
841 }
842
843 /// <summary>
844 /// Avatars the notes update.
845 /// </summary>
846 /// <param name='remoteClient'>
847 /// Remote client.
848 /// </param>
849 /// <param name='queryTargetID'>
850 /// Query target I.
851 /// </param>
852 /// <param name='queryNotes'>
853 /// Query notes.
854 /// </param>
855 public void NotesUpdate(IClientAPI remoteClient, UUID queryTargetID, string queryNotes)
856 {
857 UserProfileNotes note = new UserProfileNotes();
858
859 note.UserId = remoteClient.AgentId;
860 note.TargetId = queryTargetID;
861 note.Notes = queryNotes;
862
863 string serverURI = string.Empty;
864 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
865
866 object Note = note;
867 if(!rpc.JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString()))
868 {
869 remoteClient.SendAgentAlertMessage(
870 "Error updating note", false);
871 return;
872 }
873 }
874 #endregion Notes
875
876 #region User Preferences
877 /// <summary>
878 /// Updates the user preferences.
879 /// </summary>
880 /// <param name='imViaEmail'>
881 /// Im via email.
882 /// </param>
883 /// <param name='visible'>
884 /// Visible.
885 /// </param>
886 /// <param name='remoteClient'>
887 /// Remote client.
888 /// </param>
889 public void UpdateUserPreferences(bool imViaEmail, bool visible, IClientAPI remoteClient)
890 {
891 UserPreferences pref = new UserPreferences();
892
893 pref.UserId = remoteClient.AgentId;
894 pref.IMViaEmail = imViaEmail;
895 pref.Visible = visible;
896
897 string serverURI = string.Empty;
898 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
899
900 object Pref = pref;
901 if(!rpc.JsonRpcRequest(ref Pref, "user_preferences_update", serverURI, UUID.Random().ToString()))
902 {
903 m_log.InfoFormat("[PROFILES]: UserPreferences update error");
904 remoteClient.SendAgentAlertMessage("Error updating preferences", false);
905 return;
906 }
907 }
908
909 /// <summary>
910 /// Users the preferences request.
911 /// </summary>
912 /// <param name='remoteClient'>
913 /// Remote client.
914 /// </param>
915 public void UserPreferencesRequest(IClientAPI remoteClient)
916 {
917 UserPreferences pref = new UserPreferences();
918
919 pref.UserId = remoteClient.AgentId;
920
921 string serverURI = string.Empty;
922 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
923
924
925 object Pref = (object)pref;
926 if(!rpc.JsonRpcRequest(ref Pref, "user_preferences_request", serverURI, UUID.Random().ToString()))
927 {
928// m_log.InfoFormat("[PROFILES]: UserPreferences request error");
929// remoteClient.SendAgentAlertMessage("Error requesting preferences", false);
930 return;
931 }
932 pref = (UserPreferences) Pref;
933
934 remoteClient.SendUserInfoReply(pref.IMViaEmail, pref.Visible, pref.EMail);
935
936 }
937 #endregion User Preferences
938
939 #region Avatar Properties
940 /// <summary>
941 /// Update the avatars interests .
942 /// </summary>
943 /// <param name='remoteClient'>
944 /// Remote client.
945 /// </param>
946 /// <param name='wantmask'>
947 /// Wantmask.
948 /// </param>
949 /// <param name='wanttext'>
950 /// Wanttext.
951 /// </param>
952 /// <param name='skillsmask'>
953 /// Skillsmask.
954 /// </param>
955 /// <param name='skillstext'>
956 /// Skillstext.
957 /// </param>
958 /// <param name='languages'>
959 /// Languages.
960 /// </param>
961 public void AvatarInterestsUpdate(IClientAPI remoteClient, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages)
962 {
963 UserProfileProperties prop = new UserProfileProperties();
964
965 prop.UserId = remoteClient.AgentId;
966 prop.WantToMask = (int)wantmask;
967 prop.WantToText = wanttext;
968 prop.SkillsMask = (int)skillsmask;
969 prop.SkillsText = skillstext;
970 prop.Language = languages;
971
972 string serverURI = string.Empty;
973 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
974
975 object Param = prop;
976 if(!rpc.JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString()))
977 {
978 remoteClient.SendAgentAlertMessage(
979 "Error updating interests", false);
980 return;
981 }
982 }
983
984 public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID)
985 {
986 if (String.IsNullOrEmpty(avatarID.ToString()) || String.IsNullOrEmpty(remoteClient.AgentId.ToString()))
987 {
988 // Looking for a reason that some viewers are sending null Id's
989 m_log.DebugFormat("[PROFILES]: This should not happen remoteClient.AgentId {0} - avatarID {1}", remoteClient.AgentId, avatarID);
990 return;
991 }
992
993 // Can't handle NPC yet...
994 ScenePresence p = FindPresence(avatarID);
995
996 if (null != p)
997 {
998 if (p.PresenceType == PresenceType.Npc)
999 return;
1000 }
1001
1002 string serverURI = string.Empty;
1003 bool foreign = GetUserProfileServerURI(avatarID, out serverURI);
1004
1005 UserAccount account = null;
1006 Dictionary<string,object> userInfo;
1007
1008 if (!foreign)
1009 {
1010 account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, avatarID);
1011 }
1012 else
1013 {
1014 userInfo = new Dictionary<string, object>();
1015 }
1016
1017 Byte[] charterMember = new Byte[1];
1018 string born = String.Empty;
1019 uint flags = 0x00;
1020
1021 if (null != account)
1022 {
1023 if (account.UserTitle == "")
1024 {
1025 charterMember[0] = (Byte)((account.UserFlags & 0xf00) >> 8);
1026 }
1027 else
1028 {
1029 charterMember = Utils.StringToBytes(account.UserTitle);
1030 }
1031
1032 born = Util.ToDateTime(account.Created).ToString(
1033 "M/d/yyyy", CultureInfo.InvariantCulture);
1034 flags = (uint)(account.UserFlags & 0xff);
1035 }
1036 else
1037 {
1038 if (GetUserAccountData(avatarID, out userInfo) == true)
1039 {
1040 if ((string)userInfo["user_title"] == "")
1041 {
1042 charterMember[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8);
1043 }
1044 else
1045 {
1046 charterMember = Utils.StringToBytes((string)userInfo["user_title"]);
1047 }
1048
1049 int val_born = (int)userInfo["user_created"];
1050 born = Util.ToDateTime(val_born).ToString(
1051 "M/d/yyyy", CultureInfo.InvariantCulture);
1052
1053 // picky, picky
1054 int val_flags = (int)userInfo["user_flags"];
1055 flags = (uint)(val_flags & 0xff);
1056 }
1057 }
1058
1059 UserProfileProperties props = new UserProfileProperties();
1060 string result = string.Empty;
1061
1062 props.UserId = avatarID;
1063
1064 if (!GetProfileData(ref props, foreign, out result))
1065 {
1066// m_log.DebugFormat("Error getting profile for {0}: {1}", avatarID, result);
1067 return;
1068 }
1069
1070 remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, charterMember , props.FirstLifeText, flags,
1071 props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId);
1072
1073
1074 remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, (uint)props.SkillsMask,
1075 props.SkillsText, props.Language);
1076 }
1077
1078 /// <summary>
1079 /// Updates the avatar properties.
1080 /// </summary>
1081 /// <param name='remoteClient'>
1082 /// Remote client.
1083 /// </param>
1084 /// <param name='newProfile'>
1085 /// New profile.
1086 /// </param>
1087 public void AvatarPropertiesUpdate(IClientAPI remoteClient, UserProfileData newProfile)
1088 {
1089 if (remoteClient.AgentId == newProfile.ID)
1090 {
1091 UserProfileProperties prop = new UserProfileProperties();
1092
1093 prop.UserId = remoteClient.AgentId;
1094 prop.WebUrl = newProfile.ProfileUrl;
1095 prop.ImageId = newProfile.Image;
1096 prop.AboutText = newProfile.AboutText;
1097 prop.FirstLifeImageId = newProfile.FirstLifeImage;
1098 prop.FirstLifeText = newProfile.FirstLifeAboutText;
1099
1100 string serverURI = string.Empty;
1101 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
1102
1103 object Prop = prop;
1104
1105 if(!rpc.JsonRpcRequest(ref Prop, "avatar_properties_update", serverURI, UUID.Random().ToString()))
1106 {
1107 remoteClient.SendAgentAlertMessage(
1108 "Error updating properties", false);
1109 return;
1110 }
1111
1112 RequestAvatarProperties(remoteClient, newProfile.ID);
1113 }
1114 }
1115
1116 /// <summary>
1117 /// Gets the profile data.
1118 /// </summary>
1119 /// <returns>
1120 /// The profile data.
1121 /// </returns>
1122 bool GetProfileData(ref UserProfileProperties properties, bool foreign, out string message)
1123 {
1124 // Can't handle NPC yet...
1125 ScenePresence p = FindPresence(properties.UserId);
1126
1127 if (null != p)
1128 {
1129 if (p.PresenceType == PresenceType.Npc)
1130 {
1131 message = "Id points to NPC";
1132 return false;
1133 }
1134 }
1135
1136 string serverURI = string.Empty;
1137 GetUserProfileServerURI(properties.UserId, out serverURI);
1138
1139 // This is checking a friend on the home grid
1140 // Not HG friend
1141 if (String.IsNullOrEmpty(serverURI))
1142 {
1143 message = "No Presence - foreign friend";
1144 return false;
1145 }
1146
1147 object Prop = (object)properties;
1148 if (!rpc.JsonRpcRequest(ref Prop, "avatar_properties_request", serverURI, UUID.Random().ToString()))
1149 {
1150 // If it's a foreign user then try again using OpenProfile, in case that's what the grid is using
1151 bool secondChanceSuccess = false;
1152 if (foreign)
1153 {
1154 try
1155 {
1156 OpenProfileClient client = new OpenProfileClient(serverURI);
1157 if (client.RequestAvatarPropertiesUsingOpenProfile(ref properties))
1158 secondChanceSuccess = true;
1159 }
1160 catch (Exception e)
1161 {
1162 m_log.Debug(
1163 string.Format(
1164 "[PROFILES]: Request using the OpenProfile API for user {0} to {1} failed",
1165 properties.UserId, serverURI),
1166 e);
1167
1168 // Allow the return 'message' to say "JsonRpcRequest" and not "OpenProfile", because
1169 // the most likely reason that OpenProfile failed is that the remote server
1170 // doesn't support OpenProfile, and that's not very interesting.
1171 }
1172 }
1173
1174 if (!secondChanceSuccess)
1175 {
1176 message = string.Format("JsonRpcRequest for user {0} to {1} failed", properties.UserId, serverURI);
1177 m_log.DebugFormat("[PROFILES]: {0}", message);
1178
1179 return false;
1180 }
1181 // else, continue below
1182 }
1183
1184 properties = (UserProfileProperties)Prop;
1185
1186 message = "Success";
1187 return true;
1188 }
1189 #endregion Avatar Properties
1190
1191 #region Utils
1192 bool GetImageAssets(UUID avatarId)
1193 {
1194 string profileServerURI = string.Empty;
1195 string assetServerURI = string.Empty;
1196
1197 bool foreign = GetUserProfileServerURI(avatarId, out profileServerURI);
1198
1199 if(!foreign)
1200 return true;
1201
1202 assetServerURI = UserManagementModule.GetUserServerURL(avatarId, "AssetServerURI");
1203
1204 if(string.IsNullOrEmpty(profileServerURI) || string.IsNullOrEmpty(assetServerURI))
1205 return false;
1206
1207 OSDMap parameters= new OSDMap();
1208 parameters.Add("avatarId", OSD.FromUUID(avatarId));
1209 OSD Params = (OSD)parameters;
1210 if(!rpc.JsonRpcRequest(ref Params, "image_assets_request", profileServerURI, UUID.Random().ToString()))
1211 {
1212 return false;
1213 }
1214
1215 parameters = (OSDMap)Params;
1216
1217 if (parameters.ContainsKey("result"))
1218 {
1219 OSDArray list = (OSDArray)parameters["result"];
1220
1221 foreach (OSD asset in list)
1222 {
1223 OSDString assetId = (OSDString)asset;
1224
1225 Scene.AssetService.Get(string.Format("{0}/{1}", assetServerURI, assetId.AsString()));
1226 }
1227 return true;
1228 }
1229 else
1230 {
1231 m_log.ErrorFormat("[PROFILES]: Problematic response for image_assets_request from {0}", profileServerURI);
1232 return false;
1233 }
1234 }
1235
1236 /// <summary>
1237 /// Gets the user account data.
1238 /// </summary>
1239 /// <returns>
1240 /// The user profile data.
1241 /// </returns>
1242 /// <param name='userID'>
1243 /// If set to <c>true</c> user I.
1244 /// </param>
1245 /// <param name='userInfo'>
1246 /// If set to <c>true</c> user info.
1247 /// </param>
1248 bool GetUserAccountData(UUID userID, out Dictionary<string, object> userInfo)
1249 {
1250 Dictionary<string,object> info = new Dictionary<string, object>();
1251
1252 if (UserManagementModule.IsLocalGridUser(userID))
1253 {
1254 // Is local
1255 IUserAccountService uas = Scene.UserAccountService;
1256 UserAccount account = uas.GetUserAccount(Scene.RegionInfo.ScopeID, userID);
1257
1258 info["user_flags"] = account.UserFlags;
1259 info["user_created"] = account.Created;
1260
1261 if (!String.IsNullOrEmpty(account.UserTitle))
1262 info["user_title"] = account.UserTitle;
1263 else
1264 info["user_title"] = "";
1265
1266 userInfo = info;
1267
1268 return false;
1269 }
1270 else
1271 {
1272 // Is Foreign
1273 string home_url = UserManagementModule.GetUserServerURL(userID, "HomeURI");
1274
1275 if (String.IsNullOrEmpty(home_url))
1276 {
1277 info["user_flags"] = 0;
1278 info["user_created"] = 0;
1279 info["user_title"] = "Unavailable";
1280
1281 userInfo = info;
1282 return true;
1283 }
1284
1285 UserAgentServiceConnector uConn = new UserAgentServiceConnector(home_url);
1286
1287 Dictionary<string, object> account;
1288 try
1289 {
1290 account = uConn.GetUserInfo(userID);
1291 }
1292 catch (Exception e)
1293 {
1294 m_log.Debug("[PROFILES]: GetUserInfo call failed ", e);
1295 account = new Dictionary<string, object>();
1296 }
1297
1298 if (account.Count > 0)
1299 {
1300 if (account.ContainsKey("user_flags"))
1301 info["user_flags"] = account["user_flags"];
1302 else
1303 info["user_flags"] = "";
1304
1305 if (account.ContainsKey("user_created"))
1306 info["user_created"] = account["user_created"];
1307 else
1308 info["user_created"] = "";
1309
1310 info["user_title"] = "HG Visitor";
1311 }
1312 else
1313 {
1314 info["user_flags"] = 0;
1315 info["user_created"] = 0;
1316 info["user_title"] = "HG Visitor";
1317 }
1318 userInfo = info;
1319 return true;
1320 }
1321 }
1322
1323 /// <summary>
1324 /// Gets the user gatekeeper server URI.
1325 /// </summary>
1326 /// <returns>
1327 /// The user gatekeeper server URI.
1328 /// </returns>
1329 /// <param name='userID'>
1330 /// If set to <c>true</c> user URI.
1331 /// </param>
1332 /// <param name='serverURI'>
1333 /// If set to <c>true</c> server URI.
1334 /// </param>
1335 bool GetUserGatekeeperURI(UUID userID, out string serverURI)
1336 {
1337 bool local;
1338 local = UserManagementModule.IsLocalGridUser(userID);
1339
1340 if (!local)
1341 {
1342 serverURI = UserManagementModule.GetUserServerURL(userID, "GatekeeperURI");
1343 // Is Foreign
1344 return true;
1345 }
1346 else
1347 {
1348 serverURI = MyGatekeeper;
1349 // Is local
1350 return false;
1351 }
1352 }
1353
1354 /// <summary>
1355 /// Gets the user profile server UR.
1356 /// </summary>
1357 /// <returns>
1358 /// The user profile server UR.
1359 /// </returns>
1360 /// <param name='userID'>
1361 /// If set to <c>true</c> user I.
1362 /// </param>
1363 /// <param name='serverURI'>
1364 /// If set to <c>true</c> server UR.
1365 /// </param>
1366 bool GetUserProfileServerURI(UUID userID, out string serverURI)
1367 {
1368 bool local;
1369 local = UserManagementModule.IsLocalGridUser(userID);
1370
1371 if (!local)
1372 {
1373 serverURI = UserManagementModule.GetUserServerURL(userID, "ProfileServerURI");
1374 // Is Foreign
1375 return true;
1376 }
1377 else
1378 {
1379 serverURI = ProfileServerUri;
1380 // Is local
1381 return false;
1382 }
1383 }
1384
1385 /// <summary>
1386 /// Finds the presence.
1387 /// </summary>
1388 /// <returns>
1389 /// The presence.
1390 /// </returns>
1391 /// <param name='clientID'>
1392 /// Client I.
1393 /// </param>
1394 ScenePresence FindPresence(UUID clientID)
1395 {
1396 ScenePresence p;
1397
1398 p = Scene.GetScenePresence(clientID);
1399 if (p != null && !p.IsChildAgent)
1400 return p;
1401
1402 return null;
1403 }
1404 #endregion Util
1405 }
1406}