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