corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
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 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.Threading;
29 using System.Collections.Generic;
30 using OpenMetaverse.Packets;
31 using OpenMetaverse.Interfaces;
32 using OpenMetaverse.Messages.Linden;
33  
34 namespace OpenMetaverse
35 {
36 /// <summary>
37 /// Access to the data server which allows searching for land, events, people, etc
38 /// </summary>
39 public class DirectoryManager
40 {
41 #region Enums
42 /// <summary>Classified Ad categories</summary>
43 public enum ClassifiedCategories
44 {
45 /// <summary>Classified is listed in the Any category</summary>
46 Any = 0,
47 /// <summary>Classified is shopping related</summary>
48 Shopping,
49 /// <summary>Classified is </summary>
50 LandRental,
51 /// <summary></summary>
52 PropertyRental,
53 /// <summary></summary>
54 SpecialAttraction,
55 /// <summary></summary>
56 NewProducts,
57 /// <summary></summary>
58 Employment,
59 /// <summary></summary>
60 Wanted,
61 /// <summary></summary>
62 Service,
63 /// <summary></summary>
64 Personal
65 }
66  
67 /// <summary>Event Categories</summary>
68 public enum EventCategories
69 {
70 /// <summary></summary>
71 All = 0,
72 /// <summary></summary>
73 Discussion = 18,
74 /// <summary></summary>
75 Sports = 19,
76 /// <summary></summary>
77 LiveMusic = 20,
78 /// <summary></summary>
79 Commercial = 22,
80 /// <summary></summary>
81 Nightlife = 23,
82 /// <summary></summary>
83 Games = 24,
84 /// <summary></summary>
85 Pageants = 25,
86 /// <summary></summary>
87 Education = 26,
88 /// <summary></summary>
89 Arts = 27,
90 /// <summary></summary>
91 Charity = 28,
92 /// <summary></summary>
93 Miscellaneous = 29
94 }
95  
96 /// <summary>
97 /// Query Flags used in many of the DirectoryManager methods to specify which query to execute and how to return the results.
98 ///
99 /// Flags can be combined using the | (pipe) character, not all flags are available in all queries
100 /// </summary>
101 [Flags]
102 public enum DirFindFlags
103 {
104 /// <summary>Query the People database</summary>
105 People = 1 << 0,
106 /// <summary></summary>
107 Online = 1 << 1,
108 // <summary></summary>
109 //[Obsolete]
110 //Places = 1 << 2,
111 /// <summary></summary>
112 Events = 1 << 3,
113 /// <summary>Query the Groups database</summary>
114 Groups = 1 << 4,
115 /// <summary>Query the Events database</summary>
116 DateEvents = 1 << 5,
117 /// <summary>Query the land holdings database for land owned by the currently connected agent</summary>
118 AgentOwned = 1 << 6,
119 /// <summary></summary>
120 ForSale = 1 << 7,
121 /// <summary>Query the land holdings database for land which is owned by a Group</summary>
122 GroupOwned = 1 << 8,
123 // <summary></summary>
124 //[Obsolete]
125 //Auction = 1 << 9,
126 /// <summary>Specifies the query should pre sort the results based upon traffic
127 /// when searching the Places database</summary>
128 DwellSort = 1 << 10,
129 /// <summary></summary>
130 PgSimsOnly = 1 << 11,
131 /// <summary></summary>
132 PicturesOnly = 1 << 12,
133 /// <summary></summary>
134 PgEventsOnly = 1 << 13,
135 /// <summary></summary>
136 MatureSimsOnly = 1 << 14,
137 /// <summary>Specifies the query should pre sort the results in an ascending order when searching the land sales database.
138 /// This flag is only used when searching the land sales database</summary>
139 SortAsc = 1 << 15,
140 /// <summary>Specifies the query should pre sort the results using the SalePrice field when searching the land sales database.
141 /// This flag is only used when searching the land sales database</summary>
142 PricesSort = 1 << 16,
143 /// <summary>Specifies the query should pre sort the results by calculating the average price/sq.m (SalePrice / Area) when searching the land sales database.
144 /// This flag is only used when searching the land sales database</summary>
145 PerMeterSort = 1 << 17,
146 /// <summary>Specifies the query should pre sort the results using the ParcelSize field when searching the land sales database.
147 /// This flag is only used when searching the land sales database</summary>
148 AreaSort = 1 << 18,
149 /// <summary>Specifies the query should pre sort the results using the Name field when searching the land sales database.
150 /// This flag is only used when searching the land sales database</summary>
151 NameSort = 1 << 19,
152 /// <summary>When set, only parcels less than the specified Price will be included when searching the land sales database.
153 /// This flag is only used when searching the land sales database</summary>
154 LimitByPrice = 1 << 20,
155 /// <summary>When set, only parcels greater than the specified Size will be included when searching the land sales database.
156 /// This flag is only used when searching the land sales database</summary>
157 LimitByArea = 1 << 21,
158 /// <summary></summary>
159 FilterMature = 1 << 22,
160 /// <summary></summary>
161 PGOnly = 1 << 23,
162 /// <summary>Include PG land in results. This flag is used when searching both the Groups, Events and Land sales databases</summary>
163 IncludePG = 1 << 24,
164 /// <summary>Include Mature land in results. This flag is used when searching both the Groups, Events and Land sales databases</summary>
165 IncludeMature = 1 << 25,
166 /// <summary>Include Adult land in results. This flag is used when searching both the Groups, Events and Land sales databases</summary>
167 IncludeAdult = 1 << 26,
168 /// <summary></summary>
169 AdultOnly = 1 << 27
170 }
171  
172 /// <summary>
173 /// Land types to search dataserver for
174 /// </summary>
175 [Flags]
176 public enum SearchTypeFlags
177 {
178 /// <summary>Search Auction, Mainland and Estate</summary>
179 Any = -1,
180 /// <summary>Land which is currently up for auction</summary>
181 Auction = 1 << 1,
182 // <summary>Land available to new landowners (formerly the FirstLand program)</summary>
183 //[Obsolete]
184 //Newbie = 1 << 2,
185 /// <summary>Parcels which are on the mainland (Linden owned) continents</summary>
186 Mainland = 1 << 3,
187 /// <summary>Parcels which are on privately owned simulators</summary>
188 Estate = 1 << 4
189 }
190  
191 /// <summary>
192 /// The content rating of the event
193 /// </summary>
194 public enum EventFlags
195 {
196 /// <summary>Event is PG</summary>
197 PG = 0,
198 /// <summary>Event is Mature</summary>
199 Mature = 1,
200 /// <summary>Event is Adult</summary>
201 Adult = 2
202 }
203  
204 /// <summary>
205 /// Classified Ad Options
206 /// </summary>
207 /// <remarks>There appear to be two formats the flags are packed in.
208 /// This set of flags is for the newer style</remarks>
209 [Flags]
210 public enum ClassifiedFlags : byte
211 {
212 /// <summary></summary>
213 None = 1 << 0,
214 /// <summary></summary>
215 Mature = 1 << 1,
216 /// <summary></summary>
217 Enabled = 1 << 2,
218 // HasPrice = 1 << 3, // Deprecated
219 /// <summary></summary>
220 UpdateTime = 1 << 4,
221 /// <summary></summary>
222 AutoRenew = 1 << 5
223 }
224  
225 /// <summary>
226 /// Classified ad query options
227 /// </summary>
228 [Flags]
229 public enum ClassifiedQueryFlags
230 {
231 /// <summary>Include all ads in results</summary>
232 All = PG | Mature | Adult,
233 /// <summary>Include PG ads in results</summary>
234 PG = 1 << 2,
235 /// <summary>Include Mature ads in results</summary>
236 Mature = 1 << 3,
237 /// <summary>Include Adult ads in results</summary>
238 Adult = 1 << 6,
239 }
240  
241 /// <summary>
242 /// The For Sale flag in PlacesReplyData
243 /// </summary>
244 public enum PlacesFlags : byte
245 {
246 /// <summary>Parcel is not listed for sale</summary>
247 NotForSale = 0,
248 /// <summary>Parcel is For Sale</summary>
249 ForSale = 128
250 }
251  
252 #endregion
253 #region Structs
254 /// <summary>
255 /// A classified ad on the grid
256 /// </summary>
257 public struct Classified
258 {
259 /// <summary>UUID for this ad, useful for looking up detailed
260 /// information about it</summary>
261 public UUID ID;
262 /// <summary>The title of this classified ad</summary>
263 public string Name;
264 /// <summary>Flags that show certain options applied to the classified</summary>
265 public ClassifiedFlags Flags;
266 /// <summary>Creation date of the ad</summary>
267 public DateTime CreationDate;
268 /// <summary>Expiration date of the ad</summary>
269 public DateTime ExpirationDate;
270 /// <summary>Price that was paid for this ad</summary>
271 public int Price;
272  
273 /// <summary>Print the struct data as a string</summary>
274 /// <returns>A string containing the field name, and field value</returns>
275 public override string ToString()
276 {
277 return Helpers.StructToString(this);
278 }
279 }
280  
281 /// <summary>
282 /// A parcel retrieved from the dataserver such as results from the
283 /// "For-Sale" listings or "Places" Search
284 /// </summary>
285 public struct DirectoryParcel
286 {
287 /// <summary>The unique dataserver parcel ID</summary>
288 /// <remarks>This id is used to obtain additional information from the entry
289 /// by using the <see cref="ParcelManager.InfoRequest"/> method</remarks>
290 public UUID ID;
291 /// <summary>A string containing the name of the parcel</summary>
292 public string Name;
293 /// <summary>The size of the parcel</summary>
294 /// <remarks>This field is not returned for Places searches</remarks>
295 public int ActualArea;
296 /// <summary>The price of the parcel</summary>
297 /// <remarks>This field is not returned for Places searches</remarks>
298 public int SalePrice;
299 /// <summary>If True, this parcel is flagged to be auctioned</summary>
300 public bool Auction;
301 /// <summary>If true, this parcel is currently set for sale</summary>
302 public bool ForSale;
303 /// <summary>Parcel traffic</summary>
304 public float Dwell;
305  
306 /// <summary>Print the struct data as a string</summary>
307 /// <returns>A string containing the field name, and field value</returns>
308 public override string ToString()
309 {
310 return Helpers.StructToString(this);
311 }
312 }
313  
314 /// <summary>
315 /// An Avatar returned from the dataserver
316 /// </summary>
317 public struct AgentSearchData
318 {
319 /// <summary>Online status of agent</summary>
320 /// <remarks>This field appears to be obsolete and always returns false</remarks>
321 public bool Online;
322 /// <summary>The agents first name</summary>
323 public string FirstName;
324 /// <summary>The agents last name</summary>
325 public string LastName;
326 /// <summary>The agents <see cref="UUID"/></summary>
327 public UUID AgentID;
328  
329 /// <summary>Print the struct data as a string</summary>
330 /// <returns>A string containing the field name, and field value</returns>
331 public override string ToString()
332 {
333 return Helpers.StructToString(this);
334 }
335 }
336  
337 /// <summary>
338 /// Response to a "Groups" Search
339 /// </summary>
340 public struct GroupSearchData
341 {
342 /// <summary>The Group ID</summary>
343 public UUID GroupID;
344 /// <summary>The name of the group</summary>
345 public string GroupName;
346 /// <summary>The current number of members</summary>
347 public int Members;
348  
349 /// <summary>Print the struct data as a string</summary>
350 /// <returns>A string containing the field name, and field value</returns>
351 public override string ToString()
352 {
353 return Helpers.StructToString(this);
354 }
355 }
356  
357 /// <summary>
358 /// Parcel information returned from a <see cref="StartPlacesSearch"/> request
359 /// <para>
360 /// Represents one of the following:
361 /// A parcel of land on the grid that has its Show In Search flag set
362 /// A parcel of land owned by the agent making the request
363 /// A parcel of land owned by a group the agent making the request is a member of
364 /// </para>
365 /// <para>
366 /// In a request for Group Land, the First record will contain an empty record
367 /// </para>
368 /// Note: This is not the same as searching the land for sale data source
369 /// </summary>
370 public struct PlacesSearchData
371 {
372 /// <summary>The ID of the Agent of Group that owns the parcel</summary>
373 public UUID OwnerID;
374 /// <summary>The name</summary>
375 public string Name;
376 /// <summary>The description</summary>
377 public string Desc;
378 /// <summary>The Size of the parcel</summary>
379 public int ActualArea;
380 /// <summary>The billable Size of the parcel, for mainland
381 /// parcels this will match the ActualArea field. For Group owned land this will be 10 percent smaller
382 /// than the ActualArea. For Estate land this will always be 0</summary>
383 public int BillableArea;
384 /// <summary>Indicates the ForSale status of the parcel</summary>
385 public PlacesFlags Flags;
386 /// <summary>The Gridwide X position</summary>
387 public float GlobalX;
388 /// <summary>The Gridwide Y position</summary>
389 public float GlobalY;
390 /// <summary>The Z position of the parcel, or 0 if no landing point set</summary>
391 public float GlobalZ;
392 /// <summary>The name of the Region the parcel is located in</summary>
393 public string SimName;
394 /// <summary>The Asset ID of the parcels Snapshot texture</summary>
395 public UUID SnapshotID;
396 /// <summary>The calculated visitor traffic</summary>
397 public float Dwell;
398 /// <summary>The billing product SKU</summary>
399 /// <remarks>Known values are:
400 /// <list type="table">
401 /// <item><term>023</term><description>Mainland / Full Region</description></item>
402 /// <item><term>024</term><description>Estate / Full Region</description></item>
403 /// <item><term>027</term><description>Estate / Openspace</description></item>
404 /// <item><term>029</term><description>Estate / Homestead</description></item>
405 /// <item><term>129</term><description>Mainland / Homestead (Linden Owned)</description></item>
406 /// </list>
407 /// </remarks>
408 public string SKU;
409 /// <summary>No longer used, will always be 0</summary>
410 public int Price;
411  
412 /// <summary>Get a SL URL for the parcel</summary>
413 /// <returns>A string, containing a standard SLURL</returns>
414 public string ToSLurl()
415 {
416 float x, y;
417 Helpers.GlobalPosToRegionHandle(this.GlobalX, this.GlobalY, out x, out y);
418 return "secondlife://" + this.SimName + "/" + x + "/" + y + "/" + this.GlobalZ;
419 }
420  
421 /// <summary>Print the struct data as a string</summary>
422 /// <returns>A string containing the field name, and field value</returns>
423 public override string ToString()
424 {
425 return Helpers.StructToString(this);
426 }
427 }
428  
429 /// <summary>
430 /// An "Event" Listing summary
431 /// </summary>
432 public struct EventsSearchData
433 {
434 /// <summary>The ID of the event creator</summary>
435 public UUID Owner;
436 /// <summary>The name of the event</summary>
437 public string Name;
438 /// <summary>The events ID</summary>
439 public uint ID;
440 /// <summary>A string containing the short date/time the event will begin</summary>
441 public string Date;
442 /// <summary>The event start time in Unixtime (seconds since epoch)</summary>
443 public uint Time;
444 /// <summary>The events maturity rating</summary>
445 public EventFlags Flags;
446  
447 /// <summary>Print the struct data as a string</summary>
448 /// <returns>A string containing the field name, and field value</returns>
449 public override string ToString()
450 {
451 return Helpers.StructToString(this);
452 }
453 }
454  
455 /// <summary>
456 /// The details of an "Event"
457 /// </summary>
458 public struct EventInfo
459 {
460 /// <summary>The events ID</summary>
461 public uint ID;
462 /// <summary>The ID of the event creator</summary>
463 public UUID Creator;
464 /// <summary>The name of the event</summary>
465 public string Name;
466 /// <summary>The category</summary>
467 public EventCategories Category;
468 /// <summary>The events description</summary>
469 public string Desc;
470 /// <summary>The short date/time the event will begin</summary>
471 public string Date;
472 /// <summary>The event start time in Unixtime (seconds since epoch) UTC adjusted</summary>
473 public uint DateUTC;
474 /// <summary>The length of the event in minutes</summary>
475 public uint Duration;
476 /// <summary>0 if no cover charge applies</summary>
477 public uint Cover;
478 /// <summary>The cover charge amount in L$ if applicable</summary>
479 public uint Amount;
480 /// <summary>The name of the region where the event is being held</summary>
481 public string SimName;
482 /// <summary>The gridwide location of the event</summary>
483 public Vector3d GlobalPos;
484 /// <summary>The maturity rating</summary>
485 public EventFlags Flags;
486  
487 /// <summary>Get a SL URL for the parcel where the event is hosted</summary>
488 /// <returns>A string, containing a standard SLURL</returns>
489 public string ToSLurl()
490 {
491 float x, y;
492 Helpers.GlobalPosToRegionHandle((float)this.GlobalPos.X, (float)this.GlobalPos.Y, out x, out y);
493 return "secondlife://" + this.SimName + "/" + x + "/" + y + "/" + this.GlobalPos.Z;
494 }
495  
496 /// <summary>Print the struct data as a string</summary>
497 /// <returns>A string containing the field name, and field value</returns>
498 public override string ToString()
499 {
500 return Helpers.StructToString(this);
501 }
502 }
503  
504 #endregion Structs
505  
506 #region Event delegates, Raise Events
507  
508 /// <summary>The event subscribers. null if no subcribers</summary>
509 private EventHandler<EventInfoReplyEventArgs> m_EventInfoReply;
510  
511 /// <summary>Raises the EventInfoReply event</summary>
512 /// <param name="e">An EventInfoReplyEventArgs object containing the
513 /// data returned from the data server</param>
514 protected virtual void OnEventInfo(EventInfoReplyEventArgs e)
515 {
516 EventHandler<EventInfoReplyEventArgs> handler = m_EventInfoReply;
517 if (handler != null)
518 handler(this, e);
519 }
520  
521 /// <summary>Thread sync lock object</summary>
522 private readonly object m_EventDetailLock = new object();
523  
524 /// <summary>Raised when the data server responds to a <see cref="EventInfoRequest"/> request.</summary>
525 public event EventHandler<EventInfoReplyEventArgs> EventInfoReply
526 {
527 add { lock (m_EventDetailLock) { m_EventInfoReply += value; } }
528 remove { lock (m_EventDetailLock) { m_EventInfoReply -= value; } }
529 }
530  
531 /// <summary>The event subscribers. null if no subcribers</summary>
532 private EventHandler<DirEventsReplyEventArgs> m_DirEvents;
533  
534 /// <summary>Raises the DirEventsReply event</summary>
535 /// <param name="e">An DirEventsReplyEventArgs object containing the
536 /// data returned from the data server</param>
537 protected virtual void OnDirEvents(DirEventsReplyEventArgs e)
538 {
539 EventHandler<DirEventsReplyEventArgs> handler = m_DirEvents;
540 if (handler != null)
541 handler(this, e);
542 }
543  
544 /// <summary>Thread sync lock object</summary>
545 private readonly object m_DirEventsLock = new object();
546  
547 /// <summary>Raised when the data server responds to a <see cref="StartEventsSearch"/> request.</summary>
548 public event EventHandler<DirEventsReplyEventArgs> DirEventsReply
549 {
550 add { lock (m_DirEventsLock) { m_DirEvents += value; } }
551 remove { lock (m_DirEventsLock) { m_DirEvents -= value; } }
552 }
553  
554 /// <summary>The event subscribers. null if no subcribers</summary>
555 private EventHandler<PlacesReplyEventArgs> m_Places;
556  
557 /// <summary>Raises the PlacesReply event</summary>
558 /// <param name="e">A PlacesReplyEventArgs object containing the
559 /// data returned from the data server</param>
560 protected virtual void OnPlaces(PlacesReplyEventArgs e)
561 {
562 EventHandler<PlacesReplyEventArgs> handler = m_Places;
563 if (handler != null)
564 handler(this, e);
565 }
566  
567 /// <summary>Thread sync lock object</summary>
568 private readonly object m_PlacesLock = new object();
569  
570 /// <summary>Raised when the data server responds to a <see cref="StartPlacesSearch"/> request.</summary>
571 public event EventHandler<PlacesReplyEventArgs> PlacesReply
572 {
573 add { lock (m_PlacesLock) { m_Places += value; } }
574 remove { lock (m_PlacesLock) { m_Places -= value; } }
575 }
576  
577 /// <summary>The event subscribers. null if no subcribers</summary>
578 private EventHandler<DirPlacesReplyEventArgs> m_DirPlaces;
579  
580 /// <summary>Raises the DirPlacesReply event</summary>
581 /// <param name="e">A DirPlacesReplyEventArgs object containing the
582 /// data returned from the data server</param>
583 protected virtual void OnDirPlaces(DirPlacesReplyEventArgs e)
584 {
585 EventHandler<DirPlacesReplyEventArgs> handler = m_DirPlaces;
586 if (handler != null)
587 handler(this, e);
588 }
589  
590 /// <summary>Thread sync lock object</summary>
591 private readonly object m_DirPlacesLock = new object();
592  
593 /// <summary>Raised when the data server responds to a <see cref="StartDirPlacesSearch"/> request.</summary>
594 public event EventHandler<DirPlacesReplyEventArgs> DirPlacesReply
595 {
596 add { lock (m_DirPlacesLock) { m_DirPlaces += value; } }
597 remove { lock (m_DirPlacesLock) { m_DirPlaces -= value; } }
598 }
599  
600 /// <summary>The event subscribers. null if no subcribers</summary>
601 private EventHandler<DirClassifiedsReplyEventArgs> m_DirClassifieds;
602  
603 /// <summary>Raises the DirClassifiedsReply event</summary>
604 /// <param name="e">A DirClassifiedsReplyEventArgs object containing the
605 /// data returned from the data server</param>
606 protected virtual void OnDirClassifieds(DirClassifiedsReplyEventArgs e)
607 {
608 EventHandler<DirClassifiedsReplyEventArgs> handler = m_DirClassifieds;
609 if (handler != null)
610 handler(this, e);
611 }
612  
613 /// <summary>Thread sync lock object</summary>
614 private readonly object m_DirClassifiedsLock = new object();
615  
616 /// <summary>Raised when the data server responds to a <see cref="StartClassifiedSearch"/> request.</summary>
617 public event EventHandler<DirClassifiedsReplyEventArgs> DirClassifiedsReply
618 {
619 add { lock (m_DirClassifiedsLock) { m_DirClassifieds += value; } }
620 remove { lock (m_DirClassifiedsLock) { m_DirClassifieds -= value; } }
621 }
622  
623 /// <summary>The event subscribers. null if no subcribers</summary>
624 private EventHandler<DirGroupsReplyEventArgs> m_DirGroups;
625  
626 /// <summary>Raises the DirGroupsReply event</summary>
627 /// <param name="e">A DirGroupsReplyEventArgs object containing the
628 /// data returned from the data server</param>
629 protected virtual void OnDirGroups(DirGroupsReplyEventArgs e)
630 {
631 EventHandler<DirGroupsReplyEventArgs> handler = m_DirGroups;
632 if (handler != null)
633 handler(this, e);
634 }
635  
636 /// <summary>Thread sync lock object</summary>
637 private readonly object m_DirGroupsLock = new object();
638  
639 /// <summary>Raised when the data server responds to a <see cref="StartGroupSearch"/> request.</summary>
640 public event EventHandler<DirGroupsReplyEventArgs> DirGroupsReply
641 {
642 add { lock (m_DirGroupsLock) { m_DirGroups += value; } }
643 remove { lock (m_DirGroupsLock) { m_DirGroups -= value; } }
644 }
645  
646 /// <summary>The event subscribers. null if no subcribers</summary>
647 private EventHandler<DirPeopleReplyEventArgs> m_DirPeople;
648  
649 /// <summary>Raises the DirPeopleReply event</summary>
650 /// <param name="e">A DirPeopleReplyEventArgs object containing the
651 /// data returned from the data server</param>
652 protected virtual void OnDirPeople(DirPeopleReplyEventArgs e)
653 {
654 EventHandler<DirPeopleReplyEventArgs> handler = m_DirPeople;
655 if (handler != null)
656 handler(this, e);
657 }
658  
659 /// <summary>Thread sync lock object</summary>
660 private readonly object m_DirPeopleLock = new object();
661  
662 /// <summary>Raised when the data server responds to a <see cref="StartPeopleSearch"/> request.</summary>
663 public event EventHandler<DirPeopleReplyEventArgs> DirPeopleReply
664 {
665 add { lock (m_DirPeopleLock) { m_DirPeople += value; } }
666 remove { lock (m_DirPeopleLock) { m_DirPeople -= value; } }
667 }
668  
669 /// <summary>The event subscribers. null if no subcribers</summary>
670 private EventHandler<DirLandReplyEventArgs> m_DirLandReply;
671  
672 /// <summary>Raises the DirLandReply event</summary>
673 /// <param name="e">A DirLandReplyEventArgs object containing the
674 /// data returned from the data server</param>
675 protected virtual void OnDirLand(DirLandReplyEventArgs e)
676 {
677 EventHandler<DirLandReplyEventArgs> handler = m_DirLandReply;
678 if (handler != null)
679 handler(this, e);
680 }
681  
682 /// <summary>Thread sync lock object</summary>
683 private readonly object m_DirLandLock = new object();
684  
685 /// <summary>Raised when the data server responds to a <see cref="StartLandSearch"/> request.</summary>
686 public event EventHandler<DirLandReplyEventArgs> DirLandReply
687 {
688 add { lock (m_DirLandLock) { m_DirLandReply += value; } }
689 remove { lock (m_DirLandLock) { m_DirLandReply -= value; } }
690 }
691  
692 #endregion
693  
694 #region Private Members
695 private GridClient Client;
696 #endregion
697  
698 #region Constructors
699 /// <summary>
700 /// Constructs a new instance of the DirectoryManager class
701 /// </summary>
702 /// <param name="client">An instance of GridClient</param>
703 public DirectoryManager(GridClient client)
704 {
705 Client = client;
706  
707 Client.Network.RegisterCallback(PacketType.DirClassifiedReply, DirClassifiedReplyHandler);
708 // Deprecated, replies come in over capabilities
709 Client.Network.RegisterCallback(PacketType.DirLandReply, DirLandReplyHandler);
710 Client.Network.RegisterEventCallback("DirLandReply", DirLandReplyEventHandler);
711 Client.Network.RegisterCallback(PacketType.DirPeopleReply, DirPeopleReplyHandler);
712 Client.Network.RegisterCallback(PacketType.DirGroupsReply, DirGroupsReplyHandler);
713 // Deprecated as of viewer 1.2.3
714 Client.Network.RegisterCallback(PacketType.PlacesReply, PlacesReplyHandler);
715 Client.Network.RegisterEventCallback("PlacesReply", PlacesReplyEventHandler);
716 Client.Network.RegisterCallback(PacketType.DirEventsReply, EventsReplyHandler);
717 Client.Network.RegisterCallback(PacketType.EventInfoReply, EventInfoReplyHandler);
718 Client.Network.RegisterCallback(PacketType.DirPlacesReply, DirPlacesReplyHandler);
719 }
720  
721 #endregion
722  
723 #region Public Methods
724 // Obsoleted due to new Adult search option
725 [Obsolete("Use Overload with ClassifiedQueryFlags option instead")]
726 public UUID StartClassifiedSearch(string searchText, ClassifiedCategories category, bool mature)
727 {
728 return UUID.Zero;
729 }
730  
731 /// <summary>
732 /// Query the data server for a list of classified ads containing the specified string.
733 /// Defaults to searching for classified placed in any category, and includes PG, Adult and Mature
734 /// results.
735 ///
736 /// Responses are sent 16 per response packet, there is no way to know how many results a query reply will contain however assuming
737 /// the reply packets arrived ordered, a response with less than 16 entries would indicate all results have been received
738 ///
739 /// The <see cref="OnClassifiedReply"/> event is raised when a response is received from the simulator
740 /// </summary>
741 /// <param name="searchText">A string containing a list of keywords to search for</param>
742 /// <returns>A UUID to correlate the results when the <see cref="OnClassifiedReply"/> event is raised</returns>
743 public UUID StartClassifiedSearch(string searchText)
744 {
745 return StartClassifiedSearch(searchText, ClassifiedCategories.Any, ClassifiedQueryFlags.All);
746 }
747  
748 /// <summary>
749 /// Query the data server for a list of classified ads which contain specified keywords (Overload)
750 ///
751 /// The <see cref="OnClassifiedReply"/> event is raised when a response is received from the simulator
752 /// </summary>
753 /// <param name="searchText">A string containing a list of keywords to search for</param>
754 /// <param name="category">The category to search</param>
755 /// <param name="queryFlags">A set of flags which can be ORed to modify query options
756 /// such as classified maturity rating.</param>
757 /// <returns>A UUID to correlate the results when the <see cref="OnClassifiedReply"/> event is raised</returns>
758 /// <example>
759 /// Search classified ads containing the key words "foo" and "bar" in the "Any" category that are either PG or Mature
760 /// <code>
761 /// UUID searchID = StartClassifiedSearch("foo bar", ClassifiedCategories.Any, ClassifiedQueryFlags.PG | ClassifiedQueryFlags.Mature);
762 /// </code>
763 /// </example>
764 /// <remarks>
765 /// Responses are sent 16 at a time, there is no way to know how many results a query reply will contain however assuming
766 /// the reply packets arrived ordered, a response with less than 16 entries would indicate all results have been received
767 /// </remarks>
768 public UUID StartClassifiedSearch(string searchText, ClassifiedCategories category, ClassifiedQueryFlags queryFlags)
769 {
770 DirClassifiedQueryPacket query = new DirClassifiedQueryPacket();
771 UUID queryID = UUID.Random();
772  
773 query.AgentData.AgentID = Client.Self.AgentID;
774 query.AgentData.SessionID = Client.Self.SessionID;
775  
776 query.QueryData.Category = (uint)category;
777 query.QueryData.QueryFlags = (uint)queryFlags;
778 query.QueryData.QueryID = queryID;
779 query.QueryData.QueryText = Utils.StringToBytes(searchText);
780  
781 Client.Network.SendPacket(query);
782  
783 return queryID;
784 }
785  
786 /// <summary>
787 /// Starts search for places (Overloaded)
788 ///
789 /// The <see cref="OnDirPlacesReply"/> event is raised when a response is received from the simulator
790 /// </summary>
791 /// <param name="searchText">Search text</param>
792 /// <param name="queryStart">Each request is limited to 100 places
793 /// being returned. To get the first 100 result entries of a request use 0,
794 /// from 100-199 use 1, 200-299 use 2, etc.</param>
795 /// <returns>A UUID to correlate the results when the <see cref="OnDirPlacesReply"/> event is raised</returns>
796 public UUID StartDirPlacesSearch(string searchText, int queryStart)
797 {
798 return StartDirPlacesSearch(searchText, DirFindFlags.DwellSort | DirFindFlags.IncludePG | DirFindFlags.IncludeMature
799 | DirFindFlags.IncludeAdult, ParcelCategory.Any, queryStart);
800 }
801  
802 /// <summary>
803 /// Queries the dataserver for parcels of land which are flagged to be shown in search
804 ///
805 /// The <see cref="OnDirPlacesReply"/> event is raised when a response is received from the simulator
806 /// </summary>
807 /// <param name="searchText">A string containing a list of keywords to search for separated by a space character</param>
808 /// <param name="queryFlags">A set of flags which can be ORed to modify query options
809 /// such as classified maturity rating.</param>
810 /// <param name="category">The category to search</param>
811 /// <param name="queryStart">Each request is limited to 100 places
812 /// being returned. To get the first 100 result entries of a request use 0,
813 /// from 100-199 use 1, 200-299 use 2, etc.</param>
814 /// <returns>A UUID to correlate the results when the <see cref="OnDirPlacesReply"/> event is raised</returns>
815 /// <example>
816 /// Search places containing the key words "foo" and "bar" in the "Any" category that are either PG or Adult
817 /// <code>
818 /// UUID searchID = StartDirPlacesSearch("foo bar", DirFindFlags.DwellSort | DirFindFlags.IncludePG | DirFindFlags.IncludeAdult, ParcelCategory.Any, 0);
819 /// </code>
820 /// </example>
821 /// <remarks>
822 /// Additional information on the results can be obtained by using the ParcelManager.InfoRequest method
823 /// </remarks>
824 public UUID StartDirPlacesSearch(string searchText, DirFindFlags queryFlags, ParcelCategory category, int queryStart)
825 {
826 DirPlacesQueryPacket query = new DirPlacesQueryPacket();
827  
828 UUID queryID = UUID.Random();
829  
830 query.AgentData.AgentID = Client.Self.AgentID;
831 query.AgentData.SessionID = Client.Self.SessionID;
832  
833 query.QueryData.Category = (sbyte)category;
834 query.QueryData.QueryFlags = (uint)queryFlags;
835  
836 query.QueryData.QueryID = queryID;
837 query.QueryData.QueryText = Utils.StringToBytes(searchText);
838 query.QueryData.QueryStart = queryStart;
839 query.QueryData.SimName = Utils.StringToBytes(string.Empty);
840  
841 Client.Network.SendPacket(query);
842  
843 return queryID;
844  
845 }
846  
847 /// <summary>
848 /// Starts a search for land sales using the directory
849 ///
850 /// The <see cref="OnDirLandReply"/> event is raised when a response is received from the simulator
851 /// </summary>
852 /// <param name="typeFlags">What type of land to search for. Auction,
853 /// estate, mainland, "first land", etc</param>
854 /// <remarks>The OnDirLandReply event handler must be registered before
855 /// calling this function. There is no way to determine how many
856 /// results will be returned, or how many times the callback will be
857 /// fired other than you won't get more than 100 total parcels from
858 /// each query.</remarks>
859 public void StartLandSearch(SearchTypeFlags typeFlags)
860 {
861 StartLandSearch(DirFindFlags.SortAsc | DirFindFlags.PerMeterSort, typeFlags, 0, 0, 0);
862 }
863  
864 /// <summary>
865 /// Starts a search for land sales using the directory
866 ///
867 /// The <seealso cref="OnDirLandReply"/> event is raised when a response is received from the simulator
868 /// </summary>
869 /// <param name="typeFlags">What type of land to search for. Auction,
870 /// estate, mainland, "first land", etc</param>
871 /// <param name="priceLimit">Maximum price to search for</param>
872 /// <param name="areaLimit">Maximum area to search for</param>
873 /// <param name="queryStart">Each request is limited to 100 parcels
874 /// being returned. To get the first 100 parcels of a request use 0,
875 /// from 100-199 use 1, 200-299 use 2, etc.</param>
876 /// <remarks>The OnDirLandReply event handler must be registered before
877 /// calling this function. There is no way to determine how many
878 /// results will be returned, or how many times the callback will be
879 /// fired other than you won't get more than 100 total parcels from
880 /// each query.</remarks>
881 public void StartLandSearch(SearchTypeFlags typeFlags, int priceLimit, int areaLimit, int queryStart)
882 {
883 StartLandSearch(DirFindFlags.SortAsc | DirFindFlags.PerMeterSort | DirFindFlags.LimitByPrice |
884 DirFindFlags.LimitByArea, typeFlags, priceLimit, areaLimit, queryStart);
885 }
886  
887 /// <summary>
888 /// Send a request to the data server for land sales listings
889 /// </summary>
890 ///
891 /// <param name="findFlags">Flags sent to specify query options
892 ///
893 /// Available flags:
894 /// Specify the parcel rating with one or more of the following:
895 /// IncludePG IncludeMature IncludeAdult
896 ///
897 /// Specify the field to pre sort the results with ONLY ONE of the following:
898 /// PerMeterSort NameSort AreaSort PricesSort
899 ///
900 /// Specify the order the results are returned in, if not specified the results are pre sorted in a Descending Order
901 /// SortAsc
902 ///
903 /// Specify additional filters to limit the results with one or both of the following:
904 /// LimitByPrice LimitByArea
905 ///
906 /// Flags can be combined by separating them with the | (pipe) character
907 ///
908 /// Additional details can be found in <see cref="DirFindFlags"/>
909 /// </param>
910 /// <param name="typeFlags">What type of land to search for. Auction,
911 /// Estate or Mainland</param>
912 /// <param name="priceLimit">Maximum price to search for when the
913 /// DirFindFlags.LimitByPrice flag is specified in findFlags</param>
914 /// <param name="areaLimit">Maximum area to search for when the
915 /// DirFindFlags.LimitByArea flag is specified in findFlags</param>
916 /// <param name="queryStart">Each request is limited to 100 parcels
917 /// being returned. To get the first 100 parcels of a request use 0,
918 /// from 100-199 use 100, 200-299 use 200, etc.</param>
919 /// <remarks><para>The <seealso cref="OnDirLandReply"/> event will be raised with the response from the simulator
920 ///
921 /// There is no way to determine how many results will be returned, or how many times the callback will be
922 /// fired other than you won't get more than 100 total parcels from
923 /// each reply.</para>
924 ///
925 /// <para>Any land set for sale to either anybody or specific to the connected agent will be included in the
926 /// results if the land is included in the query</para></remarks>
927 /// <example>
928 /// <code>
929 /// // request all mainland, any maturity rating that is larger than 512 sq.m
930 /// StartLandSearch(DirFindFlags.SortAsc | DirFindFlags.PerMeterSort | DirFindFlags.LimitByArea | DirFindFlags.IncludePG | DirFindFlags.IncludeMature | DirFindFlags.IncludeAdult, SearchTypeFlags.Mainland, 0, 512, 0);
931 /// </code></example>
932 public void StartLandSearch(DirFindFlags findFlags, SearchTypeFlags typeFlags, int priceLimit,
933 int areaLimit, int queryStart)
934 {
935 DirLandQueryPacket query = new DirLandQueryPacket();
936 query.AgentData.AgentID = Client.Self.AgentID;
937 query.AgentData.SessionID = Client.Self.SessionID;
938 query.QueryData.Area = areaLimit;
939 query.QueryData.Price = priceLimit;
940 query.QueryData.QueryStart = queryStart;
941 query.QueryData.SearchType = (uint)typeFlags;
942 query.QueryData.QueryFlags = (uint)findFlags;
943 query.QueryData.QueryID = UUID.Random();
944  
945 Client.Network.SendPacket(query);
946 }
947  
948 /// <summary>
949 /// Search for Groups
950 /// </summary>
951 /// <param name="searchText">The name or portion of the name of the group you wish to search for</param>
952 /// <param name="queryStart">Start from the match number</param>
953 /// <returns></returns>
954 public UUID StartGroupSearch(string searchText, int queryStart)
955 {
956 return StartGroupSearch(searchText, queryStart, DirFindFlags.Groups | DirFindFlags.IncludePG
957 | DirFindFlags.IncludeMature | DirFindFlags.IncludeAdult);
958 }
959  
960 /// <summary>
961 /// Search for Groups
962 /// </summary>
963 /// <param name="searchText">The name or portion of the name of the group you wish to search for</param>
964 /// <param name="queryStart">Start from the match number</param>
965 /// <param name="flags">Search flags</param>
966 /// <returns></returns>
967 public UUID StartGroupSearch(string searchText, int queryStart, DirFindFlags flags)
968 {
969 DirFindQueryPacket find = new DirFindQueryPacket();
970 find.AgentData.AgentID = Client.Self.AgentID;
971 find.AgentData.SessionID = Client.Self.SessionID;
972 find.QueryData.QueryFlags = (uint)flags;
973 find.QueryData.QueryText = Utils.StringToBytes(searchText);
974 find.QueryData.QueryID = UUID.Random();
975 find.QueryData.QueryStart = queryStart;
976  
977 Client.Network.SendPacket(find);
978  
979 return find.QueryData.QueryID;
980 }
981  
982 /// <summary>
983 /// Search the People directory for other avatars
984 /// </summary>
985 /// <param name="searchText">The name or portion of the name of the avatar you wish to search for</param>
986 /// <param name="queryStart"></param>
987 /// <returns></returns>
988 public UUID StartPeopleSearch(string searchText, int queryStart)
989 {
990 DirFindQueryPacket find = new DirFindQueryPacket();
991 find.AgentData.AgentID = Client.Self.AgentID;
992 find.AgentData.SessionID = Client.Self.SessionID;
993 find.QueryData.QueryFlags = (uint)DirFindFlags.People;
994 find.QueryData.QueryText = Utils.StringToBytes(searchText);
995 find.QueryData.QueryID = UUID.Random();
996 find.QueryData.QueryStart = queryStart;
997  
998 Client.Network.SendPacket(find);
999  
1000 return find.QueryData.QueryID;
1001 }
1002  
1003 /// <summary>
1004 /// Search Places for parcels of land you personally own
1005 /// </summary>
1006 public UUID StartPlacesSearch()
1007 {
1008 return StartPlacesSearch(DirFindFlags.AgentOwned, ParcelCategory.Any, String.Empty, String.Empty,
1009 UUID.Zero, UUID.Random());
1010 }
1011  
1012 /// <summary>
1013 /// Searches Places for land owned by the specified group
1014 /// </summary>
1015 /// <param name="groupID">ID of the group you want to recieve land list for (You must be a member of the group)</param>
1016 /// <returns>Transaction (Query) ID which can be associated with results from your request.</returns>
1017 public UUID StartPlacesSearch(UUID groupID)
1018 {
1019 return StartPlacesSearch(DirFindFlags.GroupOwned, ParcelCategory.Any, String.Empty, String.Empty,
1020 groupID, UUID.Random());
1021 }
1022  
1023 /// <summary>
1024 /// Search the Places directory for parcels that are listed in search and contain the specified keywords
1025 /// </summary>
1026 /// <param name="searchText">A string containing the keywords to search for</param>
1027 /// <returns>Transaction (Query) ID which can be associated with results from your request.</returns>
1028 public UUID StartPlacesSearch(string searchText)
1029 {
1030 return StartPlacesSearch(DirFindFlags.DwellSort | DirFindFlags.IncludePG | DirFindFlags.IncludeMature | DirFindFlags.IncludeAdult,
1031 ParcelCategory.Any, searchText, String.Empty, UUID.Zero, UUID.Random());
1032 }
1033  
1034 /// <summary>
1035 /// Search Places - All Options
1036 /// </summary>
1037 /// <param name="findFlags">One of the Values from the DirFindFlags struct, ie: AgentOwned, GroupOwned, etc.</param>
1038 /// <param name="searchCategory">One of the values from the SearchCategory Struct, ie: Any, Linden, Newcomer</param>
1039 /// <param name="searchText">A string containing a list of keywords to search for separated by a space character</param>
1040 /// <param name="simulatorName">String Simulator Name to search in</param>
1041 /// <param name="groupID">LLUID of group you want to recieve results for</param>
1042 /// <param name="transactionID">Transaction (Query) ID which can be associated with results from your request.</param>
1043 /// <returns>Transaction (Query) ID which can be associated with results from your request.</returns>
1044 public UUID StartPlacesSearch(DirFindFlags findFlags, ParcelCategory searchCategory, string searchText, string simulatorName,
1045 UUID groupID, UUID transactionID)
1046 {
1047 PlacesQueryPacket find = new PlacesQueryPacket();
1048 find.AgentData.AgentID = Client.Self.AgentID;
1049 find.AgentData.SessionID = Client.Self.SessionID;
1050 find.AgentData.QueryID = groupID;
1051  
1052 find.TransactionData.TransactionID = transactionID;
1053  
1054 find.QueryData.QueryText = Utils.StringToBytes(searchText);
1055 find.QueryData.QueryFlags = (uint)findFlags;
1056 find.QueryData.Category = (sbyte)searchCategory;
1057 find.QueryData.SimName = Utils.StringToBytes(simulatorName);
1058  
1059 Client.Network.SendPacket(find);
1060 return transactionID;
1061 }
1062  
1063 /// <summary>
1064 /// Search All Events with specifid searchText in all categories, includes PG, Mature and Adult
1065 /// </summary>
1066 /// <param name="searchText">A string containing a list of keywords to search for separated by a space character</param>
1067 /// <param name="queryStart">Each request is limited to 100 entries
1068 /// being returned. To get the first group of entries of a request use 0,
1069 /// from 100-199 use 100, 200-299 use 200, etc.</param>
1070 /// <returns>UUID of query to correlate results in callback.</returns>
1071 public UUID StartEventsSearch(string searchText, uint queryStart)
1072 {
1073 return StartEventsSearch(searchText, DirFindFlags.DateEvents | DirFindFlags.IncludePG | DirFindFlags.IncludeMature | DirFindFlags.IncludeAdult,
1074 "u", queryStart, EventCategories.All);
1075 }
1076  
1077 /// <summary>
1078 /// Search Events
1079 /// </summary>
1080 /// <param name="searchText">A string containing a list of keywords to search for separated by a space character</param>
1081 /// <param name="queryFlags">One or more of the following flags: DateEvents, IncludePG, IncludeMature, IncludeAdult
1082 /// from the <see cref="DirFindFlags"/> Enum
1083 ///
1084 /// Multiple flags can be combined by separating the flags with the | (pipe) character</param>
1085 /// <param name="eventDay">"u" for in-progress and upcoming events, -or- number of days since/until event is scheduled
1086 /// For example "0" = Today, "1" = tomorrow, "2" = following day, "-1" = yesterday, etc.</param>
1087 /// <param name="queryStart">Each request is limited to 100 entries
1088 /// being returned. To get the first group of entries of a request use 0,
1089 /// from 100-199 use 100, 200-299 use 200, etc.</param>
1090 /// <param name="category">EventCategory event is listed under.</param>
1091 /// <returns>UUID of query to correlate results in callback.</returns>
1092 public UUID StartEventsSearch(string searchText, DirFindFlags queryFlags, string eventDay, uint queryStart, EventCategories category)
1093 {
1094 DirFindQueryPacket find = new DirFindQueryPacket();
1095 find.AgentData.AgentID = Client.Self.AgentID;
1096 find.AgentData.SessionID = Client.Self.SessionID;
1097  
1098 UUID queryID = UUID.Random();
1099  
1100 find.QueryData.QueryID = queryID;
1101 find.QueryData.QueryText = Utils.StringToBytes(eventDay + "|" + (int)category + "|" + searchText);
1102 find.QueryData.QueryFlags = (uint)queryFlags;
1103 find.QueryData.QueryStart = (int)queryStart;
1104  
1105 Client.Network.SendPacket(find);
1106 return queryID;
1107 }
1108  
1109 /// <summary>Requests Event Details</summary>
1110 /// <param name="eventID">ID of Event returned from the <see cref="StartEventsSearch"/> method</param>
1111 public void EventInfoRequest(uint eventID)
1112 {
1113 EventInfoRequestPacket find = new EventInfoRequestPacket();
1114 find.AgentData.AgentID = Client.Self.AgentID;
1115 find.AgentData.SessionID = Client.Self.SessionID;
1116  
1117 find.EventData.EventID = eventID;
1118  
1119 Client.Network.SendPacket(find);
1120 }
1121 #endregion
1122  
1123 #region Blocking Functions
1124  
1125 [Obsolete("Use the async StartPeoplSearch method instead")]
1126 public bool PeopleSearch(DirFindFlags findFlags, string searchText, int queryStart,
1127 int timeoutMS, out List<AgentSearchData> results)
1128 {
1129 AutoResetEvent searchEvent = new AutoResetEvent(false);
1130 UUID id = UUID.Zero;
1131 List<AgentSearchData> people = null;
1132  
1133 EventHandler<DirPeopleReplyEventArgs> callback =
1134 delegate(object sender, DirPeopleReplyEventArgs e)
1135 {
1136 if (id == e.QueryID)
1137 {
1138 people = e.MatchedPeople;
1139 searchEvent.Set();
1140 }
1141 };
1142  
1143 DirPeopleReply += callback;
1144  
1145 id = StartPeopleSearch(searchText, queryStart);
1146 searchEvent.WaitOne(timeoutMS, false);
1147 DirPeopleReply -= callback;
1148  
1149 results = people;
1150 return (results != null);
1151 }
1152  
1153 #endregion Blocking Functions
1154  
1155 #region Packet Handlers
1156  
1157 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1158 /// <param name="sender">The sender</param>
1159 /// <param name="e">The EventArgs object containing the packet data</param>
1160 protected void DirClassifiedReplyHandler(object sender, PacketReceivedEventArgs e)
1161 {
1162 if (m_DirClassifieds != null)
1163 {
1164 DirClassifiedReplyPacket reply = (DirClassifiedReplyPacket)e.Packet;
1165 List<Classified> classifieds = new List<Classified>();
1166  
1167 foreach (DirClassifiedReplyPacket.QueryRepliesBlock block in reply.QueryReplies)
1168 {
1169 Classified classified = new Classified();
1170  
1171 classified.CreationDate = Utils.UnixTimeToDateTime(block.CreationDate);
1172 classified.ExpirationDate = Utils.UnixTimeToDateTime(block.ExpirationDate);
1173 classified.Flags = (ClassifiedFlags)block.ClassifiedFlags;
1174 classified.ID = block.ClassifiedID;
1175 classified.Name = Utils.BytesToString(block.Name);
1176 classified.Price = block.PriceForListing;
1177  
1178 classifieds.Add(classified);
1179 }
1180  
1181 OnDirClassifieds(new DirClassifiedsReplyEventArgs(classifieds));
1182 }
1183 }
1184  
1185 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1186 /// <param name="sender">The sender</param>
1187 /// <param name="e">The EventArgs object containing the packet data</param>
1188 protected void DirLandReplyHandler(object sender, PacketReceivedEventArgs e)
1189 {
1190 if (m_DirLandReply != null)
1191 {
1192 List<DirectoryParcel> parcelsForSale = new List<DirectoryParcel>();
1193 DirLandReplyPacket reply = (DirLandReplyPacket)e.Packet;
1194  
1195 foreach (DirLandReplyPacket.QueryRepliesBlock block in reply.QueryReplies)
1196 {
1197 DirectoryParcel dirParcel = new DirectoryParcel();
1198  
1199 dirParcel.ActualArea = block.ActualArea;
1200 dirParcel.ID = block.ParcelID;
1201 dirParcel.Name = Utils.BytesToString(block.Name);
1202 dirParcel.SalePrice = block.SalePrice;
1203 dirParcel.Auction = block.Auction;
1204 dirParcel.ForSale = block.ForSale;
1205  
1206 parcelsForSale.Add(dirParcel);
1207 }
1208 OnDirLand(new DirLandReplyEventArgs(parcelsForSale));
1209 }
1210 }
1211  
1212 /// <summary>Process an incoming <see cref="DirLandReplyMessage"/> event message</summary>
1213 /// <param name="capsKey">The Unique Capabilities Key</param>
1214 /// <param name="message">The <see cref="DirLandReplyMessage"/> event message containing the data</param>
1215 /// <param name="simulator">The simulator the message originated from</param>
1216 protected void DirLandReplyEventHandler(string capsKey, IMessage message, Simulator simulator)
1217 {
1218 if (m_DirLandReply != null)
1219 {
1220 List<DirectoryParcel> parcelsForSale = new List<DirectoryParcel>();
1221  
1222 DirLandReplyMessage reply = (DirLandReplyMessage)message;
1223  
1224 foreach (DirLandReplyMessage.QueryReply block in reply.QueryReplies)
1225 {
1226 DirectoryParcel dirParcel = new DirectoryParcel();
1227  
1228 dirParcel.ActualArea = block.ActualArea;
1229 dirParcel.ID = block.ParcelID;
1230 dirParcel.Name = block.Name;
1231 dirParcel.SalePrice = block.SalePrice;
1232 dirParcel.Auction = block.Auction;
1233 dirParcel.ForSale = block.ForSale;
1234  
1235 parcelsForSale.Add(dirParcel);
1236 }
1237  
1238 OnDirLand(new DirLandReplyEventArgs(parcelsForSale));
1239 }
1240 }
1241  
1242 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1243 /// <param name="sender">The sender</param>
1244 /// <param name="e">The EventArgs object containing the packet data</param>
1245 protected void DirPeopleReplyHandler(object sender, PacketReceivedEventArgs e)
1246 {
1247 if (m_DirPeople != null)
1248 {
1249 DirPeopleReplyPacket peopleReply = e.Packet as DirPeopleReplyPacket;
1250 List<AgentSearchData> matches = new List<AgentSearchData>(peopleReply.QueryReplies.Length);
1251 foreach (DirPeopleReplyPacket.QueryRepliesBlock reply in peopleReply.QueryReplies)
1252 {
1253 AgentSearchData searchData = new AgentSearchData();
1254 searchData.Online = reply.Online;
1255 searchData.FirstName = Utils.BytesToString(reply.FirstName);
1256 searchData.LastName = Utils.BytesToString(reply.LastName);
1257 searchData.AgentID = reply.AgentID;
1258 matches.Add(searchData);
1259 }
1260  
1261 OnDirPeople(new DirPeopleReplyEventArgs(peopleReply.QueryData.QueryID, matches));
1262 }
1263 }
1264  
1265 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1266 /// <param name="sender">The sender</param>
1267 /// <param name="e">The EventArgs object containing the packet data</param>
1268 protected void DirGroupsReplyHandler(object sender, PacketReceivedEventArgs e)
1269 {
1270 if (m_DirGroups != null)
1271 {
1272 Packet packet = e.Packet;
1273 DirGroupsReplyPacket groupsReply = (DirGroupsReplyPacket)packet;
1274 List<GroupSearchData> matches = new List<GroupSearchData>(groupsReply.QueryReplies.Length);
1275 foreach (DirGroupsReplyPacket.QueryRepliesBlock reply in groupsReply.QueryReplies)
1276 {
1277 GroupSearchData groupsData = new GroupSearchData();
1278 groupsData.GroupID = reply.GroupID;
1279 groupsData.GroupName = Utils.BytesToString(reply.GroupName);
1280 groupsData.Members = reply.Members;
1281 matches.Add(groupsData);
1282 }
1283  
1284 OnDirGroups(new DirGroupsReplyEventArgs(groupsReply.QueryData.QueryID, matches));
1285 }
1286 }
1287  
1288 /// <summary>Process an incoming <see cref="PlacesReplyMessage"/> event message</summary>
1289 /// <param name="capsKey">The Unique Capabilities Key</param>
1290 /// <param name="message">The <see cref="PlacesReplyMessage"/> event message containing the data</param>
1291 /// <param name="simulator">The simulator the message originated from</param>
1292 protected void PlacesReplyEventHandler(string capsKey, IMessage message, Simulator simulator)
1293 {
1294 if (m_Places != null)
1295 {
1296 PlacesReplyMessage replyMessage = (PlacesReplyMessage)message;
1297 List<PlacesSearchData> places = new List<PlacesSearchData>();
1298  
1299 for (int i = 0; i < replyMessage.QueryDataBlocks.Length; i++)
1300 {
1301 PlacesSearchData place = new PlacesSearchData();
1302 place.ActualArea = replyMessage.QueryDataBlocks[i].ActualArea;
1303 place.BillableArea = replyMessage.QueryDataBlocks[i].BillableArea;
1304 place.Desc = replyMessage.QueryDataBlocks[i].Description;
1305 place.Dwell = replyMessage.QueryDataBlocks[i].Dwell;
1306 place.Flags = (DirectoryManager.PlacesFlags)(byte)replyMessage.QueryDataBlocks[i].Flags;
1307 place.GlobalX = replyMessage.QueryDataBlocks[i].GlobalX;
1308 place.GlobalY = replyMessage.QueryDataBlocks[i].GlobalY;
1309 place.GlobalZ = replyMessage.QueryDataBlocks[i].GlobalZ;
1310 place.Name = replyMessage.QueryDataBlocks[i].Name;
1311 place.OwnerID = replyMessage.QueryDataBlocks[i].OwnerID;
1312 place.Price = replyMessage.QueryDataBlocks[i].Price;
1313 place.SimName = replyMessage.QueryDataBlocks[i].SimName;
1314 place.SnapshotID = replyMessage.QueryDataBlocks[i].SnapShotID;
1315 place.SKU = replyMessage.QueryDataBlocks[i].ProductSku;
1316 places.Add(place);
1317 }
1318  
1319 OnPlaces(new PlacesReplyEventArgs(replyMessage.QueryID, places));
1320 }
1321 }
1322  
1323 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1324 /// <param name="sender">The sender</param>
1325 /// <param name="e">The EventArgs object containing the packet data</param>
1326 protected void PlacesReplyHandler(object sender, PacketReceivedEventArgs e)
1327 {
1328 if (m_Places != null)
1329 {
1330 Packet packet = e.Packet;
1331 PlacesReplyPacket placesReply = packet as PlacesReplyPacket;
1332 List<PlacesSearchData> places = new List<PlacesSearchData>();
1333  
1334 foreach (PlacesReplyPacket.QueryDataBlock block in placesReply.QueryData)
1335 {
1336 PlacesSearchData place = new PlacesSearchData();
1337 place.OwnerID = block.OwnerID;
1338 place.Name = Utils.BytesToString(block.Name);
1339 place.Desc = Utils.BytesToString(block.Desc);
1340 place.ActualArea = block.ActualArea;
1341 place.BillableArea = block.BillableArea;
1342 place.Flags = (PlacesFlags)block.Flags;
1343 place.GlobalX = block.GlobalX;
1344 place.GlobalY = block.GlobalY;
1345 place.GlobalZ = block.GlobalZ;
1346 place.SimName = Utils.BytesToString(block.SimName);
1347 place.SnapshotID = block.SnapshotID;
1348 place.Dwell = block.Dwell;
1349 place.Price = block.Price;
1350  
1351 places.Add(place);
1352 }
1353  
1354 OnPlaces(new PlacesReplyEventArgs(placesReply.TransactionData.TransactionID, places));
1355 }
1356 }
1357  
1358 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1359 /// <param name="sender">The sender</param>
1360 /// <param name="e">The EventArgs object containing the packet data</param>
1361 protected void EventsReplyHandler(object sender, PacketReceivedEventArgs e)
1362 {
1363 if (m_DirEvents != null)
1364 {
1365 Packet packet = e.Packet;
1366 DirEventsReplyPacket eventsReply = (DirEventsReplyPacket)packet;
1367 List<EventsSearchData> matches = new List<EventsSearchData>(eventsReply.QueryReplies.Length);
1368  
1369 foreach (DirEventsReplyPacket.QueryRepliesBlock reply in eventsReply.QueryReplies)
1370 {
1371 EventsSearchData eventsData = new EventsSearchData();
1372 eventsData.Owner = reply.OwnerID;
1373 eventsData.Name = Utils.BytesToString(reply.Name);
1374 eventsData.ID = reply.EventID;
1375 eventsData.Date = Utils.BytesToString(reply.Date);
1376 eventsData.Time = reply.UnixTime;
1377 eventsData.Flags = (EventFlags)reply.EventFlags;
1378 matches.Add(eventsData);
1379 }
1380  
1381 OnDirEvents(new DirEventsReplyEventArgs(eventsReply.QueryData.QueryID, matches));
1382 }
1383 }
1384  
1385 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1386 /// <param name="sender">The sender</param>
1387 /// <param name="e">The EventArgs object containing the packet data</param>
1388 protected void EventInfoReplyHandler(object sender, PacketReceivedEventArgs e)
1389 {
1390 if (m_EventInfoReply != null)
1391 {
1392 Packet packet = e.Packet;
1393 EventInfoReplyPacket eventReply = (EventInfoReplyPacket)packet;
1394 EventInfo evinfo = new EventInfo();
1395 evinfo.ID = eventReply.EventData.EventID;
1396 evinfo.Name = Utils.BytesToString(eventReply.EventData.Name);
1397 evinfo.Desc = Utils.BytesToString(eventReply.EventData.Desc);
1398 evinfo.Amount = eventReply.EventData.Amount;
1399 evinfo.Category = (EventCategories)Utils.BytesToUInt(eventReply.EventData.Category);
1400 evinfo.Cover = eventReply.EventData.Cover;
1401 evinfo.Creator = (UUID)Utils.BytesToString(eventReply.EventData.Creator);
1402 evinfo.Date = Utils.BytesToString(eventReply.EventData.Date);
1403 evinfo.DateUTC = eventReply.EventData.DateUTC;
1404 evinfo.Duration = eventReply.EventData.Duration;
1405 evinfo.Flags = (EventFlags)eventReply.EventData.EventFlags;
1406 evinfo.SimName = Utils.BytesToString(eventReply.EventData.SimName);
1407 evinfo.GlobalPos = eventReply.EventData.GlobalPos;
1408  
1409 OnEventInfo(new EventInfoReplyEventArgs(evinfo));
1410 }
1411 }
1412  
1413 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1414 /// <param name="sender">The sender</param>
1415 /// <param name="e">The EventArgs object containing the packet data</param>
1416 protected void DirPlacesReplyHandler(object sender, PacketReceivedEventArgs e)
1417 {
1418 if (m_DirPlaces != null)
1419 {
1420 Packet packet = e.Packet;
1421 DirPlacesReplyPacket reply = (DirPlacesReplyPacket)packet;
1422 List<DirectoryParcel> result = new List<DirectoryParcel>();
1423  
1424 for (int i = 0; i < reply.QueryReplies.Length; i++)
1425 {
1426 DirectoryParcel p = new DirectoryParcel();
1427  
1428 p.ID = reply.QueryReplies[i].ParcelID;
1429 p.Name = Utils.BytesToString(reply.QueryReplies[i].Name);
1430 p.Dwell = reply.QueryReplies[i].Dwell;
1431 p.Auction = reply.QueryReplies[i].Auction;
1432 p.ForSale = reply.QueryReplies[i].ForSale;
1433  
1434 result.Add(p);
1435 }
1436  
1437 OnDirPlaces(new DirPlacesReplyEventArgs(reply.QueryData[0].QueryID, result));
1438 }
1439 }
1440  
1441 #endregion Packet Handlers
1442 }
1443  
1444 #region DirectoryManager EventArgs Classes
1445  
1446 /// <summary>Contains the Event data returned from the data server from an EventInfoRequest</summary>
1447 public class EventInfoReplyEventArgs : EventArgs
1448 {
1449 private readonly DirectoryManager.EventInfo m_MatchedEvent;
1450  
1451 /// <summary>
1452 /// A single EventInfo object containing the details of an event
1453 /// </summary>
1454 public DirectoryManager.EventInfo MatchedEvent { get { return m_MatchedEvent; } }
1455  
1456 /// <summary>Construct a new instance of the EventInfoReplyEventArgs class</summary>
1457 /// <param name="matchedEvent">A single EventInfo object containing the details of an event</param>
1458 public EventInfoReplyEventArgs(DirectoryManager.EventInfo matchedEvent)
1459 {
1460 this.m_MatchedEvent = matchedEvent;
1461 }
1462 }
1463  
1464 /// <summary>Contains the "Event" detail data returned from the data server</summary>
1465 public class DirEventsReplyEventArgs : EventArgs
1466 {
1467 private readonly UUID m_QueryID;
1468 /// <summary>The ID returned by <see cref="DirectoryManager.StartEventsSearch"/></summary>
1469 public UUID QueryID { get { return m_QueryID; } }
1470  
1471 private readonly List<DirectoryManager.EventsSearchData> m_matchedEvents;
1472  
1473 /// <summary>A list of "Events" returned by the data server</summary>
1474 public List<DirectoryManager.EventsSearchData> MatchedEvents { get { return m_matchedEvents; } }
1475  
1476 /// <summary>Construct a new instance of the DirEventsReplyEventArgs class</summary>
1477 /// <param name="queryID">The ID of the query returned by the data server.
1478 /// This will correlate to the ID returned by the <see cref="StartEventsSearch"/> method</param>
1479 /// <param name="matchedEvents">A list containing the "Events" returned by the search query</param>
1480 public DirEventsReplyEventArgs(UUID queryID, List<DirectoryManager.EventsSearchData> matchedEvents)
1481 {
1482 this.m_QueryID = queryID;
1483 this.m_matchedEvents = matchedEvents;
1484 }
1485 }
1486  
1487 /// <summary>Contains the "Event" list data returned from the data server</summary>
1488 public class PlacesReplyEventArgs : EventArgs
1489 {
1490 private readonly UUID m_QueryID;
1491 /// <summary>The ID returned by <see cref="DirectoryManager.StartPlacesSearch"/></summary>
1492 public UUID QueryID { get { return m_QueryID; } }
1493  
1494 private readonly List<DirectoryManager.PlacesSearchData> m_MatchedPlaces;
1495  
1496 /// <summary>A list of "Places" returned by the data server</summary>
1497 public List<DirectoryManager.PlacesSearchData> MatchedPlaces { get { return m_MatchedPlaces; } }
1498  
1499 /// <summary>Construct a new instance of PlacesReplyEventArgs class</summary>
1500 /// <param name="queryID">The ID of the query returned by the data server.
1501 /// This will correlate to the ID returned by the <see cref="StartPlacesSearch"/> method</param>
1502 /// <param name="matchedPlaces">A list containing the "Places" returned by the data server query</param>
1503 public PlacesReplyEventArgs(UUID queryID, List<DirectoryManager.PlacesSearchData> matchedPlaces)
1504 {
1505 this.m_QueryID = queryID;
1506 this.m_MatchedPlaces = matchedPlaces;
1507 }
1508 }
1509  
1510 /// <summary>Contains the places data returned from the data server</summary>
1511 public class DirPlacesReplyEventArgs : EventArgs
1512 {
1513 private readonly UUID m_QueryID;
1514 /// <summary>The ID returned by <see cref="DirectoryManager.StartDirPlacesSearch"/></summary>
1515 public UUID QueryID { get { return m_QueryID; } }
1516  
1517 private readonly List<DirectoryManager.DirectoryParcel> m_MatchedParcels;
1518  
1519 /// <summary>A list containing Places data returned by the data server</summary>
1520 public List<DirectoryManager.DirectoryParcel> MatchedParcels { get { return m_MatchedParcels; } }
1521  
1522 /// <summary>Construct a new instance of the DirPlacesReplyEventArgs class</summary>
1523 /// <param name="queryID">The ID of the query returned by the data server.
1524 /// This will correlate to the ID returned by the <see cref="StartDirPlacesSearch"/> method</param>
1525 /// <param name="matchedParcels">A list containing land data returned by the data server</param>
1526 public DirPlacesReplyEventArgs(UUID queryID, List<DirectoryManager.DirectoryParcel> matchedParcels)
1527 {
1528 this.m_QueryID = queryID;
1529 this.m_MatchedParcels = matchedParcels;
1530 }
1531 }
1532  
1533 /// <summary>Contains the classified data returned from the data server</summary>
1534 public class DirClassifiedsReplyEventArgs : EventArgs
1535 {
1536 private readonly List<DirectoryManager.Classified> m_Classifieds;
1537 /// <summary>A list containing Classified Ads returned by the data server</summary>
1538 public List<DirectoryManager.Classified> Classifieds { get { return m_Classifieds; } }
1539  
1540 /// <summary>Construct a new instance of the DirClassifiedsReplyEventArgs class</summary>
1541 /// <param name="classifieds">A list of classified ad data returned from the data server</param>
1542 public DirClassifiedsReplyEventArgs(List<DirectoryManager.Classified> classifieds)
1543 {
1544 this.m_Classifieds = classifieds;
1545 }
1546 }
1547  
1548 /// <summary>Contains the group data returned from the data server</summary>
1549 public class DirGroupsReplyEventArgs : EventArgs
1550 {
1551 private readonly UUID m_QueryID;
1552 /// <summary>The ID returned by <see cref="DirectoryManager.StartGroupSearch"/></summary>
1553 public UUID QueryID { get { return m_QueryID; } }
1554  
1555 private readonly List<DirectoryManager.GroupSearchData> m_matchedGroups;
1556  
1557 /// <summary>A list containing Groups data returned by the data server</summary>
1558 public List<DirectoryManager.GroupSearchData> MatchedGroups { get { return m_matchedGroups; } }
1559  
1560 /// <summary>Construct a new instance of the DirGroupsReplyEventArgs class</summary>
1561 /// <param name="queryID">The ID of the query returned by the data server.
1562 /// This will correlate to the ID returned by the <see cref="StartGroupSearch"/> method</param>
1563 /// <param name="matchedGroups">A list of groups data returned by the data server</param>
1564 public DirGroupsReplyEventArgs(UUID queryID, List<DirectoryManager.GroupSearchData> matchedGroups)
1565 {
1566 this.m_QueryID = queryID;
1567 this.m_matchedGroups = matchedGroups;
1568 }
1569 }
1570  
1571 /// <summary>Contains the people data returned from the data server</summary>
1572 public class DirPeopleReplyEventArgs : EventArgs
1573 {
1574 private readonly UUID m_QueryID;
1575 /// <summary>The ID returned by <see cref="DirectoryManager.StartPeopleSearch"/></summary>
1576 public UUID QueryID { get { return m_QueryID; } }
1577  
1578 private readonly List<DirectoryManager.AgentSearchData> m_MatchedPeople;
1579  
1580 /// <summary>A list containing People data returned by the data server</summary>
1581 public List<DirectoryManager.AgentSearchData> MatchedPeople { get { return m_MatchedPeople; } }
1582  
1583 /// <summary>Construct a new instance of the DirPeopleReplyEventArgs class</summary>
1584 /// <param name="queryID">The ID of the query returned by the data server.
1585 /// This will correlate to the ID returned by the <see cref="StartPeopleSearch"/> method</param>
1586 /// <param name="matchedPeople">A list of people data returned by the data server</param>
1587 public DirPeopleReplyEventArgs(UUID queryID, List<DirectoryManager.AgentSearchData> matchedPeople)
1588 {
1589 this.m_QueryID = queryID;
1590 this.m_MatchedPeople = matchedPeople;
1591 }
1592 }
1593  
1594 /// <summary>Contains the land sales data returned from the data server</summary>
1595 public class DirLandReplyEventArgs : EventArgs
1596 {
1597 private readonly List<DirectoryManager.DirectoryParcel> m_DirParcels;
1598  
1599 /// <summary>A list containing land forsale data returned by the data server</summary>
1600 public List<DirectoryManager.DirectoryParcel> DirParcels { get { return m_DirParcels; } }
1601  
1602 /// <summary>Construct a new instance of the DirLandReplyEventArgs class</summary>
1603 /// <param name="dirParcels">A list of parcels for sale returned by the data server</param>
1604 public DirLandReplyEventArgs(List<DirectoryManager.DirectoryParcel> dirParcels)
1605 {
1606 this.m_DirParcels = dirParcels;
1607 }
1608 }
1609 #endregion
1610 }