1 /******************************************************************************
3 * Copyright (c) 2003 Novell Inc., www.novell.com
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the Software), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 *******************************************************************************/
25 // System.DirectoryServices.DirectorySearcher.cs
28 // Sunil Kumar (sunilk@novell.com)
29 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
34 using System
.ComponentModel
;
35 using Novell
.Directory
.Ldap
;
36 using Novell
.Directory
.Ldap
.Utilclass
;
37 using System
.Collections
.Specialized
;
39 namespace System
.DirectoryServices
43 ///Performs queries against Ldap directory.
45 public class DirectorySearcher
: Component
48 private DirectoryEntry _SearchRoot
=null;
49 private bool _CacheResults
=true;
50 private TimeSpan _ClientTimeout
= new TimeSpan(-1);
51 private string _Filter
="(objectClass=*)";
52 private int _PageSize
=0;
53 private StringCollection _PropertiesToLoad
=new StringCollection();
54 private bool _PropertyNamesOnly
=false;
55 private ReferralChasingOption _ReferralChasing
=
56 System
.DirectoryServices
.ReferralChasingOption
.External
;
57 private SearchScope _SearchScope
=
58 System
.DirectoryServices
.SearchScope
.Subtree
;
59 private TimeSpan _ServerPageTimeLimit
=new TimeSpan(-1);
60 private int _SizeLimit
=1000;
61 private LdapConnection _conn
= null;
62 private string _Host
=null;
63 private int _Port
=389;
64 private SearchResultCollection _SrchColl
=null;
65 private bool emptycoll
=true;
67 internal SearchResultCollection SrchColl
73 _SrchColl
= new SearchResultCollection();
81 private void InitBlock()
83 _conn
= new LdapConnection();
84 LdapUrl lUrl
=new LdapUrl(SearchRoot
.Path
);
87 _conn
.Connect(_Host
,_Port
);
88 _conn
.Bind(SearchRoot
.Username
,SearchRoot
.Password
);
93 /// Gets or sets a value indicating whether the result is
94 /// cached on the client computer.
97 /// true if the result is cached on the client computer; otherwise,
98 /// false. The default is true
101 /// If the search returns a large result set, it is better to set
102 /// this property to false.
104 [DSDescription ("The cacheability of results.")]
105 [DefaultValue (true)]
106 public bool CacheResults
110 return _CacheResults
;
114 CacheResults
= value;
119 /// Gets or sets the maximum amount of time that the client waits for
120 /// the server to return results. If the server does not respond
121 /// within this time, the search is aborted and no results are
125 /// A TimeSpan that represents the maximum amount of time (in seconds)
126 /// for the client to wait for the server to return results. The
127 /// default is -1, which means to wait indefinitely.
130 /// If the ServerTimeLimit is reached before the client times out,
131 /// the server returns its results and the client stops waiting. The
132 /// maximum server time limit is 120 seconds.
134 [DSDescription ("The maximum amount of time that the client waits for the server to return results.")]
135 public TimeSpan ClientTimeout
139 return _ClientTimeout
;
143 _ClientTimeout
= value;
148 /// Gets or sets the Lightweight Directory Access Protocol (Ldap)
149 /// format filter string.
152 /// The search filter string in Ldap format, such as
153 /// "(objectClass=user)". The default is "(objectClass=*)", which
154 /// retrieves all objects.
157 /// The filter uses the following guidelines:
158 /// 1. The string must be enclosed in parentheses.
159 /// 2. Expressions can use the relational operators: <, <=, =, >=,
160 /// and >. An example is "(objectClass=user)". Another example is
161 /// "(lastName>=Davis)".
162 /// 3. Compound expressions are formed with the prefix operators &
163 /// and |. Anexampleis"(&(objectClass=user)(lastName= Davis))".
164 /// Anotherexampleis"(&(objectClass=printer)(|(building=42)
165 /// (building=43)))".
167 [DSDescription ("The Lightweight Directory Access Protocol (Ldap) format filter string.")]
168 [DefaultValue ("(objectClass=*)")]
169 [RecommendedAsConfigurable (true)]
170 [TypeConverter ("System.Diagnostics.Design.StringValueConverter, " + Consts
.AssemblySystem_Design
)]
184 /// Gets or sets the page size in a paged search.
187 /// The maximum number of objects the server can return in a paged
188 /// search. The default is zero, which means do not do a paged search.
191 /// After the server has found a PageSize object, it will stop
192 /// searching and return the results to the client. When the client
193 /// requests more data, the server will restart the search where it
196 [DSDescription ("The page size in a paged search.")]
211 /// Gets the set of properties retrieved during the search.
214 /// The set of properties retrieved during the search. The default is
215 /// an empty StringCollection, which retrieves all properties.
218 /// To retrieve specific properties, add them to this collection
219 /// before you begin the search. For example, searcher.
220 /// PropertiesToLoad.Add("phone");.
222 [DSDescription ("The set of properties retrieved during the search.")]
223 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Content
)]
224 [Editor ("System.Windows.Forms.Design.StringCollectionEditor, " + Consts
.AssemblySystem_Design
, "System.Drawing.Design.UITypeEditor, " + Consts
.AssemblySystem_Drawing
)]
225 public StringCollection PropertiesToLoad
229 return _PropertiesToLoad
;
234 /// Gets or sets a value indicating whether the search retrieves only the
235 /// names of attributes to which values have been assigned.
238 /// true if the search obtains only the names of attributes to which
239 /// values have been assigned; false if the search obtains the names
240 /// and values for all the requested attributes. The default is false.
242 [DSDescription ("A value indicating whether the search retrieves only the names of attributes to which values have been assigned.")]
243 [DefaultValue (false)]
244 public bool PropertyNamesOnly
248 return _PropertyNamesOnly
;
252 _PropertyNamesOnly
= value;
257 /// Gets or sets how referrals are chased.
260 /// One of the ReferralChasingOption values. The default is External.
263 /// If the root search is not specified in the naming context of the
264 /// server or when the search results cross a naming context (for
265 /// example, when you have child domains and search in the parent
266 /// domain), the server sends a referral message to the client that
267 /// the client can choose to ignore or chase.
269 [DSDescription ("How referrals are chased.")]
270 [DefaultValue (ReferralChasingOption
.External
)]
271 public ReferralChasingOption ReferralChasing
275 return _ReferralChasing
;
279 _ReferralChasing
= value;
284 /// Gets or sets the node in the Ldap Directory hierarchy where the
288 /// The DirectoryEntry in the Ldap Directory hierarchy where the
289 /// search starts. The default is a null reference
291 [DSDescription ("The node in the Ldap Directory hierarchy where the search starts.")]
292 [DefaultValue (null)]
293 public DirectoryEntry SearchRoot
306 /// Gets or sets the scope of the search that is observed by the
310 /// One of the SearchScope values. The default is Subtree.
312 [DSDescription ("The scope of the search that is observed by the server.")]
313 [DefaultValue (SearchScope
.Subtree
)]
314 [RecommendedAsConfigurable (true)]
315 public SearchScope SearchScope
323 _SearchScope
= value;
328 /// Gets or sets the time limit the server should observe to search an
329 /// individual page of results (as opposed to the time limit for the
333 /// A TimeSpan that represents the amount of time the server should
334 /// observe to search a page of results. The default is -1, which
335 /// means to search indefinitely.
338 /// When the time limit is reached, the server stops searching and
339 /// returns the result obtained up to that point, along with a cookie
340 /// containing the information about where to resume searching.
341 /// A negative value means to search indefinitely.
342 /// Note: This property only applies to searches where PageSize
343 /// is set to a value that is not the default of -1.
345 [DSDescription ("The time limit the server should observe to search an individual page of results.")]
346 public TimeSpan ServerPageTimeLimit
350 return _ServerPageTimeLimit
;
354 _ServerPageTimeLimit
= value;
359 /// Gets or sets the time limit the server should observe to search.
362 /// A TimeSpan that represents the amount of time the server should
363 /// observe to search.
368 [DSDescription ("The time limit the server should observe to search.")]
369 public TimeSpan ServerTimeLimit
374 throw new NotImplementedException();
379 throw new NotImplementedException();
384 /// Gets or sets the maximum number of objects the server returns in
388 /// The maximum number of objects the server returns in a search. The
389 /// default of zero means to use the server-determined default size
390 /// limit of 1000 entries.
393 /// The server stops searching after the size limit is reached and
394 /// returns the results accumulated up to that point.
395 /// Note: If you set SizeLimit to a value that is larger
396 /// than the server-determined default of 1000 entries, the
397 /// server-determined default is used.
399 [DSDescription ("The maximum number of objects the server returns in a search.")]
413 [DSDescription ("An object that defines how the data should be sorted.")]
414 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Content
)]
415 [TypeConverter (typeof (ExpandableObjectConverter
))]
416 public SortOption Sort
421 throw new NotImplementedException();
426 throw new NotImplementedException();
431 /// Initializes a new instance of the DirectorySearcher class with
432 /// SearchRoot, Filter, PropertiesToLoad, and SearchScope set to the
435 public DirectorySearcher()
440 /// Initializes a new instance of the DirectorySearcher class with
441 /// Filter, PropertiesToLoad, and SearchScope set to the default
442 /// values. SearchRoot is set to the specified value.
444 /// <param name="searchRoot">
445 /// The node in the Active Directory hierarchy where the search starts.
446 /// The SearchRoot property is initialized to this value.
448 public DirectorySearcher(DirectoryEntry searchRoot
)
450 _SearchRoot
= searchRoot
;
454 /// Initializes a new instance of the DirectorySearcher class with
455 /// SearchRoot, PropertiesToLoad, and SearchScope set to the default
456 /// values. Filter is set to the specified value.
458 /// <param name="filter">
459 /// The search filter string in Lightweight Directory Access Protocol
460 /// (Ldap) format. The Filter property is initialized to this value.
462 public DirectorySearcher(string filter
)
468 /// Initializes a new instance of the DirectorySearcher class with
469 /// PropertiesToLoad and SearchScope set to the default values.
470 /// SearchRoot and Filter are set to the specified values.
472 /// <param name="searchRoot">
473 /// The node in the Active Directory hierarchy where the search starts.
474 /// The SearchRoot property is initialized to this value.
476 /// <param name="filter">
477 /// The search filter string in Lightweight Directory Access Protocol
478 /// (Ldap) format. The Filter property is initialized to this value.
480 public DirectorySearcher( DirectoryEntry searchRoot
,
483 _SearchRoot
= searchRoot
;
488 /// Initializes a new instance of the DirectorySearcher class with
489 /// SearchRoot and SearchScope set to the default values. Filter and
490 /// PropertiesToLoad are set to the specified values.
492 /// <param name="filter">
493 /// The search filter string in Lightweight Directory Access Protocol
494 /// (Ldap) format. The Filter property is initialized to this value.
496 /// <param name="propertiesToLoad">
497 /// The set of properties to retrieve during the search. The
498 /// PropertiesToLoad property is initialized to this value.
500 public DirectorySearcher( string filter
,
501 string[] propertiesToLoad
)
504 PropertiesToLoad
.AddRange(propertiesToLoad
);
508 /// Initializes a new instance of the DirectorySearcher class with
509 /// SearchScope set to its default value. SearchRoot, Filter, and
510 /// PropertiesToLoad are set to the specified values.
512 /// <param name="searchRoot">
513 /// The node in the Active Directory hierarchy where the search starts.
514 /// The SearchRoot property is initialized to this value
516 /// <param name="filter">
517 /// The search filter string in Lightweight Directory Access Protocol
518 /// (Ldap) format. The Filter property is initialized to this value.
520 /// <param name="propertiesToLoad">
521 /// The set of properties retrieved during the search. The
522 /// PropertiesToLoad property is initialized to this value.
524 public DirectorySearcher( DirectoryEntry searchRoot
,
526 string[] propertiesToLoad
)
528 _SearchRoot
= searchRoot
;
530 PropertiesToLoad
.AddRange(propertiesToLoad
);
534 /// Initializes a new instance of the DirectorySearcher class with
535 /// SearchRoot set to its default value. Filter, PropertiesToLoad,
536 /// and SearchScope are set to the specified values
538 /// <param name="filter">
539 /// The search filter string in Lightweight Directory Access Protocol
540 /// (Ldap) format. The Filter property is initialized to this value.
542 /// <param name="propertiesToLoad">
543 /// The set of properties to retrieve during the search. The
544 /// PropertiesToLoad property is initialized to this value.
546 /// <param name="scope">
547 /// The scope of the search that is observed by the server. The
548 /// SearchScope property is initialized to this value.
550 public DirectorySearcher( string filter
,
551 string[] propertiesToLoad
,
554 _SearchScope
= scope
;
556 PropertiesToLoad
.AddRange(propertiesToLoad
);
560 /// Initializes a new instance of the DirectorySearcher class with the
561 /// SearchRoot, Filter, PropertiesToLoad, and SearchScope properties
562 /// set to the specified values
564 /// <param name="searchRoot">
565 /// The node in the Active Directory hierarchy where the search starts.
566 /// The SearchRoot property is initialized to this value.
568 /// <param name="filter">
569 /// The search filter string in Lightweight Directory Access Protocol
570 /// (Ldap) format. The Filter property is initialized to this value.
572 /// <param name="propertiesToLoad">
573 /// The set of properties to retrieve during the search. The
574 /// PropertiesToLoad property is initialized to this value.
576 /// <param name="scope">
577 /// The scope of the search that is observed by the server. The
578 /// SearchScope property is initialized to this value.
580 public DirectorySearcher( DirectoryEntry searchRoot
,
582 string[] propertiesToLoad
,
585 _SearchRoot
= searchRoot
;
586 _SearchScope
= scope
;
588 PropertiesToLoad
.AddRange(propertiesToLoad
);
593 /// Executes the Search and returns only the first entry found
596 /// A SearchResult that is the first entry found during the Search
598 public SearchResult
FindOne()
604 /// Executes the Search and returns a collection of the entries that are found
607 /// A SearchResultCollection collection of entries from the director
609 public SearchResultCollection
FindAll()
614 private void DoSearch()
617 String
[] attrs
= new String
[PropertiesToLoad
.Count
];
618 PropertiesToLoad
.CopyTo(attrs
,0);
619 LdapSearchResults lsc
=_conn
.Search( SearchRoot
.Fdn
,
620 LdapConnection
.SCOPE_SUB
,
628 LdapEntry nextEntry
= null;
631 nextEntry
= lsc
.next();
633 catch(LdapException e
)
635 Console
.WriteLine("Error: " + e
.LdapErrorMessage
);
636 // Exception is thrown, go for next entry
639 DirectoryEntry de
= new DirectoryEntry(_conn
);
640 PropertyCollection pcoll
= new PropertyCollection();
641 // de.SetProperties();
642 de
.Path
="LDAP://" + _Host
+ ":" + _Port
+ "/" + nextEntry
.DN
;
643 LdapAttributeSet attributeSet
= nextEntry
.getAttributeSet();
644 System
.Collections
.IEnumerator ienum
=attributeSet
.GetEnumerator();
647 while(ienum
.MoveNext())
649 LdapAttribute attribute
=(LdapAttribute
)ienum
.Current
;
650 string attributeName
= attribute
.Name
;
651 pcoll
[attributeName
].AddRange(attribute
.StringValueArray
);
652 // de.Properties[attributeName].AddRange(attribute.StringValueArray);
653 // de.Properties[attributeName].Mbit=false;
656 // _SrchColl.Add(new SearchResult(de,PropertiesToLoad));
657 _SrchColl
.Add(new SearchResult(de
,pcoll
));
663 protected override void Dispose(bool disposing
)
665 throw new NotImplementedException();