OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
UserProfileModule.cs
Go to the documentation of this file.
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;
52 using Microsoft.CSharp;
53 
54 namespace OpenSim.Region.CoreModules.Avatar.UserProfiles
55 {
56  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserProfilesModule")]
58  {
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 
83  public IConfigSource Config
84  {
85  get;
86  set;
87  }
88 
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 
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  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 
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 
206  public void RemoveRegion(Scene scene)
207  {
208  if(!Enabled)
209  return;
210  }
211 
221  public void RegionLoaded(Scene scene)
222  {
223  if(!Enabled)
224  return;
225  }
226 
238  public Type ReplaceableInterface
239  {
240  get; private set;
241  }
242 
246  public void Close()
247  {
248  }
249 
256  public string Name
257  {
258  get { return "UserProfileModule"; }
259  }
260  #endregion IRegionModuleBase implementation
261 
262  #region Region Event Handlers
263  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  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;
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 
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 
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 
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  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 
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 
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 
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  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 
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 
877  #region User Preferences
878  public void UpdateUserPreferences(bool imViaEmail, bool visible, IClientAPI remoteClient)
891  {
892  UserPreferences pref = new UserPreferences();
893 
894  pref.UserId = remoteClient.AgentId;
895  pref.IMViaEmail = imViaEmail;
896  pref.Visible = visible;
897 
898  string serverURI = string.Empty;
899  bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
900 
901  object Pref = pref;
902  if(!rpc.JsonRpcRequest(ref Pref, "user_preferences_update", serverURI, UUID.Random().ToString()))
903  {
904  m_log.InfoFormat("[PROFILES]: UserPreferences update error");
905  remoteClient.SendAgentAlertMessage("Error updating preferences", false);
906  return;
907  }
908  }
909 
916  public void UserPreferencesRequest(IClientAPI remoteClient)
917  {
918  UserPreferences pref = new UserPreferences();
919 
920  pref.UserId = remoteClient.AgentId;
921 
922  string serverURI = string.Empty;
923  bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
924 
925 
926  object Pref = (object)pref;
927  if(!rpc.JsonRpcRequest(ref Pref, "user_preferences_request", serverURI, UUID.Random().ToString()))
928  {
929 // m_log.InfoFormat("[PROFILES]: UserPreferences request error");
930 // remoteClient.SendAgentAlertMessage("Error requesting preferences", false);
931  return;
932  }
933  pref = (UserPreferences) Pref;
934 
935  remoteClient.SendUserInfoReply(pref.IMViaEmail, pref.Visible, pref.EMail);
936 
937  }
938  #endregion User Preferences
939 
940  #region Avatar Properties
941  public void AvatarInterestsUpdate(IClientAPI remoteClient, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages)
963  {
965 
966  prop.UserId = remoteClient.AgentId;
967  prop.WantToMask = (int)wantmask;
968  prop.WantToText = wanttext;
969  prop.SkillsMask = (int)skillsmask;
970  prop.SkillsText = skillstext;
971  prop.Language = languages;
972 
973  string serverURI = string.Empty;
974  GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
975 
976  object Param = prop;
977  if(!rpc.JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString()))
978  {
979  remoteClient.SendAgentAlertMessage(
980  "Error updating interests", false);
981  return;
982  }
983  }
984 
985  public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID)
986  {
987  if (String.IsNullOrEmpty(avatarID.ToString()) || String.IsNullOrEmpty(remoteClient.AgentId.ToString()))
988  {
989  // Looking for a reason that some viewers are sending null Id's
990  m_log.DebugFormat("[PROFILES]: This should not happen remoteClient.AgentId {0} - avatarID {1}", remoteClient.AgentId, avatarID);
991  return;
992  }
993 
994  // Can't handle NPC yet...
995  ScenePresence p = FindPresence(avatarID);
996 
997  if (null != p)
998  {
999  if (p.PresenceType == PresenceType.Npc)
1000  return;
1001  }
1002 
1003  string serverURI = string.Empty;
1004  bool foreign = GetUserProfileServerURI(avatarID, out serverURI);
1005 
1006  UserAccount account = null;
1007  Dictionary<string,object> userInfo;
1008 
1009  if (!foreign)
1010  {
1011  account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, avatarID);
1012  }
1013  else
1014  {
1015  userInfo = new Dictionary<string, object>();
1016  }
1017 
1018  Byte[] charterMember = new Byte[1];
1019  string born = String.Empty;
1020  uint flags = 0x00;
1021 
1022  if (null != account)
1023  {
1024  if (account.UserTitle == "")
1025  {
1026  charterMember[0] = (Byte)((account.UserFlags & 0xf00) >> 8);
1027  }
1028  else
1029  {
1030  charterMember = Utils.StringToBytes(account.UserTitle);
1031  }
1032 
1033  born = Util.ToDateTime(account.Created).ToString(
1034  "M/d/yyyy", CultureInfo.InvariantCulture);
1035  flags = (uint)(account.UserFlags & 0xff);
1036  }
1037  else
1038  {
1039  if (GetUserAccountData(avatarID, out userInfo) == true)
1040  {
1041  if ((string)userInfo["user_title"] == "")
1042  {
1043  charterMember[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8);
1044  }
1045  else
1046  {
1047  charterMember = Utils.StringToBytes((string)userInfo["user_title"]);
1048  }
1049 
1050  int val_born = (int)userInfo["user_created"];
1051  born = Util.ToDateTime(val_born).ToString(
1052  "M/d/yyyy", CultureInfo.InvariantCulture);
1053 
1054  // picky, picky
1055  int val_flags = (int)userInfo["user_flags"];
1056  flags = (uint)(val_flags & 0xff);
1057  }
1058  }
1059 
1061  string result = string.Empty;
1062 
1063  props.UserId = avatarID;
1064 
1065  if (!GetProfileData(ref props, foreign, out result))
1066  {
1067 // m_log.DebugFormat("Error getting profile for {0}: {1}", avatarID, result);
1068  return;
1069  }
1070 
1071  remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, charterMember , props.FirstLifeText, flags,
1072  props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId);
1073 
1074 
1075  remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, (uint)props.SkillsMask,
1076  props.SkillsText, props.Language);
1077  }
1078 
1088  public void AvatarPropertiesUpdate(IClientAPI remoteClient, UserProfileData newProfile)
1089  {
1090  if (remoteClient.AgentId == newProfile.ID)
1091  {
1093 
1094  prop.UserId = remoteClient.AgentId;
1095  prop.WebUrl = newProfile.ProfileUrl;
1096  prop.ImageId = newProfile.Image;
1097  prop.AboutText = newProfile.AboutText;
1098  prop.FirstLifeImageId = newProfile.FirstLifeImage;
1099  prop.FirstLifeText = newProfile.FirstLifeAboutText;
1100 
1101  string serverURI = string.Empty;
1102  GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
1103 
1104  object Prop = prop;
1105 
1106  if(!rpc.JsonRpcRequest(ref Prop, "avatar_properties_update", serverURI, UUID.Random().ToString()))
1107  {
1108  remoteClient.SendAgentAlertMessage(
1109  "Error updating properties", false);
1110  return;
1111  }
1112 
1113  RequestAvatarProperties(remoteClient, newProfile.ID);
1114  }
1115  }
1116 
1123  bool GetProfileData(ref UserProfileProperties properties, bool foreign, out string message)
1124  {
1125  // Can't handle NPC yet...
1126  ScenePresence p = FindPresence(properties.UserId);
1127 
1128  if (null != p)
1129  {
1130  if (p.PresenceType == PresenceType.Npc)
1131  {
1132  message = "Id points to NPC";
1133  return false;
1134  }
1135  }
1136 
1137  string serverURI = string.Empty;
1138  GetUserProfileServerURI(properties.UserId, out serverURI);
1139 
1140  // This is checking a friend on the home grid
1141  // Not HG friend
1142  if (String.IsNullOrEmpty(serverURI))
1143  {
1144  message = "No Presence - foreign friend";
1145  return false;
1146  }
1147 
1148  object Prop = (object)properties;
1149  if (!rpc.JsonRpcRequest(ref Prop, "avatar_properties_request", serverURI, UUID.Random().ToString()))
1150  {
1151  // If it's a foreign user then try again using OpenProfile, in case that's what the grid is using
1152  bool secondChanceSuccess = false;
1153  if (foreign)
1154  {
1155  try
1156  {
1157  OpenProfileClient client = new OpenProfileClient(serverURI);
1158  if (client.RequestAvatarPropertiesUsingOpenProfile(ref properties))
1159  secondChanceSuccess = true;
1160  }
1161  catch (Exception e)
1162  {
1163  m_log.Debug(
1164  string.Format(
1165  "[PROFILES]: Request using the OpenProfile API for user {0} to {1} failed",
1166  properties.UserId, serverURI),
1167  e);
1168 
1169  // Allow the return 'message' to say "JsonRpcRequest" and not "OpenProfile", because
1170  // the most likely reason that OpenProfile failed is that the remote server
1171  // doesn't support OpenProfile, and that's not very interesting.
1172  }
1173  }
1174 
1175  if (!secondChanceSuccess)
1176  {
1177  message = string.Format("JsonRpcRequest for user {0} to {1} failed", properties.UserId, serverURI);
1178  m_log.DebugFormat("[PROFILES]: {0}", message);
1179 
1180  return false;
1181  }
1182  // else, continue below
1183  }
1184 
1185  properties = (UserProfileProperties)Prop;
1186 
1187  message = "Success";
1188  return true;
1189  }
1190  #endregion Avatar Properties
1191 
1192  #region Utils
1193  bool GetImageAssets(UUID avatarId)
1194  {
1195  string profileServerURI = string.Empty;
1196  string assetServerURI = string.Empty;
1197 
1198  bool foreign = GetUserProfileServerURI(avatarId, out profileServerURI);
1199 
1200  if(!foreign)
1201  return true;
1202 
1203  assetServerURI = UserManagementModule.GetUserServerURL(avatarId, "AssetServerURI");
1204 
1205  if(string.IsNullOrEmpty(profileServerURI) || string.IsNullOrEmpty(assetServerURI))
1206  return false;
1207 
1208  OSDMap parameters= new OSDMap();
1209  parameters.Add("avatarId", OSD.FromUUID(avatarId));
1210  OSD Params = (OSD)parameters;
1211  if(!rpc.JsonRpcRequest(ref Params, "image_assets_request", profileServerURI, UUID.Random().ToString()))
1212  {
1213  return false;
1214  }
1215 
1216  parameters = (OSDMap)Params;
1217 
1218  if (parameters.ContainsKey("result"))
1219  {
1220  OSDArray list = (OSDArray)parameters["result"];
1221 
1222  foreach (OSD asset in list)
1223  {
1224  OSDString assetId = (OSDString)asset;
1225 
1226  Scene.AssetService.Get(string.Format("{0}/{1}", assetServerURI, assetId.AsString()));
1227  }
1228  return true;
1229  }
1230  else
1231  {
1232  m_log.ErrorFormat("[PROFILES]: Problematic response for image_assets_request from {0}", profileServerURI);
1233  return false;
1234  }
1235  }
1236 
1249  bool GetUserAccountData(UUID userID, out Dictionary<string, object> userInfo)
1250  {
1251  Dictionary<string,object> info = new Dictionary<string, object>();
1252 
1253  if (UserManagementModule.IsLocalGridUser(userID))
1254  {
1255  // Is local
1256  IUserAccountService uas = Scene.UserAccountService;
1257  UserAccount account = uas.GetUserAccount(Scene.RegionInfo.ScopeID, userID);
1258 
1259  info["user_flags"] = account.UserFlags;
1260  info["user_created"] = account.Created;
1261 
1262  if (!String.IsNullOrEmpty(account.UserTitle))
1263  info["user_title"] = account.UserTitle;
1264  else
1265  info["user_title"] = "";
1266 
1267  userInfo = info;
1268 
1269  return false;
1270  }
1271  else
1272  {
1273  // Is Foreign
1274  string home_url = UserManagementModule.GetUserServerURL(userID, "HomeURI");
1275 
1276  if (String.IsNullOrEmpty(home_url))
1277  {
1278  info["user_flags"] = 0;
1279  info["user_created"] = 0;
1280  info["user_title"] = "Unavailable";
1281 
1282  userInfo = info;
1283  return true;
1284  }
1285 
1287 
1288  Dictionary<string, object> account;
1289  try
1290  {
1291  account = uConn.GetUserInfo(userID);
1292  }
1293  catch (Exception e)
1294  {
1295  m_log.Debug("[PROFILES]: GetUserInfo call failed ", e);
1296  account = new Dictionary<string, object>();
1297  }
1298 
1299  if (account.Count > 0)
1300  {
1301  if (account.ContainsKey("user_flags"))
1302  info["user_flags"] = account["user_flags"];
1303  else
1304  info["user_flags"] = "";
1305 
1306  if (account.ContainsKey("user_created"))
1307  info["user_created"] = account["user_created"];
1308  else
1309  info["user_created"] = "";
1310 
1311  info["user_title"] = "HG Visitor";
1312  }
1313  else
1314  {
1315  info["user_flags"] = 0;
1316  info["user_created"] = 0;
1317  info["user_title"] = "HG Visitor";
1318  }
1319  userInfo = info;
1320  return true;
1321  }
1322  }
1323 
1336  bool GetUserGatekeeperURI(UUID userID, out string serverURI)
1337  {
1338  bool local;
1339  local = UserManagementModule.IsLocalGridUser(userID);
1340 
1341  if (!local)
1342  {
1343  serverURI = UserManagementModule.GetUserServerURL(userID, "GatekeeperURI");
1344  // Is Foreign
1345  return true;
1346  }
1347  else
1348  {
1349  serverURI = MyGatekeeper;
1350  // Is local
1351  return false;
1352  }
1353  }
1354 
1367  bool GetUserProfileServerURI(UUID userID, out string serverURI)
1368  {
1369  bool local;
1370  local = UserManagementModule.IsLocalGridUser(userID);
1371 
1372  if (!local)
1373  {
1374  serverURI = UserManagementModule.GetUserServerURL(userID, "ProfileServerURI");
1375  // Is Foreign
1376  return true;
1377  }
1378  else
1379  {
1380  serverURI = ProfileServerUri;
1381  // Is local
1382  return false;
1383  }
1384  }
1385 
1395  ScenePresence FindPresence(UUID clientID)
1396  {
1397  ScenePresence p;
1398 
1399  p = Scene.GetScenePresence(clientID);
1400  if (p != null && !p.IsChildAgent)
1401  return p;
1402 
1403  return null;
1404  }
1405  #endregion Util
1406 
1407  #region Web Util
1408  bool JsonRpcRequest(ref object parameters, string method, string uri, string jsonId)
1427  {
1428  if (jsonId == null)
1429  throw new ArgumentNullException ("jsonId");
1430  if (uri == null)
1431  throw new ArgumentNullException ("uri");
1432  if (method == null)
1433  throw new ArgumentNullException ("method");
1434  if (parameters == null)
1435  throw new ArgumentNullException ("parameters");
1436 
1437  // Prep our payload
1438  OSDMap json = new OSDMap();
1439 
1440  json.Add("jsonrpc", OSD.FromString("2.0"));
1441  json.Add("id", OSD.FromString(jsonId));
1442  json.Add("method", OSD.FromString(method));
1443 
1444  json.Add("params", OSD.SerializeMembers(parameters));
1445 
1446  string jsonRequestData = OSDParser.SerializeJsonString(json);
1447  byte[] content = Encoding.UTF8.GetBytes(jsonRequestData);
1448 
1449  HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
1450 
1451  webRequest.ContentType = "application/json-rpc";
1452  webRequest.Method = "POST";
1453 
1454  Stream dataStream = webRequest.GetRequestStream();
1455  dataStream.Write(content, 0, content.Length);
1456  dataStream.Close();
1457 
1458  WebResponse webResponse = null;
1459  try
1460  {
1461  webResponse = webRequest.GetResponse();
1462  }
1463  catch (WebException e)
1464  {
1465  Console.WriteLine("Web Error" + e.Message);
1466  Console.WriteLine ("Please check input");
1467  return false;
1468  }
1469 
1470  OSDMap mret = new OSDMap();
1471 
1472  using (Stream rstream = webResponse.GetResponseStream())
1473  {
1474  try
1475  {
1476  mret = (OSDMap)OSDParser.DeserializeJson(rstream);
1477  }
1478  catch (Exception e)
1479  {
1480  m_log.DebugFormat("[PROFILES]: JsonRpcRequest Error {0} - remote user with legacy profiles?", e.Message);
1481  if (webResponse != null)
1482  webResponse.Close();
1483  return false;
1484  }
1485  }
1486 
1487  if (webResponse != null)
1488  webResponse.Close();
1489 
1490  if (mret.ContainsKey("error"))
1491  return false;
1492 
1493  // get params...
1494  OSD.DeserializeMembers(ref parameters, (OSDMap) mret["result"]);
1495  return true;
1496  }
1497 
1516  bool JsonRpcRequest(ref OSD data, string method, string uri, string jsonId)
1517  {
1518  OSDMap map = new OSDMap();
1519 
1520  map["jsonrpc"] = "2.0";
1521  if(string.IsNullOrEmpty(jsonId))
1522  map["id"] = UUID.Random().ToString();
1523  else
1524  map["id"] = jsonId;
1525 
1526  map["method"] = method;
1527  map["params"] = data;
1528 
1529  string jsonRequestData = OSDParser.SerializeJsonString(map);
1530  byte[] content = Encoding.UTF8.GetBytes(jsonRequestData);
1531 
1532  HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
1533  webRequest.ContentType = "application/json-rpc";
1534  webRequest.Method = "POST";
1535 
1536  Stream dataStream = webRequest.GetRequestStream();
1537  dataStream.Write(content, 0, content.Length);
1538  dataStream.Close();
1539 
1540  WebResponse webResponse = null;
1541  try
1542  {
1543  webResponse = webRequest.GetResponse();
1544  }
1545  catch (WebException e)
1546  {
1547  Console.WriteLine("Web Error" + e.Message);
1548  Console.WriteLine ("Please check input");
1549  return false;
1550  }
1551 
1552  OSDMap response = new OSDMap();
1553 
1554  using (Stream rstream = webResponse.GetResponseStream())
1555  {
1556  try
1557  {
1558  response = (OSDMap)OSDParser.DeserializeJson(rstream);
1559  }
1560  catch (Exception e)
1561  {
1562  m_log.DebugFormat("[PROFILES]: JsonRpcRequest Error {0} - remote user with legacy profiles?", e.Message);
1563  if (webResponse != null)
1564  webResponse.Close();
1565  return false;
1566  }
1567  }
1568 
1569  if (webResponse != null)
1570  webResponse.Close();
1571 
1572  if(response.ContainsKey("error"))
1573  {
1574  data = response["error"];
1575  return false;
1576  }
1577 
1578  data = response;
1579 
1580  return true;
1581  }
1582  #endregion Web Util
1583  }
1584 }
RegionInfo RegionInfo
Definition: IScene.cs:64
void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient)
Classifieds delete.
delegate void PickInfoUpdate(IClientAPI client, UUID pickID, UUID creatorID, bool topPick, string name, string desc, UUID snapshotID, int sortOrder, bool enabled)
OpenMetaverse.StructuredData.OSDArray OSDArray
void PickDelete(IClientAPI remoteClient, UUID queryPickID)
Delete a Pick
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
OpenMetaverse.StructuredData.OSDMap OSDMap
delegate void ClassifiedInfoUpdate(UUID classifiedID, uint category, string name, string description, UUID parcelID, uint parentEstate, UUID snapshotID, Vector3 globalPos, byte classifiedFlags, int price, IClientAPI client)
OpenSim.Services.Interfaces.GridRegion GridRegion
A client for accessing a profile server using the OpenProfile protocol.
PresenceType
Indicate the type of ScenePresence.
Definition: PresenceType.cs:34
bool RequestAvatarPropertiesUsingOpenProfile(ref UserProfileProperties props)
Gets an avatar's profile using the OpenProfile protocol.
void ClassifiedInfoRequest(UUID queryClassifiedID, IClientAPI remoteClient)
void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID)
Information about a particular user known to the userserver
OpenMetaverse.StructuredData.OSD OSD
void PickInfoUpdate(IClientAPI remoteClient, UUID pickID, UUID creatorID, bool topPick, string name, string desc, UUID snapshotID, int sortOrder, bool enabled)
Updates the userpicks
void ClassifiedInfoUpdate(UUID queryclassifiedID, uint queryCategory, string queryName, string queryDescription, UUID queryParcelID, uint queryParentEstate, UUID querySnapshotID, Vector3 queryGlobalPos, byte queryclassifiedFlags, int queryclassifiedPrice, IClientAPI remoteClient)
Classifieds info update.
Interactive OpenSim region server
Definition: OpenSim.cs:55
void PickInfoRequest(Object sender, string method, List< String > args)
Handles the pick info request.
delegate void ClassifiedDelete(UUID classifiedID, IClientAPI client)
delegate void ClassifiedInfoRequest(UUID classifiedID, IClientAPI client)
delegate void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID)
delegate void PickDelete(IClientAPI client, UUID pickID)
void NotesUpdate(IClientAPI remoteClient, UUID queryTargetID, string queryNotes)
Avatars the notes update.
void UserPreferencesRequest(IClientAPI remoteClient)
Users the preferences request.
void AvatarPropertiesUpdate(IClientAPI remoteClient, UserProfileData newProfile)
Updates the avatar properties.
This maintains the relationship between a UUID and a user name.