clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.IO;
30 using System.Text;
31 using System.Collections;
32 using System.Collections.Generic;
33 using System.Globalization;
34 using System.Net;
35 using System.Net.Sockets;
36 using System.Reflection;
37 using System.Xml;
38 using OpenMetaverse;
39 using OpenMetaverse.StructuredData;
40 using log4net;
41 using Nini.Config;
42 using Nwc.XmlRpc;
43 using OpenSim.Framework;
44 using OpenSim.Region.Framework.Interfaces;
45 using OpenSim.Region.Framework.Scenes;
46 using OpenSim.Services.Interfaces;
47 using Mono.Addins;
48 using OpenSim.Services.Connectors.Hypergrid;
49 using OpenSim.Framework.Servers.HttpServer;
50 using OpenSim.Services.UserProfilesService;
51  
52 namespace OpenSim.Region.CoreModules.Avatar.UserProfiles
53 {
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserProfilesModule")]
55 public class UserProfileModule : IProfileModule, INonSharedRegionModule
56 {
57 /// <summary>
58 /// Logging
59 /// </summary>
60 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61  
62 // The pair of Dictionaries are used to handle the switching of classified ads
63 // by maintaining a cache of classified id to creator id mappings and an interest
64 // count. The entries are removed when the interest count reaches 0.
65 Dictionary<UUID, UUID> m_classifiedCache = new Dictionary<UUID, UUID>();
66 Dictionary<UUID, int> m_classifiedInterest = new Dictionary<UUID, int>();
67  
68 private JsonRpcRequestManager rpc = new JsonRpcRequestManager();
69  
70 public Scene Scene
71 {
72 get; private set;
73 }
74  
75 /// <summary>
76 /// Gets or sets the ConfigSource.
77 /// </summary>
78 /// <value>
79 /// The configuration
80 /// </value>
81 public IConfigSource Config {
82 get;
83 set;
84 }
85  
86 /// <summary>
87 /// Gets or sets the URI to the profile server.
88 /// </summary>
89 /// <value>
90 /// The profile server URI.
91 /// </value>
92 public string ProfileServerUri {
93 get;
94 set;
95 }
96  
97 IProfileModule ProfileModule
98 {
99 get; set;
100 }
101  
102 IUserManagement UserManagementModule
103 {
104 get; set;
105 }
106  
107 /// <summary>
108 /// Gets or sets a value indicating whether this
109 /// <see cref="OpenSim.Region.Coremodules.UserProfiles.UserProfileModule"/> is enabled.
110 /// </summary>
111 /// <value>
112 /// <c>true</c> if enabled; otherwise, <c>false</c>.
113 /// </value>
114 public bool Enabled {
115 get;
116 set;
117 }
118  
119  
120 #region IRegionModuleBase implementation
121 /// <summary>
122 /// This is called to initialize the region module. For shared modules, this is called exactly once, after
123 /// creating the single (shared) instance. For non-shared modules, this is called once on each instance, after
124 /// the instace for the region has been created.
125 /// </summary>
126 /// <param name='source'>
127 /// Source.
128 /// </param>
129 public void Initialise(IConfigSource source)
130 {
131 Config = source;
132 ReplaceableInterface = typeof(IProfileModule);
133  
134 IConfig profileConfig = Config.Configs["UserProfiles"];
135  
136 if (profileConfig == null)
137 {
138 m_log.Debug("[PROFILES]: UserProfiles disabled, no configuration");
139 Enabled = false;
140 return;
141 }
142  
143 // If we find ProfileURL then we configure for FULL support
144 // else we setup for BASIC support
145 ProfileServerUri = profileConfig.GetString("ProfileServiceURL", "");
146 if (ProfileServerUri == "")
147 {
148 Enabled = false;
149 return;
150 }
151  
152 m_log.Debug("[PROFILES]: Full Profiles Enabled");
153 ReplaceableInterface = null;
154 Enabled = true;
155 }
156  
157 /// <summary>
158 /// Adds the region.
159 /// </summary>
160 /// <param name='scene'>
161 /// Scene.
162 /// </param>
163 public void AddRegion(Scene scene)
164 {
165 if(!Enabled)
166 return;
167  
168 Scene = scene;
169 Scene.RegisterModuleInterface<IProfileModule>(this);
170 Scene.EventManager.OnNewClient += OnNewClient;
171 Scene.EventManager.OnMakeRootAgent += HandleOnMakeRootAgent;
172  
173 UserManagementModule = Scene.RequestModuleInterface<IUserManagement>();
174 }
175  
176 void HandleOnMakeRootAgent (ScenePresence obj)
177 {
178 if(obj.PresenceType == PresenceType.Npc)
179 return;
180  
181 Util.FireAndForget(delegate
182 {
183 GetImageAssets(((IScenePresence)obj).UUID);
184 });
185 }
186  
187 /// <summary>
188 /// Removes the region.
189 /// </summary>
190 /// <param name='scene'>
191 /// Scene.
192 /// </param>
193 public void RemoveRegion(Scene scene)
194 {
195 if(!Enabled)
196 return;
197 }
198  
199 /// <summary>
200 /// This will be called once for every scene loaded. In a shared module this will be multiple times in one
201 /// instance, while a nonshared module instance will only be called once. This method is called after AddRegion
202 /// has been called in all modules for that scene, providing an opportunity to request another module's
203 /// interface, or hook an event from another module.
204 /// </summary>
205 /// <param name='scene'>
206 /// Scene.
207 /// </param>
208 public void RegionLoaded(Scene scene)
209 {
210 if(!Enabled)
211 return;
212 }
213  
214 /// <summary>
215 /// If this returns non-null, it is the type of an interface that this module intends to register. This will
216 /// cause the loader to defer loading of this module until all other modules have been loaded. If no other
217 /// module has registered the interface by then, this module will be activated, else it will remain inactive,
218 /// letting the other module take over. This should return non-null ONLY in modules that are intended to be
219 /// easily replaceable, e.g. stub implementations that the developer expects to be replaced by third party
220 /// provided modules.
221 /// </summary>
222 /// <value>
223 /// The replaceable interface.
224 /// </value>
225 public Type ReplaceableInterface
226 {
227 get; private set;
228 }
229  
230 /// <summary>
231 /// Called as the instance is closed.
232 /// </summary>
233 public void Close()
234 {
235 }
236  
237 /// <value>
238 /// The name of the module
239 /// </value>
240 /// <summary>
241 /// Gets the module name.
242 /// </summary>
243 public string Name
244 {
245 get { return "UserProfileModule"; }
246 }
247 #endregion IRegionModuleBase implementation
248  
249 #region Region Event Handlers
250 /// <summary>
251 /// Raises the new client event.
252 /// </summary>
253 /// <param name='client'>
254 /// Client.
255 /// </param>
256 void OnNewClient(IClientAPI client)
257 {
258 //Profile
259 client.OnRequestAvatarProperties += RequestAvatarProperties;
260 client.OnUpdateAvatarProperties += AvatarPropertiesUpdate;
261 client.OnAvatarInterestUpdate += AvatarInterestsUpdate;
262  
263 // Classifieds
264 client.AddGenericPacketHandler("avatarclassifiedsrequest", ClassifiedsRequest);
265 client.OnClassifiedInfoUpdate += ClassifiedInfoUpdate;
266 client.OnClassifiedInfoRequest += ClassifiedInfoRequest;
267 client.OnClassifiedDelete += ClassifiedDelete;
268  
269 // Picks
270 client.AddGenericPacketHandler("avatarpicksrequest", PicksRequest);
271 client.AddGenericPacketHandler("pickinforequest", PickInfoRequest);
272 client.OnPickInfoUpdate += PickInfoUpdate;
273 client.OnPickDelete += PickDelete;
274  
275 // Notes
276 client.AddGenericPacketHandler("avatarnotesrequest", NotesRequest);
277 client.OnAvatarNotesUpdate += NotesUpdate;
278  
279 // Preferences
280 client.OnUserInfoRequest += UserPreferencesRequest;
281 client.OnUpdateUserInfo += UpdateUserPreferences;
282 }
283 #endregion Region Event Handlers
284  
285 #region Classified
286 ///
287 /// <summary>
288 /// Handles the avatar classifieds request.
289 /// </summary>
290 /// <param name='sender'>
291 /// Sender.
292 /// </param>
293 /// <param name='method'>
294 /// Method.
295 /// </param>
296 /// <param name='args'>
297 /// Arguments.
298 /// </param>
299 public void ClassifiedsRequest(Object sender, string method, List<String> args)
300 {
301 if (!(sender is IClientAPI))
302 return;
303  
304 IClientAPI remoteClient = (IClientAPI)sender;
305  
306 UUID targetID;
307 UUID.TryParse(args[0], out targetID);
308  
309 // Can't handle NPC yet...
310 ScenePresence p = FindPresence(targetID);
311  
312 if (null != p)
313 {
314 if (p.PresenceType == PresenceType.Npc)
315 return;
316 }
317  
318 string serverURI = string.Empty;
319 GetUserProfileServerURI(targetID, out serverURI);
320 UUID creatorId = UUID.Zero;
321 Dictionary<UUID, string> classifieds = new Dictionary<UUID, string>();
322  
323 OSDMap parameters= new OSDMap();
324 UUID.TryParse(args[0], out creatorId);
325 parameters.Add("creatorId", OSD.FromUUID(creatorId));
326 OSD Params = (OSD)parameters;
327 if(!rpc.JsonRpcRequest(ref Params, "avatarclassifiedsrequest", serverURI, UUID.Random().ToString()))
328 {
329 remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds);
330 return;
331 }
332  
333 parameters = (OSDMap)Params;
334  
335 OSDArray list = (OSDArray)parameters["result"];
336  
337  
338 foreach(OSD map in list)
339 {
340 OSDMap m = (OSDMap)map;
341 UUID cid = m["classifieduuid"].AsUUID();
342 string name = m["name"].AsString();
343  
344 classifieds[cid] = name;
345  
346 lock (m_classifiedCache)
347 {
348 if (!m_classifiedCache.ContainsKey(cid))
349 {
350 m_classifiedCache.Add(cid,creatorId);
351 m_classifiedInterest.Add(cid, 0);
352 }
353  
354 m_classifiedInterest[cid]++;
355 }
356 }
357  
358 remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds);
359 }
360  
361 public void ClassifiedInfoRequest(UUID queryClassifiedID, IClientAPI remoteClient)
362 {
363 UUID target = remoteClient.AgentId;
364 UserClassifiedAdd ad = new UserClassifiedAdd();
365 ad.ClassifiedId = queryClassifiedID;
366  
367 lock (m_classifiedCache)
368 {
369 if (m_classifiedCache.ContainsKey(queryClassifiedID))
370 {
371 target = m_classifiedCache[queryClassifiedID];
372  
373 m_classifiedInterest[queryClassifiedID] --;
374  
375 if (m_classifiedInterest[queryClassifiedID] == 0)
376 {
377 m_classifiedInterest.Remove(queryClassifiedID);
378 m_classifiedCache.Remove(queryClassifiedID);
379 }
380 }
381 }
382  
383 string serverURI = string.Empty;
384 GetUserProfileServerURI(target, out serverURI);
385  
386 object Ad = (object)ad;
387 if(!rpc.JsonRpcRequest(ref Ad, "classifieds_info_query", serverURI, UUID.Random().ToString()))
388 {
389 remoteClient.SendAgentAlertMessage(
390 "Error getting classified info", false);
391 return;
392 }
393 ad = (UserClassifiedAdd) Ad;
394  
395 if(ad.CreatorId == UUID.Zero)
396 return;
397  
398 Vector3 globalPos = new Vector3();
399 Vector3.TryParse(ad.GlobalPos, out globalPos);
400  
401 remoteClient.SendClassifiedInfoReply(ad.ClassifiedId, ad.CreatorId, (uint)ad.CreationDate, (uint)ad.ExpirationDate,
402 (uint)ad.Category, ad.Name, ad.Description, ad.ParcelId, (uint)ad.ParentEstate,
403 ad.SnapshotId, ad.SimName, globalPos, ad.ParcelName, ad.Flags, ad.Price);
404  
405 }
406  
407 /// <summary>
408 /// Classifieds info update.
409 /// </summary>
410 /// <param name='queryclassifiedID'>
411 /// Queryclassified I.
412 /// </param>
413 /// <param name='queryCategory'>
414 /// Query category.
415 /// </param>
416 /// <param name='queryName'>
417 /// Query name.
418 /// </param>
419 /// <param name='queryDescription'>
420 /// Query description.
421 /// </param>
422 /// <param name='queryParcelID'>
423 /// Query parcel I.
424 /// </param>
425 /// <param name='queryParentEstate'>
426 /// Query parent estate.
427 /// </param>
428 /// <param name='querySnapshotID'>
429 /// Query snapshot I.
430 /// </param>
431 /// <param name='queryGlobalPos'>
432 /// Query global position.
433 /// </param>
434 /// <param name='queryclassifiedFlags'>
435 /// Queryclassified flags.
436 /// </param>
437 /// <param name='queryclassifiedPrice'>
438 /// Queryclassified price.
439 /// </param>
440 /// <param name='remoteClient'>
441 /// Remote client.
442 /// </param>
443 public void ClassifiedInfoUpdate(UUID queryclassifiedID, uint queryCategory, string queryName, string queryDescription, UUID queryParcelID,
444 uint queryParentEstate, UUID querySnapshotID, Vector3 queryGlobalPos, byte queryclassifiedFlags,
445 int queryclassifiedPrice, IClientAPI remoteClient)
446 {
447 UserClassifiedAdd ad = new UserClassifiedAdd();
448  
449 Scene s = (Scene) remoteClient.Scene;
450 Vector3 pos = remoteClient.SceneAgent.AbsolutePosition;
451 ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y);
452 ScenePresence p = FindPresence(remoteClient.AgentId);
453  
454 string serverURI = string.Empty;
455 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
456  
457 if (land == null)
458 {
459 ad.ParcelName = string.Empty;
460 }
461 else
462 {
463 ad.ParcelName = land.LandData.Name;
464 }
465  
466 ad.CreatorId = remoteClient.AgentId;
467 ad.ClassifiedId = queryclassifiedID;
468 ad.Category = Convert.ToInt32(queryCategory);
469 ad.Name = queryName;
470 ad.Description = queryDescription;
471 ad.ParentEstate = Convert.ToInt32(queryParentEstate);
472 ad.SnapshotId = querySnapshotID;
473 ad.SimName = remoteClient.Scene.RegionInfo.RegionName;
474 ad.GlobalPos = queryGlobalPos.ToString ();
475 ad.Flags = queryclassifiedFlags;
476 ad.Price = queryclassifiedPrice;
477 ad.ParcelId = p.currentParcelUUID;
478  
479 object Ad = ad;
480  
481 OSD.SerializeMembers(Ad);
482  
483 if(!rpc.JsonRpcRequest(ref Ad, "classified_update", serverURI, UUID.Random().ToString()))
484 {
485 remoteClient.SendAgentAlertMessage(
486 "Error updating classified", false);
487 return;
488 }
489 }
490  
491 /// <summary>
492 /// Classifieds delete.
493 /// </summary>
494 /// <param name='queryClassifiedID'>
495 /// Query classified I.
496 /// </param>
497 /// <param name='remoteClient'>
498 /// Remote client.
499 /// </param>
500 public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient)
501 {
502 string serverURI = string.Empty;
503 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
504  
505 UUID classifiedId;
506 OSDMap parameters= new OSDMap();
507 UUID.TryParse(queryClassifiedID.ToString(), out classifiedId);
508 parameters.Add("classifiedId", OSD.FromUUID(classifiedId));
509 OSD Params = (OSD)parameters;
510 if(!rpc.JsonRpcRequest(ref Params, "classified_delete", serverURI, UUID.Random().ToString()))
511 {
512 remoteClient.SendAgentAlertMessage(
513 "Error classified delete", false);
514 return;
515 }
516  
517 parameters = (OSDMap)Params;
518 }
519 #endregion Classified
520  
521 #region Picks
522 /// <summary>
523 /// Handles the avatar picks request.
524 /// </summary>
525 /// <param name='sender'>
526 /// Sender.
527 /// </param>
528 /// <param name='method'>
529 /// Method.
530 /// </param>
531 /// <param name='args'>
532 /// Arguments.
533 /// </param>
534 public void PicksRequest(Object sender, string method, List<String> args)
535 {
536 if (!(sender is IClientAPI))
537 return;
538  
539 IClientAPI remoteClient = (IClientAPI)sender;
540  
541 UUID targetId;
542 UUID.TryParse(args[0], out targetId);
543  
544 // Can't handle NPC yet...
545 ScenePresence p = FindPresence(targetId);
546  
547 if (null != p)
548 {
549 if (p.PresenceType == PresenceType.Npc)
550 return;
551 }
552  
553 string serverURI = string.Empty;
554 GetUserProfileServerURI(targetId, out serverURI);
555  
556 Dictionary<UUID, string> picks = new Dictionary<UUID, string>();
557  
558 OSDMap parameters= new OSDMap();
559 parameters.Add("creatorId", OSD.FromUUID(targetId));
560 OSD Params = (OSD)parameters;
561 if(!rpc.JsonRpcRequest(ref Params, "avatarpicksrequest", serverURI, UUID.Random().ToString()))
562 {
563 remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks);
564 return;
565 }
566  
567 parameters = (OSDMap)Params;
568  
569 OSDArray list = (OSDArray)parameters["result"];
570  
571 foreach(OSD map in list)
572 {
573 OSDMap m = (OSDMap)map;
574 UUID cid = m["pickuuid"].AsUUID();
575 string name = m["name"].AsString();
576  
577 m_log.DebugFormat("[PROFILES]: PicksRequest {0}", name);
578  
579 picks[cid] = name;
580 }
581 remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks);
582 }
583  
584 /// <summary>
585 /// Handles the pick info request.
586 /// </summary>
587 /// <param name='sender'>
588 /// Sender.
589 /// </param>
590 /// <param name='method'>
591 /// Method.
592 /// </param>
593 /// <param name='args'>
594 /// Arguments.
595 /// </param>
596 public void PickInfoRequest(Object sender, string method, List<String> args)
597 {
598 if (!(sender is IClientAPI))
599 return;
600  
601 UUID targetID;
602 UUID.TryParse(args[0], out targetID);
603 string serverURI = string.Empty;
604 GetUserProfileServerURI(targetID, out serverURI);
605 IClientAPI remoteClient = (IClientAPI)sender;
606  
607 UserProfilePick pick = new UserProfilePick();
608 UUID.TryParse(args[0], out pick.CreatorId);
609 UUID.TryParse(args[1], out pick.PickId);
610  
611  
612 object Pick = (object)pick;
613 if(!rpc.JsonRpcRequest(ref Pick, "pickinforequest", serverURI, UUID.Random().ToString()))
614 {
615 remoteClient.SendAgentAlertMessage(
616 "Error selecting pick", false);
617 return;
618 }
619 pick = (UserProfilePick) Pick;
620  
621 Vector3 globalPos;
622 Vector3.TryParse(pick.GlobalPos,out globalPos);
623  
624 m_log.DebugFormat("[PROFILES]: PickInfoRequest: {0} : {1}", pick.Name.ToString(), pick.SnapshotId.ToString());
625  
626 remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name,
627 pick.Desc,pick.SnapshotId,pick.User,pick.OriginalName,pick.SimName,
628 globalPos,pick.SortOrder,pick.Enabled);
629 }
630  
631 /// <summary>
632 /// Updates the userpicks
633 /// </summary>
634 /// <param name='remoteClient'>
635 /// Remote client.
636 /// </param>
637 /// <param name='pickID'>
638 /// Pick I.
639 /// </param>
640 /// <param name='creatorID'>
641 /// the creator of the pick
642 /// </param>
643 /// <param name='topPick'>
644 /// Top pick.
645 /// </param>
646 /// <param name='name'>
647 /// Name.
648 /// </param>
649 /// <param name='desc'>
650 /// Desc.
651 /// </param>
652 /// <param name='snapshotID'>
653 /// Snapshot I.
654 /// </param>
655 /// <param name='sortOrder'>
656 /// Sort order.
657 /// </param>
658 /// <param name='enabled'>
659 /// Enabled.
660 /// </param>
661 public void PickInfoUpdate(IClientAPI remoteClient, UUID pickID, UUID creatorID, bool topPick, string name, string desc, UUID snapshotID, int sortOrder, bool enabled)
662 {
663 m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString());
664  
665 UserProfilePick pick = new UserProfilePick();
666 string serverURI = string.Empty;
667 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
668 ScenePresence p = FindPresence(remoteClient.AgentId);
669  
670 Vector3 avaPos = p.AbsolutePosition;
671 // Getting the global position for the Avatar
672 Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.WorldLocX + avaPos.X,
673 remoteClient.Scene.RegionInfo.WorldLocY + avaPos.Y,
674 avaPos.Z);
675  
676 string landOwnerName = string.Empty;
677 ILandObject land = p.Scene.LandChannel.GetLandObject(avaPos.X, avaPos.Y);
678  
679 if (land != null)
680 {
681 if (land.LandData.IsGroupOwned)
682 {
683 IGroupsModule groupMod = p.Scene.RequestModuleInterface<IGroupsModule>();
684 UUID groupId = land.LandData.GroupID;
685 GroupRecord groupRecord = groupMod.GetGroupRecord(groupId);
686 landOwnerName = groupRecord.GroupName;
687 }
688 else
689 {
690 IUserAccountService accounts = p.Scene.RequestModuleInterface<IUserAccountService>();
691 UserAccount user = accounts.GetUserAccount(p.Scene.RegionInfo.ScopeID, land.LandData.OwnerID);
692 landOwnerName = user.Name;
693 }
694 }
695 else
696 {
697 m_log.WarnFormat(
698 "[PROFILES]: PickInfoUpdate found no parcel info at {0},{1} in {2}",
699 avaPos.X, avaPos.Y, p.Scene.Name);
700 }
701  
702 pick.PickId = pickID;
703 pick.CreatorId = creatorID;
704 pick.TopPick = topPick;
705 pick.Name = name;
706 pick.Desc = desc;
707 pick.ParcelId = p.currentParcelUUID;
708 pick.SnapshotId = snapshotID;
709 pick.User = landOwnerName;
710 pick.SimName = remoteClient.Scene.RegionInfo.RegionName;
711 pick.GlobalPos = posGlobal.ToString();
712 pick.SortOrder = sortOrder;
713 pick.Enabled = enabled;
714  
715 object Pick = (object)pick;
716 if(!rpc.JsonRpcRequest(ref Pick, "picks_update", serverURI, UUID.Random().ToString()))
717 {
718 remoteClient.SendAgentAlertMessage(
719 "Error updating pick", false);
720 return;
721 }
722  
723 m_log.DebugFormat("[PROFILES]: Finish PickInfoUpdate {0} {1}", pick.Name, pick.PickId.ToString());
724 }
725  
726 /// <summary>
727 /// Delete a Pick
728 /// </summary>
729 /// <param name='remoteClient'>
730 /// Remote client.
731 /// </param>
732 /// <param name='queryPickID'>
733 /// Query pick I.
734 /// </param>
735 public void PickDelete(IClientAPI remoteClient, UUID queryPickID)
736 {
737 string serverURI = string.Empty;
738 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
739  
740 OSDMap parameters= new OSDMap();
741 parameters.Add("pickId", OSD.FromUUID(queryPickID));
742 OSD Params = (OSD)parameters;
743 if(!rpc.JsonRpcRequest(ref Params, "picks_delete", serverURI, UUID.Random().ToString()))
744 {
745 remoteClient.SendAgentAlertMessage(
746 "Error picks delete", false);
747 return;
748 }
749 }
750 #endregion Picks
751  
752 #region Notes
753 /// <summary>
754 /// Handles the avatar notes request.
755 /// </summary>
756 /// <param name='sender'>
757 /// Sender.
758 /// </param>
759 /// <param name='method'>
760 /// Method.
761 /// </param>
762 /// <param name='args'>
763 /// Arguments.
764 /// </param>
765 public void NotesRequest(Object sender, string method, List<String> args)
766 {
767 UserProfileNotes note = new UserProfileNotes();
768  
769 if (!(sender is IClientAPI))
770 return;
771  
772 IClientAPI remoteClient = (IClientAPI)sender;
773 string serverURI = string.Empty;
774 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
775 note.UserId = remoteClient.AgentId;
776 UUID.TryParse(args[0], out note.TargetId);
777  
778 object Note = (object)note;
779 if(!rpc.JsonRpcRequest(ref Note, "avatarnotesrequest", serverURI, UUID.Random().ToString()))
780 {
781 remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes);
782 return;
783 }
784 note = (UserProfileNotes) Note;
785  
786 remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes);
787 }
788  
789 /// <summary>
790 /// Avatars the notes update.
791 /// </summary>
792 /// <param name='remoteClient'>
793 /// Remote client.
794 /// </param>
795 /// <param name='queryTargetID'>
796 /// Query target I.
797 /// </param>
798 /// <param name='queryNotes'>
799 /// Query notes.
800 /// </param>
801 public void NotesUpdate(IClientAPI remoteClient, UUID queryTargetID, string queryNotes)
802 {
803 UserProfileNotes note = new UserProfileNotes();
804  
805 note.UserId = remoteClient.AgentId;
806 note.TargetId = queryTargetID;
807 note.Notes = queryNotes;
808  
809 string serverURI = string.Empty;
810 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
811  
812 object Note = note;
813 if(!rpc.JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString()))
814 {
815 remoteClient.SendAgentAlertMessage(
816 "Error updating note", false);
817 return;
818 }
819 }
820 #endregion Notes
821  
822 #region User Preferences
823 /// <summary>
824 /// Updates the user preferences.
825 /// </summary>
826 /// <param name='imViaEmail'>
827 /// Im via email.
828 /// </param>
829 /// <param name='visible'>
830 /// Visible.
831 /// </param>
832 /// <param name='remoteClient'>
833 /// Remote client.
834 /// </param>
835 public void UpdateUserPreferences(bool imViaEmail, bool visible, IClientAPI remoteClient)
836 {
837 UserPreferences pref = new UserPreferences();
838  
839 pref.UserId = remoteClient.AgentId;
840 pref.IMViaEmail = imViaEmail;
841 pref.Visible = visible;
842  
843 string serverURI = string.Empty;
844 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
845  
846 object Pref = pref;
847 if(!rpc.JsonRpcRequest(ref Pref, "user_preferences_update", serverURI, UUID.Random().ToString()))
848 {
849 m_log.InfoFormat("[PROFILES]: UserPreferences update error");
850 remoteClient.SendAgentAlertMessage("Error updating preferences", false);
851 return;
852 }
853 }
854  
855 /// <summary>
856 /// Users the preferences request.
857 /// </summary>
858 /// <param name='remoteClient'>
859 /// Remote client.
860 /// </param>
861 public void UserPreferencesRequest(IClientAPI remoteClient)
862 {
863 UserPreferences pref = new UserPreferences();
864  
865 pref.UserId = remoteClient.AgentId;
866  
867 string serverURI = string.Empty;
868 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
869  
870  
871 object Pref = (object)pref;
872 if(!rpc.JsonRpcRequest(ref Pref, "user_preferences_request", serverURI, UUID.Random().ToString()))
873 {
874 m_log.InfoFormat("[PROFILES]: UserPreferences request error");
875 remoteClient.SendAgentAlertMessage("Error requesting preferences", false);
876 return;
877 }
878 pref = (UserPreferences) Pref;
879  
880 remoteClient.SendUserInfoReply(pref.IMViaEmail, pref.Visible, pref.EMail);
881  
882 }
883 #endregion User Preferences
884  
885 #region Avatar Properties
886 /// <summary>
887 /// Update the avatars interests .
888 /// </summary>
889 /// <param name='remoteClient'>
890 /// Remote client.
891 /// </param>
892 /// <param name='wantmask'>
893 /// Wantmask.
894 /// </param>
895 /// <param name='wanttext'>
896 /// Wanttext.
897 /// </param>
898 /// <param name='skillsmask'>
899 /// Skillsmask.
900 /// </param>
901 /// <param name='skillstext'>
902 /// Skillstext.
903 /// </param>
904 /// <param name='languages'>
905 /// Languages.
906 /// </param>
907 public void AvatarInterestsUpdate(IClientAPI remoteClient, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages)
908 {
909 UserProfileProperties prop = new UserProfileProperties();
910  
911 prop.UserId = remoteClient.AgentId;
912 prop.WantToMask = (int)wantmask;
913 prop.WantToText = wanttext;
914 prop.SkillsMask = (int)skillsmask;
915 prop.SkillsText = skillstext;
916 prop.Language = languages;
917  
918 string serverURI = string.Empty;
919 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
920  
921 object Param = prop;
922 if(!rpc.JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString()))
923 {
924 remoteClient.SendAgentAlertMessage(
925 "Error updating interests", false);
926 return;
927 }
928 }
929  
930 public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID)
931 {
932 if (String.IsNullOrEmpty(avatarID.ToString()) || String.IsNullOrEmpty(remoteClient.AgentId.ToString()))
933 {
934 // Looking for a reason that some viewers are sending null Id's
935 m_log.DebugFormat("[PROFILES]: This should not happen remoteClient.AgentId {0} - avatarID {1}", remoteClient.AgentId, avatarID);
936 return;
937 }
938  
939 // Can't handle NPC yet...
940 ScenePresence p = FindPresence(avatarID);
941  
942 if (null != p)
943 {
944 if (p.PresenceType == PresenceType.Npc)
945 return;
946 }
947  
948 string serverURI = string.Empty;
949 bool foreign = GetUserProfileServerURI(avatarID, out serverURI);
950  
951 UserAccount account = null;
952 Dictionary<string,object> userInfo;
953  
954 if (!foreign)
955 {
956 account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, avatarID);
957 }
958 else
959 {
960 userInfo = new Dictionary<string, object>();
961 }
962  
963 Byte[] charterMember = new Byte[1];
964 string born = String.Empty;
965 uint flags = 0x00;
966  
967 if (null != account)
968 {
969 if (account.UserTitle == "")
970 {
971 charterMember[0] = (Byte)((account.UserFlags & 0xf00) >> 8);
972 }
973 else
974 {
975 charterMember = Utils.StringToBytes(account.UserTitle);
976 }
977  
978 born = Util.ToDateTime(account.Created).ToString(
979 "M/d/yyyy", CultureInfo.InvariantCulture);
980 flags = (uint)(account.UserFlags & 0xff);
981 }
982 else
983 {
984 if (GetUserAccountData(avatarID, out userInfo) == true)
985 {
986 if ((string)userInfo["user_title"] == "")
987 {
988 charterMember[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8);
989 }
990 else
991 {
992 charterMember = Utils.StringToBytes((string)userInfo["user_title"]);
993 }
994  
995 int val_born = (int)userInfo["user_created"];
996 born = Util.ToDateTime(val_born).ToString(
997 "M/d/yyyy", CultureInfo.InvariantCulture);
998  
999 // picky, picky
1000 int val_flags = (int)userInfo["user_flags"];
1001 flags = (uint)(val_flags & 0xff);
1002 }
1003 }
1004  
1005 UserProfileProperties props = new UserProfileProperties();
1006 string result = string.Empty;
1007  
1008 props.UserId = avatarID;
1009  
1010 if (!GetProfileData(ref props, foreign, out result))
1011 {
1012 m_log.DebugFormat("Error getting profile for {0}: {1}", avatarID, result);
1013 return;
1014 }
1015  
1016 remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, charterMember , props.FirstLifeText, flags,
1017 props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId);
1018  
1019  
1020 remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, (uint)props.SkillsMask,
1021 props.SkillsText, props.Language);
1022 }
1023  
1024 /// <summary>
1025 /// Updates the avatar properties.
1026 /// </summary>
1027 /// <param name='remoteClient'>
1028 /// Remote client.
1029 /// </param>
1030 /// <param name='newProfile'>
1031 /// New profile.
1032 /// </param>
1033 public void AvatarPropertiesUpdate(IClientAPI remoteClient, UserProfileData newProfile)
1034 {
1035 if (remoteClient.AgentId == newProfile.ID)
1036 {
1037 UserProfileProperties prop = new UserProfileProperties();
1038  
1039 prop.UserId = remoteClient.AgentId;
1040 prop.WebUrl = newProfile.ProfileUrl;
1041 prop.ImageId = newProfile.Image;
1042 prop.AboutText = newProfile.AboutText;
1043 prop.FirstLifeImageId = newProfile.FirstLifeImage;
1044 prop.FirstLifeText = newProfile.FirstLifeAboutText;
1045  
1046 string serverURI = string.Empty;
1047 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
1048  
1049 object Prop = prop;
1050  
1051 if(!rpc.JsonRpcRequest(ref Prop, "avatar_properties_update", serverURI, UUID.Random().ToString()))
1052 {
1053 remoteClient.SendAgentAlertMessage(
1054 "Error updating properties", false);
1055 return;
1056 }
1057  
1058 RequestAvatarProperties(remoteClient, newProfile.ID);
1059 }
1060 }
1061  
1062 /// <summary>
1063 /// Gets the profile data.
1064 /// </summary>
1065 /// <returns>
1066 /// The profile data.
1067 /// </returns>
1068 bool GetProfileData(ref UserProfileProperties properties, bool foreign, out string message)
1069 {
1070 // Can't handle NPC yet...
1071 ScenePresence p = FindPresence(properties.UserId);
1072  
1073 if (null != p)
1074 {
1075 if (p.PresenceType == PresenceType.Npc)
1076 {
1077 message = "Id points to NPC";
1078 return false;
1079 }
1080 }
1081  
1082 string serverURI = string.Empty;
1083 GetUserProfileServerURI(properties.UserId, out serverURI);
1084  
1085 // This is checking a friend on the home grid
1086 // Not HG friend
1087 if (String.IsNullOrEmpty(serverURI))
1088 {
1089 message = "No Presence - foreign friend";
1090 return false;
1091 }
1092  
1093 object Prop = (object)properties;
1094 if (!rpc.JsonRpcRequest(ref Prop, "avatar_properties_request", serverURI, UUID.Random().ToString()))
1095 {
1096 // If it's a foreign user then try again using OpenProfile, in case that's what the grid is using
1097 bool secondChanceSuccess = false;
1098 if (foreign)
1099 {
1100 try
1101 {
1102 OpenProfileClient client = new OpenProfileClient(serverURI);
1103 if (client.RequestAvatarPropertiesUsingOpenProfile(ref properties))
1104 secondChanceSuccess = true;
1105 }
1106 catch (Exception e)
1107 {
1108 m_log.Debug(string.Format("Request using the OpenProfile API to {0} failed", serverURI), e);
1109 // Allow the return 'message' to say "JsonRpcRequest" and not "OpenProfile", because
1110 // the most likely reason that OpenProfile failed is that the remote server
1111 // doesn't support OpenProfile, and that's not very interesting.
1112 }
1113 }
1114  
1115 if (!secondChanceSuccess)
1116 {
1117 message = string.Format("JsonRpcRequest to {0} failed", serverURI);
1118 return false;
1119 }
1120 // else, continue below
1121 }
1122  
1123 properties = (UserProfileProperties)Prop;
1124  
1125 message = "Success";
1126 return true;
1127 }
1128 #endregion Avatar Properties
1129  
1130 #region Utils
1131 bool GetImageAssets(UUID avatarId)
1132 {
1133 string profileServerURI = string.Empty;
1134 string assetServerURI = string.Empty;
1135  
1136 bool foreign = GetUserProfileServerURI(avatarId, out profileServerURI);
1137  
1138 if(!foreign)
1139 return true;
1140  
1141 assetServerURI = UserManagementModule.GetUserServerURL(avatarId, "AssetServerURI");
1142  
1143 if(string.IsNullOrEmpty(profileServerURI) || string.IsNullOrEmpty(assetServerURI))
1144 return false;
1145  
1146 OSDMap parameters= new OSDMap();
1147 parameters.Add("avatarId", OSD.FromUUID(avatarId));
1148 OSD Params = (OSD)parameters;
1149 if(!rpc.JsonRpcRequest(ref Params, "image_assets_request", profileServerURI, UUID.Random().ToString()))
1150 {
1151 return false;
1152 }
1153  
1154 parameters = (OSDMap)Params;
1155  
1156 if (parameters.ContainsKey("result"))
1157 {
1158 OSDArray list = (OSDArray)parameters["result"];
1159  
1160 foreach (OSD asset in list)
1161 {
1162 OSDString assetId = (OSDString)asset;
1163  
1164 Scene.AssetService.Get(string.Format("{0}/{1}", assetServerURI, assetId.AsString()));
1165 }
1166 return true;
1167 }
1168 else
1169 {
1170 m_log.ErrorFormat("[PROFILES]: Problematic response for image_assets_request from {0}", profileServerURI);
1171 return false;
1172 }
1173 }
1174  
1175 /// <summary>
1176 /// Gets the user account data.
1177 /// </summary>
1178 /// <returns>
1179 /// The user profile data.
1180 /// </returns>
1181 /// <param name='userID'>
1182 /// If set to <c>true</c> user I.
1183 /// </param>
1184 /// <param name='userInfo'>
1185 /// If set to <c>true</c> user info.
1186 /// </param>
1187 bool GetUserAccountData(UUID userID, out Dictionary<string, object> userInfo)
1188 {
1189 Dictionary<string,object> info = new Dictionary<string, object>();
1190  
1191 if (UserManagementModule.IsLocalGridUser(userID))
1192 {
1193 // Is local
1194 IUserAccountService uas = Scene.UserAccountService;
1195 UserAccount account = uas.GetUserAccount(Scene.RegionInfo.ScopeID, userID);
1196  
1197 info["user_flags"] = account.UserFlags;
1198 info["user_created"] = account.Created;
1199  
1200 if (!String.IsNullOrEmpty(account.UserTitle))
1201 info["user_title"] = account.UserTitle;
1202 else
1203 info["user_title"] = "";
1204  
1205 userInfo = info;
1206  
1207 return false;
1208 }
1209 else
1210 {
1211 // Is Foreign
1212 string home_url = UserManagementModule.GetUserServerURL(userID, "HomeURI");
1213  
1214 if (String.IsNullOrEmpty(home_url))
1215 {
1216 info["user_flags"] = 0;
1217 info["user_created"] = 0;
1218 info["user_title"] = "Unavailable";
1219  
1220 userInfo = info;
1221 return true;
1222 }
1223  
1224 UserAgentServiceConnector uConn = new UserAgentServiceConnector(home_url);
1225  
1226 Dictionary<string, object> account;
1227 try
1228 {
1229 account = uConn.GetUserInfo(userID);
1230 }
1231 catch (Exception e)
1232 {
1233 m_log.Debug("[PROFILES]: GetUserInfo call failed ", e);
1234 account = new Dictionary<string, object>();
1235 }
1236  
1237 if (account.Count > 0)
1238 {
1239 if (account.ContainsKey("user_flags"))
1240 info["user_flags"] = account["user_flags"];
1241 else
1242 info["user_flags"] = "";
1243  
1244 if (account.ContainsKey("user_created"))
1245 info["user_created"] = account["user_created"];
1246 else
1247 info["user_created"] = "";
1248  
1249 info["user_title"] = "HG Visitor";
1250 }
1251 else
1252 {
1253 info["user_flags"] = 0;
1254 info["user_created"] = 0;
1255 info["user_title"] = "HG Visitor";
1256 }
1257 userInfo = info;
1258 return true;
1259 }
1260 }
1261  
1262 /// <summary>
1263 /// Gets the user profile server UR.
1264 /// </summary>
1265 /// <returns>
1266 /// The user profile server UR.
1267 /// </returns>
1268 /// <param name='userID'>
1269 /// If set to <c>true</c> user I.
1270 /// </param>
1271 /// <param name='serverURI'>
1272 /// If set to <c>true</c> server UR.
1273 /// </param>
1274 bool GetUserProfileServerURI(UUID userID, out string serverURI)
1275 {
1276 bool local;
1277 local = UserManagementModule.IsLocalGridUser(userID);
1278  
1279 if (!local)
1280 {
1281 serverURI = UserManagementModule.GetUserServerURL(userID, "ProfileServerURI");
1282 // Is Foreign
1283 return true;
1284 }
1285 else
1286 {
1287 serverURI = ProfileServerUri;
1288 // Is local
1289 return false;
1290 }
1291 }
1292  
1293 /// <summary>
1294 /// Finds the presence.
1295 /// </summary>
1296 /// <returns>
1297 /// The presence.
1298 /// </returns>
1299 /// <param name='clientID'>
1300 /// Client I.
1301 /// </param>
1302 ScenePresence FindPresence(UUID clientID)
1303 {
1304 ScenePresence p;
1305  
1306 p = Scene.GetScenePresence(clientID);
1307 if (p != null && !p.IsChildAgent)
1308 return p;
1309  
1310 return null;
1311 }
1312 #endregion Util
1313 }
1314 }