123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478 |
- /*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSimulator Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- using System;
- using System.Collections.Generic;
- using System.Collections.Specialized;
- using System.Reflection;
- using log4net;
- using Mono.Addins;
- using Nini.Config;
- using OpenMetaverse;
- using OpenMetaverse.StructuredData;
- using OpenSim.Framework;
- using OpenSim.Framework.Client;
- using OpenSim.Region.Framework.Interfaces;
- using OpenSim.Region.Framework.Scenes;
- using OpenSim.Services.Interfaces;
- namespace OpenSim.Services.Connectors.SimianGrid
- {
- /// <summary>
- /// Avatar profile flags
- /// </summary>
- [Flags]
- public enum ProfileFlags : uint
- {
- AllowPublish = 1,
- MaturePublish = 2,
- Identified = 4,
- Transacted = 8,
- Online = 16
- }
- /// <summary>
- /// Connects avatar profile and classified queries to the SimianGrid
- /// backend
- /// </summary>
- [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianProfiles")]
- public class SimianProfiles : INonSharedRegionModule
- {
- private static readonly ILog m_log =
- LogManager.GetLogger(
- MethodBase.GetCurrentMethod().DeclaringType);
- private string m_serverUrl = String.Empty;
- private bool m_Enabled = false;
- #region INonSharedRegionModule
- public Type ReplaceableInterface { get { return null; } }
- public void RegionLoaded(Scene scene) { }
- public void Close() { }
- public SimianProfiles() { }
- public string Name { get { return "SimianProfiles"; } }
- public void AddRegion(Scene scene)
- {
- if (m_Enabled)
- {
- CheckEstateManager(scene);
- scene.EventManager.OnClientConnect += ClientConnectHandler;
- }
- }
- public void RemoveRegion(Scene scene)
- {
- if (m_Enabled)
- {
- scene.EventManager.OnClientConnect -= ClientConnectHandler;
- }
- }
- #endregion INonSharedRegionModule
- public SimianProfiles(IConfigSource source)
- {
- Initialise(source);
- }
- public void Initialise(IConfigSource source)
- {
- IConfig profileConfig = source.Configs["Profiles"];
- if (profileConfig == null)
- return;
- if (profileConfig.GetString("Module", String.Empty) != Name)
- return;
- m_log.DebugFormat("[SIMIAN PROFILES] module enabled");
- m_Enabled = true;
- IConfig gridConfig = source.Configs["UserAccountService"];
- if (gridConfig != null)
- {
- string serviceUrl = gridConfig.GetString("UserAccountServerURI");
- if (!String.IsNullOrEmpty(serviceUrl))
- {
- if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
- serviceUrl = serviceUrl + '/';
- m_serverUrl = serviceUrl;
- }
- }
- if (String.IsNullOrEmpty(m_serverUrl))
- m_log.Info("[SIMIAN PROFILES]: No UserAccountServerURI specified, disabling connector");
- }
- private void ClientConnectHandler(IClientCore clientCore)
- {
- if (clientCore is IClientAPI)
- {
- IClientAPI client = (IClientAPI)clientCore;
- // Classifieds
- client.AddGenericPacketHandler("avatarclassifiedsrequest", AvatarClassifiedsRequestHandler);
- client.OnClassifiedInfoRequest += ClassifiedInfoRequestHandler;
- client.OnClassifiedInfoUpdate += ClassifiedInfoUpdateHandler;
- client.OnClassifiedDelete += ClassifiedDeleteHandler;
- // Picks
- client.AddGenericPacketHandler("avatarpicksrequest", HandleAvatarPicksRequest);
- client.AddGenericPacketHandler("pickinforequest", HandlePickInfoRequest);
- client.OnPickInfoUpdate += PickInfoUpdateHandler;
- client.OnPickDelete += PickDeleteHandler;
- // Notes
- client.AddGenericPacketHandler("avatarnotesrequest", HandleAvatarNotesRequest);
- client.OnAvatarNotesUpdate += AvatarNotesUpdateHandler;
- // Profiles
- client.OnRequestAvatarProperties += RequestAvatarPropertiesHandler;
- client.OnUpdateAvatarProperties += UpdateAvatarPropertiesHandler;
- client.OnAvatarInterestUpdate += AvatarInterestUpdateHandler;
- client.OnUserInfoRequest += UserInfoRequestHandler;
- client.OnUpdateUserInfo += UpdateUserInfoHandler;
- }
- }
- #region Classifieds
- private void AvatarClassifiedsRequestHandler(Object sender, string method, List<String> args)
- {
- if (!(sender is IClientAPI))
- return;
- IClientAPI client = (IClientAPI)sender;
- UUID targetAvatarID;
- if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID))
- {
- m_log.Error("[SIMIAN PROFILES]: Unrecognized arguments for " + method);
- return;
- }
- // FIXME: Query the generic key/value store for classifieds
- client.SendAvatarClassifiedReply(targetAvatarID, new Dictionary<UUID, string>(0));
- }
- private void ClassifiedInfoRequestHandler(UUID classifiedID, IClientAPI client)
- {
- // FIXME: Fetch this info
- client.SendClassifiedInfoReply(classifiedID, UUID.Zero, 0, Utils.DateTimeToUnixTime(DateTime.UtcNow + TimeSpan.FromDays(1)),
- 0, String.Empty, String.Empty, UUID.Zero, 0, UUID.Zero, String.Empty, Vector3.Zero, String.Empty, 0, 0);
- }
- private void ClassifiedInfoUpdateHandler(UUID classifiedID, uint category, string name, string description,
- UUID parcelID, uint parentEstate, UUID snapshotID, Vector3 globalPos, byte classifiedFlags, int price,
- IClientAPI client)
- {
- // FIXME: Save this info
- }
- private void ClassifiedDeleteHandler(UUID classifiedID, IClientAPI client)
- {
- // FIXME: Delete the specified classified ad
- }
- #endregion Classifieds
- #region Picks
- private void HandleAvatarPicksRequest(Object sender, string method, List<String> args)
- {
- if (!(sender is IClientAPI))
- return;
- IClientAPI client = (IClientAPI)sender;
- UUID targetAvatarID;
- if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID))
- {
- m_log.Error("[SIMIAN PROFILES]: Unrecognized arguments for " + method);
- return;
- }
- // FIXME: Fetch these
- client.SendAvatarPicksReply(targetAvatarID, new Dictionary<UUID, string>(0));
- }
- private void HandlePickInfoRequest(Object sender, string method, List<String> args)
- {
- if (!(sender is IClientAPI))
- return;
- IClientAPI client = (IClientAPI)sender;
- UUID avatarID;
- UUID pickID;
- if (args.Count < 2 || !UUID.TryParse(args[0], out avatarID) || !UUID.TryParse(args[1], out pickID))
- {
- m_log.Error("[SIMIAN PROFILES]: Unrecognized arguments for " + method);
- return;
- }
- // FIXME: Fetch this
- client.SendPickInfoReply(pickID, avatarID, false, UUID.Zero, String.Empty, String.Empty, UUID.Zero, String.Empty,
- String.Empty, String.Empty, Vector3.Zero, 0, false);
- }
- private void PickInfoUpdateHandler(IClientAPI client, UUID pickID, UUID creatorID, bool topPick, string name,
- string desc, UUID snapshotID, int sortOrder, bool enabled)
- {
- // FIXME: Save this
- }
- private void PickDeleteHandler(IClientAPI client, UUID pickID)
- {
- // FIXME: Delete
- }
- #endregion Picks
- #region Notes
- private void HandleAvatarNotesRequest(Object sender, string method, List<String> args)
- {
- if (!(sender is IClientAPI))
- return;
- IClientAPI client = (IClientAPI)sender;
- UUID targetAvatarID;
- if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID))
- {
- m_log.Error("[SIMIAN PROFILES]: Unrecognized arguments for " + method);
- return;
- }
- // FIXME: Fetch this
- client.SendAvatarNotesReply(targetAvatarID, String.Empty);
- }
- private void AvatarNotesUpdateHandler(IClientAPI client, UUID targetID, string notes)
- {
- // FIXME: Save this
- }
- #endregion Notes
- #region Profiles
- private void RequestAvatarPropertiesHandler(IClientAPI client, UUID avatarID)
- {
- m_log.DebugFormat("[SIMIAN PROFILES]: Request avatar properties for {0}",avatarID);
- OSDMap user = FetchUserData(avatarID);
- ProfileFlags flags = ProfileFlags.AllowPublish | ProfileFlags.MaturePublish;
- if (user != null)
- {
- OSDMap about = null;
- if (user.ContainsKey("LLAbout"))
- {
- try
- {
- about = OSDParser.DeserializeJson(user["LLAbout"].AsString()) as OSDMap;
- }
- catch
- {
- m_log.WarnFormat("[SIMIAN PROFILES]: Unable to decode LLAbout");
- }
- }
- if (about == null)
- about = new OSDMap(0);
- // Check if this user is a grid operator
- byte[] membershipType;
- if (user["AccessLevel"].AsInteger() >= 200)
- membershipType = Utils.StringToBytes("Operator");
- else
- membershipType = Utils.EmptyBytes;
- // Check if the user is online
- if (client.Scene is Scene)
- {
- OpenSim.Services.Interfaces.PresenceInfo[] presences = ((Scene)client.Scene).PresenceService.GetAgents(new string[] { avatarID.ToString() });
- if (presences != null && presences.Length > 0)
- flags |= ProfileFlags.Online;
- }
- // Check if the user is identified
- if (user["Identified"].AsBoolean())
- flags |= ProfileFlags.Identified;
- client.SendAvatarProperties(avatarID, about["About"].AsString(), user["CreationDate"].AsDate().ToString("M/d/yyyy",
- System.Globalization.CultureInfo.InvariantCulture), membershipType, about["FLAbout"].AsString(), (uint)flags,
- about["FLImage"].AsUUID(), about["Image"].AsUUID(), about["URL"].AsString(), user["Partner"].AsUUID());
- OSDMap interests = null;
- if (user.ContainsKey("LLInterests"))
- {
- try
- {
- interests = OSDParser.DeserializeJson(user["LLInterests"].AsString()) as OSDMap;
- client.SendAvatarInterestsReply(avatarID, interests["WantMask"].AsUInteger(), interests["WantText"].AsString(), interests["SkillsMask"].AsUInteger(), interests["SkillsText"].AsString(), interests["Languages"].AsString());
- }
- catch { }
- }
- if (about == null)
- about = new OSDMap(0);
- }
- else
- {
- m_log.Warn("[SIMIAN PROFILES]: Failed to fetch profile information for " + client.Name + ", returning default values");
- client.SendAvatarProperties(avatarID, String.Empty, "1/1/1970", Utils.EmptyBytes,
- String.Empty, (uint)flags, UUID.Zero, UUID.Zero, String.Empty, UUID.Zero);
- }
- }
- private void UpdateAvatarPropertiesHandler(IClientAPI client, UserProfileData profileData)
- {
- OSDMap map = new OSDMap
- {
- { "About", OSD.FromString(profileData.AboutText) },
- { "Image", OSD.FromUUID(profileData.Image) },
- { "FLAbout", OSD.FromString(profileData.FirstLifeAboutText) },
- { "FLImage", OSD.FromUUID(profileData.FirstLifeImage) },
- { "URL", OSD.FromString(profileData.ProfileUrl) }
- };
- AddUserData(client.AgentId, "LLAbout", map);
- }
- private void AvatarInterestUpdateHandler(IClientAPI client, uint wantmask, string wanttext, uint skillsmask,
- string skillstext, string languages)
- {
- OSDMap map = new OSDMap
- {
- { "WantMask", OSD.FromInteger(wantmask) },
- { "WantText", OSD.FromString(wanttext) },
- { "SkillsMask", OSD.FromInteger(skillsmask) },
- { "SkillsText", OSD.FromString(skillstext) },
- { "Languages", OSD.FromString(languages) }
- };
- AddUserData(client.AgentId, "LLInterests", map);
- }
- private void UserInfoRequestHandler(IClientAPI client)
- {
- m_log.Error("[SIMIAN PROFILES]: UserInfoRequestHandler");
- // Fetch this user's e-mail address
- NameValueCollection requestArgs = new NameValueCollection
- {
- { "RequestMethod", "GetUser" },
- { "UserID", client.AgentId.ToString() }
- };
- OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
- string email = response["Email"].AsString();
- if (!response["Success"].AsBoolean())
- m_log.Warn("[SIMIAN PROFILES]: GetUser failed during a user info request for " + client.Name);
- client.SendUserInfoReply(false, true, email);
- }
- private void UpdateUserInfoHandler(bool imViaEmail, bool visible, IClientAPI client)
- {
- m_log.Info("[SIMIAN PROFILES]: Ignoring user info update from " + client.Name);
- }
- #endregion Profiles
- /// <summary>
- /// Sanity checks regions for a valid estate owner at startup
- /// </summary>
- private void CheckEstateManager(Scene scene)
- {
- EstateSettings estate = scene.RegionInfo.EstateSettings;
- if (estate.EstateOwner == UUID.Zero)
- {
- // Attempt to lookup the grid admin
- UserAccount admin = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, UUID.Zero);
- if (admin != null)
- {
- m_log.InfoFormat("[SIMIAN PROFILES]: Setting estate {0} (ID: {1}) owner to {2}", estate.EstateName,
- estate.EstateID, admin.Name);
- estate.EstateOwner = admin.PrincipalID;
- scene.EstateDataService.StoreEstateSettings(estate);
- }
- else
- {
- m_log.WarnFormat("[SIMIAN PROFILES]: Estate {0} (ID: {1}) does not have an owner", estate.EstateName, estate.EstateID);
- }
- }
- }
- private bool AddUserData(UUID userID, string key, OSDMap value)
- {
- NameValueCollection requestArgs = new NameValueCollection
- {
- { "RequestMethod", "AddUserData" },
- { "UserID", userID.ToString() },
- { key, OSDParser.SerializeJsonString(value) }
- };
- OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
- bool success = response["Success"].AsBoolean();
- if (!success)
- m_log.WarnFormat("[SIMIAN PROFILES]: Failed to add user data with key {0} for {1}: {2}", key, userID, response["Message"].AsString());
- return success;
- }
- private OSDMap FetchUserData(UUID userID)
- {
- m_log.DebugFormat("[SIMIAN PROFILES]: Fetch information about {0}",userID);
- NameValueCollection requestArgs = new NameValueCollection
- {
- { "RequestMethod", "GetUser" },
- { "UserID", userID.ToString() }
- };
- OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
- if (response["Success"].AsBoolean() && response["User"] is OSDMap)
- {
- return (OSDMap)response["User"];
- }
- else
- {
- m_log.Error("[SIMIAN PROFILES]: Failed to fetch user data for " + userID + ": " + response["Message"].AsString());
- }
- return null;
- }
- }
- }
|