From e92c05ebbdc44084326c3dcfa0a2ca0958e4b5e6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 7 May 2013 18:01:48 -0700 Subject: [PATCH] Added AvatarPickerSearch capability handler. --- .../AvatarPickerSearchHandler.cs | 116 +++++++++++++++ OpenSim/Capabilities/LLSDAvatarPicker.cs | 51 +++++++ OpenSim/Framework/IPeople.cs | 47 ++++++ .../Linden/Caps/AvatarPickerSearchModule.cs | 140 ++++++++++++++++++ .../UserManagement/HGUserManagementModule.cs | 2 +- .../UserManagement/UserManagementModule.cs | 72 ++++----- bin/OpenSim.ini.example | 4 +- bin/OpenSimDefaults.ini | 4 + 8 files changed, 400 insertions(+), 36 deletions(-) create mode 100644 OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs create mode 100644 OpenSim/Capabilities/LLSDAvatarPicker.cs create mode 100644 OpenSim/Framework/IPeople.cs create mode 100644 OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs diff --git a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs new file mode 100644 index 0000000000..4dca59231e --- /dev/null +++ b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs @@ -0,0 +1,116 @@ +/* + * 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.IO; +using System.Reflection; +using System.Web; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +//using OpenSim.Region.Framework.Interfaces; +using OpenSim.Services.Interfaces; +using Caps = OpenSim.Framework.Capabilities.Caps; + +namespace OpenSim.Capabilities.Handlers +{ + public class AvatarPickerSearchHandler : BaseStreamHandler + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private IPeople m_PeopleService; + + public AvatarPickerSearchHandler(string path, IPeople peopleService, string name, string description) + : base("GET", path, name, description) + { + m_PeopleService = peopleService; + } + + public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + // Try to parse the texture ID from the request URL + NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); + string names = query.GetOne("names"); + string psize = query.GetOne("page_size"); + string pnumber = query.GetOne("page"); + + if (m_PeopleService == null) + return FailureResponse(names, (int)System.Net.HttpStatusCode.InternalServerError, httpResponse); + + if (string.IsNullOrEmpty(names) || names.Length < 3) + return FailureResponse(names, (int)System.Net.HttpStatusCode.BadRequest, httpResponse); + + m_log.DebugFormat("[AVATAR PICKER SEARCH]: search for {0}", names); + + int page_size = (string.IsNullOrEmpty(psize) ? 500 : Int32.Parse(psize)); + int page_number = (string.IsNullOrEmpty(pnumber) ? 1 : Int32.Parse(pnumber)); + + // Full content request + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK; + //httpResponse.ContentLength = ??; + httpResponse.ContentType = "application/llsd+xml"; + + List users = m_PeopleService.GetUserData(names, page_size, page_number); + + LLSDAvatarPicker osdReply = new LLSDAvatarPicker(); + osdReply.next_page_url = httpRequest.RawUrl; + foreach (UserData u in users) + osdReply.agents.Array.Add(ConvertUserData(u)); + + string reply = LLSDHelpers.SerialiseLLSDReply(osdReply); + return System.Text.Encoding.UTF8.GetBytes(reply); + } + + private LLSDPerson ConvertUserData(UserData user) + { + LLSDPerson p = new LLSDPerson(); + p.legacy_first_name = user.FirstName; + p.legacy_last_name = user.LastName; + p.display_name = user.FirstName + " " + user.LastName; + if (user.LastName.StartsWith("@")) + p.username = user.FirstName.ToLower() + user.LastName.ToLower(); + else + p.username = user.FirstName.ToLower() + "." + user.LastName.ToLower(); + p.id = user.Id; + p.is_display_name_default = false; + return p; + } + + private byte[] FailureResponse(string names, int statuscode, IOSHttpResponse httpResponse) + { + m_log.Error("[AVATAR PICKER SEARCH]: Error searching for " + names); + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return System.Text.Encoding.UTF8.GetBytes(string.Empty); + } + } +} \ No newline at end of file diff --git a/OpenSim/Capabilities/LLSDAvatarPicker.cs b/OpenSim/Capabilities/LLSDAvatarPicker.cs new file mode 100644 index 0000000000..d0b3f3a5ec --- /dev/null +++ b/OpenSim/Capabilities/LLSDAvatarPicker.cs @@ -0,0 +1,51 @@ +/* + * 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 OpenMetaverse; + +namespace OpenSim.Framework.Capabilities +{ + [OSDMap] + public class LLSDAvatarPicker + { + public string next_page_url; + // an array of LLSDPerson + public OSDArray agents = new OSDArray(); + } + + [OSDMap] + public class LLSDPerson + { + public string username; + public string display_name; + //'display_name_next_update':d"1970-01-01T00:00:00Z" + public string legacy_first_name; + public string legacy_last_name; + public UUID id; + public bool is_display_name_default; + } +} \ No newline at end of file diff --git a/OpenSim/Framework/IPeople.cs b/OpenSim/Framework/IPeople.cs new file mode 100644 index 0000000000..b88e1039e6 --- /dev/null +++ b/OpenSim/Framework/IPeople.cs @@ -0,0 +1,47 @@ +/* + * 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 OpenMetaverse; + +namespace OpenSim.Framework +{ + public class UserData + { + public UUID Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string HomeURL { get; set; } + public Dictionary ServerURLs { get; set; } + } + + public interface IPeople + { + List GetUserData(string query, int page_size, int page_number); + } +} \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs new file mode 100644 index 0000000000..d7af1f29a0 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs @@ -0,0 +1,140 @@ +/* + * 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; +using System.Collections.Specialized; +using System.Drawing; +using System.Drawing.Imaging; +using System.Reflection; +using System.IO; +using System.Web; +using log4net; +using Nini.Config; +using Mono.Addins; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using Caps = OpenSim.Framework.Capabilities.Caps; +using OpenSim.Capabilities.Handlers; + +namespace OpenSim.Region.ClientStack.Linden +{ + + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AvatarPickerSearchModule")] + public class AvatarPickerSearchModule : INonSharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Scene m_scene; + private IPeople m_People; + private bool m_Enabled = false; + + private string m_URL; + + #region ISharedRegionModule Members + + public void Initialise(IConfigSource source) + { + IConfig config = source.Configs["ClientStack.LindenCaps"]; + if (config == null) + return; + + m_URL = config.GetString("Cap_AvatarPickerSearch", string.Empty); + m_log.DebugFormat("[XXX]: Cap_AvatarPickerSearch = {0}", m_URL); + // Cap doesn't exist + if (m_URL != string.Empty) + m_Enabled = true; + } + + public void AddRegion(Scene s) + { + if (!m_Enabled) + return; + + m_scene = s; + } + + public void RemoveRegion(Scene s) + { + if (!m_Enabled) + return; + + m_scene.EventManager.OnRegisterCaps -= RegisterCaps; + m_scene = null; + } + + public void RegionLoaded(Scene s) + { + if (!m_Enabled) + return; + + m_People = m_scene.RequestModuleInterface(); + m_scene.EventManager.OnRegisterCaps += RegisterCaps; + } + + public void PostInitialise() + { + } + + public void Close() { } + + public string Name { get { return "AvatarPickerSearchModule"; } } + + public Type ReplaceableInterface + { + get { return null; } + } + + #endregion + + public void RegisterCaps(UUID agentID, Caps caps) + { + UUID capID = UUID.Random(); + + if (m_URL == "localhost") + { + m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); + caps.RegisterHandler( + "AvatarPickerSearch", + new AvatarPickerSearchHandler("/CAPS/" + capID + "/", m_People, "AvatarPickerSearch", "Search for avatars by name")); + } + else + { + // m_log.DebugFormat("[AVATAR PICKER SEARCH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); + caps.RegisterHandler("AvatarPickerSearch", m_URL); + } + } + + } +} diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs index 8ce20e9950..fac93e63bb 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs @@ -70,7 +70,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #endregion ISharedRegionModule - protected override void AddAdditionalUsers(UUID avatarID, string query, List users) + protected override void AddAdditionalUsers(string query, List users) { if (query.Contains("@")) // First.Last@foo.com, maybe? { diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 7b823ba8f0..6847e572fb 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -46,17 +46,8 @@ using Mono.Addins; namespace OpenSim.Region.CoreModules.Framework.UserManagement { - public class UserData - { - public UUID Id { get; set; } - public string FirstName { get; set; } - public string LastName { get; set; } - public string HomeURL { get; set; } - public Dictionary ServerURLs { get; set; } - } - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")] - public class UserManagementModule : ISharedRegionModule, IUserManagement + public class UserManagementModule : ISharedRegionModule, IUserManagement, IPeople { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -101,6 +92,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement m_Scenes.Add(scene); scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient); scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded); } @@ -181,29 +173,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); - // searhc the user accounts service - List accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); - - List users = new List(); - if (accs != null) - { - foreach (UserAccount acc in accs) - { - UserData ud = new UserData(); - ud.FirstName = acc.FirstName; - ud.LastName = acc.LastName; - ud.Id = acc.PrincipalID; - users.Add(ud); - } - } - - // search the local cache - foreach (UserData data in m_UserCache.Values) - if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null && - (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower()))) - users.Add(data); - - AddAdditionalUsers(avatarID, query, users); + List users = GetUserData(query, 500, 1); AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); // TODO: don't create new blocks if recycling an old packet @@ -249,12 +219,46 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement client.SendAvatarPickerReply(agent_data, data_args); } - protected virtual void AddAdditionalUsers(UUID avatarID, string query, List users) + protected virtual void AddAdditionalUsers(string query, List users) { } #endregion Event Handlers + #region IPeople + + public List GetUserData(string query, int page_size, int page_number) + { + // search the user accounts service + List accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); + + List users = new List(); + if (accs != null) + { + foreach (UserAccount acc in accs) + { + UserData ud = new UserData(); + ud.FirstName = acc.FirstName; + ud.LastName = acc.LastName; + ud.Id = acc.PrincipalID; + users.Add(ud); + } + } + + // search the local cache + foreach (UserData data in m_UserCache.Values) + if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null && + (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower()))) + users.Add(data); + + AddAdditionalUsers(query, users); + + return users; + + } + + #endregion IPeople + private void CacheCreators(SceneObjectGroup sog) { //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification); diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index ce2e6008cf..5e486d4d2e 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -507,8 +507,10 @@ ;; "" -- capability enabled and served by some other server ;; ; These are enabled by default to localhost. Change if you see fit. - Cap_GetTexture = "localhost" + Cap_GetTexture = "localhost" Cap_GetMesh = "localhost" + Cap_AvatarPickerSearch = "localhost" + ; This is disabled by default. Change if you see fit. Note that ; serving this cap from the simulators may lead to poor performace. Cap_WebFetchInventoryDescendents = "" diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 28c1db27e7..7666243e2c 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -609,6 +609,10 @@ Cap_WebFetchInventoryDescendents = "" Cap_FetchInventoryDescendents2 = "localhost" Cap_FetchInventory2 = "localhost" + + ; Capability for searching for people + Cap_AvatarPickerSearch = "localhost" + [Chat]