[Cleanup] Removed TARGET_JVM
[mono.git] / mcs / class / Novell.Directory.Ldap / Novell.Directory.Ldap / LdapConnection.cs
1 /******************************************************************************
2 * The MIT License
3 * Copyright (c) 2003 Novell Inc.  www.novell.com
4
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:
11
12 * The above copyright notice and this permission notice shall be included in 
13 * all copies or substantial portions of the Software.
14
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
21 * SOFTWARE.
22 *******************************************************************************/
23 //
24 // Novell.Directory.Ldap.LdapConnection.cs
25 //
26 // Author:
27 //   Sunil Kumar (Sunilk@novell.com)
28 //
29 // (C) 2003 Novell, Inc (http://www.novell.com)
30 //
31
32 using System;
33 using Novell.Directory.Ldap;
34 using Novell.Directory.Ldap.Asn1;
35 using Novell.Directory.Ldap.Rfc2251;
36 using Novell.Directory.Ldap.Utilclass;
37 using Mono.Security.Protocol.Tls;
38 using System.Security.Cryptography.X509Certificates;
39
40 namespace Novell.Directory.Ldap
41 {
42         
43         /// <summary> The central class that encapsulates the connection
44         /// to a directory server through the Ldap protocol.
45         /// LdapConnection objects are used to perform common Ldap
46         /// operations such as search, modify and add.
47         /// 
48         /// In addition, LdapConnection objects allow you to bind to an
49         /// Ldap server, set connection and search constraints, and perform
50         /// several other tasks.
51         /// 
52         /// An LdapConnection object is not connected on
53         /// construction and can only be connected to one server at one
54         /// port. Multiple threads may share this single connection, typically
55         /// by cloning the connection object, one for each thread. An
56         /// application may have more than one LdapConnection object, connected
57         /// to the same or different directory servers.
58         /// 
59         /// 
60         /// </summary>
61         public class LdapConnection : System.ICloneable
62         {
63                 private void  InitBlock()
64                 {
65                         defSearchCons = new LdapSearchConstraints();
66                         responseCtlSemaphore = new System.Object();
67                 }
68                 /// <summary> Returns the protocol version uses to authenticate.
69                 /// 
70                 ///  0 is returned if no authentication has been performed.
71                 /// 
72                 /// </summary>
73                 /// <returns> The protol version used for authentication or 0
74                 /// not authenticated.
75                 /// 
76                 /// </returns>
77                 virtual public int ProtocolVersion
78                 {
79                         get
80                         {
81                                 BindProperties prop = conn.BindProperties;
82                                 if (prop == null)
83                                 {
84                                         return Ldap_V3;
85                                 }
86                                 return prop.ProtocolVersion;
87                         }
88                         
89                 }
90                 /// <summary> Returns the distinguished name (DN) used for as the bind name during
91                 /// the last successful bind operation.  <code>null</code> is returned
92                 /// if no authentication has been performed or if the bind resulted in
93                 /// an aonymous connection.
94                 /// 
95                 /// </summary>
96                 /// <returns> The distinguished name if authenticated; otherwise, null.
97                 /// 
98                 /// </returns>
99                 virtual public System.String AuthenticationDN
100                 {
101                         get
102                         {
103                                 BindProperties prop = conn.BindProperties;
104                                 if (prop == null)
105                                 {
106                                         return null;
107                                 }
108                                 if (prop.Anonymous)
109                                 {
110                                         return null;
111                                 }
112                                 return prop.AuthenticationDN;
113                         }
114                         
115                 }
116                 /// <summary> Returns the method used to authenticate the connection. The return
117                 /// value is one of the following:
118                 /// 
119                 /// <ul>
120                 /// <li>"none" indicates the connection is not authenticated.</li>
121                 /// 
122                 /// 
123                 /// <li>"simple" indicates simple authentication was used or that a null
124                 /// or empty authentication DN was specified.</li>
125                 /// 
126                 /// <li>"sasl" indicates that a SASL mechanism was used to authenticate</li>
127                 /// </ul>
128                 /// 
129                 /// </summary>
130                 /// <returns> The method used to authenticate the connection.
131                 /// </returns>
132                 virtual public System.String AuthenticationMethod
133                 {
134                         get
135                         {
136                                 BindProperties prop = conn.BindProperties;
137                                 if (prop == null)
138                                 {
139                                         return "simple";
140                                 }
141                                 return conn.BindProperties.AuthenticationMethod;
142                         }
143                         
144                 }
145                 /// <summary> Returns the properties if any specified on binding with a
146                 /// SASL mechanism.
147                 /// 
148                 ///  Null is returned if no authentication has been performed
149                 /// or no authentication Map is present.
150                 /// 
151                 /// </summary>
152                 /// <returns> The bind properties Map Object used for SASL bind or null if
153                 /// the connection is not present or not authenticated.
154                 /// 
155                 /// </returns>
156                 virtual public System.Collections.IDictionary SaslBindProperties
157                 {
158                         get
159                         {
160                                 BindProperties prop = conn.BindProperties;
161                                 if (prop == null)
162                                 {
163                                         return null;
164                                 }
165                                 return conn.BindProperties.SaslBindProperties;
166                         }
167                         
168                 }
169                 /// <summary> Returns the call back handler if any specified on binding with a
170                 /// SASL mechanism.
171                 /// 
172                 ///  Null is returned if no authentication has been performed
173                 /// or no authentication call back handler is present.
174                 /// 
175                 /// </summary>
176                 /// <returns> The call back handler used for SASL bind or null if the
177                 /// object is not present or not authenticated.
178                 /// 
179                 /// </returns>
180                 virtual public System.Object SaslBindCallbackHandler
181                 {
182                         get
183                         {
184                                 BindProperties prop = conn.BindProperties;
185                                 if (prop == null)
186                                 {
187                                         return null;
188                                 }
189                                 return conn.BindProperties.SaslCallbackHandler;
190                         }
191                         
192                 }
193                 /// <summary> Returns a copy of the set of constraints associated with this
194                 /// connection. These constraints apply to all operations performed
195                 /// through this connection (unless a different set of constraints is
196                 /// specified when calling an operation method).
197                 /// 
198                 /// </summary>
199                 /// <returns> The set of default contraints that apply to this connection.
200                 /// 
201                 /// </returns>
202                 /// <summary> Sets the constraints that apply to all operations performed through
203                 /// this connection (unless a different set of constraints is specified
204                 /// when calling an operation method).  An LdapSearchConstraints object
205                 /// which is passed to this method sets all constraints, while an
206                 /// LdapConstraints object passed to this method sets only base constraints.
207                 /// 
208                 /// </summary>
209                 /// <param name="cons"> An LdapConstraints or LdapSearchConstraints Object
210                 /// containing the contstraint values to set.
211                 /// 
212                 /// </param>
213                 /// <seealso cref="Constraints()">
214                 /// </seealso>
215                 /// <seealso cref="SearchConstraints()">
216                 /// </seealso>
217                 virtual public LdapConstraints Constraints
218                 {
219                         get
220                         {
221                                 return (LdapConstraints) (this.defSearchCons).Clone();
222                         }
223                         
224                         set
225                         {
226                                 // Set all constraints, replace the object with a new one
227                                 if (value is LdapSearchConstraints)
228                                 {
229                                         defSearchCons = (LdapSearchConstraints) value.Clone();
230                                         return ;
231                                 }
232                                 
233                                 // We set the constraints this way, so a thread doesn't get an
234                                 // conconsistant view of the referrals.
235                                 LdapSearchConstraints newCons = (LdapSearchConstraints) defSearchCons.Clone();
236                                 newCons.HopLimit = value.HopLimit;
237                                 newCons.TimeLimit = value.TimeLimit;
238                                 newCons.setReferralHandler(value.getReferralHandler());
239                                 newCons.ReferralFollowing = value.ReferralFollowing;
240                                 LdapControl[] lsc = value.getControls();
241                                 if (lsc != null)
242                                 {
243                                         newCons.setControls(lsc);
244                                 }
245                                 System.Collections.Hashtable lp = newCons.Properties;
246                                 if (lp != null)
247                                 {
248                                         newCons.Properties = lp;
249                                 }
250                                 defSearchCons = newCons;
251                                 return ;
252                         }
253                         
254                 }
255                 /// <summary> Returns the host name of the Ldap server to which the object is or
256                 /// was last connected, in the format originally specified.
257                 /// 
258                 /// </summary>
259                 /// <returns> The host name of the Ldap server to which the object last
260                 /// connected or null if the object has never connected.
261                 /// 
262                 /// </returns>
263                 virtual public System.String Host
264                 {
265                         get
266                         {
267                                 return conn.Host;
268                         }
269                         
270                 }
271                 /// <summary> Returns the port number of the Ldap server to which the object is or
272                 /// was last connected.
273                 /// 
274                 /// </summary>
275                 /// <returns> The port number of the Ldap server to which the object last
276                 /// connected or -1 if the object has never connected.
277                 /// 
278                 /// </returns>
279                 virtual public int Port
280                 {
281                         get
282                         {
283                                 return conn.Port;
284                         }
285                         
286                 }
287                 /// <summary> Returns a copy of the set of search constraints associated with this
288                 /// connection. These constraints apply to search operations performed
289                 /// through this connection (unless a different set of
290                 /// constraints is specified when calling the search operation method).
291                 /// 
292                 /// </summary>
293                 /// <returns> The set of default search contraints that apply to
294                 /// this connection.
295                 /// 
296                 /// </returns>
297                 /// <seealso cref="Constraints">
298                 /// </seealso>
299                 /// <seealso cref="LdapSearchConstraints">
300                 /// </seealso>
301                 virtual public LdapSearchConstraints SearchConstraints
302                 {
303                         get
304                         {
305                                 return (LdapSearchConstraints) this.defSearchCons.Clone();
306                         }
307                         
308                 }
309
310
311                 ///<summary>  Indicates whther the perform Secure Operation or not
312                 ///</summary>
313                 ///
314                 ///<returns> 
315                 /// True if SSL is on
316                 /// False if its not on 
317                 ///</returns>
318                 public bool SecureSocketLayer
319                 {
320                         get
321                         {
322                                 return conn.Ssl;
323                         }
324                         set
325                         {
326                                 conn.Ssl=value;
327                         }
328                 }
329
330
331
332
333                 /// <summary> Indicates whether the object has authenticated to the connected Ldap
334                 /// server.
335                 /// 
336                 /// </summary>
337                 /// <returns> True if the object has authenticated; false if it has not
338                 /// authenticated.
339                 /// 
340                 /// </returns>
341                 virtual public bool Bound
342                 {
343                         get
344                         {
345                                 return conn.Bound;
346                         }
347                         
348                 }
349                 /// <summary> Indicates whether the connection represented by this object is open
350                 /// at this time.
351                 /// 
352                 /// </summary>
353                 /// <returns>  True if connection is open; false if the connection is closed.
354                 /// </returns>
355                 virtual public bool Connected
356                 {
357                         get
358                         {
359                                 return conn.Connected;
360                         }
361                         
362                 }
363
364                 /// <summary> Indicatates if the connection is protected by TLS.
365                 ///
366                 /// </summary>
367                 /// <returns> If startTLS has completed this method returns true.
368                 /// If stopTLS has completed or start tls failed, this method returns false.
369                 /// </returns>
370                 /// <returns>  True if the connection is protected by TLS.
371                 ///
372                 /// </returns>
373                 virtual public bool TLS
374                 {
375                         get
376                         {
377                                 return conn.TLS;
378                         }
379             
380                 }
381
382
383                 /// <summary>  Returns the Server Controls associated with the most recent response
384                 /// to a synchronous request on this connection object, or null
385                 /// if the latest response contained no Server Controls. The method
386                 /// always returns null for asynchronous requests. For asynchronous
387                 /// requests, the response controls are available in LdapMessage.
388                 /// 
389                 /// </summary>
390                 /// <returns> The server controls associated with the most recent response
391                 /// to a synchronous request or null if the response contains no server
392                 /// controls.
393                 /// 
394                 /// </returns>
395                 /// <seealso cref="LdapMessage.Controls">
396                 /// </seealso>
397                 virtual public LdapControl[] ResponseControls
398                 {
399                         get
400                         {
401                                 if (responseCtls == null)
402                                 {
403                                         return null;
404                                 }
405                                 
406                                 
407                                 // We have to clone the control just in case
408                                 // we have two client threads that end up retreiving the
409                                 // same control.
410                                 LdapControl[] clonedControl = new LdapControl[responseCtls.Length];
411                                 
412                                 // Also note we synchronize access to the local response
413                                 // control object just in case another message containing controls
414                                 // comes in from the server while we are busy duplicating
415                                 // this one.
416                                 lock (responseCtlSemaphore)
417                                 {
418                                         for (int i = 0; i < responseCtls.Length; i++)
419                                         {
420                                                 clonedControl[i] = (LdapControl) (responseCtls[i]).Clone();
421                                         }
422                                 }
423                                 
424                                 // Return the cloned copy.  Note we have still left the
425                                 // control in the local responseCtls variable just in case
426                                 // somebody requests it again.
427                                 return clonedControl;
428                         }
429                         
430                 }
431                 /// <summary> Return the Connection object associated with this LdapConnection
432                 /// 
433                 /// </summary>
434                 /// <returns> the Connection object
435                 /// </returns>
436                 virtual internal Connection Connection
437                 {
438                         /* package */
439                         
440                         get
441                         {
442                                 return conn;
443                         }
444                         
445                 }
446                 /// <summary> Return the Connection object name associated with this LdapConnection
447                 /// 
448                 /// </summary>
449                 /// <returns> the Connection object name
450                 /// </returns>
451                 virtual internal System.String ConnectionName
452                 {
453                         /* package */
454                         
455                         get
456                         {
457                                 return name;
458                         }
459                         
460                 }
461                 private LdapSearchConstraints defSearchCons;
462                 private LdapControl[] responseCtls = null;
463                 
464                 // Synchronization Object used to synchronize access to responseCtls
465                 private System.Object responseCtlSemaphore;
466                 
467                 private Connection conn = null;
468                 
469                 private static System.Object nameLock; // protect agentNum
470                 private static int lConnNum = 0; // Debug, LdapConnection number
471                 private System.String name; // String name for debug
472                 
473                 /// <summary> Used with search to specify that the scope of entrys to search is to
474                 /// search only the base obect.
475                 /// 
476                 /// SCOPE_BASE = 0
477                 /// </summary>
478                 public const int SCOPE_BASE = 0;
479                 
480                 /// <summary> Used with search to specify that the scope of entrys to search is to
481                 /// search only the immediate subordinates of the base obect.
482                 /// 
483                 /// SCOPE_ONE = 1
484                 /// </summary>
485                 public const int SCOPE_ONE = 1;
486                 
487                 /// <summary> Used with search to specify that the scope of entrys to search is to
488                 /// search the base object and all entries within its subtree.
489                 /// 
490                 /// SCOPE_ONE = 2
491                 /// </summary>
492                 public const int SCOPE_SUB = 2;
493                 
494                 /// <summary> Used with search instead of an attribute list to indicate that no
495                 /// attributes are to be returned.
496                 /// 
497                 /// NO_ATTRS = "1.1"
498                 /// </summary>
499                 public const System.String NO_ATTRS = "1.1";
500                 
501                 /// <summary> Used with search instead of an attribute list to indicate that all
502                 /// attributes are to be returned.
503                 /// 
504                 /// ALL_USER_ATTRS = "*"
505                 /// </summary>
506                 public const System.String ALL_USER_ATTRS = "*";
507                 
508                 /// <summary> Specifies the Ldapv3 protocol version when performing a bind operation.
509                 /// 
510                 /// Specifies Ldap version V3 of the protocol, and is specified
511                 /// when performing bind operations.
512                 /// You can use this identifier in the version parameter
513                 /// of the bind method to specify an Ldapv3 bind.
514                 /// Ldap_V3 is the default protocol version
515                 /// 
516                 /// Ldap_V3 = 3
517                 /// 
518                 /// </summary>
519                 public const int Ldap_V3 = 3;
520                 
521                 /// <summary> The default port number for Ldap servers.
522                 /// 
523                 /// You can use this identifier to specify the port when establishing
524                 /// a clear text connection to a server.  This the default port.
525                 /// 
526                 /// DEFAULT_PORT = 389
527                 /// 
528                 /// </summary>
529                 public const int DEFAULT_PORT = 389;
530                 
531                 
532                 /// <summary> The default SSL port number for Ldap servers.
533                 /// 
534                 /// DEFAULT_SSL_PORT = 636
535                 /// 
536                 /// You can use this identifier to specify the port when establishing
537                 /// a an SSL connection to a server..
538                 /// </summary>
539                 public const int DEFAULT_SSL_PORT = 636;
540                 
541                 /// <summary> A string that can be passed in to the getProperty method.
542                 /// 
543                 /// Ldap_PROPERTY_SDK = "version.sdk"
544                 /// 
545                 /// You can use this string to request the version of the SDK.
546                 /// </summary>
547                 public const System.String Ldap_PROPERTY_SDK = "version.sdk";
548                 
549                 /// <summary> A string that can be passed in to the getProperty method.
550                 /// 
551                 /// Ldap_PROPERTY_PROTOCOL = "version.protocol"
552                 /// 
553                 /// You can use this string to request the version of the
554                 /// Ldap protocol.
555                 /// </summary>
556                 public const System.String Ldap_PROPERTY_PROTOCOL = "version.protocol";
557                 
558                 /// <summary> A string that can be passed in to the getProperty method.
559                 /// 
560                 /// Ldap_PROPERTY_SECURITY = "version.security"
561                 /// 
562                 /// You can use this string to request the type of security
563                 /// being used.
564                 /// </summary>
565                 public const System.String Ldap_PROPERTY_SECURITY = "version.security";
566                 
567                 /// <summary> A string that corresponds to the server shutdown notification OID.
568                 /// This notification may be used by the server to advise the client that
569                 /// the server is about to close the connection due to an error
570                 /// condition.
571                 /// 
572                 /// SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036"
573                 /// </summary>
574                 public const System.String SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036";
575                 
576                 /// <summary> The OID string that identifies a StartTLS request and response.</summary>
577                 private const System.String START_TLS_OID = "1.3.6.1.4.1.1466.20037";
578                 
579                 public event CertificateValidationCallback UserDefinedServerCertValidationDelegate
580                 {
581                         add
582                         {
583                                 this.conn.OnCertificateValidation += value;
584                         }
585
586                         remove
587                         {
588                                 this.conn.OnCertificateValidation -= value;
589                         }
590                 }
591                 /*
592                 * Constructors
593                 */
594                 
595                 
596                 /// <summary> Constructs a new LdapConnection object, which will use the supplied
597                 /// class factory to construct a socket connection during
598                 /// LdapConnection.connect method.
599                 /// 
600                 /// </summary>
601                 /// <param name="factory">    An object capable of producing a Socket.
602                 /// 
603                 /// </param>
604                 public LdapConnection()
605                 {
606                         InitBlock();
607                         // Get a unique connection name for debug
608                         conn = new Connection();
609                         return ;
610                 }
611                 
612 /*              public LdapConnection(X509Certificate cert)
613                 {
614                         InitBlock();
615                         // Get a unique connection name for debug
616                         conn = new Connection();
617                         conn.Cert = cert;
618                         return ;
619                 }
620 */
621                 /*
622                 * The following are methods that affect the operation of
623                 * LdapConnection, but are not Ldap requests.
624                 */
625                 
626                 /// <summary> Returns a copy of the object with a private context, but sharing the
627                 /// network connection if there is one.
628                 /// 
629                 /// The network connection remains open until all clones have
630                 /// disconnected or gone out of scope. Any connection opened after
631                 /// cloning is private to the object making the connection.
632                 /// 
633                 /// The clone can issue requests and freely modify options and search
634                 /// constraints, and , without affecting the source object or other clones.
635                 /// If the clone disconnects or reconnects, it is completely dissociated
636                 /// from the source object and other clones. Reauthenticating in a clone,
637                 /// however, is a global operation which will affect the source object
638                 /// and all associated clones, because it applies to the single shared
639                 /// physical connection. Any request by an associated object after one
640                 /// has reauthenticated will carry the new identity.
641                 /// 
642                 /// </summary>
643                 /// <returns> A of the object.
644                 /// </returns>
645                 public System.Object Clone()
646                 {
647                         LdapConnection newClone;
648                         System.Object newObj;
649                         try
650                         {
651                                 newObj = base.MemberwiseClone();
652                                 newClone = (LdapConnection) newObj;
653                         }
654                         catch (System.Exception ce)
655                         {
656                                 throw new System.SystemException("Internal error, cannot create clone");
657                         }
658                         newClone.conn = conn; // same underlying connection
659                         
660                         //now just duplicate the defSearchCons and responseCtls
661                         if (defSearchCons != null)
662                         {
663                                 newClone.defSearchCons = (LdapSearchConstraints) defSearchCons.Clone();
664                         }
665                         else
666                         {
667                                 newClone.defSearchCons = null;
668                         }
669                         if (responseCtls != null)
670                         {
671                                 newClone.responseCtls = new LdapControl[responseCtls.Length];
672                                 for (int i = 0; i < responseCtls.Length; i++)
673                                 {
674                                         newClone.responseCtls[i] = (LdapControl) responseCtls[i].Clone();
675                                 }
676                         }
677                         else
678                         {
679                                 newClone.responseCtls = null;
680                         }
681                         conn.incrCloneCount(); // Increment the count of clones
682                         return newObj;
683                 }
684                 
685                 /// <summary> Closes the connection, if open, and releases any other resources held
686                 /// by the object.
687                 /// 
688                 /// </summary>
689                 /// <exception> LdapException A general exception which includes an error
690                 /// message and an Ldap error code.
691                 /// 
692                 /// </exception>
693                 /// <seealso cref="Disconnect">
694                 /// </seealso>
695                 ~LdapConnection()
696                 {
697                         // Disconnect did not come from user API call
698                         Disconnect(defSearchCons, false);
699                         return ;
700                 }
701                 
702                 /// <summary> Returns a property of a connection object.
703                 /// 
704                 /// </summary>
705                 /// <param name="name">  Name of the property to be returned.
706                 /// 
707                 /// The following read-only properties are available
708                 /// for any given connection:
709                 /// <ul>
710                 /// <li>Ldap_PROPERTY_SDK returns the version of this SDK,
711                 /// as a Float data type.</li>
712                 /// 
713                 /// <li>Ldap_PROPERTY_PROTOCOL returns the highest supported version of
714                 /// the Ldap protocol, as a Float data type.</li>
715                 /// 
716                 /// <li>Ldap_PROPERTY_SECURITY returns a comma-separated list of the
717                 /// types of authentication supported, as a
718                 /// string.</li>
719                 /// </ul>
720                 /// 
721                 /// A deep copy of the property is provided where applicable; a
722                 /// client does not need to clone the object received.
723                 /// 
724                 /// </param>
725                 /// <returns> The object associated with the requested property,
726                 /// or null if the property is not defined.
727                 /// 
728                 /// </returns>
729                 /// <seealso cref="LdapConstraints.getProperty">
730                 /// </seealso>
731                 /// <seealso cref="Object">
732                 /// </seealso>
733                 public virtual System.Object getProperty(System.String name)
734                 {
735                         if (name.ToUpper().Equals(Ldap_PROPERTY_SDK.ToUpper()))
736                                 return Connection.sdk;
737                         else if (name.ToUpper().Equals(Ldap_PROPERTY_PROTOCOL.ToUpper()))
738                                 return Connection.protocol;
739                         else if (name.ToUpper().Equals(Ldap_PROPERTY_SECURITY.ToUpper()))
740                                 return Connection.security;
741                         else
742                         {
743                                 return null;
744                         }
745                 }
746                 
747                 /// <summary> Registers an object to be notified on arrival of an unsolicited
748                 /// message from a server.
749                 /// 
750                 /// An unsolicited message has the ID 0. A new thread is created and
751                 /// the method "messageReceived" in each registered object is called in
752                 /// turn.
753                 /// 
754                 /// </summary>
755                 /// <param name="listener"> An object to be notified on arrival of an
756                 /// unsolicited message from a server.  This object must
757                 /// implement the LdapUnsolicitedNotificationListener interface.
758                 /// 
759                 /// </param>
760                 public virtual void  AddUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
761                 {
762                         if (listener != null)
763                                 conn.AddUnsolicitedNotificationListener(listener);
764                 }
765                 
766                 
767                 
768                 /// <summary> Deregisters an object so that it will no longer be notified on
769                 /// arrival of an unsolicited message from a server. If the object is
770                 /// null or was not previously registered for unsolicited notifications,
771                 /// the method does nothing.
772                 /// 
773                 /// 
774                 /// </summary>
775                 /// <param name="listener"> An object to no longer be notified on arrival of
776                 /// an unsolicited message from a server.
777                 /// 
778                 /// </param>
779                 public virtual void  RemoveUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
780                 {
781                         
782                         if (listener != null)
783                                 conn.RemoveUnsolicitedNotificationListener(listener);
784                 }
785                 
786                 /// <summary> Starts Transport Layer Security (TLS) protocol on this connection
787                 /// to enable session privacy.
788                 /// 
789                 /// This affects the LdapConnection object and all cloned objects. A
790                 /// socket factory that implements LdapTLSSocketFactory must be set on the
791                 /// connection.
792                 /// 
793                 /// </summary>
794                 /// <exception> LdapException Thrown if TLS cannot be started.  If a
795                 /// SocketFactory has been specified that does not implement
796                 /// LdapTLSSocketFactory an LdapException is thrown.
797                 /// 
798                 /// </exception>
799
800         public virtual void  startTLS()
801         {
802  
803             LdapMessage startTLS = MakeExtendedOperation(new LdapExtendedOperation(LdapConnection.START_TLS_OID, null), null);
804                                                                                 
805             int tlsID = startTLS.MessageID;
806                                                                                 
807             conn.acquireWriteSemaphore(tlsID);
808             try
809             {
810                 if (!conn.areMessagesComplete())
811                 {
812                     throw new LdapLocalException(ExceptionMessages.OUTSTANDING_OPERATIONS, LdapException.OPERATIONS_ERROR);
813                 }
814                 // Stop reader when response to startTLS request received
815                 conn.stopReaderOnReply(tlsID);
816                                                                                 
817                 // send tls message
818                 LdapResponseQueue queue = SendRequestToServer(startTLS, defSearchCons.TimeLimit, null, null);
819                                                                                 
820                 LdapExtendedResponse response = (LdapExtendedResponse) queue.getResponse();
821                 response.chkResultCode();
822                                                                                 
823                 conn.startTLS();
824             }
825             finally
826             {
827                 //Free this semaphore no matter what exceptions get thrown
828                 conn.startReader();
829                 conn.freeWriteSemaphore(tlsID);
830            }
831             return ;
832         }
833                                                                                 
834         /// <summary> Stops Transport Layer Security(TLS) on the LDAPConnection and reverts
835         /// back to an anonymous state.
836         ///
837         /// @throws LDAPException This can occur for the following reasons: 
838         /// <UL>        
839         /// <LI>StartTLS has not been called before stopTLS</LI>
840         /// <LI>There exists outstanding messages that have not received all
841         /// responses</LI>
842         /// <LI>The sever was not able to support the operation</LI></UL>
843         ///
844         /// <p>Note: The Sun and IBM implementions of JSSE do not currently allow
845         /// stopping TLS on an open Socket.  In order to produce the same results
846         /// this method currently disconnects the socket and reconnects, giving
847         /// the application an anonymous connection to the server, as required
848         /// by StopTLS</p>
849         /// </summary>
850         public virtual void  stopTLS()
851         {
852                                                                                 
853             if (!TLS)
854             {
855                 throw new LdapLocalException(ExceptionMessages.NO_STARTTLS, LdapException.OPERATIONS_ERROR);
856             }
857                                                                                 
858             int semaphoreID = conn.acquireWriteSemaphore();
859             try
860             {
861                 if (!conn.areMessagesComplete())
862                {
863                     throw new LdapLocalException(ExceptionMessages.OUTSTANDING_OPERATIONS, LdapException.OPERATIONS_ERROR);
864                 }
865                 //stopTLS stops and starts the reader thread for us.
866                 conn.stopTLS();
867             }
868             finally
869             {
870                 conn.freeWriteSemaphore(semaphoreID);
871                                                                                 
872                 /* Now that the TLS socket is closed, reset everything.  This next
873                 line is temporary until JSSE is fixed to properly handle TLS stop */
874                 this.Connect(this.Host, this.Port);
875             }
876             return ;
877         }
878                                                                                 
879
880                 //*************************************************************************
881                 // Below are all of the Ldap protocol operation methods
882                 //*************************************************************************
883                 
884                 //*************************************************************************
885                 // abandon methods
886                 //*************************************************************************
887                 
888                 /// <summary> 
889                 /// 
890                 /// Notifies the server not to send additional results associated with
891                 /// this LdapSearchResults object, and discards any results already
892                 /// received.
893                 /// 
894                 /// </summary>
895                 /// <param name="results">  An object returned from a search.
896                 /// 
897                 /// </param>
898                 /// <exception> LdapException A general exception which includes an error
899                 /// message and an Ldap error code.
900                 /// </exception>
901                 public virtual void  Abandon(LdapSearchResults results)
902                 {
903                         Abandon(results, defSearchCons);
904                         return ;
905                 }
906                 
907                 /// <summary> 
908                 /// 
909                 /// Notifies the server not to send additional results associated with
910                 /// this LdapSearchResults object, and discards any results already
911                 /// received.
912                 /// 
913                 /// </summary>
914                 /// <param name="results">  An object returned from a search.
915                 /// 
916                 /// </param>
917                 /// <param name="cons">    The contraints specific to the operation.
918                 /// 
919                 /// </param>
920                 /// <exception> LdapException A general exception which includes an error
921                 /// message and an Ldap error code.
922                 /// </exception>
923                 public virtual void  Abandon(LdapSearchResults results, LdapConstraints cons)
924                 {
925                         results.Abandon();
926                         return ;
927                 }
928                 
929                 /// <summary> 
930                 /// Abandons an asynchronous operation.
931                 /// 
932                 /// </summary>
933                 /// <param name="id">     The ID of the asynchronous operation to abandon. The ID
934                 /// can be obtained from the response queue for the
935                 /// operation.
936                 /// 
937                 /// </param>
938                 /// <exception> LdapException A general exception which includes an error
939                 /// message and an Ldap error code.
940                 /// </exception>
941                 public virtual void  Abandon(int id)
942                 {
943                         Abandon(id, defSearchCons);
944                         return ;
945                 }
946                 
947                 /// <summary>  Abandons an asynchronous operation, using the specified
948                 /// constraints.
949                 /// 
950                 /// </summary>
951                 /// <param name="id">The ID of the asynchronous operation to abandon.
952                 /// The ID can be obtained from the search
953                 /// queue for the operation.
954                 /// 
955                 /// </param>
956                 /// <param name="cons">The contraints specific to the operation.
957                 /// 
958                 /// </param>
959                 /// <exception> LdapException A general exception which includes an error
960                 /// message and an Ldap error code.
961                 /// </exception>
962                 public virtual void  Abandon(int id, LdapConstraints cons)
963                 {
964                         // We need to inform the Message Agent which owns this messageID to
965                         // remove it from the queue.
966                         try
967                         {
968                                 MessageAgent agent = conn.getMessageAgent(id);
969                                 agent.Abandon(id, cons);
970                                 return ;
971                         }
972                         catch (System.FieldAccessException ex)
973                         {
974                                 return ; // Ignore error
975                         }
976                 }
977                 
978                 /// <summary> Abandons all outstanding operations managed by the queue.
979                 /// 
980                 /// All operations in progress, which are managed by the specified queue,
981                 /// are abandoned.
982                 /// 
983                 /// </summary>
984                 /// <param name="queue">    The queue returned from an asynchronous request.
985                 /// All outstanding operations managed by the queue
986                 /// are abandoned, and the queue is emptied.
987                 /// 
988                 /// </param>
989                 /// <exception> LdapException A general exception which includes an error
990                 /// message and an Ldap error code.
991                 /// </exception>
992                 public virtual void  Abandon(LdapMessageQueue queue)
993                 {
994                         Abandon(queue, defSearchCons);
995                         return ;
996                 }
997                 
998                 /// <summary> Abandons all outstanding operations managed by the queue.
999                 /// 
1000                 /// All operations in progress, which are managed by the specified
1001                 /// queue, are abandoned.
1002                 /// 
1003                 /// </summary>
1004                 /// <param name="queue">    The queue returned from an asynchronous request.
1005                 /// All outstanding operations managed by the queue
1006                 /// are abandoned, and the queue is emptied.
1007                 /// 
1008                 /// </param>
1009                 /// <param name="cons">    The contraints specific to the operation.
1010                 /// 
1011                 /// </param>
1012                 /// <exception> LdapException A general exception which includes an error
1013                 /// message and an Ldap error code.
1014                 /// </exception>
1015                 public virtual void  Abandon(LdapMessageQueue queue, LdapConstraints cons)
1016                 {
1017                         if (queue != null)
1018                         {
1019                                 MessageAgent agent;
1020                                 if (queue is LdapSearchQueue)
1021                                 {
1022                                         agent = queue.MessageAgent;
1023                                 }
1024                                 else
1025                                 {
1026                                         agent = queue.MessageAgent;
1027                                 }
1028                                 int[] msgIds = agent.MessageIDs;
1029                                 for (int i = 0; i < msgIds.Length; i++)
1030                                 {
1031                                         agent.Abandon(msgIds[i], cons);
1032                                 }
1033                         }
1034                         return ;
1035                 }
1036                 
1037                 //*************************************************************************
1038                 // add methods
1039                 //*************************************************************************
1040                 
1041                 /// <summary> Synchronously adds an entry to the directory.
1042                 /// 
1043                 /// </summary>
1044                 /// <param name="entry">   LdapEntry object specifying the distinguished
1045                 /// name and attributes of the new entry.
1046                 /// 
1047                 /// </param>
1048                 /// <exception> LdapException A general exception which includes an error
1049                 /// message and an Ldap error code.
1050                 /// </exception>
1051                 public virtual void  Add(LdapEntry entry)
1052                 {
1053                         Add(entry, defSearchCons);
1054                         return ;
1055                 }
1056                 
1057                 /// <summary> 
1058                 /// Synchronously adds an entry to the directory, using the specified
1059                 /// constraints.
1060                 /// 
1061                 /// </summary>
1062                 /// <param name="entry">  LdapEntry object specifying the distinguished
1063                 /// name and attributes of the new entry.
1064                 /// 
1065                 /// </param>
1066                 /// <param name="cons">   Constraints specific to the operation.
1067                 /// 
1068                 /// </param>
1069                 /// <exception> LdapException A general exception which includes an error
1070                 /// message and an Ldap error code.
1071                 /// </exception>
1072                 
1073                 public virtual void  Add(LdapEntry entry, LdapConstraints cons)
1074                 {
1075                         LdapResponseQueue queue = Add(entry, null, cons);
1076                         
1077                         // Get a handle to the add response
1078                         LdapResponse addResponse = (LdapResponse) (queue.getResponse());
1079                         
1080                         // Set local copy of responseControls synchronously if there were any
1081                         lock (responseCtlSemaphore)
1082                         {
1083                                 responseCtls = addResponse.Controls;
1084                         }
1085                         chkResultCode(queue, cons, addResponse);
1086                         return ;
1087                 }
1088                 
1089                 /// <summary> Asynchronously adds an entry to the directory.
1090                 /// 
1091                 /// </summary>
1092                 /// <param name="entry">  LdapEntry object specifying the distinguished
1093                 /// name and attributes of the new entry.
1094                 /// 
1095                 /// </param>
1096                 /// <param name="queue">  Handler for messages returned from a server in
1097                 /// response to this request. If it is null, a
1098                 /// queue object is created internally.
1099                 /// 
1100                 /// </param>
1101                 /// <exception> LdapException A general exception which includes an error
1102                 /// message and an Ldap error code.
1103                 /// </exception>
1104                 public virtual LdapResponseQueue Add(LdapEntry entry, LdapResponseQueue queue)
1105                 {
1106                         return Add(entry, queue, defSearchCons);
1107                 }
1108                 
1109                 /// <summary> Asynchronously adds an entry to the directory, using the specified
1110                 /// constraints.
1111                 /// 
1112                 /// </summary>
1113                 /// <param name="entry">  LdapEntry object specifying the distinguished
1114                 /// name and attributes of the new entry.
1115                 /// 
1116                 /// </param>
1117                 /// <param name="queue"> Handler for messages returned from a server in
1118                 /// response to this request. If it is null, a
1119                 /// queue object is created internally.
1120                 /// 
1121                 /// </param>
1122                 /// <param name="cons">  Constraints specific to the operation.
1123                 /// 
1124                 /// </param>
1125                 /// <exception> LdapException A general exception which includes an error
1126                 /// message and an Ldap error code.
1127                 /// </exception>
1128                 public virtual LdapResponseQueue Add(LdapEntry entry, LdapResponseQueue queue, LdapConstraints cons)
1129                 {
1130                         if (cons == null)
1131                                 cons = defSearchCons;
1132                         
1133                         // error check the parameters
1134                         if (entry == null)
1135                         {
1136                                 throw new System.ArgumentException("The LdapEntry parameter" + " cannot be null");
1137                         }
1138                         if ((System.Object) entry.DN == null)
1139                         {
1140                                 throw new System.ArgumentException("The DN value must be present" + " in the LdapEntry object");
1141                         }
1142                         
1143                         LdapMessage msg = new LdapAddRequest(entry, cons.getControls());
1144                         
1145                         return SendRequestToServer(msg, cons.TimeLimit, queue, null);
1146                 }
1147                 
1148                 //*************************************************************************
1149                 // bind methods
1150                 //*************************************************************************
1151                 
1152                 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1153                 /// currently connected to) as an Ldapv3 bind, using the specified name and
1154                 /// password.
1155                 /// 
1156                 /// If the object has been disconnected from an Ldap server,
1157                 /// this method attempts to reconnect to the server. If the object
1158                 /// has already authenticated, the old authentication is discarded.
1159                 /// 
1160                 /// </summary>
1161                 /// <param name="dn">     If non-null and non-empty, specifies that the
1162                 /// connection and all operations through it should
1163                 /// be authenticated with dn as the distinguished
1164                 /// name.
1165                 /// 
1166                 /// </param>
1167                 /// <param name="passwd"> If non-null and non-empty, specifies that the
1168                 /// connection and all operations through it should
1169                 /// be authenticated with dn as the distinguished
1170                 /// name and passwd as password.
1171                 /// 
1172                 /// Note: the application should use care in the use
1173                 /// of String password objects.  These are long lived
1174                 /// objects, and may expose a security risk, especially
1175                 /// in objects that are serialized.  The LdapConnection
1176                 /// keeps no long lived instances of these objects.
1177                 /// 
1178                 /// </param>
1179                 /// <exception> LdapException A general exception which includes an error
1180                 /// message and an Ldap error code.
1181                 /// 
1182                 /// </exception>
1183                 public virtual void  Bind(System.String dn, System.String passwd)
1184                 {
1185                         Bind(dn, passwd, AuthenticationTypes.None);
1186                         return ;
1187                 }
1188                 
1189                 public virtual void  Bind(System.String dn, System.String passwd, AuthenticationTypes authenticationTypes)
1190                 {
1191                                 Bind(Ldap_V3, dn, passwd, defSearchCons);               
1192
1193                         return ;
1194                 }
1195                 
1196                 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1197                 /// currently connected to) using the specified name, password,
1198                 /// and Ldap version.
1199                 /// 
1200                 /// If the object has been disconnected from an Ldap server,
1201                 /// this method attempts to reconnect to the server. If the object
1202                 /// has already authenticated, the old authentication is discarded.
1203                 /// 
1204                 /// </summary>
1205                 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1206                 /// Ldap_V2 is not supported.
1207                 /// 
1208                 /// </param>
1209                 /// <param name="dn">     If non-null and non-empty, specifies that the
1210                 /// connection and all operations through it should
1211                 /// be authenticated with dn as the distinguished
1212                 /// name.
1213                 /// 
1214                 /// </param>
1215                 /// <param name="passwd"> If non-null and non-empty, specifies that the
1216                 /// connection and all operations through it should
1217                 /// be authenticated with dn as the distinguished
1218                 /// name and passwd as password.
1219                 /// 
1220                 /// Note: the application should use care in the use
1221                 /// of String password objects.  These are long lived
1222                 /// objects, and may expose a security risk, especially
1223                 /// in objects that are serialized.  The LdapConnection
1224                 /// keeps no long lived instances of these objects.
1225                 /// 
1226                 /// </param>
1227                 /// <exception> LdapException A general exception which includes an error
1228                 /// message and an Ldap error code.
1229                 /// 
1230                 /// </exception>
1231                 public virtual void  Bind(int version, System.String dn, System.String passwd)
1232                 {
1233                         Bind(version, dn, passwd, defSearchCons);
1234                         return ;
1235                 }
1236                 
1237                 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1238                 /// currently connected to) as an Ldapv3 bind, using the specified name,
1239                 /// password, and constraints.
1240                 /// 
1241                 /// If the object has been disconnected from an Ldap server,
1242                 /// this method attempts to reconnect to the server. If the object
1243                 /// has already authenticated, the old authentication is discarded.
1244                 /// 
1245                 /// </summary>
1246                 /// <param name="dn">     If non-null and non-empty, specifies that the
1247                 /// connection and all operations through it should
1248                 /// be authenticated with dn as the distinguished
1249                 /// name.
1250                 /// 
1251                 /// </param>
1252                 /// <param name="passwd"> If non-null and non-empty, specifies that the
1253                 /// connection and all operations through it should
1254                 /// be authenticated with dn as the distinguished
1255                 /// name and passwd as password.
1256                 /// Note: the application should use care in the use
1257                 /// of String password objects.  These are long lived
1258                 /// objects, and may expose a security risk, especially
1259                 /// in objects that are serialized.  The LdapConnection
1260                 /// keeps no long lived instances of these objects.
1261                 /// 
1262                 /// </param>
1263                 /// <param name="cons">    Constraints specific to the operation.
1264                 /// 
1265                 /// </param>
1266                 /// <exception> LdapException A general exception which includes an error
1267                 /// message and an Ldap error code.
1268                 /// 
1269                 /// </exception>
1270                 public virtual void  Bind(System.String dn, System.String passwd, LdapConstraints cons)
1271                 {
1272                         Bind(Ldap_V3, dn, passwd, cons);
1273                         return ;
1274                 }
1275                 
1276                 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1277                 /// currently connected to) using the specified name, password, Ldap version,
1278                 /// and constraints.
1279                 /// 
1280                 /// If the object has been disconnected from an Ldap server,
1281                 /// this method attempts to reconnect to the server. If the object
1282                 /// has already authenticated, the old authentication is discarded.
1283                 /// 
1284                 /// </summary>
1285                 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1286                 /// Ldap_V2 is not supported.
1287                 /// 
1288                 /// </param>
1289                 /// <param name="dn">      If non-null and non-empty, specifies that the
1290                 /// connection and all operations through it should
1291                 /// be authenticated with dn as the distinguished
1292                 /// name.
1293                 /// 
1294                 /// </param>
1295                 /// <param name="passwd"> If non-null and non-empty, specifies that the
1296                 /// connection and all operations through it should
1297                 /// be authenticated with dn as the distinguished
1298                 /// name and passwd as password.
1299                 /// 
1300                 /// Note: the application should use care in the use
1301                 /// of String password objects.  These are long lived
1302                 /// objects, and may expose a security risk, especially
1303                 /// in objects that are serialized.  The LdapConnection
1304                 /// keeps no long lived instances of these objects.
1305                 /// 
1306                 /// </param>
1307                 /// <param name="cons">   The constraints specific to the operation.
1308                 /// 
1309                 /// </param>
1310                 /// <exception> LdapException A general exception which includes an error
1311                 /// message and an Ldap error code.
1312                 /// 
1313                 /// </exception>
1314                 public virtual void  Bind(int version, System.String dn, System.String passwd, LdapConstraints cons)
1315                 {
1316                         sbyte[] pw = null;
1317                         if ((System.Object) passwd != null)
1318                         {
1319                                 try
1320                                 {
1321                                         System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8"); 
1322                                         byte[] ibytes = encoder.GetBytes(passwd);
1323                                         pw=SupportClass.ToSByteArray(ibytes);
1324
1325                                         //                                      pw = passwd.getBytes("UTF8");
1326                                         passwd = null; // Keep no reference to String object
1327                                 }
1328                                 catch (System.IO.IOException ex)
1329                                 {
1330                                         passwd = null; // Keep no reference to String object
1331                                         throw new System.SystemException(ex.ToString());
1332                                 }
1333                         }
1334                         Bind(version, dn, pw, cons);
1335                         return ;
1336                 }
1337                 
1338                 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1339                 /// currently connected to) using the specified name, password,
1340                 /// and Ldap version.
1341                 /// 
1342                 /// If the object has been disconnected from an Ldap server,
1343                 /// this method attempts to reconnect to the server. If the object
1344                 /// has already authenticated, the old authentication is discarded.
1345                 /// 
1346                 /// </summary>
1347                 /// <param name="version"> The version of the Ldap protocol to use
1348                 /// in the bind, use Ldap_V3.  Ldap_V2 is not supported.
1349                 /// 
1350                 /// </param>
1351                 /// <param name="dn">     If non-null and non-empty, specifies that the
1352                 /// connection and all operations through it should
1353                 /// be authenticated with dn as the distinguished
1354                 /// name.
1355                 /// 
1356                 /// </param>
1357                 /// <param name="passwd"> If non-null and non-empty, specifies that the
1358                 /// connection and all operations through it should
1359                 /// be authenticated with dn as the distinguished
1360                 /// name and passwd as password.
1361                 /// 
1362                 /// </param>
1363                 /// <exception> LdapException A general exception which includes an error
1364                 /// message and an Ldap error code.
1365                 /// </exception>
1366                 [CLSCompliantAttribute(false)]
1367                 public virtual void  Bind(int version, System.String dn, sbyte[] passwd)
1368                 {
1369                         Bind(version, dn, passwd, defSearchCons);
1370                         return ;
1371                 }
1372                 
1373                 /// <summary> 
1374                 /// Synchronously authenticates to the Ldap server (that the object is
1375                 /// currently connected to) using the specified name, password, Ldap version,
1376                 /// and constraints.
1377                 /// 
1378                 /// If the object has been disconnected from an Ldap server,
1379                 /// this method attempts to reconnect to the server. If the object
1380                 /// has already authenticated, the old authentication is discarded.
1381                 /// 
1382                 /// </summary>
1383                 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1384                 /// Ldap_V2 is not supported.
1385                 /// 
1386                 /// </param>
1387                 /// <param name="dn">      If non-null and non-empty, specifies that the
1388                 /// connection and all operations through it should
1389                 /// be authenticated with dn as the distinguished
1390                 /// name.
1391                 /// 
1392                 /// </param>
1393                 /// <param name="passwd"> If non-null and non-empty, specifies that the
1394                 /// connection and all operations through it should
1395                 /// be authenticated with dn as the distinguished
1396                 /// name and passwd as password.
1397                 /// 
1398                 /// </param>
1399                 /// <param name="cons">   The constraints specific to the operation.
1400                 /// 
1401                 /// </param>
1402                 /// <exception> LdapException A general exception which includes an error
1403                 /// message and an Ldap error code.
1404                 /// </exception>
1405                 [CLSCompliantAttribute(false)]
1406                 public virtual void  Bind(int version, System.String dn, sbyte[] passwd, LdapConstraints cons)
1407                 {
1408                         LdapResponseQueue queue = Bind(version, dn, passwd, null, cons, null);
1409                         LdapResponse res = (LdapResponse) queue.getResponse();
1410                         if (res != null)
1411                         {
1412                                 // Set local copy of responseControls synchronously if any
1413                                 lock (responseCtlSemaphore)
1414                                 {
1415                                         responseCtls = res.Controls;
1416                                 }
1417                                 
1418                                 chkResultCode(queue, cons, res);
1419                         }
1420                         return ;
1421                 }
1422                 
1423                 /// <summary> Asynchronously authenticates to the Ldap server (that the object is
1424                 /// currently connected to) using the specified name, password, Ldap
1425                 /// version, and queue.
1426                 /// 
1427                 /// If the object has been disconnected from an Ldap server,
1428                 /// this method attempts to reconnect to the server. If the object
1429                 /// has already authenticated, the old authentication is discarded.
1430                 /// 
1431                 /// 
1432                 /// </summary>
1433                 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1434                 /// Ldap_V2 is not supported.
1435                 /// 
1436                 /// </param>
1437                 /// <param name="dn">     If non-null and non-empty, specifies that the
1438                 /// connection and all operations through it should
1439                 /// be authenticated with dn as the distinguished
1440                 /// name.
1441                 /// 
1442                 /// </param>
1443                 /// <param name="passwd"> If non-null and non-empty, specifies that the
1444                 /// connection and all operations through it should
1445                 /// be authenticated with dn as the distinguished
1446                 /// name and passwd as password.
1447                 /// 
1448                 /// </param>
1449                 /// <param name="queue">  Handler for messages returned from a server in
1450                 /// response to this request. If it is null, a
1451                 /// queue object is created internally.
1452                 /// 
1453                 /// </param>
1454                 /// <exception> LdapException A general exception which includes an error
1455                 /// message and an Ldap error code.
1456                 /// </exception>
1457                 [CLSCompliantAttribute(false)]
1458                 public virtual LdapResponseQueue Bind(int version, System.String dn, sbyte[] passwd, LdapResponseQueue queue)
1459                 {
1460                         return Bind(version, dn, passwd, queue, defSearchCons, null);
1461                 }
1462                 
1463                 /// <summary> Asynchronously authenticates to the Ldap server (that the object is
1464                 /// currently connected to) using the specified name, password, Ldap
1465                 /// version, queue, and constraints.
1466                 /// 
1467                 /// If the object has been disconnected from an Ldap server,
1468                 /// this method attempts to reconnect to the server. If the object
1469                 /// had already authenticated, the old authentication is discarded.
1470                 /// 
1471                 /// </summary>
1472                 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1473                 /// Ldap_V2 is not supported.
1474                 /// 
1475                 /// </param>
1476                 /// <param name="dn">     If non-null and non-empty, specifies that the
1477                 /// connection and all operations through it should
1478                 /// be authenticated with dn as the distinguished
1479                 /// name.
1480                 /// 
1481                 /// </param>
1482                 /// <param name="passwd"> If non-null and non-empty, specifies that the
1483                 /// connection and all operations through it should
1484                 /// be authenticated with dn as the distinguished
1485                 /// name and passwd as password.
1486                 /// 
1487                 /// </param>
1488                 /// <param name="queue">  Handler for messages returned from a server in
1489                 /// response to this request. If it is null, a
1490                 /// queue object is created internally.
1491                 /// 
1492                 /// </param>
1493                 /// <param name="cons">     Constraints specific to the operation.
1494                 /// 
1495                 /// </param>
1496                 /// <exception> LdapException A general exception which includes an error
1497                 /// message and an Ldap error code.
1498                 /// </exception>
1499                 [CLSCompliantAttribute(false)]
1500                 public virtual LdapResponseQueue Bind(int version, System.String dn, sbyte[] passwd, LdapResponseQueue queue, LdapConstraints cons, string mech)
1501                 {
1502                         int msgId;
1503                         BindProperties bindProps;
1504                         if (cons == null)
1505                                 cons = defSearchCons;
1506                         
1507                         if ((System.Object) dn == null)
1508                         {
1509                                 dn = "";
1510                         }
1511                         else
1512                         {
1513                                 dn = dn.Trim();
1514                         }
1515                         
1516                         if (passwd == null)
1517                                 passwd = new sbyte[]{};
1518                         
1519                         bool anonymous = false;
1520                         if (passwd.Length == 0)
1521                         {
1522                                 anonymous = true; // anonymous, passwd length zero with simple bind
1523                                 dn = ""; // set to null if anonymous
1524                         }
1525
1526                         LdapMessage msg;
1527                                 msg = new LdapBindRequest(version, dn, passwd, cons.getControls());
1528                         
1529                         msgId = msg.MessageID;
1530                         bindProps = new BindProperties(version, dn, "simple", anonymous, null, null);
1531                         
1532                         // For bind requests, if not connected, attempt to reconnect
1533                         if (!conn.Connected)
1534                         {
1535                                 if ((System.Object) conn.Host != null)
1536                                 {
1537                                         conn.connect(conn.Host, conn.Port);
1538                                 }
1539                                 else
1540                                 {
1541                                         throw new LdapException(ExceptionMessages.CONNECTION_IMPOSSIBLE, LdapException.CONNECT_ERROR, null);
1542                                 }
1543                         }
1544                         
1545                         // The semaphore is released when the bind response is queued.
1546                         conn.acquireWriteSemaphore(msgId);
1547                         
1548                         return SendRequestToServer(msg, cons.TimeLimit, queue, bindProps);
1549                 }
1550
1551                 
1552                 //*************************************************************************
1553                 // compare methods
1554                 //*************************************************************************
1555                 
1556                 /// <summary> 
1557                 /// Synchronously checks to see if an entry contains an attribute
1558                 /// with a specified value.
1559                 /// 
1560                 /// </summary>
1561                 /// <param name="dn">     The distinguished name of the entry to use in the
1562                 /// comparison.
1563                 /// 
1564                 /// </param>
1565                 /// <param name="attr">   The attribute to compare against the entry. The
1566                 /// method checks to see if the entry has an
1567                 /// attribute with the same name and value as this
1568                 /// attribute.
1569                 /// 
1570                 /// </param>
1571                 /// <returns> True if the entry has the value,
1572                 /// and false if the entry does not
1573                 /// have the value or the attribute.
1574                 /// 
1575                 /// </returns>
1576                 /// <exception> LdapException A general exception which includes an error
1577                 /// message and an Ldap error code.
1578                 /// </exception>
1579                 public virtual bool Compare(System.String dn, LdapAttribute attr)
1580                 {
1581                         return Compare(dn, attr, defSearchCons);
1582                 }
1583                 
1584                 /// <summary> 
1585                 /// Synchronously checks to see if an entry contains an attribute with a
1586                 /// specified value, using the specified constraints.
1587                 /// 
1588                 /// </summary>
1589                 /// <param name="dn">     The distinguished name of the entry to use in the
1590                 /// comparison.
1591                 /// 
1592                 /// </param>
1593                 /// <param name="attr">   The attribute to compare against the entry. The
1594                 /// method checks to see if the entry has an
1595                 /// attribute with the same name and value as this
1596                 /// attribute.
1597                 /// 
1598                 /// </param>
1599                 /// <param name="cons">   Constraints specific to the operation.
1600                 /// 
1601                 /// </param>
1602                 /// <returns> True if the entry has the value,
1603                 /// and false if the entry does not
1604                 /// have the value or the attribute.
1605                 /// 
1606                 /// </returns>
1607                 /// <exception> LdapException A general exception which includes an error
1608                 /// message and an Ldap error code.
1609                 /// </exception>
1610                 public virtual bool Compare(System.String dn, LdapAttribute attr, LdapConstraints cons)
1611                 {
1612                         bool ret = false;
1613                         
1614                         LdapResponseQueue queue = Compare(dn, attr, null, cons);
1615                         
1616                         LdapResponse res = (LdapResponse) queue.getResponse();
1617                         
1618                         // Set local copy of responseControls synchronously - if there were any
1619                         lock (responseCtlSemaphore)
1620                         {
1621                                 responseCtls = res.Controls;
1622                         }
1623                         
1624                         if (res.ResultCode == LdapException.COMPARE_TRUE)
1625                         {
1626                                 ret = true;
1627                         }
1628                         else if (res.ResultCode == LdapException.COMPARE_FALSE)
1629                         {
1630                                 ret = false;
1631                         }
1632                         else
1633                         {
1634                                 chkResultCode(queue, cons, res);
1635                         }
1636                         return ret;
1637                 }
1638                 
1639                 /// <summary> Asynchronously compares an attribute value with one in the directory,
1640                 /// using the specified queue.
1641                 /// 
1642                 /// Please note that a successful completion of this command results in
1643                 /// one of two status codes: LdapException.COMPARE_TRUE if the entry
1644                 /// has the value, and LdapException.COMPARE_FALSE if the entry
1645                 /// does not have the value or the attribute.
1646                 /// 
1647                 /// </summary>
1648                 /// <param name="dn">     The distinguished name of the entry containing an
1649                 /// attribute to compare.
1650                 /// 
1651                 /// </param>
1652                 /// <param name="attr">   An attribute to compare.
1653                 /// 
1654                 /// </param>
1655                 /// <param name="queue">  The queue for messages returned from a server in
1656                 /// response to this request. If it is null, a
1657                 /// queue object is created internally.
1658                 /// 
1659                 /// </param>
1660                 /// <exception> LdapException A general exception which includes an error
1661                 /// message and an Ldap error code.
1662                 /// 
1663                 /// </exception>
1664                 /// <seealso cref="LdapException.COMPARE_TRUE">
1665                 /// </seealso>
1666                 /// <seealso cref="LdapException.COMPARE_FALSE">
1667                 /// </seealso>
1668                 public virtual LdapResponseQueue Compare(System.String dn, LdapAttribute attr, LdapResponseQueue queue)
1669                 {
1670                         return Compare(dn, attr, queue, defSearchCons);
1671                 }
1672                 
1673                 /// <summary> Asynchronously compares an attribute value with one in the directory,
1674                 /// using the specified queue and contraints.
1675                 /// 
1676                 /// Please note that a successful completion of this command results in
1677                 /// one of two status codes: LdapException.COMPARE_TRUE if the entry
1678                 /// has the value, and LdapException.COMPARE_FALSE if the entry
1679                 /// does not have the value or the attribute.
1680                 /// 
1681                 /// </summary>
1682                 /// <param name="dn">     The distinguished name of the entry containing an
1683                 /// attribute to compare.
1684                 /// 
1685                 /// </param>
1686                 /// <param name="attr">   An attribute to compare.
1687                 /// 
1688                 /// </param>
1689                 /// <param name="queue">    Handler for messages returned from a server in
1690                 /// response to this request. If it is null, a
1691                 /// queue object is created internally.
1692                 /// 
1693                 /// </param>
1694                 /// <param name="cons">     Constraints specific to the operation.
1695                 /// 
1696                 /// </param>
1697                 /// <exception> LdapException A general exception which includes an error
1698                 /// message and an Ldap error code.
1699                 /// 
1700                 /// </exception>
1701                 /// <seealso cref="LdapException.COMPARE_TRUE">
1702                 /// </seealso>
1703                 /// <seealso cref="LdapException.COMPARE_FALSE">
1704                 /// </seealso>
1705                 public virtual LdapResponseQueue Compare(System.String dn, LdapAttribute attr, LdapResponseQueue queue, LdapConstraints cons)
1706                 {
1707                         if (attr.size() != 1)
1708                         {
1709                                 throw new System.ArgumentException("compare: Exactly one value " + "must be present in the LdapAttribute");
1710                         }
1711                         
1712                         if ((System.Object) dn == null)
1713                         {
1714                                 // Invalid parameter
1715                                 throw new System.ArgumentException("compare: DN cannot be null");
1716                         }
1717                         
1718                         if (cons == null)
1719                                 cons = defSearchCons;
1720                         
1721                         LdapMessage msg = new LdapCompareRequest(dn, attr.Name, attr.ByteValue, cons.getControls());
1722                         
1723                         return SendRequestToServer(msg, cons.TimeLimit, queue, null);
1724                 }
1725                 
1726                 //*************************************************************************
1727                 // connect methods
1728                 //*************************************************************************
1729                 
1730                 /// <summary> 
1731                 /// Connects to the specified host and port.
1732                 /// 
1733                 /// If this LdapConnection object represents an open connection, the
1734                 /// connection is closed first before the new connection is opened.
1735                 /// At this point, there is no authentication, and any operations are
1736                 /// conducted as an anonymous client.
1737                 /// 
1738                 ///  When more than one host name is specified, each host is contacted
1739                 /// in turn until a connection can be established.
1740                 /// 
1741                 /// </summary>
1742                 /// <param name="host">A host name or a dotted string representing the IP address
1743                 /// of a host running an Ldap server. It may also
1744                 /// contain a list of host names, space-delimited. Each host
1745                 /// name can include a trailing colon and port number.
1746                 /// 
1747                 /// </param>
1748                 /// <param name="port">The TCP or UDP port number to connect to or contact.
1749                 /// The default Ldap port is 389. The port parameter is
1750                 /// ignored for any host hame which includes a colon and
1751                 /// port number.
1752                 /// 
1753                 /// </param>
1754                 /// <exception> LdapException A general exception which includes an error
1755                 /// message and an Ldap error code.
1756                 /// 
1757                 /// </exception>
1758                 public virtual void  Connect(System.String host, int port)
1759                 {
1760                         // connect doesn't affect other clones
1761                         // If not a clone, destroys old connection.
1762                         // Step through the space-delimited list
1763                         SupportClass.Tokenizer hostList = new SupportClass.Tokenizer(host, " ");
1764                         System.String address = null;
1765                         
1766                         int specifiedPort;
1767                         int colonIndex; //after the colon is the port
1768                         while (hostList.HasMoreTokens())
1769                         {
1770                                 try
1771                                 {
1772                                         specifiedPort = port;
1773                                         address = hostList.NextToken();
1774                                         colonIndex = address.IndexOf((System.Char) ':');
1775                                         if (colonIndex != - 1 && colonIndex + 1 != address.Length)
1776                                         {
1777                                                 //parse Port out of address
1778                                                 try
1779                                                 {
1780                                                         specifiedPort = System.Int32.Parse(address.Substring(colonIndex + 1));
1781                                                         address = address.Substring(0, (colonIndex) - (0));
1782                                                 }
1783                                                 catch (System.Exception e)
1784                                                 {
1785                                                         throw new System.ArgumentException(ExceptionMessages.INVALID_ADDRESS);
1786                                                 }
1787                                         }
1788                                         // This may return a different conn object
1789                                         // Disassociate this clone with the underlying connection.
1790                                         conn = conn.destroyClone(true);
1791                                         conn.connect(address, specifiedPort);
1792                                         break;
1793                                 }
1794                                 catch (LdapException LE)
1795                                 {
1796                                         if (!hostList.HasMoreTokens())
1797                                                 throw LE;
1798                                 }
1799                         }
1800                         return ;
1801                 }
1802                 
1803                 //*************************************************************************
1804                 // delete methods
1805                 //*************************************************************************
1806                 
1807                 /// <summary> 
1808                 /// Synchronously deletes the entry with the specified distinguished name
1809                 /// from the directory.
1810                 /// 
1811                 /// Note: A Delete operation will not remove an entry that contains
1812                 /// subordinate entries, nor will it dereference alias entries. 
1813                 /// 
1814                 /// </summary>
1815                 /// <param name="dn">     The distinguished name of the entry to delete.
1816                 /// 
1817                 /// </param>
1818                 /// <exception> LdapException A general exception which includes an error
1819                 /// message and an Ldap error code.
1820                 /// </exception>
1821                 public virtual void  Delete(System.String dn)
1822                 {
1823                         Delete(dn, defSearchCons);
1824                         return ;
1825                 }
1826                 
1827                 
1828                 /// <summary> Synchronously deletes the entry with the specified distinguished name
1829                 /// from the directory, using the specified constraints.
1830                 /// 
1831                 /// Note: A Delete operation will not remove an entry that contains
1832                 /// subordinate entries, nor will it dereference alias entries. 
1833                 /// 
1834                 /// </summary>
1835                 /// <param name="dn">     The distinguished name of the entry to delete.
1836                 /// 
1837                 /// </param>
1838                 /// <param name="cons">   Constraints specific to the operation.
1839                 /// 
1840                 /// </param>
1841                 /// <exception> LdapException A general exception which includes an error
1842                 /// message and an Ldap error code.
1843                 /// </exception>
1844                 public virtual void  Delete(System.String dn, LdapConstraints cons)
1845                 {
1846                         LdapResponseQueue queue = Delete(dn, null, cons);
1847                         
1848                         // Get a handle to the delete response
1849                         LdapResponse deleteResponse = (LdapResponse) (queue.getResponse());
1850                         
1851                         // Set local copy of responseControls synchronously - if there were any
1852                         lock (responseCtlSemaphore)
1853                         {
1854                                 responseCtls = deleteResponse.Controls;
1855                         }
1856                         chkResultCode(queue, cons, deleteResponse);
1857                         return ;
1858                 }
1859                 
1860                 /// <summary> Asynchronously deletes the entry with the specified distinguished name
1861                 /// from the directory and returns the results to the specified queue.
1862                 /// 
1863                 /// Note: A Delete operation will not remove an entry that contains
1864                 /// subordinate entries, nor will it dereference alias entries. 
1865                 /// 
1866                 /// </summary>
1867                 /// <param name="dn">     The distinguished name of the entry to modify.
1868                 /// 
1869                 /// </param>
1870                 /// <param name="queue">    The queue for messages returned from a server in
1871                 /// response to this request. If it is null, a
1872                 /// queue object is created internally.
1873                 /// 
1874                 /// </param>
1875                 /// <exception> LdapException A general exception which includes an error
1876                 /// message and an Ldap error code.
1877                 /// 
1878                 /// </exception>
1879                 public virtual LdapResponseQueue Delete(System.String dn, LdapResponseQueue queue)
1880                 {
1881                         return Delete(dn, queue, defSearchCons);
1882                 }
1883                 
1884                 /// <summary> Asynchronously deletes the entry with the specified distinguished name
1885                 /// from the directory, using the specified contraints and queue.
1886                 /// 
1887                 /// Note: A Delete operation will not remove an entry that contains
1888                 /// subordinate entries, nor will it dereference alias entries. 
1889                 /// 
1890                 /// </summary>
1891                 /// <param name="dn">     The distinguished name of the entry to delete.
1892                 /// 
1893                 /// </param>
1894                 /// <param name="queue">     The queue for messages returned from a server in
1895                 /// response to this request. If it is null, a
1896                 /// queue object is created internally.
1897                 /// 
1898                 /// </param>
1899                 /// <param name="cons">   The constraints specific to the operation.
1900                 /// 
1901                 /// </param>
1902                 /// <exception> LdapException A general exception which includes an error
1903                 /// message and an Ldap error code.
1904                 /// 
1905                 /// </exception>
1906                 public virtual LdapResponseQueue Delete(System.String dn, LdapResponseQueue queue, LdapConstraints cons)
1907                 {
1908                         if ((System.Object) dn == null)
1909                         {
1910                                 // Invalid DN parameter
1911                                 throw new System.ArgumentException(ExceptionMessages.DN_PARAM_ERROR);
1912                         }
1913                         
1914                         if (cons == null)
1915                                 cons = defSearchCons;
1916                         
1917                         LdapMessage msg = new LdapDeleteRequest(dn, cons.getControls());
1918                         
1919                         return SendRequestToServer(msg, cons.TimeLimit, queue, null);
1920                 }
1921                 
1922                 //*************************************************************************
1923                 // disconnect method
1924                 //*************************************************************************
1925                 
1926                 /// <summary> 
1927                 /// Synchronously disconnects from the Ldap server.
1928                 /// 
1929                 /// Before the object can perform Ldap operations again, it must
1930                 /// reconnect to the server by calling connect.
1931                 /// 
1932                 /// The disconnect method abandons any outstanding requests, issues an
1933                 /// unbind request to the server, and then closes the socket.
1934                 /// 
1935                 /// </summary>
1936                 /// <exception> LdapException A general exception which includes an error
1937                 /// message and an Ldap error code.
1938                 /// 
1939                 /// </exception>
1940                 public virtual void  Disconnect()
1941                 {
1942                         // disconnect from API call
1943                         Disconnect(defSearchCons, true);
1944                         return ;
1945                 }
1946                 
1947                 /// <summary> Synchronously disconnects from the Ldap server.
1948                 /// 
1949                 /// Before the object can perform Ldap operations again, it must
1950                 /// reconnect to the server by calling connect.
1951                 /// 
1952                 /// The disconnect method abandons any outstanding requests, issues an
1953                 /// unbind request to the server, and then closes the socket.
1954                 /// 
1955                 /// </summary>
1956                 /// <param name="cons">LDPConstraints to be set with the unbind request
1957                 /// 
1958                 /// </param>
1959                 /// <exception> LdapException A general exception which includes an error
1960                 /// message and an Ldap error code.
1961                 /// </exception>
1962                 public virtual void  Disconnect(LdapConstraints cons)
1963                 {
1964                         // disconnect from API call
1965                         Disconnect(cons, true);
1966                         return ;
1967                 }
1968                 
1969                 /// <summary> Synchronously disconnect from the server
1970                 /// 
1971                 /// </summary>
1972                 /// <param name="how">true if application call disconnect API, false if finalize.
1973                 /// </param>
1974                 private void  Disconnect(LdapConstraints cons, bool how)
1975                 {
1976                         // disconnect doesn't affect other clones
1977                         // If not a clone, distroys connection
1978                         conn = conn.destroyClone(how);
1979                         return ;
1980                 }
1981                 
1982                 //*************************************************************************
1983                 // extendedOperation methods
1984                 //*************************************************************************
1985                 
1986                 /// <summary> Provides a synchronous means to access extended, non-mandatory
1987                 /// operations offered by a particular Ldapv3 compliant server.
1988                 /// 
1989                 /// </summary>
1990                 /// <param name="op"> The object which contains (1) an identifier of an extended
1991                 /// operation which should be recognized by the particular Ldap
1992                 /// server this client is connected to and (2)
1993                 /// an operation-specific sequence of octet strings
1994                 /// or BER-encoded values.
1995                 /// 
1996                 /// </param>
1997                 /// <returns> An operation-specific object, containing an ID and either an octet
1998                 /// string or BER-encoded values.
1999                 /// 
2000                 /// </returns>
2001                 /// <exception> LdapException A general exception which includes an error
2002                 /// message and an Ldap error code.
2003                 /// </exception>
2004                 public virtual LdapExtendedResponse ExtendedOperation(LdapExtendedOperation op)
2005                 {
2006                         return ExtendedOperation(op, defSearchCons);
2007                 }
2008                 
2009                 /*
2010                 *  Synchronous Ldap extended request with SearchConstraints
2011                 */
2012                 
2013                 /// <summary> 
2014                 /// Provides a synchronous means to access extended, non-mandatory
2015                 /// operations offered by a particular Ldapv3 compliant server.
2016                 /// 
2017                 /// </summary>
2018                 /// <param name="op"> The object which contains (1) an identifier of an extended
2019                 /// operation which should be recognized by the particular Ldap
2020                 /// server this client is connected to and (2) an
2021                 /// operation-specific sequence of octet strings
2022                 /// or BER-encoded values.
2023                 /// 
2024                 /// </param>
2025                 /// <param name="cons">The constraints specific to the operation.
2026                 /// 
2027                 /// </param>
2028                 /// <returns> An operation-specific object, containing an ID and either an
2029                 /// octet string or BER-encoded values.
2030                 /// 
2031                 /// </returns>
2032                 /// <exception> LdapException A general exception which includes an error
2033                 /// message and an Ldap error code.
2034                 /// </exception>
2035                 
2036                 public virtual LdapExtendedResponse ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
2037                 {
2038                         
2039                         // Call asynchronous API and get back handler to reponse queue
2040                         LdapResponseQueue queue = ExtendedOperation(op, cons, null);
2041                         LdapExtendedResponse response = (LdapExtendedResponse) queue.getResponse();
2042                         
2043                         // Set local copy of responseControls synchronously - if there were any
2044                         lock (responseCtlSemaphore)
2045                         {
2046                                 responseCtls = response.Controls;
2047                         }
2048                         
2049                         chkResultCode(queue, cons, response);
2050                         return response;
2051                 }
2052                 
2053                 
2054                 /*
2055                 * Asynchronous Ldap extended request
2056                 */
2057                 
2058                 /// <summary> Provides an asynchronous means to access extended, non-mandatory
2059                 /// operations offered by a particular Ldapv3 compliant server.
2060                 /// 
2061                 /// </summary>
2062                 /// <param name="op"> The object which contains (1) an identifier of an extended
2063                 /// operation which should be recognized by the particular Ldap
2064                 /// server this client is connected to and (2) an
2065                 /// operation-specific sequence of octet strings
2066                 /// or BER-encoded values.
2067                 /// 
2068                 /// </param>
2069                 /// <param name="queue">    The queue for messages returned from a server in
2070                 /// response to this request. If it is null, a queue
2071                 /// object is created internally.
2072                 /// 
2073                 /// </param>
2074                 /// <returns> An operation-specific object, containing an ID and either an octet
2075                 /// string or BER-encoded values.
2076                 /// 
2077                 /// </returns>
2078                 /// <exception> LdapException A general exception which includes an error
2079                 /// message and an Ldap error code.
2080                 /// </exception>
2081                 
2082                 public virtual LdapResponseQueue ExtendedOperation(LdapExtendedOperation op, LdapResponseQueue queue)
2083                 {
2084                         
2085                         return ExtendedOperation(op, defSearchCons, queue);
2086                 }
2087                 
2088                 
2089                 /*
2090                 *  Asynchronous Ldap extended request with SearchConstraints
2091                 */
2092                 
2093                 /// <summary> Provides an asynchronous means to access extended, non-mandatory
2094                 /// operations offered by a particular Ldapv3 compliant server.
2095                 /// 
2096                 /// </summary>
2097                 /// <param name="op"> The object which contains (1) an identifier of an extended
2098                 /// operation which should be recognized by the particular Ldap
2099                 /// server this client is connected to and (2) an operation-
2100                 /// specific sequence of octet strings or BER-encoded values.
2101                 /// 
2102                 /// </param>
2103                 /// <param name="queue">    The queue for messages returned from a server in
2104                 /// response to this request. If it is null, a queue
2105                 /// object is created internally.
2106                 /// 
2107                 /// </param>
2108                 /// <param name="cons">     The constraints specific to this operation.
2109                 /// 
2110                 /// </param>
2111                 /// <returns> An operation-specific object, containing an ID and either an
2112                 /// octet string or BER-encoded values.
2113                 /// 
2114                 /// </returns>
2115                 /// <exception> LdapException A general exception which includes an error
2116                 /// message and an Ldap error code.
2117                 /// </exception>
2118                 
2119                 public virtual LdapResponseQueue ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons, LdapResponseQueue queue)
2120                 {
2121                         // Use default constraints if none-specified
2122                         if (cons == null)
2123                                 cons = defSearchCons;
2124                         LdapMessage msg = MakeExtendedOperation(op, cons);
2125                         return SendRequestToServer(msg, cons.TimeLimit, queue, null);
2126                 }
2127                 
2128                 /// <summary> Formulates the extended operation, constraints into an
2129                 /// LdapMessage and returns the LdapMessage.  This is used by
2130                 /// extendedOperation and startTLS which needs the LdapMessage to
2131                 /// get the MessageID.
2132                 /// </summary>
2133                 protected internal virtual LdapMessage MakeExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
2134                 {
2135                         // Use default constraints if none-specified
2136                         if (cons == null)
2137                                 cons = defSearchCons;
2138                         
2139                         // error check the parameters
2140                         if ((System.Object) op.getID() == null)
2141                         {
2142                                 // Invalid extended operation parameter, no OID specified
2143                                 throw new System.ArgumentException(ExceptionMessages.OP_PARAM_ERROR);
2144                         }
2145                         
2146                         return new LdapExtendedRequest(op, cons.getControls());
2147                 }
2148                 
2149                 //*************************************************************************
2150                 // getResponseControls method
2151                 //*************************************************************************
2152                 
2153                 //*************************************************************************
2154                 // modify methods
2155                 //*************************************************************************
2156                 
2157                 /// <summary> Synchronously makes a single change to an existing entry in the
2158                 /// directory.
2159                 /// 
2160                 /// For example, this modify method changes the value of an attribute,
2161                 /// adds a new attribute value, or removes an existing attribute value. 
2162                 /// 
2163                 /// The LdapModification object specifies both the change to be made and
2164                 /// the LdapAttribute value to be changed.
2165                 /// 
2166                 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2167                 /// it is indeterminate whether or not the server made the modification.
2168                 /// 
2169                 /// </summary>
2170                 /// <param name="dn">    The distinguished name of the entry to modify.
2171                 /// 
2172                 /// </param>
2173                 /// <param name="mod">   A single change to be made to the entry.
2174                 /// 
2175                 /// </param>
2176                 /// <exception> LdapException A general exception which includes an error
2177                 /// message and an Ldap error code.
2178                 /// </exception>
2179                 public virtual void  Modify(System.String dn, LdapModification mod)
2180                 {
2181                         Modify(dn, mod, defSearchCons);
2182                         return ;
2183                 }
2184                 
2185                 /// <summary> 
2186                 /// Synchronously makes a single change to an existing entry in the
2187                 /// directory, using the specified constraints.
2188                 /// 
2189                 /// For example, this modify method changes the value of an attribute,
2190                 /// adds a new attribute value, or removes an existing attribute value.
2191                 /// 
2192                 /// The LdapModification object specifies both the change to be
2193                 /// made and the LdapAttribute value to be changed.
2194                 /// 
2195                 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2196                 /// it is indeterminate whether or not the server made the modification.
2197                 /// 
2198                 /// </summary>
2199                 /// <param name="dn">      The distinguished name of the entry to modify.
2200                 /// 
2201                 /// </param>
2202                 /// <param name="mod">     A single change to be made to the entry.
2203                 /// 
2204                 /// </param>
2205                 /// <param name="cons">    The constraints specific to the operation.
2206                 /// 
2207                 /// </param>
2208                 /// <exception> LdapException A general exception which includes an error
2209                 /// message and an Ldap error code.
2210                 /// </exception>
2211                 public virtual void  Modify(System.String dn, LdapModification mod, LdapConstraints cons)
2212                 {
2213                         LdapModification[] mods = new LdapModification[1];
2214                         mods[0] = mod;
2215                         Modify(dn, mods, cons);
2216                         return ;
2217                 }
2218                 
2219                 /// <summary> 
2220                 /// Synchronously makes a set of changes to an existing entry in the
2221                 /// directory.
2222                 /// 
2223                 /// For example, this modify method changes attribute values, adds
2224                 /// new attribute values, or removes existing attribute values.
2225                 /// 
2226                 /// Because the server applies all changes in an LdapModification array
2227                 /// atomically, the application can expect that no changes
2228                 /// have been performed if an error is returned.
2229                 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2230                 /// it is indeterminate whether or not the server made the modifications.
2231                 /// 
2232                 /// </summary>
2233                 /// <param name="dn">    Distinguished name of the entry to modify.
2234                 /// 
2235                 /// </param>
2236                 /// <param name="mods">  The changes to be made to the entry.
2237                 /// 
2238                 /// </param>
2239                 /// <exception> LdapException A general exception which includes an error
2240                 /// message and an Ldap error code.
2241                 /// </exception>
2242                 public virtual void  Modify(System.String dn, LdapModification[] mods)
2243                 {
2244                         Modify(dn, mods, defSearchCons);
2245                         return ;
2246                 }
2247                 
2248                 /// <summary> Synchronously makes a set of changes to an existing entry in the
2249                 /// directory, using the specified constraints.
2250                 /// 
2251                 /// For example, this modify method changes attribute values, adds new
2252                 /// attribute values, or removes existing attribute values.
2253                 /// 
2254                 /// Because the server applies all changes in an LdapModification array
2255                 /// atomically, the application can expect that no changes
2256                 /// have been performed if an error is returned.
2257                 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2258                 /// it is indeterminate whether or not the server made the modifications.
2259                 /// 
2260                 /// </summary>
2261                 /// <param name="dn">     The distinguished name of the entry to modify.
2262                 /// 
2263                 /// </param>
2264                 /// <param name="mods">   The changes to be made to the entry.
2265                 /// 
2266                 /// </param>
2267                 /// <param name="cons">   The constraints specific to the operation.
2268                 /// 
2269                 /// </param>
2270                 /// <exception> LdapException A general exception which includes an
2271                 /// error message and an Ldap error code.
2272                 /// </exception>
2273                 public virtual void  Modify(System.String dn, LdapModification[] mods, LdapConstraints cons)
2274                 {
2275                         LdapResponseQueue queue = Modify(dn, mods, null, cons);
2276                         
2277                         // Get a handle to the modify response
2278                         LdapResponse modifyResponse = (LdapResponse) (queue.getResponse());
2279                         
2280                         // Set local copy of responseControls synchronously - if there were any
2281                         lock (responseCtlSemaphore)
2282                         {
2283                                 responseCtls = modifyResponse.Controls;
2284                         }
2285                         
2286                         chkResultCode(queue, cons, modifyResponse);
2287                         
2288                         return ;
2289                 }
2290                 
2291                 /// <summary> Asynchronously makes a single change to an existing entry in the
2292                 /// directory.
2293                 /// 
2294                 /// For example, this modify method can change the value of an attribute,
2295                 /// add a new attribute value, or remove an existing attribute value.
2296                 /// 
2297                 /// The LdapModification object specifies both the change to be made and
2298                 /// the LdapAttribute value to be changed.
2299                 /// 
2300                 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2301                 /// it is indeterminate whether or not the server made the modification.
2302                 /// 
2303                 /// </summary>
2304                 /// <param name="dn">        Distinguished name of the entry to modify.
2305                 /// 
2306                 /// </param>
2307                 /// <param name="mod">       A single change to be made to the entry.
2308                 /// 
2309                 /// </param>
2310                 /// <param name="queue">     Handler for messages returned from a server in
2311                 /// response to this request. If it is null, a
2312                 /// queue object is created internally.
2313                 /// 
2314                 /// </param>
2315                 /// <exception> LdapException A general exception which includes an error
2316                 /// message and an Ldap error code.
2317                 /// </exception>
2318                 public virtual LdapResponseQueue Modify(System.String dn, LdapModification mod, LdapResponseQueue queue)
2319                 {
2320                         return Modify(dn, mod, queue, defSearchCons);
2321                 }
2322                 
2323                 /// <summary> Asynchronously makes a single change to an existing entry in the
2324                 /// directory, using the specified constraints and queue.
2325                 /// 
2326                 /// For example, this modify method can change the value of an attribute,
2327                 /// add a new attribute value, or remove an existing attribute value.
2328                 /// 
2329                 /// The LdapModification object specifies both the change to be made
2330                 /// and the LdapAttribute value to be changed.
2331                 /// 
2332                 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2333                 /// it is indeterminate whether or not the server made the modification.
2334                 /// 
2335                 /// </summary>
2336                 /// <param name="dn">         Distinguished name of the entry to modify.
2337                 /// 
2338                 /// </param>
2339                 /// <param name="mod">        A single change to be made to the entry.
2340                 /// 
2341                 /// </param>
2342                 /// <param name="queue">      Handler for messages returned from a server in
2343                 /// response to this request. If it is null, a
2344                 /// queue object is created internally.
2345                 /// 
2346                 /// </param>
2347                 /// <param name="cons">       Constraints specific to the operation.
2348                 /// 
2349                 /// </param>
2350                 /// <exception> LdapException A general exception which includes an error
2351                 /// message and an Ldap error code.
2352                 /// </exception>
2353                 public virtual LdapResponseQueue Modify(System.String dn, LdapModification mod, LdapResponseQueue queue, LdapConstraints cons)
2354                 {
2355                         LdapModification[] mods = new LdapModification[1];
2356                         mods[0] = mod;
2357                         return Modify(dn, mods, queue, cons);
2358                 }
2359                 
2360                 /// <summary> Asynchronously makes a set of changes to an existing entry in the
2361                 /// directory.
2362                 /// 
2363                 /// For example, this modify method can change attribute values, add new
2364                 /// attribute values, or remove existing attribute values.
2365                 /// 
2366                 /// Because the server applies all changes in an LdapModification array
2367                 /// atomically, the application can expect that no changes
2368                 /// have been performed if an error is returned.
2369                 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2370                 /// it is indeterminate whether or not the server made the modifications.
2371                 /// 
2372                 /// </summary>
2373                 /// <param name="dn">        The distinguished name of the entry to modify.
2374                 /// 
2375                 /// </param>
2376                 /// <param name="mods">      The changes to be made to the entry.
2377                 /// 
2378                 /// </param>
2379                 /// <param name="queue">     The queue for messages returned from a server in
2380                 /// response to this request. If it is null, a
2381                 /// queue object is created internally.
2382                 /// 
2383                 /// </param>
2384                 /// <exception> LdapException A general exception which includes an error
2385                 /// message and an Ldap error code.
2386                 /// </exception>
2387                 public virtual LdapResponseQueue Modify(System.String dn, LdapModification[] mods, LdapResponseQueue queue)
2388                 {
2389                         return Modify(dn, mods, queue, defSearchCons);
2390                 }
2391                 
2392                 /// <summary> Asynchronously makes a set of changes to an existing entry in the
2393                 /// directory, using the specified constraints and queue.
2394                 /// 
2395                 /// For example, this modify method can change attribute values, add new
2396                 /// attribute values, or remove existing attribute values.
2397                 /// 
2398                 /// Because the server applies all changes in an LdapModification array
2399                 /// atomically, the application can expect that no changes
2400                 /// have been performed if an error is returned.
2401                 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2402                 /// it is indeterminate whether or not the server made the modifications.
2403                 /// 
2404                 /// </summary>
2405                 /// <param name="dn">        The distinguished name of the entry to modify.
2406                 /// 
2407                 /// </param>
2408                 /// <param name="mods">      The changes to be made to the entry.
2409                 /// 
2410                 /// </param>
2411                 /// <param name="queue">     The queue for messages returned from a server in
2412                 /// response to this request. If it is null, a
2413                 /// queue object is created internally.
2414                 /// 
2415                 /// </param>
2416                 /// <param name="cons">      Constraints specific to the operation.
2417                 /// 
2418                 /// </param>
2419                 /// <exception> LdapException A general exception which includes an error
2420                 /// message and an Ldap error code.
2421                 /// </exception>
2422                 public virtual LdapResponseQueue Modify(System.String dn, LdapModification[] mods, LdapResponseQueue queue, LdapConstraints cons)
2423                 {
2424                         if ((System.Object) dn == null)
2425                         {
2426                                 // Invalid DN parameter
2427                                 throw new System.ArgumentException(ExceptionMessages.DN_PARAM_ERROR);
2428                         }
2429                         
2430                         if (cons == null)
2431                                 cons = defSearchCons;
2432                         
2433                         LdapMessage msg = new LdapModifyRequest(dn, mods, cons.getControls());
2434                         
2435                         return SendRequestToServer(msg, cons.TimeLimit, queue, null);
2436                 }
2437                 
2438                 //*************************************************************************
2439                 // read methods
2440                 //*************************************************************************
2441                 
2442                 /// <summary> Synchronously reads the entry for the specified distiguished name (DN)
2443                 /// and retrieves all attributes for the entry.
2444                 /// 
2445                 /// </summary>
2446                 /// <param name="dn">       The distinguished name of the entry to retrieve.
2447                 /// 
2448                 /// </param>
2449                 /// <returns> the LdapEntry read from the server.
2450                 /// 
2451                 /// </returns>
2452                 /// <exception> LdapException if the object was not found
2453                 /// </exception>
2454                 public virtual LdapEntry Read(System.String dn)
2455                 {
2456                         return Read(dn, defSearchCons);
2457                 }
2458                 
2459                 
2460                 /// <summary> 
2461                 /// Synchronously reads the entry for the specified distiguished name (DN),
2462                 /// using the specified constraints, and retrieves all attributes for the
2463                 /// entry.
2464                 /// 
2465                 /// </summary>
2466                 /// <param name="dn">        The distinguished name of the entry to retrieve.
2467                 /// 
2468                 /// </param>
2469                 /// <param name="cons">      The constraints specific to the operation.
2470                 /// 
2471                 /// </param>
2472                 /// <returns> the LdapEntry read from the server
2473                 /// 
2474                 /// </returns>
2475                 /// <exception> LdapException if the object was not found
2476                 /// </exception>
2477                 public virtual LdapEntry Read(System.String dn, LdapSearchConstraints cons)
2478                 {
2479                         return Read(dn, null, cons);
2480                 }
2481                 
2482                 /// <summary> 
2483                 /// Synchronously reads the entry for the specified distinguished name (DN)
2484                 /// and retrieves only the specified attributes from the entry.
2485                 /// 
2486                 /// </summary>
2487                 /// <param name="dn">        The distinguished name of the entry to retrieve.
2488                 /// 
2489                 /// </param>
2490                 /// <param name="attrs">     The names of the attributes to retrieve.
2491                 /// 
2492                 /// </param>
2493                 /// <returns> the LdapEntry read from the server
2494                 /// 
2495                 /// </returns>
2496                 /// <exception> LdapException if the object was not found
2497                 /// </exception>
2498                 public virtual LdapEntry Read(System.String dn, System.String[] attrs)
2499                 {
2500                         return Read(dn, attrs, defSearchCons);
2501                 }
2502                 
2503                 /// <summary> Synchronously reads the entry for the specified distinguished name (DN),
2504                 /// using the specified constraints, and retrieves only the specified
2505                 /// attributes from the entry.
2506                 /// 
2507                 /// </summary>
2508                 /// <param name="dn">      The distinguished name of the entry to retrieve.
2509                 /// 
2510                 /// </param>
2511                 /// <param name="attrs">   The names of the attributes to retrieve.
2512                 /// 
2513                 /// </param>
2514                 /// <param name="cons">    The constraints specific to the operation.
2515                 /// 
2516                 /// </param>
2517                 /// <returns> the LdapEntry read from the server
2518                 /// 
2519                 /// </returns>
2520                 /// <exception> LdapException if the object was not found
2521                 /// </exception>
2522                 public virtual LdapEntry Read(System.String dn, System.String[] attrs, LdapSearchConstraints cons)
2523                 {
2524                         LdapSearchResults sr = Search(dn, SCOPE_BASE, null, attrs, false, cons);
2525                         
2526                         LdapEntry ret = null;
2527                         if (sr.hasMore())
2528                         {
2529                                 ret = sr.next();
2530                                 if (sr.hasMore())
2531                                 {
2532                                         // "Read response is ambiguous, multiple entries returned"
2533                                         throw new LdapLocalException(ExceptionMessages.READ_MULTIPLE, LdapException.AMBIGUOUS_RESPONSE);
2534                                 }
2535                         }
2536                         return ret;
2537                 }
2538                 
2539                 /// <summary> Synchronously reads the entry specified by the Ldap URL.
2540                 /// 
2541                 /// When this read method is called, a new connection is created
2542                 /// automatically, using the host and port specified in the URL. After
2543                 /// finding the entry, the method closes the connection (in other words,
2544                 /// it disconnects from the Ldap server).
2545                 /// 
2546                 /// If the URL specifies a filter and scope, they are not used. Of the
2547                 /// information specified in the URL, this method only uses the Ldap host
2548                 /// name and port number, the base distinguished name (DN), and the list
2549                 /// of attributes to return.
2550                 /// 
2551                 /// </summary>
2552                 /// <param name="toGet">          Ldap URL specifying the entry to read.
2553                 /// 
2554                 /// </param>
2555                 /// <returns> The entry specified by the base DN.
2556                 /// 
2557                 /// </returns>
2558                 /// <exception> LdapException if the object was not found
2559                 /// </exception>
2560                 public static LdapEntry Read(LdapUrl toGet)
2561                 {
2562                         LdapConnection lconn = new LdapConnection();
2563                         lconn.Connect(toGet.Host, toGet.Port);
2564                         LdapEntry toReturn = lconn.Read(toGet.getDN(), toGet.AttributeArray);
2565                         lconn.Disconnect();
2566                         return toReturn;
2567                 }
2568                 
2569                 /// <summary> Synchronously reads the entry specified by the Ldap URL, using the
2570                 /// specified constraints.
2571                 /// 
2572                 /// When this method is called, a new connection is created
2573                 /// automatically, using the host and port specified in the URL. After
2574                 /// finding the entry, the method closes the connection (in other words,
2575                 /// it disconnects from the Ldap server).
2576                 /// 
2577                 /// If the URL specifies a filter and scope, they are not used. Of the
2578                 /// information specified in the URL, this method only uses the Ldap host
2579                 /// name and port number, the base distinguished name (DN), and the list
2580                 /// of attributes to return.
2581                 /// 
2582                 /// </summary>
2583                 /// <returns> The entry specified by the base DN.
2584                 /// 
2585                 /// </returns>
2586                 /// <param name="toGet">      Ldap URL specifying the entry to read.
2587                 /// 
2588                 /// </param>
2589                 /// <param name="cons">      Constraints specific to the operation.
2590                 /// 
2591                 /// </param>
2592                 /// <exception> LdapException if the object was not found
2593                 /// </exception>
2594                 public static LdapEntry Read(LdapUrl toGet, LdapSearchConstraints cons)
2595                 {
2596                         LdapConnection lconn = new LdapConnection();
2597                         lconn.Connect(toGet.Host, toGet.Port);
2598                         LdapEntry toReturn = lconn.Read(toGet.getDN(), toGet.AttributeArray, cons);
2599                         lconn.Disconnect();
2600                         return toReturn;
2601                 }
2602                 
2603                 //*************************************************************************
2604                 // rename methods
2605                 //*************************************************************************
2606                 
2607                 /// <summary> 
2608                 /// Synchronously renames an existing entry in the directory.
2609                 /// 
2610                 /// </summary>
2611                 /// <param name="dn">      The current distinguished name of the entry.
2612                 /// 
2613                 /// </param>
2614                 /// <param name="newRdn">  The new relative distinguished name for the entry.
2615                 /// 
2616                 /// </param>
2617                 /// <param name="deleteOldRdn">  If true, the old name is not retained as an
2618                 /// attribute value. If false, the old name is
2619                 /// retained as an attribute value.
2620                 /// 
2621                 /// </param>
2622                 /// <exception> LdapException A general exception which includes an error
2623                 /// message and an Ldap error code.
2624                 /// </exception>
2625                 public virtual void  Rename(System.String dn, System.String newRdn, bool deleteOldRdn)
2626                 {
2627                         Rename(dn, newRdn, deleteOldRdn, defSearchCons);
2628                         return ;
2629                 }
2630                 
2631                 /// <summary> 
2632                 /// Synchronously renames an existing entry in the directory, using the
2633                 /// specified constraints.
2634                 /// 
2635                 /// </summary>
2636                 /// <param name="dn">            The current distinguished name of the entry.
2637                 /// 
2638                 /// </param>
2639                 /// <param name="newRdn">        The new relative distinguished name for the entry.
2640                 /// 
2641                 /// </param>
2642                 /// <param name="deleteOldRdn">  If true, the old name is not retained as an
2643                 /// attribute value. If false, the old name is
2644                 /// retained as an attribute value.
2645                 /// 
2646                 /// </param>
2647                 /// <param name="cons">          The constraints specific to the operation.
2648                 /// 
2649                 /// </param>
2650                 /// <exception> LdapException A general exception which includes an error
2651                 /// message and an Ldap error code.
2652                 /// </exception>
2653                 public virtual void  Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapConstraints cons)
2654                 {
2655                         // null for newParentdn means that this is originating as an Ldapv2 call
2656                         Rename(dn, newRdn, null, deleteOldRdn, cons);
2657                         return ;
2658                 }
2659                 
2660                 /// <summary> Synchronously renames an existing entry in the directory, possibly
2661                 /// repositioning the entry in the directory tree.
2662                 /// 
2663                 /// </summary>
2664                 /// <param name="dn">            The current distinguished name of the entry.
2665                 /// 
2666                 /// </param>
2667                 /// <param name="newRdn">        The new relative distinguished name for the entry.
2668                 /// 
2669                 /// </param>
2670                 /// <param name="newParentdn">   The distinguished name of an existing entry which
2671                 /// is to be the new parent of the entry.
2672                 /// 
2673                 /// </param>
2674                 /// <param name="deleteOldRdn">  If true, the old name is not retained as an
2675                 /// attribute value. If false, the old name is
2676                 /// retained as an attribute value.
2677                 /// 
2678                 /// </param>
2679                 /// <exception> LdapException A general exception which includes an error
2680                 /// message and an Ldap error code.
2681                 /// </exception>
2682                 public virtual void  Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn)
2683                 {
2684                         Rename(dn, newRdn, newParentdn, deleteOldRdn, defSearchCons);
2685                         return ;
2686                 }
2687                 
2688                 /// <summary> 
2689                 /// Synchronously renames an existing entry in the directory, using the
2690                 /// specified constraints and possibly repositioning the entry in the
2691                 /// directory tree.
2692                 /// 
2693                 /// </summary>
2694                 /// <param name="dn">            The current distinguished name of the entry.
2695                 /// 
2696                 /// </param>
2697                 /// <param name="newRdn">        The new relative distinguished name for the entry.
2698                 /// 
2699                 /// </param>
2700                 /// <param name="newParentdn">   The distinguished name of an existing entry which
2701                 /// is to be the new parent of the entry.
2702                 /// 
2703                 /// </param>
2704                 /// <param name="deleteOldRdn">  If true, the old name is not retained as an
2705                 /// attribute value. If false, the old name is
2706                 /// retained as an attribute value.
2707                 /// 
2708                 /// </param>
2709                 /// <param name="cons">          The constraints specific to the operation.
2710                 /// 
2711                 /// </param>
2712                 /// <exception> LdapException A general exception which includes an error
2713                 /// message and an Ldap error code.
2714                 /// </exception>
2715                 public virtual void  Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapConstraints cons)
2716                 {
2717                         LdapResponseQueue queue = Rename(dn, newRdn, newParentdn, deleteOldRdn, null, cons);
2718                         
2719                         // Get a handle to the rename response
2720                         LdapResponse renameResponse = (LdapResponse) (queue.getResponse());
2721                         
2722                         // Set local copy of responseControls synchronously - if there were any
2723                         lock (responseCtlSemaphore)
2724                         {
2725                                 responseCtls = renameResponse.Controls;
2726                         }
2727                         
2728                         chkResultCode(queue, cons, renameResponse);
2729                         return ;
2730                 }
2731                 
2732                 /*
2733                 * rename
2734                 */
2735                 
2736                 /// <summary> Asynchronously renames an existing entry in the directory.
2737                 /// 
2738                 /// </summary>
2739                 /// <param name="dn">            The current distinguished name of the entry.
2740                 /// 
2741                 /// </param>
2742                 /// <param name="newRdn">        The new relative distinguished name for the entry.
2743                 /// 
2744                 /// </param>
2745                 /// <param name="deleteOldRdn">  If true, the old name is not retained as an
2746                 /// attribute value. If false, the old name is
2747                 /// retained as an attribute value.
2748                 /// 
2749                 /// </param>
2750                 /// <param name="queue">         The queue for messages returned from a server in
2751                 /// response to this request. If it is null, a
2752                 /// queue object is created internally.
2753                 /// 
2754                 /// </param>
2755                 /// <exception> LdapException A general exception which includes an error
2756                 /// message and an Ldap error code.
2757                 /// </exception>
2758                 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapResponseQueue queue)
2759                 {
2760                         return Rename(dn, newRdn, deleteOldRdn, queue, defSearchCons);
2761                 }
2762                 
2763                 /// <summary> Asynchronously renames an existing entry in the directory, using the
2764                 /// specified constraints.
2765                 /// 
2766                 /// </summary>
2767                 /// <param name="dn">            The current distinguished name of the entry.
2768                 /// 
2769                 /// </param>
2770                 /// <param name="newRdn">        The new relative distinguished name for the entry.
2771                 /// 
2772                 /// </param>
2773                 /// <param name="deleteOldRdn">  If true, the old name is not retained as an
2774                 /// attribute value. If false, the old name is
2775                 /// retained as an attribute value.
2776                 /// 
2777                 /// </param>
2778                 /// <param name="queue">         The queue for messages returned from a server in
2779                 /// response to this request. If it is null, a
2780                 /// queue object is created internally.
2781                 /// 
2782                 /// </param>
2783                 /// <param name="cons">          The constraints specific to the operation.
2784                 /// 
2785                 /// </param>
2786                 /// <exception> LdapException A general exception which includes an error
2787                 /// message and an Ldap error code.
2788                 /// </exception>
2789                 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
2790                 {
2791                         return Rename(dn, newRdn, null, deleteOldRdn, queue, cons);
2792                 }
2793                 
2794                 /// <summary> Asynchronously renames an existing entry in the directory, possibly
2795                 /// repositioning the entry in the directory.
2796                 /// 
2797                 /// </summary>
2798                 /// <param name="dn">            The current distinguished name of the entry.
2799                 /// 
2800                 /// </param>
2801                 /// <param name="newRdn">        The new relative distinguished name for the entry.
2802                 /// 
2803                 /// </param>
2804                 /// <param name="newParentdn">   The distinguished name of an existing entry which
2805                 /// is to be the new parent of the entry.
2806                 /// 
2807                 /// </param>
2808                 /// <param name="deleteOldRdn">  If true, the old name is not retained as an
2809                 /// attribute value. If false, the old name is
2810                 /// retained as an attribute value.
2811                 /// 
2812                 /// </param>
2813                 /// <param name="queue">         The queue for messages returned from a server in
2814                 /// response to this request. If it is null, a
2815                 /// queue object is created internally.
2816                 /// 
2817                 /// </param>
2818                 /// <exception> LdapException A general exception which includes an error
2819                 /// message and an Ldap error code.
2820                 /// </exception>
2821                 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapResponseQueue queue)
2822                 {
2823                         return Rename(dn, newRdn, newParentdn, deleteOldRdn, queue, defSearchCons);
2824                 }
2825                 
2826                 /// <summary> Asynchronously renames an existing entry in the directory, using the
2827                 /// specified constraints and possibily repositioning the entry in the
2828                 /// directory.
2829                 /// 
2830                 /// </summary>
2831                 /// <param name="dn">            The current distinguished name of the entry.
2832                 /// 
2833                 /// </param>
2834                 /// <param name="newRdn">        The new relative distinguished name for the entry.
2835                 /// 
2836                 /// </param>
2837                 /// <param name="newParentdn">   The distinguished name of an existing entry which
2838                 /// is to be the new parent of the entry.
2839                 /// 
2840                 /// </param>
2841                 /// <param name="deleteOldRdn">  If true, the old name is not retained as an
2842                 /// attribute value. If false, the old name is
2843                 /// retained as an attribute value.
2844                 /// 
2845                 /// </param>
2846                 /// <param name="queue">         The queue for messages returned from a server in
2847                 /// response to this request. If it is null, a
2848                 /// queue object is created internally.
2849                 /// 
2850                 /// </param>
2851                 /// <param name="cons">          The constraints specific to the operation.
2852                 /// 
2853                 /// </param>
2854                 /// <exception> LdapException A general exception which includes an error
2855                 /// message and an Ldap error code.
2856                 /// </exception>
2857                 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
2858                 {
2859                         if ((System.Object) dn == null || (System.Object) newRdn == null)
2860                         {
2861                                 // Invalid DN or RDN parameter
2862                                 throw new System.ArgumentException(ExceptionMessages.RDN_PARAM_ERROR);
2863                         }
2864                         
2865                         if (cons == null)
2866                                 cons = defSearchCons;
2867                         
2868                         LdapMessage msg = new LdapModifyDNRequest(dn, newRdn, newParentdn, deleteOldRdn, cons.getControls());
2869                         
2870                         return SendRequestToServer(msg, cons.TimeLimit, queue, null);
2871                 }
2872                 
2873                 //*************************************************************************
2874                 // search methods
2875                 //*************************************************************************
2876                 
2877                 /// <summary> 
2878                 /// Synchronously performs the search specified by the parameters.
2879                 /// 
2880                 /// </summary>
2881                 /// <param name="base">          The base distinguished name to search from.
2882                 /// 
2883                 /// </param>
2884                 /// <param name="scope">         The scope of the entries to search. The following
2885                 /// are the valid options:
2886                 /// <ul>
2887                 /// <li>SCOPE_BASE - searches only the base DN</li>
2888                 /// 
2889                 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2890                 /// 
2891                 /// <li>SCOPE_SUB - searches the base DN and all entries
2892                 /// within its subtree</li>
2893                 /// </ul>
2894                 /// </param>
2895                 /// <param name="filter">        Search filter specifying the search criteria.
2896                 /// 
2897                 /// </param>
2898                 /// <param name="attrs">         Names of attributes to retrieve.
2899                 /// 
2900                 /// </param>
2901                 /// <param name="typesOnly">     If true, returns the names but not the values of
2902                 /// the attributes found. If false, returns the
2903                 /// names and values for attributes found.
2904                 /// 
2905                 /// </param>
2906                 /// <exception> LdapException A general exception which includes an error
2907                 /// message and an Ldap error code.
2908                 /// </exception>
2909                 public virtual LdapSearchResults Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly)
2910                 {
2911                         return Search(base_Renamed, scope, filter, attrs, typesOnly, defSearchCons);
2912                 }
2913                 
2914                 /// <summary> 
2915                 /// Synchronously performs the search specified by the parameters,
2916                 /// using the specified search constraints (such as the
2917                 /// maximum number of entries to find or the maximum time to wait for
2918                 /// search results).
2919                 /// 
2920                 /// As part of the search constraints, the method allows specifying
2921                 /// whether or not the results are to be delivered all at once or in
2922                 /// smaller batches. If specified that the results are to be delivered in
2923                 /// smaller batches, each iteration blocks only until the next batch of
2924                 /// results is returned.
2925                 /// 
2926                 /// </summary>
2927                 /// <param name="base">          The base distinguished name to search from.
2928                 /// 
2929                 /// </param>
2930                 /// <param name="scope">         The scope of the entries to search. The following
2931                 /// are the valid options:
2932                 /// <ul>
2933                 /// <li>SCOPE_BASE - searches only the base DN</li>
2934                 /// 
2935                 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2936                 /// 
2937                 /// <li>SCOPE_SUB - searches the base DN and all entries
2938                 /// within its subtree</li>
2939                 /// </ul>
2940                 /// </param>
2941                 /// <param name="filter">        The search filter specifying the search criteria.
2942                 /// 
2943                 /// </param>
2944                 /// <param name="attrs">         The names of attributes to retrieve.
2945                 /// 
2946                 /// </param>
2947                 /// <param name="typesOnly">     If true, returns the names but not the values of
2948                 /// the attributes found.  If false, returns the
2949                 /// names and values for attributes found.
2950                 /// 
2951                 /// </param>
2952                 /// <param name="cons">          The constraints specific to the search.
2953                 /// 
2954                 /// </param>
2955                 /// <exception> LdapException A general exception which includes an error
2956                 /// message and an Ldap error code.
2957                 /// </exception>
2958                 public virtual LdapSearchResults Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchConstraints cons)
2959                 {
2960                         LdapSearchQueue queue = Search(base_Renamed, scope, filter, attrs, typesOnly, null, cons);
2961                         
2962                         if (cons == null)
2963                                 cons = defSearchCons;
2964                         return new LdapSearchResults(this, queue, cons);
2965                 }
2966                 
2967                 /// <summary> Asynchronously performs the search specified by the parameters.
2968                 /// 
2969                 /// </summary>
2970                 /// <param name="base">          The base distinguished name to search from.
2971                 /// 
2972                 /// </param>
2973                 /// <param name="scope">         The scope of the entries to search. The following
2974                 /// are the valid options:
2975                 /// <ul>
2976                 /// <li>SCOPE_BASE - searches only the base DN</li>
2977                 /// 
2978                 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2979                 /// 
2980                 /// <li>SCOPE_SUB - searches the base DN and all entries
2981                 /// within its subtree</li>
2982                 /// </ul>
2983                 /// </param>
2984                 /// <param name="filter">        Search filter specifying the search criteria.
2985                 /// 
2986                 /// </param>
2987                 /// <param name="attrs">         Names of attributes to retrieve.
2988                 /// 
2989                 /// </param>
2990                 /// <param name="typesOnly">     If true, returns the names but not the values of
2991                 /// the attributes found.  If false, returns the
2992                 /// names and values for attributes found.
2993                 /// 
2994                 /// </param>
2995                 /// <param name="queue">         Handler for messages returned from a server in
2996                 /// response to this request. If it is null, a
2997                 /// queue object is created internally.
2998                 /// 
2999                 /// </param>
3000                 /// <exception> LdapException A general exception which includes an error
3001                 /// message and an Ldap error code.
3002                 /// </exception>
3003                 public virtual LdapSearchQueue Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchQueue queue)
3004                 {
3005                         return Search(base_Renamed, scope, filter, attrs, typesOnly, queue, defSearchCons);
3006                 }
3007                 
3008                 /// <summary> Asynchronously performs the search specified by the parameters,
3009                 /// also allowing specification of constraints for the search (such
3010                 /// as the maximum number of entries to find or the maximum time to
3011                 /// wait for search results).
3012                 /// 
3013                 /// </summary>
3014                 /// <param name="base">          The base distinguished name to search from.
3015                 /// 
3016                 /// </param>
3017                 /// <param name="scope">         The scope of the entries to search. The following
3018                 /// are the valid options:
3019                 /// <ul>
3020                 /// <li>SCOPE_BASE - searches only the base DN</li>
3021                 /// 
3022                 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
3023                 /// 
3024                 /// <li>SCOPE_SUB - searches the base DN and all entries
3025                 /// within its subtree</li>
3026                 /// </ul>
3027                 /// </param>
3028                 /// <param name="filter">        The search filter specifying the search criteria.
3029                 /// 
3030                 /// </param>
3031                 /// <param name="attrs">         The names of attributes to retrieve.
3032                 /// 
3033                 /// </param>
3034                 /// <param name="typesOnly">     If true, returns the names but not the values of
3035                 /// the attributes found.  If false, returns the
3036                 /// names and values for attributes found.
3037                 /// 
3038                 /// </param>
3039                 /// <param name="queue">         The queue for messages returned from a server in
3040                 /// response to this request. If it is null, a
3041                 /// queue object is created internally.
3042                 /// 
3043                 /// </param>
3044                 /// <param name="cons">          The constraints specific to the search.
3045                 /// 
3046                 /// </param>
3047                 /// <exception> LdapException A general exception which includes an error
3048                 /// message and an Ldap error code.
3049                 /// </exception>
3050                 public virtual LdapSearchQueue Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchQueue queue, LdapSearchConstraints cons)
3051                 {
3052                         if ((System.Object) filter == null)
3053                         {
3054                                 filter = "objectclass=*";
3055                         }
3056                         if (cons == null)
3057                                 cons = defSearchCons;
3058                         
3059                         LdapMessage msg = new LdapSearchRequest(base_Renamed, scope, filter, attrs, cons.Dereference, cons.MaxResults, cons.ServerTimeLimit, typesOnly, cons.getControls());
3060                         MessageAgent agent;
3061                         LdapSearchQueue myqueue = queue;
3062                         if (myqueue == null)
3063                         {
3064                                 agent = new MessageAgent();
3065                                 myqueue = new LdapSearchQueue(agent);
3066                         }
3067                         else
3068                         {
3069                                 agent = queue.MessageAgent;
3070                         }
3071                         
3072                         try
3073                         {
3074                                 agent.sendMessage(conn, msg, cons.TimeLimit, myqueue, null);
3075                         }
3076                         catch (LdapException lex)
3077                         {
3078                                 throw lex;
3079                         }
3080                         return myqueue;
3081                 }
3082                 
3083                 /*
3084                 * Ldap URL search
3085                 */
3086                 
3087                 /// <summary> Synchronously performs the search specified by the Ldap URL, returning
3088                 /// an enumerable LdapSearchResults object.
3089                 /// 
3090                 /// </summary>
3091                 /// <param name="toGet">The Ldap URL specifying the entry to read.
3092                 /// 
3093                 /// </param>
3094                 /// <exception> LdapException A general exception which includes an error
3095                 /// message and an Ldap error code.
3096                 /// </exception>
3097                 public static LdapSearchResults Search(LdapUrl toGet)
3098                 {
3099                         // Get a clone of default search constraints, method alters batchSize
3100                         return Search(toGet, null);
3101                 }
3102                 
3103                 /*
3104                 * Ldap URL search
3105                 */
3106                 
3107                 /// <summary> Synchronously perfoms the search specified by the Ldap URL, using
3108                 /// the specified search constraints (such as the maximum number of
3109                 /// entries to find or the maximum time to wait for search results).
3110                 /// 
3111                 /// When this method is called, a new connection is created
3112                 /// automatically, using the host and port specified in the URL. After
3113                 /// all search results have been received from the server, the method
3114                 /// closes the connection (in other words, it disconnects from the Ldap
3115                 /// server).
3116                 /// 
3117                 /// As part of the search constraints, a choice can be made as to whether
3118                 /// to have the results delivered all at once or in smaller batches. If
3119                 /// the results are to be delivered in smaller batches, each iteration
3120                 /// blocks only until the next batch of results is returned.
3121                 /// 
3122                 /// 
3123                 /// </summary>
3124                 /// <param name="toGet">         Ldap URL specifying the entry to read.
3125                 /// 
3126                 /// </param>
3127                 /// <param name="cons">          The constraints specific to the search.
3128                 /// 
3129                 /// </param>
3130                 /// <exception> LdapException A general exception which includes an error
3131                 /// message and an Ldap error code.
3132                 /// </exception>
3133                 public static LdapSearchResults Search(LdapUrl toGet, LdapSearchConstraints cons)
3134                 {
3135                         LdapConnection lconn = new LdapConnection();
3136                         lconn.Connect(toGet.Host, toGet.Port);
3137                         if (cons == null)
3138                         {
3139                                 // This is a clone, so we already have our own copy
3140                                 cons = lconn.SearchConstraints;
3141                         }
3142                         else
3143                         {
3144                                 // get our own copy of user's constraints because we modify it
3145                                 cons = (LdapSearchConstraints) cons.Clone();
3146                         }
3147                         cons.BatchSize = 0; // Must wait until all results arrive
3148                         LdapSearchResults toReturn = lconn.Search(toGet.getDN(), toGet.Scope, toGet.Filter, toGet.AttributeArray, false, cons);
3149                         lconn.Disconnect();
3150                         return toReturn;
3151                 }
3152                 
3153                 /// <summary> Sends an Ldap request to a directory server.
3154                 /// 
3155                 /// The specified the Ldap request is sent to the directory server
3156                 /// associated with this connection using default constraints. An Ldap
3157                 /// request object is a subclass {@link LdapMessage} with the operation
3158                 /// type set to one of the request types. You can build a request by using
3159                 /// the request classes found in this package
3160                 /// 
3161                 /// You should note that, since Ldap requests sent to the server
3162                 /// using sendRequest are asynchronous, automatic referral following
3163                 /// does not apply to these requests.
3164                 /// 
3165                 /// </summary>
3166                 /// <param name="request">The Ldap request to send to the directory server.
3167                 /// </param>
3168                 /// <param name="queue">   The queue for messages returned from a server in
3169                 /// response to this request. If it is null, a
3170                 /// queue object is created internally.
3171                 /// </param>
3172                 /// <exception>     LdapException A general exception which includes an error
3173                 /// message and an Ldap error code.
3174                 /// 
3175                 /// </exception>
3176                 /// <seealso cref="LdapMessage.Type">
3177                 /// </seealso>
3178                 /// <seealso cref="RfcLdapMessage.isRequest">
3179                 /// </seealso>
3180                 public virtual LdapMessageQueue SendRequest(LdapMessage request, LdapMessageQueue queue)
3181                 {
3182                         return SendRequest(request, queue, null);
3183                 }
3184                 
3185                 /// <summary> Sends an Ldap request to a directory server.
3186                 /// 
3187                 /// The specified the Ldap request is sent to the directory server
3188                 /// associated with this connection. An Ldap request object is an
3189                 /// {@link LdapMessage} with the operation type set to one of the request
3190                 /// types. You can build a request by using the request classes found in this
3191                 /// package
3192                 /// 
3193                 /// You should note that, since Ldap requests sent to the server
3194                 /// using sendRequest are asynchronous, automatic referral following
3195                 /// does not apply to these requests.
3196                 /// 
3197                 /// </summary>
3198                 /// <param name="request">The Ldap request to send to the directory server.
3199                 /// </param>
3200                 /// <param name="queue">   The queue for messages returned from a server in
3201                 /// response to this request. If it is null, a
3202                 /// queue object is created internally.
3203                 /// </param>
3204                 /// <param name="cons">   The constraints that apply to this request
3205                 /// </param>
3206                 /// <exception>     LdapException A general exception which includes an error
3207                 /// message and an Ldap error code.
3208                 /// 
3209                 /// </exception>
3210                 /// <seealso cref="LdapMessage.Type">
3211                 /// </seealso>
3212                 /// <seealso cref="RfcLdapMessage.isRequest">
3213                 /// </seealso>
3214                 public virtual LdapMessageQueue SendRequest(LdapMessage request, LdapMessageQueue queue, LdapConstraints cons)
3215                 {
3216                         
3217                         
3218                         if (!request.Request)
3219                         {
3220                                 throw new System.SystemException("Object is not a request message");
3221                         }
3222                         
3223                         if (cons == null)
3224                         {
3225                                 cons = defSearchCons;
3226                         }
3227                         
3228                         // Get the correct queue for a search request
3229                         MessageAgent agent;
3230                         LdapMessageQueue myqueue = queue;
3231                         if (myqueue == null)
3232                         {
3233                                 agent = new MessageAgent();
3234                                 if (request.Type == LdapMessage.SEARCH_REQUEST)
3235                                 {
3236                                         myqueue = new LdapSearchQueue(agent);
3237                                 }
3238                                 else
3239                                 {
3240                                         myqueue = new LdapResponseQueue(agent);
3241                                 }
3242                         }
3243                         else
3244                         {
3245                                 if (request.Type == LdapMessage.SEARCH_REQUEST)
3246                                 {
3247                                         agent = queue.MessageAgent;
3248                                 }
3249                                 else
3250                                 {
3251                                         agent = queue.MessageAgent;
3252                                 }
3253                         }
3254                         
3255                         try
3256                         {
3257                                 agent.sendMessage(conn, request, cons.TimeLimit, myqueue, null);
3258                         }
3259                         catch (LdapException lex)
3260                         {
3261                                 throw lex;
3262                         }
3263                         return myqueue;
3264                 }
3265                 
3266                 //*************************************************************************
3267                 // helper methods
3268                 //*************************************************************************
3269                 
3270                 /// <summary> Locates the appropriate message agent and sends
3271                 /// the Ldap request to a directory server.
3272                 /// 
3273                 /// </summary>
3274                 /// <param name="msg">the message to send
3275                 /// 
3276                 /// </param>
3277                 /// <param name="timeout">the timeout value
3278                 /// 
3279                 /// </param>
3280                 /// <param name="queue">the response queue or null
3281                 /// 
3282                 /// </param>
3283                 /// <returns> the LdapResponseQueue for this request
3284                 /// 
3285                 /// </returns>
3286                 /// <exception> LdapException A general exception which includes an error
3287                 /// message and an Ldap error code.
3288                 /// </exception>
3289                 private LdapResponseQueue SendRequestToServer(LdapMessage msg, int timeout, LdapResponseQueue queue, BindProperties bindProps)
3290                 {
3291                         MessageAgent agent;
3292                         if (queue == null)
3293                         {
3294                                 agent = new MessageAgent();
3295                                 queue = new LdapResponseQueue(agent);
3296                         }
3297                         else
3298                         {
3299                                 agent = queue.MessageAgent;
3300                         }
3301                         
3302                         agent.sendMessage(conn, msg, timeout, queue, bindProps);
3303                         return queue;
3304                 }
3305                 
3306                 /// <summary> get an LdapConnection object so that we can follow a referral.
3307                 /// This function is never called if cons.getReferralFollowing() returns
3308                 /// false.
3309                 /// 
3310                 /// </summary>
3311                 /// <param name="referrals">the array of referral strings
3312                 /// 
3313                 /// 
3314                 /// </param>
3315                 /// <returns> The referralInfo object
3316                 /// 
3317                 /// </returns>
3318                 /// <exception> LdapReferralException A general exception which includes
3319                 /// an error message and an Ldap error code.
3320                 /// </exception>
3321                 private ReferralInfo getReferralConnection(System.String[] referrals)
3322                 {
3323                         ReferralInfo refInfo = null;
3324                         System.Exception ex = null;
3325                         LdapConnection rconn = null;
3326                         LdapReferralHandler rh = defSearchCons.getReferralHandler();
3327                         int i = 0;
3328                         // Check if we use LdapRebind to get authentication credentials
3329                         if ((rh == null) || (rh is LdapAuthHandler))
3330                         {
3331                                 for (i = 0; i < referrals.Length; i++)
3332                                 {
3333                                         // dn, pw are null in the default case (anonymous bind)
3334                                         System.String dn = null;
3335                                         sbyte[] pw = null;
3336                                         try
3337                                         {
3338                                                 rconn = new LdapConnection();
3339                                                 rconn.Constraints = defSearchCons;
3340                                                 LdapUrl url = new LdapUrl(referrals[i]);
3341                                                 rconn.Connect(url.Host, url.Port);
3342                                                 if (rh != null)
3343                                                 {
3344                                                         if (rh is LdapAuthHandler)
3345                                                         {
3346                                                                 // Get application supplied dn and pw
3347                                                                 LdapAuthProvider ap = ((LdapAuthHandler) rh).getAuthProvider(url.Host, url.Port);
3348                                                                 dn = ap.DN;
3349                                                                 pw = ap.Password;
3350                                                         }
3351                                                 }
3352                                                 rconn.Bind(Ldap_V3, dn, pw);
3353                                                 ex = null;
3354                                                 refInfo = new ReferralInfo(rconn, referrals, url);
3355                                                 // Indicate this connection created to follow referral
3356                                                 rconn.Connection.ActiveReferral = refInfo;
3357                                                 break;
3358                                         }
3359                                         catch (System.Exception lex)
3360                                         {
3361                                                 if (rconn != null)
3362                                                 {
3363                                                         try
3364                                                         {
3365                                                                 rconn.Disconnect();
3366                                                                 rconn = null;
3367                                                                 ex = lex;
3368                                                         }
3369                                                         catch (LdapException e)
3370                                                         {
3371                                                                 ; // ignore
3372                                                         }
3373                                                 }
3374                                         }
3375                                 }
3376                         }
3377                                 // Check if application gets connection and does bind
3378                         else
3379                         {
3380                                 //  rh instanceof LdapBind
3381                                 try
3382                                 {
3383                                         rconn = ((LdapBindHandler) rh).Bind(referrals, this);
3384                                         if (rconn == null)
3385                                         {
3386                                                 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR);
3387                                                 rex.setReferrals(referrals);
3388                                                 throw rex;
3389                                         }
3390                                         // Figure out which Url belongs to the connection
3391                                         for (int idx = 0; idx < referrals.Length; idx++)
3392                                         {
3393                                                 try
3394                                                 {
3395                                                         LdapUrl url = new LdapUrl(referrals[idx]);
3396                                                         if (url.Host.ToUpper().Equals(rconn.Host.ToUpper()) && (url.Port == rconn.Port))
3397                                                         {
3398                                                                 refInfo = new ReferralInfo(rconn, referrals, url);
3399                                                                 break;
3400                                                         }
3401                                                 }
3402                                                 catch (System.Exception e)
3403                                                 {
3404                                                         ; // ignore
3405                                                 }
3406                                         }
3407                                         if (refInfo == null)
3408                                         {
3409                                                 // Could not match LdapBind.bind() connecction with URL list
3410                                                 ex = new LdapLocalException(ExceptionMessages.REFERRAL_BIND_MATCH, LdapException.CONNECT_ERROR);
3411                                         }
3412                                 }
3413                                 catch (System.Exception lex)
3414                                 {
3415                                         rconn = null;
3416                                         ex = lex;
3417                                 }
3418                         }
3419                         if (ex != null)
3420                         {
3421                                 // Could not connect to any server, throw an exception
3422                                 LdapException ldapex;
3423                                 if (ex is LdapReferralException)
3424                                 {
3425                                         throw (LdapReferralException) ex;
3426                                 }
3427                                 else if (ex is LdapException)
3428                                 {
3429                                         ldapex = (LdapException) ex;
3430                                 }
3431                                 else
3432                                 {
3433                                         ldapex = new LdapLocalException(ExceptionMessages.SERVER_CONNECT_ERROR, new System.Object[]{conn.Host}, LdapException.CONNECT_ERROR, ex);
3434                                 }
3435                                 // Error attempting to follow a referral
3436                                 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR, ldapex);
3437                                 rex.setReferrals(referrals);
3438                                 // Use last URL string for the failed referral
3439                                 rex.FailedReferral = referrals[referrals.Length - 1];
3440                                 throw rex;
3441                         }
3442                         
3443                         // We now have an authenticated connection
3444                         // to be used to follow the referral.
3445                         return refInfo;
3446                 }
3447                 
3448                 /// <summary> Check the result code and throw an exception if needed.
3449                 /// 
3450                 /// If referral following is enabled, checks if we need to
3451                 /// follow a referral
3452                 /// 
3453                 /// </summary>
3454                 /// <param name="queue">- the message queue of the current response
3455                 /// 
3456                 /// </param>
3457                 /// <param name="cons">- the constraints that apply to the request
3458                 /// 
3459                 /// </param>
3460                 /// <param name="response">- the LdapResponse to check
3461                 /// </param>
3462                 private void  chkResultCode(LdapMessageQueue queue, LdapConstraints cons, LdapResponse response)
3463                 {
3464                         if ((response.ResultCode == LdapException.REFERRAL) && cons.ReferralFollowing)
3465                         {
3466                                 // Perform referral following and return
3467                                 System.Collections.ArrayList refConn = null;
3468                                 try
3469                                 {
3470                                         chaseReferral(queue, cons, response, response.Referrals, 0, false, null);
3471                                 }
3472                                 finally
3473                                 {
3474                                         releaseReferralConnections(refConn);
3475                                 }
3476                         }
3477                         else
3478                         {
3479                                 // Throws exception for non success result
3480                                 response.chkResultCode();
3481                         }
3482                         return ;
3483                 }
3484                 
3485                 /// <summary> Follow referrals if necessary referral following enabled.
3486                 /// This function is called only by synchronous requests.
3487                 /// Search responses come here only if referral following is
3488                 /// enabled and if we are processing a SearchResultReference
3489                 /// or a Response with a status of REFERRAL, i.e. we are
3490                 /// going to follow a referral.
3491                 /// 
3492                 /// This functions recursively follows a referral until a result
3493                 /// is returned or until the hop limit is reached.
3494                 /// 
3495                 /// </summary>
3496                 /// <param name="queue">The LdapResponseQueue for this request
3497                 /// 
3498                 /// </param>
3499                 /// <param name="cons">The constraints that apply to the request
3500                 /// 
3501                 /// </param>
3502                 /// <param name="msg">The referral or search reference response message
3503                 /// 
3504                 /// </param>
3505                 /// <param name="initialReferrals">The referral array returned from the
3506                 /// initial request.
3507                 /// 
3508                 /// </param>
3509                 /// <param name="hopCount">the number of hops already used while
3510                 /// following this referral
3511                 /// 
3512                 /// </param>
3513                 /// <param name="searchReference">true if the message is a search reference
3514                 /// 
3515                 /// </param>
3516                 /// <param name="connectionList">An optional array list used to store
3517                 /// the LdapConnection objects used in following the referral.
3518                 /// 
3519                 /// </param>
3520                 /// <returns> The array list used to store the all LdapConnection objects
3521                 /// used in following the referral.  The list will be empty
3522                 /// if there were none.
3523                 /// 
3524                 /// </returns>
3525                 /// <exception> LdapException A general exception which includes an error
3526                 /// message and an Ldap error code.
3527                 /// </exception>
3528                 /* package */
3529                 internal virtual System.Collections.ArrayList chaseReferral(LdapMessageQueue queue, LdapConstraints cons, LdapMessage msg, System.String[] initialReferrals, int hopCount, bool searchReference, System.Collections.ArrayList connectionList)
3530                 {
3531                         System.Collections.ArrayList connList = connectionList;
3532                         LdapConnection rconn = null; // new conn for following referral
3533                         ReferralInfo rinfo = null; // referral info
3534                         LdapMessage origMsg;
3535                         
3536                         // Get a place to store new connections
3537                         if (connList == null)
3538                         {
3539                                 connList = new System.Collections.ArrayList(cons.HopLimit);
3540                         }
3541                         // Following referrals or search reference
3542                         System.String[] refs; // referral list
3543                         if (initialReferrals != null)
3544                         {
3545                                 // Search continuation reference from a search request
3546                                 refs = initialReferrals;
3547                                 origMsg = msg.RequestingMessage;
3548                         }
3549                         else
3550                         {
3551                                 // Not a search request
3552                                 LdapResponse resp = (LdapResponse) queue.getResponse();
3553                                 if (resp.ResultCode != LdapException.REFERRAL)
3554                                 {
3555                                         // Not referral result,throw Exception if nonzero result
3556                                         resp.chkResultCode();
3557                                         return connList;
3558                                 }
3559                                 // We have a referral response
3560                                 refs = resp.Referrals;
3561                                 origMsg = resp.RequestingMessage;
3562                         }
3563                         LdapUrl refUrl; // referral represented as URL
3564                         try
3565                         {
3566                                 // increment hop count, check max hops
3567                                 if (hopCount++ > cons.HopLimit)
3568                                 {
3569                                         throw new LdapLocalException("Max hops exceeded", LdapException.REFERRAL_LIMIT_EXCEEDED);
3570                                 }
3571                                 // Get a connection to follow the referral
3572                                 rinfo = getReferralConnection(refs);
3573                                 rconn = rinfo.ReferralConnection;
3574                                 refUrl = rinfo.ReferralUrl;
3575                                 connList.Add(rconn);
3576                                 
3577                                 
3578                                 // rebuild msg into new msg changing msgID,dn,scope,filter
3579                                 LdapMessage newMsg = rebuildRequest(origMsg, refUrl, searchReference);
3580                                 
3581                                 
3582                                 // Send new message on new connection
3583                                 try
3584                                 {
3585                                         MessageAgent agent;
3586                                         if (queue is LdapResponseQueue)
3587                                         {
3588                                                 agent = queue.MessageAgent;
3589                                         }
3590                                         else
3591                                         {
3592                                                 agent = queue.MessageAgent;
3593                                         }
3594                                         agent.sendMessage(rconn.Connection, newMsg, defSearchCons.TimeLimit, queue, null);
3595                                 }
3596                                 catch (InterThreadException ex)
3597                                 {
3598                                         // Error ending request to referred server
3599                                         LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_SEND, LdapException.CONNECT_ERROR, null, ex);
3600                                         rex.setReferrals(initialReferrals);
3601                                         ReferralInfo ref_Renamed = rconn.Connection.ActiveReferral;
3602                                         rex.FailedReferral = ref_Renamed.ReferralUrl.ToString();
3603                                         throw rex;
3604                                 }
3605                                 
3606                                 if (initialReferrals == null)
3607                                 {
3608                                         // For operation results, when all responses are complete,
3609                                         // the stack unwinds back to the original and returns
3610                                         // to the application.
3611                                         // An exception is thrown for an error
3612                                         connList = chaseReferral(queue, cons, null, null, hopCount, false, connList);
3613                                 }
3614                                 else
3615                                 {
3616                                         // For search, just return to LdapSearchResults object
3617                                         return connList;
3618                                 }
3619                         }
3620                         catch (System.Exception ex)
3621                         {
3622                                 
3623                                 if (ex is LdapReferralException)
3624                                 {
3625                                         throw (LdapReferralException) ex;
3626                                 }
3627                                 else
3628                                 {
3629                                         
3630                                         // Set referral list and failed referral
3631                                         LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR, ex);
3632                                         rex.setReferrals(refs);
3633                                         if (rinfo != null)
3634                                         {
3635                                                 rex.FailedReferral = rinfo.ReferralUrl.ToString();
3636                                         }
3637                                         else
3638                                         {
3639                                                 rex.FailedReferral = refs[refs.Length - 1];
3640                                         }
3641                                         throw rex;
3642                                 }
3643                         }
3644                         return connList;
3645                 }
3646                 
3647                 /// <summary> Builds a new request replacing dn, scope, and filter where approprate
3648                 /// 
3649                 /// </summary>
3650                 /// <param name="msg">the original LdapMessage to build the new request from
3651                 /// 
3652                 /// </param>
3653                 /// <param name="url">the referral url
3654                 /// 
3655                 /// </param>
3656                 /// <returns> a new LdapMessage with appropriate information replaced
3657                 /// 
3658                 /// </returns>
3659                 /// <exception> LdapException A general exception which includes an error
3660                 /// message and an Ldap error code.
3661                 /// </exception>
3662                 private LdapMessage rebuildRequest(LdapMessage msg, LdapUrl url, bool reference)
3663                 {
3664                         
3665                         System.String dn = url.getDN(); // new base
3666                         System.String filter = null;
3667                         
3668                         switch (msg.Type)
3669                         {
3670                                 
3671                                 case LdapMessage.SEARCH_REQUEST: 
3672                                         if (reference)
3673                                         {
3674                                                 filter = url.Filter;
3675                                         }
3676                                         break;
3677                                         // We are allowed to get a referral for the following
3678                                 
3679                                 case LdapMessage.ADD_REQUEST: 
3680                                 case LdapMessage.BIND_REQUEST: 
3681                                 case LdapMessage.COMPARE_REQUEST: 
3682                                 case LdapMessage.DEL_REQUEST: 
3683                                 case LdapMessage.EXTENDED_REQUEST: 
3684                                 case LdapMessage.MODIFY_RDN_REQUEST: 
3685                                 case LdapMessage.MODIFY_REQUEST: 
3686                                         break;
3687                                         // The following return no response
3688                                 
3689                                 case LdapMessage.ABANDON_REQUEST: 
3690                                 case LdapMessage.UNBIND_REQUEST: 
3691                                 default: 
3692                                         throw new LdapLocalException(ExceptionMessages.IMPROPER_REFERRAL, new System.Object[]{msg.Type}, LdapException.LOCAL_ERROR);
3693                         }
3694                         
3695                         return msg.Clone(dn, filter, reference);
3696                 }
3697                 
3698                 /*
3699                 * Release connections acquired by following referrals
3700                 *
3701                 * @param list the list of the connections
3702                 */
3703                 /* package */
3704                 internal virtual void  releaseReferralConnections(System.Collections.ArrayList list)
3705                 {
3706                         if (list == null)
3707                         {
3708                                 return ;
3709                         }
3710                         // Release referral connections
3711                         for (int i = list.Count - 1; i >= 0; i--)
3712                         {
3713                                 LdapConnection rconn = null;
3714                                 try
3715                                 {
3716                                         rconn=(LdapConnection)list[i];
3717                                         list.RemoveAt(i);
3718 //                                      rconn = (LdapConnection) list.RemoveAt(i);
3719                                         rconn.Disconnect();
3720                                 }
3721                                 catch (System.IndexOutOfRangeException ex)
3722                                 {
3723                                         continue;
3724                                 }
3725                                 catch (LdapException lex)
3726                                 {
3727                                         continue;
3728                                 }
3729                         }
3730                         return ;
3731                 }
3732
3733                 //*************************************************************************
3734                 // Schema Related methods
3735                 //*************************************************************************
3736                 
3737                 /// <summary> Retrieves the schema associated with a particular schema DN in the
3738                 /// directory server.
3739                 /// The schema DN for a particular entry is obtained by calling the
3740                 /// getSchemaDN method of LDAPConnection
3741                 /// 
3742                 /// </summary>
3743                 /// <param name="schemaDN">The schema DN used to fetch the schema.
3744                 /// 
3745                 /// </param>
3746                 /// <returns>    An LDAPSchema entry containing schema attributes.  If the
3747                 /// entry contains no schema attributes then the returned LDAPSchema object
3748                 /// will be empty.
3749                 /// 
3750                 /// </returns>
3751                 /// <exception> LDAPException     This exception occurs if the schema entry
3752                 /// cannot be retrieved with this connection.
3753                 /// </exception>
3754                 /// <seealso cref="GetSchemaDN()">
3755                 /// </seealso>
3756                 /// <seealso cref="GetSchemaDN(String)">
3757                 /// </seealso>
3758                 public virtual LdapSchema FetchSchema(System.String schemaDN)
3759                 {
3760                         LdapEntry ent = Read(schemaDN, LdapSchema.schemaTypeNames);
3761                         return new LdapSchema(ent);
3762                 }
3763                 
3764                 /// <summary> Retrieves the Distiguished Name (DN) for the schema advertised in the
3765                 /// root DSE of the Directory Server.
3766                 /// 
3767                 /// The DN can be used with the methods fetchSchema and modify to retreive
3768                 /// and extend schema definitions.  The schema entry is located by reading
3769                 /// subschemaSubentry attribute of the root DSE.  This is equivalent to
3770                 /// calling {@link #getSchemaDN(String) } with the DN parameter as an empty
3771                 /// string: <code>getSchemaDN("")</code>.
3772                 /// 
3773                 /// 
3774                 /// </summary>
3775                 /// <returns>     Distinguished Name of a schema entry in effect for the
3776                 /// Directory.
3777                 /// </returns>
3778                 /// <exception> LDAPException     This exception occurs if the schema DN
3779                 /// cannot be retrieved, or if the subschemaSubentry attribute associated
3780                 /// with the root DSE contains multiple values.
3781                 /// 
3782                 /// </exception>
3783                 /// <seealso cref="FetchSchema">
3784                 /// </seealso>
3785                 /// <seealso cref="Modify">
3786                 /// </seealso>
3787                 public virtual System.String GetSchemaDN()
3788                 {
3789                         return GetSchemaDN("");
3790                 }
3791                 
3792                 /// <summary> Retrieves the Distiguished Name (DN) of the schema associated with a
3793                 /// entry in the Directory.
3794                 /// 
3795                 /// The DN can be used with the methods fetchSchema and modify to retreive
3796                 /// and extend schema definitions.  Reads the subschemaSubentry of the entry
3797                 /// specified.
3798                 /// 
3799                 /// </summary>
3800                 /// <param name="dn">    Distinguished Name of any entry.  The subschemaSubentry
3801                 /// attribute is queried from this entry.
3802                 /// 
3803                 /// </param>
3804                 /// <returns>      Distinguished Name of a schema entry in effect for the entry
3805                 /// identified by <code>dn</code>.
3806                 /// 
3807                 /// </returns>
3808                 /// <exception> LDAPException     This exception occurs if a null or empty
3809                 /// value is passed as dn, if the subschemasubentry attribute cannot
3810                 /// be retrieved, or the subschemasubentry contains multiple values.
3811                 /// 
3812                 /// </exception>
3813                 /// <seealso cref="FetchSchema">
3814                 /// </seealso>
3815                 /// <seealso cref="Modify">
3816                 /// </seealso>
3817                 public virtual System.String GetSchemaDN(System.String dn)
3818                 {
3819                         System.String[] attrSubSchema = new System.String[]{"subschemaSubentry"};
3820                         
3821                         /* Read the entries subschemaSubentry attribute. Throws an exception if
3822                         * no entries are returned. */
3823                         LdapEntry ent = this.Read(dn, attrSubSchema);
3824                         
3825                         LdapAttribute attr = ent.getAttribute(attrSubSchema[0]);
3826                         System.String[] values = attr.StringValueArray;
3827                         if (values == null || values.Length < 1)
3828                         {
3829                                 throw new LdapLocalException(ExceptionMessages.NO_SCHEMA, new System.Object[]{dn}, LdapException.NO_RESULTS_RETURNED);
3830                         }
3831                         else if (values.Length > 1)
3832                         {
3833                                 throw new LdapLocalException(ExceptionMessages.MULTIPLE_SCHEMA, new System.Object[]{dn}, LdapException.CONSTRAINT_VIOLATION);
3834                         }
3835                         return values[0];
3836                 }
3837
3838         }
3839 }