From 371fde3dbbba576fa158bb7ddf7b9c1d5a3cf2f6 Mon Sep 17 00:00:00 2001 From: Jim Radford Date: Thu, 8 Oct 2009 02:56:37 +0000 Subject: [PATCH] LIBOMV-671 Adds adult flag to login options to enable age verified accounts to obtain adult specific content and results from searches * Adds additional inline documentation for DirFindFlags, flags in this enum without inline comments do not appear to be in use any longer * Additional DirectoryManager documentation added * Adult specific result/query implemented for all DirectoryManager public Methods * Additional Decoders added to PacketDecoder for EventFlags * New TestClient command for searching Places git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@3133 52acb1d6-8a22-11de-b505-999d5b087335 --- OpenMetaverse/DirectoryManager.cs | 302 ++++++++++++------ OpenMetaverse/Login.cs | 7 +- OpenMetaverse/PacketDecoder.cs | 9 + .../Commands/Directory/SearchEventsCommand.cs | 2 +- .../Commands/Directory/SearchPlacesCommand.cs | 58 ++++ 5 files changed, 276 insertions(+), 102 deletions(-) create mode 100644 Programs/examples/TestClient/Commands/Directory/SearchPlacesCommand.cs diff --git a/OpenMetaverse/DirectoryManager.cs b/OpenMetaverse/DirectoryManager.cs index e97d727e..38a31470 100644 --- a/OpenMetaverse/DirectoryManager.cs +++ b/OpenMetaverse/DirectoryManager.cs @@ -94,30 +94,41 @@ namespace OpenMetaverse Miscellaneous = 29 } + // I can be deleted as soon as the flags for DirLandQuery can be verified to not use + // the below listed combinations. e.g: PgSimsOnly *should not* be necessary any longer as it looks redundant + // -- Jim + // + // + // Modifier flags sent to DirectoryManager to change the behavior of the + // query + // + // Land Search Flags required in addition to specify land maturity rating: + // + // PgSimsOnly | SortAsc | PerMeterSort | IncludePG | IncludeAdult + // would sort the results ascending, sort by sale price/m2, Include only Adult and PG Land + // in the search results. + // + // + // Desired QueryRequired Flags + // PGPgSimsOnly | IncludePG + // PG+MatureIncludePG | IncludeMature + // PG+Mature+AdultIncludePG | IncludeMature | IncludeAdult + // Mature+AdultMatureSimsOnly | IncludeMature | IncludeAdult + // AdultIncludeAdult + // MatureMatureSimsOnly | IncludeMature + // PG+AdultPgSimsOnly | IncludePG | IncludeAdult + // + + /// - /// Modifier flags sent to DirectoryManager to change the behavior of the - /// query + /// Query Flags used in many of the DirectoryManager methods to specify which query to execute and how to return the results. + /// + /// Flags can be combined using the | (pipe) character /// - /// Land Search Flags required in addition to specify land maturity rating: - /// - /// PgSimsOnly | SortAsc | PerMeterSort | IncludePG | IncludeAdult - /// would sort the results ascending, sort by sale price/m2, Include only Adult and PG Land - /// in the search results. - /// - /// - /// Desired QueryRequired Flags - /// PGPgSimsOnly | IncludePG - /// PG+MatureIncludePG | IncludeMature - /// PG+Mature+AdultIncludePG | IncludeMature | IncludeAdult - /// Mature+AdultMatureSimsOnly | IncludeMature | IncludeAdult - /// AdultIncludeAdult - /// MatureMatureSimsOnly | IncludeMature - /// PG+AdultPgSimsOnly | IncludePG | IncludeAdult - /// [Flags] public enum DirFindFlags { - /// + /// Query the People database People = 1 << 0, /// Online = 1 << 1, @@ -128,18 +139,19 @@ namespace OpenMetaverse Events = 1 << 3, /// Groups = 1 << 4, - /// + /// Query the Events database DateEvents = 1 << 5, - /// + /// Query the land holdings database for land owned by the currently connected agent AgentOwned = 1 << 6, /// ForSale = 1 << 7, - /// + /// Query the land holdings database for land which is owned by a Group GroupOwned = 1 << 8, // //[Obsolete] //Auction = 1 << 9, - /// + /// Specifies the query should pre sort the results based upon traffic + /// when searching the Places database DwellSort = 1 << 10, /// PgSimsOnly = 1 << 11, @@ -149,29 +161,36 @@ namespace OpenMetaverse PgEventsOnly = 1 << 13, /// MatureSimsOnly = 1 << 14, - /// + /// Specifies the query should pre sort the results in an ascending order when searching the land sales database. + /// This flag is only used when searching the land sales database SortAsc = 1 << 15, - /// + /// Specifies the query should pre sort the results using the SalePrice field when searching the land sales database. + /// This flag is only used when searching the land sales database PricesSort = 1 << 16, - /// + /// Specifies the query should pre sort the results by calculating the average price/sq.m (SalePrice / Area) when searching the land sales database. + /// This flag is only used when searching the land sales database PerMeterSort = 1 << 17, - /// + /// Specifies the query should pre sort the results using the ParcelSize field when searching the land sales database. + /// This flag is only used when searching the land sales database AreaSort = 1 << 18, - /// + /// Specifies the query should pre sort the results using the Name field when searching the land sales database. + /// This flag is only used when searching the land sales database NameSort = 1 << 19, - /// + /// When set, only parcels less than the specified Price will be included when searching the land sales database. + /// This flag is only used when searching the land sales database LimitByPrice = 1 << 20, - /// + /// When set, only parcels greater than the specified Size will be included when searching the land sales database. + /// This flag is only used when searching the land sales database LimitByArea = 1 << 21, /// FilterMature = 1 << 22, /// PGOnly = 1 << 23, - /// Include PG land in results + /// Include PG land in results. This flag is used when searching both the Events and Land sales databases IncludePG = 1 << 24, - /// Include Mature land in results + /// Include Mature land in results. This flag is used when searching both the Events and Land sales databases IncludeMature = 1 << 25, - /// Include Adult land in results + /// Include Adult land in results. This flag is used when searching both the Events and Land sales databases IncludeAdult = 1 << 26, /// AdultOnly = 1 << 27 @@ -198,11 +217,17 @@ namespace OpenMetaverse Estate = 1 << 4 } - [Flags] + /// + /// The content rating of the event + /// public enum EventFlags { - None = 0, - Mature = 1 << 1 + /// Event is PG + PG = 0, + /// Event is Mature + Mature = 1, + /// Event is Adult + Adult = 2 } /// @@ -269,24 +294,38 @@ namespace OpenMetaverse /// /// A parcel retrieved from the dataserver such as results from the - /// "For-Sale" listings + /// "For-Sale" listings or "Places" Search /// public struct DirectoryParcel { - /// + /// The unique dataserver parcel ID + /// This id is used to obtain additional information from the entry + /// by using the method public UUID ID; - /// + /// A string containing the name of the parcel public string Name; - /// + /// The size of the parcel + /// This field is not returned for Places searches public int ActualArea; - /// + /// The price of the parcel + /// This field is not returned for Places searches public int SalePrice; - /// + /// If True, this parcel is flagged to be auctioned public bool Auction; - /// + /// If true, this parcel is currently set for sale public bool ForSale; /// Parcel traffic public float Dwell; + + /// + /// Display an entry in a one line human readable format + /// + /// A string representing a single parcel entry + public override string ToString() + { + return String.Format("Parcel ID: {0}, Name: {1}, Area: {2}, Price: {3}, IsAuction: {4}, IsForSale: {5}, Dwell: {6}" + System.Environment.NewLine, + this.ID, this.Name, this.ActualArea, this.SalePrice, this.Auction, this.ForSale, this.Dwell); + } } /// @@ -457,8 +496,9 @@ namespace OpenMetaverse public DirectoryManager(GridClient client) { Client = client; - + Client.Network.RegisterCallback(PacketType.DirClassifiedReply, new NetworkManager.PacketCallback(DirClassifiedReplyHandler)); + // Deprecated, replies come in over capabilities Client.Network.RegisterCallback(PacketType.DirLandReply, new NetworkManager.PacketCallback(DirLandReplyHandler)); Client.Network.RegisterEventCallback("DirLandReply", DirLandReplyEventHandler); Client.Network.RegisterCallback(PacketType.DirPeopleReply, new NetworkManager.PacketCallback(DirPeopleReplyHandler)); @@ -483,8 +523,10 @@ namespace OpenMetaverse /// Defaults to searching for classified placed in any category, and includes PG, Adult and Mature /// results. /// - /// Responses are sent 16 at a time, there is no way to know how many results a query reply will contain however assuming + /// Responses are sent 16 per response packet, there is no way to know how many results a query reply will contain however assuming /// the reply packets arrived ordered, a response with less than 16 entries would indicate all results have been received + /// + /// The event is raised when a response is received from the simulator /// /// A string containing a list of keywords to search for /// A UUID to correlate the results when the event is raised @@ -495,6 +537,8 @@ namespace OpenMetaverse /// /// Query the data server for a list of classified ads which contain specified keywords (Overload) + /// + /// The event is raised when a response is received from the simulator /// /// A string containing a list of keywords to search for /// The category to search @@ -530,27 +574,56 @@ namespace OpenMetaverse } /// - /// Starts search for places + /// Starts search for places (Overloaded) + /// + /// The event is raised when a response is received from the simulator /// /// Search text /// Start result (we get 100 results at a time, so we start with 0, then 100, etc). - /// - public UUID StartDirPlacesSearch(string searchText, int startAtResult) + /// A UUID to correlate the results when the event is raised + public UUID StartDirPlacesSearch(string searchText, int queryStart) { + return StartDirPlacesSearch(searchText, DirFindFlags.DwellSort | DirFindFlags.IncludePG | DirFindFlags.IncludeMature + | DirFindFlags.IncludeAdult, ParcelCategory.Any, queryStart); + } + + /// + /// Queries the dataserver for parcels of land which are flagged to be shown in search + /// + /// The event is raised when a response is received from the simulator + /// + /// A string containing a list of keywords to search for separated by a space character + /// A set of flags which can be ORed to modify query options + /// such as classified maturity rating. + /// The category to search + /// Each request is limited to 100 places + /// being returned. To get the first 100 result entries of a request use 0, + /// from 100-199 use 1, 200-299 use 2, etc. + /// A UUID to correlate the results when the event is raised + /// + /// Search places containing the key words "foo" and "bar" in the "Any" category that are either PG or Adult + /// + /// UUID searchID = StartDirPlacesSearch("foo bar", DirFindFlags.DwellSort | DirFindFlags.IncludePG | DirFindFlags.IncludeAdult, ParcelCategory.Any, 0); + /// + /// + /// + /// Additional information on the results can be obtained by using the ParcelManager.InfoRequest method + /// + public UUID StartDirPlacesSearch(string searchText, DirFindFlags queryFlags, ParcelCategory category, int queryStart) + { DirPlacesQueryPacket query = new DirPlacesQueryPacket(); + + UUID queryID = UUID.Random(); + query.AgentData.AgentID = Client.Self.AgentID; query.AgentData.SessionID = Client.Self.SessionID; - UUID queryID = UUID.Random(); - // TODO: need to figure out new enums for Category and Flags that - // include all of the settings (including new maturity levels) - // For now, hard code all categories, all maturity levels - query.QueryData.Category = -1; - query.QueryData.QueryFlags = 117441536; + query.QueryData.Category = (sbyte)category; + query.QueryData.QueryFlags = (uint)queryFlags; query.QueryData.QueryID = queryID; query.QueryData.QueryText = Utils.StringToBytes(searchText); - query.QueryData.QueryStart = startAtResult; + query.QueryData.QueryStart = queryStart; query.QueryData.SimName = Utils.StringToBytes(string.Empty); Client.Network.SendPacket(query); @@ -561,6 +634,8 @@ namespace OpenMetaverse /// /// Starts a search for land sales using the directory + /// + /// The event is raised when a response is received from the simulator /// /// What type of land to search for. Auction, /// estate, mainland, "first land", etc @@ -578,6 +653,8 @@ namespace OpenMetaverse /// /// Starts a search for land sales using the directory + /// + /// The event is raised when a response is received from the simulator /// /// What type of land to search for. Auction, /// estate, mainland, "first land", etc @@ -600,32 +677,57 @@ namespace OpenMetaverse } /// - /// Starts a search for land sales using the directory + /// Request land listed for public sale /// - /// A flags parameter that can modify the way - /// search results are returned, for example changing the ordering of - /// results or limiting based on price or area + /// + /// Flags sent to specify query options + /// + /// Available flags: + /// Specify the parcel rating with one or more of the following: + /// IncludePG IncludeMature IncludeAdult + /// + /// Specify the field to pre sort the results with ONLY ONE of the following: + /// PerMeterSort NameSort AreaSort PricesSort + /// + /// Specify the order the results are returned in, if not specified the results are pre sorted in a Descending Order + /// SortAsc + /// + /// Specify additional filters to limit the results with one or both of the following: + /// LimitByPrice LimitByArea + /// + /// Flags can be combined by separating them with the | (pipe) character + /// + /// Additional details can be found in + /// /// What type of land to search for. Auction, - /// estate, mainland, "first land", etc - /// Maximum price to search for, the - /// DirFindFlags.LimitByPrice flag must be set - /// Maximum area to search for, the - /// DirFindFlags.LimitByArea flag must be set + /// Estate or Mainland + /// Maximum price to search for when the + /// DirFindFlags.LimitByPrice flag is specified in findFlags + /// Maximum area to search for when the + /// DirFindFlags.LimitByArea flag is specified in findFlags /// Each request is limited to 100 parcels /// being returned. To get the first 100 parcels of a request use 0, /// from 100-199 use 100, 200-299 use 200, etc. /// A unique identifier that can identify packets associated /// with this query from other queries - /// The OnDirLandReply event handler must be registered before - /// calling this function. There is no way to determine how many - /// results will be returned, or how many times the callback will be + /// The event will be raised with the response from the simulator + /// + /// There is no way to determine how many results will be returned, or how many times the callback will be /// fired other than you won't get more than 100 total parcels from - /// each query. + /// each reply. + /// + /// Any land set for sale to either anybody or specific to the connected agent will be included in the + /// results if the land is included in the query + /// + /// + /// // request all mainland, any maturity rating that is larger than 512 sq.m + /// StartLandSearch(DirFindFlags.SortAsc | DirFindFlags.PerMeterSort | DirFindFlags.LimitByArea | DirFindFlags.IncludePG | DirFindFlags.IncludeMature | DirFindFlags.IncludeAdult, SearchTypeFlags.Mainland, 0, 512, 0); + /// public UUID StartLandSearch(DirFindFlags findFlags, SearchTypeFlags typeFlags, int priceLimit, int areaLimit, int queryStart) { UUID queryID = UUID.Random(); - + DirLandQueryPacket query = new DirLandQueryPacket(); query.AgentData.AgentID = Client.Self.AgentID; query.AgentData.SessionID = Client.Self.SessionID; @@ -645,7 +747,7 @@ namespace OpenMetaverse /// Starts a search for a Group in the directory manager /// /// - /// The text to search for + /// A string containing a list of keywords to search for separated by a space character /// Each request is limited to 100 parcels /// being returned. To get the first 100 parcels of a request use 0, /// from 100-199 use 100, 200-299 use 200, etc. @@ -684,9 +786,11 @@ namespace OpenMetaverse /// /// Search the people directory for other avatars + /// + /// The event is raised when a response is received from the simulator /// /// - /// + /// A string containing a list of keywords to search for separated by a space character /// /// public UUID StartPeopleSearch(DirFindFlags findFlags, string searchText, int queryStart) @@ -698,7 +802,7 @@ namespace OpenMetaverse /// /// /// - /// + /// A string containing a list of keywords to search for separated by a space character /// /// /// @@ -744,7 +848,7 @@ namespace OpenMetaverse /// /// One of the Values from the DirFindFlags struct, ie: AgentOwned, GroupOwned, etc. /// One of the values from the SearchCategory Struct, ie: Any, Linden, Newcomer - /// LLUID of group you want to recieve results for + /// UUID of group you want to recieve results for /// Transaction (Query) ID which can be associated with results from your request. /// Transaction (Query) ID which can be associated with results from your request. public UUID StartPlacesSearch(DirFindFlags findFlags, ParcelCategory searchCategory, UUID groupID, UUID transactionID) @@ -757,7 +861,7 @@ namespace OpenMetaverse /// /// One of the Values from the DirFindFlags struct, ie: AgentOwned, GroupOwned, etc. /// One of the values from the SearchCategory Struct, ie: Any, Linden, Newcomer - /// String Text to search for + /// A string containing a list of keywords to search for separated by a space character /// String Simulator Name to search in /// LLUID of group you want to recieve results for /// Transaction (Query) ID which can be associated with results from your request. @@ -782,53 +886,51 @@ namespace OpenMetaverse /// - /// Search All Events with specifid searchText in all categories, includes Mature + /// Search All Events with specifid searchText in all categories, includes PG, Mature and Adult /// - /// Text to search for + /// A string containing a list of keywords to search for separated by a space character + /// Each request is limited to 100 entries + /// being returned. To get the first group of entries of a request use 0, + /// from 100-199 use 100, 200-299 use 200, etc. /// UUID of query to correlate results in callback. - public UUID StartEventsSearch(string searchText) + public UUID StartEventsSearch(string searchText, uint queryStart) { - return StartEventsSearch(searchText, true, EventCategories.All); + return StartEventsSearch(searchText, DirFindFlags.DateEvents | DirFindFlags.IncludePG | DirFindFlags.IncludeMature | DirFindFlags.IncludeAdult, "u", queryStart, EventCategories.All); } /// - /// Search Events with Options to specify category and Mature events. + /// Search Events /// - /// Text to search for - /// true to include Mature events - /// category to search - /// UUID of query to correlate results in callback. - public UUID StartEventsSearch(string searchText, bool showMature, EventCategories category) - { - return StartEventsSearch(searchText, showMature, "u", 0, category, UUID.Random()); - } - - /// - /// Search Events - ALL options - /// - /// string text to search for e.g.: live music - /// Include mature events in results - /// "u" for now and upcoming events, -or- number of days since/until event is scheduled + /// A string containing a list of keywords to search for separated by a space character + /// One or more of the following flags: DateEvents, IncludePG, IncludeMature, IncludeAdult + /// from the Enum + /// + /// Multiple flags can be combined by separating the flags with the | (pipe) character + /// "u" for in-progress and upcoming events, -or- number of days since/until event is scheduled /// For example "0" = Today, "1" = tomorrow, "2" = following day, "-1" = yesterday, etc. - /// Page # to show, 0 for First Page + /// Each request is limited to 100 entries + /// being returned. To get the first group of entries of a request use 0, + /// from 100-199 use 100, 200-299 use 200, etc. /// EventCategory event is listed under. /// a UUID that can be used to track queries with results. /// UUID of query to correlate results in callback. - public UUID StartEventsSearch(string searchText, bool showMature, string eventDay, uint queryStart, EventCategories category, UUID queryID) + public UUID StartEventsSearch(string searchText, DirFindFlags queryFlags, string eventDay, uint queryStart, EventCategories category) { DirFindQueryPacket find = new DirFindQueryPacket(); find.AgentData.AgentID = Client.Self.AgentID; find.AgentData.SessionID = Client.Self.SessionID; + UUID queryID = UUID.Random(); + find.QueryData.QueryID = queryID; find.QueryData.QueryText = Utils.StringToBytes(eventDay + "|" + (int)category + "|" + searchText); - find.QueryData.QueryFlags = showMature ? (uint)32 : (uint)8224; + find.QueryData.QueryFlags = (uint)queryFlags; find.QueryData.QueryStart = (int)queryStart; Client.Network.SendPacket(find); return queryID; } - + /// Requests Event Details /// ID of Event returned from Places Search public void EventInfoRequest(uint eventID) @@ -842,8 +944,10 @@ namespace OpenMetaverse Client.Network.SendPacket(find); } + #region Blocking Functions + [Obsolete("Use the async StartPeoplSearch method instead")] public bool PeopleSearch(DirFindFlags findFlags, string searchText, int queryStart, int timeoutMS, out List results) { @@ -1118,7 +1222,7 @@ namespace OpenMetaverse p.Name = Utils.BytesToString(reply.QueryReplies[i].Name); p.Dwell = reply.QueryReplies[i].Dwell; p.Auction = reply.QueryReplies[i].Auction; - p.ForSale = reply.QueryReplies[i].ForSale; + p.ForSale = reply.QueryReplies[i].ForSale; result.Add(p); } diff --git a/OpenMetaverse/Login.cs b/OpenMetaverse/Login.cs index 6e7cdb30..8572803d 100644 --- a/OpenMetaverse/Login.cs +++ b/OpenMetaverse/Login.cs @@ -705,7 +705,9 @@ namespace OpenMetaverse private string InternalLoginMessage = String.Empty; private string InternalRawLoginReply = String.Empty; private Dictionary CallbackOptions = new Dictionary(); - /// A list of packets obtained during the login process which networkmanager will log but not process + + /// A list of packets obtained during the login process which + /// networkmanager will log but not process private readonly List UDPBlacklist = new List(); #endregion @@ -724,7 +726,7 @@ namespace OpenMetaverse public LoginParams DefaultLoginParams(string firstName, string lastName, string password, string userAgent, string userVersion) { - List options = new List(15); + List options = new List(16); options.Add("inventory-root"); options.Add("inventory-skeleton"); options.Add("inventory-lib-root"); @@ -740,6 +742,7 @@ namespace OpenMetaverse options.Add("tutorial_settings"); options.Add("login-flags"); options.Add("global-textures"); + options.Add("adult_compliant"); LoginParams loginParams = new LoginParams(); if (Client == null) diff --git a/OpenMetaverse/PacketDecoder.cs b/OpenMetaverse/PacketDecoder.cs index 25416e6b..22d1dee7 100644 --- a/OpenMetaverse/PacketDecoder.cs +++ b/OpenMetaverse/PacketDecoder.cs @@ -121,6 +121,7 @@ namespace OpenMetaverse.Packets AddCallback("QueryData.SearchType", SearchTypeFlags); AddCallback("ClassifiedFlags", DecodeDirClassifiedFlags); + AddCallback("EventFlags", DecodeEventFlags); AddCallback("ParcelAccessListRequest.Data.Flags", DecodeParcelACL); AddCallback("ParcelAccessListReply.Data.Flags", DecodeParcelACL); @@ -840,6 +841,14 @@ namespace OpenMetaverse.Packets "(" + (ClickAction)(byte)fieldData + ")"); } + private static string DecodeEventFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [EventFlags]", + fieldName, + fieldData, + "(" + (DirectoryManager.EventFlags)(uint)fieldData + ")"); + } + private static string DecodeDirQueryFlags(string fieldName, object fieldData) { return String.Format("{0,30}: {1,-10} {2,-29} [DirectoryManager.DirFindFlags]", diff --git a/Programs/examples/TestClient/Commands/Directory/SearchEventsCommand.cs b/Programs/examples/TestClient/Commands/Directory/SearchEventsCommand.cs index eb6c4b69..dfd2daa7 100644 --- a/Programs/examples/TestClient/Commands/Directory/SearchEventsCommand.cs +++ b/Programs/examples/TestClient/Commands/Directory/SearchEventsCommand.cs @@ -28,7 +28,7 @@ namespace OpenMetaverse.TestClient.Commands waitQuery.Reset(); Client.Directory.OnEventsReply += new DirectoryManager.EventReplyCallback(Directory_OnEventsReply); - Client.Directory.StartEventsSearch(searchText, true, "u", 0, DirectoryManager.EventCategories.All, UUID.Random()); + Client.Directory.StartEventsSearch(searchText, 0); string result; if (waitQuery.WaitOne(20000, false) && Client.Network.Connected) { diff --git a/Programs/examples/TestClient/Commands/Directory/SearchPlacesCommand.cs b/Programs/examples/TestClient/Commands/Directory/SearchPlacesCommand.cs new file mode 100644 index 00000000..368b45d2 --- /dev/null +++ b/Programs/examples/TestClient/Commands/Directory/SearchPlacesCommand.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMetaverse.TestClient.Commands +{ + class SearchPlacesCommand : Command + { + System.Threading.AutoResetEvent waitQuery = new System.Threading.AutoResetEvent(false); + int resultCount; + + public SearchPlacesCommand(TestClient testClient) + { + Name = "searchplaces"; + Description = "Searches Places. Usage: searchplaces [search text]"; + Category = CommandCategory.Other; + } + + public override string Execute(string[] args, UUID fromAgentID) + { + if (args.Length < 1) + return "Usage: searchplaces [search text]"; + + string searchText = string.Empty; + for (int i = 0; i < args.Length; i++) + searchText += args[i] + " "; + searchText = searchText.TrimEnd(); + waitQuery.Reset(); + + StringBuilder result = new StringBuilder(); + + DirectoryManager.DirPlacesReplyCallback callback = delegate(UUID queryID, List matchedParcels) + { + result.AppendFormat("Your search string '{0}' returned {1} results" + System.Environment.NewLine, + searchText, matchedParcels.Count); + foreach (DirectoryManager.DirectoryParcel place in matchedParcels) + { + result.AppendLine(place.ToString()); + } + + waitQuery.Set(); + }; + + Client.Directory.OnDirPlacesReply += callback; + + UUID searchID = Client.Directory.StartClassifiedSearch(searchText, DirectoryManager.ClassifiedCategories.Any, DirectoryManager.ClassifiedQueryFlags.Mature | DirectoryManager.ClassifiedQueryFlags.PG); + + if (!waitQuery.WaitOne(20000, false) && Client.Network.Connected) + { + result.AppendLine("Timeout waiting for simulator to respond to query."); + } + + Client.Directory.OnDirPlacesReply -= callback; + + return result.ToString(); + } + } +}